first init of 0.9

This commit is contained in:
cnjinhao
2014-12-11 03:32:35 +08:00
commit d0a317bd45
206 changed files with 69773 additions and 0 deletions

View File

@@ -0,0 +1,119 @@
#include <nana/paint/detail/image_process_provider.hpp>
#include <nana/paint/detail/image_processor.hpp>
namespace nana
{
namespace paint
{
namespace image_process
{
//There are definitions of pure virtual destructor of image processor interfaces
stretch_interface::~stretch_interface(){}
alpha_blend_interface::~alpha_blend_interface(){}
blend_interface::~blend_interface(){}
line_interface::~line_interface(){}
blur_interface::~blur_interface(){}
}
namespace detail
{
//class image_process_provider
image_process_provider& image_process_provider::instance()
{
static image_process_provider obj;
return obj;
}
image_process_provider::image_process_provider()
{
add<paint::detail::algorithms::bilinear_interoplation>(stretch_, "bilinear interoplation");
add<paint::detail::algorithms::proximal_interoplation>(stretch_, "proximal interoplation");
add<paint::detail::algorithms::alpha_blend>(alpha_blend_, "alpha_blend");
add<paint::detail::algorithms::blend>(blend_, "blend");
add<paint::detail::algorithms::bresenham_line>(line_, "bresenham_line");
add<paint::detail::algorithms::superfast_blur>(blur_, "superfast_blur");
}
image_process_provider::stretch_tag& image_process_provider::ref_stretch_tag()
{
return stretch_;
}
paint::image_process::stretch_interface * const * image_process_provider::stretch() const
{
return &stretch_.employee;
}
paint::image_process::stretch_interface * image_process_provider::ref_stretch(const std::string& name) const
{
return _m_read(stretch_, name);
}
//alpha_blend
image_process_provider::alpha_blend_tag& image_process_provider::ref_alpha_blend_tag()
{
return alpha_blend_;
}
paint::image_process::alpha_blend_interface * const * image_process_provider::alpha_blend() const
{
return &alpha_blend_.employee;
}
paint::image_process::alpha_blend_interface * image_process_provider::ref_alpha_blend(const std::string& name) const
{
return _m_read(alpha_blend_, name);
}
//blend
image_process_provider::blend_tag& image_process_provider::ref_blend_tag()
{
return blend_;
}
paint::image_process::blend_interface * const * image_process_provider::blend() const
{
return &blend_.employee;
}
paint::image_process::blend_interface * image_process_provider::ref_blend(const std::string& name) const
{
return _m_read(blend_, name);
}
//line
image_process_provider::line_tag & image_process_provider::ref_line_tag()
{
return line_;
}
paint::image_process::line_interface * const * image_process_provider::line() const
{
return &line_.employee;
}
paint::image_process::line_interface * image_process_provider::ref_line(const std::string& name) const
{
return _m_read(line_, name);
}
//Blur
image_process_provider::blur_tag & image_process_provider::ref_blur_tag()
{
return blur_;
}
paint::image_process::blur_interface * const * image_process_provider::blur() const
{
return &blur_.employee;
}
paint::image_process::blur_interface * image_process_provider::ref_blur(const std::string& name) const
{
return _m_read(blur_, name);
}
//end class image_process_provider
}
}
}//end namespace nana

View File

@@ -0,0 +1,230 @@
/*
* Platform Implementation
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/paint/detail/native_paint_interface.cpp
*/
#include <nana/config.hpp>
#include PLATFORM_SPEC_HPP
#include <nana/paint/detail/native_paint_interface.hpp>
#include <nana/paint/pixel_buffer.hpp>
#include <nana/gui/layout_utility.hpp>
#if defined(NANA_WINDOWS)
#include <windows.h>
#elif defined(NANA_X11)
#include <X11/Xlib.h>
#endif
namespace nana
{
namespace paint
{
namespace detail
{
nana::size drawable_size(drawable_type dw)
{
if(0 == dw) return nana::size();
#if defined(NANA_WINDOWS)
BITMAP bmp;
::GetObject(dw->pixmap, sizeof bmp, &bmp);
return nana::size(bmp.bmWidth, bmp.bmHeight);
#elif defined(NANA_X11)
nana::detail::platform_spec & spec = nana::detail::platform_spec::instance();
Window root;
int x, y;
unsigned width, height;
unsigned border, depth;
nana::detail::platform_scope_guard psg;
::XGetGeometry(spec.open_display(), dw->pixmap, &root, &x, &y, &width, &height, &border, &depth);
return nana::size(width, height);
#endif
}
unsigned char * alloc_fade_table(double fade_rate)
{
unsigned char* tablebuf = new unsigned char[0x100 * 2];
unsigned char* d_table = tablebuf;
unsigned char* s_table = d_table + 0x100;
double fade_rate_mul_to_add = 0;
double fade_rate_2 = fade_rate + fade_rate;
double fade_rate_3 = fade_rate_2 + fade_rate;
double fade_rate_4 = fade_rate_3 + fade_rate;
for(int i = 0; i < 0x100; i += 4, fade_rate_mul_to_add += fade_rate_4)
{
d_table[0] = static_cast<unsigned char>(fade_rate_mul_to_add);
s_table[0] = i - d_table[0];
d_table[1] = static_cast<unsigned char>(fade_rate_mul_to_add + fade_rate);
s_table[1] = i + 1 - d_table[1];
d_table[2] = static_cast<unsigned char>(fade_rate_mul_to_add + fade_rate_2);
s_table[2] = i + 2 - d_table[2];
d_table[3] = static_cast<unsigned char>(fade_rate_mul_to_add + fade_rate_3);
s_table[3] = i + 3 - d_table[3];
d_table += 4;
s_table += 4;
}
return tablebuf;
}
void free_fade_table(const unsigned char* table)
{
delete [] table;
}
nana::pixel_rgb_t fade_color(nana::pixel_rgb_t bgcolor, nana::pixel_rgb_t fgcolor, double fade_rate)
{
pixel_rgb_t ret;
double lrate = 1.0 - fade_rate;
ret.u.element.red = static_cast<unsigned char>(bgcolor.u.element.red * fade_rate + fgcolor.u.element.red * lrate);
ret.u.element.green = static_cast<unsigned char>(bgcolor.u.element.green * fade_rate + fgcolor.u.element.green * lrate);
ret.u.element.blue = static_cast<unsigned char>(bgcolor.u.element.blue * fade_rate + fgcolor.u.element.blue * lrate);
ret.u.element.alpha_channel = 0;
return ret;
}
nana::pixel_rgb_t fade_color(nana::pixel_rgb_t bgcolor, nana::pixel_rgb_t fgcolor, const unsigned char* const fade_table)
{
const unsigned char * const s_fade_table = fade_table + 0x100;
bgcolor.u.element.red = fade_table[bgcolor.u.element.red] + s_fade_table[fgcolor.u.element.red];
bgcolor.u.element.green = fade_table[bgcolor.u.element.green] + s_fade_table[fgcolor.u.element.green];
bgcolor.u.element.blue = fade_table[bgcolor.u.element.blue] + s_fade_table[fgcolor.u.element.blue];
return bgcolor;
}
nana::pixel_rgb_t fade_color_intermedia(nana::pixel_rgb_t fgcolor, const unsigned char* fade_table)
{
fade_table += 0x100;
fgcolor.u.element.red = fade_table[fgcolor.u.element.red];
fgcolor.u.element.green = fade_table[fgcolor.u.element.green];
fgcolor.u.element.blue = fade_table[fgcolor.u.element.blue];
return fgcolor;
}
nana::pixel_rgb_t fade_color_by_intermedia(nana::pixel_rgb_t bgcolor, nana::pixel_rgb_t fgcolor_intermedia, const unsigned char* const fade_table)
{
bgcolor.u.element.red = fade_table[bgcolor.u.element.red] + fgcolor_intermedia.u.element.red;
bgcolor.u.element.green = fade_table[bgcolor.u.element.green] + fgcolor_intermedia.u.element.green;
bgcolor.u.element.blue = fade_table[bgcolor.u.element.blue] + fgcolor_intermedia.u.element.blue;
return bgcolor;
}
void blend(drawable_type dw, const nana::rectangle& area, unsigned color, double fade_rate)
{
if(fade_rate <= 0) return;
if(fade_rate > 1) fade_rate = 1;
nana::rectangle r;
if(false == nana::overlap(drawable_size(dw), area, r))
return;
unsigned red = static_cast<unsigned>((color & 0xFF0000) * fade_rate);
unsigned green = static_cast<unsigned>((color & 0xFF00) * fade_rate);
unsigned blue = static_cast<unsigned>((color & 0xFF) * fade_rate);
double lrate = 1 - fade_rate;
pixel_buffer pixbuf(dw, r.y, r.height);
for(std::size_t row = 0; row < r.height; ++row)
{
nana::pixel_rgb_t * i = pixbuf.raw_ptr(row) + r.x;
const nana::pixel_rgb_t * const end = i + r.width;
for(; i < end; ++i)
{
unsigned px_r = ((static_cast<unsigned>((i->u.color & 0xFF0000) * lrate) + red) & 0xFF0000);
unsigned px_g = ((static_cast<unsigned>((i->u.color & 0xFF00) * lrate) + green) & 0xFF00);
unsigned px_b = ((static_cast<unsigned>((i->u.color & 0xFF) * lrate) + blue) & 0xFF);
i->u.color = (px_r | px_g | px_b);
}
}
pixbuf.paste(nana::rectangle(r.x, 0, r.width, r.height), dw, r.x, r.y);
}
nana::size raw_text_extent_size(drawable_type dw, const nana::char_t* text, std::size_t len)
{
if(nullptr == dw || nullptr == text || 0 == len) return nana::size();
#if defined(NANA_WINDOWS)
::SIZE size;
if(::GetTextExtentPoint32(dw->context, text, static_cast<int>(len), &size))
return nana::size(size.cx, size.cy);
#elif defined(NANA_X11)
#if defined(NANA_UNICODE)
std::string utf8str = nana::charset(nana::string(text, len));
XGlyphInfo ext;
XftFont * fs = reinterpret_cast<XftFont*>(dw->font->handle);
::XftTextExtentsUtf8(nana::detail::platform_spec::instance().open_display(), fs,
reinterpret_cast<XftChar8*>(const_cast<char*>(utf8str.c_str())), utf8str.size(), &ext);
return nana::size(ext.xOff, fs->ascent + fs->descent);
#else
XRectangle ink;
XRectangle logic;
::XmbTextExtents(reinterpret_cast<XFontSet>(dw->font->handle), text, len, &ink, &logic);
return nana::size(logic.width, logic.height);
#endif
#endif
return nana::size();
}
nana::size text_extent_size(drawable_type dw, const nana::char_t * text, std::size_t len)
{
nana::size extents = raw_text_extent_size(dw, text, len);
const nana::char_t* const end = text + len;
int tabs = 0;
for(; text != end; ++text)
{
if(*text == '\t')
++tabs;
}
if(tabs)
extents.width = static_cast<int>(extents.width) - tabs * static_cast<int>(dw->string.tab_pixels - dw->string.whitespace_pixels * dw->string.tab_length);
return extents;
}
void draw_string(drawable_type dw, int x, int y, const nana::char_t * str, std::size_t len)
{
#if defined(NANA_WINDOWS)
::TextOut(dw->context, x, y, str, static_cast<int>(len));
#elif defined(NANA_X11)
#if defined(NANA_UNICODE)
std::string utf8str = nana::charset(nana::string(str, len));
XftFont * fs = reinterpret_cast<XftFont*>(dw->font->handle);
::XftDrawStringUtf8(dw->xftdraw, &(dw->xft_fgcolor), fs, x, y + fs->ascent,
reinterpret_cast<XftChar8*>(const_cast<char*>(utf8str.c_str())), utf8str.size());
#else
XFontSet fs = reinterpret_cast<XFontSet>(dw->font->handle);
XFontSetExtents * ext = ::XExtentsOfFontSet(fs);
XFontStruct ** fontstructs;
char ** font_names;
int size = ::XFontsOfFontSet(fs, &fontstructs, &font_names);
unsigned ascent = 0;
unsigned descent = 0;
XFontStruct **fontstructs_end = fontstructs + size;
for(XFontStruct** i = fontstructs; i < fontstructs_end; ++i)
{
if(ascent < (*i)->ascent)
ascent = (*i)->ascent;
if(descent < (*i)->descent)
descent = (*i)->descent;
}
XmbDrawString(display, dw->pixmap, reinterpret_cast<XFontSet>(dw->font->handle), dw->context, x, y + ascent + descent, buf, len);
#endif
#endif
}
}//end namespace detail
}//end namespace paint
}//end namespace nana

316
source/paint/gadget.cpp Normal file
View File

@@ -0,0 +1,316 @@
/*
* Graphics Gadget Implementation
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/paint/gadget.cpp
*/
#include <nana/paint/graphics.hpp>
#include <nana/paint/gadget.hpp>
namespace nana
{
namespace paint
{
namespace gadget
{
namespace detail
{
typedef nana::paint::graphics& graph_reference;
void hollow_triangle(graph_reference graph, int x, int y, nana::color_t color, uint32_t direction)
{
x += 3;
y += 3;
switch(direction)
{
case directions::to_east:
graph.line(x + 3, y + 1, x + 3, y + 9, color);
graph.line(x + 4, y + 2 , x + 7, y + 5, color);
graph.line(x + 6, y + 6, x + 4, y + 8, color);
break;
case directions::to_southeast:
graph.line(x + 2, y + 7, x + 7, y + 7, color);
graph.line(x + 7, y + 2, x + 7, y + 6, color);
graph.line(x + 3, y + 6, x + 6, y + 3, color);
break;
case directions::to_south:
y += 3;
graph.line(x, y, x + 8, y, color);
graph.line(x + 1, y + 1, x + 4, y + 4, color);
graph.line(x + 7, y + 1, x + 5, y + 3, color);
break;
case directions::to_west:
x += 5;
y += 1;
graph.line(x, y, x, y + 8, color);
graph.line(x - 4, y + 4, x - 1, y + 1, color);
graph.line(x - 3, y + 5, x - 1, y + 7, color);
break;
case directions::to_north:
y += 7;
graph.line(x, y, x + 8, y, color);
graph.line(x + 1, y - 1, x + 4, y - 4, color);
graph.line(x + 5, y - 3, x + 7, y - 1, color);
break;
}
}
void solid_triangle(graph_reference graph, int x, int y, nana::color_t color, uint32_t dir)
{
x += 3;
y += 3;
switch(dir)
{
case directions::to_east:
for(int i = 0; i < 5; ++i)
graph.line(x + 3 + i, y + 1 + i, x + 3 + i, y + 9 - i, color);
break;
case directions::to_southeast:
for(int i = 0; i < 6; ++i)
graph.line(x + 2 + i, y + 7 - i, x + 7, y + 7 - i, color);
break;
case directions::to_south:
y += 3;
for(int i = 0; i < 5; ++i)
graph.line(x + i, y + i, x + 8 - i, y + i, color);
break;
case directions::to_west:
x += 5;
y += 1;
for(int i = 0; i < 5; ++i)
graph.line(x - i, y + i, x - i, y + 8 - i, color);
break;
case directions::to_north:
y += 7;
for(int i = 0; i < 5; ++i)
graph.line(x + i, y - i, x + 8 - i, y - i, color);
break;
}
}
void direction_arrow(graph_reference graph, int x, int y, nana::color_t color, uint32_t dir)
{
y += 5;
switch(dir)
{
case directions::to_north:
{
x += 3;
int pixels = 1;
for(int l = 0; l < 4; ++l)
{
for(int i = 0; i < pixels; ++i)
{
if(l ==3 && i == 3)
{}
else
graph.set_pixel(x + i, y, 0x262);
}
x--;
y++;
pixels += 2;
}
graph.set_pixel(x + 1, y, 0x262);
graph.set_pixel(x + 2, y, 0x262);
graph.set_pixel(x + 6, y, 0x262);
graph.set_pixel(x + 7, y, 0x262);
}
break;
case directions::to_south:
{
graph.set_pixel(x, y, 0x262);
graph.set_pixel(x + 1, y, 0x262);
graph.set_pixel(x + 5, y, 0x262);
graph.set_pixel(x + 6, y, 0x262);
++y;
int pixels = 7;
for(int l = 0; l < 4; ++l)
{
for(int i = 0; i < pixels; ++i)
{
if(l == 0 && i == 3){}
else
graph.set_pixel(x + i, y, 0x262);
}
x++;
y++;
pixels -= 2;
}
}
break;
}
}
void double_arrow_line(nana::paint::graphics & graph, int x, int y, color_t color, bool horizontal)
{
graph.set_pixel(x, y, color);
if(horizontal)
{
graph.set_pixel(x + 1, y, color);
graph.set_pixel(x + 4, y, color);
graph.set_pixel(x + 5, y, color);
}
else
{
graph.set_pixel(x, y + 1, color);
graph.set_pixel(x, y + 4, color);
graph.set_pixel(x, y + 5, color);
}
}
void double_arrow(nana::paint::graphics& graph, int x, int y, color_t color, directions::t dir)
{
switch(dir)
{
case directions::to_east:
double_arrow_line(graph, x + 4, y + 6, color, true);
double_arrow_line(graph, x + 5, y + 7, color, true);
double_arrow_line(graph, x + 6, y + 8, color, true);
double_arrow_line(graph, x + 5, y + 9, color, true);
double_arrow_line(graph, x + 4, y + 10, color, true);
break;
case directions::to_west:
double_arrow_line(graph, x + 5, y + 6, color, true);
double_arrow_line(graph, x + 4, y + 7, color, true);
double_arrow_line(graph, x + 3, y + 8, color, true);
double_arrow_line(graph, x + 4, y + 9, color, true);
double_arrow_line(graph, x + 5, y + 10, color, true);
break;
case directions::to_south:
double_arrow_line(graph, x + 5, y + 4, color, false);
double_arrow_line(graph, x + 6, y + 5, color, false);
double_arrow_line(graph, x + 7, y + 6, color, false);
double_arrow_line(graph, x + 8, y + 5, color, false);
double_arrow_line(graph, x + 9, y + 4, color, false);
break;
case directions::to_north:
double_arrow_line(graph, x + 5, y + 6, color, false);
double_arrow_line(graph, x + 6, y + 5, color, false);
double_arrow_line(graph, x + 7, y + 4, color, false);
double_arrow_line(graph, x + 8, y + 5, color, false);
double_arrow_line(graph, x + 9, y + 6, color, false);
break;
default:
break;
}
}
}//end namespace detail
//arrow_16_pixels
//param@style: 0 = hollow, 1 = solid
void arrow_16_pixels(nana::paint::graphics& graph, int x, int y, unsigned color, uint32_t style, directions::t dir)
{
switch(style)
{
case 1:
detail::solid_triangle(graph, x, y, color, dir);
break;
case 2:
detail::direction_arrow(graph, x, y, color, dir);
break;
case 3:
detail::double_arrow(graph, x, y, color, dir);
break;
case 0:
default:
detail::hollow_triangle(graph, x, y, color, dir);
break;
}
}
void close_16_pixels(nana::paint::graphics& graph, int x, int y, uint32_t style, uint32_t color)
{
if(0 == style)
{
x += 3;
y += 3;
graph.line(x, y, x + 9, y + 9, color);
graph.line(x + 1, y, x + 9, y + 8, color);
graph.line(x, y + 1, x + 8, y + 9, color);
graph.line(x + 9, y, x , y + 9, color);
graph.line(x + 8, y, x, y + 8, color);
graph.line(x + 9, y + 1, x + 1, y + 9, color);
}
else
{
x += 4;
y += 4;
graph.line(x, y, x + 7, y + 7, color);
graph.line(x + 1, y, x + 7, y + 6, color);
graph.line(x, y + 1, x + 6, y + 7, color);
graph.line(x + 7, y, x , y + 7, color);
graph.line(x + 6, y, x, y + 6, color);
graph.line(x + 7, y + 1, x + 1, y + 7, color);
}
}
void cross(graphics& graph, int x, int y, uint32_t size, uint32_t thickness, nana::color_t color)
{
if(thickness + 2 <= size)
{
int gap = (size - thickness) / 2;
nana::point ps[12];
ps[0].x = x + gap;
ps[1].x = ps[0].x + thickness - 1;
ps[1].y = ps[0].y = y;
ps[2].x = ps[1].x;
ps[2].y = y + gap;
ps[3].x = ps[2].x + gap;
ps[3].y = ps[2].y;
ps[4].x = ps[3].x;
ps[4].y = ps[3].y + thickness - 1;
ps[5].x = ps[1].x;
ps[5].y = ps[4].y;
ps[6].x = ps[5].x;
ps[6].y = ps[5].y + gap;
ps[7].x = x + gap;
ps[7].y = ps[6].y;
ps[8].x = ps[7].x;
ps[8].y = ps[4].y;
ps[9].x = x;
ps[9].y = ps[4].y;
ps[10].x = x;
ps[10].y = y + gap;
ps[11].x = x + gap;
ps[11].y = y + gap;
nana::color_t dkcolor = graph.mix(color, 0x0, 0.5);
for(int i = 0; i < 11; ++i)
graph.line(ps[i], ps[i + 1], dkcolor);
graph.line(ps[11], ps[0], dkcolor);
graph.rectangle(ps[10].x + 1, ps[10].y + 1, (gap << 1) + thickness - 2, thickness - 2, color, true);
graph.rectangle(ps[0].x + 1, ps[0].y + 1, thickness - 2, (gap << 1) + thickness - 2, color, true);
}
}
}//end namespace gadget
}//end namespace paint
}//end namespace nana

1189
source/paint/graphics.cpp Normal file

File diff suppressed because it is too large Load Diff

276
source/paint/image.cpp Normal file
View File

@@ -0,0 +1,276 @@
/*
* Paint Image Implementation
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/paint/image.cpp
*/
#include <nana/config.hpp>
#include PLATFORM_SPEC_HPP
#include <nana/paint/image.hpp>
#include <algorithm>
#include <fstream>
#include <iterator>
#include <nana/paint/detail/image_impl_interface.hpp>
#include <nana/paint/pixel_buffer.hpp>
#if defined(NANA_ENABLE_PNG)
#include <nana/paint/detail/image_png.hpp>
#endif
#include <nana/paint/detail/image_bmp.hpp>
#include <nana/paint/detail/image_ico.hpp>
namespace nana
{
namespace paint
{
namespace detail
{
//class image_ico
image_ico::image_ico(bool is_ico): is_ico_(is_ico){}
bool image_ico::open(const nana::char_t* filename)
{
close();
#if defined(NANA_WINDOWS)
HICON handle = 0;
if(is_ico_)
{
handle = (HICON)::LoadImage(0, filename, IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
}
else
{
SHFILEINFO sfi;
::SHGetFileInfo(filename, 0, &sfi, sizeof(sfi), SHGFI_ICON);
handle = sfi.hIcon;
}
if(handle)
{
HICON * p = new HICON(handle);
ptr_ = std::shared_ptr<HICON>(p, handle_deleter());
ICONINFO info;
::GetIconInfo(handle, &info);
size_.width = (info.xHotspot << 1);
size_.height = (info.yHotspot << 1);
::DeleteObject(info.hbmColor);
::DeleteObject(info.hbmMask);
return true;
}
#endif
return false;
}
bool image_ico::alpha_channel() const
{
return false;
}
bool image_ico::empty() const
{
return (nullptr == ptr_);
}
void image_ico::close()
{
ptr_.reset();
}
nana::size image_ico::size() const
{
return size_;
}
void image_ico::paste(const nana::rectangle& src_r, graph_reference graph, int x, int y) const
{
if(ptr_ && (graph.empty() == false))
{
#if defined(NANA_WINDOWS)
::DrawIconEx(graph.handle()->context, x, y, *ptr_, src_r.width, src_r.height, 0, 0, DI_NORMAL);
#endif
}
}
void image_ico::stretch(const nana::rectangle&, graph_reference graph, const nana::rectangle& r) const
{
if(ptr_ && (graph.empty() == false))
{
#if defined(NANA_WINDOWS)
::DrawIconEx(graph.handle()->context, r.x, r.y, *ptr_, r.width, r.height, 0, 0, DI_NORMAL);
#endif
}
}
const image_ico::ptr_t& image_ico::ptr() const
{
return ptr_;
}
#if defined(NANA_WINDOWS)
//struct handle_deleter
void image_ico::handle_deleter::operator()(HICON* p) const
{
if(p && *p)
::DestroyIcon(*p);
delete p;
}
//end struct handle_deleter
#endif
//end class image_ico
}
image::image_impl_interface::~image_impl_interface()
{}
namespace detail
{
int toupper(int c)
{
return (('a' <= c && c <= 'z') ?
c - ('a' - 'A')
: c);
}
}//end namespace detail
//class image
image::image()
{}
image::image(const image& rhs)
: image_ptr_(rhs.image_ptr_)
{}
image::image(image&& r)
: image_ptr_(std::move(r.image_ptr_))
{}
image::image(const nana::char_t* file)
{
if(file)
open(file);
}
image::image(const nana::string& file)
{
this->open(file);
}
image::~image()
{
close();
}
image& image::operator=(const image& r)
{
if(this != &r)
image_ptr_ = r.image_ptr_;
return * this;
}
image& image::operator=(image&& r)
{
if(this != &r)
image_ptr_ = std::move(r.image_ptr_);
return *this;
}
bool image::open(const nana::string& filename)
{
image_ptr_.reset();
image::image_impl_interface * helper = nullptr;
if(filename.size())
{
nana::string fn;
std::transform(filename.cbegin(), filename.cend(), std::back_inserter(fn), detail::toupper);
if(filename.size() >= 4)
{
nana::string suffix = fn.substr(fn.size() - 4);
if(STR(".ICO") == suffix)
{
#if defined(NANA_WINDOWS)
helper = new detail::image_ico(true);
#endif
}
#if defined(NANA_ENABLE_PNG)
else if(STR(".PNG") == suffix)
helper = new detail::image_png;
#endif
}
if(0 == helper)
{
#if defined(NANA_UNICODE)
std::ifstream ifs(std::string(nana::charset(filename)).c_str(), std::ios::binary);
#else
std::ifstream ifs(filename.c_str(), std::ios::binary);
#endif
if(ifs)
{
unsigned short meta = 0;
ifs.read(reinterpret_cast<char*>(&meta), 2);
if(*reinterpret_cast<const short*>("BM") == meta)
helper = new detail::image_bmp;
else if(*reinterpret_cast<const short*>("MZ") == meta)
helper = new detail::image_ico(false);
}
}
if(helper)
{
image_ptr_ = std::shared_ptr<image_impl_interface>(helper);
return helper->open(filename.data());
}
}
return false;
}
bool image::empty() const
{
return ((nullptr == image_ptr_) || image_ptr_->empty());
}
image::operator unspecified_bool_t() const
{
return (image_ptr_ ? &image::empty : nullptr);
}
void image::close()
{
image_ptr_.reset();
}
nana::size image::size() const
{
return (image_ptr_ ? image_ptr_->size() : nana::size());
}
void image::paste(graphics& dst, int x, int y) const
{
if(image_ptr_)
image_ptr_->paste(image_ptr_->size(), dst, x, y);
}
void image::paste(const nana::rectangle& r_src, graphics & dst, const nana::point& p_dst) const
{
if(image_ptr_)
image_ptr_->paste(r_src, dst, p_dst.x, p_dst.y);
}
void image::stretch(const nana::rectangle& r_src, graphics& dst, const nana::rectangle & r_dst) const
{
if(image_ptr_)
image_ptr_->stretch(r_src, dst, r_dst);
}
//end class image
}//end namespace paint
}//end namespace nana

View File

@@ -0,0 +1,42 @@
#include <nana/paint/image_process_selector.hpp>
namespace nana
{
namespace paint
{
namespace image_process
{
//class selector
void selector::stretch(const std::string& name)
{
detail::image_process_provider & p = detail::image_process_provider::instance();
p.set(p.ref_stretch_tag(), name);
}
void selector::alpha_blend(const std::string& name)
{
detail::image_process_provider & p = detail::image_process_provider::instance();
p.set(p.ref_alpha_blend_tag(), name);
}
void selector::blend(const std::string& name)
{
detail::image_process_provider & p = detail::image_process_provider::instance();
p.set(p.ref_blend_tag(), name);
}
void selector::line(const std::string& name)
{
detail::image_process_provider & p = detail::image_process_provider::instance();
p.set(p.ref_line_tag(), name);
}
void selector::blur(const std::string& name)
{
detail::image_process_provider & p = detail::image_process_provider::instance();
p.set(p.ref_blur_tag(), name);
}
//end class selector
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,590 @@
#include <nana/config.hpp>
#include PLATFORM_SPEC_HPP
#include <nana/paint/text_renderer.hpp>
#include <nana/unicode_bidi.hpp>
#include <nana/paint/detail/native_paint_interface.hpp>
namespace nana
{
namespace paint
{
namespace helper
{
template<typename F>
void for_each_line(const nana::char_t * str, std::size_t len, int top, F & f)
{
auto head = str;
auto end = str + len;
for(auto i = str; i != end; ++i)
{
if(*i == '\n')
{
top += static_cast<int>(f(top, head, i - head));
head = i + 1;
}
}
if(head != end)
f(top, head, end - head);
}
struct draw_string
{
drawable_type dw;
const int x, endpos;
nana::unicode_bidi bidi;
std::vector<nana::unicode_bidi::entity> reordered;
align text_align;
draw_string(drawable_type dw, int x, int endpos, align ta)
: dw(dw), x(x), endpos(endpos), text_align(ta)
{}
unsigned operator()(int top, const nana::char_t * buf, std::size_t bufsize)
{
int xpos = x;
unsigned pixels = 0;
bidi.linestr(buf, bufsize, reordered);
switch(text_align)
{
case align::left:
for(auto & ent : reordered)
{
std::size_t len = ent.end - ent.begin;
nana::size ts = detail::text_extent_size(dw, ent.begin, len);
if(ts.height > pixels) pixels = ts.height;
if(xpos + static_cast<int>(ts.width) > 0)
detail::draw_string(dw, xpos, top, ent.begin, len);
xpos += static_cast<int>(ts.width);
if(xpos >= endpos)
break;
}
break;
case align::center:
{
unsigned lenpx = 0;
std::vector<unsigned> widths;
for(auto & ent : reordered)
{
auto ts = detail::text_extent_size(dw, ent.begin, ent.end - ent.begin);
if(ts.height > pixels) pixels = ts.height;
lenpx += ts.width;
widths.push_back(ts.width);
}
xpos += (endpos - xpos - static_cast<int>(lenpx))/2;
auto ipx = widths.begin();
for(auto & ent : reordered)
{
if(xpos + static_cast<int>(*ipx) > 0)
detail::draw_string(dw, xpos, top, ent.begin, ent.end - ent.begin);
xpos += static_cast<int>(*ipx);
if(xpos >= endpos)
break;
}
}
break;
case align::right:
{
int xend = endpos;
std::swap(xpos, xend);
for(auto i = reordered.rbegin(), end = reordered.rend(); i != end; ++i)
{
auto & ent = *i;
std::size_t len = ent.end - ent.begin;
nana::size ts = detail::text_extent_size(dw, ent.begin, len);
if(ts.height > pixels) pixels = ts.height;
if(xpos > xend)
{
xpos -= static_cast<int>(ts.width);
detail::draw_string(dw, xpos, top, i->begin, len);
}
if(xpos <= xend || xpos <= 0)
break;
}
}
break;
}
return pixels;
}
};
struct draw_string_omitted
{
graphics & graph;
int x, endpos;
nana::color_t color;
unsigned omitted_pixels;
nana::unicode_bidi bidi;
std::vector<nana::unicode_bidi::entity> reordered;
draw_string_omitted(graphics& graph, int x, int endpos, nana::color_t color, bool omitted)
: graph(graph), x(x), endpos(endpos), color(color)
{
omitted_pixels = (omitted ? graph.text_extent_size(STR("..."), 3).width : 0);
if(endpos - x > static_cast<int>(omitted_pixels))
this->endpos -= omitted_pixels;
else
this->endpos = x;
}
unsigned operator()(int top, const nana::char_t * buf, std::size_t bufsize)
{
drawable_type dw = graph.handle();
int xpos = x;
unsigned pixels = 0;
bidi.linestr(buf, bufsize, reordered);
for(auto & i : reordered)
{
std::size_t len = i.end - i.begin;
nana::size ts = detail::text_extent_size(dw, i.begin, len);
if(ts.height > pixels) pixels = ts.height;
if(xpos + static_cast<int>(ts.width) <= endpos)
{
detail::draw_string(dw, xpos, top, i.begin, len);
xpos += static_cast<int>(ts.width);
}
else
{
nana::rectangle r;
r.width = endpos - xpos;
r.height = ts.height;
nana::paint::graphics dum_graph(r.width, r.height);
dum_graph.bitblt(r, graph, nana::point(xpos, top));
dum_graph.string(0, 0, color, i.begin, len);
r.x = xpos;
r.y = top;
graph.bitblt(r, dum_graph);
if(omitted_pixels)
detail::draw_string(dw, endpos, top, STR("..."), 3);
break;
}
}
return pixels;
}
};
struct draw_string_auto_changing_lines
{
graphics & graph;
int x, endpos;
nana::unicode_bidi bidi;
std::vector<nana::unicode_bidi::entity> reordered;
std::vector<nana::size> ts_keeper;
align text_align;
draw_string_auto_changing_lines(graphics& graph, int x, int endpos, align ta)
: graph(graph), x(x), endpos(endpos), text_align(ta)
{}
unsigned operator()(int top, const nana::char_t * buf, std::size_t bufsize)
{
unsigned pixels = 0;
drawable_type dw = graph.handle();
unsigned str_w = 0;
ts_keeper.clear();
bidi.linestr(buf, bufsize, reordered);
for(auto & i : reordered)
{
nana::size ts = detail::text_extent_size(dw, i.begin, i.end - i.begin);
if(ts.height > pixels) pixels = ts.height;
ts_keeper.push_back(ts);
str_w += ts.width;
}
//Test whether the text needs the new line.
if(x + static_cast<int>(str_w) > endpos)
{
pixels = 0;
unsigned line_pixels = 0;
int xpos = x;
int orig_top = top;
auto i_ts_keeper = ts_keeper.cbegin();
for(auto & i : reordered)
{
if(line_pixels < i_ts_keeper->height)
line_pixels = i_ts_keeper->height;
bool beyond_edge = (xpos + static_cast<int>(i_ts_keeper->width) > endpos);
if(beyond_edge)
{
std::size_t len = i.end - i.begin;
if(len > 1)
{
unsigned * pxbuf = new unsigned[len];
//Find the char that should be splitted
graph.glyph_pixels(i.begin, len, pxbuf);
std::size_t idx_head = 0, idx_splitted;
do
{
idx_splitted = find_splitted(idx_head, len, xpos, endpos, pxbuf);
if(idx_splitted == len)
{
detail::draw_string(dw, xpos, top, i.begin + idx_head, idx_splitted - idx_head);
for(std::size_t i = idx_head; i < len; ++i)
xpos += static_cast<int>(pxbuf[i]);
break;
}
//Check the word whether it is splittable.
if(splittable(i.begin, idx_splitted))
{
detail::draw_string(dw, xpos, top, i.begin + idx_head, idx_splitted - idx_head);
idx_head = idx_splitted;
xpos = x;
top += line_pixels;
line_pixels = i_ts_keeper->height;
}
else
{
//Search the splittable character from idx_head to idx_splitted
const nana::char_t * u = i.begin + idx_splitted;
const nana::char_t * head = i.begin + idx_head;
for(; head < u; --u)
{
if(splittable(head, u - head))
break;
}
if(u != head)
{
detail::draw_string(dw, xpos, top, head, u - head);
idx_head += u - head;
xpos = x;
top += line_pixels;
line_pixels = i_ts_keeper->height;
}
else
{
u = i.begin + idx_splitted;
const nana::char_t * end = i.begin + len;
for(; u < end; ++u)
{
if(splittable(head, u - head))
break;
}
std::size_t splen = u - head;
top += line_pixels;
xpos = x;
detail::draw_string(dw, x, top, head, splen);
line_pixels = i_ts_keeper->height;
for(std::size_t k = idx_head; k < idx_head + splen; ++k)
xpos += static_cast<int>(pxbuf[k]);
if(xpos >= endpos)
{
xpos = x;
top += line_pixels;
line_pixels = i_ts_keeper->height;
}
idx_head += splen;
}
}
}while(idx_head < len);
delete [] pxbuf;
}
else
{
detail::draw_string(dw, x, top += static_cast<int>(line_pixels), i.begin, 1);
xpos = x + static_cast<int>(i_ts_keeper->width);
}
line_pixels = 0;
}
else
{
detail::draw_string(dw, xpos, top, i.begin, i.end - i.begin);
xpos += static_cast<int>(i_ts_keeper->width);
}
++i_ts_keeper;
}
pixels = (top - orig_top) + line_pixels;
}
else
{
//The text could be drawn in a line.
if((align::left == text_align) || (align::center == text_align))
{
int xpos = x;
if(align::center == text_align)
xpos += (endpos - x - static_cast<int>(str_w)) / 2;
auto i_ts_keeper = ts_keeper.cbegin();
for(auto & ent : reordered)
{
const nana::size & ts = *i_ts_keeper;
if(xpos + static_cast<int>(ts.width) > 0)
detail::draw_string(dw, xpos, top, ent.begin, ent.end - ent.begin);
xpos += static_cast<int>(ts.width);
++i_ts_keeper;
}
}
else if(align::right == text_align)
{
int xpos = endpos;
auto i_ts_keeper = ts_keeper.crbegin();
for(auto i = reordered.crbegin(), end = reordered.crend(); i != end; ++i)
{
auto & ent = *i;
std::size_t len = ent.end - ent.begin;
const nana::size & ts = *i_ts_keeper;
xpos -= ts.width;
if(xpos >= 0)
detail::draw_string(dw, xpos, top, ent.begin, len);
++i_ts_keeper;
}
}
}
return pixels;
}
static std::size_t find_splitted(std::size_t begin, std::size_t end, int x, int endpos, unsigned * pxbuf)
{
unsigned acc_width = 0;
for(std::size_t i = begin; i < end; ++i)
{
if(x + static_cast<int>(acc_width + pxbuf[i]) > endpos)
{
if(i == begin)
++i;
return i;
}
acc_width += pxbuf[i];
}
return end;
}
static bool splittable(const nana::char_t * str, std::size_t index)
{
nana::char_t ch = str[index];
if(('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z'))
{
nana::char_t prch;
if(index)
{
prch = str[index - 1];
if('0' <= ch && ch <= '9')
return !(('0' <= prch && prch <= '9') || (str[index - 1] == '-'));
return (('z' < prch || prch < 'a') && ('Z' < prch || prch < 'A'));
}
else
return false;
}
return true;
}
};
struct extent_auto_changing_lines
{
graphics & graph;
int x, endpos;
nana::unicode_bidi bidi;
std::vector<nana::unicode_bidi::entity> reordered;
std::vector<nana::size> ts_keeper;
unsigned extents;
extent_auto_changing_lines(graphics& graph, int x, int endpos)
: graph(graph), x(x), endpos(endpos), extents(0)
{}
unsigned operator()(int top, const nana::char_t * buf, std::size_t bufsize)
{
unsigned pixels = 0;
drawable_type dw = graph.handle();
unsigned str_w = 0;
ts_keeper.clear();
bidi.linestr(buf, bufsize, reordered);
for(auto & i : reordered)
{
nana::size ts = detail::text_extent_size(dw, i.begin, i.end - i.begin);
ts_keeper.push_back(ts);
str_w += ts.width;
}
auto i_ts_keeper = ts_keeper.cbegin();
//Test whether the text needs the new line.
if(x + static_cast<int>(str_w) > endpos)
{
unsigned line_pixels = 0;
int xpos = x;
int orig_top = top;
for(auto & i : reordered)
{
if(line_pixels < i_ts_keeper->height)
line_pixels = i_ts_keeper->height;
bool beyond_edge = (xpos + static_cast<int>(i_ts_keeper->width) > endpos);
if(beyond_edge)
{
std::size_t len = i.end - i.begin;
if(len > 1)
{
unsigned * pxbuf = new unsigned[len];
//Find the char that should be splitted
graph.glyph_pixels(i.begin, len, pxbuf);
std::size_t idx_head = 0, idx_splitted;
do
{
idx_splitted = draw_string_auto_changing_lines::find_splitted(idx_head, len, xpos, endpos, pxbuf);
if(idx_splitted == len)
{
for(std::size_t i = idx_head; i < len; ++i)
xpos += static_cast<int>(pxbuf[i]);
break;
}
//Check the word whether it is splittable.
if(draw_string_auto_changing_lines::splittable(i.begin, idx_splitted))
{
idx_head = idx_splitted;
xpos = x;
top += line_pixels;
line_pixels = i_ts_keeper->height;
}
else
{
//Search the splittable character from idx_head to idx_splitted
const nana::char_t * u = i.begin + idx_splitted;
const nana::char_t * head = i.begin + idx_head;
for(; head < u; --u)
{
if(draw_string_auto_changing_lines::splittable(head, u - head))
break;
}
if(u != head)
{
idx_head += u - head;
xpos = x;
top += line_pixels;
line_pixels = i_ts_keeper->height;
}
else
{
u = i.begin + idx_splitted;
const nana::char_t * end = i.begin + len;
for(; u < end; ++u)
{
if(draw_string_auto_changing_lines::splittable(head, u - head))
break;
}
std::size_t splen = u - head;
top += line_pixels;
xpos = x;
line_pixels = i_ts_keeper->height;
for(std::size_t k = idx_head; k < idx_head + splen; ++k)
xpos += static_cast<int>(pxbuf[k]);
if(xpos >= endpos)
{
xpos = x;
top += line_pixels;
line_pixels = i_ts_keeper->height;
}
idx_head += splen;
}
}
}while(idx_head < len);
delete [] pxbuf;
}
else
xpos = x + static_cast<int>(i_ts_keeper->width);
line_pixels = 0;
}
else
xpos += static_cast<int>(i_ts_keeper->width);
++i_ts_keeper;
}
pixels = (top - orig_top) + line_pixels;
}
else
{
while(i_ts_keeper != ts_keeper.cend())
{
const nana::size & ts = *(i_ts_keeper++);
if(ts.height > pixels) pixels = ts.height;
}
}
extents += pixels;
return pixels;
}
};
}//end namespace helper
//class text_renderer
text_renderer::text_renderer(graph_reference graph, align ta)
: graph_(graph), text_align_(ta)
{}
void text_renderer::render(int x, int y, nana::color_t col, const nana::char_t * str, std::size_t len)
{
if(graph_)
{
helper::draw_string ds(graph_.handle(), x, static_cast<int>(graph_.width()), text_align_);
ds.dw->fgcolor(col);
helper::for_each_line(str, len, y, ds);
}
}
void text_renderer::render(int x, int y, nana::color_t col, const nana::char_t * str, std::size_t len, unsigned restricted_pixels, bool omitted)
{
if(graph_)
{
helper::draw_string_omitted dso(graph_, x, x + static_cast<int>(restricted_pixels), col, omitted);
graph_.handle()->fgcolor(col);
helper::for_each_line(str, len, y, dso);
}
}
void text_renderer::render(int x, int y, nana::color_t col, const nana::char_t * str, std::size_t len, unsigned restricted_pixels)
{
if(graph_)
{
helper::draw_string_auto_changing_lines dsacl(graph_, x, x + static_cast<int>(restricted_pixels), text_align_);
graph_.handle()->fgcolor(col);
helper::for_each_line(str, len, y, dsacl);
}
}
nana::size text_renderer::extent_size(int x, int y, const nana::char_t* str, std::size_t len, unsigned restricted_pixels) const
{
nana::size extents;
if(graph_)
{
helper::extent_auto_changing_lines eacl(graph_, x, x + static_cast<int>(restricted_pixels));
helper::for_each_line(str, len, y, eacl);
extents.width = restricted_pixels;
extents.height = eacl.extents;
}
return extents;
}
//end class text_renderer
}
}