first init of 0.9
This commit is contained in:
119
source/paint/detail/image_process_provider.cpp
Normal file
119
source/paint/detail/image_process_provider.cpp
Normal 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
|
||||
230
source/paint/detail/native_paint_interface.cpp
Normal file
230
source/paint/detail/native_paint_interface.cpp
Normal 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
316
source/paint/gadget.cpp
Normal 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
1189
source/paint/graphics.cpp
Normal file
File diff suppressed because it is too large
Load Diff
276
source/paint/image.cpp
Normal file
276
source/paint/image.cpp
Normal 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
|
||||
|
||||
42
source/paint/image_process_selector.cpp
Normal file
42
source/paint/image_process_selector.cpp
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
1130
source/paint/pixel_buffer.cpp
Normal file
1130
source/paint/pixel_buffer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
590
source/paint/text_renderer.cpp
Normal file
590
source/paint/text_renderer.cpp
Normal 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
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user