diff --git a/build/cmake/CMakeLists.txt b/build/cmake/CMakeLists.txt new file mode 100644 index 00000000..e04ee417 --- /dev/null +++ b/build/cmake/CMakeLists.txt @@ -0,0 +1,50 @@ +# CMake configuration for Nana +# Author: ierofant(https://github.com/ierofant) + +project(nana) +cmake_minimum_required(VERSION 2.8) + +string(REGEX REPLACE "/[^/]*$" "" CMAKE_SOURCE_DIR ${CMAKE_SOURCE_DIR}) +string(REGEX REPLACE "/[^/]*$" "" CMAKE_SOURCE_DIR ${CMAKE_SOURCE_DIR}) + +set(NANA_SOURCE_DIR ${CMAKE_SOURCE_DIR}/source) +set(NANA_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include) + +if(CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall") +endif(CMAKE_COMPILER_IS_GNUCXX) + +include_directories(${NANA_INCLUDE_DIR}) +aux_source_directory(${NANA_SOURCE_DIR} NANA_SOURCE) +aux_source_directory(${NANA_SOURCE_DIR}/detail NANA_DETAIL_SOURCE) +aux_source_directory(${NANA_SOURCE_DIR}/filesystem NANA_FILESYSTEM_SOURCE) +aux_source_directory(${NANA_SOURCE_DIR}/audio NANA_AUDIO_SOURCE) +aux_source_directory(${NANA_SOURCE_DIR}/audio/detail NANA_AUDIO_DETAIL_SOURCE) +aux_source_directory(${NANA_SOURCE_DIR}/gui NANA_GUI_SOURCE) +aux_source_directory(${NANA_SOURCE_DIR}/gui/detail NANA_GUI_DETAIL_SOURCE) +aux_source_directory(${NANA_SOURCE_DIR}/gui/widgets NANA_GUI_WIDGETS_SOURCE) +aux_source_directory(${NANA_SOURCE_DIR}/gui/widgets/skeletons NANA_GUI_WIDGETS_SKELETONS_SOURCE) +aux_source_directory(${NANA_SOURCE_DIR}/paint NANA_PAINT_SOURCE) +aux_source_directory(${NANA_SOURCE_DIR}/paint/detail NANA_PAINT_DETAIL_SOURCE) +aux_source_directory(${NANA_SOURCE_DIR}/system NANA_SYSTEM_SOURCE) +aux_source_directory(${NANA_SOURCE_DIR}/threads NANA_THREADS_SOURCE) + +add_library(${PROJECT_NAME} ${NANA_SOURCE} + ${NANA_DETAIL_SOURCE} + ${NANA_FILESYSTEM_SOURCE} + ${NANA_AUDIO_SOURCE} + ${NANA_AUDIO_DETAIL_SOURCE} + ${NANA_GUI_SOURCE} + ${NANA_GUI_DETAIL_SOURCE} + ${NANA_GUI_WIDGETS_SOURCE} + ${NANA_GUI_WIDGETS_SKELETONS_SOURCE} + ${NANA_PAINT_SOURCE} + ${NANA_PAINT_DETAIL_SOURCE} + ${NANA_SYSTEM_SOURCE} + ${NANA_THREADS_SOURCE}) + + +install(TARGETS ${PROJECT_NAME} + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib) +install(DIRECTORY ${NANA_INCLUDE_DIR}/nana DESTINATION include) \ No newline at end of file diff --git a/build/codeblocks/nana.cbp b/build/codeblocks/nana.cbp index b2021965..83985a24 100644 --- a/build/codeblocks/nana.cbp +++ b/build/codeblocks/nana.cbp @@ -52,6 +52,7 @@ + @@ -68,6 +69,7 @@ + @@ -89,6 +91,7 @@ + diff --git a/build/codeblocks/nana.layout b/build/codeblocks/nana.layout index 469d6a54..57a19817 100644 --- a/build/codeblocks/nana.layout +++ b/build/codeblocks/nana.layout @@ -1,39 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - - - - - - - - - - - + @@ -41,6 +81,11 @@ + + + + + @@ -56,9 +101,9 @@ - + - + @@ -66,9 +111,9 @@ - + - + @@ -76,79 +121,34 @@ + + + + + + + + + + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/build/vc2013/nana.vcxproj b/build/vc2013/nana.vcxproj index 292712b0..d6b6e976 100644 --- a/build/vc2013/nana.vcxproj +++ b/build/vc2013/nana.vcxproj @@ -99,6 +99,7 @@ + @@ -116,6 +117,7 @@ + @@ -137,6 +139,7 @@ + diff --git a/build/vc2013/nana.vcxproj.filters b/build/vc2013/nana.vcxproj.filters index 3309f037..f0f82981 100644 --- a/build/vc2013/nana.vcxproj.filters +++ b/build/vc2013/nana.vcxproj.filters @@ -291,5 +291,14 @@ Source Files\nana + + Source Files\nana\gui\detail + + + Source Files\nana\gui + + + Source Files\nana\gui\widgets + \ No newline at end of file diff --git a/include/nana/basic_types.hpp b/include/nana/basic_types.hpp index 05088e89..9a2d85f2 100644 --- a/include/nana/basic_types.hpp +++ b/include/nana/basic_types.hpp @@ -1,7 +1,7 @@ /* * Basic Types definition * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -14,6 +14,7 @@ #define NANA_BASIC_TYPES_HPP #include +#include namespace nana { @@ -98,27 +99,251 @@ namespace nana typedef unsigned char uint8_t; typedef unsigned long uint32_t; typedef unsigned uint_t; - typedef unsigned color_t; typedef long long long_long_t; - const color_t null_color = 0xFFFFFFFF; - - struct pixel_rgb_t + union pixel_argb_t { - union + struct element_tag { - struct element_tag - { - unsigned int blue:8; - unsigned int green:8; - unsigned int red:8; - unsigned int alpha_channel:8; - }element; - - color_t color; - }u; + unsigned char blue; + unsigned char green; + unsigned char red; + unsigned char alpha_channel; + }element; + unsigned value; }; + union pixel_rgba_t + { + struct element_tag + { + unsigned char alpha_channel; + unsigned char blue; + unsigned char green; + unsigned char red; + }element; + unsigned value; + }; + + using pixel_color_t = pixel_argb_t; + + //http://www.w3.org/TR/2011/REC-css3-color-20110607/ + //4.3. Extended color keywords + enum class colors + { + alice_blue = 0xf0f8ff, + antique_white = 0xfaebd7, + aqua = 0xFFFF, + aquamarine = 0x7fffd4, + azure = 0xf0ffff, + beige = 0xf5f5dc, + bisque = 0xffe4ce, + black = 0x0, + blanched_almond = 0xffebcd, + blue = 0x0000FF, + blue_violet = 0x8a2be2, + brown = 0xa52a2a, + burly_wood = 0xdeb887, + cadet_blue = 0x5f9ea0, + chartreuse = 0x7fff00, + chocolate = 0xd2691e, + coral = 0xff7f50, + cornflower_blue = 0x6495ed, + cornsilk = 0xfff8dc, + crimson = 0xdc143c, + cyan = 0xffff, + dark_blue = 0x8b, + dark_cyan = 0x8b8b, + dark_goldenrod = 0xb8860b, + dark_gray = 0xa9a9a9, + dark_green = 0x6400, + dark_grey = dark_gray, + dark_khaki = 0xbdb76b, + dark_magenta = 0x8b008b, + dark_olive_green = 0x556b2f, + dark_orange = 0xff8c00, + dark_orchid = 0x9932cc, + dark_red = 0x8b0000, + dark_salmon = 0xe9976a, + dark_sea_green = 0x8fbc8f, + dark_slate_blue = 0x483d8b, + dark_slate_gray = 0x2f4f4f, + dark_slate_grey = 0x2f4f4f, + dark_turquoise = 0xced1, + dark_violet = 0x9400d3, + deep_pink = 0xff1493, + deep_sky_blue = 0xbfff, + dim_gray = 0x696969, + dim_grey = dim_gray, + dodger_blue = 0x1e90ff, + firebrick = 0xb22222, + floral_white = 0xfffaf0, + forest_green = 0x228b22, + fuchsia = 0xFF00FF, + gainsboro = 0xdcdcdc, + ghost_white = 0xf8f8ff, + gold = 0xffd700, + goldenrod = 0xdaa520, + gray = 0x808080, + green = 0x008000, + green_yellow = 0xadff2f, + grey = gray, + honeydew = 0xf0fff0, + hot_pink = 0xff69b4, + indian_red = 0xcd5c5c, + indigo = 0x4b0082, + ivory = 0xfffff0, + khaki = 0xf0e68c, + lavendar = 0xe6e6fa, + lavender_blush = 0xfff0f5, + lawn_green = 0x7cfc00, + lemon_chiffon = 0xfffacd, + light_blue = 0xadd8e6, + light_coral = 0xf08080, + light_cyan = 0xe0ffff, + light_goldenrod_yellow = 0xfafad2, + light_gray = 0xd3d3d3, + light_green = 0x90ee90, + light_grey = light_gray, + light_pink = 0xffb6c1, + light_salmon = 0xffa07a, + light_sea_green = 0x20b2aa, + light_sky_blue = 0x87cefa, + light_slate_gray = 0x778899, + light_slate_grey = light_slate_gray, + light_steel_blue = 0xb0c4de, + light_yellow = 0xffffe0, + lime = 0x00FF00, + lime_green = 0x32cd32, + linen = 0xfaf0e6, + magenta = 0xff00ff, + maroon = 0x800000, + medium_aquamarine = 0x66cdaa, + medium_blue = 0xcd, + medium_orchid = 0xba55d3, + medium_purple = 0x9370db, + medium_sea_green = 0x3cb371, + medium_slate_blue = 0x7b68ee, + medium_spring_green = 0xfa9a, + medium_turquoise = 0x48d1cc, + medium_violet_red = 0xc71585, + midnight_blue = 0x191970, + mint_cream = 0xf5fffa, + + misty_rose = 0xffe4e1, + moccasin = 0xffe4b5, + navajo_white = 0xffdead, + navy = 0x000080, + old_lace = 0xfdf5e6, + olive = 0x808000, + olive_drab = 0x6b8e23, + orange = 0xffa500, + orange_red = 0xff4500, + orchid = 0xda70d6, + pale_goldenrod = 0xeee8aa, + pale_green = 0x98fb98, + pale_turquoise = 0xafeeee, + pale_violet_red = 0xdb7093, + papaya_whip = 0xffefd5, + peach_puff = 0xffdab9, + peru = 0xcd853f, + pink = 0xffc0cb, + plum = 0xdda0dd, + powder_blue = 0xb0e0e6, + purple = 0x800080, + red = 0xFF0000, + rosy_brown = 0xbc8f8f, + royal_blue = 0x4169e1, + saddle_brown = 0x8b4513, + salmon = 0xfa8072, + sandy_brown = 0xf4a460, + sea_green = 0x2e8b57, + sea_shell = 0xfff5ee, + sienna = 0xa0522d, + silver = 0xc0c0c0, + sky_blue = 0x87ceeb, + slate_blue = 0x6a5acd, + slate_gray = 0x708090, + slate_grey = 0x708090, + snow = 0xfffafa, + spring_green = 0xff7f, + steel_blue = 0x4682b4, + tan = 0xd2b48c, + teal = 0x008080, + thistle = 0xd8bfd8, + tomato = 0xff6347, + turquoise = 0x40e0d0, + violet = 0xee82ee, + wheat = 0xf5deb3, + white = 0xFFFFFF, + white_smoke = 0xf5f5f5, + yellow = 0xFFFF00, + yellow_green = 0x9acd32, + + //temporary defintions, these will be replaced by color schema + button_face_shadow_start = 0xF5F4F2, + button_face_shadow_end = 0xD5D2CA, + button_face = 0xD4D0C8, + dark_border = 0x404040, + gray_border = 0x808080, + highlight = 0x1CC4F7 + }; + + //Some helper types to identify an integer as color. + enum class color_rgb : unsigned{}; + enum class color_argb: unsigned{}; + enum class color_rgba : unsigned{}; + + class color + { + public: + color() = default; + color(colors); + color(colors, double alpha); + color(color_rgb); + color(color_argb); + color(color_rgba); + color(unsigned red, unsigned green, unsigned blue); + color(unsigned red, unsigned green, unsigned blue, double alpha); + + /// Initializes the color with a CSS-like rgb string. + color(std::string css_rgb); + + color& alpha(double); ///< Sets alpha channel + color& from_rgb(unsigned red, unsigned green, unsigned blue); ///< immutable alpha channel + + /// Sets color with a HSL value. + /// @param hue in range of [0, 360] + /// @param saturation in range of [0, 1] + /// @param lightness in range of [0, 1] + color& from_hsl(double hue, double saturation, double lightness); ///< immutable alpha channel + + color blend(const color& bgcolor, bool ignore_bgcolor_alpha) const; + + ///< Blends two colors with the specified alpha, and the alpha values that come with these two colors are both ignored. + color blend(const color& bgcolor, double alpha) const; + + ///< Determines whether the color is completely transparent. + bool invisible() const; + pixel_color_t px_color() const; + pixel_argb_t argb() const; + pixel_rgba_t rgba() const; + + const double& r() const; + const double& g() const; + const double& b() const; + const double& a() const; + + bool operator==(const color& other) const; + bool operator!=(const color& other) const; + private: + double r_; + double g_; + double b_; + double a_{ 0.0 }; //invisible + }; + + struct rectangle; struct point @@ -163,8 +388,9 @@ namespace nana struct size { + using value_type = unsigned; size(); - size(unsigned width, unsigned height); + size(value_type width, value_type height); size(const rectangle&); size& operator=(const rectangle&); @@ -175,8 +401,8 @@ namespace nana bool operator!=(const size& rhs) const; size operator+(const size&) const; - unsigned width; - unsigned height; + value_type width; + value_type height; }; struct rectangle @@ -247,6 +473,16 @@ namespace nana { top, center, bottom }; + + ///The definition of the four corners of the world + enum class direction + { + north, + south, + east, + west, + southeast + }; }//end namespace nana #endif diff --git a/include/nana/config.hpp b/include/nana/config.hpp index 8c25d372..418871f1 100644 --- a/include/nana/config.hpp +++ b/include/nana/config.hpp @@ -18,7 +18,6 @@ //Windows: #define NANA_WINDOWS 1 #define PLATFORM_SPEC_HPP - #define GUI_BEDROCK_HPP //Test if it is MINGW #if defined(__MINGW32__) @@ -31,8 +30,6 @@ #define NANA_LINUX 1 #define NANA_X11 1 #define PLATFORM_SPEC_HPP - #define GUI_BEDROCK_HPP - #define STD_CODECVT_NOT_SUPPORTED #endif diff --git a/include/nana/deploy.hpp b/include/nana/deploy.hpp index 66fe0cfe..d417d06d 100644 --- a/include/nana/deploy.hpp +++ b/include/nana/deploy.hpp @@ -42,6 +42,14 @@ namespace nana std::size_t strlen(const char_t* str); double strtod(const char_t* str, char_t** endptr); char_t* strcpy(char_t* dest, const char_t* source); + + //Workaround for no implemenation of std::stoi in MinGW. + int stoi(const std::string&, std::size_t * pos = nullptr, int base = 10); + int stoi(const std::wstring&, std::size_t* pos = nullptr, int base = 10); + + //Workaround for no implemenation of std::stod in MinGW. + double stod(const std::string&, std::size_t * pos = nullptr); + double stod(const std::wstring&, std::size_t* pos = nullptr); } #if defined(NANA_WINDOWS) diff --git a/include/nana/detail/linux_X11/platform_spec.hpp b/include/nana/detail/linux_X11/platform_spec.hpp index be306f5c..ae4a1830 100644 --- a/include/nana/detail/linux_X11/platform_spec.hpp +++ b/include/nana/detail/linux_X11/platform_spec.hpp @@ -85,11 +85,6 @@ namespace detail { typedef std::shared_ptr font_ptr_t; - drawable_impl_type(); - ~drawable_impl_type(); - - void fgcolor(unsigned color); - Pixmap pixmap; GC context; font_ptr_t font; @@ -107,8 +102,20 @@ namespace detail XftColor xft_fgcolor; const std::string charset(const nana::string& str, const std::string& strcode); #endif + drawable_impl_type(); + ~drawable_impl_type(); + + void fgcolor(const ::nana::color&); //deprecated + void set_color(const ::nana::color&); + void set_text_color(const ::nana::color&); + + void update_color(); + void update_text_color(); private: - unsigned fgcolor_{0xFFFFFFFF}; + unsigned current_color_{ 0xFFFFFF }; + unsigned color_{ 0xFFFFFFFF }; + unsigned text_color_{ 0xFFFFFFFF }; + #if defined(NANA_UNICODE) struct conv_tag { @@ -217,9 +224,9 @@ namespace detail void read_keystate(XKeyEvent&); XIC caret_input_context(native_window_type) const; - void caret_open(native_window_type, unsigned width, unsigned height); + void caret_open(native_window_type, const ::nana::size&); void caret_close(native_window_type); - void caret_pos(native_window_type, int x, int y); + void caret_pos(native_window_type, const ::nana::point&); void caret_visible(native_window_type, bool); void caret_flash(caret_tag&); bool caret_update(native_window_type, nana::paint::graphics& root_graph, bool is_erase_caret_from_root_graph); diff --git a/include/nana/detail/win32/platform_spec.hpp b/include/nana/detail/win32/platform_spec.hpp index cb4be1fd..9e735f99 100644 --- a/include/nana/detail/win32/platform_spec.hpp +++ b/include/nana/detail/win32/platform_spec.hpp @@ -1,6 +1,7 @@ /* * Platform Specification Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -91,8 +92,8 @@ namespace detail HDC context; HBITMAP pixmap; - pixel_rgb_t* pixbuf_ptr; - std::size_t bytes_per_line; + pixel_argb_t* pixbuf_ptr{nullptr}; + std::size_t bytes_per_line{0}; font_ptr_t font; struct pen_spec @@ -102,7 +103,7 @@ namespace detail int style; int width; - void set(HDC context, int style, int width, nana::color_t color); + void set(HDC context, int style, int width,unsigned color); }pen; struct brush_spec @@ -111,9 +112,9 @@ namespace detail HBRUSH handle; t style; - nana::color_t color; + unsigned color; - void set(HDC context, t style, nana::color_t color); + void set(HDC context, t style, unsigned color); }brush; struct round_region_spec @@ -136,9 +137,16 @@ namespace detail drawable_impl_type(); ~drawable_impl_type(); - void fgcolor(nana::color_t); + void fgcolor(const ::nana::color&); //deprecated + unsigned get_color() const; + void set_color(const ::nana::color&); + void set_text_color(const ::nana::color&); + + void update_pen(); + void update_brush(); private: - unsigned fgcolor_; + unsigned color_{ 0xffffffff }; + unsigned text_color_{0xffffffff}; }; class platform_spec diff --git a/include/nana/gui/basis.hpp b/include/nana/gui/basis.hpp index aade6c38..4eb95c88 100644 --- a/include/nana/gui/basis.hpp +++ b/include/nana/gui/basis.hpp @@ -1,7 +1,7 @@ /* * Basis Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -25,6 +25,7 @@ namespace nana struct native_window_handle_impl{}; struct window_handle_impl{}; struct event_handle_impl{}; + struct native_drawable_impl{}; } enum class checkstate @@ -63,56 +64,39 @@ namespace nana struct frame_tag: widget_tag{ static const flags value = flags::frame; }; }// end namespace category - typedef detail::native_window_handle_impl * native_window_type; - - typedef detail::window_handle_impl* window; ///< \see [What is window class ](https://sourceforge.net/p/nanapro/discussion/general/thread/bd0fabfb/) - typedef detail::event_handle_impl* event_handle; + using native_window_type = detail::native_window_handle_impl*; + using window = detail::window_handle_impl*; ///< \see [What is window class ](https://sourceforge.net/p/nanapro/discussion/general/thread/bd0fabfb/) + using event_handle = detail::event_handle_impl*; + using native_drawable_type = detail::native_drawable_impl*; struct keyboard { - enum t{ + enum{ //Control Code for ASCII - select_all = 0x1, - end_of_text = 0x3, //Ctrl+C - backspace = 0x8, tab = 0x9, - enter_n = 0xA, enter = 0xD, enter_r = 0xD, - alt = 0x12, - sync_idel = 0x16, //Ctrl+V - cancel = 0x18, //Ctrl+X - end_of_medium = 0x19, //Ctrl+Y - substitute = 0x1A, //Ctrl+Z - escape = 0x1B, + start_of_headline = 0x1, //Ctrl+A + end_of_text = 0x3, //Ctrl+C + backspace = 0x8, tab = 0x9, + enter_n = 0xA, enter = 0xD, enter_r = 0xD, + alt = 0x12, + sync_idel = 0x16, //Ctrl+V + cancel = 0x18, //Ctrl+X + end_of_medium = 0x19, //Ctrl+Y + substitute = 0x1A, //Ctrl+Z + escape = 0x1B, //The following names are intuitive name of ASCII control codes - copy = 0x3, //end_of_text - paste = 0x16, //sync_idel - cut = 0x18, //cancel - redo = 0x19, //end_of_medium - undo = 0x1A, //substitue + select_all = start_of_headline, + copy = end_of_text, + paste = sync_idel, + cut = cancel, + redo = end_of_medium, + undo = substitute, //System Code for OS - os_pageup = 0x21, os_pagedown, - os_arrow_left = 0x25, os_arrow_up, os_arrow_right, os_arrow_down, - os_insert = 0x2D, os_del - }; - }; - - namespace color - { - enum - { - white = 0xFFFFFF, - blue = 0x0000FF, - green = 0x00FF00, - red = 0xFF0000, - - button_face_shadow_start = 0xF5F4F2, - button_face_shadow_end = 0xD5D2CA, - button_face = 0xD4D0C8, - dark_border = 0x404040, - gray_border = 0x808080, - highlight = 0x1CC4F7 + os_pageup = 0x21, os_pagedown, + os_arrow_left = 0x25, os_arrow_up, os_arrow_right, os_arrow_down, + os_insert = 0x2D, os_del }; }; diff --git a/include/nana/gui/detail/basic_window.hpp b/include/nana/gui/detail/basic_window.hpp index f84e3692..2834c870 100644 --- a/include/nana/gui/detail/basic_window.hpp +++ b/include/nana/gui/detail/basic_window.hpp @@ -1,7 +1,7 @@ /* * A Basic Window Widget Definition * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -14,7 +14,7 @@ #define NANA_GUI_DETAIL_BASIC_WINDOW_HPP #include "drawer.hpp" #include "events_holder.hpp" -#include "../basis.hpp" +#include "widget_colors.hpp" #include #include #include @@ -74,7 +74,7 @@ namespace detail struct basic_window : public events_holder { - typedef std::vector container; + using container = std::vector; struct root_context { @@ -119,6 +119,8 @@ namespace detail bool is_ancestor_of(const basic_window* wd) const; bool visible_parents() const; bool belong_to_lazy() const; + + bool is_draw_through() const; ///< Determines whether it is a draw-through window. public: //Override event_holder bool set_events(const std::shared_ptr&) override; @@ -155,7 +157,7 @@ namespace detail { bool enabled :1; bool dbl_click :1; - bool capture :1; //if mouse button is down, it always receive mouse move even the mouse is out of its rectangle + bool captured :1; //if mouse button is down, it always receive mouse move even the mouse is out of its rectangle bool modal :1; bool take_active:1; //If take_active is false, other.active_window still keeps the focus. bool refreshing :1; @@ -163,7 +165,8 @@ namespace detail bool dropable :1; //Whether the window has make mouse_drop event. bool fullscreen :1; //When the window is maximizing whether it fit for fullscreen. bool borderless :1; - unsigned Reserved :22; + bool make_bground_declared : 1; //explicitly make bground for bground effects + unsigned Reserved :21; unsigned char tab; //indicate a window that can receive the keyboard TAB mouse_action action; }flags; @@ -174,13 +177,8 @@ namespace detail std::shared_ptr events_ptr; general_events* attached_events; }together; - - struct - { - color_t foreground; - color_t background; - color_t active; - }color; + + widget_colors* scheme{ nullptr }; struct { @@ -211,6 +209,8 @@ namespace detail #endif cursor state_cursor{nana::cursor::arrow}; basic_window* state_cursor_window{ nullptr }; + + std::function draw_through; ///< A draw through renderer for root widgets. }; const category::flags category; diff --git a/include/nana/gui/detail/bedrock.hpp b/include/nana/gui/detail/bedrock.hpp index d58cc680..71a52149 100644 --- a/include/nana/gui/detail/bedrock.hpp +++ b/include/nana/gui/detail/bedrock.hpp @@ -1,7 +1,7 @@ /* * A Bedrock Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -16,6 +16,7 @@ #include "events_operation.hpp" #include "runtime_manager.hpp" #include "general_events.hpp" +#include "color_schemes.hpp" #include "internal_scope_guard.hpp" namespace nana @@ -41,7 +42,7 @@ namespace detail ~bedrock(); void pump_event(window, bool is_modal); - void map_thread_root_buffer(core_window_t* ); + void map_thread_root_buffer(core_window_t*, bool forced); static int inc_window(unsigned tid = 0); thread_context* open_thread_context(unsigned tid = 0); thread_context* get_thread_context(unsigned tid = 0); @@ -66,6 +67,7 @@ namespace detail bool whether_keyboard_shortkey() const; element_store& get_element_store() const; + void map_through_widgets(core_window_t*, native_drawable_type); public: void event_expose(core_window_t *, bool exposed); void event_move(core_window_t*, int x, int y); @@ -76,22 +78,27 @@ namespace detail void set_cursor(core_window_t*, nana::cursor, thread_context*); void define_state_cursor(core_window_t*, nana::cursor, thread_context*); void undefine_state_cursor(core_window_t*, thread_context*); + + widget_colors& get_scheme_template(scheme_factory_base&&); + std::unique_ptr make_scheme(scheme_factory_base&&); public: - window_manager_t wd_manager; events_operation evt_operation; + window_manager_t wd_manager; runtime_manager rt_manager; bool emit(event_code, core_window_t*, const arg_mouse&, bool ask_update, thread_context*); - bool emit(event_code, core_window_t*, const event_arg_interface&, bool ask_update, thread_context*); - bool emit_drawer(event_code, core_window_t*, const event_arg_interface&, thread_context*); + bool emit(event_code, core_window_t*, const event_arg&, bool ask_update, thread_context*); + bool emit_drawer(event_code, core_window_t*, const event_arg&, thread_context*); private: - void _m_emit_core(event_code, core_window_t*, bool draw_only, const event_arg_interface&); + void _m_emit_core(event_code, core_window_t*, bool draw_only, const event_arg&); void _m_event_filter(event_code, core_window_t*, thread_context*); void _m_except_handler(); private: static bedrock bedrock_object; + struct pi_data; + pi_data* pi_data_; struct private_impl; private_impl *impl_; };//end class bedrock diff --git a/include/nana/gui/detail/bedrock_pi_data.hpp b/include/nana/gui/detail/bedrock_pi_data.hpp new file mode 100644 index 00000000..b54e658f --- /dev/null +++ b/include/nana/gui/detail/bedrock_pi_data.hpp @@ -0,0 +1,18 @@ +#ifndef NANA_DETAIL_BEDROCK_PI_DATA_HPP +#define NANA_DETAIL_BEDROCK_PI_DATA_HPP + +#include +#include "color_schemes.hpp" + +namespace nana +{ + namespace detail + { + struct bedrock::pi_data + { + color_schemes scheme; + + }; + } +} +#endif diff --git a/include/nana/gui/detail/color_schemes.hpp b/include/nana/gui/detail/color_schemes.hpp new file mode 100644 index 00000000..25f75079 --- /dev/null +++ b/include/nana/gui/detail/color_schemes.hpp @@ -0,0 +1,80 @@ +/* +* Color Schemes +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2014 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/gui/color_schemes.hpp +* @description: +*/ +#ifndef NANA_DETAIL_COLOR_SCHEMES_HPP +#define NANA_DETAIL_COLOR_SCHEMES_HPP + +#include "widget_colors.hpp" +#include + +namespace nana +{ + namespace detail + { + class scheme_factory_base + { + public: + struct factory_identifier{}; + virtual ~scheme_factory_base() = default; + + virtual factory_identifier* get_id() const = 0; + virtual std::unique_ptr create() = 0; + virtual std::unique_ptr create(widget_colors&) = 0; + }; + + template + class scheme_factory + : public scheme_factory_base + { + private: + factory_identifier* get_id() const override + { + return &fid_; + } + + std::unique_ptr create() override + { + return std::unique_ptr(new Scheme); + } + + std::unique_ptr create(widget_colors& other) override + { + return std::unique_ptr{new Scheme(static_cast(other))}; + } + private: + static factory_identifier fid_; + }; + + template + scheme_factory_base::factory_identifier scheme_factory::fid_; + + class color_schemes + { + struct implement; + color_schemes(const color_schemes&) = delete; + color_schemes(color_schemes&&) = delete; + color_schemes& operator=(const color_schemes&) = delete; + color_schemes& operator=(color_schemes&&) = delete; + public: + using scheme = widget_colors; + + color_schemes(); + ~color_schemes(); + + scheme& scheme_template(scheme_factory_base&&); + std::unique_ptr create(scheme_factory_base&&); + private: + implement * impl_; + }; + }//end namespace detail; +}//end namespace nana +#endif \ No newline at end of file diff --git a/include/nana/gui/detail/drawer.hpp b/include/nana/gui/detail/drawer.hpp index 8cb5465a..f6948a45 100644 --- a/include/nana/gui/detail/drawer.hpp +++ b/include/nana/gui/detail/drawer.hpp @@ -1,7 +1,7 @@ /* * A Drawer Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -110,7 +110,7 @@ namespace nana void key_char(const arg_keyboard&); void key_release(const arg_keyboard&); void shortkey(const arg_keyboard&); - void map(window); //Copy the root buffer to screen + void map(window, bool forced); //Copy the root buffer to screen void refresh(); drawer_trigger* realizer() const; void attached(widget&, drawer_trigger&); @@ -123,7 +123,7 @@ namespace nana void _m_bground_pre(); void _m_bground_end(); void _m_draw_dynamic_drawing_object(); - void _m_use_refresh(); + bool _m_lazy_decleared() const; template void _m_emit(event_code evt_code, const Arg& arg, Mfptr mfptr) @@ -139,14 +139,20 @@ namespace nana { realizer_->_m_reset_overrided(); (realizer_->*mfptr)(graphics, arg); - mth_state_[pos] = (realizer_->_m_overrided() ? method_state::overrided : method_state::not_overrided); + + //Check realizer, when the window is closed in that event handler, the drawer will be + //detached and realizer will be a nullptr + if(realizer_) + mth_state_[pos] = (realizer_->_m_overrided() ? method_state::overrided : method_state::not_overrided); } else (realizer_->*mfptr)(graphics, arg); - _m_use_refresh(); - _m_draw_dynamic_drawing_object(); - _m_bground_end(); + if (_m_lazy_decleared()) + { + _m_draw_dynamic_drawing_object(); + _m_bground_end(); + } } } } diff --git a/include/nana/gui/detail/effects_renderer.hpp b/include/nana/gui/detail/effects_renderer.hpp index a3eb42c6..91daf849 100644 --- a/include/nana/gui/detail/effects_renderer.hpp +++ b/include/nana/gui/detail/effects_renderer.hpp @@ -3,7 +3,6 @@ #include #include #include - #include namespace nana{ @@ -12,7 +11,7 @@ namespace nana{ template class edge_nimbus_renderer { - edge_nimbus_renderer(){} + edge_nimbus_renderer() = default; public: typedef CoreWindow core_window_t; typedef window_layout window_layer; @@ -29,7 +28,7 @@ namespace nana{ return 2; } - bool render(core_window_t * wd) + bool render(core_window_t * wd, bool forced) { bool rendered = false; core_window_t * root_wd = wd->root_widget; @@ -44,7 +43,7 @@ namespace nana{ auto graph = root_wd->root_graph; std::vector erase; - std::vector r_set; + std::vector> rd_set; nana::rectangle r; for(auto & action : nimbus) { @@ -53,8 +52,12 @@ namespace nana{ if(action.window == wd) rendered = true; - r_set.push_back(r); - action.rendered = true; + //Avoiding duplicated rendering. If the window is declared to lazy refresh, it should be rendered. + if ((forced && (action.window == wd)) || !action.rendered || (action.window->other.upd_state == core_window_t::update_state::refresh)) + { + rd_set.emplace_back(r, action.window); + action.rendered = true; + } } else if(action.rendered) { @@ -77,13 +80,9 @@ namespace nana{ graph->paste(native, r, r.x, r.y); } - auto visual_iterator = r_set.begin(); //Render - for(auto & action : nimbus) - { - if(action.rendered) - _m_render_edge_nimbus(action.window, *(visual_iterator++)); - } + for (auto & rd : rd_set) + _m_render_edge_nimbus(rd.second, rd.first); } return rendered; } @@ -102,7 +101,7 @@ namespace nana{ nana::rectangle r(visual); r.pare_off(-static_cast(weight())); nana::rectangle good_r; - if(overlap(r, nana::rectangle(wd->root_graph->size()), good_r)) + if(overlap(r, wd->root_graph->size(), good_r)) { if( (good_r.x < wd->pos_root.x) || (good_r.y < wd->pos_root.y) || (good_r.x + good_r.width > visual.x + visual.width) || (good_r.y + good_r.height > visual.y + visual.height)) @@ -110,7 +109,7 @@ namespace nana{ auto graph = wd->root_graph; nana::paint::pixel_buffer pixbuf(graph->handle(), r); - pixel_rgb_t px0, px1, px2, px3; + pixel_argb_t px0, px1, px2, px3; px0 = pixbuf.pixel(0, 0); px1 = pixbuf.pixel(r.width - 1, 0); @@ -120,12 +119,12 @@ namespace nana{ good_r.x = good_r.y = 1; good_r.width = r.width - 2; good_r.height = r.height - 2; - pixbuf.rectangle(good_r, wd->color.active, 0.95, false); + pixbuf.rectangle(good_r, wd->scheme->activated.get_color(), 0.95, false); good_r.x = good_r.y = 0; good_r.width = r.width; good_r.height = r.height; - pixbuf.rectangle(good_r, wd->color.active, 0.4, false); + pixbuf.rectangle(good_r, wd->scheme->activated.get_color(), 0.4, false); pixbuf.pixel(0, 0, px0); pixbuf.pixel(r.width - 1, 0, px1); diff --git a/include/nana/gui/detail/general_events.hpp b/include/nana/gui/detail/general_events.hpp index 486373d8..20dae998 100644 --- a/include/nana/gui/detail/general_events.hpp +++ b/include/nana/gui/detail/general_events.hpp @@ -1,7 +1,7 @@ /* * Definition of General Events * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -28,27 +28,32 @@ namespace nana class event_interface { public: - virtual ~event_interface(){} + virtual ~event_interface() = default; virtual void remove(event_handle) = 0; }; class docker_interface { public: - virtual ~docker_interface(){} + virtual ~docker_interface() = default; virtual event_interface* get_event() const = 0; }; - class event_arg_interface - { - public: - virtual ~event_arg_interface(){} - }; - void events_operation_register(event_handle); void events_operation_cancel(event_handle); }//end namespace detail + class event_arg + { + public: + virtual ~event_arg(); + + void stop_propagation() const; + bool propagation_stopped() const; + private: + mutable bool stop_propagation_{ false }; + }; + struct general_events; template @@ -62,15 +67,16 @@ namespace nana { basic_event * const event_ptr; std::function invoke; - bool flag_entered = false; - bool flag_deleted = false; + bool flag_entered{ false }; + bool flag_deleted{ false }; + bool unignorable{false}; - docker(basic_event * s, std::function && ivk) - : event_ptr(s), invoke(std::move(ivk)) + docker(basic_event * s, std::function && ivk, bool unignorable_flag) + : event_ptr(s), invoke(std::move(ivk)), unignorable(unignorable_flag) {} - docker(basic_event * s, const std::function & ivk) - : event_ptr(s), invoke(ivk) + docker(basic_event * s, const std::function & ivk, bool unignorable_flag) + : event_ptr(s), invoke(ivk), unignorable(unignorable_flag) {} ~docker() @@ -91,8 +97,8 @@ namespace nana if (nullptr == dockers_) dockers_.reset(new std::vector>); - typedef typename std::remove_reference::type prototype; - std::unique_ptr dck(new docker(this, factory::value>::build(std::forward(fn)))); + using prototype = typename std::remove_reference::type; + std::unique_ptr dck(new docker(this, factory::value>::build(std::forward(fn)), false)); auto evt = reinterpret_cast(static_cast(dck.get())); dockers_->emplace(dockers_->begin(), std::move(dck)); detail::events_operation_register(evt); @@ -113,8 +119,8 @@ namespace nana if (nullptr == dockers_) dockers_.reset(new std::vector>); - typedef typename std::remove_reference::type prototype; - std::unique_ptr dck(new docker(this, factory::value>::build(std::forward(fn)))); + using prototype = typename std::remove_reference::type; + std::unique_ptr dck(new docker(this, factory::value>::build(std::forward(fn)), false)); auto evt = reinterpret_cast(static_cast(dck.get())); dockers_->emplace_back(std::move(dck)); detail::events_operation_register(evt); @@ -127,6 +133,24 @@ namespace nana return connect(std::forward(fn)); } + template + event_handle connect_unignorable(Function && fn, bool in_front = false) + { + internal_scope_guard lock; + if (nullptr == dockers_) + dockers_.reset(new std::vector>); + + using prototype = typename std::remove_reference::type; + std::unique_ptr dck(new docker(this, factory::value>::build(std::forward(fn)), true)); + auto evt = reinterpret_cast(static_cast(dck.get())); + if (in_front) + dockers_->emplace(dockers_->begin(), std::move(dck)); + else + dockers_->emplace_back(std::move(dck)); + detail::events_operation_register(evt); + return evt; + } + std::size_t length() const { internal_scope_guard lock; @@ -158,20 +182,30 @@ namespace nana (*output++) = dck.get(); } + bool stop_propagation = false; for (; transitory != output; ++transitory) { - std::unique_ptr p(*transitory); - auto i = std::find(dockers.begin(), dockers.end(), p); + auto docker_ptr = *transitory; + if (stop_propagation && !docker_ptr->unignorable) + continue; + + auto i = std::find_if(dockers.begin(), dockers.end(), [docker_ptr](std::unique_ptr& p){ + return (docker_ptr == p.get()); + }); + if (i != dockers.end()) { - (*transitory)->flag_entered = true; - (*transitory)->invoke(arg); - (*transitory)->flag_entered = false; + docker_ptr->flag_entered = true; + docker_ptr->invoke(arg); - if ((*transitory)->flag_deleted) + if (arg.propagation_stopped()) + stop_propagation = true; + + docker_ptr->flag_entered = false; + + if (docker_ptr->flag_deleted) dockers.erase(i); } - p.release(); } } @@ -182,7 +216,7 @@ namespace nana dockers_.reset(); } - void remove(event_handle evt) + void remove(event_handle evt) override { internal_scope_guard lock; if (dockers_) @@ -362,7 +396,7 @@ namespace nana }; struct arg_mouse - : public detail::event_arg_interface + : public event_arg { event_code evt_code; ::nana::window window_handle; @@ -386,27 +420,27 @@ namespace nana unsigned distance; //expressed in multiples or divisions of 120 }; - struct arg_dropfiles : public detail::event_arg_interface + struct arg_dropfiles : public event_arg { ::nana::window window_handle; ::nana::point pos; std::vector files; }; - struct arg_expose : public detail::event_arg_interface + struct arg_expose : public event_arg { ::nana::window window_handle; bool exposed; }; - struct arg_focus : public detail::event_arg_interface + struct arg_focus : public event_arg { ::nana::window window_handle; ::nana::native_window_type receiver; bool getting; }; - struct arg_keyboard : public detail::event_arg_interface + struct arg_keyboard : public event_arg { event_code evt_code; ::nana::window window_handle; @@ -416,21 +450,21 @@ namespace nana bool shift; }; - struct arg_move : public detail::event_arg_interface + struct arg_move : public event_arg { ::nana::window window_handle; int x; int y; }; - struct arg_resized : public detail::event_arg_interface + struct arg_resized : public event_arg { ::nana::window window_handle; unsigned width; unsigned height; }; - struct arg_resizing : public detail::event_arg_interface + struct arg_resizing : public event_arg { ::nana::window window_handle; window_border border; @@ -438,13 +472,13 @@ namespace nana mutable unsigned height; }; - struct arg_unload : public detail::event_arg_interface + struct arg_unload : public event_arg { ::nana::window window_handle; mutable bool cancel; }; - struct arg_destroy : public detail::event_arg_interface + struct arg_destroy : public event_arg { ::nana::window window_handle; }; @@ -471,6 +505,7 @@ namespace nana basic_event move; basic_event resizing; basic_event resized; + basic_event destroy; }; @@ -482,16 +517,6 @@ namespace nana basic_event unload; }; }//end namespace detail - - namespace dev - { - template - struct event_mapping - { - typedef general_events type; - }; - }//end namespace dev - }//end namespace nana #endif diff --git a/include/nana/gui/detail/inner_fwd_implement.hpp b/include/nana/gui/detail/inner_fwd_implement.hpp index 31b59733..9e782092 100644 --- a/include/nana/gui/detail/inner_fwd_implement.hpp +++ b/include/nana/gui/detail/inner_fwd_implement.hpp @@ -124,7 +124,7 @@ namespace nana{ root_misc(core_window_t * wd, unsigned width, unsigned height) : window(wd), - root_graph(width, height) + root_graph({ width, height }) {} };//end struct root_misc diff --git a/include/nana/gui/detail/native_window_interface.hpp b/include/nana/gui/detail/native_window_interface.hpp index fca2b828..39cd7c49 100644 --- a/include/nana/gui/detail/native_window_interface.hpp +++ b/include/nana/gui/detail/native_window_interface.hpp @@ -1,6 +1,7 @@ /* * Platform Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -33,7 +34,7 @@ namespace detail unsigned extra_height; //extra border size, it is useful in Windows, ignore in X11 always 0 }; - static nana::size screen_size(); + static nana::size primary_monitor_size(); static rectangle screen_area_from_point(const point&); static window_result create_window(native_window_type, bool nested, const rectangle&, const appearance&); static native_window_type create_child_window(native_window_type, const rectangle&); @@ -58,7 +59,7 @@ namespace detail static nana::point window_position(native_window_type); static void move_window(native_window_type, int x, int y); static void move_window(native_window_type, const rectangle&); - static void bring_to_top(native_window_type); + static void bring_top(native_window_type, bool activated); static void set_window_z_order(native_window_type, native_window_type wd_after, z_order_action action_if_no_wd_after); static void window_size(native_window_type, const size&); @@ -69,9 +70,9 @@ namespace detail static nana::point cursor_position(); static native_window_type get_owner_window(native_window_type); //For Caret - static void caret_create(native_window_type, unsigned width, unsigned height); + static void caret_create(native_window_type, const ::nana::size&); static void caret_destroy(native_window_type); - static void caret_pos(native_window_type, int x, int y); + static void caret_pos(native_window_type, const ::nana::point&); static void caret_visible(native_window_type, bool); static void set_focus(native_window_type); diff --git a/include/nana/gui/detail/widget_colors.hpp b/include/nana/gui/detail/widget_colors.hpp new file mode 100644 index 00000000..d4d81e1a --- /dev/null +++ b/include/nana/gui/detail/widget_colors.hpp @@ -0,0 +1,46 @@ +/* +* Color Schemes +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2014 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/gui/widget_colors.hpp +* @description: +*/ +#ifndef NANA_DETAIL_WIDGET_COLORS_HPP +#define NANA_DETAIL_WIDGET_COLORS_HPP + +#include +#include +namespace nana +{ + class color_proxy + { + public: + color_proxy(const color_proxy&); + color_proxy(color_rgb); + color_proxy(colors); + color_proxy& operator=(const color_proxy&); + color_proxy& operator=(const ::nana::color&); + color_proxy& operator=(color_rgb); + color_proxy& operator=(colors); + color get_color() const; + operator color() const; + private: + std::shared_ptr color_; + };//end namespace color_proxy + + struct widget_colors + { + virtual ~widget_colors() = default; + + color_proxy activated{ static_cast(0x60C8FD) }; + color_proxy background{colors::button_face}; + color_proxy foreground{colors::black}; + }; +} + +#endif \ No newline at end of file diff --git a/include/nana/gui/detail/window_manager.hpp b/include/nana/gui/detail/window_manager.hpp index baab1232..2e07ac31 100644 --- a/include/nana/gui/detail/window_manager.hpp +++ b/include/nana/gui/detail/window_manager.hpp @@ -150,7 +150,7 @@ namespace detail core_window_t* root(native_window_type) const; //Copy the root buffer that wnd specified into DeviceContext - void map(core_window_t*); + void map(core_window_t*, bool forced); bool update(core_window_t*, bool redraw, bool force); void refresh_tree(core_window_t*); diff --git a/include/nana/gui/element.hpp b/include/nana/gui/element.hpp index 121e7ce6..ee63ecf0 100644 --- a/include/nana/gui/element.hpp +++ b/include/nana/gui/element.hpp @@ -30,19 +30,17 @@ namespace nana class element_interface { public: - typedef paint::graphics & graph_reference; + using graph_reference = paint::graphics&; - virtual ~element_interface() - {} - - virtual bool draw(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle&, element_state) = 0; + virtual ~element_interface() = default; + virtual bool draw(graph_reference, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle&, element_state) = 0; }; class crook_interface { public: - typedef paint::graphics & graph_reference; - typedef checkstate state; + using graph_reference = paint::graphics&; + using state = checkstate; struct data { @@ -50,10 +48,25 @@ namespace nana bool radio; }; - virtual ~crook_interface() - {} + virtual ~crook_interface() = default; + virtual bool draw(graph_reference, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle&, element_state, const data&) = 0; + }; - virtual bool draw(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle&, element_state, const data&) = 0; + class border_interface + { + public: + using graph_reference = paint::graphics&; + + virtual ~border_interface() = default; + virtual bool draw(graph_reference, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle&, element_state, unsigned weight) = 0; + }; + + class arrow_interface + { + public: + using graph_reference = paint::graphics&; + virtual ~arrow_interface() = default; + virtual bool draw(graph_reference, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle&, element_state, direction) = 0; }; class provider @@ -87,16 +100,48 @@ namespace nana void add_crook(const std::string& name, const pat::cloneable>&); crook_interface* const * keeper_crook(const std::string& name); + + void add_border(const std::string&, const pat::cloneable>&); + border_interface* const * keeper_border(const std::string&); + + void add_arrow(const std::string&, const pat::cloneable>&); + arrow_interface* const * keeper_arrow(const std::string&); + + void add_button(const std::string&, const pat::cloneable>&); + element_interface* const* keeper_button(const std::string&); }; + class crook; template void add_crook(const std::string& name) { - typedef provider::factory factory_t; + using factory_t = provider::factory; provider().add_crook(name, pat::cloneable(factory_t())); } - class crook; + class border; + template + void add_border(const std::string& name) + { + using factory_t = provider::factory; + provider().add_border(name, pat::cloneable(factory_t())); + } + + class arrow; + template + void add_arrow(const std::string& name) + { + using factory_t = provider::factory; + provider().add_arrow(name, pat::cloneable(factory_t())); + } + + class button; + template + void add_button(const std::string& name) + { + using factory_t = provider::factory; + provider().add_button(name, pat::cloneable(factory_t())); + } }//end namespace element template class facade; @@ -106,11 +151,10 @@ namespace nana : public element::element_interface { public: - typedef ::nana::paint::graphics & graph_reference; - typedef element::crook_interface::state state; + using graph_reference = ::nana::paint::graphics &; + using state = element::crook_interface::state; - facade(); - facade(const char* name); + facade(const char* name = nullptr); facade & reverse(); facade & check(state); @@ -122,11 +166,65 @@ namespace nana void switch_to(const char*); public: //Implement element_interface - bool draw(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle& r, element_state) override; + bool draw(graph_reference, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle& r, element_state) override; private: element::crook_interface::data data_; element::crook_interface* const * keeper_; - }; + }; //end class facade + + template<> + class facade + : public element::element_interface + { + using graph_reference = ::nana::paint::graphics &; + public: + facade(const char* name = nullptr); + + void switch_to(const char*); + public: + //Implement element_interface + bool draw(graph_reference, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle&, element_state) override; + private: + element::border_interface* const * keeper_; + };//end class facade + + template<> + class facade + : public element::element_interface + { + using graph_reference = ::nana::paint::graphics &; + public: + enum class style + { + solid + }; + + facade(const char* name = nullptr); + + void switch_to(const char*); + void direction(::nana::direction); + public: + //Implement element_interface + bool draw(graph_reference, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle&, element_state) override; + private: + element::arrow_interface* const * keeper_; + ::nana::direction dir_{::nana::direction::north}; + };//end class facade + + template<> + class facade + : public element::element_interface + { + public: + facade(const char* name = nullptr); + void switch_to(const char*); + public: + //Implement element_interface + bool draw(graph_reference, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle&, element_state) override; + private: + element::element_interface* const * keeper_; + };//end class facade + namespace element { @@ -144,7 +242,7 @@ namespace nana void set(const cloneable_element&); void set(const char*); - bool draw(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle&, element_state); + bool draw(graph_reference, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle&, element_state); private: cloneable_element holder_; element_interface * place_ptr_; @@ -174,7 +272,7 @@ namespace nana void stretch_parts(unsigned left, unsigned top, unsigned right, unsigned bottom); //Implement the methods of element_interface. - virtual bool draw(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle&, element_state); + virtual bool draw(graph_reference, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle&, element_state); private: struct draw_method; struct draw_image; diff --git a/include/nana/gui/msgbox.hpp b/include/nana/gui/msgbox.hpp index f179c556..fe6ae1ff 100644 --- a/include/nana/gui/msgbox.hpp +++ b/include/nana/gui/msgbox.hpp @@ -1,7 +1,7 @@ /* * A Message Box Class * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -91,6 +91,141 @@ namespace nana button_t button_; icon_t icon_; }; + + class inputbox + { + struct abstract_content + { + virtual ~abstract_content() = default; + + virtual const ::nana::string& label() const = 0; + virtual window create(window, unsigned label_px) = 0; + virtual unsigned fixed_pixels() const = 0; + }; + public: + class integer + : public abstract_content + { + struct implement; + public: + integer(::nana::string label, int init_value, int begin, int last, int step); + ~integer(); + + int value() const; + private: + //Implementation of abstract_content + const ::nana::string& label() const override; + window create(window, unsigned label_px) override; + unsigned fixed_pixels() const override; + private: + std::unique_ptr impl_; + }; + + class real + : public abstract_content + { + struct implement; + public: + real(::nana::string label, double init_value, double begin, double last, double step); + ~real(); + + double value() const; + private: + //Implementation of abstract_content + const ::nana::string& label() const override; + window create(window, unsigned label_px) override; + unsigned fixed_pixels() const override; + private: + std::unique_ptr impl_; + }; + + class text + : public abstract_content + { + struct implement; + public: + text(::nana::string label); + text(::nana::string label, std::vector<::nana::string>); + + ~text(); + + ::nana::string value() const; + private: + //Implementation of abstract_content + const ::nana::string& label() const override; + window create(window, unsigned label_px) override; + unsigned fixed_pixels() const override; + private: + std::unique_ptr impl_; + }; + + class date + : public abstract_content + { + struct implement; + public: + date(::nana::string label); + + ~date(); + + ::nana::string value() const; + int year() const; + int month() const; //[1, 12] + int day() const; //[1, 31] + unsigned fixed_pixels() const override; + private: + //Implementation of abstract_content + const ::nana::string& label() const override; + window create(window, unsigned label_px) override; + private: + std::unique_ptr impl_; + }; + + inputbox(window, ::nana::string description, ::nana::string title = ::nana::string()); + + template + bool show(Args&& ... args) + { + std::vector contents; + _m_fetch_args(contents, std::forward(args)...); + + if (contents.empty()) + return false; + + return _m_open(contents, false); + } + + template + bool show_modal(Args&& ... args) + { + std::vector contents; + _m_fetch_args(contents, std::forward(args)...); + + if (contents.empty()) + return false; + + return _m_open(contents, true); + } + + /// Sets a verifier to verify the user input. + void verify(std::function verifier); + private: + void _m_fetch_args(std::vector&); + + template + void _m_fetch_args(std::vector& contents, abstract_content& content, Args&&... args) + { + contents.push_back(&content); + _m_fetch_args(contents, std::forward(args)...); + } + + bool _m_open(std::vector&, bool modal); + private: + window owner_; + ::nana::string description_; + ::nana::string title_; + std::function verifier_; + }; }//end namespace nana #endif diff --git a/include/nana/gui/notifier.hpp b/include/nana/gui/notifier.hpp index f7a7531d..c6eea9da 100644 --- a/include/nana/gui/notifier.hpp +++ b/include/nana/gui/notifier.hpp @@ -1,7 +1,7 @@ /* * Definition of Notifier * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -20,6 +20,7 @@ namespace nana class notifier; struct arg_notifier + : public event_arg { event_code evt_code; notifier* notifier_ptr; diff --git a/include/nana/gui/programming_interface.hpp b/include/nana/gui/programming_interface.hpp index 2fcb4b15..b65a15fc 100644 --- a/include/nana/gui/programming_interface.hpp +++ b/include/nana/gui/programming_interface.hpp @@ -1,7 +1,7 @@ /* * Nana GUI Programming Interface Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -13,7 +13,7 @@ #ifndef NANA_GUI_PROGRAMMING_INTERFACE_HPP #define NANA_GUI_PROGRAMMING_INTERFACE_HPP #include -#include GUI_BEDROCK_HPP +#include "detail/bedrock.hpp" #include "effects.hpp" #include "detail/general_events.hpp" #include @@ -24,6 +24,17 @@ namespace nana class drawer_trigger; class widget; + namespace dev + { + /// Traits for widget classes + template + struct widget_traits + { + using event_type = ::nana::general_events; + using scheme_type = ::nana::widget_colors; + }; + } + namespace API { void effects_edge_nimbus(window, effects::edge_nimbus); @@ -45,6 +56,16 @@ namespace API } bool set_events(window, const std::shared_ptr&); + + template + std::unique_ptr make_scheme() + { + return std::unique_ptr( + static_cast(::nana::detail::bedrock::instance().make_scheme(::nana::detail::scheme_factory()).release())); + } + + void set_scheme(window, widget_colors*); + widget_colors* get_scheme(window); void attach_drawer(widget&, drawer_trigger&); nana::string window_caption(window); @@ -70,8 +91,6 @@ namespace API bool register_shortkey(window, unsigned long); void unregister_shortkey(window); - nana::size screen_size(); - rectangle screen_area_from_point(const point&); nana::point cursor_position(); rectangle make_center(unsigned width, unsigned height); ///< Retrieves a rectangle which is in the center of the screen. rectangle make_center(window, unsigned width, unsigned height); ///< Retrieves a rectangle which is in the center of the window @@ -100,7 +119,8 @@ namespace API void window_icon_default(const paint::image&); void window_icon(window, const paint::image&); - bool empty_window(window); ///< Determines whether a window is existing. + bool empty_window(window); ///< Determines whether a window is existing. + bool is_window(window); ///< Determines whether a window is existing, equal to !empty_window. void enable_dropfiles(window, bool); /// \brief Retrieves the native window of a Nana.GUI window. @@ -127,16 +147,16 @@ namespace API bool set_parent_window(window, window new_parent); template - typename ::nana::dev::event_mapping::type & events(window wd) + typename ::nana::dev::widget_traits::event_type & events(window wd) { - typedef typename ::nana::dev::event_mapping::type event_type; + using event_type = typename ::nana::dev::widget_traits::event_type; internal_scope_guard lock; auto * general_evt = detail::get_general_events(wd); if (nullptr == general_evt) throw std::invalid_argument("API::events(): bad parameter window handle, no events object or invalid window handle."); - if (std::is_same::value) + if (std::is_same<::nana::general_events, event_type>::value) return *static_cast(general_evt); auto * widget_evt = dynamic_cast(general_evt); @@ -145,7 +165,7 @@ namespace API return *widget_evt; } - template::value>::type* = nullptr> + template::value>::type* = nullptr> bool emit_event(event_code evt_code, window wd, const EventArg& arg) { auto & brock = ::nana::detail::bedrock::instance(); @@ -154,13 +174,35 @@ namespace API void umake_event(event_handle); + template + typename ::nana::dev::widget_traits::scheme_type & scheme(window wd) + { + using scheme_type = typename ::nana::dev::widget_traits::scheme_type; + + internal_scope_guard lock; + auto * wdg_colors = dev::get_scheme(wd); + if (nullptr == wdg_colors) + throw std::invalid_argument("API::scheme(): bad parameter window handle, no events object or invalid window handle."); + + if (std::is_same<::nana::widget_colors, scheme_type>::value) + return *static_cast(wdg_colors); + + auto * comp_wdg_colors = dynamic_cast(wdg_colors); + if (nullptr == comp_wdg_colors) + throw std::invalid_argument("API::scheme(): bad template parameter Widget, the widget type and window handle do not match."); + return *comp_wdg_colors; + } + nana::point window_position(window); void move_window(window, int x, int y); void move_window(window wd, const rectangle&); - void bring_to_top(window); + void bring_top(window, bool activated); bool set_window_z_order(window wd, window wd_after, z_order_action action_if_no_wd_after); + void draw_through(window, std::function); + void map_through_widgets(window, native_drawable_type); + nana::size window_size(window); void window_size(window, const size&); bool window_rectangle(window, rectangle&); @@ -185,6 +227,7 @@ namespace API void refresh_window_tree(window); ///< Refreshs the specified window and all it’s children windows, then display it immediately void update_window(window); ///< Copies the off-screen buffer to the screen for immediate display. + void window_caption(window, const std::string& title_utf8); void window_caption(window, const nana::string& title); nana::string window_caption(window); @@ -201,17 +244,18 @@ namespace API void capture_ignore_children(bool ignore); ///< Enables or disables the captured window whether redirects the mouse input to its children if the mouse is over its children. void modal_window(window); ///< Blocks the routine til the specified window is closed. void wait_for(window); - color_t foreground(window); - color_t foreground(window, color_t); - color_t background(window); - color_t background(window, color_t); - color_t active(window); - color_t active(window, color_t); + + color fgcolor(window); + color fgcolor(window, const color&); + color bgcolor(window); + color bgcolor(window, const color&); + color activated_color(window); + color activated_color(window, const color&); void create_caret(window, unsigned width, unsigned height); void destroy_caret(window); void caret_effective_range(window, const rectangle&); - void caret_pos(window, int x, int y); + void caret_pos(window, const ::nana::point&); nana::point caret_pos(window); nana::size caret_size(window); void caret_size(window, const size&); diff --git a/include/nana/gui/screen.hpp b/include/nana/gui/screen.hpp new file mode 100644 index 00000000..ef2aaac1 --- /dev/null +++ b/include/nana/gui/screen.hpp @@ -0,0 +1,52 @@ +/* +* Screen Informations +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2015 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/gui/screen.hpp +*/ + +#ifndef NANA_GUI_SCREEN_HPP +#define NANA_GUI_SCREEN_HPP +#include "basis.hpp" +#include +#include + +namespace nana +{ + /// The monitor display metrics + class display + { + public: + virtual ~display() = default; + + /// The index of monitor. + virtual std::size_t get_index() const = 0; + + /// Returns the positional coordinates and size of the display device in reference to the desktop area + virtual const ::nana::rectangle& area() const = 0; + }; + + class screen + { + public: + static ::nana::size desktop_size(); + static ::nana::size primary_monitor_size(); + static std::shared_ptr from_point(const point&); + static std::shared_ptr from_window(window); + + /// Returns the number of display monitors + std::size_t count() const; + + std::shared_ptr get_display(std::size_t index) const; + std::shared_ptr get_primary() const; + + void for_each(std::function) const; + }; +}//end namespace nana + +#endif diff --git a/include/nana/gui/timer.hpp b/include/nana/gui/timer.hpp index 458e929e..893a4e5d 100644 --- a/include/nana/gui/timer.hpp +++ b/include/nana/gui/timer.hpp @@ -1,6 +1,6 @@ /* * A Timer Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -22,6 +22,7 @@ namespace nana /// Can repeatedly call a piece of code. struct arg_elapse + : public event_arg { long long id; //timer identifier; }; diff --git a/include/nana/gui/widgets/button.hpp b/include/nana/gui/widgets/button.hpp index f6d67d9b..5305e4f6 100644 --- a/include/nana/gui/widgets/button.hpp +++ b/include/nana/gui/widgets/button.hpp @@ -53,10 +53,10 @@ namespace nana{ void _m_draw_background(graph_reference); void _m_draw_border(graph_reference); private: - widget* widget_; - paint::graphics* graph_; + widget* wdg_{nullptr}; + paint::graphics* graph_{nullptr}; - element::cite_bground cite_; + element::cite_bground cite_{"button"}; struct attr_tag { @@ -68,8 +68,8 @@ namespace nana{ bool enable_pushed; bool focus_color; paint::image * icon; - color_t bgcolor; - color_t fgcolor; + ::nana::color bgcolor; + ::nana::color fgcolor; }attr_; }; }//end namespace button diff --git a/include/nana/gui/widgets/categorize.hpp b/include/nana/gui/widgets/categorize.hpp index 204e4fc5..72df23d6 100644 --- a/include/nana/gui/widgets/categorize.hpp +++ b/include/nana/gui/widgets/categorize.hpp @@ -1,7 +1,7 @@ /* * A Categorize Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -23,6 +23,7 @@ namespace nana template struct arg_categorize + : public event_arg { categorize & widget; ValueType & value; @@ -164,7 +165,7 @@ namespace nana categorize(window wd, const rectangle& r = rectangle(), bool visible = true) { - this->get_drawer_trigger().template create_event_agent(*this); + this->get_drawer_trigger().create_event_agent(*this); this->create(wd, r, visible); } diff --git a/include/nana/gui/widgets/checkbox.hpp b/include/nana/gui/widgets/checkbox.hpp index 5f9da66a..0795fa1a 100644 --- a/include/nana/gui/widgets/checkbox.hpp +++ b/include/nana/gui/widgets/checkbox.hpp @@ -44,7 +44,6 @@ namespace drawerbase private: static const int interval = 4; widget* widget_; - unsigned state_; std::unique_ptr imptr_; implement * impl_; }; diff --git a/include/nana/gui/widgets/combox.hpp b/include/nana/gui/widgets/combox.hpp index fc00c092..5a1f7e84 100644 --- a/include/nana/gui/widgets/combox.hpp +++ b/include/nana/gui/widgets/combox.hpp @@ -1,7 +1,7 @@ /* * A Combox Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -14,6 +14,7 @@ #define NANA_GUI_WIDGETS_COMBOX_HPP #include "widget.hpp" #include "float_listbox.hpp" +#include "skeletons/text_editor_scheme.hpp" #include #include #include @@ -21,15 +22,13 @@ namespace nana { /// A list box combined with a textbox - the list box should drop down when the user selects the arrow next to the control - class combox; + class combox; struct arg_combox + : public event_arg { combox & widget; - - arg_combox(combox& wdg) - : widget(wdg) - {} + arg_combox(combox&); }; namespace drawerbase @@ -39,7 +38,8 @@ namespace nana struct combox_events : public general_events { - basic_event selected; + basic_event selected; + basic_event text_changed; }; class drawer_impl; @@ -51,8 +51,6 @@ namespace nana trigger(); ~trigger(); - void set_accept(std::function&&); - drawer_impl& get_drawer_impl(); const drawer_impl& get_drawer_impl() const; private: @@ -69,7 +67,6 @@ namespace nana void key_press(graph_reference, const arg_keyboard&) override; void key_char(graph_reference, const arg_keyboard&) override; private: - std::function pred_acceptive_; drawer_impl * drawer_; }; @@ -160,7 +157,7 @@ namespace nana }//end namespace drawerbase class combox - : public widget_object, + : public widget_object, public nana::concepts::any_objective { public: @@ -169,15 +166,15 @@ namespace nana combox(); combox(window, bool visible); - combox(window, const nana::string& text, bool visible = true); - combox(window, const nana::char_t* text, bool visible = true); + combox(window, nana::string, bool visible = true); + combox(window, const nana::char_t*, bool visible = true); combox(window, const rectangle& r = rectangle(), bool visible = true); void clear(); void editable(bool); bool editable() const; void set_accept(std::function); - combox& push_back(const nana::string&); + combox& push_back(nana::string); std::size_t the_number_of_options() const; std::size_t option() const; ///< Index of the last selected, from drop-down list, item. void option(std::size_t); ///< Select the text specified by index @@ -223,11 +220,23 @@ namespace nana private: item_proxy _m_at_key(std::shared_ptr&&); void _m_erase(nana::detail::key_interface*); + drawerbase::combox::drawer_impl & _m_impl(); + const drawerbase::combox::drawer_impl& _m_impl() const; private: //Overrides widget's virtual functions nana::string _m_caption() const override; void _m_caption(nana::string&&) override; nana::any * _m_anyobj(std::size_t pos, bool alloc_if_empty) const override; }; + + namespace dev + { + template<> + struct widget_traits + { + using event_type = drawerbase::combox::combox_events; + using scheme_type = ::nana::widgets::skeletons::text_editor_scheme; + }; + } } #endif diff --git a/include/nana/gui/widgets/date_chooser.hpp b/include/nana/gui/widgets/date_chooser.hpp index 03b47c5d..b4bf2126 100644 --- a/include/nana/gui/widgets/date_chooser.hpp +++ b/include/nana/gui/widgets/date_chooser.hpp @@ -1,7 +1,7 @@ /* * A date chooser Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -43,10 +43,8 @@ namespace nana bool chose() const; nana::date read() const; void week_name(unsigned index, const nana::string&); - void month_name(unsigned index, const nana::string&); private: - void _m_init_color(); - where _m_pos_where(graph_reference, int x, int y); + where _m_pos_where(graph_reference, const ::nana::point& pos); void _m_draw(graph_reference); void _m_draw_topbar(graph_reference); void _m_make_drawing_basis(drawing_basis&, graph_reference, const nana::point& refpos); @@ -58,14 +56,13 @@ namespace nana bool _m_get_trace(point, int & res); void _m_perf_transform(transform_action tfid, graph_reference, graph_reference dirtybuf, graph_reference newbuf, const nana::point& refpos); private: - void refresh(graph_reference); + void refresh(graph_reference) override; void attached(widget_reference, graph_reference) override; void mouse_move(graph_reference, const arg_mouse&) override; void mouse_leave(graph_reference, const arg_mouse&) override; void mouse_up(graph_reference, const arg_mouse&) override; private: nana::string weekstr_[7]; - nana::string monthstr_[12]; widget * widget_; @@ -91,10 +88,10 @@ namespace nana struct color_tag { - nana::color_t highlight; - nana::color_t selected; - nana::color_t normal; - nana::color_t bkcolor; + ::nana::color highlight; + ::nana::color selected; + ::nana::color normal; + ::nana::color bgcolor; }color_; }; @@ -116,7 +113,6 @@ namespace nana bool chose() const; nana::date read() const; void weekstr(unsigned index, const nana::string&);///> items; - std::size_t max_items; // the number of items display. - mutable std::size_t index; // the result of the selection. + std::size_t max_items{10}; // the number of items display. + mutable std::size_t index{::nana::npos}; // the result of the selection. mutable bool have_selected; - - module_def(); }; class item_renderer @@ -51,7 +49,7 @@ namespace nana typedef paint::graphics& graph_reference; enum state_t{StateNone, StateHighlighted}; - virtual ~item_renderer() = 0; + virtual ~item_renderer() = default; virtual void image(bool enabled, unsigned pixels) = 0; virtual void render(widget_reference, graph_reference, const nana::rectangle&, const item_interface*, state_t) = 0; virtual unsigned item_pixels(graph_reference) const = 0; diff --git a/include/nana/gui/widgets/form.hpp b/include/nana/gui/widgets/form.hpp index 4f6c0aaf..0f64c54a 100644 --- a/include/nana/gui/widgets/form.hpp +++ b/include/nana/gui/widgets/form.hpp @@ -24,12 +24,10 @@ namespace nana class trigger: public drawer_trigger { public: - trigger(); void attached(widget_reference, graph_reference) override; void refresh(graph_reference) override; - void resized(graph_reference, const arg_resized&) override; private: - widget* wd_; + widget* wd_{nullptr}; }; }//end namespace form }//end namespace drawerbase @@ -47,6 +45,9 @@ namespace nana form(window, const ::nana::size& = { 300, 200 }, const appearance& = {}); /// Creates a window at the point and size specified by rect, with the specified appearance. This window is always floating above its owner. form(window, const rectangle&, const appearance& = {}); + + void modality() const; + void wait_for_this(); }; class nested_form : public widget_object diff --git a/include/nana/gui/widgets/label.hpp b/include/nana/gui/widgets/label.hpp index dc79eb1c..c6488e5b 100644 --- a/include/nana/gui/widgets/label.hpp +++ b/include/nana/gui/widgets/label.hpp @@ -69,6 +69,8 @@ namespace nana /// "corrected" size that changes lines to fit the text into the specified width nana::size measure(unsigned allowed_width_in_pixel) const; + static ::nana::size measure(::nana::paint::graphics&, const ::nana::string&, unsigned allowed_width_in_pixel, bool format_enabled, align h_align, align_v v_align); + label& text_align(align horizontal_align, align_v vertical_align= align_v::top); private: //Overrides widget's virtual function diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 691e83c5..8274d3e3 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -1,7 +1,7 @@ /* * A List Box Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -33,10 +33,11 @@ namespace nana { struct format { - ::nana::color_t bgcolor; - ::nana::color_t fgcolor; + ::nana::color bgcolor; + ::nana::color fgcolor; - format(color_t bgcolor = 0xFF000000, color_t fgcolor = 0xFF000000); + format() = default; + format(const ::nana::color& bgcolor, const ::nana::color& fgcolor); }; using format_ptr = std::unique_ptr < format > ; @@ -49,7 +50,7 @@ namespace nana cell(cell&&); cell(nana::string); cell(nana::string, const format&); - cell(nana::string, color_t bgcolor, color_t fgcolor); + cell(nana::string, const ::nana::color& bgcolor, const ::nana::color& fgcolor); cell& operator=(const cell&); cell& operator=(cell&&); @@ -212,11 +213,11 @@ namespace nana item_proxy & select(bool); bool selected() const; - item_proxy & bgcolor(nana::color_t); - nana::color_t bgcolor() const; + item_proxy & bgcolor(const nana::color&); + nana::color bgcolor() const; - item_proxy& fgcolor(nana::color_t); - nana::color_t fgcolor() const; + item_proxy& fgcolor(const nana::color&); + nana::color fgcolor() const; index_pair pos() const; @@ -415,9 +416,12 @@ namespace nana }//end namespace drawerbase struct arg_listbox + : public event_arg { mutable drawerbase::listbox::item_proxy item; bool selected; + + arg_listbox(const drawerbase::listbox::item_proxy&, bool selected); }; namespace drawerbase @@ -430,6 +434,15 @@ namespace nana basic_event checked; basic_event selected; }; + + struct scheme + : public widget_colors + { + color_proxy header_bgcolor{static_cast(0xf1f2f4)}; + color_proxy header_grabbed{ static_cast(0x8BD6F6)}; + color_proxy header_floated{ static_cast(0xBABBBC)}; + color_proxy item_selected{ static_cast(0xD5EFFC) }; + }; } }//end namespace drawerbase @@ -441,7 +454,7 @@ The user can \a drag the header to \a reisize it or to \a reorganize it. By \a clicking on a header the list get \a reordered, first up, and then down alternatively, */ class listbox - : public widget_object, + : public widget_object, public concepts::any_objective { public: @@ -471,8 +484,8 @@ By \a clicking on a header the list get \a reordered, first up, and then down al template cat_proxy operator[](const Key & ck) { - typedef typename nana::detail::type_escape::type key_t; - std::shared_ptr p(new nana::key>(ck), [](nana::detail::key_interface* p) + using catkey = typename ::nana::detail::type_escape::type; + std::shared_ptr p(new nana::key>(ck), [](nana::detail::key_interface* p) { delete p; }); @@ -483,8 +496,8 @@ By \a clicking on a header the list get \a reordered, first up, and then down al template cat_proxy operator[](Key && ck) { - typedef typename nana::detail::type_escape::type key_t; - std::shared_ptr p(new nana::key>(std::move(ck)), [](nana::detail::key_interface* p) + using catkey = typename ::nana::detail::type_escape::type; + std::shared_ptr p(new nana::key>(std::move(ck)), [](nana::detail::key_interface* p) { delete p; }); @@ -539,6 +552,9 @@ By \a clicking on a header the list get \a reordered, first up, and then down al size_type size_categ() const; ///); void _m_ease_key(nana::detail::key_interface*); }; + + namespace dev + { + template<> + struct widget_traits + { + using event_type = drawerbase::listbox::listbox_events; + using scheme_type = drawerbase::listbox::scheme; + }; + } }//end namespace nana #endif diff --git a/include/nana/gui/widgets/menu.hpp b/include/nana/gui/widgets/menu.hpp index 7e072324..36f99a28 100644 --- a/include/nana/gui/widgets/menu.hpp +++ b/include/nana/gui/widgets/menu.hpp @@ -104,7 +104,7 @@ namespace nana checks check_style; }; - virtual ~renderer_interface() = 0; + virtual ~renderer_interface() = default; virtual void background(graph_reference, window) = 0; virtual void item(graph_reference, const nana::rectangle&, const attr&) = 0; diff --git a/include/nana/gui/widgets/panel.hpp b/include/nana/gui/widgets/panel.hpp index a9dc6a18..e1d98d00 100644 --- a/include/nana/gui/widgets/panel.hpp +++ b/include/nana/gui/widgets/panel.hpp @@ -1,7 +1,7 @@ /* * A Panel Implementation * Nana C++ Library(http://www.nanaro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -25,13 +25,10 @@ namespace nana { class drawer: public drawer_trigger { - public: - drawer(); - private: void attached(widget_reference, graph_reference) override; void refresh(graph_reference) override; private: - window window_; + window window_{nullptr}; }; }// end namespace panel }//end namespace drawerbase diff --git a/include/nana/gui/widgets/picture.hpp b/include/nana/gui/widgets/picture.hpp index 7238fe32..5c9b5f97 100644 --- a/include/nana/gui/widgets/picture.hpp +++ b/include/nana/gui/widgets/picture.hpp @@ -1,7 +1,7 @@ /* * A Picture Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -26,7 +26,7 @@ namespace nana void attached(widget_reference, graph_reference) override; void load(const nana::char_t* file); void load(const nana::paint::image&); - void set_shadow_background(unsigned begin_color, unsigned end_color, bool horizontal); + void set_shadow_background(const ::nana::color& from, const ::nana::color& to, bool horizontal); bool bgstyle(bool is_stretch, nana::arrange, int beg, int end); private: void refresh(graph_reference) override; @@ -35,13 +35,12 @@ namespace nana widget* widget_; nana::paint::graphics* graph_; - struct runtime_type + struct { - runtime_type(); - unsigned background_shadow_start; - unsigned background_shadow_end; + ::nana::color gradual_from; + ::nana::color gradual_to; bool horizontal; - }runtime_; + }bground_; struct back_image_tag { @@ -72,8 +71,8 @@ namespace nana int end ///< specify the stretchy area of image. ); - /// Fills a gradual change color in background. - void set_shadow_background(unsigned begin_color, unsigned end_color, bool horizontal); + /// Fills a gradual-change color in background. If One of colors is invisible or clr_from is equal to clr_to, it draws background in bgcolor. + void set_gradual_background(const ::nana::color& clr_from, const ::nana::color& clr_to, bool horizontal); void transparent(bool); bool transparent() const; }; diff --git a/include/nana/gui/widgets/progress.hpp b/include/nana/gui/widgets/progress.hpp index 6b12fee5..352069df 100644 --- a/include/nana/gui/widgets/progress.hpp +++ b/include/nana/gui/widgets/progress.hpp @@ -1,7 +1,7 @@ /* * A Progress Indicator Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -23,7 +23,6 @@ namespace nana class trigger: public drawer_trigger { public: - trigger(); unsigned value() const; unsigned value(unsigned); unsigned inc(); @@ -41,13 +40,14 @@ namespace nana bool _m_check_changing(unsigned) const; private: static const unsigned border = 2; - widget * widget_; - nana::paint::graphics* graph_; - unsigned draw_width_; - bool has_value_; - bool unknown_; - unsigned max_; - unsigned value_; + + widget * widget_{nullptr}; + nana::paint::graphics* graph_{nullptr}; + unsigned draw_width_{static_cast(-1)}; + //bool has_value_{true}; //deprecated + bool unknown_{false}; + unsigned max_{100}; + unsigned value_{0}; }; //end class drawer } }//end namespace drawerbase diff --git a/include/nana/gui/widgets/scroll.hpp b/include/nana/gui/widgets/scroll.hpp index 26421b48..4b165313 100644 --- a/include/nana/gui/widgets/scroll.hpp +++ b/include/nana/gui/widgets/scroll.hpp @@ -1,7 +1,7 @@ /* * A Scroll Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -22,8 +22,13 @@ namespace nana template struct arg_scroll + : public event_arg { scroll & widget; + + arg_scroll(scroll & wdg) + : widget(wdg) + {} }; namespace drawerbase @@ -81,9 +86,9 @@ namespace nana bool _m_check() const; void _m_adjust_scroll(graph_reference); void _m_background(graph_reference); - void _m_button_frame(graph_reference, int x, int y, unsigned width, unsigned height, int state); + void _m_button_frame(graph_reference, ::nana::rectangle, int state); void _m_draw_scroll(graph_reference, int state); - void _m_draw_button(graph_reference, int x, int y, unsigned width, unsigned height, buttons what, int state); + void _m_draw_button(graph_reference, ::nana::rectangle, buttons what, int state); private: metrics_type &metrics_; bool vertical_; @@ -180,7 +185,7 @@ namespace nana return false; } private: - void attached(widget_reference widget, graph_reference graph) + void attached(widget_reference widget, graph_reference graph) override { graph_ = &graph; widget_ = static_cast< ::nana::scroll*>(&widget); @@ -190,12 +195,12 @@ namespace nana timer_.elapse(std::bind(&trigger::_m_tick, this)); } - void detached() + void detached() override { graph_ = nullptr; } - void refresh(graph_reference graph) + void refresh(graph_reference graph) override { drawer_.draw(graph, metrics_.what); } @@ -213,7 +218,7 @@ namespace nana API::lazy_refresh(); } - void mouse_move(graph_reference graph, const ::nana::arg_mouse& arg) + void mouse_move(graph_reference graph, const ::nana::arg_mouse& arg) override { bool redraw = false; if(metrics_.pressed && (metrics_.what == buttons::scroll)) @@ -240,7 +245,7 @@ namespace nana } } - void mouse_down(graph_reference graph, const arg_mouse& arg) + void mouse_down(graph_reference graph, const arg_mouse& arg) override { if(arg.left_button) { @@ -275,7 +280,7 @@ namespace nana } } - void mouse_up(graph_reference graph, const arg_mouse& arg) + void mouse_up(graph_reference graph, const arg_mouse& arg) override { timer_.stop(); @@ -287,7 +292,7 @@ namespace nana API::lazy_refresh(); } - void mouse_leave(graph_reference graph, const arg_mouse&) + void mouse_leave(graph_reference graph, const arg_mouse&) override { if(metrics_.pressed) return; @@ -296,7 +301,7 @@ namespace nana API::lazy_refresh(); } - void mouse_wheel(graph_reference graph, const arg_wheel& arg) + void mouse_wheel(graph_reference graph, const arg_wheel& arg) override { if(make_step(arg.upwards == false, 3)) { @@ -307,7 +312,7 @@ namespace nana private: void _m_emit_value_changed() { - widget_->events().value_changed.emit(::nana::arg_scroll({*widget_})); + widget_->events().value_changed.emit(::nana::arg_scroll(*widget_)); } void _m_tick() diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index 0af6b895..7b861606 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -1,7 +1,7 @@ /* * A text editor implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -14,9 +14,9 @@ #ifndef NANA_GUI_SKELETONS_TEXT_EDITOR_HPP #define NANA_GUI_SKELETONS_TEXT_EDITOR_HPP #include "textbase.hpp" +#include "text_editor_scheme.hpp" #include #include -#include namespace nana{ namespace widgets { @@ -127,22 +127,37 @@ namespace nana{ namespace widgets class undo_backspace; class undo_input_text; class undo_move_text; - public: - typedef nana::char_t char_type; - typedef textbase::size_type size_type; - typedef textbase::string_type string_type; - typedef nana::paint::graphics & graph_reference; + struct keywords; + class keyword_parser; + public: + using char_type = ::nana::char_t; + using size_type = textbase::size_type; + using string_type = textbase::string_type; + + using graph_reference = ::nana::paint::graphics&; struct ext_renderer_tag { - std::function background; + std::function background; }; - text_editor(window, graph_reference); + enum class accepts + { + no_restrict, integer, real + }; + + text_editor(window, graph_reference, const text_editor_scheme*); ~text_editor(); - bool respone_keyboard(nana::char_t, bool enterable); + void set_highlight(const std::string& name, const ::nana::color&, const ::nana::color&); + void erase_highlight(const std::string& name); + void set_keyword(const ::nana::string& kw, const std::string& name, bool case_sensitive, bool whole_word_matched); + void erase_keyword(const ::nana::string& kw); + + void set_accept(std::function); + void set_accept(accepts); + bool respone_keyboard(char_type); void typeface_changed(); @@ -151,12 +166,12 @@ namespace nana{ namespace widgets /// Set the text_editor whether it is line wrapped, it returns false if the state is not changed. bool line_wrapped(bool); - void border_renderer(std::function); + void border_renderer(std::function); bool load(const nana::char_t*); - //text_area - //@return: Returns true if the area of text is changed. + /// Sets the text area. + /// @return true if the area is changed with the new value. bool text_area(const nana::rectangle&); bool tip_string(nana::string&&); @@ -180,8 +195,7 @@ namespace nana{ namespace widgets void text(nana::string); nana::string text() const; - //move_caret - //@brief: Set caret position through text coordinate + /// Sets caret position through text coordinate. void move_caret(const upoint&); void move_caret_end(); void reset_caret_height() const; @@ -190,7 +204,7 @@ namespace nana{ namespace widgets bool selected() const; bool select(bool); - //Set the end position of a selected string + /// Sets the end position of a selected string. void set_end_caret(); bool hit_text_area(const point&) const; bool hit_select_area(nana::upoint pos) const; @@ -199,6 +213,7 @@ namespace nana{ namespace widgets /// Returns width of text area excluding the vscroll size. unsigned width_pixels() const; + window window_handle() const; public: void draw_scroll_rectangle(); void render(bool focused); @@ -227,46 +242,43 @@ namespace nana{ namespace widgets skeletons::textbase& textbase(); const skeletons::textbase& textbase() const; private: - nana::color_t _m_bgcolor() const; + bool _m_accepts(char_type) const; + ::nana::color _m_bgcolor() const; bool _m_scroll_text(bool vertical); void _m_on_scroll(const arg_mouse&); void _m_scrollbar(); - nana::size _m_text_area() const; + ::nana::size _m_text_area() const; void _m_get_scrollbar_size(); void _m_reset(); - nana::upoint _m_put(nana::string); - nana::upoint _m_erase_select(); + ::nana::upoint _m_put(nana::string); + ::nana::upoint _m_erase_select(); bool _m_make_select_string(nana::string&) const; static bool _m_resolve_text(const nana::string&, std::vector> & lines); bool _m_cancel_select(int align); unsigned _m_tabs_pixels(size_type tabs) const; - nana::size _m_text_extent_size(const char_type*) const; nana::size _m_text_extent_size(const char_type*, size_type n) const; - //_m_move_offset_x_while_over_border - //@brief: Moves the view window + /// Moves the view of window. bool _m_move_offset_x_while_over_border(int many); bool _m_move_select(bool record_undo); int _m_text_top_base() const; - //_m_endx - //@brief: Gets the right point of text area + + /// Returns the right point of text area. int _m_endx() const; - //_m_endy - //@brief: Get the bottom point of text area + /// Returns the bottom point of text area. int _m_endy() const; - void _m_draw_tip_string() const; - + void _m_draw_parse_string(const keyword_parser&, bool rtl, ::nana::point pos, const ::nana::color& fgcolor, const ::nana::char_t*, std::size_t len) const; //_m_draw_string //@brief: Draw a line of string - void _m_draw_string(int top, nana::color_t color, const nana::upoint& str_pos, const nana::string&, bool if_mask) const; - //_m_draw - //@brief: Draw a character at a position specified by caret pos. - //@return: true if beyond the border - bool _m_draw(nana::char_t, std::size_t secondary_before); + void _m_draw_string(int top, const ::nana::color&, const nana::upoint& str_pos, const nana::string&, bool if_mask) const; + //_m_update_caret_line + //@brief: redraw whole line specified by caret pos. + //@return: true if caret overs the border + bool _m_update_caret_line(std::size_t secondary_before); bool _m_get_sort_select_points(nana::upoint&, nana::upoint&) const; void _m_offset_y(int y); @@ -279,6 +291,9 @@ namespace nana{ namespace widgets undoable undo_; nana::window window_; graph_reference graph_; + const text_editor_scheme* scheme_; + std::unique_ptr keywords_; + skeletons::textbase textbase_; nana::char_t mask_char_{0}; @@ -286,6 +301,9 @@ namespace nana{ namespace widgets struct attributes { + accepts acceptive{ accepts::no_restrict }; + std::function pred_acceptive; + nana::string tip_string; bool line_wrapped{false}; @@ -308,7 +326,7 @@ namespace nana{ namespace widgets unsigned scroll_pixels; unsigned vscroll; unsigned hscroll; - std::function border_renderer; + std::function border_renderer; }text_area_; struct selection diff --git a/include/nana/gui/widgets/skeletons/text_editor_scheme.hpp b/include/nana/gui/widgets/skeletons/text_editor_scheme.hpp new file mode 100644 index 00000000..00806b3b --- /dev/null +++ b/include/nana/gui/widgets/skeletons/text_editor_scheme.hpp @@ -0,0 +1,22 @@ + +#ifndef NANA_WIDGETS_SKELETONS_TEXT_EDITOR_SCHEME_HPP +#define NANA_WIDGETS_SKELETONS_TEXT_EDITOR_SCHEME_HPP + +#include "../../detail/widget_colors.hpp" + +namespace nana +{ + namespace widgets + { + namespace skeletons + { + struct text_editor_scheme + : public ::nana::widget_colors + { + color_proxy selection{static_cast(0x3399FF)}; + color_proxy selection_text{colors::white}; + }; + } + } +} +#endif \ No newline at end of file diff --git a/include/nana/gui/widgets/skeletons/text_token_stream.hpp b/include/nana/gui/widgets/skeletons/text_token_stream.hpp index a753f3f4..024c12ce 100644 --- a/include/nana/gui/widgets/skeletons/text_token_stream.hpp +++ b/include/nana/gui/widgets/skeletons/text_token_stream.hpp @@ -45,9 +45,7 @@ namespace nana{ namespace widgets{ namespace skeletons tokenizer(const nana::string& s, bool format_enabled) : iptr_(s.data()), endptr_(s.data() + s.size()), - format_enabled_(format_enabled), - format_state_(false), - revert_token_(token::eof) + format_enabled_(format_enabled) { } @@ -414,17 +412,14 @@ namespace nana{ namespace widgets{ namespace skeletons } } private: - const nana::char_t * iptr_; - const nana::char_t * endptr_; + const ::nana::char_t * iptr_; + const ::nana::char_t * endptr_; const bool format_enabled_; - bool format_state_; + bool format_state_{false}; - nana::string idstr_; + ::nana::string idstr_; std::pair binary_; - - std::size_t whspace_size_; - - token revert_token_; + token revert_token_{token::eof}; }; //The fblock states a format, and a format from which it is inherted @@ -439,16 +434,16 @@ namespace nana{ namespace widgets{ namespace skeletons }; }; - nana::string font; + ::nana::string font; std::size_t font_size; bool bold; bool bold_empty; //bold should be ignored if bold_empty is true aligns::t text_align; - nana::color_t bgcolor; //If the color is not specified, it will be ignored, and the system will search for its parent. - nana::color_t fgcolor; //ditto + ::nana::color bgcolor; //If the color is not specified, it will be ignored, and the system will search for its parent. + ::nana::color fgcolor; //ditto - nana::string target; - nana::string url; + ::nana::string target; + ::nana::string url; fblock * parent; }; @@ -528,7 +523,7 @@ namespace nana{ namespace widgets{ namespace skeletons { public: data_image(const nana::string& imgpath, const nana::size & sz, std::size_t limited) - : image_(imgpath), limited_(limited) + : image_(imgpath)//, limited_(limited) { size_ = image_.size(); @@ -597,7 +592,6 @@ namespace nana{ namespace widgets{ namespace skeletons nana::string str_; nana::paint::image image_; nana::size size_; - std::size_t limited_; }; class dstream @@ -741,41 +735,45 @@ namespace nana{ namespace widgets{ namespace skeletons switch(tknizer.read()) { case token::number: - fp->fgcolor = tknizer.number(); + { + pixel_color_t px; + px.value = static_cast(tknizer.number()); + fp->fgcolor = {px.element.red, px.element.green, px.element.blue}; + } break; case token::red: - fp->fgcolor = 0xFF0000; + fp->fgcolor = colors::red; break; case token::green: - fp->fgcolor = 0xFF00; + fp->fgcolor = colors::green; break; case token::blue: - fp->fgcolor = 0xFF; + fp->fgcolor = colors::blue; break; case token::white: - fp->fgcolor = 0xFFFFFF; + fp->fgcolor = colors::white; break; case token::black: - fp->fgcolor = 0x0; + fp->fgcolor = colors::black; break; default: throw std::runtime_error(""); } break; case token::red: //support the omitting of color. - fp->fgcolor = 0xFF0000; + fp->fgcolor = colors::red; break; case token::green: //support the omitting of color. - fp->fgcolor = 0xFF00; + fp->fgcolor = colors::green; break; case token::blue: //support the omitting of color. - fp->fgcolor = 0xFF; + fp->fgcolor = colors::blue; break; case token::white: //support the omitting of color. - fp->fgcolor = 0xFFFFFF; + fp->fgcolor = colors::white; break; case token::black: //support the omitting of color. - fp->fgcolor = 0x0; + fp->fgcolor = colors::black; break; case token::baseline: fp->text_align = fblock::aligns::baseline; @@ -867,10 +865,6 @@ namespace nana{ namespace widgets{ namespace skeletons fbp->bold_empty = true; fbp->text_align = fblock::aligns::baseline; - //Refer to the definition for the color specification. - fbp->bgcolor = 0xFFFFFFFF; - fbp->fgcolor = 0xFFFFFFFF; - fbp->parent = nullptr; fblocks_.push_back(fbp); @@ -910,8 +904,7 @@ namespace nana{ namespace widgets{ namespace skeletons v.data_ptr = new data_text(idstr); break; default: - int * debug = 0; //for debug - *debug = 0; + break; } line.push_back(v); @@ -928,7 +921,6 @@ namespace nana{ namespace widgets{ namespace skeletons } private: - bool format_enabled_; std::vector fblocks_; std::list > lines_; diff --git a/include/nana/gui/widgets/skeletons/textbase.hpp b/include/nana/gui/widgets/skeletons/textbase.hpp index 3c1cae59..6bdcf105 100644 --- a/include/nana/gui/widgets/skeletons/textbase.hpp +++ b/include/nana/gui/widgets/skeletons/textbase.hpp @@ -1,7 +1,7 @@ /* * A textbase class implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -511,6 +511,9 @@ namespace skeletons _m_first_change(); changed_ = true; } + + if (evt_agent_) + evt_agent_->text_changed(); } private: std::deque text_cont_; diff --git a/include/nana/gui/widgets/skeletons/textbase_export_interface.hpp b/include/nana/gui/widgets/skeletons/textbase_export_interface.hpp index 6f474721..eeda5b45 100644 --- a/include/nana/gui/widgets/skeletons/textbase_export_interface.hpp +++ b/include/nana/gui/widgets/skeletons/textbase_export_interface.hpp @@ -1,7 +1,7 @@ /* * Definitions of textbase export interfaces * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -25,6 +25,7 @@ namespace nana{ namespace widgets virtual ~textbase_event_agent_interface() = default; virtual void first_change() = 0; ///< An event for the text first change after text has been opened or stored. + virtual void text_changed() = 0; ///< An event for the change of text. }; }//end namespace skeletons }//end namespace widgets diff --git a/include/nana/gui/widgets/slider.hpp b/include/nana/gui/widgets/slider.hpp index 51ada7e5..ca1ab75a 100644 --- a/include/nana/gui/widgets/slider.hpp +++ b/include/nana/gui/widgets/slider.hpp @@ -1,7 +1,7 @@ /* * A Slider Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -19,8 +19,11 @@ namespace nana class slider; struct arg_slider + : public event_arg { slider & widget; + + arg_slider(slider&); }; namespace drawerbase @@ -41,7 +44,7 @@ namespace nana class provider { public: - virtual ~provider() = 0; + virtual ~provider() = default; virtual nana::string adorn_trace(unsigned vmax, unsigned vadorn) const = 0; }; @@ -74,7 +77,7 @@ namespace nana unsigned vcur_scale; //pixels of vcur scale. }; - virtual ~renderer() = 0; + virtual ~renderer() = default; virtual void background(window, graph_reference, bool isglass) = 0; virtual void adorn(window, graph_reference, const adorn_t&) = 0; diff --git a/include/nana/gui/widgets/spinbox.hpp b/include/nana/gui/widgets/spinbox.hpp new file mode 100644 index 00000000..a1a85021 --- /dev/null +++ b/include/nana/gui/widgets/spinbox.hpp @@ -0,0 +1,124 @@ +/* + * A Spin box widget + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 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/gui/widgets/spinbox.hpp + */ + +#ifndef NANA_GUI_WIDGET_SPINBOX_HPP +#define NANA_GUI_WIDGET_SPINBOX_HPP +#include "widget.hpp" +#include "skeletons/text_editor_scheme.hpp" + +namespace nana +{ + class spinbox; + + struct arg_spinbox + : public event_arg + { + spinbox & widget; + arg_spinbox(spinbox&); + }; + + namespace drawerbase + { + namespace spinbox + { + struct spinbox_events + : public general_events + { + basic_event text_changed; + }; + + /// Declaration of internal spinbox implementation + class implementation; + + /// Drawer of spinbox + class drawer + : public ::nana::drawer_trigger + { + drawer(const drawer&) = delete; + drawer(drawer&&) = delete; + drawer& operator=(const drawer&) = delete; + drawer& operator=(drawer&&) = delete; + public: + drawer(); + ~drawer(); + implementation * impl() const; + private: + //Overrides drawer_trigger + void attached(widget_reference, graph_reference) override; + void refresh(graph_reference) override; + + void focus(graph_reference, const arg_focus&) override; + void mouse_wheel(graph_reference, const arg_wheel&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse& arg) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void key_press(graph_reference, const arg_keyboard&) override; + void key_char(graph_reference, const arg_keyboard&) override; + void resized(graph_reference, const arg_resized&) override; + private: + implementation * const impl_; + }; + }; + }//end namespace drawerbase + + /// Spinbox Widget + class spinbox + : public widget_object + { + public: + /// Constructs a spinbox. + spinbox(); + spinbox(window, bool visible); + spinbox(window, const nana::rectangle& = {}, bool visible = true); + + /// Sets the widget whether it accepts user keyboard input. + /// @param accept Set to indicate whether it accepts uesr keyboard input. + void editable(bool accept); + + /// Determines whether the widget accepts user keyboard input. + bool editable() const; + + /// Sets the numeric spin values and step. + void range(int begin, int last, int step); + void range(double begin, double last, double step); + + /// Sets the string spin values. + void range(std::initializer_list values_utf8); + void range(std::initializer_list values); + + /// Gets the spined value + ::nana::string value() const; + void value(const ::nana::string&); + int to_int() const; + double to_double() const; + + /// Sets the modifiers + void modifier(std::wstring prefix, std::wstring suffix); + void modifier(const std::string & prefix_utf8, const std::string& suffix_utf8); + private: + ::nana::string _m_caption() const; + void _m_caption(::nana::string&&); + }; //end class spinbox + + namespace dev + { + template<> + struct widget_traits + { + using event_type = drawerbase::spinbox::spinbox_events; + using scheme_type = ::nana::widgets::skeletons::text_editor_scheme; + }; + } +}//end namespace nana + +#endif //NANA_GUI_WIDGET_SPINBOX_HPP diff --git a/include/nana/gui/widgets/tabbar.hpp b/include/nana/gui/widgets/tabbar.hpp index 3e265a55..4d641461 100644 --- a/include/nana/gui/widgets/tabbar.hpp +++ b/include/nana/gui/widgets/tabbar.hpp @@ -1,7 +1,7 @@ /* * A Tabbar implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -24,9 +24,14 @@ namespace nana template struct arg_tabbar + : public event_arg { tabbar & widget; T & value; + + arg_tabbar(tabbar& wdg, T& v) + : widget{ wdg }, value{ v } + {} }; template @@ -57,7 +62,7 @@ namespace nana class event_agent_interface { public: - virtual ~event_agent_interface() = 0; + virtual ~event_agent_interface() = default; virtual void added(std::size_t) = 0; virtual void activated(std::size_t) = 0; virtual bool removed(std::size_t) = 0; @@ -67,18 +72,18 @@ namespace nana { public: typedef item_renderer item_renderer_type; - typedef nana::paint::graphics & graph_reference; + typedef ::nana::paint::graphics & graph_reference; enum state_t{disable, normal, highlight, press}; struct item_t { - nana::rectangle r; - nana::color_t bgcolor; - nana::color_t fgcolor; + ::nana::rectangle r; + ::nana::color bgcolor; + ::nana::color fgcolor; }; - virtual ~item_renderer() = 0; - virtual void background(graph_reference, const nana::rectangle& r, nana::color_t bgcolor) = 0; + virtual ~item_renderer() = default; + virtual void background(graph_reference, const nana::rectangle& r, const ::nana::color& bgcolor) = 0; virtual void item(graph_reference, const item_t&, bool active, state_t) = 0; virtual void close_fly(graph_reference, const nana::rectangle&, bool active, state_t) = 0; @@ -150,7 +155,7 @@ namespace nana std::size_t length() const; bool close_fly(bool); void relate(size_t, window); - void tab_color(std::size_t, bool is_bgcolor, nana::color_t); + void tab_color(std::size_t, bool is_bgcolor, const ::nana::color&); void tab_image(size_t, const nana::paint::image&); void text(std::size_t, const nana::string&); nana::string text(std::size_t) const; @@ -278,14 +283,14 @@ namespace nana this->get_drawer_trigger().relate(pos, wd); } - void tab_bgcolor(std::size_t i, nana::color_t color) + void tab_bgcolor(std::size_t i, const ::nana::color& clr) { - this->get_drawer_trigger().tab_color(i, true, color); + this->get_drawer_trigger().tab_color(i, true, clr); } - void tab_fgcolor(std::size_t i, nana::color_t color) + void tab_fgcolor(std::size_t i, const ::nana::color& clr) { - this->get_drawer_trigger().tab_color(i, false, color); + this->get_drawer_trigger().tab_color(i, false, clr); } void tab_image(std::size_t i, const nana::paint::image& img) diff --git a/include/nana/gui/widgets/textbox.hpp b/include/nana/gui/widgets/textbox.hpp index 11528b35..045a05fc 100644 --- a/include/nana/gui/widgets/textbox.hpp +++ b/include/nana/gui/widgets/textbox.hpp @@ -1,7 +1,7 @@ /* * A Textbox Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -13,14 +13,18 @@ #define NANA_GUI_WIDGET_TEXTBOX_HPP #include #include "skeletons/textbase_export_interface.hpp" +#include "skeletons/text_editor_scheme.hpp" namespace nana { class textbox; struct arg_textbox + : public event_arg { textbox& widget; + + arg_textbox(textbox&); }; namespace widgets @@ -39,14 +43,16 @@ namespace nana : public general_events { basic_event first_change; + basic_event text_changed; }; class event_agent : public widgets::skeletons::textbase_event_agent_interface { public: - event_agent(::nana::textbox& wdg); + event_agent(::nana::textbox&); void first_change() override; + void text_changed() override; private: ::nana::textbox & widget_; }; @@ -56,12 +62,11 @@ namespace nana : public drawer_trigger { public: - typedef widgets::skeletons::text_editor text_editor; + using text_editor = widgets::skeletons::text_editor; drawer(); text_editor * editor(); const text_editor * editor() const; - void set_accept(std::function &&); private: void attached(widget_reference, graph_reference) override; void detached() override; @@ -79,15 +84,8 @@ namespace nana void typeface_changed(graph_reference) override; private: void _m_text_area(unsigned width, unsigned height); - void _m_draw_border(graph_reference, nana::color_t bgcolor); private: widget* widget_; - struct status_type - { - bool has_focus; //Indicates whether it has the keyboard focus - }status_; - - std::function pred_acceptive_; widgets::skeletons::text_editor * editor_; std::unique_ptr evt_agent_; }; @@ -96,7 +94,7 @@ namespace nana /// Allow users to enter and edit text by typing on the keyboard. class textbox - :public widget_object + :public widget_object { public: /// The default constructor without creating the widget. @@ -181,11 +179,28 @@ namespace nana double to_double() const; textbox& from(int); textbox& from(double); + + void set_highlight(const std::string& name, const ::nana::color& fgcolor, const ::nana::color& bgcolor); + void erase_highlight(const std::string& name); + void set_keywords(const std::string& name, bool case_sensitive, bool whole_word_match, std::initializer_list kw_list); + void set_keywords(const std::string& name, bool case_sensitive, bool whole_word_match, std::initializer_list kw_list_utf8); + void erase_keyword(const nana::string& kw); protected: //Overrides widget's virtual functions ::nana::string _m_caption() const override; void _m_caption(::nana::string&&) override; void _m_typeface(const paint::font&) override; }; + + namespace dev + { + /// Traits for widget classes + template<> + struct widget_traits + { + using event_type = drawerbase::textbox::textbox_events; + using scheme_type = ::nana::widgets::skeletons::text_editor_scheme; + }; + } }//end namespace nana #endif diff --git a/include/nana/gui/widgets/toolbar.hpp b/include/nana/gui/widgets/toolbar.hpp index fd3b43df..35f539ac 100644 --- a/include/nana/gui/widgets/toolbar.hpp +++ b/include/nana/gui/widgets/toolbar.hpp @@ -1,7 +1,7 @@ /* * A Toolbar Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -21,9 +21,12 @@ namespace nana class toolbar; struct arg_toolbar + : public event_arg { toolbar& widget; std::size_t button; + + arg_toolbar(toolbar&, std::size_t); }; namespace drawerbase @@ -67,7 +70,7 @@ namespace nana void mouse_up(graph_reference, const arg_mouse&) override; private: size_type _m_which(int x, int y, bool want_if_disabled) const; - void _m_draw_background(nana::color_t); + void _m_draw_background(const ::nana::color&); void _m_draw(); void _m_owner_sized(const arg_resized&); private: @@ -87,7 +90,7 @@ namespace nana public: typedef std::size_t size_type; ///< A type to count the number of elements. - toolbar(); + toolbar() = default; toolbar(window, bool visible); toolbar(window, const rectangle& = rectangle(), bool visible = true); diff --git a/include/nana/gui/widgets/treebox.hpp b/include/nana/gui/widgets/treebox.hpp index a5235880..4d8748eb 100644 --- a/include/nana/gui/widgets/treebox.hpp +++ b/include/nana/gui/widgets/treebox.hpp @@ -1,7 +1,7 @@ /* * A Tree Box Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -74,11 +74,13 @@ namespace nana virtual ~renderer_interface() {} - virtual void bground(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const compset_interface *) const = 0; - virtual void expander(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const compset_interface *) const = 0; - virtual void crook(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const compset_interface *) const = 0; - virtual void icon(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const compset_interface *) const = 0; - virtual void text(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const compset_interface *) const = 0; + virtual void set_color(const nana::color& bgcolor, const nana::color& fgcolor) = 0; + + virtual void bground(graph_reference, const compset_interface *) const = 0; + virtual void expander(graph_reference, const compset_interface *) const = 0; + virtual void crook(graph_reference, const compset_interface *) const = 0; + virtual void icon(graph_reference, const compset_interface *) const = 0; + virtual void text(graph_reference, const compset_interface *) const = 0; }; class item_proxy; @@ -331,10 +333,13 @@ namespace nana }//end namespace drawerbase struct arg_treebox + : public event_arg { treebox& widget; drawerbase::treebox::item_proxy & item; bool operated; + + arg_treebox(treebox&, drawerbase::treebox::item_proxy&, bool operated); }; namespace drawerbase @@ -411,8 +416,6 @@ namespace nana /// Determinte whether the checkbox is enabled. bool checkable() const; - treebox& icon(const nana::string& id, const node_image_type& node_img); - node_image_type& icon(const nana::string& id) const; void icon_erase(const nana::string& id); diff --git a/include/nana/gui/widgets/widget.hpp b/include/nana/gui/widgets/widget.hpp index ce11aeec..0de7a33d 100644 --- a/include/nana/gui/widgets/widget.hpp +++ b/include/nana/gui/widgets/widget.hpp @@ -1,7 +1,7 @@ /* * The fundamental widget class implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -22,15 +22,13 @@ namespace nana { - class drawer_trigger; - - /// Abstract class for defining the capacity interface. + /// Abstract class for defining the capacity interface. class widget : nana::noncopyable, nana::nonmovable { typedef void(*dummy_bool_type)(widget* (*)(const widget&)); public: - virtual ~widget(); + virtual ~widget() = default; virtual window handle() const = 0; ///< Returns the handle of window, returns 0 if window is not created. bool empty() const; ///< Determines whether the manipulator is handling a window. void close(); @@ -38,6 +36,7 @@ namespace nana window parent() const; nana::string caption() const; + void caption(std::string utf8); void caption(nana::string); template @@ -73,14 +72,18 @@ namespace nana void move(int x, int y); void move(const rectangle&); - void foreground(nana::color_t); - nana::color_t foreground() const; - void background(nana::color_t); - nana::color_t background() const; + void fgcolor(const nana::color&); + nana::color fgcolor() const; + void bgcolor(const nana::color&); + nana::color bgcolor() const; general_events& events() const; void umake_event(event_handle eh) const; ///< Deletes an event callback by a handle. + + widget& register_shortkey(char_t); ///< Registers a shortkey. To remove a registered key, pass 0. + + widget& take_active(bool activated, window take_if_not_activated); widget& tooltip(const nana::string&); operator dummy_bool_type() const; @@ -106,21 +109,24 @@ namespace nana virtual void _m_typeface(const nana::paint::font& font); virtual nana::paint::font _m_typeface() const; - virtual void _m_foreground(nana::color_t); - virtual nana::color_t _m_foreground() const; - virtual void _m_background(nana::color_t); - virtual nana::color_t _m_background() const; + virtual void _m_fgcolor(const nana::color&); + virtual nana::color _m_fgcolor() const; + virtual void _m_bgcolor(const nana::color&); + virtual nana::color _m_bgcolor() const; }; /// Base class of all the classes defined as a widget window. Defaultly a widget_tag - template + template class widget_object: public widget { protected: typedef DrawerTrigger drawer_trigger_t; public: + using scheme_type = Scheme; + widget_object() - : events_(std::make_shared()) + : events_{ std::make_shared() }, + scheme_{ API::dev::make_scheme() } {} ~widget_object() @@ -139,12 +145,13 @@ namespace nana return create(parent_wd, rectangle(), visible); } - bool create(window parent_wd, const rectangle & r = rectangle(), bool visible = true) ///< in a widget/root window specified by parent_wd. + bool create(window parent_wd, const rectangle & r = {}, bool visible = true) ///< in a widget/root window specified by parent_wd. { if(parent_wd && this->empty()) { handle_ = API::dev::create_widget(parent_wd, r, this); API::dev::set_events(handle_, events_); + API::dev::set_scheme(handle_, scheme_.get()); API::dev::attach_signal(handle_, *this, &widget_object::signal); API::dev::attach_drawer(*this, trigger_); if(visible) @@ -170,6 +177,11 @@ namespace nana { return API::widget_borderless(handle_); } + + scheme_type& scheme() const + { + return *scheme_; + } protected: DrawerTrigger& get_drawer_trigger() { @@ -200,7 +212,7 @@ namespace nana } } - general_events& _m_get_general_events() const + general_events& _m_get_general_events() const override { return *events_; } @@ -208,18 +220,20 @@ namespace nana window handle_{nullptr}; DrawerTrigger trigger_; std::shared_ptr events_; + std::unique_ptr scheme_; };//end class widget_object /// Base class of all the classes defined as a non-graphics-buffer widget window. The second template parameter DrawerTrigger is always ignored.\see nana::panel - template - class widget_object: public widget + template + class widget_object: public widget { protected: typedef DrawerTrigger drawer_trigger_t; public: + using scheme_type = Scheme; widget_object() - : events_(std::make_shared()) + : events_{ std::make_shared() }, scheme_{ API::dev::make_scheme() } {} ~widget_object() @@ -244,6 +258,7 @@ namespace nana { handle_ = API::dev::create_lite_widget(parent_wd, r, this); API::dev::set_events(handle_, events_); + API::dev::set_scheme(handle_, scheme_.get()); if(visible) API::show_window(handle_, true); this->_m_complete_creation(); @@ -251,10 +266,15 @@ namespace nana return (this->empty() == false); } - window handle() const + window handle() const override { return handle_; } + + scheme_type& scheme() const + { + return *scheme_; + } private: void signal(detail::signals::code code, const detail::signals& sig) { @@ -275,23 +295,25 @@ namespace nana } } - general_events& _m_get_general_events() const + general_events& _m_get_general_events() const override { return *events_; } private: window handle_{nullptr}; std::shared_ptr events_; + std::unique_ptr scheme_; };//end class widget_object /// Base class of all the classes defined as a root window. \see nana::form - template - class widget_object: public widget + template + class widget_object: public widget { protected: typedef DrawerTrigger drawer_trigger_t; public: + using scheme_type = Scheme; widget_object() { @@ -299,13 +321,13 @@ namespace nana _m_bind_and_attach(); } - widget_object(const rectangle& r, const appearance& apr = appearance()) + widget_object(const rectangle& r, const appearance& apr = {}) { handle_ = API::dev::create_window(nullptr, false, r, apr, this); _m_bind_and_attach(); } - widget_object(window owner, bool nested, const rectangle& r = rectangle(), const appearance& apr = appearance()) + widget_object(window owner, bool nested, const rectangle& r = {}, const appearance& apr = {}) { handle_ = API::dev::create_window(owner, nested, r, apr, this); _m_bind_and_attach(); @@ -327,12 +349,7 @@ namespace nana API::activate_window(handle_); } - void bring_to_top() - { - API::bring_to_top(handle_); - } - - window handle() const + window handle() const override { return handle_; } @@ -342,6 +359,11 @@ namespace nana return API::root(handle_); } + void bring_top(bool activated) + { + API::bring_top(handle(), activated); + } + window owner() const { return API::get_owner_window(handle_); @@ -362,9 +384,30 @@ namespace nana API::zoom_window(handle_, ask_for_max); } - bool is_zoomed(bool ask_for_max) const + bool is_zoomed(bool check_maximized) const { - return API::is_window_zoomed(handle_, ask_for_max); + return API::is_window_zoomed(handle_, check_maximized); + } + + widget_object& z_order(window wd_after, z_order_action action_if_no_wd_after) + { + API::set_window_z_order(handle_, wd_after, action_if_no_wd_after); + return *this; + } + + scheme_type& scheme() const + { + return *scheme_; + } + + void draw_through(std::function draw_fn) + { + API::draw_through(handle(), draw_fn); + } + + void map_through_widgets(native_drawable_type drawable) + { + API::map_through_widgets(handle(), drawable); } protected: DrawerTrigger& get_drawer_trigger() @@ -400,11 +443,14 @@ namespace nana { events_ = std::make_shared(); API::dev::set_events(handle_, events_); + + scheme_ = API::dev::make_scheme(); + API::dev::set_scheme(handle_, scheme_.get()); API::dev::attach_signal(handle_, *this, &widget_object::signal); API::dev::attach_drawer(*this, trigger_); } - general_events& _m_get_general_events() const + general_events& _m_get_general_events() const override { return *events_; } @@ -412,21 +458,24 @@ namespace nana window handle_; DrawerTrigger trigger_; std::shared_ptr events_; + std::unique_ptr scheme_; };//end class widget_object /// Base class of all the classes defined as a frame window. \see nana::frame - template - class widget_object: public widget{}; + template + class widget_object: public widget{}; /// Especialization. Base class of all the classes defined as a frame window. \see nana::frame - template - class widget_object: public widget + template + class widget_object: public widget { protected: typedef int drawer_trigger_t; public: + using scheme_type = Scheme; + widget_object() - : events_(std::make_shared()) + : events_{ std::make_shared() }, scheme_{ API::dev::make_scheme() } {} ~widget_object() @@ -451,6 +500,7 @@ namespace nana { handle_ = API::dev::create_frame(parent_wd, r, this); API::dev::set_events(handle_, events_); + API::dev::set_scheme(handle_, scheme_.get()); API::dev::attach_signal(handle_, *this, &widget_object::signal); API::show_window(handle_, visible); this->_m_complete_creation(); @@ -458,10 +508,15 @@ namespace nana return (this->empty() == false); } - window handle() const + window handle() const override { return handle_; } + + scheme_type& scheme() const + { + return *scheme_; + } private: virtual drawer_trigger* get_drawer_trigger() { @@ -487,13 +542,14 @@ namespace nana } } - general_events& _m_get_general_events() const + general_events& _m_get_general_events() const override { return *events_; } private: window handle_{nullptr}; std::shared_ptr events_; + std::unique_ptr scheme_; };//end class widget_object }//end namespace nana #endif diff --git a/include/nana/gui/wvl.hpp b/include/nana/gui/wvl.hpp index a69f350a..e9855208 100644 --- a/include/nana/gui/wvl.hpp +++ b/include/nana/gui/wvl.hpp @@ -1,6 +1,7 @@ /* * Nana GUI Library Definition - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -15,6 +16,7 @@ #define NANA_GUI_WVL_HPP #include "programming_interface.hpp" +#include "screen.hpp" #include "widgets/form.hpp" #include "drawing.hpp" #include "msgbox.hpp" diff --git a/include/nana/internationalization.hpp b/include/nana/internationalization.hpp index 4c9942af..341c8e97 100644 --- a/include/nana/internationalization.hpp +++ b/include/nana/internationalization.hpp @@ -127,7 +127,7 @@ namespace nana class arg_eval; template - class arg_function + class arg_function: public eval_arg { public: arg_function(std::function fn) @@ -208,4 +208,4 @@ namespace nana };//end class i18n_eval; } -#endif//NANA_I18N_HPP \ No newline at end of file +#endif//NANA_I18N_HPP diff --git a/include/nana/paint/detail/image_bmp.hpp b/include/nana/paint/detail/image_bmp.hpp index a329628a..e7b27c35 100644 --- a/include/nana/paint/detail/image_bmp.hpp +++ b/include/nana/paint/detail/image_bmp.hpp @@ -102,7 +102,7 @@ namespace nana{ namespace paint pixbuf_.open(info->bmiHeader.biWidth, height_pixels); - pixel_rgb_t * d = pixbuf_.raw_ptr(0); + auto d = pixbuf_.raw_ptr(0); if(16 <= info->bmiHeader.biBitCount) { @@ -110,23 +110,23 @@ namespace nana{ namespace paint } else if(8 == info->bmiHeader.biBitCount) { - const pixel_rgb_t * const lend = d + info->bmiHeader.biWidth * height_pixels; + const auto lend = d + info->bmiHeader.biWidth * height_pixels; if(info->bmiHeader.biHeight < 0) { - const unsigned char* s = bits; + auto s = bits; while(d < lend) { - pixel_rgb_t * d_p = d; - pixel_rgb_t * const dpend = d_p + info->bmiHeader.biWidth; - const unsigned char * s_p = s; + auto d_p = d; + auto dpend = d_p + info->bmiHeader.biWidth; + auto s_p = s; while(d_p != dpend) { rgb_quad & rgb = info->bmiColors[*s_p++]; - d_p->u.element.red = rgb.rgbRed; - d_p->u.element.green = rgb.rgbGreen; - d_p->u.element.blue = rgb.rgbBlue; - d_p->u.element.alpha_channel = rgb.rgbReserved; + d_p->element.red = rgb.rgbRed; + d_p->element.green = rgb.rgbGreen; + d_p->element.blue = rgb.rgbBlue; + d_p->element.alpha_channel = rgb.rgbReserved; ++d_p; } d = dpend; @@ -135,19 +135,19 @@ namespace nana{ namespace paint } else { - const unsigned char* s = bits + bytes_per_line * (height_pixels - 1); + const auto* s = bits + bytes_per_line * (height_pixels - 1); while(d < lend) { - pixel_rgb_t * d_p = d; - pixel_rgb_t * const dpend = d_p + info->bmiHeader.biWidth; - const unsigned char * s_p = s; + auto d_p = d; + auto* const dpend = d_p + info->bmiHeader.biWidth; + const auto * s_p = s; while(d_p != dpend) { rgb_quad & rgb = info->bmiColors[*s_p++]; - d_p->u.element.red = rgb.rgbRed; - d_p->u.element.green = rgb.rgbGreen; - d_p->u.element.blue = rgb.rgbBlue; - d_p->u.element.alpha_channel = rgb.rgbReserved; + d_p->element.red = rgb.rgbRed; + d_p->element.green = rgb.rgbGreen; + d_p->element.blue = rgb.rgbBlue; + d_p->element.alpha_channel = rgb.rgbReserved; ++d_p; } d = dpend; @@ -157,23 +157,23 @@ namespace nana{ namespace paint } else if(4 == info->bmiHeader.biBitCount) { - const pixel_rgb_t * const lend = d + info->bmiHeader.biWidth * height_pixels; + const auto * const lend = d + info->bmiHeader.biWidth * height_pixels; if(info->bmiHeader.biHeight < 0) { const unsigned char* s = bits; while(d < lend) { - pixel_rgb_t * d_p = d; - pixel_rgb_t * const dpend = d_p + info->bmiHeader.biWidth; + auto d_p = d; + auto * const dpend = d_p + info->bmiHeader.biWidth; unsigned index = 0; while(d_p != dpend) { rgb_quad & rgb = info->bmiColors[(index & 1) ? (s[index >> 1] & 0xF) : (s[index >> 1] & 0xF0) >> 4]; - d_p->u.element.red = rgb.rgbRed; - d_p->u.element.green = rgb.rgbGreen; - d_p->u.element.blue = rgb.rgbBlue; - d_p->u.element.alpha_channel = rgb.rgbReserved; + d_p->element.red = rgb.rgbRed; + d_p->element.green = rgb.rgbGreen; + d_p->element.blue = rgb.rgbBlue; + d_p->element.alpha_channel = rgb.rgbReserved; ++d_p; ++index; } @@ -183,21 +183,21 @@ namespace nana{ namespace paint } else { - const unsigned char* s = bits + bytes_per_line * (height_pixels - 1); + const auto* s = bits + bytes_per_line * (height_pixels - 1); while(d < lend) { - pixel_rgb_t * d_p = d; - pixel_rgb_t * const dpend = d_p + info->bmiHeader.biWidth; + auto d_p = d; + auto * const dpend = d_p + info->bmiHeader.biWidth; unsigned index = 0; while(d_p != dpend) { rgb_quad & rgb = info->bmiColors[(index & 1) ? (s[index >> 1] & 0xF) : (s[index >> 1] & 0xF0) >> 4]; - d_p->u.element.red = rgb.rgbRed; - d_p->u.element.green = rgb.rgbGreen; - d_p->u.element.blue = rgb.rgbBlue; - d_p->u.element.alpha_channel = rgb.rgbReserved; + d_p->element.red = rgb.rgbRed; + d_p->element.green = rgb.rgbGreen; + d_p->element.blue = rgb.rgbBlue; + d_p->element.alpha_channel = rgb.rgbReserved; ++d_p; ++index; } @@ -208,24 +208,24 @@ namespace nana{ namespace paint } else if(2 == info->bmiHeader.biBitCount) { - const pixel_rgb_t * const lend = d + info->bmiHeader.biWidth * height_pixels; + const auto * const lend = d + info->bmiHeader.biWidth * height_pixels; if(info->bmiHeader.biHeight < 0) { const unsigned char* s = bits; while(d < lend) { - pixel_rgb_t * d_p = d; - pixel_rgb_t * const dpend = d_p + info->bmiHeader.biWidth; + auto d_p = d; + auto * const dpend = d_p + info->bmiHeader.biWidth; unsigned index = 0; while(d_p != dpend) { unsigned shift = (3 - (index & 0x3)) << 1; // (index % 4) * 2 rgb_quad& rgb = info->bmiColors[(s[index >> 2] & (0x3 << shift))>>shift]; - d_p->u.element.red = rgb.rgbRed; - d_p->u.element.green = rgb.rgbGreen; - d_p->u.element.blue = rgb.rgbBlue; - d_p->u.element.alpha_channel = rgb.rgbReserved; + d_p->element.red = rgb.rgbRed; + d_p->element.green = rgb.rgbGreen; + d_p->element.blue = rgb.rgbBlue; + d_p->element.alpha_channel = rgb.rgbReserved; ++d_p; ++index; } @@ -235,11 +235,11 @@ namespace nana{ namespace paint } else { - const unsigned char* s = bits + bytes_per_line * (height_pixels - 1); + const auto* s = bits + bytes_per_line * (height_pixels - 1); while(d < lend) { - pixel_rgb_t * d_p = d; - pixel_rgb_t * const dpend = d_p + info->bmiHeader.biWidth; + auto d_p = d; + auto * const dpend = d_p + info->bmiHeader.biWidth; unsigned index = 0; while(d_p != dpend) @@ -247,10 +247,10 @@ namespace nana{ namespace paint unsigned shift = (3 - (index & 0x3)) << 1; // (index % 4) * 2 rgb_quad& rgb = info->bmiColors[(s[index >> 2] & (0x3 << shift))>>shift]; - d_p->u.element.red = rgb.rgbRed; - d_p->u.element.green = rgb.rgbGreen; - d_p->u.element.blue = rgb.rgbBlue; - d_p->u.element.alpha_channel = rgb.rgbReserved; + d_p->element.red = rgb.rgbRed; + d_p->element.green = rgb.rgbGreen; + d_p->element.blue = rgb.rgbBlue; + d_p->element.alpha_channel = rgb.rgbReserved; ++d_p; ++index; } @@ -261,24 +261,24 @@ namespace nana{ namespace paint } else if(1 == info->bmiHeader.biBitCount) { - const pixel_rgb_t * const lend = d + info->bmiHeader.biWidth * height_pixels; + const auto * const lend = d + info->bmiHeader.biWidth * height_pixels; if(info->bmiHeader.biHeight < 0) { - const unsigned char* s = bits; + const auto* s = bits; while(d < lend) { - pixel_rgb_t * d_p = d; - pixel_rgb_t * const dpend = d_p + info->bmiHeader.biWidth; + auto d_p = d; + auto * const dpend = d_p + info->bmiHeader.biWidth; unsigned index = 0; while(d_p != dpend) { unsigned bi = (7 - (index & 7)); //(index % 8) rgb_quad & rgb = info->bmiColors[(s[index >> 3] & (1 << bi)) >> bi]; - d_p->u.element.red = rgb.rgbRed; - d_p->u.element.green = rgb.rgbGreen; - d_p->u.element.blue = rgb.rgbBlue; - d_p->u.element.alpha_channel = rgb.rgbReserved; + d_p->element.red = rgb.rgbRed; + d_p->element.green = rgb.rgbGreen; + d_p->element.blue = rgb.rgbBlue; + d_p->element.alpha_channel = rgb.rgbReserved; ++d_p; ++index; } @@ -288,11 +288,11 @@ namespace nana{ namespace paint } else { - const unsigned char* s = bits + bytes_per_line * (height_pixels - 1); + const auto* s = bits + bytes_per_line * (height_pixels - 1); while(d < lend) { - pixel_rgb_t * d_p = d; - pixel_rgb_t * const dpend = d_p + info->bmiHeader.biWidth; + auto d_p = d; + auto * const dpend = d_p + info->bmiHeader.biWidth; unsigned index = 0; while(d_p != dpend) @@ -300,10 +300,10 @@ namespace nana{ namespace paint unsigned bi = (7 - (index & 7)); rgb_quad & rgb = info->bmiColors[(s[index >> 3] & (1 << bi)) >> bi]; - d_p->u.element.red = rgb.rgbRed; - d_p->u.element.green = rgb.rgbGreen; - d_p->u.element.blue = rgb.rgbBlue; - d_p->u.element.alpha_channel = rgb.rgbReserved; + d_p->element.red = rgb.rgbRed; + d_p->element.green = rgb.rgbGreen; + d_p->element.blue = rgb.rgbBlue; + d_p->element.alpha_channel = rgb.rgbReserved; ++d_p; ++index; } diff --git a/include/nana/paint/detail/image_png.hpp b/include/nana/paint/detail/image_png.hpp index ef61df1f..9f54e8ef 100644 --- a/include/nana/paint/detail/image_png.hpp +++ b/include/nana/paint/detail/image_png.hpp @@ -72,7 +72,7 @@ namespace nana const bool is_alpha_enabled = ((PNG_COLOR_MASK_ALPHA & color_type) != 0); pixbuf_.alpha_channel(is_alpha_enabled); - if(is_alpha_enabled && (png_rowbytes == png_width * sizeof(pixel_rgb_t))) + if(is_alpha_enabled && (png_rowbytes == png_width * sizeof(pixel_argb_t))) { for(int i = 0; i < png_height; ++i) row_ptrs[i] = reinterpret_cast(pixbuf_.raw_ptr(i)); @@ -85,9 +85,9 @@ namespace nana auto p = pixbuf_.raw_ptr(i); for (int u = 0; u < png_width; ++u) { - auto t = p[u].u.element.red; - p[u].u.element.red = p[u].u.element.blue; - p[u].u.element.blue = t; + auto t = p[u].element.red; + p[u].element.red = p[u].element.blue; + p[u].element.blue = t; } } } @@ -103,32 +103,32 @@ namespace nana std::size_t png_pixel_bytes = png_rowbytes / png_width; - pixel_rgb_t * rgb_row_ptr = pixbuf_.raw_ptr(0); + pixel_argb_t * rgb_row_ptr = pixbuf_.raw_ptr(0); for(int y = 0; y < png_height; ++y) { png_bytep png_ptr = row_ptrs[y]; - pixel_rgb_t * rgb_end = rgb_row_ptr + png_width; + pixel_argb_t * rgb_end = rgb_row_ptr + png_width; if(is_alpha_enabled) { - for(pixel_rgb_t * i = rgb_row_ptr; i < rgb_end; ++i) + for(pixel_argb_t * i = rgb_row_ptr; i < rgb_end; ++i) { - i->u.element.red = png_ptr[0]; - i->u.element.green = png_ptr[1]; - i->u.element.blue = png_ptr[2]; - i->u.element.alpha_channel = png_ptr[3]; + i->element.red = png_ptr[0]; + i->element.green = png_ptr[1]; + i->element.blue = png_ptr[2]; + i->element.alpha_channel = png_ptr[3]; png_ptr += png_pixel_bytes; } } else { - for(pixel_rgb_t * i = rgb_row_ptr; i < rgb_end; ++i) + for(pixel_argb_t * i = rgb_row_ptr; i < rgb_end; ++i) { - i->u.element.red = png_ptr[0]; - i->u.element.green = png_ptr[1]; - i->u.element.blue = png_ptr[2]; - i->u.element.alpha_channel = 255; + i->element.red = png_ptr[0]; + i->element.green = png_ptr[1]; + i->element.blue = png_ptr[2]; + i->element.alpha_channel = 255; png_ptr += png_pixel_bytes; } } diff --git a/include/nana/paint/detail/image_processor.hpp b/include/nana/paint/detail/image_processor.hpp index 44129682..13d1d6ab 100644 --- a/include/nana/paint/detail/image_processor.hpp +++ b/include/nana/paint/detail/image_processor.hpp @@ -38,32 +38,32 @@ namespace detail double rate_x = double(r_src.width) / r_dst.width; double rate_y = double(r_src.height) / r_dst.height; - pixel_rgb_t * s_raw_pixbuf = s_pixbuf.raw_ptr(0); + pixel_argb_t * s_raw_pixbuf = s_pixbuf.raw_ptr(0); if(s_pixbuf.alpha_channel()) { for(std::size_t row = 0; row < r_dst.height; ++row) { - const pixel_rgb_t * s_line = pixel_at(s_raw_pixbuf, (static_cast(row * rate_y) + r_src.y) * bytes_per_line); - pixel_rgb_t * i = pixbuf.raw_ptr(r_dst.y + row); + const pixel_argb_t * s_line = pixel_at(s_raw_pixbuf, (static_cast(row * rate_y) + r_src.y) * bytes_per_line); + pixel_argb_t * i = pixbuf.raw_ptr(r_dst.y + row); for(std::size_t x = 0; x < r_dst.width; ++x, ++i) { - const pixel_rgb_t * s = s_line + static_cast(x * rate_x) + r_src.x; - if(0 == s->u.element.alpha_channel) + const pixel_argb_t * s = s_line + static_cast(x * rate_x) + r_src.x; + if(0 == s->element.alpha_channel) continue; - if(s->u.element.alpha_channel != 255) + if(s->element.alpha_channel != 255) { - i->u.element.red = unsigned(i->u.element.red * (255 - s->u.element.alpha_channel) + s->u.element.red * s->u.element.alpha_channel) / 255; - i->u.element.green = unsigned(i->u.element.green * (255 - s->u.element.alpha_channel) + s->u.element.green * s->u.element.alpha_channel) / 255; - i->u.element.blue = unsigned(i->u.element.blue * (255 - s->u.element.alpha_channel) + s->u.element.blue * s->u.element.alpha_channel) / 255; + i->element.red = unsigned(i->element.red * (255 - s->element.alpha_channel) + s->element.red * s->element.alpha_channel) / 255; + i->element.green = unsigned(i->element.green * (255 - s->element.alpha_channel) + s->element.green * s->element.alpha_channel) / 255; + i->element.blue = unsigned(i->element.blue * (255 - s->element.alpha_channel) + s->element.blue * s->element.alpha_channel) / 255; } else { - unsigned alpha_chn = i->u.element.alpha_channel; + unsigned alpha_chn = i->element.alpha_channel; *i = *s; - i->u.element.alpha_channel = alpha_chn; + i->element.alpha_channel = alpha_chn; } } } @@ -72,8 +72,8 @@ namespace detail { for(std::size_t row = 0; row < r_dst.height; ++row) { - const pixel_rgb_t * s_line = pixel_at(s_raw_pixbuf, (static_cast(row * rate_y) + r_src.y) * bytes_per_line); - pixel_rgb_t * i = pixbuf.raw_ptr(r_dst.y + row); + const pixel_argb_t * s_line = pixel_at(s_raw_pixbuf, (static_cast(row * rate_y) + r_src.y) * bytes_per_line); + pixel_argb_t * i = pixbuf.raw_ptr(r_dst.y + row); for(std::size_t x = 0; x < r_dst.width; ++x, ++i) *i = s_line[static_cast(x * rate_x) + r_src.x]; @@ -105,7 +105,7 @@ namespace detail const int right_bound = static_cast(r_src.width) - 1 + r_src.x; - const nana::pixel_rgb_t * s_raw_pixel_buffer = s_pixbuf.raw_ptr(0); + const nana::pixel_argb_t * s_raw_pixel_buffer = s_pixbuf.raw_ptr(0); const int bottom = r_src.y + static_cast(r_src.height - 1); @@ -151,15 +151,15 @@ namespace detail std::size_t iv = static_cast(v * coef); const std::size_t iv_minus_coef = coef - iv; - const nana::pixel_rgb_t * s_line = pixel_at(s_raw_pixel_buffer, sy * s_bytes_per_line); - const nana::pixel_rgb_t * next_s_line = pixel_at(s_line, (sy < bottom ? s_bytes_per_line : 0)); + const nana::pixel_argb_t * s_line = pixel_at(s_raw_pixel_buffer, sy * s_bytes_per_line); + const nana::pixel_argb_t * next_s_line = pixel_at(s_line, (sy < bottom ? s_bytes_per_line : 0)); - nana::pixel_rgb_t col0; - nana::pixel_rgb_t col1; - nana::pixel_rgb_t col2; - nana::pixel_rgb_t col3; + nana::pixel_argb_t col0; + nana::pixel_argb_t col1; + nana::pixel_argb_t col2; + nana::pixel_argb_t col3; - pixel_rgb_t * i = pixbuf.raw_ptr(row + r_dst.y) + r_dst.x; + pixel_argb_t * i = pixbuf.raw_ptr(row + r_dst.y) + r_dst.x; if(is_alpha_channel) { @@ -186,24 +186,24 @@ namespace detail std::size_t coef2 = el.iu * iv_minus_coef; std::size_t coef3 = el.iu * iv; - unsigned alpha_chn = static_cast((coef0 * col0.u.element.alpha_channel + coef1 * col1.u.element.alpha_channel + (coef2 * col2.u.element.alpha_channel + coef3 * col3.u.element.alpha_channel)) >> double_shift_size); - unsigned s_red = static_cast((coef0 * col0.u.element.red + coef1 * col1.u.element.red + (coef2 * col2.u.element.red + coef3 * col3.u.element.red)) >> double_shift_size); - unsigned s_green = static_cast((coef0 * col0.u.element.green + coef1 * col1.u.element.green + (coef2 * col2.u.element.green + coef3 * col3.u.element.green)) >> double_shift_size); - unsigned s_blue = static_cast((coef0 * col0.u.element.blue + coef1 * col1.u.element.blue + (coef2 * col2.u.element.blue + coef3 * col3.u.element.blue)) >> double_shift_size); + unsigned alpha_chn = static_cast((coef0 * col0.element.alpha_channel + coef1 * col1.element.alpha_channel + (coef2 * col2.element.alpha_channel + coef3 * col3.element.alpha_channel)) >> double_shift_size); + unsigned s_red = static_cast((coef0 * col0.element.red + coef1 * col1.element.red + (coef2 * col2.element.red + coef3 * col3.element.red)) >> double_shift_size); + unsigned s_green = static_cast((coef0 * col0.element.green + coef1 * col1.element.green + (coef2 * col2.element.green + coef3 * col3.element.green)) >> double_shift_size); + unsigned s_blue = static_cast((coef0 * col0.element.blue + coef1 * col1.element.blue + (coef2 * col2.element.blue + coef3 * col3.element.blue)) >> double_shift_size); if(alpha_chn) { if(alpha_chn != 255) { - i->u.element.red = unsigned(i->u.element.red * (255 - alpha_chn) + s_red * alpha_chn) / 255; - i->u.element.green = unsigned(i->u.element.green * (255 - alpha_chn) + s_green * alpha_chn) / 255; - i->u.element.blue = unsigned(i->u.element.blue * (255 - alpha_chn) + s_blue * alpha_chn) / 255; + i->element.red = unsigned(i->element.red * (255 - alpha_chn) + s_red * alpha_chn) / 255; + i->element.green = unsigned(i->element.green * (255 - alpha_chn) + s_green * alpha_chn) / 255; + i->element.blue = unsigned(i->element.blue * (255 - alpha_chn) + s_blue * alpha_chn) / 255; } else { - i->u.element.red = s_red; - i->u.element.green = s_green; - i->u.element.blue = s_blue; + i->element.red = s_red; + i->element.green = s_green; + i->element.blue = s_blue; } } } @@ -233,9 +233,9 @@ namespace detail std::size_t coef2 = el.iu * iv_minus_coef; std::size_t coef3 = el.iu * iv; - i->u.element.red = static_cast((coef0 * col0.u.element.red + coef1 * col1.u.element.red + (coef2 * col2.u.element.red + coef3 * col3.u.element.red)) >> double_shift_size); - i->u.element.green = static_cast((coef0 * col0.u.element.green + coef1 * col1.u.element.green + (coef2 * col2.u.element.green + coef3 * col3.u.element.green)) >> double_shift_size); - i->u.element.blue = static_cast((coef0 * col0.u.element.blue + coef1 * col1.u.element.blue + (coef2 * col2.u.element.blue + coef3 * col3.u.element.blue)) >> double_shift_size); + i->element.red = static_cast((coef0 * col0.element.red + coef1 * col1.element.red + (coef2 * col2.element.red + coef3 * col3.element.red)) >> double_shift_size); + i->element.green = static_cast((coef0 * col0.element.green + coef1 * col1.element.green + (coef2 * col2.element.green + coef3 * col3.element.green)) >> double_shift_size); + i->element.blue = static_cast((coef0 * col0.element.blue + coef1 * col1.element.blue + (coef2 * col2.element.blue + coef3 * col3.element.blue)) >> double_shift_size); } } } @@ -250,83 +250,83 @@ namespace detail //process virtual void process(const paint::pixel_buffer& s_pixbuf, const nana::rectangle& s_r, paint::pixel_buffer& d_pixbuf, const nana::point& d_pos) const { - nana::pixel_rgb_t * d_rgb = d_pixbuf.at(d_pos); - nana::pixel_rgb_t * s_rgb = s_pixbuf.raw_ptr(s_r.y) + s_r.x; + auto d_rgb = d_pixbuf.at(d_pos); + auto s_rgb = s_pixbuf.raw_ptr(s_r.y) + s_r.x; if(d_rgb && s_rgb) { const unsigned rest = s_r.width & 0x3; const unsigned length_align4 = s_r.width - rest; - std::size_t d_step_bytes = d_pixbuf.bytes_per_line() - (s_r.width - rest) * sizeof(pixel_rgb_t); - std::size_t s_step_bytes = s_pixbuf.bytes_per_line() - (s_r.width - rest) * sizeof(pixel_rgb_t); + std::size_t d_step_bytes = d_pixbuf.bytes_per_line() - (s_r.width - rest) * sizeof(pixel_argb_t); + std::size_t s_step_bytes = s_pixbuf.bytes_per_line() - (s_r.width - rest) * sizeof(pixel_argb_t); for(unsigned line = 0; line < s_r.height; ++line) { - pixel_rgb_t* end = d_rgb + length_align4; + const auto end = d_rgb + length_align4; for(; d_rgb < end; d_rgb += 4, s_rgb += 4) { //0 - if(s_rgb->u.element.alpha_channel) + if(s_rgb->element.alpha_channel) { - if(s_rgb->u.element.alpha_channel != 255) + if(s_rgb->element.alpha_channel != 255) { - d_rgb->u.element.red = unsigned(d_rgb->u.element.red * (255 - s_rgb[0].u.element.alpha_channel) + s_rgb[0].u.element.red * s_rgb[0].u.element.alpha_channel) / 255; - d_rgb->u.element.green = unsigned(d_rgb->u.element.green * (255 - s_rgb[0].u.element.alpha_channel) + s_rgb[0].u.element.green * s_rgb[0].u.element.alpha_channel) / 255; - d_rgb->u.element.blue = unsigned(d_rgb->u.element.blue * (255 - s_rgb[0].u.element.alpha_channel) + s_rgb[0].u.element.blue * s_rgb[0].u.element.alpha_channel) / 255; + d_rgb->element.red = unsigned(d_rgb->element.red * (255 - s_rgb[0].element.alpha_channel) + s_rgb[0].element.red * s_rgb[0].element.alpha_channel) / 255; + d_rgb->element.green = unsigned(d_rgb->element.green * (255 - s_rgb[0].element.alpha_channel) + s_rgb[0].element.green * s_rgb[0].element.alpha_channel) / 255; + d_rgb->element.blue = unsigned(d_rgb->element.blue * (255 - s_rgb[0].element.alpha_channel) + s_rgb[0].element.blue * s_rgb[0].element.alpha_channel) / 255; } else *d_rgb = *s_rgb; } //1 - if(s_rgb[1].u.element.alpha_channel) + if(s_rgb[1].element.alpha_channel) { - if(s_rgb[1].u.element.alpha_channel != 255) + if(s_rgb[1].element.alpha_channel != 255) { - d_rgb[1].u.element.red = unsigned(d_rgb[1].u.element.red * (255 - s_rgb[1].u.element.alpha_channel) + s_rgb[1].u.element.red * s_rgb[1].u.element.alpha_channel) / 255; - d_rgb[1].u.element.green = unsigned(d_rgb[1].u.element.green * (255 - s_rgb[1].u.element.alpha_channel) + s_rgb[1].u.element.green * s_rgb[1].u.element.alpha_channel) / 255; - d_rgb[1].u.element.blue = unsigned(d_rgb[1].u.element.blue * (255 - s_rgb[1].u.element.alpha_channel) + s_rgb[1].u.element.blue * s_rgb[1].u.element.alpha_channel) / 255; + d_rgb[1].element.red = unsigned(d_rgb[1].element.red * (255 - s_rgb[1].element.alpha_channel) + s_rgb[1].element.red * s_rgb[1].element.alpha_channel) / 255; + d_rgb[1].element.green = unsigned(d_rgb[1].element.green * (255 - s_rgb[1].element.alpha_channel) + s_rgb[1].element.green * s_rgb[1].element.alpha_channel) / 255; + d_rgb[1].element.blue = unsigned(d_rgb[1].element.blue * (255 - s_rgb[1].element.alpha_channel) + s_rgb[1].element.blue * s_rgb[1].element.alpha_channel) / 255; } else d_rgb[1] = s_rgb[1]; } //2 - if(s_rgb[2].u.element.alpha_channel) + if(s_rgb[2].element.alpha_channel) { - if(s_rgb[2].u.element.alpha_channel != 255) + if(s_rgb[2].element.alpha_channel != 255) { - d_rgb[2].u.element.red = unsigned(d_rgb[2].u.element.red * (255 - s_rgb[2].u.element.alpha_channel) + s_rgb[2].u.element.red * s_rgb[2].u.element.alpha_channel) / 255; - d_rgb[2].u.element.green = unsigned(d_rgb[2].u.element.green * (255 - s_rgb[2].u.element.alpha_channel) + s_rgb[2].u.element.green * s_rgb[2].u.element.alpha_channel) / 255; - d_rgb[2].u.element.blue = unsigned(d_rgb[2].u.element.blue * (255 - s_rgb[2].u.element.alpha_channel) + s_rgb[2].u.element.blue * s_rgb[2].u.element.alpha_channel) / 255; + d_rgb[2].element.red = unsigned(d_rgb[2].element.red * (255 - s_rgb[2].element.alpha_channel) + s_rgb[2].element.red * s_rgb[2].element.alpha_channel) / 255; + d_rgb[2].element.green = unsigned(d_rgb[2].element.green * (255 - s_rgb[2].element.alpha_channel) + s_rgb[2].element.green * s_rgb[2].element.alpha_channel) / 255; + d_rgb[2].element.blue = unsigned(d_rgb[2].element.blue * (255 - s_rgb[2].element.alpha_channel) + s_rgb[2].element.blue * s_rgb[2].element.alpha_channel) / 255; } else d_rgb[2] = s_rgb[2]; } //3 - if(s_rgb[3].u.element.alpha_channel) + if(s_rgb[3].element.alpha_channel) { - if(s_rgb[3].u.element.alpha_channel != 255) + if(s_rgb[3].element.alpha_channel != 255) { - d_rgb[3].u.element.red = unsigned(d_rgb[3].u.element.red * (255 - s_rgb[3].u.element.alpha_channel) + s_rgb[3].u.element.red * s_rgb[3].u.element.alpha_channel) / 255; - d_rgb[3].u.element.green = unsigned(d_rgb[3].u.element.green * (255 - s_rgb[3].u.element.alpha_channel) + s_rgb[3].u.element.green * s_rgb[3].u.element.alpha_channel) / 255; - d_rgb[3].u.element.blue = unsigned(d_rgb[3].u.element.blue * (255 - s_rgb[3].u.element.alpha_channel) + s_rgb[3].u.element.blue * s_rgb[3].u.element.alpha_channel) / 255; + d_rgb[3].element.red = unsigned(d_rgb[3].element.red * (255 - s_rgb[3].element.alpha_channel) + s_rgb[3].element.red * s_rgb[3].element.alpha_channel) / 255; + d_rgb[3].element.green = unsigned(d_rgb[3].element.green * (255 - s_rgb[3].element.alpha_channel) + s_rgb[3].element.green * s_rgb[3].element.alpha_channel) / 255; + d_rgb[3].element.blue = unsigned(d_rgb[3].element.blue * (255 - s_rgb[3].element.alpha_channel) + s_rgb[3].element.blue * s_rgb[3].element.alpha_channel) / 255; } else d_rgb[3] = s_rgb[3]; } } - const pixel_rgb_t * s_end = s_rgb + rest; + const pixel_argb_t * s_end = s_rgb + rest; for(auto i = s_rgb; i != s_end; ++i) { - if(i->u.element.alpha_channel) + if(i->element.alpha_channel) { - if(i->u.element.alpha_channel != 255) + if(i->element.alpha_channel != 255) { - d_rgb[3].u.element.red = unsigned(d_rgb[3].u.element.red * (255 - i->u.element.alpha_channel) + i->u.element.red * i->u.element.alpha_channel) / 255; - d_rgb[3].u.element.green = unsigned(d_rgb[3].u.element.green * (255 - i->u.element.alpha_channel) + i->u.element.green * i->u.element.alpha_channel) / 255; - d_rgb[3].u.element.blue = unsigned(d_rgb[3].u.element.blue * (255 - i->u.element.alpha_channel) + i->u.element.blue * i->u.element.alpha_channel) / 255; + d_rgb[3].element.red = unsigned(d_rgb[3].element.red * (255 - i->element.alpha_channel) + i->element.red * i->element.alpha_channel) / 255; + d_rgb[3].element.green = unsigned(d_rgb[3].element.green * (255 - i->element.alpha_channel) + i->element.green * i->element.alpha_channel) / 255; + d_rgb[3].element.blue = unsigned(d_rgb[3].element.blue * (255 - i->element.alpha_channel) + i->element.blue * i->element.alpha_channel) / 255; } else d_rgb[3] = *i; @@ -347,56 +347,56 @@ namespace detail //process virtual void process(const paint::pixel_buffer& s_pixbuf, const nana::rectangle& s_r, paint::pixel_buffer& d_pixbuf, const nana::point& d_pos, double fade_rate) const { - nana::pixel_rgb_t * d_rgb = d_pixbuf.raw_ptr(d_pos.y) + d_pos.x; - nana::pixel_rgb_t * s_rgb = s_pixbuf.raw_ptr(s_r.y) + s_r.x; + auto d_rgb = d_pixbuf.raw_ptr(d_pos.y) + d_pos.x; + auto s_rgb = s_pixbuf.raw_ptr(s_r.y) + s_r.x; if(d_rgb && s_rgb) { - unsigned char* tablebuf = detail::alloc_fade_table(fade_rate);//new unsigned char[0x100 * 2]; - unsigned char* d_table = tablebuf; + auto ptr = detail::alloc_fade_table(fade_rate);//new unsigned char[0x100 * 2]; + + unsigned char* d_table = ptr.get(); unsigned char* s_table = d_table + 0x100; const unsigned rest = s_r.width & 0x3; const unsigned length_align4 = s_r.width - rest; - std::size_t d_step_bytes = d_pixbuf.bytes_per_line() - (s_r.width - rest) * sizeof(pixel_rgb_t); - std::size_t s_step_bytes = s_pixbuf.bytes_per_line() - (s_r.width - rest) * sizeof(pixel_rgb_t); + std::size_t d_step_bytes = d_pixbuf.bytes_per_line() - (s_r.width - rest) * sizeof(pixel_argb_t); + std::size_t s_step_bytes = s_pixbuf.bytes_per_line() - (s_r.width - rest) * sizeof(pixel_argb_t); for(unsigned line = 0; line < s_r.height; ++line) { - pixel_rgb_t* end = d_rgb + length_align4; + const auto end = d_rgb + length_align4; for(; d_rgb < end; d_rgb += 4, s_rgb += 4) { //0 - d_rgb[0].u.element.red = unsigned(d_table[d_rgb[0].u.element.red] + s_table[s_rgb[0].u.element.red]); - d_rgb[0].u.element.green = unsigned(d_table[d_rgb[0].u.element.green] + s_table[s_rgb[0].u.element.green]); - d_rgb[0].u.element.blue = unsigned(d_table[d_rgb[0].u.element.blue] + s_table[s_rgb[0].u.element.blue]); + d_rgb[0].element.red = unsigned(d_table[d_rgb[0].element.red] + s_table[s_rgb[0].element.red]); + d_rgb[0].element.green = unsigned(d_table[d_rgb[0].element.green] + s_table[s_rgb[0].element.green]); + d_rgb[0].element.blue = unsigned(d_table[d_rgb[0].element.blue] + s_table[s_rgb[0].element.blue]); //1 - d_rgb[1].u.element.red = unsigned(d_table[d_rgb[1].u.element.red] + s_table[s_rgb[1].u.element.red]); - d_rgb[1].u.element.green = unsigned(d_table[d_rgb[1].u.element.green] + s_table[s_rgb[1].u.element.green]); - d_rgb[1].u.element.blue = unsigned(d_table[d_rgb[1].u.element.blue] + s_table[s_rgb[1].u.element.blue]); + d_rgb[1].element.red = unsigned(d_table[d_rgb[1].element.red] + s_table[s_rgb[1].element.red]); + d_rgb[1].element.green = unsigned(d_table[d_rgb[1].element.green] + s_table[s_rgb[1].element.green]); + d_rgb[1].element.blue = unsigned(d_table[d_rgb[1].element.blue] + s_table[s_rgb[1].element.blue]); //2 - d_rgb[2].u.element.red = unsigned(d_table[d_rgb[2].u.element.red] + s_table[s_rgb[2].u.element.red]); - d_rgb[2].u.element.green = unsigned(d_table[d_rgb[2].u.element.green] + s_table[s_rgb[2].u.element.green]); - d_rgb[2].u.element.blue = unsigned(d_table[d_rgb[2].u.element.blue] + s_table[s_rgb[2].u.element.blue]); + d_rgb[2].element.red = unsigned(d_table[d_rgb[2].element.red] + s_table[s_rgb[2].element.red]); + d_rgb[2].element.green = unsigned(d_table[d_rgb[2].element.green] + s_table[s_rgb[2].element.green]); + d_rgb[2].element.blue = unsigned(d_table[d_rgb[2].element.blue] + s_table[s_rgb[2].element.blue]); //3 - d_rgb[3].u.element.red = unsigned(d_table[d_rgb[3].u.element.red] + s_table[s_rgb[3].u.element.red]); - d_rgb[3].u.element.green = unsigned(d_table[d_rgb[3].u.element.green] + s_table[s_rgb[3].u.element.green]); - d_rgb[3].u.element.blue = unsigned(d_table[d_rgb[3].u.element.blue] + s_table[s_rgb[3].u.element.blue]); + d_rgb[3].element.red = unsigned(d_table[d_rgb[3].element.red] + s_table[s_rgb[3].element.red]); + d_rgb[3].element.green = unsigned(d_table[d_rgb[3].element.green] + s_table[s_rgb[3].element.green]); + d_rgb[3].element.blue = unsigned(d_table[d_rgb[3].element.blue] + s_table[s_rgb[3].element.blue]); } for(unsigned i = 0; i < rest; ++i) { - d_rgb[i].u.element.red = unsigned(d_table[d_rgb[i].u.element.red] + s_table[s_rgb[i].u.element.red]); - d_rgb[i].u.element.green = unsigned(d_table[d_rgb[i].u.element.green] + s_table[s_rgb[i].u.element.green]); - d_rgb[i].u.element.blue = unsigned(d_table[d_rgb[i].u.element.blue] + s_table[s_rgb[i].u.element.blue]); + d_rgb[i].element.red = unsigned(d_table[d_rgb[i].element.red] + s_table[s_rgb[i].element.red]); + d_rgb[i].element.green = unsigned(d_table[d_rgb[i].element.green] + s_table[s_rgb[i].element.green]); + d_rgb[i].element.blue = unsigned(d_table[d_rgb[i].element.blue] + s_table[s_rgb[i].element.blue]); } d_rgb = pixel_at(d_rgb, d_step_bytes); s_rgb = pixel_at(s_rgb, s_step_bytes); } - detail::free_fade_table(tablebuf); } } }; @@ -405,19 +405,23 @@ namespace detail class bresenham_line : public image_process::line_interface { - virtual void process(paint::pixel_buffer & pixbuf, const nana::point& pos_beg, const nana::point& pos_end, nana::color_t color, double fade_rate) const + virtual void process(paint::pixel_buffer & pixbuf, const nana::point& pos_beg, const nana::point& pos_end, const ::nana::color& clr, double fade_rate) const { + auto rgb_color = clr.px_color().value; const std::size_t bytes_pl = pixbuf.bytes_per_line(); + unsigned char * fade_table = nullptr; - nana::pixel_rgb_t rgb_imd; + std::unique_ptr autoptr; + nana::pixel_argb_t rgb_imd; if(fade_rate != 0.0) { - fade_table = detail::alloc_fade_table(1 - fade_rate); - rgb_imd.u.color = color; + autoptr = detail::alloc_fade_table(1 - fade_rate); + fade_table = autoptr.get(); + rgb_imd.value = rgb_color; rgb_imd = detail::fade_color_intermedia(rgb_imd, fade_table); } - nana::pixel_rgb_t * i = pixel_at(pixbuf.raw_ptr(0), pos_beg.y * bytes_pl) + pos_beg.x; + auto i = pixel_at(pixbuf.raw_ptr(0), pos_beg.y * bytes_pl) + pos_beg.x; auto delta = pos_end - pos_beg; @@ -432,7 +436,7 @@ namespace detail if(delta.x == delta.y) { - step_bytes += sizeof(pixel_rgb_t); + step_bytes += sizeof(pixel_argb_t); ++delta.x; if(fade_table) @@ -447,7 +451,7 @@ namespace detail { for(int x = 0; x < delta.x; ++x) { - i->u.color = color; + i->value = rgb_color; i = pixel_at(i, step_bytes); } } @@ -479,7 +483,7 @@ namespace detail { for(int x = 0; x < delta.x; ++x) { - i->u.color = color; + i->value = rgb_color; if(error >= 0) { error -= dx_2; @@ -513,7 +517,7 @@ namespace detail { for (int y = 0; y < delta.y; ++y) { - i->u.color = color; + i->value = rgb_color; if(error >= 0) { error -= dy_2; @@ -525,8 +529,6 @@ namespace detail } } } - - detail::free_fade_table(fade_table); } }; @@ -579,20 +581,20 @@ namespace detail { for(int i = - radius; i <= radius; ++i) { - nana::pixel_rgb_t px = linepix[(i > 0 ? i : 0)]; - sum_r += px.u.element.red; - sum_g += px.u.element.green; - sum_b += px.u.element.blue; + auto px = linepix[(i > 0 ? i : 0)]; + sum_r += px.element.red; + sum_g += px.element.green; + sum_b += px.element.blue; } } else { for(int i = - radius; i <= radius; ++i) { - nana::pixel_rgb_t px = linepix[std::min(wm, (i > 0 ? i : 0))]; - sum_r += px.u.element.red; - sum_g += px.u.element.green; - sum_b += px.u.element.blue; + auto px = linepix[std::min(wm, (i > 0 ? i : 0))]; + sum_r += px.element.red; + sum_g += px.element.green; + sum_b += px.element.blue; } } @@ -608,12 +610,12 @@ namespace detail vmax[x] = std::max(x - radius, 0); } - nana::pixel_rgb_t p1 = linepix[vmin[x]]; - nana::pixel_rgb_t p2 = linepix[vmax[x]]; + auto p1 = linepix[vmin[x]]; + auto p2 = linepix[vmax[x]]; - sum_r += p1.u.element.red - p2.u.element.red; - sum_g += p1.u.element.green - p2.u.element.green; - sum_b += p1.u.element.blue - p2.u.element.blue; + sum_r += p1.element.red - p2.element.red; + sum_g += p1.element.green - p2.element.green; + sum_b += p1.element.blue - p2.element.blue; ++yi; } linepix = pixbuf.raw_ptr(area.y + y) + area.x; @@ -649,7 +651,7 @@ namespace detail for(int y = 0; y < h; ++y) { - linepix->u.color = 0xFF000000 | (dv[sum_r] << 16) | (dv[sum_g] << 8) | dv[sum_b]; + linepix->value = 0xFF000000 | (dv[sum_r] << 16) | (dv[sum_g] << 8) | dv[sum_b]; if(x == 0) { vmin[y] = std::min(y + radius + 1, hm) * w; diff --git a/include/nana/paint/detail/native_paint_interface.hpp b/include/nana/paint/detail/native_paint_interface.hpp index 91f47b4d..4281aca1 100644 --- a/include/nana/paint/detail/native_paint_interface.hpp +++ b/include/nana/paint/detail/native_paint_interface.hpp @@ -21,20 +21,20 @@ namespace detail { nana::size drawable_size(drawable_type); - unsigned char * alloc_fade_table(double fade_rate); + std::unique_ptr alloc_fade_table(double fade_rate); void free_fade_table(const unsigned char*); //color = bgcolor * fade_rate + fgcolor * (1 - fade_rate); - nana::pixel_rgb_t fade_color(nana::pixel_rgb_t bgcolor, nana::pixel_rgb_t fgcolor, double fade_rate); - nana::pixel_rgb_t fade_color(nana::pixel_rgb_t bgcolor, nana::pixel_rgb_t fgcolor, const unsigned char* const fade_table); - nana::pixel_rgb_t fade_color_intermedia(nana::pixel_rgb_t fgcolor, const unsigned char* fade_table); - 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); + //nana::pixel_color_t fade_color(nana::pixel_color_t bgcolor, nana::pixel_color_t fgcolor, double fade_rate); //deprecated + nana::pixel_color_t fade_color(nana::pixel_color_t bgcolor, nana::pixel_color_t fgcolor, const unsigned char* const fade_table); + nana::pixel_color_t fade_color_intermedia(pixel_color_t fgcolor, const unsigned char* fade_table); + nana::pixel_color_t fade_color_by_intermedia(pixel_color_t bgcolor, nana::pixel_color_t fgcolor_intermedia, const unsigned char* const fade_table); - void blend(drawable_type dw, const nana::rectangle& r, nana::color_t, double fade_rate); + void blend(drawable_type dw, const nana::rectangle& r, pixel_color_t, double fade_rate); nana::size raw_text_extent_size(drawable_type, const nana::char_t*, std::size_t len); nana::size text_extent_size(drawable_type, const nana::char_t*, std::size_t len); - void draw_string(drawable_type, int x, int y, const nana::char_t *, std::size_t len); + void draw_string(drawable_type, const nana::point&, const nana::char_t *, std::size_t len); }//end namespace detail }//end namespace paint }//end namespace nana diff --git a/include/nana/paint/gadget.hpp b/include/nana/paint/gadget.hpp index d7e4e3d7..d64c9293 100644 --- a/include/nana/paint/gadget.hpp +++ b/include/nana/paint/gadget.hpp @@ -1,6 +1,7 @@ /* * Graphics Gadget Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -21,14 +22,8 @@ namespace paint { namespace gadget { - struct directions - { - enum t{to_east, to_southeast, to_south, to_southwest, to_west, to_northwest, to_north, to_northeast}; - }; - - void arrow_16_pixels(nana::paint::graphics&, int x, int y, unsigned color, uint32_t style, directions::t direction); - void close_16_pixels(nana::paint::graphics&, int x, int y, uint32_t style, uint32_t color); - void cross(nana::paint::graphics&, int x, int y, uint32_t size, uint32_t thickness, nana::color_t color); + void close_16_pixels(::nana::paint::graphics&, int x, int y, unsigned style, const color&); + void cross(::nana::paint::graphics&, int x, int y, unsigned size, unsigned thickness, const nana::color&); }//end namespace gadget diff --git a/include/nana/paint/graphics.hpp b/include/nana/paint/graphics.hpp index e1ca70b5..b14a4cb7 100644 --- a/include/nana/paint/graphics.hpp +++ b/include/nana/paint/graphics.hpp @@ -1,6 +1,7 @@ /* * Paint Graphics Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -73,7 +74,6 @@ namespace nana typedef ::nana::native_window_type native_window_type; graphics(); - graphics(unsigned width, unsigned height); ///< size in pixel graphics(const ::nana::size&); ///< size in pixel graphics(const graphics&); ///< the resource is not copyed, the two graphics objects refer to the *SAME* resource graphics& operator=(const graphics&); @@ -84,9 +84,10 @@ namespace nana drawable_type handle() const; const void* pixmap() const; const void* context() const; - void make(unsigned width, unsigned height); ///< Creates a bitmap resource that size is width by height in pixel - void resize(unsigned width, unsigned height); - void typeface(const font&); ///< Selects a specified font type into the graphics object. + + void make(const ::nana::size&); ///< Creates a bitmap resource that size is width by height in pixel + void resize(const ::nana::size&); + void typeface(const font&); ///< Selects a specified font type into the graphics object. font typeface() const; ::nana::size text_extent_size(const char_t*) const; ///< Computes the width and height of the specified string of text. ::nana::size text_extent_size(const string&) const; ///< Computes the width and height of the specified string of text. @@ -99,27 +100,7 @@ namespace nana bool text_metrics(unsigned & ascent, unsigned& descent, unsigned& internal_leading) const; - unsigned bidi_string(int x, int y, color_t, const char_t *, std::size_t len); - void string(int x, int y, color_t, const ::nana::string&, std::size_t len); - void string(int x, int y, color_t, const ::nana::string&); - void string(int x, int y, color_t, const char_t*, std::size_t len); - void string(int x, int y, color_t, const char_t*); - - void set_pixel(int x, int y, color_t); - void rectangle(int x, int y, unsigned width, unsigned height, color_t, bool solid); - void rectangle(color_t, bool solid); - void rectangle(const ::nana::rectangle&, color_t, bool solid); - void rectangle_line(const ::nana::rectangle&, color_t left, color_t top, color_t right, color_t bottom); - void round_rectangle(int x, int y, unsigned width, unsigned height, unsigned radius_x, unsigned radius_y, color_t, bool solid, color_t color_if_solid); - void round_rectangle(const ::nana::rectangle&, unsigned radius_x, unsigned radius_y, color_t, bool solid, color_t color_if_solid); - void shadow_rectangle(const ::nana::rectangle&, color_t beg_color, color_t end_color, bool vertical); - void shadow_rectangle(int x, int y, unsigned width, unsigned height, color_t beg_color, color_t end_color, bool vertical); ///< Draws a width and height rectangle at (x, y) and the color in range of [begin, end] - - void line(int x1, int y1, int x2, int y2, color_t); ///< Draws a line from point (x1, y1) to point (x2, y2) in the specified color. - void line(const point& beg, const point& end, color_t); - void lines(const point* points, std::size_t n_of_points, color_t); void line_begin(int x, int y); - void line_to(int x, int y, color_t); void bitblt(int x, int y, const graphics& source); ///< Transfers the source to the specified point. void bitblt(const ::nana::rectangle& r_dst, native_window_type src); ///< Transfers the color data corresponding to r_dst from the src window to this graphics. @@ -128,7 +109,6 @@ namespace nana void bitblt(const ::nana::rectangle& r_dst, const graphics& src, const point& p_src);///< Transfers the color data corresponding to r_dst from the src graphics at point p_src to this graphics. void blend(const ::nana::rectangle& s_r, graphics& dst, const point& d_pos, double fade_rate) const;///< blends with the dst object. - void blend(const ::nana::rectangle& r, color_t, double fade_rate); ///< blends the specifed block width the specified color. void blur(const ::nana::rectangle& r, std::size_t radius); ///< Blur process. @@ -140,7 +120,7 @@ namespace nana void rgb_to_wb(); ///< Transform a color graphics into black&white. void stretch(const ::nana::rectangle& src_r, graphics& dst, const ::nana::rectangle& r) const; - void stretch(graphics& dst, const ::nana::rectangle& r) const; + void stretch(graphics& dst, const ::nana::rectangle&) const; void flush(); @@ -151,7 +131,34 @@ namespace nana void release(); void save_as_file(const char*); - static color_t mix(color_t colorX, color_t colorY, double persent); + void set_color(const ::nana::color&); + void set_text_color(const ::nana::color&); + + unsigned bidi_string(const nana::point&, const char_t *, std::size_t len); + + void blend(const ::nana::rectangle& r, const ::nana::color&, double fade_rate); + + void set_pixel(int x, int y, const ::nana::color&); + void set_pixel(int x, int y); + + void string(point, const char_t*, std::size_t len); + void string(const point&, const char_t*); + void string(const point&, const ::nana::string&); + void string(const point&, const ::nana::string&, const color&); + + void line(const point&, const point&); + void line(const point&, const point&, const color&); + void line_to(const point&, const color&); + void line_to(const point&); + + void rectangle(bool solid); + void rectangle(bool solid, const color&); + void rectangle(const ::nana::rectangle&, bool solid); + void rectangle(const ::nana::rectangle&, bool solid, const color&); + void frame_rectangle(const ::nana::rectangle&, const color& left, const color& top, const color& right, const color& bottom); + + void gradual_rectangle(const ::nana::rectangle&, const color& from, const color& to, bool vertical); + void round_rectangle(const ::nana::rectangle&, unsigned radius_x, unsigned radius_y, const color&, bool solid, const color& color_if_solid); private: std::shared_ptr< ::nana::detail::drawable_impl_type> dwptr_; font font_shadow_; diff --git a/include/nana/paint/image_process_interface.hpp b/include/nana/paint/image_process_interface.hpp index 11fc9ed7..75945f9f 100644 --- a/include/nana/paint/image_process_interface.hpp +++ b/include/nana/paint/image_process_interface.hpp @@ -24,7 +24,7 @@ namespace nana class stretch_interface { public: - virtual ~stretch_interface() = 0; + virtual ~stretch_interface() = default; /// Copies the image from a source rectangle into a destination rectangle, stretching or compressing the image to fit the dimensions of the destination rectangle in destination(d_pixbuf). virtual void process(const paint::pixel_buffer & s_pixbuf, const nana::rectangle& source_rectangle, @@ -36,14 +36,14 @@ namespace nana class alpha_blend_interface { public: - virtual ~alpha_blend_interface() = 0; + virtual ~alpha_blend_interface() = default; virtual void process(const paint::pixel_buffer& s_pixbuf, const nana::rectangle& s_r, paint::pixel_buffer& d_pixbuf, const point& d_pos) const = 0; }; /// The interface of a blend algorithm. class blend_interface { public: - virtual ~blend_interface() = 0; + virtual ~blend_interface() = default; /// \brief Blends two images with specified area and blend rate. /// /// Semantics: \code dest_pixbuf = dest_pixbuf * fade_rate + scr_pixbuf * (1 - fade_rate); \endcode @@ -59,16 +59,16 @@ namespace nana class line_interface { public: - virtual ~line_interface() = 0; + virtual ~line_interface() = default; /// \brief Draws a line /// /// Semantics: \code pixbuf = pixbuf * (1 - fade_rate) + color * fade_rate \endcode /// The two points are calculated by Nana, they are always valid, and pos_beg.x <= pos_end.x virtual void process(paint::pixel_buffer & pixbuf, - const nana::point& pos_beg, ///< left point - const nana::point& pos_end, ///< right point - nana::color_t color, + const point& pos_beg, ///< left point + const point& pos_end, ///< right point + const ::nana::color&, double fade_rate ///< blend rate in the range of [0, 1] If not 0, the line is blended to the pixbuf ) const = 0; }; @@ -76,7 +76,7 @@ namespace nana class blur_interface { public: - virtual ~blur_interface() = 0; + virtual ~blur_interface() = default; virtual void process(paint::pixel_buffer&, const nana::rectangle& r, std::size_t radius) const = 0; }; } diff --git a/include/nana/paint/pixel_buffer.hpp b/include/nana/paint/pixel_buffer.hpp index 9d9dc7fa..b7ef1be9 100644 --- a/include/nana/paint/pixel_buffer.hpp +++ b/include/nana/paint/pixel_buffer.hpp @@ -1,6 +1,7 @@ /* * Pixel Buffer Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -19,14 +20,14 @@ namespace nana{ namespace paint { ///@brief Seek a pixel address by using offset bytes ///@return the specified pixel address - inline pixel_rgb_t * pixel_at(pixel_rgb_t * p, std::size_t bytes) + inline pixel_color_t * pixel_at(pixel_color_t * p, std::size_t bytes) { - return reinterpret_cast(reinterpret_cast(p) + bytes); + return reinterpret_cast(reinterpret_cast(p)+bytes); } - inline const pixel_rgb_t * pixel_at(const pixel_rgb_t * p, std::size_t bytes) + inline const pixel_color_t * pixel_at(const pixel_color_t * p, std::size_t bytes) { - return reinterpret_cast(reinterpret_cast(p) + bytes); + return reinterpret_cast(reinterpret_cast(p)+bytes); } class pixel_buffer @@ -34,7 +35,7 @@ namespace nana{ namespace paint struct pixel_buffer_storage; typedef bool (pixel_buffer:: * unspecified_bool_t)() const; public: - pixel_buffer(); + pixel_buffer() = default; pixel_buffer(drawable_type, const nana::rectangle& want_rectangle); pixel_buffer(drawable_type, std::size_t top, std::size_t lines); pixel_buffer(std::size_t width, std::size_t height); @@ -60,20 +61,20 @@ namespace nana{ namespace paint std::size_t bytes_per_line() const; nana::size size() const; - pixel_rgb_t * at(const point& pos) const; - pixel_rgb_t * raw_ptr(std::size_t row) const; - pixel_rgb_t * operator[](std::size_t row) const; + pixel_color_t * at(const point& pos) const; + pixel_color_t * raw_ptr(std::size_t row) const; + pixel_color_t * operator[](std::size_t row) const; void put(const unsigned char* rawbits, std::size_t width, std::size_t height, std::size_t bits_per_pixel, std::size_t bytes_per_line, bool is_negative); void line(const std::string& name); - void line(const nana::point& pos_beg, const nana::point& pos_end, nana::color_t color, double fade_rate); + void line(const ::nana::point& pos_beg, const ::nana::point& pos_end, const ::nana::color&, double fade_rate); - void rectangle(const nana::rectangle&, nana::color_t, double fade_rate, bool solid); - void shadow_rectangle(const nana::rectangle&, nana::color_t beg, nana::color_t end, double fade_rate, bool vertical); + void rectangle(const nana::rectangle&, const ::nana::color&, double fade_rate, bool solid); + void gradual_rectangle(const ::nana::rectangle&, const ::nana::color& from, const ::nana::color& to, double fade_rate, bool vertical); - pixel_rgb_t pixel(int x, int y) const; - void pixel(int x, int y, pixel_rgb_t); + pixel_color_t pixel(int x, int y) const; + void pixel(int x, int y, pixel_color_t); void paste(drawable_type, int x, int y) const; void paste(const nana::rectangle& s_r, drawable_type, int x, int y) const; diff --git a/include/nana/paint/text_renderer.hpp b/include/nana/paint/text_renderer.hpp index 7f8ce910..28bb4e8f 100644 --- a/include/nana/paint/text_renderer.hpp +++ b/include/nana/paint/text_renderer.hpp @@ -13,11 +13,11 @@ namespace nana text_renderer(graph_reference graph, align = align::left); - void render(int x, int y, nana::color_t, const nana::char_t*, std::size_t len); - void render(int x, int y, nana::color_t, const nana::char_t*, std::size_t len, unsigned restricted_pixels, bool omitted); - - void render(int x, int y, nana::color_t, const nana::char_t*, std::size_t len, unsigned restricted_pixels); nana::size extent_size(int x, int y, const nana::char_t*, std::size_t len, unsigned restricted_pixels) const; + + void render(const point&, const char_t*, std::size_t len); + void render(const point&, const char_t*, std::size_t len, unsigned restricted_pixels, bool omitted); + void render(const point&, const char_t*, std::size_t len, unsigned restricted_pixels); private: graph_reference graph_; align text_align_; diff --git a/source/basic_types.cpp b/source/basic_types.cpp index e4cf6acf..f8bb0823 100644 --- a/source/basic_types.cpp +++ b/source/basic_types.cpp @@ -1,18 +1,390 @@ /* * Basic Types definition - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at + * 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/basic_types.cpp */ #include +#include +#include namespace nana { + //class color + color::color(colors clr) + : color((static_cast(clr)& 0xFF0000) >> 16, (static_cast(clr)& 0xFF00) >> 8, static_cast(clr)& 0xFF) + {} + + color::color(colors clr, double alpha) + : color((static_cast(clr)& 0xFF0000) >> 16, (static_cast(clr)& 0xFF00) >> 8, static_cast(clr)& 0xFF, alpha) + {} + + color::color(color_rgb rgb) + : r_((static_cast(rgb) >> 16) & 0xFF), + g_((static_cast(rgb) >> 8) & 0xFF), + b_(static_cast(rgb) & 0xFF), + a_(1.0) + {} + + color::color(color_argb argb) + : r_((static_cast(argb) >> 16) & 0xFF), + g_((static_cast(argb) >> 8) & 0xFF), + b_(static_cast(argb) & 0xFF), + a_(((static_cast(argb) >> 24) & 0xFF) / 255.0) + {} + + color::color(color_rgba rgba) + : r_((static_cast(rgba) >> 24) & 0xFF), + g_((static_cast(rgba) >> 16) & 0xFF), + b_((static_cast(rgba) >> 8) & 0xFF), + a_((static_cast(rgba) & 0xFF) / 255.0) + {} + + color::color(unsigned red, unsigned green, unsigned blue) + : r_(red), g_(green), b_(blue), a_(1.0) + { + } + + color::color(unsigned red, unsigned green, unsigned blue, double alpha) + : r_(red), g_(green), b_(blue), a_(alpha) + { + if (alpha < 0.0) + a_ = 0.0; + else if (alpha > 1.0) + a_ = 1.0; + } + + //Initializes the color with a CSS-like string + //contributor: BigDave(mortis2007 at hotmail co uk) + //date: February 3, 2015 + //maintainor: Jinhao, extended the support of CSS-spec + color::color(std::string css_color) + : a_(1.0) + { + const char * excpt_what = "color: invalid rgb format"; + + auto pos = css_color.find_first_not_of(' '); + if (pos == css_color.npos) + throw std::invalid_argument(excpt_what); + + if ('#' == css_color[pos]) + { + if (css_color.size() < pos + 4) + throw std::invalid_argument(excpt_what); + + auto endpos = css_color.find_first_not_of("0123456789abcdefABCDEF", pos + 1); + if (endpos == css_color.npos) + endpos = static_cast(css_color.size()); + + if ((endpos - pos != 4) && (endpos - pos != 7)) + throw std::invalid_argument(excpt_what); + + auto n = ::nana::stoi(css_color.substr(pos + 1, endpos - pos - 1), nullptr, 16); + + if (endpos - pos == 4) + { + r_ = ((0xF00 & n) >> 4) | ((0xF00 & n) >> 8); + g_ = (0xF0 & n) | ((0xF0 & n) >> 4); + b_ = (0xF & n) | ((0xF & n) << 4); + } + else + { + r_ = (0xFF0000 & n) >> 16; + g_ = (0xFF00 & n) >> 8; + b_ = (0xFF & n); + } + + return; + } + + //std::tolower is not allowed because of concept requirements + std::transform(css_color.begin(), css_color.end(), css_color.begin(), [](char ch){ + if('A' <= ch && ch <= 'Z') + return static_cast(ch - ('A' - 'a')); + return ch; + }); + auto endpos = css_color.find(' ', pos + 1); + if (endpos == css_color.npos) + endpos = css_color.size(); + + if ((endpos - pos == 11) && (css_color.substr(pos, 11) == "transparent")) + { + r_ = 0; + g_ = 0; + b_ = 0; + a_ = 0; + return; + } + + auto type_end = css_color.find_first_of(" (", pos + 1); + + if (type_end == css_color.npos || ((type_end - pos != 3) && (type_end - pos != 4))) //rgb/hsl = 3, rgba/hsla = 4 + throw std::invalid_argument(excpt_what); + + bool has_alpha = false; + if (type_end - pos == 4) //maybe rgba/hsla + { + if (css_color[pos + 3] != 'a') + throw std::invalid_argument(excpt_what); + has_alpha = true; + } + + std::regex pat; + std::regex_iterator i, end; + auto type_name = css_color.substr(pos, 3); + if ("rgb" == type_name) + { + pat.assign("(\\d*\\.)?\\d+\\%?"); + i = std::regex_iterator(css_color.begin() + pos, css_color.end(), pat); + + if (i == end) + throw std::invalid_argument(excpt_what); + + std::vector rgb; + + rgb.emplace_back(i->str()); + + const bool is_real = (rgb.back().back() == '%'); + pat.assign(is_real ? "(\\d*\\.)?\\d+\\%" : "\\d+"); + + for (++i; i != end; ++i) + { + rgb.emplace_back(i->str()); + if (rgb.size() == 3) + break; + } + + if (rgb.size() != 3) + throw std::invalid_argument(excpt_what); + + if (is_real) + { + auto pr = ::nana::stod(rgb[0].substr(0, rgb[0].size() - 1)); + r_ = (pr > 100 ? 255.0 : 2.55 * pr); + + pr = ::nana::stod(rgb[1].substr(0, rgb[1].size() - 1)); + g_ = (pr > 100 ? 255.0 : 2.55 * pr); + + pr = ::nana::stod(rgb[2].substr(0, rgb[2].size() - 1)); + b_ = (pr > 100 ? 255.0 : 2.55 * pr); + } + else + { + r_ = ::nana::stod(rgb[0]); + if (r_ > 255.0) r_ = 255; + + g_ = ::nana::stod(rgb[1]); + if (g_ > 255.0) g_ = 255; + + b_ = ::nana::stod(rgb[2]); + if (b_ > 255.0) b_ = 255; + } + } + else if ("hsl" == type_name) + { + pat.assign("(\\d*\\.)?\\d+"); + i = std::regex_iterator(css_color.begin() + pos, css_color.end(), pat); + + if (i == end) + throw std::invalid_argument(excpt_what); + + auto h = ::nana::stod(i->str()); + + pat.assign("(\\d*\\.)?\\d+\\%"); + + if (++i == end) + throw std::invalid_argument(excpt_what); + + auto str = i->str(); + auto s = ::nana::stod(str.substr(0, str.size() - 1)); + + if (++i == end) + throw std::invalid_argument(excpt_what); + + str = i->str(); + auto l = ::nana::stod(str.substr(0, str.size() - 1)); + + from_hsl(h, s / 100, l / 100); + } + else + throw std::invalid_argument(excpt_what); //invalid color type + + if (has_alpha) + { + pat.assign("(\\d*\\.)?\\d+"); + if (++i == end) + throw std::invalid_argument(excpt_what); //invalid alpha value + a_ = ::nana::stod(i->str()); + } + } + + color& color::from_rgb(unsigned red, unsigned green, unsigned blue) + { + r_ = red; + g_ = green; + b_ = blue; + return *this; + } + + double rgb_from_hue(double v1, double v2, double h) + { + if (h < 0.0) + h += 1.0; + else if (h > 1.0) + h -= 1.0; + + if (h < 0.1666666) return v1 + (v2 - v1) * (6.0 * h); + if (h < 0.5) return v2; + if (h < 0.6666666) return v1 + (v2 - v1) * (4.0 - h * 6.0); + return v1; + } + + color& color::from_hsl(double hue, double saturation, double lightness) + { + if (0.0 == saturation) + { + r_ = lightness * 255.0; + g_ = r_; + b_ = r_; + } + else + { + double var2; + if (lightness < 0.5) + var2 = lightness * (1.0 + saturation); + else + var2 = (lightness + saturation) - (saturation * lightness); + + double var1 = 2.0 * lightness - var2; + + hue /= 360; + r_ = 255.0 * rgb_from_hue(var1, var2, hue + 0.33333); + g_ = 255.0 * rgb_from_hue(var1, var2, hue); + b_ = 255.0 * rgb_from_hue(var1, var2, hue - 0.33333); + } + return *this; + } + + color& color::alpha(double al) + { + if (al < 0.0) + a_ = 0.0; + else if (al > 1.0) + a_ = 1.0; + else + a_ = al; + return *this; + } + + color color::blend(const color& bgcolor, bool ignore_bgcolor_alpha) const + { + if (a_ < 1.0) + { + color result; + if (0.0 < a_) + { + if (ignore_bgcolor_alpha || (1.0 == bgcolor.b_)) + { + result.r_ = r_ * a_ + bgcolor.r_ * (1.0 - a_); + result.g_ = g_ * a_ + bgcolor.g_ * (1.0 - a_); + result.b_ = b_ * a_ + bgcolor.b_ * (1.0 - a_); + result.a_ = 1.0; + } + else + { + result.r_ = r_ * a_ + bgcolor.r_ * bgcolor.a_ * (1.0 - a_); + result.g_ = g_ * a_ + bgcolor.g_ * bgcolor.a_ * (1.0 - a_); + result.b_ = b_ * a_ + bgcolor.b_ * bgcolor.a_ * (1.0 - a_); + result.a_ = a_ + (bgcolor.a_ * (1.0 - a_)); + } + } + else + { + result.r_ = bgcolor.r_; + result.g_ = bgcolor.g_; + result.b_ = bgcolor.b_; + result.a_ = (ignore_bgcolor_alpha ? 1.0 : bgcolor.a_); + } + return result; + } + + return *this; + } + + color color::blend(const color& bgcolor, double alpha) const + { + color result; + result.r_ = r_ * alpha + bgcolor.r_ * (1.0 - alpha); + result.g_ = g_ * alpha + bgcolor.g_ * (1.0 - alpha); + result.b_ = b_ * alpha + bgcolor.b_ * (1.0 - alpha); + result.a_ = 1.0; + return result; + } + + bool color::invisible() const + { + return (a_ == 0.0); + } + + pixel_color_t color::px_color() const + { + return argb(); + } + + pixel_argb_t color::argb() const + { + pixel_argb_t argb; + argb.element.red = static_cast(r_); + argb.element.green = static_cast(g_); + argb.element.blue = static_cast(b_); + argb.element.alpha_channel = static_cast(a_ * 255); + return argb; + } + + pixel_rgba_t color::rgba() const + { + pixel_rgba_t rgba; + rgba.element.red = static_cast(r_); + rgba.element.green = static_cast(g_); + rgba.element.blue = static_cast(b_); + rgba.element.alpha_channel = static_cast(a_ * 255); + return rgba; + } + + const double& color::r() const + { + return r_; + } + const double& color::g() const + { + return g_; + } + const double& color::b() const + { + return b_; + } + + const double& color::a() const + { + return a_; + } + + bool color::operator==(const color& other) const + { + return (px_color().value == other.px_color().value); + } + bool color::operator!=(const color& other) const + { + return (px_color().value != other.px_color().value); + } + + //end class color //struct point point::point():x(0), y(0){} point::point(int x, int y):x(x), y(y){} @@ -119,7 +491,7 @@ namespace nana //struct size size::size():width(0), height(0){} - size::size(unsigned width, unsigned height):width(width), height(height){} + size::size(value_type width, value_type height) : width(width), height(height){} size::size(const rectangle& r) : width(r.width), height(r.height) {} diff --git a/source/deploy.cpp b/source/deploy.cpp index d326ba7c..6017edfd 100644 --- a/source/deploy.cpp +++ b/source/deploy.cpp @@ -1,9 +1,10 @@ /* * The Deploy Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at + * 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/depoly.cpp @@ -12,7 +13,8 @@ */ #include - +#include +#include #if defined(NANA_WINDOWS) #include #elif defined(NANA_LINUX) @@ -46,7 +48,89 @@ namespace nana return ::wcscpy(dest, source); #else return ::strcpy(dest, source); -#endif +#endif + } + + int stoi(const std::string& str, std::size_t * pos, int base) + { +#if defined(NANA_MINGW) + auto sptr = str.c_str(); + char *end; + errno = 0; + auto result = std::strtol(sptr, &end, base); + + if (sptr == end) + throw std::invalid_argument("invalid stoi argument"); + if (errno == ERANGE) + throw std::out_of_range("stoi argument out of range"); + + if (pos) + *pos = (std::size_t)(end - sptr); + return ((int)result); +#else + return std::stoi(str, pos, base); +#endif + } + + int stoi(const std::wstring& str, std::size_t* pos, int base) + { +#if defined(NANA_MINGW) + auto sptr = str.data(); + wchar_t *end; + errno = 0; + auto result = std::wcstol(sptr, &end, base); + + if (sptr == end) + throw std::invalid_argument("invalid stoi argument"); + if (errno == ERANGE) + throw std::out_of_range("stoi argument out of range"); + + if (pos) + *pos = (std::size_t)(end - sptr); + return ((int)result); +#else + return std::stoi(str, pos, base); +#endif + } + + double stod(const std::string& str, std::size_t * pos) + { +#ifdef NANA_MINGW + auto *ptr = str.data(); + errno = 0; + char *end; + auto result = std::strtod(ptr, &end); + + if (ptr == end) + throw std::invalid_argument("invalid stod argument"); + if (errno == ERANGE) + throw std::out_of_range("stod argument out of range"); + if (pos) + *pos = (std::size_t)(end - ptr); + return result; +#else + return std::stod(str, pos); +#endif + } + + double stod(const std::wstring& str, std::size_t* pos) + { +#ifdef NANA_MINGW + auto *ptr = str.data(); + errno = 0; + wchar_t *end; + auto result = std::wcstod(ptr, &end); + + if (ptr == end) + throw std::invalid_argument("invalid stod argument"); + if (errno == ERANGE) + throw std::out_of_range("stod argument out of range"); + if (pos) + *pos = (std::size_t)(end - ptr); + return result; +#else + return std::stod(str, pos); +#endif } bool is_incomplete(const nana::string& str, unsigned pos) diff --git a/source/detail/linux_X11/platform_spec.cpp b/source/detail/linux_X11/platform_spec.cpp index a0751b4b..103ce221 100644 --- a/source/detail/linux_X11/platform_spec.cpp +++ b/source/detail/linux_X11/platform_spec.cpp @@ -23,7 +23,7 @@ #include #include #include -#include GUI_BEDROCK_HPP +#include #include #include #include @@ -301,31 +301,95 @@ namespace detail #endif } - void drawable_impl_type::fgcolor(unsigned color) + void drawable_impl_type::set_color(const ::nana::color& clr) { - if(color == fgcolor_) - return; + color_ = clr.px_color().value; + } - auto & spec = nana::detail::platform_spec::instance(); - platform_scope_guard psg; + void drawable_impl_type::set_text_color(const ::nana::color& clr) + { + text_color_ = clr.px_color().value; + update_text_color(); + } - fgcolor_ = color; - switch(spec.screen_depth()) + void drawable_impl_type::update_color() + { + if (color_ != current_color_) { - case 16: - color = ((((color >> 16) & 0xFF) * 31 / 255) << 11) | - ((((color >> 8) & 0xFF) * 63 / 255) << 5) | - (color & 0xFF) * 31 / 255; - break; + auto & spec = nana::detail::platform_spec::instance(); + platform_scope_guard lock; + + current_color_ = color_; + auto col = color_; + switch (spec.screen_depth()) + { + case 16: + col = ((((col >> 16) & 0xFF) * 31 / 255) << 11) | + ((((col >> 8) & 0xFF) * 63 / 255) << 5) | + (col & 0xFF) * 31 / 255; + break; + } + ::XSetForeground(spec.open_display(), context, col); + ::XSetBackground(spec.open_display(), context, col); } - ::XSetForeground(spec.open_display(), context, color); - ::XSetBackground(spec.open_display(), context, color); + } + + void drawable_impl_type::update_text_color() + { + if (text_color_ != current_color_) + { + auto & spec = nana::detail::platform_spec::instance(); + platform_scope_guard lock; + + current_color_ = text_color_; + auto col = text_color_; + switch (spec.screen_depth()) + { + case 16: + col = ((((col >> 16) & 0xFF) * 31 / 255) << 11) | + ((((col >> 8) & 0xFF) * 63 / 255) << 5) | + (col & 0xFF) * 31 / 255; + break; + } + ::XSetForeground(spec.open_display(), context, col); + ::XSetBackground(spec.open_display(), context, col); + #if defined(NANA_UNICODE) - xft_fgcolor.color.red = ((0xFF0000 & color) >> 16) * 0x101; - xft_fgcolor.color.green = ((0xFF00 & color) >> 8) * 0x101; - xft_fgcolor.color.blue = (0xFF & color) * 0x101; - xft_fgcolor.color.alpha = 0xFFFF; + xft_fgcolor.color.red = ((0xFF0000 & col) >> 16) * 0x101; + xft_fgcolor.color.green = ((0xFF00 & col) >> 8) * 0x101; + xft_fgcolor.color.blue = (0xFF & col) * 0x101; + xft_fgcolor.color.alpha = 0xFFFF; #endif + } + } + + void drawable_impl_type::fgcolor(const ::nana::color& clr) + { + auto rgb = clr.px_color().value; + + if (rgb != current_color_) + { + auto & spec = nana::detail::platform_spec::instance(); + platform_scope_guard psg; + + current_color_ = rgb; + switch(spec.screen_depth()) + { + case 16: + rgb = ((((rgb >> 16) & 0xFF) * 31 / 255) << 11) | + ((((rgb >> 8) & 0xFF) * 63 / 255) << 5) | + (rgb & 0xFF) * 31 / 255; + break; + } + ::XSetForeground(spec.open_display(), context, rgb); + ::XSetBackground(spec.open_display(), context, rgb); +#if defined(NANA_UNICODE) + xft_fgcolor.color.red = ((0xFF0000 & rgb) >> 16) * 0x101; + xft_fgcolor.color.green = ((0xFF00 & rgb) >> 8) * 0x101; + xft_fgcolor.color.blue = (0xFF & rgb) * 0x101; + xft_fgcolor.color.alpha = 0xFFFF; +#endif + } } class font_deleter @@ -652,7 +716,7 @@ namespace detail return 0; } - void platform_spec::caret_open(native_window_type wd, unsigned width, unsigned height) + void platform_spec::caret_open(native_window_type wd, const ::nana::size& caret_sz) { bool is_start_routine = false; platform_scope_guard psg; @@ -731,12 +795,11 @@ namespace detail } addr->visible = false; - addr->graph.make(width, height); - addr->graph.rectangle(0x0, true); - addr->rev_graph.make(width, height); + addr->graph.make(caret_sz); + addr->graph.rectangle(true, colors::black); + addr->rev_graph.make(caret_sz); - addr->size.width = width; - addr->size.height = height; + addr->size = caret_sz; if(addr->input_context && (false == addr->has_input_method_focus)) { @@ -809,7 +872,7 @@ namespace detail } } - void platform_spec::caret_pos(native_window_type wd, int x, int y) + void platform_spec::caret_pos(native_window_type wd, const point& pos) { platform_scope_guard psg; auto i = caret_holder_.carets.find(wd); @@ -817,8 +880,7 @@ namespace detail { caret_tag & crt = *i->second; caret_reinstate(crt); - crt.pos.x = x; - crt.pos.y = y; + crt.pos = pos; } } @@ -1066,7 +1128,7 @@ namespace detail const nana::paint::graphics& platform_spec::keep_window_icon(native_window_type wd, const nana::paint::image& img) { nana::paint::graphics & graph = iconbase_[wd]; - graph.make(img.size().width, img.size().height); + graph.make(img.size()); img.paste(graph, 0, 0); return graph; } diff --git a/source/detail/win32/platform_spec.cpp b/source/detail/win32/platform_spec.cpp index 84ed07d4..aff569d2 100644 --- a/source/detail/win32/platform_spec.cpp +++ b/source/detail/win32/platform_spec.cpp @@ -1,6 +1,7 @@ /* * Platform Specification Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -21,17 +22,15 @@ namespace nana namespace detail { drawable_impl_type::drawable_impl_type() - : pixbuf_ptr(nullptr), bytes_per_line(0), - fgcolor_(0xFFFFFFFF) { pen.handle = nullptr; - pen.color = nana::null_color; + pen.color = 0xffffffff; pen.style = -1; pen.width = -1; brush.handle = nullptr; brush.style = brush_spec::Solid; - brush.color = nana::null_color; + brush.color = 0xffffffff; round_region.handle = nullptr; round_region.radius_x = round_region.radius_y = 0; @@ -50,37 +49,69 @@ namespace detail ::DeleteObject(round_region.handle); } - void drawable_impl_type::fgcolor(nana::color_t col) + void drawable_impl_type::fgcolor(const ::nana::color& clr) { - if(this->fgcolor_ != col) + set_text_color(clr); + } + + unsigned drawable_impl_type::get_color() const + { + return color_; + } + + void drawable_impl_type::set_color(const ::nana::color& clr) + { + color_ = clr.px_color().value; + } + + void drawable_impl_type::set_text_color(const ::nana::color& clr) + { + auto rgb = clr.px_color().value; + if (text_color_ != rgb) { - ::SetTextColor(context, NANA_RGB(col)); - fgcolor_ = col; + ::SetTextColor(context, NANA_RGB(rgb)); + text_color_ = rgb; } } - void drawable_impl_type::pen_spec::set(HDC context, int style, int width, nana::color_t color) + void drawable_impl_type::update_pen() { - if(this->color != color || this->width != width || this->style != style) + if (pen.color != color_) { - this->color = color; + pen.handle = ::CreatePen(PS_SOLID, 1, NANA_RGB(color_)); + ::DeleteObject(::SelectObject(context, pen.handle)); + pen.color = color_; + } + } + + void drawable_impl_type::update_brush() + { + if (brush.color != color_) + brush.set(context, brush.style, color_); + } + + void drawable_impl_type::pen_spec::set(HDC context, int style, int width, unsigned clr) + { + if (this->color != clr || this->width != width || this->style != style) + { + this->color = clr; this->width = width; this->style = style; - this->handle = ::CreatePen(style, width, NANA_RGB(color)); + this->handle = ::CreatePen(style, width, NANA_RGB(clr)); ::DeleteObject(::SelectObject(context, this->handle)); } } - void drawable_impl_type::brush_spec::set(HDC context, drawable_impl_type::brush_spec::t style, nana::color_t color) + void drawable_impl_type::brush_spec::set(HDC context, drawable_impl_type::brush_spec::t style, unsigned rgb) { - if(this->color != color || this->style != style) + if (this->color != rgb || this->style != style) { - this->color = color; + this->color = rgb; this->style = style; switch(style) { case brush_spec::HatchBDiagonal: - this->handle = ::CreateHatchBrush(HS_BDIAGONAL, NANA_RGB(color)); + this->handle = ::CreateHatchBrush(HS_BDIAGONAL, NANA_RGB(rgb)); break; case brush_spec::Solid: default: diff --git a/source/gui/basis.cpp b/source/gui/basis.cpp index 337d9291..28893fb4 100644 --- a/source/gui/basis.cpp +++ b/source/gui/basis.cpp @@ -1,6 +1,7 @@ /* * Basis Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at diff --git a/source/gui/detail/basic_window.cpp b/source/gui/detail/basic_window.cpp index 6487eefb..f1bd3c95 100644 --- a/source/gui/detail/basic_window.cpp +++ b/source/gui/detail/basic_window.cpp @@ -21,7 +21,7 @@ namespace nana { if(active) { - native_interface::caret_create(wd_->root, size_.width, size_.height); + native_interface::caret_create(wd_->root, size_); real_visible_state_ = false; visible_ = false; this->position(point_.x, point_.y); @@ -49,9 +49,7 @@ namespace nana void caret_descriptor::effective_range(nana::rectangle rect) { //Chech rect - if( (rect.width && rect.height) && - (rect.x + rect.width > 0) && - (rect.y + rect.height > 0)) + if (rect.width && rect.height && rect.right() > 0 && rect.bottom() > 0) { if(rect.x < 0) { @@ -132,8 +130,8 @@ namespace nana pos.y += effective_range_.y; } - if( (pos.x + static_cast(size.width) <= rect.x) || (pos.x >= rect.x + static_cast(rect.width)) || - (pos.y + static_cast(size.height) <= rect.y) || (pos.y >= rect.y + static_cast(rect.height)) + if( (pos.x + static_cast(size.width) <= rect.x) || (pos.x >= rect.right()) || + (pos.y + static_cast(size.height) <= rect.y) || (pos.y >= rect.bottom()) ) {//Out of Range without overlap if(false == out_of_range_) @@ -151,9 +149,9 @@ namespace nana size.width -= (rect.x - pos.x); pos.x = rect.x; } - else if(pos.x + size.width > rect.x + rect.width) + else if(pos.x + static_cast(size.width) > rect.right()) { - size.width -= pos.x + size.width - (rect.x + rect.width); + size.width -= pos.x + size.width - rect.right(); } if(pos.y < rect.y) @@ -161,8 +159,8 @@ namespace nana size.width -= (rect.y - pos.y); pos.y = rect.y; } - else if(pos.y + size.height > rect.y + rect.height) - size.height -= pos.y + size.height - (rect.y + rect.height); + else if(pos.y + static_cast(size.height) > rect.bottom()) + size.height -= pos.y + size.height - rect.bottom(); if(out_of_range_) { @@ -175,7 +173,7 @@ namespace nana if(paint_size_ != size) { native_interface::caret_destroy(wd_->root); - native_interface::caret_create(wd_->root, size.width, size.height); + native_interface::caret_create(wd_->root, size); real_visible_state_ = false; if(visible_) _m_visible(true); @@ -183,7 +181,7 @@ namespace nana paint_size_ = size; } - native_interface::caret_pos(wd_->root, wd_->pos_root.x + pos.x, wd_->pos_root.y + pos.y); + native_interface::caret_pos(wd_->root, wd_->pos_root + pos); } } //end class caret_descriptor @@ -228,7 +226,7 @@ namespace nana : widget_ptr(wdg), other(category::root_tag::value) { drawer.bind(this); - _m_init_pos_and_size(0, rectangle()); + _m_init_pos_and_size(nullptr, rectangle()); this->_m_initialize(owner); } @@ -294,16 +292,20 @@ namespace nana return false; } + bool basic_window::is_draw_through() const + { + if (::nana::category::flags::root == this->other.category) + return static_cast(other.attribute.root->draw_through); + return false; + } + void basic_window::_m_init_pos_and_size(basic_window* parent, const rectangle& r) { pos_owner = pos_root = r; dimension = r; - if(parent) - { - pos_root.x += parent->pos_root.x; - pos_root.y += parent->pos_root.y; - } + if (parent) + pos_root += parent->pos_root; } void basic_window::_m_initialize(basic_window* agrparent) @@ -332,7 +334,7 @@ namespace nana } predef_cursor = cursor::arrow; - flags.capture = false; + flags.captured = false; flags.dbl_click = true; flags.enabled = true; flags.modal = false; @@ -344,13 +346,10 @@ namespace nana flags.refreshing = false; flags.destroying = false; flags.borderless = false; + flags.make_bground_declared = false; visible = false; - color.foreground = 0x0; - color.background = nana::color::button_face; - color.active = 0x60C8FD; - effect.edge_nimbus = effects::edge_nimbus::none; effect.bground = nullptr; effect.bground_fade_rate = 0; diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp index 66dec171..be824a0b 100644 --- a/source/gui/detail/bedrock_pi.cpp +++ b/source/gui/detail/bedrock_pi.cpp @@ -1,7 +1,7 @@ /* * A Bedrock Platform-Independent Implementation * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -12,7 +12,7 @@ #include #include PLATFORM_SPEC_HPP -#include GUI_BEDROCK_HPP +#include #include #include #include @@ -25,6 +25,20 @@ namespace nana { + //class event_arg + event_arg::~event_arg(){} + + void event_arg::stop_propagation() const + { + stop_propagation_ = true; + } + + bool event_arg::propagation_stopped() const + { + return stop_propagation_; + } + //end class event_arg + namespace detail { void events_operation_register(event_handle evt) @@ -63,7 +77,7 @@ namespace nana } wd_manager.refresh_tree(wd); - wd_manager.map(wd); + wd_manager.map(wd, false); } } @@ -120,7 +134,17 @@ namespace nana } } - void bedrock::_m_emit_core(event_code evt_code, core_window_t* wd, bool draw_only, const ::nana::detail::event_arg_interface& event_arg) + widget_colors& bedrock::get_scheme_template(scheme_factory_base&& factory) + { + return pi_data_->scheme.scheme_template(std::move(factory)); + } + + std::unique_ptr bedrock::make_scheme(scheme_factory_base&& factory) + { + return pi_data_->scheme.create(std::move(factory)); + } + + void bedrock::_m_emit_core(event_code evt_code, core_window_t* wd, bool draw_only, const ::nana::event_arg& event_arg) { switch (evt_code) { diff --git a/source/gui/detail/color_schemes.cpp b/source/gui/detail/color_schemes.cpp new file mode 100644 index 00000000..527b4644 --- /dev/null +++ b/source/gui/detail/color_schemes.cpp @@ -0,0 +1,90 @@ +#include +#include + +namespace nana +{ + //class color_proxy + color_proxy::color_proxy(const color_proxy& other) + : color_(other.color_) + {} + + color_proxy::color_proxy(color_rgb clr) + : color_(std::make_shared(clr)) + {} + + color_proxy::color_proxy(colors clr) + : color_(std::make_shared(clr)) + {} + + color_proxy& color_proxy::operator=(const color_proxy& other) + { + if (this != &other) + color_ = other.color_; + return *this; + } + + color_proxy& color_proxy::operator=(const ::nana::color& clr) + { + color_ = std::make_shared<::nana::color>(clr); + return *this; + } + + color_proxy& color_proxy::operator = (color_rgb clr) + { + color_ = std::make_shared<::nana::color>(clr); + return *this; + } + + color_proxy& color_proxy::operator = (colors clr) + { + color_ = std::make_shared<::nana::color>(clr); + return *this; + } + + color color_proxy::get_color() const + { + return *color_; + } + + color_proxy::operator color() const + { + return *color_; + } + //end class color_proxy + + namespace detail + { + //class color_schemes + struct color_schemes::implement + { + std::map> scheme_template; + }; + + color_schemes::color_schemes() + : impl_(new implement) + { + } + + color_schemes::~color_schemes() + { + delete impl_; + } + + auto color_schemes::scheme_template(scheme_factory_base&& factory) -> scheme& + { + auto & tmpl_scheme = impl_->scheme_template[factory.get_id()]; + + //Creates a scheme template if no template + if (!tmpl_scheme) + factory.create().swap(tmpl_scheme); + + return *tmpl_scheme.get(); + } + + std::unique_ptr color_schemes::create(scheme_factory_base&& factory) + { + return factory.create(scheme_template(std::move(factory))); + } + //end class color_system + }//end namespace detail +}//end namespace nana \ No newline at end of file diff --git a/source/gui/detail/drawer.cpp b/source/gui/detail/drawer.cpp index 42ef8cd8..7270aa7a 100644 --- a/source/gui/detail/drawer.cpp +++ b/source/gui/detail/drawer.cpp @@ -11,7 +11,7 @@ */ #include -#include GUI_BEDROCK_HPP +#include #include #include #include @@ -242,7 +242,7 @@ namespace nana _m_emit(event_code::shortkey, arg, &drawer_trigger::shortkey); } - void drawer::map(window wd) //Copy the root buffer to screen + void drawer::map(window wd, bool forced) //Copy the root buffer to screen { if(wd) { @@ -264,7 +264,7 @@ namespace nana #endif } - if(false == edge_nimbus_renderer_t::instance().render(iwd)) + if (false == edge_nimbus_renderer_t::instance().render(iwd, forced)) { nana::rectangle vr; if(bedrock_type::window_manager_t::wndlayout_type::read_visual_rectangle(iwd, vr)) @@ -378,11 +378,9 @@ namespace nana dw->draw(graphics); } - //If the drawer_trigger didn't declear a lazy refresh, then use the refresh(). - void drawer::_m_use_refresh() + bool drawer::_m_lazy_decleared() const { - if (basic_window::update_state::refresh != core_window_->other.upd_state) - refresh(); + return (basic_window::update_state::refresh == core_window_->other.upd_state); } }//end namespace detail }//end namespace nana diff --git a/source/gui/detail/linux_X11/bedrock.cpp b/source/gui/detail/linux_X11/bedrock.cpp index 10aa860a..d6546f08 100644 --- a/source/gui/detail/linux_X11/bedrock.cpp +++ b/source/gui/detail/linux_X11/bedrock.cpp @@ -1,7 +1,7 @@ /* * A Bedrock Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -12,7 +12,7 @@ #include #include PLATFORM_SPEC_HPP -#include GUI_BEDROCK_HPP +#include #include #include #include @@ -165,19 +165,20 @@ namespace detail } bedrock::bedrock() - : impl_(new private_impl) + : pi_data_(new pi_data), impl_(new private_impl) { nana::detail::platform_spec::instance().msg_set(timer_proc, window_proc_dispatcher); } bedrock::~bedrock() { + delete pi_data_; delete impl_; } - void bedrock::map_thread_root_buffer(bedrock::core_window_t* wnd) + void bedrock::map_thread_root_buffer(core_window_t*, bool forced) { - //GUI in X11 is not thread-dependent, so no implementation. + //GUI in X11 is thread-independent, so no implementation. } //inc_window @@ -376,14 +377,20 @@ namespace detail return impl_->estore; } + void bedrock::map_through_widgets(core_window_t* wd, native_drawable_type drawable) + { + //No implementation for Linux + } + + bool bedrock::emit(event_code evt_code, core_window_t* wd, const arg_mouse& arg, bool ask_update, thread_context* thrd) { if(evt_code != arg.evt_code) throw std::runtime_error("Nana.bedrock: Invalid event arg."); - return emit(evt_code, wd, static_cast(arg), ask_update, thrd); + return emit(evt_code, wd, static_cast(arg), ask_update, thrd); } - bool bedrock::emit(event_code evt_code, core_window_t* wd, const ::nana::detail::event_arg_interface& arg, bool ask_update, thread_context* thrd) + bool bedrock::emit(event_code evt_code, core_window_t* wd, const ::nana::event_arg& arg, bool ask_update, thread_context* thrd) { if(wd_manager.available(wd) == false) return false; @@ -410,7 +417,7 @@ namespace detail return true; } - bool bedrock::emit_drawer(event_code evt_code, core_window_t* wd, const ::nana::detail::event_arg_interface& arg, thread_context* thrd) + bool bedrock::emit_drawer(event_code evt_code, core_window_t* wd, const ::nana::event_arg& arg, thread_context* thrd) { if(wd_manager.available(wd) == false) return false; @@ -618,7 +625,8 @@ namespace detail msgwnd = brock.wd_manager.find_window(native_window, xevent.xcrossing.x, xevent.xcrossing.y); if(msgwnd) { - msgwnd->flags.action = mouse_action::over; + if (mouse_action::pressed != msgwnd->flags.action) + msgwnd->flags.action = mouse_action::over; hovered_wd = msgwnd; arg_mouse arg; @@ -869,7 +877,8 @@ namespace detail else { evt_code = event_code::mouse_enter; - msgwnd->flags.action = mouse_action::over; + if (mouse_action::pressed != msgwnd->flags.action) + msgwnd->flags.action = mouse_action::over; } arg_mouse arg; assign_arg(arg, msgwnd, message, xevent); @@ -882,7 +891,10 @@ namespace detail { arg_mouse arg; assign_arg(arg, msgwnd, message, xevent); - msgwnd->flags.action = mouse_action::over; + + if (mouse_action::pressed != msgwnd->flags.action) + msgwnd->flags.action = mouse_action::over; + if (hovered_wd != msgwnd) { hovered_wd = msgwnd; diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index 9199ce79..a862af75 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -23,7 +23,7 @@ #include #elif defined(NANA_X11) #include - #include GUI_BEDROCK_HPP + #include #endif namespace nana{ @@ -146,7 +146,7 @@ namespace nana{ #endif //struct native_interface - nana::size native_interface::screen_size() + nana::size native_interface::primary_monitor_size() { #if defined(NANA_WINDOWS) return nana::size(::GetSystemMetrics(SM_CXSCREEN), ::GetSystemMetrics(SM_CYSCREEN)); @@ -176,13 +176,10 @@ namespace nana{ mi.rcWork.right - mi.rcWork.left, mi.rcWork.bottom - mi.rcWork.top); } } -#elif defined(NANA_X11) #endif - return screen_size(); + return primary_monitor_size(); } - - //platform-dependent native_interface::window_result native_interface::create_window(native_window_type owner, bool nested, const rectangle& r, const appearance& app) { @@ -933,7 +930,7 @@ namespace nana{ #endif } - void native_interface::bring_to_top(native_window_type wd) + void native_interface::bring_top(native_window_type wd, bool activated) { #if defined(NANA_WINDOWS) HWND native_wd = reinterpret_cast(wd); @@ -944,7 +941,7 @@ namespace nana{ HWND fg_wd = ::GetForegroundWindow(); DWORD fg_tid = ::GetWindowThreadProcessId(fg_wd, nullptr); ::AttachThreadInput(::GetCurrentThreadId(), fg_tid, TRUE); - ::ShowWindow(native_wd, SW_SHOWNORMAL); + ::ShowWindow(native_wd, activated ? SW_SHOWNORMAL : SW_SHOWNOACTIVATE); ::SetWindowPos(native_wd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); ::SetWindowPos(native_wd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); ::AttachThreadInput(::GetCurrentThreadId(), fg_tid, FALSE); @@ -1196,13 +1193,13 @@ namespace nana{ #endif } - void native_interface::caret_create(native_window_type wd, unsigned width, unsigned height) + void native_interface::caret_create(native_window_type wd, const ::nana::size& caret_sz) { #if defined(NANA_WINDOWS) - ::CreateCaret(reinterpret_cast(wd), 0, int(width), int(height)); + ::CreateCaret(reinterpret_cast(wd), 0, int(caret_sz.width), int(caret_sz.height)); #elif defined(NANA_X11) nana::detail::platform_scope_guard psg; - restrict::spec.caret_open(wd, width, height); + restrict::spec.caret_open(wd, caret_sz); #endif } @@ -1219,21 +1216,21 @@ namespace nana{ #endif } - void native_interface::caret_pos(native_window_type wd, int x, int y) + void native_interface::caret_pos(native_window_type wd, const point& pos) { #if defined(NANA_WINDOWS) if(::GetCurrentThreadId() != ::GetWindowThreadProcessId(reinterpret_cast(wd), 0)) { auto cp = new nana::detail::messages::caret; - cp->x = x; - cp->y = y; + cp->x = pos.x; + cp->y = pos.y; ::PostMessage(reinterpret_cast(wd), nana::detail::messages::operate_caret, 2, reinterpret_cast(cp)); } else - ::SetCaretPos(x, y); + ::SetCaretPos(pos.x, pos.y); #elif defined(NANA_X11) nana::detail::platform_scope_guard psg; - restrict::spec.caret_pos(wd, x, y); + restrict::spec.caret_pos(wd, pos); #endif } diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index 4d02ccea..36c50e69 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -1,7 +1,7 @@ /* * A Bedrock Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -13,16 +13,18 @@ #include #include PLATFORM_SPEC_HPP -#include GUI_BEDROCK_HPP +#include +#include #include #include #include #include -#include +#include #include #include #include #include +#include #ifndef WM_MOUSEWHEEL #define WM_MOUSEWHEEL 0x020A @@ -175,7 +177,8 @@ namespace detail std::recursive_mutex mutex; thr_context_container thr_contexts; - element_store estore; + color_schemes schemes; + element_store estore; struct cache_type { @@ -213,7 +216,8 @@ namespace detail static LRESULT WINAPI Bedrock_WIN32_WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); bedrock::bedrock() - :impl_(new private_impl) + : pi_data_(new pi_data), + impl_(new private_impl) { nana::detail::platform_spec::instance(); //to guaranty the platform_spec object is initialized before using. @@ -269,6 +273,7 @@ namespace detail ::MessageBoxA(0, ss.str().c_str(), ("Nana C++ Library"), MB_OK); } delete impl_; + delete pi_data_; } //inc_window @@ -337,9 +342,9 @@ namespace detail return bedrock_object; } - void bedrock::map_thread_root_buffer(core_window_t* wd) + void bedrock::map_thread_root_buffer(core_window_t* wd, bool forced) { - ::PostMessage(reinterpret_cast(wd->root), nana::detail::messages::map_thread_root_buffer, reinterpret_cast(wd), 0); + ::PostMessage(reinterpret_cast(wd->root), nana::detail::messages::map_thread_root_buffer, reinterpret_cast(wd), static_cast(forced ? TRUE : FALSE)); } void interior_helper_for_menu(MSG& msg, native_window_type menu_window) @@ -591,7 +596,7 @@ namespace detail } return true; case nana::detail::messages::map_thread_root_buffer: - bedrock.wd_manager.map(reinterpret_cast(wParam)); + bedrock.wd_manager.map(reinterpret_cast(wParam), (TRUE == lParam)); ::UpdateWindow(wd); return true; case nana::detail::messages::remote_thread_move_window: @@ -1003,7 +1008,7 @@ namespace detail arg.evt_code = event_code::mouse_up; emit_drawer(&drawer::mouse_up, msgwnd, arg, &context); - auto evt_ptr = msgwnd->together.events_ptr; + //auto evt_ptr = msgwnd->together.events_ptr; //deprecated if (fire_click) { @@ -1055,7 +1060,10 @@ namespace detail else { evt_code = event_code::mouse_enter; - msgwnd->flags.action = mouse_action::over; + if (pressed_wd == msgwnd) + msgwnd->flags.action = mouse_action::pressed; + else if (mouse_action::pressed != msgwnd->flags.action) + msgwnd->flags.action = mouse_action::over; } arg_mouse arg; assign_arg(arg, msgwnd, message, pmdec); @@ -1068,9 +1076,14 @@ namespace detail { arg_mouse arg; assign_arg(arg, msgwnd, message, pmdec); - msgwnd->flags.action = mouse_action::over; + if (hovered_wd != msgwnd) { + if (pressed_wd == msgwnd) + msgwnd->flags.action = mouse_action::pressed; + else if (mouse_action::pressed != msgwnd->flags.action) + msgwnd->flags.action = mouse_action::over; + hovered_wd = msgwnd; arg.evt_code = event_code::mouse_enter; brock.emit(event_code::mouse_enter, msgwnd, arg, true, &context); @@ -1100,21 +1113,34 @@ namespace detail auto scrolled_wd = brock.wd_manager.find_window(reinterpret_cast(pointer_wd), scr_pos.x, scr_pos.y); def_window_proc = true; - while (scrolled_wd) + auto evt_wd = scrolled_wd; + while (evt_wd) { - if (scrolled_wd->together.attached_events->mouse_wheel.length() != 0) + if (evt_wd->together.attached_events->mouse_wheel.length() != 0) { def_window_proc = false; nana::point mspos{ scr_pos.x, scr_pos.y }; - brock.wd_manager.calc_window_point(scrolled_wd, mspos); + brock.wd_manager.calc_window_point(evt_wd, mspos); arg_wheel arg; arg.which = (WM_MOUSEHWHEEL == message ? arg_wheel::wheel::horizontal : arg_wheel::wheel::vertical); - assign_arg(arg, scrolled_wd, pmdec); - brock.emit(event_code::mouse_wheel, scrolled_wd, arg, true, &context); + assign_arg(arg, evt_wd, pmdec); + brock.emit(event_code::mouse_wheel, evt_wd, arg, true, &context); break; } - scrolled_wd = scrolled_wd->parent; + evt_wd = evt_wd->parent; + } + + if (scrolled_wd && (nullptr == evt_wd)) + { + nana::point mspos{ scr_pos.x, scr_pos.y }; + brock.wd_manager.calc_window_point(scrolled_wd, mspos); + + arg_wheel arg; + arg.which = (WM_MOUSEHWHEEL == message ? arg_wheel::wheel::horizontal : arg_wheel::wheel::vertical); + assign_arg(arg, scrolled_wd, pmdec); + brock.emit_drawer(event_code::mouse_wheel, scrolled_wd, arg, &context); + brock.wd_manager.do_lazy_refresh(scrolled_wd, false); } } else @@ -1260,6 +1286,15 @@ namespace detail brock.event_move(msgwnd, (int)(short) LOWORD(lParam), (int)(short) HIWORD(lParam)); break; case WM_PAINT: + if (msgwnd->is_draw_through()) + { + msgwnd->other.attribute.root->draw_through(); + + ::PAINTSTRUCT ps; + ::BeginPaint(root_window, &ps); + ::EndPaint(root_window, &ps); + } + else { ::PAINTSTRUCT ps; ::HDC dc = ::BeginPaint(root_window, &ps); @@ -1576,15 +1611,35 @@ namespace detail return impl_->estore; } + void bedrock::map_through_widgets(core_window_t* wd, native_drawable_type drawable) + { +#if defined(NANA_WINDOWS) + auto graph_context = reinterpret_cast(wd->root_graph->handle()->context); + + for (auto child : wd->children) + { + if (!child->visible) continue; + + if (::nana::category::flags::widget == child->other.category) + { + ::BitBlt(reinterpret_cast(drawable), child->pos_root.x, child->pos_root.y, static_cast(child->dimension.width), static_cast(child->dimension.height), + graph_context, child->pos_root.x, child->pos_root.y, SRCCOPY); + } + else if (::nana::category::flags::lite_widget == child->other.category) + map_through_widgets(child, drawable); + } +#endif + } + bool bedrock::emit(event_code evt_code, core_window_t* wd, const arg_mouse& arg, bool ask_update, thread_context* thrd) { if (evt_code != arg.evt_code) throw std::runtime_error("Nana.bedrock: invalid event arg."); - return emit(evt_code, wd, static_cast(arg), ask_update, thrd); + return emit(evt_code, wd, static_cast(arg), ask_update, thrd); } - bool bedrock::emit(event_code evt_code, core_window_t* wd, const ::nana::detail::event_arg_interface& arg, bool ask_update, thread_context* thrd) + bool bedrock::emit(event_code evt_code, core_window_t* wd, const ::nana::event_arg& arg, bool ask_update, thread_context* thrd) { if (wd_manager.available(wd) == false) return false; @@ -1611,7 +1666,7 @@ namespace detail return true; } - bool bedrock::emit_drawer(event_code evt_code, core_window_t* wd, const ::nana::detail::event_arg_interface& arg, thread_context* thrd) + bool bedrock::emit_drawer(event_code evt_code, core_window_t* wd, const ::nana::event_arg& arg, thread_context* thrd) { if (bedrock_object.wd_manager.available(wd) == false) return false; diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index 6e80adb3..99ab04ab 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -183,7 +183,7 @@ namespace nana //Enable the effect. data_sect.effects_bground_windows.push_back(wd); - wd->other.glass_buffer.make(wd->dimension.width, wd->dimension.height); + wd->other.glass_buffer.make(wd->dimension); make_bground(wd); return true; } @@ -308,8 +308,14 @@ namespace nana { if (is_redraw || called_by_notify) { - if (called_by_notify) + //The background is made by more than calling by notification(such as redraw of parent, + //redraw of siblings which are covered by wd), sometimes it should be remade when an attribute + //of the wd is changed(such as its background color is changed). + if (called_by_notify || wd->flags.make_bground_declared) + { make_bground(wd); + wd->flags.make_bground_declared = false; + } wd->flags.refreshing = true; wd->drawer.refresh(); diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 2c119d0f..f594e6a0 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -12,12 +12,13 @@ */ #include -#include GUI_BEDROCK_HPP +#include #include #include #include #include #include +#include #include #include @@ -320,7 +321,7 @@ namespace detail //Thread-Safe Required! std::lock_guard lock(mutex_); if (impl_->wd_register.available(parent) == false) - return nullptr; + throw std::invalid_argument("invalid parent/owner handle"); core_window_t * wd; if(is_lite) @@ -546,8 +547,8 @@ namespace detail { wd->dimension.width = r.width; wd->dimension.height = r.height; - wd->drawer.graphics.make(r.width, r.height); - wd->root_graph->make(r.width, r.height); + wd->drawer.graphics.make(wd->dimension); + wd->root_graph->make(wd->dimension); native_interface::move_window(wd->root, r); arg_resized arg; @@ -612,7 +613,7 @@ namespace detail if(category::lite_widget_tag::value != wd->other.category) { bool graph_state = wd->drawer.graphics.empty(); - wd->drawer.graphics.make(sz.width, sz.height); + wd->drawer.graphics.make(sz); //It shall make a typeface_changed() call when the graphics state is changing. //Because when a widget is created with zero-size, it may get some wrong result in typeface_changed() call @@ -622,7 +623,7 @@ namespace detail if(category::root_tag::value == wd->other.category) { - wd->root_graph->make(sz.width, sz.height); + wd->root_graph->make(sz); if(false == passive) native_interface::window_size(wd->root, sz + nana::size(wd->extra_width, wd->extra_height)); } @@ -637,7 +638,7 @@ namespace detail //update the bground buffer of glass window. if(wd->effect.bground && wd->parent) { - wd->other.glass_buffer.make(sz.width, sz.height); + wd->other.glass_buffer.make(sz); wndlayout_type::make_bground(wd); } } @@ -670,20 +671,20 @@ namespace detail } //Copy the root buffer that wnd specified into DeviceContext - void window_manager::map(core_window_t* wd) + void window_manager::map(core_window_t* wd, bool forced) { //Thread-Safe Required! std::lock_guard lock(mutex_); - if (impl_->wd_register.available(wd)) + if (impl_->wd_register.available(wd) && !wd->is_draw_through()) { //Copy the root buffer that wd specified into DeviceContext #if defined(NANA_LINUX) - wd->drawer.map(reinterpret_cast(wd)); + wd->drawer.map(reinterpret_cast(wd), forced); #elif defined(NANA_WINDOWS) if(nana::system::this_thread_id() == wd->thread_id) - wd->drawer.map(reinterpret_cast(wd)); + wd->drawer.map(reinterpret_cast(wd), forced); else - bedrock::instance().map_thread_root_buffer(wd); + bedrock::instance().map_thread_root_buffer(wd, forced); #endif } } @@ -692,7 +693,7 @@ namespace detail //@brief: update is used for displaying the screen-off buffer. // Because of a good efficiency, if it is called in an event procedure and the event procedure window is the // same as update's, update would not map the screen-off buffer and just set the window for lazy refresh - bool window_manager::update(core_window_t* wd, bool redraw, bool force) + bool window_manager::update(core_window_t* wd, bool redraw, bool forced) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -700,10 +701,10 @@ namespace detail if (wd->visible && wd->visible_parents()) { - if(force || (false == wd->belong_to_lazy())) + if(forced || (false == wd->belong_to_lazy())) { wndlayout_type::paint(wd, redraw, false); - this->map(wd); + this->map(wd, forced); } else { @@ -738,14 +739,20 @@ namespace detail if (false == impl_->wd_register.available(wd)) return false; - if(wd->visible) + if(wd->visible && (!wd->is_draw_through())) { if (wd->visible_parents()) { if ((wd->other.upd_state == core_window_t::update_state::refresh) || force_copy_to_screen) { wndlayout_type::paint(wd, false, false); - this->map(wd); + this->map(wd, force_copy_to_screen); + } + else if (effects::edge_nimbus::none != wd->effect.edge_nimbus) + { + //Update the nimbus effect + using nimbus_renderer = detail::edge_nimbus_renderer; + nimbus_renderer::instance().render(wd, force_copy_to_screen); } } else @@ -767,7 +774,7 @@ namespace detail if (!impl_->wd_register.available(wd)) return false; - result.make(wd->drawer.graphics.width(), wd->drawer.graphics.height()); + result.make(wd->drawer.graphics.size()); result.bitblt(0, 0, wd->drawer.graphics); wndlayout_type::paste_children_to_graphics(wd, result); return true; @@ -928,7 +935,7 @@ namespace detail if (impl_->wd_register.available(wd)) { - wd->flags.capture = true; + wd->flags.captured = true; native_interface::capture_window(wd->root, value); auto prev = attr_.capture.window; if(prev && (prev != wd)) @@ -946,6 +953,7 @@ namespace detail else if(wd == attr_.capture.window) { attr_.capture.window = nullptr; + wd->flags.captured = false; if(attr_cap.size()) { std::pair last = attr_cap.back(); @@ -957,6 +965,7 @@ namespace detail attr_.capture.ignore_children = last.second; native_interface::capture_window(last.first->root, true); native_interface::calc_window_point(last.first->root, pos); + last.first->flags.captured = true; attr_.capture.inside = _m_effective(last.first, pos); } } diff --git a/source/gui/drawing.cpp b/source/gui/drawing.cpp index e524d2e5..1a13d18a 100644 --- a/source/gui/drawing.cpp +++ b/source/gui/drawing.cpp @@ -1,7 +1,7 @@ /* * A Drawing Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -20,19 +20,27 @@ namespace nana //@brief: This name is only visible for this compiling-unit namespace restrict { - typedef detail::bedrock::core_window_t core_window_t; - extern detail::bedrock& bedrock; - - inline detail::drawer& get_drawer(window wd) + namespace { - return reinterpret_cast(wd)->drawer; + using core_window_t = detail::bedrock::core_window_t; + + inline detail::drawer& get_drawer(window wd) + { + return reinterpret_cast(wd)->drawer; + } } } //class drawing drawing::drawing(window wd) :handle_(wd) - {} + { + if (!API::is_window(wd)) + throw std::invalid_argument("drawing: invalid window parameter"); + + if (reinterpret_cast(wd)->is_draw_through()) + throw std::invalid_argument("drawing: the window is draw_through enabled"); + } drawing::~drawing(){} //Just for polymorphism diff --git a/source/gui/effects.cpp b/source/gui/effects.cpp index 8ed77777..3570fa21 100644 --- a/source/gui/effects.cpp +++ b/source/gui/effects.cpp @@ -26,9 +26,7 @@ namespace nana { if(fade_rate_ < 0.001) return; - - nana::color_t color = API::background(wd); - graph.blend(graph.size(), color, fade_rate_); + graph.blend(graph.size(), API::bgcolor(wd), fade_rate_); } private: const double fade_rate_; diff --git a/source/gui/element.cpp b/source/gui/element.cpp index e7eb758c..71d70f8b 100644 --- a/source/gui/element.cpp +++ b/source/gui/element.cpp @@ -1,3 +1,15 @@ +/* +* Elements of GUI Gadgets +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2015 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/gui/element.cpp +*/ + #include #include #include @@ -19,7 +31,7 @@ namespace nana class crook : public crook_interface { - bool draw(graph_reference graph, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle& r, element_state es, const data& crook_data) override + bool draw(graph_reference graph, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle& r, element_state es, const data& crook_data) override { if(crook_data.radio) { @@ -123,27 +135,28 @@ namespace nana for(int left = 0; left < 12; ++left) { if((*colormap)[top][left] != 0xFFFFFF) - graph.set_pixel(left + x, top + y, (*colormap)[top][left]); + graph.set_pixel(left + x, top + y, static_cast((*colormap)[top][left])); } } } else { - const nana::color_t highlighted = 0x5EB6F7; - + ::nana::color highlighted(0x5e, 0xb6, 0xf7); + auto bld_bgcolor = bgcolor; + auto bld_fgcolor = fgcolor; switch(es) { case element_state::hovered: case element_state::focus_hovered: - bgcolor = graph.mix(bgcolor, highlighted, 0.8); - fgcolor = graph.mix(fgcolor, highlighted, 0.8); + bld_bgcolor = bgcolor.blend(highlighted, 0.8); + bld_fgcolor = fgcolor.blend(highlighted, 0.8); break; case element_state::pressed: - bgcolor = graph.mix(bgcolor, highlighted, 0.4); - fgcolor = graph.mix(fgcolor, highlighted, 0.4); + bld_bgcolor = bgcolor.blend(highlighted, 0.4); + bld_fgcolor = fgcolor.blend(highlighted, 0.4); break; case element_state::disabled: - bgcolor = fgcolor = 0xB2B7BC; + bld_bgcolor = bld_fgcolor = nana::color(0xb2, 0xb7, 0xbc); break; default: //Leave things as they are @@ -152,8 +165,11 @@ namespace nana const int x = r.x + 1; const int y = r.y + 1; - graph.rectangle(x, y, 13, 13, fgcolor, false); - graph.rectangle(x + 1, y + 1, 11, 11, bgcolor, true); + graph.set_color(bld_bgcolor); + graph.rectangle(rectangle{ x + 1, y + 1, 11, 11 }, true); + + graph.set_color(bld_fgcolor); + graph.rectangle(rectangle{ x, y, 13, 13 }, false); switch(crook_data.check_state) { @@ -166,19 +182,19 @@ namespace nana { sx++; sy++; - graph.line(sx, sy, sx, sy + 3, fgcolor); + graph.line(point{ sx, sy }, point{ sx, sy + 3 }); } for(int i = 0; i < 4; i++) { sx++; sy--; - graph.line(sx, sy, sx, sy + 3, fgcolor); + graph.line(point{ sx, sy }, point{ sx, sy + 3 }); } } break; case state::partial: - graph.rectangle(x + 2, y + 2, 9, 9, fgcolor, true); + graph.rectangle(rectangle{ x + 2, y + 2, 9, 9 }, true); break; default: break; @@ -191,7 +207,7 @@ namespace nana class menu_crook : public crook_interface { - bool draw(graph_reference graph, nana::color_t, nana::color_t fgcolor, const nana::rectangle& r, element_state es, const data& crook_data) override + bool draw(graph_reference graph, const ::nana::color&, const ::nana::color& fgcolor, const nana::rectangle& r, element_state es, const data& crook_data) override { if(crook_data.check_state == state::unchecked) return true; @@ -218,7 +234,7 @@ namespace nana { if(colormap[u][v] & 0xFF000000) continue; - graph.set_pixel(x + v, y, colormap[u][v]); + graph.set_pixel(x + v, y, static_cast(colormap[u][v])); } ++y; } @@ -228,19 +244,292 @@ namespace nana int x = r.x + (static_cast(r.width) - 16) / 2; int y = r.y + (static_cast(r.height) - 16) / 2; - nana::color_t light = graph.mix(fgcolor, 0xFFFFFF, 0.5); + graph.set_color(fgcolor); + graph.line(point{ x + 3, y + 7 }, point{ x + 6, y + 10 }); + graph.line(point{ x + 7, y + 9 }, point{ x + 12, y + 4 }); - graph.line(x + 3, y + 7, x + 6, y + 10, fgcolor); - graph.line(x + 7, y + 9, x + 12, y + 4, fgcolor); - graph.line(x + 3, y + 8, x + 6, y + 11, light); - graph.line(x + 7, y + 10, x + 12, y + 5, light); - graph.line(x + 4, y + 7, x + 6, y + 9, light); - graph.line(x + 7, y + 8, x + 11, y + 4, light); + graph.set_color(fgcolor.blend(colors::white, 0.5)); + graph.line(point{ x + 3, y + 8 }, point{ x + 6, y + 11 }); + graph.line(point{ x + 7, y + 10 }, point{ x + 12, y + 5 }); + graph.line(point{ x + 4, y + 7 }, point{ x + 6, y + 9 }); + graph.line(point{ x + 7, y + 8 }, point{ x + 11, y + 4 }); } return true; } }; - } + + class border_depressed + : public border_interface + { + bool draw(graph_reference graph, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle& r, element_state estate, unsigned weight) + { + graph.rectangle(r, false, static_cast((element_state::focus_hovered == estate || element_state::focus_normal == estate) ? 0x0595E2 : 0x999A9E)); + graph.rectangle(::nana::rectangle{r}.pare_off(1), false, bgcolor); + return true; + } + }; + + class arrow_solid_triangle + : public arrow_interface + { + bool draw(graph_reference graph, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle& r, element_state estate, direction dir) override + { + ::nana::point pos{ r.x + 3, r.y + 3 }; + switch (dir) + { + case ::nana::direction::east: + pos.x += 3; + pos.y += 1; + for (int i = 0; i < 5; ++i) + graph.line(point{ pos.x + i, pos.y + i }, point{ pos.x + i, pos.y + 8 - i }); + break; + case ::nana::direction::south: + pos.y += 3; + for (int i = 0; i < 5; ++i) + graph.line(point{ pos.x + i, pos.y + i }, point{ pos.x + 8 - i, pos.y + i }); + break; + case ::nana::direction::west: + pos.x += 5; + pos.y += 1; + for (int i = 0; i < 5; ++i) + graph.line(point{ pos.x - i, pos.y + i }, point{ pos.x - i, pos.y + 8 - i }); + break; + case ::nana::direction::north: + pos.y += 7; + for (int i = 0; i < 5; ++i) + graph.line(point{ pos.x + i, pos.y - i }, point{ pos.x + 8 - i, pos.y - i }); + break; + case direction::southeast: + pos.x += 2; + pos.y += 7; + for (int i = 0; i < 6; ++i) + graph.line(point{ pos.x + i, pos.y - i }, point{ pos.x + 5, pos.y - i }); + break; + } + return true; + } + };//end class arrow_solid_triangle + + class arrow_hollow_triangle + : public arrow_interface + { + bool draw(graph_reference graph, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle& r, element_state estate, ::nana::direction dir) override + { + int x = r.x + 3; + int y = r.y + 3; + switch (dir) + { + case ::nana::direction::east: + x += 3; + graph.line(point{ x, y + 1 }, point{ x, y + 9 }); + graph.line(point{ x + 1, y + 2 }, point{ x + 4, y + 5 }); + graph.line(point{ x + 3, y + 6 }, point{ x + 1, y + 8 }); + break; + case direction::southeast: + x += 7; + y += 6; + graph.line(point{ x - 5 , y + 1 }, point{ x, y + 1 }); + graph.line(point{ x, y - 4 }, point{ x, y }); + graph.line(point{ x - 4, y }, point{ x - 1, y - 3 }); + break; + case direction::south: + y += 3; + graph.line(point{ x, y }, point{ x + 8, y }); + graph.line(point{ x + 1, y + 1 }, point{ x + 4, y + 4 }); + graph.line(point{ x + 7, y + 1 }, point{ x + 5, y + 3 }); + break; + case direction::west: + x += 5; + y += 1; + graph.line(point{ x, y }, point{ x, y + 8 }); + graph.line(point{ x - 4, y + 4 }, point{ x - 1, y + 1 }); + graph.line(point{ x - 3, y + 5 }, point{ x - 1, y + 7 }); + break; + case direction::north: + y += 7; + graph.line(point{ x, y }, point{ x + 8, y }); + graph.line(point{ x + 1, y - 1 }, point{ x + 4, y - 4 }); + graph.line(point{ x + 5, y - 3 }, point{ x + 7, y - 1 }); + break; + } + return true; + } + };//end class arrow_hollow_triangle + + class arrowhead + : public arrow_interface + { + bool draw(graph_reference graph, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle& r, element_state estate, ::nana::direction dir) override + { + int x = r.x; + int y = r.y + 5; + switch (dir) + { + case direction::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) + continue; + graph.set_pixel(x + i, y); + } + + x--; + y++; + pixels += 2; + } + + graph.set_pixel(x + 1, y); + graph.set_pixel(x + 2, y); + graph.set_pixel(x + 6, y); + graph.set_pixel(x + 7, y); + } + break; + case direction::south: + { + graph.set_pixel(x, y); + graph.set_pixel(x + 1, y); + graph.set_pixel(x + 5, y); + graph.set_pixel(x + 6, y); + + ++y; + int pixels = 7; + for (int l = 0; l < 4; ++l) + { + for (int i = 0; i < pixels; ++i) + { + if (l != 0 || i != 3) + graph.set_pixel(x + i, y); + } + + x++; + y++; + pixels -= 2; + } + } + default:break; + } + return true; + } + };//end class arrowhead + + class arrow_double + : public arrow_interface + { + bool draw(graph_reference graph, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle& r, element_state estate, ::nana::direction dir) override + { + int x = r.x; + int y = r.y; + switch (dir) + { + case direction::east: + _m_line(graph, x + 4, y + 6, true); + _m_line(graph, x + 5, y + 7, true); + _m_line(graph, x + 6, y + 8, true); + _m_line(graph, x + 5, y + 9, true); + _m_line(graph, x + 4, y + 10, true); + break; + case direction::west: + _m_line(graph, x + 5, y + 6, true); + _m_line(graph, x + 4, y + 7, true); + _m_line(graph, x + 3, y + 8, true); + _m_line(graph, x + 4, y + 9, true); + _m_line(graph, x + 5, y + 10, true); + break; + case direction::south: + _m_line(graph, x + 5, y + 4, false); + _m_line(graph, x + 6, y + 5, false); + _m_line(graph, x + 7, y + 6, false); + _m_line(graph, x + 8, y + 5, false); + _m_line(graph, x + 9, y + 4, false); + break; + case direction::north: + _m_line(graph, x + 5, y + 6, false); + _m_line(graph, x + 6, y + 5, false); + _m_line(graph, x + 7, y + 4, false); + _m_line(graph, x + 8, y + 5, false); + _m_line(graph, x + 9, y + 6, false); + break; + default: + break; + } + return true; + } + + static void _m_line(nana::paint::graphics & graph, int x, int y, bool horizontal) + { + graph.set_pixel(x, y); + if (horizontal) + { + graph.set_pixel(x + 1, y); + graph.set_pixel(x + 4, y); + graph.set_pixel(x + 5, y); + } + else + { + graph.set_pixel(x, y + 1); + graph.set_pixel(x, y + 4); + graph.set_pixel(x, y + 5); + } + } + };//end class arrow_double + + class annex_button + : public element_interface + { + bool draw(graph_reference graph, const ::nana::color& arg_bgcolor, const ::nana::color& fgcolor, const rectangle& r, element_state estate) override + { + auto bgcolor = arg_bgcolor; + + switch (estate) + { + case element_state::hovered: + case element_state::focus_hovered: + bgcolor = arg_bgcolor.blend(colors::white, 0.8); + break; + case element_state::pressed: + bgcolor = arg_bgcolor.blend(colors::black, 0.8); + break; + case element_state::disabled: + bgcolor = colors::dark_gray; + default: + break; + } + + auto part_px = (r.height - 3) * 5 / 13; + graph.rectangle(r, false, bgcolor.blend(colors::black, 0.6)); + + ::nana::point left_top{ r.x + 1, r.y + 1 }, right_top{r.right() - 2, r.y + 1}; + ::nana::point left_mid{ r.x + 1, r.y + 1 + static_cast(part_px) }, right_mid{ right_top.x, left_mid.y }; + ::nana::point left_bottom{ r.x + 1, r.bottom() - 2 }, right_bottom{ r.right() - 2, r.bottom() - 2 }; + + graph.set_color(bgcolor.blend(colors::white, 0.9)); + graph.line(left_top, left_mid); + graph.line(right_top, right_mid); + + graph.set_color(bgcolor.blend(colors::white, 0.5)); + graph.line(left_top, right_top); + + left_mid.y++; + right_mid.y++; + graph.set_color(bgcolor.blend(colors::black, 0.8)); + graph.line(left_mid, left_bottom); + graph.line(right_mid, right_bottom); + + ::nana::rectangle part_r{ r.x + 2, r.y + 2, r.width - 4, part_px }; + graph.rectangle(part_r, true, bgcolor.blend(colors::white, 0.8)); + + part_r.y += static_cast(part_r.height); + part_r.height = (r.height - 3 - part_r.height); + graph.rectangle(part_r, true, bgcolor); + return true; + } + };//end class annex_button + }//end namespace element template class element_object @@ -250,11 +539,6 @@ namespace nana typedef pat::cloneable> factory_interface; public: - element_object() - : element_ptr_(nullptr) - { - } - ~element_object() { if(factory_) @@ -289,7 +573,7 @@ namespace nana } private: factory_interface factory_; //Keep the factory for destroying the element - element_t * element_ptr_; + element_t * element_ptr_{nullptr}; std::vector> spare_; }; @@ -309,6 +593,7 @@ namespace nana element_manager() { crook_.employee = nullptr; + border_.employee = nullptr; } public: @@ -322,6 +607,15 @@ namespace nana element::add_crook(""); element::add_crook("menu_crook"); + + element::add_border(""); + + element::add_arrow(""); //"arrowhead" in default + element::add_arrow("double"); + element::add_arrow("solid_triangle"); + element::add_arrow("hollow_triangle"); + + element::add_button(""); //"annex" in default } return obj; } @@ -335,8 +629,38 @@ namespace nana { return _m_get(name, crook_).keeper(); } + + void border(const std::string& name, const pat::cloneable>& factory) + { + _m_add(name, border_, factory); + } + + element::border_interface * const * border(const std::string& name) const + { + return _m_get(name, border_).keeper(); + } + + void arrow(const std::string& name, const pat::cloneable>& factory) + { + _m_add((name.empty() ? "arrowhead" : name), arrow_, factory); + } + + element::arrow_interface * const * arrow(const std::string& name) const + { + return _m_get((name.empty() ? "arrowhead" : name), arrow_).keeper(); + } + + void button(const std::string& name, const pat::cloneable>& factory) + { + _m_add((name.empty() ? "annex" : name), button_, factory); + } + + element::element_interface * const * button(const std::string& name) const + { + return _m_get((name.empty() ? "annex" : name), button_).keeper(); + } private: - typedef std::lock_guard lock_guard; + using lock_guard = std::lock_guard; template void _m_add(const std::string& name, item& m, const pat::cloneable>& factory) @@ -367,7 +691,10 @@ namespace nana private: mutable std::recursive_mutex mutex_; - item crook_; + item crook_; + item border_; + item arrow_; + item button_; }; namespace element @@ -382,17 +709,40 @@ namespace nana { return element_manager::instance().crook(name); } + + void provider::add_border(const std::string& name, const pat::cloneable>& factory) + { + element_manager::instance().border(name, factory); + } + + border_interface* const * provider::keeper_border(const std::string& name) + { + return element_manager::instance().border(name); + } + + void provider::add_arrow(const std::string& name, const pat::cloneable>& factory) + { + element_manager::instance().arrow(name, factory); + } + + arrow_interface* const * provider::keeper_arrow(const std::string& name) + { + return element_manager::instance().arrow(name); + } + + void provider::add_button(const std::string& name, const pat::cloneable>& factory) + { + element_manager::instance().button(name, factory); + } + + element_interface* const* provider::keeper_button(const std::string& name) + { + return element_manager::instance().button(name); + } }//end namespace element //facades //template<> class facade - facade::facade() - : keeper_(element::provider().keeper_crook("")) - { - data_.check_state = state::unchecked; - data_.radio = false; - } - facade::facade(const char* name) : keeper_(element::provider().keeper_crook(name ? name : "")) { @@ -430,15 +780,72 @@ namespace nana void facade::switch_to(const char* name) { - keeper_ = element::provider().keeper_crook(name); + keeper_ = element::provider().keeper_crook(name ? name : ""); } - bool facade::draw(graph_reference graph, nana::color_t bgcol, nana::color_t fgcol, const nana::rectangle& r, element_state es) + bool facade::draw(graph_reference graph, const ::nana::color& bgcol, const ::nana::color& fgcol, const nana::rectangle& r, element_state es) { return (*keeper_)->draw(graph, bgcol, fgcol, r, es, data_); } //end class facade + //class facade + facade::facade(const char* name) + : keeper_(element::provider().keeper_border(name ? name : "")) + {} + + void facade::switch_to(const char* name) + { + keeper_ = element::provider().keeper_border(name ? name : ""); + } + + bool facade::draw(graph_reference graph, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle& r, element_state es) + { + return (*keeper_)->draw(graph, bgcolor, fgcolor, r, es, 2); + } + //end class facade + + //class facade + facade::facade(const char* name) + : keeper_(element::provider().keeper_arrow(name ? name : "")) + { + } + + void facade::switch_to(const char* name) + { + keeper_ = element::provider().keeper_arrow(name ? name : ""); + } + + void facade::direction(::nana::direction dir) + { + dir_ = dir; + } + + //Implement element_interface + bool facade::draw(graph_reference graph, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle& r, element_state estate) + { + graph.set_color(fgcolor); + return (*keeper_)->draw(graph, bgcolor, fgcolor, r, estate, dir_); + } + //end class facade + + //class facade:: + facade::facade(const char* name) + : keeper_(element::provider().keeper_button(name ? name : "")) + {} + + void facade::switch_to(const char* name) + { + keeper_ = element::provider().keeper_button(name ? name : ""); + } + + //Implement element_interface + bool facade::draw(graph_reference graph, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle& r, element_state estate) + { + return (*keeper_)->draw(graph, bgcolor, fgcolor, r, estate); + } + //end class facade + namespace element { void set_bground(const char* name, const pat::cloneable& obj) @@ -470,7 +877,7 @@ namespace nana ref_ptr_ = detail::bedrock::instance().get_element_store().bground(name); } - bool cite_bground::draw(graph_reference dst, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle& r, element_state state) + bool cite_bground::draw(graph_reference dst, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const nana::rectangle& r, element_state state) { if (ref_ptr_ && *ref_ptr_) return (*ref_ptr_)->draw(dst, bgcolor, fgcolor, r, state); @@ -530,7 +937,7 @@ namespace nana draw_method * clone() const override { auto p = new draw_graph; - p->graph.make(graph.width(), graph.height()); + p->graph.make(graph.size()); graph.paste(p->graph, 0, 0); return p; } @@ -656,7 +1063,7 @@ namespace nana } //Implement the methods of bground_interface. - bool bground::draw(graph_reference dst, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle& to_r, element_state state) + bool bground::draw(graph_reference dst, const ::nana::color&, const ::nana::color&, const nana::rectangle& to_r, element_state state) { if (nullptr == method_) return false; diff --git a/source/gui/filebox.cpp b/source/gui/filebox.cpp index 46ca0a59..f8937e38 100644 --- a/source/gui/filebox.cpp +++ b/source/gui/filebox.cpp @@ -123,7 +123,7 @@ namespace nana { path_.create(*this); path_.splitstr(STR("/")); - path_.events().selected([this](const arg_categorize&) + path_.events().selected.connect_unignorable([this](const arg_categorize&) { auto path = path_.caption(); auto root = path.substr(0, path.find(STR('/'))); @@ -142,7 +142,7 @@ namespace nana filter_.multi_lines(false); filter_.tip_string(STR("Filter")); - filter_.events().key_release([this](const arg_keyboard&) + filter_.events().key_release.connect_unignorable([this](const arg_keyboard&) { _m_list_fs(); }); @@ -150,7 +150,7 @@ namespace nana btn_folder_.create(*this); btn_folder_.caption(STR("&New Folder")); - btn_folder_.events().click([this](const arg_mouse&) + btn_folder_.events().click.connect_unignorable([this](const arg_mouse&) { form fm(this->handle(), API::make_center(*this, 300, 35)); fm.caption(STR("Name the new folder")); @@ -161,12 +161,12 @@ namespace nana button btn(fm, nana::rectangle(170, 5, 60, 25)); btn.caption(STR("Create")); - btn.events().click(folder_creator(*this, fm, folder)); + btn.events().click.connect_unignorable(folder_creator(*this, fm, folder)); button btn_cancel(fm, nana::rectangle(235, 5, 60, 25)); btn_cancel.caption(STR("Cancel")); - btn_cancel.events().click([&fm](const arg_mouse&) + btn_cancel.events().click.connect_unignorable([&fm](const arg_mouse&) { fm.close(); }); @@ -184,8 +184,8 @@ namespace nana auto fn_sel_file = [this](const arg_mouse& arg){ _m_sel_file(arg); }; - ls_file_.events().dbl_click(fn_sel_file); - ls_file_.events().mouse_down(fn_sel_file); + ls_file_.events().dbl_click.connect_unignorable(fn_sel_file); + ls_file_.events().mouse_down.connect_unignorable(fn_sel_file); ls_file_.set_sort_compare(0, [](const nana::string& a, nana::any* fs_a, const nana::string& b, nana::any* fs_b, bool reverse) -> bool { int dira = fs_a->get()->directory ? 1 : 0; @@ -262,7 +262,7 @@ namespace nana tb_file_.create(*this); tb_file_.multi_lines(false); - tb_file_.events().key_char([this](const arg_keyboard& arg) + tb_file_.events().key_char.connect_unignorable([this](const arg_keyboard& arg) { if(arg.key == nana::keyboard::enter) _m_ok(); @@ -270,19 +270,19 @@ namespace nana cb_types_.create(*this); cb_types_.editable(false); - cb_types_.events().selected([this](const arg_combox&){ _m_list_fs(); }); + cb_types_.events().selected.connect_unignorable([this](const arg_combox&){ _m_list_fs(); }); btn_ok_.create(*this); btn_ok_.caption(STR("&OK")); - btn_ok_.events().click([this](const arg_mouse&) + btn_ok_.events().click.connect_unignorable([this](const arg_mouse&) { _m_ok(); }); btn_cancel_.create(*this); btn_cancel_.caption(STR("&Cancel")); - btn_cancel_.events().click([this](const arg_mouse&) + btn_cancel_.events().click.connect_unignorable([this](const arg_mouse&) { API::close_window(handle()); }); @@ -440,12 +440,12 @@ namespace nana } } - tree_.events().expanded([this](const arg_treebox& arg) + tree_.events().expanded.connect_unignorable([this](const arg_treebox& arg) { _m_tr_expand(arg.item, arg.operated); }); - tree_.events().selected([this](const arg_treebox& arg) + tree_.events().selected.connect_unignorable([this](const arg_treebox& arg) { if(arg.operated && (arg.item.value() == kind::filesystem)) { diff --git a/source/gui/msgbox.cpp b/source/gui/msgbox.cpp index 1b37d4be..a13f3c82 100644 --- a/source/gui/msgbox.cpp +++ b/source/gui/msgbox.cpp @@ -1,7 +1,7 @@ /* * A Message Box Class * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -9,17 +9,23 @@ * * @file: nana/gui/msgbox.hpp */ -#include -#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #if defined(NANA_WINDOWS) #include #elif defined(NANA_X11) - #include - #include - #include #include #include - #include #endif namespace nana @@ -29,17 +35,17 @@ namespace nana : public form { public: - msgbox_window(window wd, const nana::string& title, msgbox::button_t btn, msgbox::icon_t ico) - : form(wd, nana::rectangle(1, 1, 1, 1), appear::decorate<>()), + msgbox_window(window wd, const ::nana::string& title, msgbox::button_t btn, msgbox::icon_t ico) + : form(wd, rectangle(1, 1, 1, 1), appear::decorate<>()), owner_(wd), pick_(msgbox::pick_yes) { this->caption(title); drawing dw(*this); - dw.draw([this](::nana::paint::graphics& graph) + dw.draw([this](paint::graphics& graph) { - graph.rectangle(nana::rectangle{0, 0, graph.width(), graph.height() - 50}, 0xFFFFFF, true); + graph.rectangle(rectangle{0, 0, graph.width(), graph.height() - 50}, true, colors::white); if(ico_.empty() == false) - ico_.stretch(ico_.size(), graph, ::nana::rectangle{12, 25, 32, 32}); + ico_.stretch(ico_.size(), graph, rectangle{12, 25, 32, 32}); }); unsigned width_pixel = 45; @@ -48,7 +54,7 @@ namespace nana place_.bind(*this); yes_.create(*this); - yes_.events().click([this](const arg_mouse& arg) + yes_.events().click.connect_unignorable([this](const arg_mouse& arg) { _m_click(arg); }); @@ -60,7 +66,7 @@ namespace nana yes_.caption(STR("Yes")); no_.create(*this); no_.caption(STR("No")); - no_.events().click([this](const arg_mouse& arg) + no_.events().click.connect_unignorable([this](const arg_mouse& arg) { _m_click(arg); }); @@ -71,7 +77,7 @@ namespace nana { cancel_.create(*this); cancel_.caption(STR("Cancel")); - cancel_.events().click([this](const arg_mouse& arg) + cancel_.events().click.connect_unignorable([this](const arg_mouse& arg) { _m_click(arg); }); @@ -107,7 +113,7 @@ namespace nana const unsigned text_pixels = 500 - ico_pixels; text_.create(*this, nana::rectangle(12 + ico_pixels, 25, 1, 1)); - text_.background(0xFFFFFF); + text_.bgcolor(colors::white); text_.caption(text); nana::size ts = text_.measure(text_pixels); @@ -293,7 +299,7 @@ namespace nana { nana::paint::pixel_buffer pxbuf(32, 32); pxbuf.put(reinterpret_cast(rawpx), 32, 32, 32, 4*32, true); - ico_.make(32, 32); + ico_.make({32, 32}); pxbuf.paste(ico_.handle(), 0, 0); } } @@ -319,146 +325,709 @@ namespace nana }; #endif - //class msgbox - msgbox::msgbox() - : wd_(nullptr), button_(ok), icon_(icon_none) - {} + //class msgbox + msgbox::msgbox() + : wd_(nullptr), button_(ok), icon_(icon_none) + {} - msgbox::msgbox(const msgbox& rhs) - : wd_(rhs.wd_), title_(rhs.title_), button_(rhs.button_), icon_(rhs.icon_) + msgbox::msgbox(const msgbox& rhs) + : wd_(rhs.wd_), title_(rhs.title_), button_(rhs.button_), icon_(rhs.icon_) + { + sstream_<(nana::charset(str)); + sstream_<(nana::charset(str)); #else - sstream_<(nana::charset(str));; + sstream_<(nana::charset(str));; #else - sstream_<(API::root(wd_)), static_cast(nana::charset(sstream_.str())).c_str(), title_.c_str(), type); #else int bt = ::MessageBoxA(reinterpret_cast(API::root(wd_), sstream_.str().c_str(), title_.c_str(), type); #endif - switch(bt) - { - case IDOK: - return pick_ok; - case IDYES: - return pick_yes; - case IDNO: - return pick_no; - case IDCANCEL: - return pick_cancel; - } - - return pick_yes; -#elif defined(NANA_X11) - msgbox_window box(wd_, title_, button_, icon_); - box.prompt(nana::charset(sstream_.str())); - return box.pick(); -#endif + switch(bt) + { + case IDOK: + return pick_ok; + case IDYES: return pick_yes; + case IDNO: + return pick_no; + case IDCANCEL: + return pick_cancel; } - //end class msgbox + return pick_yes; +#elif defined(NANA_X11) + msgbox_window box(wd_, title_, button_, icon_); + box.prompt(nana::charset(sstream_.str())); + return box.pick(); +#endif + return pick_yes; + } + //end class msgbox + + + //class inputbox + + class inputbox_window + : public ::nana::form + { + public: + inputbox_window(window owner, const ::nana::string & desc, const ::nana::string& title, std::size_t contents, unsigned fixed_pixels, const std::vector& each_height) + : form(owner, API::make_center(owner, 500, 300), appear::decorate<>()) + { + desc_.create(*this); + desc_.format(true).caption(desc); + auto desc_extent = desc_.measure(470); + + btn_ok_.create(*this); + btn_ok_.i18n(i18n_eval("OK")); + btn_ok_.events().click.connect_unignorable([this]{ + + if (verifier_ && !verifier_(handle())) + return; + + close(); + valid_input_ = true; + }); + + btn_cancel_.create(*this); + btn_cancel_.i18n(i18n_eval("Cancel")); + btn_cancel_.events().click.connect_unignorable([this]{ + close(); + }); + + unsigned height = 20 + desc_extent.height + 10 + 38; + + place_.bind(*this); + std::stringstream ss; + ss << "margin=10 vert 27) + px = each_height[i]; + + ss << ""; + + height += px + 1; + } + + ss << ">>"; + + place_.div(ss.str().data()); + place_["desc"] << desc_; + place_["buttons"] << btn_ok_ << btn_cancel_; + + if (desc_extent.width < 170) + desc_extent.width = 170; + + //Make sure the complete display of input extent + if (desc_extent.width < fixed_pixels) + desc_extent.width = fixed_pixels; + + size({ desc_extent.width + 20, height }); + caption(title); + } + + void set_input(const std::vector& inputs, std::function verifier) + { + verifier_ = std::move(verifier); + + std::size_t index = 0; + for (auto wd : inputs) + { + std::stringstream ss; + ss << "input_" << index++; + place_[ss.str().data()] << wd; + } + place_.collocate(); + show(); + } + + bool valid_input() const + { + return valid_input_; + } + private: + ::nana::label desc_; + ::nana::button btn_ok_; + ::nana::button btn_cancel_; + bool valid_input_{ false }; + ::nana::place place_; + std::function verifier_; + }; + + //class integer + struct inputbox::integer::implement + { + int value; + int begin; + int last; + int step; + + ::nana::string label_text; + ::nana::panel dock; + ::nana::label label; + ::nana::spinbox spinbox; + }; + + inputbox::integer::integer(::nana::string label, int init_value, int begin, int last, int step) + : impl_(new implement) + { + auto impl = impl_.get(); + impl->value = init_value; + impl->begin = begin; + impl->last = last; + impl->step = step; + impl->label_text = std::move(label); + } + + //Instance for impl_ because implmenet is incomplete type at the point of declaration + inputbox::integer::~integer(){} + + int inputbox::integer::value() const + { + return impl_->value; + } + + //Implementation of abstract_content + const ::nana::string& inputbox::integer::label() const + { + return impl_->label_text; + } + + window inputbox::integer::create(window parent, unsigned label_px) + { + auto impl = impl_.get(); + impl->dock.create(parent); + + impl->label.create(impl->dock, rectangle{ 0, 0, label_px, 0 }); + impl->label.text_align(::nana::align::right, ::nana::align_v::center); + impl->label.caption(impl->label_text); + impl->label.format(true); + + //get the longest value + int longest = (std::abs((impl->begin < 0 ? impl->begin * 10 : impl->begin)) < std::abs(impl->last < 0 ? impl->last * 10 : impl->last) ? impl->last : impl->begin); + std::wstringstream ss; + ss << longest; + paint::graphics graph{ ::nana::size{ 10, 10 } }; + auto value_px = graph.text_extent_size(ss.str()).width + 34; + + impl->spinbox.create(impl->dock, rectangle{ static_cast(label_px + 10), 0, value_px, 0 }); + impl->spinbox.range(impl->begin, impl->last, impl->step); + //impl->spinbox.set_accept_integer(); //deprecated + + //Workaround for no implementation of std::to_wstring by MinGW. + ss.str(L""); + ss.clear(); + ss << impl->value; + impl->spinbox.value(ss.str()); + + impl->dock.events().resized.connect_unignorable([impl, label_px, value_px](const ::nana::arg_resized& arg) + { + impl->label.size({ label_px, 24 }); + impl->spinbox.size({ value_px, 24 }); + }); + + impl->spinbox.events().destroy.connect_unignorable([impl] + { + impl->value = impl->spinbox.to_int(); + }); + + return impl->dock; + } + + unsigned inputbox::integer::fixed_pixels() const + { + return 0; + } + //end class integer + + + //class real + struct inputbox::real::implement + { + double value; + double begin; + double last; + double step; + + ::nana::string label_text; + ::nana::panel dock; + ::nana::label label; + ::nana::spinbox spinbox; + }; + + inputbox::real::real(::nana::string label, double init_value, double begin, double last, double step) + : impl_(new implement) + { + auto impl = impl_.get(); + impl->value = init_value; + impl->begin = begin; + impl->last = last; + impl->step = step; + impl->label_text = std::move(label); + } + + //Instance for impl_ because implmenet is incomplete type at the point of declaration + inputbox::real::~real(){} + + double inputbox::real::value() const + { + return impl_->value; + } + + //Implementation of abstract_content + const ::nana::string& inputbox::real::label() const + { + return impl_->label_text; + } + + window inputbox::real::create(window parent, unsigned label_px) + { + auto impl = impl_.get(); + impl->dock.create(parent); + + impl->label.create(impl->dock, rectangle{ 0, 0, label_px, 0 }); + impl->label.text_align(::nana::align::right, ::nana::align_v::center); + impl->label.caption(impl->label_text); + impl->label.format(true); + + //get the longest value + auto longest = (std::abs((impl->begin < 0 ? impl->begin * 10 : impl->begin)) < std::abs(impl->last < 0 ? impl->last * 10 : impl->last) ? impl->last : impl->begin); + std::wstringstream ss; + ss << longest; + paint::graphics graph{ ::nana::size{ 10, 10 } }; + auto value_px = graph.text_extent_size(ss.str()).width + 34; + + impl->spinbox.create(impl->dock, rectangle{ static_cast(label_px + 10), 0, value_px, 0 }); + impl->spinbox.range(impl->begin, impl->last, impl->step); + //impl->spinbox.set_accept_real(); //deprecated + + //Workaround for no implementation of std::to_wstring by MinGW. + ss.str(L""); + ss.clear(); + ss << impl->value; + impl->spinbox.value(ss.str()); + + impl->dock.events().resized.connect_unignorable([impl, label_px, value_px](const ::nana::arg_resized& arg) + { + impl->label.size({ label_px, 24 }); + impl->spinbox.size({ value_px, 24 }); + }); + + impl->spinbox.events().destroy.connect_unignorable([impl] + { + impl->value = impl->spinbox.to_int(); + }); + + return impl->dock; + } + + unsigned inputbox::real::fixed_pixels() const + { + return 0; + } + //end class real + + + //class text + struct inputbox::text::implement + { + ::nana::string value; + std::vector< ::nana::string> options; + + ::nana::string label_text; + ::nana::panel dock; + ::nana::label label; + ::nana::combox combox; + ::nana::textbox textbox; + }; + + inputbox::text::text(::nana::string label) + : impl_(new implement) + { + impl_->label_text = std::move(label); + } + + inputbox::text::text(::nana::string label, std::vector<::nana::string> options) + : impl_(new implement) + { + impl_->options.swap(options); + impl_->label_text = std::move(label); + } + + //Instance for impl_ because implmenet is incomplete type at the point of declaration + inputbox::text::~text(){} + + ::nana::string inputbox::text::value() const + { + return impl_->value; + } + + //Implementation of abstract_content + const ::nana::string& inputbox::text::label() const + { + return impl_->label_text; + } + + window inputbox::text::create(window parent, unsigned label_px) + { + auto impl = impl_.get(); + impl->dock.create(parent); + + impl->label.create(impl->dock, rectangle{ 0, 0, label_px, 0 }); + impl->label.text_align(::nana::align::right, ::nana::align_v::center); + impl->label.caption(impl->label_text); + impl->label.format(true); + + unsigned value_px = 0; + if (impl->options.empty()) + { + impl->textbox.create(impl->dock, rectangle{ static_cast(label_px + 10), 0, 0, 0 }); + } + else + { + //get the longest value + paint::graphics graph{ ::nana::size{ 10, 10 } }; + for (auto & s : impl->options) + { + auto px = graph.text_extent_size(s).width; + if (px > value_px) + value_px = px; + } + value_px += 34; + + impl->combox.create(impl->dock, rectangle{ static_cast(label_px + 10), 0, value_px, 0 }); + + for (auto & s : impl->options) + impl->combox.push_back(s); + + impl->combox.option(0); + } + + impl->dock.events().resized.connect_unignorable([impl, label_px, value_px](const ::nana::arg_resized& arg) + { + impl->label.size({ label_px, arg.height }); + if (value_px) + impl->combox.size({ value_px, 24 }); + else + impl->textbox.size({arg.width - label_px - 10, 24}); + }); + + auto & wdg = (value_px ? static_cast(impl->combox) : static_cast(impl->textbox)); + wdg.events().destroy.connect_unignorable([&wdg, impl] + { + impl->value = wdg.caption(); + }); + return impl->dock; + } + + unsigned inputbox::text::fixed_pixels() const + { + return 0; + } + //end class text + + + //class date + struct inputbox::date::implement + { + int year; + int month; + int day; + + ::nana::string label_text; + ::nana::panel dock; + ::nana::label label; + ::nana::combox wdg_month; + ::nana::spinbox wdg_day; + ::nana::spinbox wdg_year; + }; + + inputbox::date::date(::nana::string label) + : impl_(new implement) + { + impl_->label_text = std::move(label); + } + + //Instance for impl_ because implmenet is incomplete type at the point of declaration + inputbox::date::~date(){} + + ::nana::string inputbox::date::value() const + { + std::wstringstream ss; + ss << impl_->month << L'-' << impl_->day << L", " << impl_->year; + return ss.str(); + } + + int inputbox::date::year() const + { + return impl_->year; + } + + int inputbox::date::month() const + { + return impl_->month; + } + int inputbox::date::day() const + { + return impl_->day; + } + + //Implementation of abstract_content + const ::nana::string& inputbox::date::label() const + { + return impl_->label_text; + } + + window inputbox::date::create(window parent, unsigned label_px) + { + auto today = ::nana::date().read(); + + auto impl = impl_.get(); + impl->dock.create(parent); + + impl->label.create(impl->dock, rectangle{ 0, 0, label_px, 0 }); + impl->label.text_align(::nana::align::right, ::nana::align_v::center); + impl->label.caption(impl->label_text); + impl->label.format(true); + + int left = static_cast(label_px + 10); + impl->wdg_month.create(impl->dock, rectangle{left, 0, 94, 0}); + + ::nana::internationalization i18n; + const char * monthstr[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; + for (auto i = std::begin(monthstr), end = std::end(monthstr); i != end; ++i) + impl->wdg_month.push_back(i18n(*i)); + + left += 104; + impl->wdg_day.create(impl->dock, rectangle{ left, 0, 38, 0 }); + impl->wdg_day.range(1, ::nana::date::month_days(today.year, today.month), 1); + //impl->wdg_day.set_accept_integer(); //deprecated + + left += 48; + impl->wdg_year.create(impl->dock, rectangle{left, 0, 50, 0}); + impl->wdg_year.range(1601, 9999, 1); + //impl->wdg_year.set_accept_integer(); //deprecated + + impl->wdg_month.option(today.month - 1); + + std::wstringstream ss; + ss << today.day; + impl->wdg_day.value(ss.str()); + ss.str(L""); + ss.clear(); + ss << today.year; + impl->wdg_year.value(ss.str()); + + impl->dock.events().resized.connect_unignorable([impl, label_px](const ::nana::arg_resized& arg) + { + impl->label.size({ label_px, arg.height }); + auto sz = impl->wdg_month.size(); + sz.height = 24; + impl->wdg_month.size(sz); + + sz = impl->wdg_day.size(); + sz.height = 24; + impl->wdg_day.size(sz); + + sz = impl->wdg_year.size(); + sz.height = 24; + impl->wdg_year.size(sz); + }); + + impl->wdg_day.events().destroy.connect_unignorable([impl] + { + impl->day = impl->wdg_day.to_int(); + impl->month = impl->wdg_month.option() + 1; + }); + + impl->wdg_year.events().destroy.connect_unignorable([impl] + { + impl->year = impl->wdg_year.to_int(); + }); + + auto make_days = [impl] + { + auto month = impl->wdg_month.option() + 1; + auto year = impl->wdg_year.to_int(); + int days = ::nana::date::month_days(year, month); + + auto day = impl->wdg_day.to_int(); + impl->wdg_day.range(1, days, 1); //It resets the current value of wdg_day + + if (day > days) + day = days; + + std::wstringstream ss; + ss << day; + impl->wdg_day.value(ss.str()); + }; + + impl->wdg_year.events().text_changed.connect_unignorable(make_days); + impl->wdg_month.events().selected.connect_unignorable(make_days); + + return impl->dock; + } + + unsigned inputbox::date::fixed_pixels() const + { + return 202; + } + //end class date + + + inputbox::inputbox(window owner, ::nana::string desc, ::nana::string title) + : owner_{ owner }, + description_(std::move(desc)), + title_(std::move(title)) + {} + + void inputbox::verify(std::function verifier) + { + verifier_ = std::move(verifier); + } + + void inputbox::_m_fetch_args(std::vector&) + {} + + + bool inputbox::_m_open(std::vector& contents, bool modal) + { + std::vector each_pixels; + unsigned label_px = 0, fixed_px = 0; + paint::graphics graph({ 5, 5 }); + for (auto p : contents) + { + auto px = label::measure(graph, p->label(), 150, true, align::right, align_v::center); + if (px.width > label_px) + label_px = px.width; + + px.width = p->fixed_pixels(); + if (px.width > fixed_px) + fixed_px = px.width; + + each_pixels.push_back(px.height); + } + + inputbox_window input_wd(owner_, description_, title_, contents.size(), label_px + 10 + fixed_px, each_pixels); + + std::vector inputs; + for (auto p : contents) + inputs.push_back(p->create(input_wd, label_px)); + + input_wd.set_input(inputs, verifier_); + + if (modal) + input_wd.modality(); + else + API::wait_for(input_wd); + + return input_wd.valid_input(); + } + //end class inputbox } diff --git a/source/gui/place.cpp b/source/gui/place.cpp index 42f3befd..005fd3cf 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -1556,7 +1556,7 @@ namespace nana splitter_.cursor(splitter_cursor_); dragger_.trigger(splitter_); - splitter_.events().mouse_down.connect([this](const arg_mouse& arg) + splitter_.events().mouse_down.connect_unignorable([this](const arg_mouse& arg) { if (false == arg.left_button) return; @@ -1584,7 +1584,7 @@ namespace nana right_pixels_ = area_right.*px_ptr; }); - splitter_.events().mouse_move.connect([this](const arg_mouse& arg) + splitter_.events().mouse_move.connect_unignorable([this](const arg_mouse& arg) { if (false == arg.left_button) return; diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index 5830b458..9ba95f03 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -97,7 +97,9 @@ namespace API } void effects_bground(window wd, const effects::bground_factory_interface& factory, double fade_rate) - { + { + if (fade_rate < 0.0 || fade_rate > 1.0) + throw std::invalid_argument("effects_bground: value range of fade_rate must be [0, 1]."); auto const iwd = reinterpret_cast(wd); internal_scope_guard isg; if(restrict::window_manager.available(iwd)) @@ -110,6 +112,10 @@ namespace API iwd->effect.bground = new_effect_ptr; iwd->effect.bground_fade_rate = fade_rate; restrict::window_manager.enable_effects_bground(iwd, true); + + if (fade_rate < 0.01) + iwd->flags.make_bground_declared = true; + API::refresh_window(wd); } } @@ -150,14 +156,29 @@ namespace API return false; } + void set_scheme(window wd, widget_colors* wdg_colors) + { + auto iwd = reinterpret_cast(wd); + internal_scope_guard lock; + if (restrict::window_manager.available(iwd)) + iwd->scheme = wdg_colors; + } + + widget_colors* get_scheme(window wd) + { + auto iwd = reinterpret_cast(wd); + internal_scope_guard lock; + return (restrict::window_manager.available(iwd) ? iwd->scheme : nullptr); + } + void attach_drawer(widget& wd, drawer_trigger& dr) { const auto iwd = reinterpret_cast(wd.handle()); internal_scope_guard isg; if(restrict::window_manager.available(iwd)) { - iwd->drawer.graphics.make(iwd->dimension.width, iwd->dimension.height); - iwd->drawer.graphics.rectangle(iwd->color.background, true); + iwd->drawer.graphics.make(iwd->dimension); + iwd->drawer.graphics.rectangle(true, iwd->scheme->background.get_color()); iwd->drawer.attached(wd, dr); iwd->drawer.refresh(); //Always redrawe no matter it is visible or invisible. This can make the graphics data correctly. } @@ -291,16 +312,6 @@ namespace API restrict::window_manager.unregister_shortkey(reinterpret_cast(wd), false); } - nana::size screen_size() - { - return restrict::interface_type::screen_size(); - } - - rectangle screen_area_from_point(const point& pos) - { - return restrict::interface_type::screen_area_from_point(pos); - } - nana::point cursor_position() { return restrict::interface_type::cursor_position(); @@ -308,7 +319,7 @@ namespace API nana::rectangle make_center(unsigned width, unsigned height) { - nana::size screen = restrict::interface_type::screen_size(); + nana::size screen = restrict::interface_type::primary_monitor_size(); nana::rectangle result( width > screen.width? 0: (screen.width - width)>>1, height > screen.height? 0: (screen.height - height)>> 1, @@ -343,6 +354,11 @@ namespace API return (restrict::window_manager.available(reinterpret_cast(wd)) == false); } + bool is_window(window wd) + { + return restrict::window_manager.available(reinterpret_cast(wd)); + } + void enable_dropfiles(window wd, bool enb) { internal_scope_guard lock; @@ -529,9 +545,9 @@ namespace API } } - void bring_to_top(window wd) + void bring_top(window wd, bool activated) { - restrict::interface_type::bring_to_top(root(wd)); + restrict::interface_type::bring_top(root(wd), activated); } bool set_window_z_order(window wd, window wd_after, z_order_action action_if_no_wd_after) @@ -558,6 +574,27 @@ namespace API return false; } + void draw_through(window wd, std::function draw_fn) + { + auto iwd = reinterpret_cast(wd); + internal_scope_guard lock; + if (!restrict::bedrock.wd_manager.available(iwd)) + throw std::invalid_argument("draw_through: invalid window parameter"); + + if (::nana::category::flags::root != iwd->other.category) + throw std::invalid_argument("draw_through: the window is not a root widget"); + + iwd->other.attribute.root->draw_through.swap(draw_fn); + } + + void map_through_widgets(window wd, native_drawable_type drawable) + { + auto iwd = reinterpret_cast<::nana::detail::basic_window*>(wd); + internal_scope_guard lock; + if (restrict::bedrock.wd_manager.available(iwd) && iwd->is_draw_through() ) + restrict::bedrock.map_through_widgets(iwd, drawable); + } + nana::size window_size(window wd) { nana::rectangle r; @@ -669,6 +706,12 @@ namespace API restrict::window_manager.update(reinterpret_cast(wd), false, true); } + + void window_caption(window wd, const std::string& title_utf8) + { + window_caption(wd, std::wstring(::nana::charset(title_utf8, ::nana::unicode::utf8))); + } + void window_caption(window wd, const nana::string& title) { auto const iwd = reinterpret_cast(wd); @@ -790,80 +833,85 @@ namespace API restrict::bedrock.pump_event(wd, false); } - nana::color_t foreground(window wd) + color fgcolor(window wd) { internal_scope_guard lock; - if(restrict::window_manager.available(reinterpret_cast(wd))) - return reinterpret_cast(wd)->color.foreground; - return 0; + if (restrict::window_manager.available(reinterpret_cast(wd))) + return reinterpret_cast(wd)->scheme->foreground.get_color(); + return{}; } - color_t foreground(window wd, color_t col) + color fgcolor(window wd, const color& clr) { auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::window_manager.available(iwd)) + if (restrict::window_manager.available(iwd)) { - color_t prev = iwd->color.foreground; - if(prev != col) + auto prev = iwd->scheme->foreground.get_color(); + if (prev != clr) { - iwd->color.foreground = col; + iwd->scheme->foreground = clr; restrict::window_manager.update(iwd, true, false); } return prev; } - return 0; + return{}; } - color_t background(window wd) + color bgcolor(window wd) { internal_scope_guard lock; - if(restrict::window_manager.available(reinterpret_cast(wd))) - return reinterpret_cast(wd)->color.background; - return 0; + if (restrict::window_manager.available(reinterpret_cast(wd))) + return reinterpret_cast(wd)->scheme->background.get_color(); + return{}; } - color_t background(window wd, color_t col) + color bgcolor(window wd, const color& clr) { auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::window_manager.available(iwd)) + if (restrict::window_manager.available(iwd)) { - color_t prev = iwd->color.background; - if(prev != col) + auto prev = iwd->scheme->background.get_color(); + if (prev != clr) { - iwd->color.background = col; + iwd->scheme->background = clr; + + //If the bground mode of this window is basic, it should remake the background + if (iwd->effect.bground && iwd->effect.bground_fade_rate < 0.01) // fade rate < 0.01 means it is basic mode + iwd->flags.make_bground_declared = true; + restrict::window_manager.update(iwd, true, false); } return prev; } - return 0; + return{}; } - color_t active(window wd) + color activated_color(window wd) { internal_scope_guard lock; - if(restrict::window_manager.available(reinterpret_cast(wd))) - return reinterpret_cast(wd)->color.active; - return 0; + if (restrict::window_manager.available(reinterpret_cast(wd))) + return reinterpret_cast(wd)->scheme->activated.get_color(); + return{}; } - color_t active(window wd, color_t col) + color activated_color(window wd, const color& clr) { auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::window_manager.available(iwd)) + if (restrict::window_manager.available(iwd)) { - color_t prev = iwd->color.active; - if(prev != col) + auto prev = iwd->scheme->activated.get_color(); + if (prev != clr) { - iwd->color.active = col; + iwd->scheme->activated = clr; restrict::window_manager.update(iwd, true, false); } return prev; } - - return 0; + + return{}; } void create_caret(window wd, unsigned width, unsigned height) @@ -886,12 +934,12 @@ namespace API } } - void caret_pos(window wd, int x, int y) + void caret_pos(window wd, const point& pos) { auto iwd = reinterpret_cast(wd); internal_scope_guard lock; if(restrict::window_manager.available(iwd) && iwd->together.caret) - iwd->together.caret->position(x, y); + iwd->together.caret->position(pos.x, pos.y); } nana::point caret_pos(window wd) diff --git a/source/gui/screen.cpp b/source/gui/screen.cpp new file mode 100644 index 00000000..ef6c8fec --- /dev/null +++ b/source/gui/screen.cpp @@ -0,0 +1,193 @@ +/* + * Screen Informations + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 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/gui/screen.cpp + */ +#include +#include +#include +#include +#include +#if defined(NANA_WINDOWS) + #include +#endif + +namespace nana +{ + //class display + class real_display + : public display + { + public: + real_display(std::size_t number) + : index_(number) + { +#if defined(NANA_WINDOWS) + DISPLAY_DEVICE disp; + disp.cb = sizeof disp; + if (::EnumDisplayDevices(nullptr, static_cast(index_), &disp, 0)) + { + DEVMODE mode; + mode.dmSize = sizeof mode; + if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode)) + { + area_.x = mode.dmPosition.x; + area_.y = mode.dmPosition.y; + area_.width = mode.dmPelsWidth; + area_.height = mode.dmPelsHeight; + return; + } + } +#else + if (0 == index_) + { + area_ = detail::native_interface::primary_monitor_size(); + return; + } +#endif + throw std::invalid_argument("Nana.Screen: Invalid monitor index."); + } + + real_display(std::size_t number, const ::nana::rectangle& r) + : index_(number), area_(r) + { + } + public: + //Implementation of display + std::size_t get_index() const override + { + return index_; + } + + const ::nana::rectangle& area() const override + { + return area_; + } + private: + const std::size_t index_; + ::nana::rectangle area_; + }; + + //class screen + + ::nana::size screen::desktop_size() + { +#if defined(NANA_WINDOWS) + auto w = static_cast(::GetSystemMetrics(SM_CXVIRTUALSCREEN)); + auto h = static_cast(::GetSystemMetrics(SM_CYVIRTUALSCREEN)); + return{w, h}; +#else + return ::nana::detail::native_interface::primary_monitor_size(); +#endif + } + + ::nana::size screen::primary_monitor_size() + { + return ::nana::detail::native_interface::primary_monitor_size(); + } + + std::shared_ptr screen::from_point(const point& pos) + { +#if defined(NANA_WINDOWS) + typedef HMONITOR(__stdcall * MonitorFromPointT)(POINT, DWORD); + + MonitorFromPointT mfp = reinterpret_cast(::GetProcAddress(::GetModuleHandleA("User32.DLL"), "MonitorFromPoint")); + if (mfp) + { + POINT native_pos = { pos.x, pos.y }; + HMONITOR monitor = mfp(native_pos, 2 /*MONITOR_DEFAULTTONEAREST*/); + + MONITORINFO mi; + mi.cbSize = sizeof mi; + if (::GetMonitorInfo(monitor, &mi)) + { + DISPLAY_DEVICE disp; + disp.cb = sizeof disp; + + DWORD index = 0; + while (::EnumDisplayDevices(nullptr, index++, &disp, 0)) + { + DEVMODE mode; + mode.dmSize = sizeof mode; + if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode)) + { + if (mode.dmPosition.x == mi.rcWork.left && mode.dmPosition.y == mi.rcWork.top && + (static_cast(mode.dmPelsWidth) == mi.rcWork.right - mi.rcWork.left) && + (static_cast(mode.dmPelsHeight) == mi.rcWork.bottom - mi.rcWork.top)) + { + return std::make_shared(static_cast(index - 1), rectangle{ mode.dmPosition.x, mode.dmPosition.y, static_cast(mode.dmPelsWidth), static_cast(mode.dmPelsHeight) }); + } + } + } + } + } +#endif + return screen().get_primary(); + } + + std::shared_ptr screen::from_window(window wd) + { + ::nana::point pos; + API::calc_screen_point(wd, pos); + return from_point(pos); + } + + std::size_t screen::count() const + { +#if defined(NANA_WINDOWS) + DISPLAY_DEVICE disp; + disp.cb = sizeof disp; + + DWORD index = 0; + while (::EnumDisplayDevices(nullptr, index++, &disp, 0)); + return static_cast(index - 1); +#else + return 1; +#endif + } + + std::shared_ptr screen::get_display(std::size_t index) const + { + return std::make_shared(index); + } + + std::shared_ptr screen::get_primary() const + { +#if defined(NANA_WINDOWS) + //return rectangle(mi.rcWork.left, mi.rcWork.top, + // mi.rcWork.right - mi.rcWork.left, mi.rcWork.bottom - mi.rcWork.top); + DISPLAY_DEVICE disp; + disp.cb = sizeof disp; + + DWORD index = 0; + while (::EnumDisplayDevices(nullptr, index++, &disp, 0)) + { + DEVMODE mode; + mode.dmSize = sizeof mode; + if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode)) + { + if (mode.dmPosition.x == 0 && mode.dmPosition.y == 0) + return std::make_shared(static_cast(index - 1), rectangle{ mode.dmPosition.x, mode.dmPosition.y, static_cast(mode.dmPelsWidth), static_cast(mode.dmPelsHeight) }); + } + } +#endif + return std::make_shared(0); + } + + void screen::for_each(std::function fn) const + { + auto n = count(); + for (decltype(n) i = 0; i < n; ++i) + { + real_display disp(i); + fn(disp); + } + } + //end class screen +} diff --git a/source/gui/tooltip.cpp b/source/gui/tooltip.cpp index 1daa20b4..02eae44d 100644 --- a/source/gui/tooltip.cpp +++ b/source/gui/tooltip.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace nana @@ -26,14 +27,14 @@ namespace nana private: void refresh(graph_reference graph) { - graph.rectangle(0x0, false); - graph.rectangle(1, 1, graph.width() - 2, graph.height() - 2, 0xF0F0F0, true); + graph.rectangle(false, colors::black); + graph.rectangle(::nana::rectangle(graph.size()).pare_off(1), true, {0xf0, 0xf0, 0xf0}); } }; nana::point pos_by_screen(nana::point pos, const nana::size& sz, bool overlap_allowed) { - auto scr_area = API::screen_area_from_point(pos); + auto scr_area = screen::from_point(pos)->area(); if (pos.x + sz.width > scr_area.x + scr_area.width) pos.x = static_cast(scr_area.x + scr_area.width - sz.width); if (pos.x < scr_area.x) @@ -76,7 +77,7 @@ namespace nana void tooltip_text(const nana::string& text) override { label_.caption(text); - auto text_s = label_.measure(API::screen_size().width * 2 / 3); + auto text_s = label_.measure(screen::from_window(label_)->area().width * 2 / 3); this->size(nana::size{ text_s.width + 10, text_s.height + 10 }); label_.move(rectangle{ 5, 5, text_s.width, text_s.height }); diff --git a/source/gui/widgets/button.cpp b/source/gui/widgets/button.cpp index 4c106182..63d8e810 100644 --- a/source/gui/widgets/button.cpp +++ b/source/gui/widgets/button.cpp @@ -1,7 +1,7 @@ /* * A Button Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -20,12 +20,8 @@ namespace nana{ namespace drawerbase //trigger //@brief: draw the button trigger::trigger() - : widget_(nullptr), - graph_(nullptr), - cite_("button") { attr_.e_state = element_state::normal; - attr_.omitted = attr_.focused = attr_.pushed = attr_.enable_pushed = attr_.keep_pressed = false; attr_.focus_color = true; attr_.icon = nullptr; @@ -40,7 +36,7 @@ namespace nana{ namespace drawerbase { graph_ = &graph; - widget_ = &widget; + wdg_ = &widget; window wd = widget; API::tabstop(wd); @@ -61,7 +57,7 @@ namespace nana{ namespace drawerbase attr_.pushed = pshd; if(false == pshd) { - if (API::find_window(API::cursor_position()) == widget_->handle()) + if (API::find_window(API::cursor_position()) == wdg_->handle()) attr_.e_state = element_state::hovered; else attr_.e_state = element_state::normal; @@ -128,13 +124,13 @@ namespace nana{ namespace drawerbase attr_.keep_pressed = true; _m_draw(graph); - API::capture_window(*widget_, true); + API::capture_window(*wdg_, true); API::lazy_refresh(); } void trigger::mouse_up(graph_reference graph, const arg_mouse&) { - API::capture_window(*widget_, false); + API::capture_window(*wdg_, false); attr_.keep_pressed = false; if(attr_.enable_pushed && (false == attr_.pushed)) { @@ -173,7 +169,7 @@ namespace nana{ namespace drawerbase default: return; } - API::move_tabstop(widget_->handle(), ch_tabstop_next); + API::move_tabstop(*wdg_, ch_tabstop_next); } void trigger::focus(graph_reference graph, const arg_focus& arg) @@ -185,7 +181,7 @@ namespace nana{ namespace drawerbase void trigger::_m_draw_title(graph_reference graph, bool enabled) { - nana::string text = widget_->caption(); + nana::string text = wdg_->caption(); nana::string::value_type shortkey; nana::string::size_type shortkey_pos; @@ -201,11 +197,12 @@ namespace nana{ namespace drawerbase icon_sz.width += 5; } - int x = (static_cast(gsize.width - 1 - ts.width) >> 1); - int y = (static_cast(gsize.height - 1 - ts.height) >> 1); + nana::point pos{ + static_cast(gsize.width - 1 - ts.width) >> 1, static_cast(gsize.height - 1 - ts.height) >> 1 + }; - if(x < static_cast(icon_sz.width)) - x = static_cast(icon_sz.width); + if(pos.x < static_cast(icon_sz.width)) + pos.x = static_cast(icon_sz.width); unsigned omitted_pixels = gsize.width - icon_sz.width; std::size_t txtlen = str.size(); @@ -217,35 +214,45 @@ namespace nana{ namespace drawerbase { if (element_state::pressed == attr_.e_state) { - ++x; - ++y; + ++pos.x; + ++pos.y; } - color_t fgcolor = (attr_.focus_color ? (attr_.focused ? 0xFF : attr_.fgcolor) : attr_.fgcolor); - if(attr_.omitted) - tr.render(x, y, fgcolor, txtptr, txtlen, omitted_pixels, true); + //color_t fgcolor = (attr_.focus_color ? (attr_.focused ? 0xFF : attr_.fgcolor) : attr_.fgcolor); + auto fgcolor = attr_.fgcolor; + if (attr_.focus_color && attr_.focused) + fgcolor = ::nana::color(colors::blue); + + graph.set_text_color(fgcolor); + + if (attr_.omitted) + tr.render(pos, txtptr, txtlen, omitted_pixels, true); else - graph.bidi_string(x, y, fgcolor, txtptr, txtlen); + graph.bidi_string(pos, txtptr, txtlen); if(shortkey) { unsigned off_w = (shortkey_pos ? graph.text_extent_size(str, static_cast(shortkey_pos)).width : 0); nana::size shortkey_size = graph.text_extent_size(txtptr + shortkey_pos, 1); - x += off_w; - y += shortkey_size.height; - graph.line(x, y, x + shortkey_size.width - 1, y, 0x0); + pos.x += off_w; + pos.y += static_cast(shortkey_size.height); + graph.set_color(colors::black); + graph.line(pos, point{ pos.x + static_cast(shortkey_size.width) - 1, pos.y }); } } else { + graph.set_text_color(::nana::color(colors::white)); if(attr_.omitted) { - tr.render(x + 1, y + 1, 0xFFFFFF, txtptr, txtlen, omitted_pixels, true); - tr.render(x, y, 0x808080, txtptr, txtlen, omitted_pixels, true); + tr.render(point{ pos.x + 1, pos.y + 1 }, txtptr, txtlen, omitted_pixels, true); + graph.set_text_color(::nana::color(colors::gray)); + tr.render(pos, txtptr, txtlen, omitted_pixels, true); } else { - graph.bidi_string(x + 1, y + 1, 0xFFFFFF, txtptr, txtlen); - graph.bidi_string(x, y, 0x808080, txtptr, txtlen); + graph.bidi_string(point{ pos.x + 1, pos.y + 1 }, txtptr, txtlen); + graph.set_text_color(::nana::color(colors::gray)); + graph.bidi_string(pos, txtptr, txtlen); } } } @@ -256,11 +263,10 @@ namespace nana{ namespace drawerbase void trigger::_m_draw(graph_reference graph) { - window wd = widget_->handle(); - bool eb = API::window_enabled(wd); + bool eb = wdg_->enabled();; - attr_.bgcolor = API::background(wd); - attr_.fgcolor = API::foreground(wd); + attr_.bgcolor = wdg_->bgcolor(); + attr_.fgcolor = wdg_->fgcolor(); element_state e_state = attr_.e_state; if (eb) @@ -278,7 +284,7 @@ namespace nana{ namespace drawerbase if (false == cite_.draw(graph, attr_.bgcolor, attr_.fgcolor, graph.size(), e_state)) { - if (bground_mode::basic != API::effects_bground_mode(wd)) + if (bground_mode::basic != API::effects_bground_mode(wdg_->handle())) { _m_draw_background(graph); _m_draw_border(graph); @@ -291,15 +297,16 @@ namespace nana{ namespace drawerbase { nana::rectangle r(graph.size()); r.pare_off(1); - nana::color_t color_start = nana::paint::graphics::mix(attr_.bgcolor, 0xFFFFFF, 0.2); - nana::color_t color_end = nana::paint::graphics::mix(attr_.bgcolor, 0x0, 0.95); + + auto from = attr_.bgcolor.blend(colors::white, 0.2); + auto to = attr_.bgcolor.blend(colors::black, 0.95); if (element_state::pressed == attr_.e_state) { r.x = r.y = 2; - std::swap(color_start, color_end); + std::swap(from, to); } - graph.shadow_rectangle(r, color_start, color_end, true); + graph.gradual_rectangle(r, from, to, true); } void trigger::_m_draw_border(graph_reference graph) @@ -308,28 +315,30 @@ namespace nana{ namespace drawerbase int right = r.width - 1; int bottom = r.height - 1; - graph.rectangle_line(r, - 0x7F7F7F, 0x7F7F7F, 0x707070, 0x707070); + ::nana::color lt{0x7f,0x7f,0x7f}, rb{0x70,0x70,0x70}; + graph.frame_rectangle(r, lt, lt, rb, rb); - graph.set_pixel(1, 1, 0x919191); - graph.set_pixel(right - 1, 1, 0x919191); - graph.set_pixel(right - 1, bottom - 1, 0x919191); - graph.set_pixel(1, bottom - 1, 0x919191); + graph.set_color({0x91,0x91,0x91}); + graph.set_pixel(1, 1); + graph.set_pixel(right - 1, 1); + graph.set_pixel(right - 1, bottom - 1); + graph.set_pixel(1, bottom - 1); - graph.set_pixel(0, 0, color::button_face); - graph.set_pixel(right, 0, color::button_face); - graph.set_pixel(0, bottom, color::button_face); - graph.set_pixel(right, bottom, color::button_face); + graph.set_color(colors::button_face); + graph.set_pixel(0, 0); + graph.set_pixel(right, 0); + graph.set_pixel(0, bottom); + graph.set_pixel(right, bottom); if (element_state::pressed == attr_.e_state) - graph.rectangle(r.pare_off(1), 0xC3C3C3, false); + graph.rectangle(r.pare_off(1), false, {0xc3, 0xc3, 0xc3}); } void trigger::emit_click() { arg_mouse arg; arg.evt_code = event_code::click; - arg.window_handle = widget_->handle(); + arg.window_handle = wdg_->handle(); arg.ctrl = arg.shift = false; arg.mid_button = arg.right_button = false; arg.left_button = true; @@ -470,7 +479,7 @@ namespace nana{ namespace drawerbase void button::_m_complete_creation() { - events().shortkey.connect([this] + events().shortkey.connect_unignorable([this] { _m_shortkey(); }); diff --git a/source/gui/widgets/categorize.cpp b/source/gui/widgets/categorize.cpp index 26eee1b3..e891afea 100644 --- a/source/gui/widgets/categorize.cpp +++ b/source/gui/widgets/categorize.cpp @@ -1,7 +1,7 @@ /* * A Categorize Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -73,35 +74,36 @@ namespace nana void background(graph_reference graph, window wd, const nana::rectangle& r, const ui_element& ue) { ui_el_ = ue; - style_.bgcolor = API::background(wd); - style_.fgcolor = API::foreground(wd); + style_.bgcolor = API::bgcolor(wd); + style_.fgcolor = API::fgcolor(wd); if(ue.what == ue.none || (API::window_enabled(wd) == false)) { //the mouse is out of the widget. - style_.bgcolor = nana::paint::graphics::mix(style_.bgcolor, 0xA0C9F5, 0.9); + style_.bgcolor = style_.bgcolor.blend(color{ 0xa0, 0xc9, 0xf5 }, 0.9); } - graph.rectangle(r, style_.bgcolor, true); + graph.rectangle(r, true, style_.bgcolor); } virtual void root_arrow(graph_reference graph, const nana::rectangle& r, mouse_action state) { - int x = r.x + (r.width - 16) / 2; - int y = r.y + (r.height - 16) / 2; + ::nana::rectangle arrow_r{r.x + static_cast(r.width - 16) / 2, r.y + static_cast(r.height - 16) / 2, 16, 16}; + if(ui_el_.what == ui_el_.item_root) { _m_item_bground(graph, r.x + 1, r.y, r.width - 2, r.height, (state == mouse_action::pressed ? mouse_action::pressed : mouse_action::over)); - graph.rectangle(r, 0x3C7FB1, false); + graph.rectangle(r, false, color{ 0x3C, 0x7F, 0xB1 }); if(state == mouse_action::pressed) { - ++x; - ++y; + ++arrow_r.x; + ++arrow_r.y; } } else - graph.rectangle(r, style_.bgcolor, true); + graph.rectangle(r, true, style_.bgcolor); - nana::paint::gadget::arrow_16_pixels(graph, x, y, - style_.fgcolor, 3, nana::paint::gadget::directions::to_west); + facade arrow("double"); + arrow.direction(::nana::direction::west); + arrow.draw(graph, {}, style_.fgcolor, arrow_r, element_state::normal); } void item(graph_reference graph, const nana::rectangle& r, std::size_t index, const nana::string& name, unsigned txtheight, bool has_child, mouse_action state) @@ -126,31 +128,39 @@ namespace nana int top = r.y + 1; unsigned width = r.width - 2; unsigned height = r.height - 2; + + ::nana::color clr{ 0x3C, 0x7F, 0xB1 }; if(has_child) { - int left = r.x + r.width - 16; - _m_item_bground(graph, left, top, 15, height, state_arrow); width -= 16; - --left; - graph.line(left, top, left, r.y + height, 0x3C7FB1); + + int left = r.x + r.width - 17; + _m_item_bground(graph, left + 1, top, 15, height, state_arrow); + graph.line({ left, top }, { left, r.y + static_cast(height) }, clr); } + _m_item_bground(graph, r.x + 1, top, width, height, state_name); - graph.rectangle(r, 0x3C7FB1, false); + graph.rectangle(r, false, clr); } - graph.string(strpos.x, strpos.y, style_.fgcolor, name); + graph.string(strpos, name, style_.fgcolor); if(has_child) { - nana::paint::gadget::arrow_16_pixels(graph, r.x + r.width - 16, r.y + (r.height - 16)/2, - style_.fgcolor, 3, nana::paint::gadget::directions::to_east); + facade arrow("double"); + arrow.direction(::nana::direction::east); + arrow.draw(graph, {}, style_.fgcolor, { r.right() - 16, r.y + static_cast(r.height - 16) / 2, 16, 16 }, element_state::normal); } } void border(graph_reference graph) { - graph.rectangle(0xF0F0F0, false); - graph.rectangle_line(nana::rectangle(graph.size()).pare_off(1), - 0x9DABB9, 0x484E55, 0x484E55, 0x9DABB9); + rectangle r{ graph.size() }; + + graph.rectangle(r, false, { 0xf0, 0xf0, 0xf0 }); + + color lb(0x9d, 0xab, 0xb9); + color tr(0x48, 0x4e, 0x55); + graph.frame_rectangle(r.pare_off(1), lb, tr, tr, lb); } private: void _m_item_bground(graph_reference graph, int x, int y, unsigned width, unsigned height, mouse_action state) @@ -158,38 +168,38 @@ namespace nana const unsigned half = (height - 2) / 2; int left = x + 1; int top = y + 1; - nana::color_t upcol, downcol; + nana::color clr_top(0xea, 0xea, 0xea), clr_bottom(0xdc, 0xdc, 0xdc); switch(state) { case mouse_action::over: - upcol = 0x0DFF2FC; - downcol = 0xA9DAF5; + clr_top.from_rgb(0xdf, 0xf2, 0xfc); + clr_bottom.from_rgb(0xa9, 0xda, 0xf5); break; case mouse_action::pressed: - upcol = 0xA6D7F2; - downcol = 0x92C4F6; + clr_top.from_rgb(0xa6, 0xd7, 0xf2); + clr_bottom.from_rgb(0x92, 0xc4, 0xf6); ++left; ++top; break; - case mouse_action::normal: default: - upcol = 0xEAEAEA; - downcol = 0xDCDCDC; break; } - graph.rectangle(left, top, width - 2, half, upcol, true); - graph.rectangle(left, top + static_cast(half), width - 2, (height - 2) - half, downcol, true); + graph.rectangle(rectangle{ left, top, width - 2, half }, true, clr_top); + graph.rectangle(rectangle{ left, top + static_cast(half), width - 2, (height - 2) - half }, true, clr_bottom); if(mouse_action::pressed == state) { int bottom = y + height - 1; int right = x + width - 1; - graph.line(x, y, right, y, 0x6E8D9F); - graph.line(x, y + 1, x, bottom, 0x6E8D9F); + + graph.set_color(color(0x6e, 0x8d, 0x9f)); + graph.line(point{ x, y }, point{right, y}); + graph.line(point{ x, y + 1 }, point{ x, bottom }); ++x; ++y; - graph.line(x, y, right, y, 0xA6C7D9); - graph.line(x, y + 1, x, bottom, 0xA6C7D9); + graph.set_color(color(0xa6, 0xc7, 0xd9)); + graph.line(point{ x, y }, point{ right, y }); + graph.line(point{ x, y + 1 }, point{ x, bottom }); } } @@ -197,8 +207,10 @@ namespace nana ui_element ui_el_; struct style_tag { - nana::color_t bgcolor; - nana::color_t fgcolor; + //nana::color_t bgcolor; + //nana::color_t fgcolor; + color bgcolor; + color fgcolor; }style_; }; @@ -369,7 +381,6 @@ namespace nana }; scheme() - : graph_(nullptr) { proto_.ui_renderer = pat::cloneable(interior_renderer()); style_.mode = mode::normal; @@ -379,7 +390,7 @@ namespace nana void attach(window wd, nana::paint::graphics* graph) { window_ = wd; - API::background(wd, 0xFFFFFF); + API::bgcolor(wd, colors::white); graph_ = graph; } @@ -582,7 +593,7 @@ namespace nana r.width = r.height = 100; style_.listbox = &(form_loader()(window_, r, true)); style_.listbox->set_module(style_.module, 16); - style_.listbox->events().destroy.connect([this] + style_.listbox->events().destroy.connect_unignorable([this] { _m_list_closed(); }); @@ -637,7 +648,7 @@ namespace nana nana::rectangle _m_make_root_rectangle() const { - return nana::rectangle(1, 1, 16, _m_item_fix_scale()); + return{ 1, 1, 16, _m_item_fix_scale() }; } //_m_make_rectangle @@ -765,8 +776,8 @@ namespace nana } } private: - window window_; - nana::paint::graphics * graph_; + window window_{nullptr}; + nana::paint::graphics * graph_{nullptr}; nana::string splitstr_; std::size_t head_; unsigned item_height_; diff --git a/source/gui/widgets/checkbox.cpp b/source/gui/widgets/checkbox.cpp index 6beee6ee..1a73f706 100644 --- a/source/gui/widgets/checkbox.cpp +++ b/source/gui/widgets/checkbox.cpp @@ -1,6 +1,7 @@ /* * A CheckBox Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -88,31 +89,33 @@ namespace checkbox void drawer::_m_draw_background(graph_reference graph) { if(bground_mode::basic != API::effects_bground_mode(*widget_)) - graph.rectangle(API::background(*widget_), true); + graph.rectangle(true, API::bgcolor(*widget_)); } void drawer::_m_draw_checkbox(graph_reference graph, unsigned first_line_height) { - impl_->crook.draw(graph, widget_->background(), widget_->foreground(), rectangle(0, first_line_height > 16 ? (first_line_height - 16) / 2 : 0, 16, 16), API::element_state(*widget_)); + impl_->crook.draw(graph, widget_->bgcolor(), widget_->fgcolor(), rectangle(0, first_line_height > 16 ? (first_line_height - 16) / 2 : 0, 16, 16), API::element_state(*widget_)); } void drawer::_m_draw_title(graph_reference graph) { - if(graph.width() > 16 + interval) + if (graph.width() > 16 + interval) { nana::string title = widget_->caption(); - unsigned fgcolor = widget_->foreground(); unsigned pixels = graph.width() - (16 + interval); nana::paint::text_renderer tr(graph); - if(API::window_enabled(widget_->handle()) == false) + if (API::window_enabled(widget_->handle()) == false) { - tr.render(17 + interval, 2, 0xFFFFFF, title.c_str(), title.length(), pixels); - fgcolor = 0x808080; + graph.set_text_color(colors::white); + tr.render({ 17 + interval, 2 }, title.c_str(), title.length(), pixels); + graph.set_text_color({ 0x80, 0x80, 0x80 }); } + else + graph.set_text_color(widget_->fgcolor()); - tr.render(16 + interval, 1, fgcolor, title.c_str(), title.length(), pixels); + tr.render({ 16 + interval, 1 }, title.c_str(), title.length(), pixels); } } //end class drawer @@ -205,8 +208,8 @@ namespace checkbox element_tag el; el.uiobj = &uiobj; - el.eh_checked = uiobj.events().click.connect_front(std::bind(&radio_group::_m_checked, this, std::placeholders::_1)); - el.eh_destroy = uiobj.events().destroy.connect(std::bind(&radio_group::_m_destroy, this, std::placeholders::_1)); + el.eh_checked = uiobj.events().click.connect_unignorable(std::bind(&radio_group::_m_checked, this, std::placeholders::_1), true); + el.eh_destroy = uiobj.events().destroy.connect_unignorable(std::bind(&radio_group::_m_destroy, this, std::placeholders::_1)); ui_container_.push_back(el); } diff --git a/source/gui/widgets/combox.cpp b/source/gui/widgets/combox.cpp index c4ec001c..c39c7a83 100644 --- a/source/gui/widgets/combox.cpp +++ b/source/gui/widgets/combox.cpp @@ -1,7 +1,7 @@ /* * A Combox Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -10,19 +10,41 @@ * @file: nana/gui/widgets/combox.cpp */ -#include +#include #include -#include +#include #include #include #include +#include namespace nana { + arg_combox::arg_combox(combox& wdg): widget(wdg) + {} + namespace drawerbase { namespace combox { + class event_agent + : public widgets::skeletons::textbase_event_agent_interface + { + public: + event_agent(::nana::combox& wdg) + : widget_(wdg) + {} + + void first_change() override{} //empty, because combox does not have this event. + + void text_changed() override + { + widget_.events().text_changed.emit(::nana::arg_combox{ widget_ }); + } + private: + ::nana::combox & widget_; + }; + struct item : public float_listbox::item_interface { @@ -38,8 +60,8 @@ namespace nana { } - item(const nana::string& s) - : item_text(s) + item(nana::string&& s) + : item_text(std::move(s)) {} private: //implement item_interface methods @@ -57,25 +79,19 @@ namespace nana class drawer_impl { public: - typedef nana::paint::graphics & graph_reference; - typedef widget & widget_reference; + using graph_reference = paint::graphics&; + using widget_reference = widget&; - enum class where_t{unknown, text, push_button}; - enum class state_t{none, mouse_over, pressed}; + enum class parts{none, text, push_button}; drawer_impl() { state_.focused = false; - state_.state = state_t::none; - state_.pointer_where = where_t::unknown; + state_.button_state = element_state::normal; + state_.pointer_where = parts::none; state_.lister = nullptr; } - ~drawer_impl() - { - clear(); - } - void renderer(drawerbase::float_listbox::item_renderer* ir) { item_renderer_ = ir; @@ -84,13 +100,15 @@ namespace nana void attached(widget_reference wd, graph_reference graph) { widget_ = static_cast< ::nana::combox*>(&wd); - editor_ = new widgets::skeletons::text_editor(widget_->handle(), graph); - editor_->border_renderer([this](graph_reference graph, nana::color_t bgcolor){ - draw_border(graph, bgcolor); - }); + + auto scheme = dynamic_cast< ::nana::widgets::skeletons::text_editor_scheme*>(API::dev::get_scheme(wd)); + editor_ = new widgets::skeletons::text_editor(widget_->handle(), graph, scheme); editor_->multi_lines(false); editable(false); graph_ = &graph; + + evt_agent_.reset(new event_agent{ static_cast(wd) }); + editor_->textbase().set_event_agent(evt_agent_.get()); } void detached() @@ -100,17 +118,12 @@ namespace nana graph_ = nullptr; } - void insert(const nana::string& text) + void insert(nana::string&& text) { - items_.emplace_back(std::make_shared(text)); + items_.emplace_back(std::make_shared(std::move(text))); API::refresh_window(widget_->handle()); } - where_t get_where() const - { - return state_.pointer_where; - } - nana::any * anyobj(std::size_t pos, bool allocate_if_empty) const { if(pos >= items_.size()) @@ -170,38 +183,36 @@ namespace nana bool editable() const { - return (editor_ ? editor_->attr().editable : false); + return (editor_ && editor_->attr().editable); } bool calc_where(graph_reference graph, int x, int y) { - auto new_where = where_t::unknown; - + auto new_where = parts::none; if(1 < x && x < static_cast(graph.width()) - 2 && 1 < y && y < static_cast(graph.height()) - 2) { if((editor_->attr().editable == false) || (static_cast(graph.width()) - 22 <= x)) - new_where = where_t::push_button; + new_where = parts::push_button; else - new_where = where_t::text; + new_where = parts::text; } - if(new_where != state_.pointer_where) - { - state_.pointer_where = new_where; - return true; - } - return false; + if (new_where == state_.pointer_where) + return false; + + state_.pointer_where = new_where; + return true; } void set_mouse_over(bool mo) { - state_.state = mo ? state_t::mouse_over : state_t::none; - state_.pointer_where = where_t::unknown; + state_.button_state = (mo ? element_state::hovered : element_state::normal); + state_.pointer_where = parts::none; } void set_mouse_press(bool mp) { - state_.state = (mp ? state_t::pressed : state_t::mouse_over); + state_.button_state = (mp ? element_state::pressed : element_state::hovered); } void set_focused(bool f) @@ -219,9 +230,9 @@ namespace nana return (state_.lister != nullptr); } - void open_lister() + void open_lister_if_push_button_positioned() { - if((nullptr == state_.lister) && !items_.empty()) + if((nullptr == state_.lister) && !items_.empty() && (parts::push_button == state_.pointer_where)) { module_.items.clear(); std::copy(items_.cbegin(), items_.cend(), std::back_inserter(module_.items)); @@ -232,7 +243,7 @@ namespace nana //The lister window closes by itself. I just take care about the destroy event. //The event should be destroy rather than unload. Because the unload event is invoked while //the lister is not closed, if popuping a message box, the lister will cover the message box. - state_.lister->events().destroy.connect([this] + state_.lister->events().destroy.connect_unignorable([this] { _m_lister_close_sig(); }); @@ -247,29 +258,30 @@ namespace nana void move_items(bool upwards, bool circle) { - if(nullptr == state_.lister) + if (state_.lister) { - std::size_t orig_i = module_.index; - if(upwards) - { - if(module_.index && (module_.index < items_.size())) - -- module_.index; - else if(circle) - module_.index = items_.size() - 1; - } - else - { - if((module_.index + 1) < items_.size()) - ++ module_.index; - else if(circle) - module_.index = 0; - } - - if(orig_i != module_.index) - option(module_.index, false); + state_.lister->move_items(upwards, circle); + return; + } + + auto pos = module_.index; + if (upwards) + { + if (pos && (pos < items_.size())) + --pos; + else if (circle) + pos = items_.size() - 1; } else - state_.lister->move_items(upwards, circle); + { + if ((pos + 1) < items_.size()) + ++pos; + else if (circle) + pos = 0; + } + + if (pos != module_.index) + option(pos, false); } void draw() @@ -284,13 +296,6 @@ namespace nana _m_draw_image(); } - void draw_border(graph_reference graph, nana::color_t bgcolor) - { - graph.rectangle((state_.focused ? 0x0595E2 : 0x999A9E), false); - nana::rectangle r(graph.size()); - graph.rectangle(r.pare_off(1), bgcolor, false); - } - std::size_t the_number_of_options() const { return items_.size(); @@ -317,14 +322,13 @@ namespace nana { auto pos = API::cursor_position(); API::calc_window_point(widget_->handle(), pos); - if(calc_where(*graph_, pos.x, pos.y)) - state_.state = state_t::none; + if (calc_where(*graph_, pos.x, pos.y)) + state_.button_state = element_state::normal; editor_->text(items_[index]->item_text); _m_draw_push_button(widget_->enabled()); _m_draw_image(); - //Yes, it's safe to static_cast here! widget_->events().selected.emit(::nana::arg_combox(*widget_)); } } @@ -334,9 +338,8 @@ namespace nana std::size_t pos = 0; for (auto & m : items_) { - if (m->key && nana::detail::pred_equal_by_less(m->key.get(), p.get())) + if (m->key && detail::pred_equal_by_less(m->key.get(), p.get())) return pos; - ++pos; } @@ -350,16 +353,17 @@ namespace nana return pos; } - void erase(nana::detail::key_interface * kv) + void erase(detail::key_interface * kv) { - for (auto i = items_.begin(); i != items_.end(); ++i) + std::size_t pos = 0; + for (auto & m : items_) { - if ((*i)->key && nana::detail::pred_equal_by_less((*i)->key.get(), kv)) + if (m->key && detail::pred_equal_by_less(m->key.get(), kv)) { - std::size_t pos = i - items_.begin(); - this->erase(pos); + erase(pos); return; } + ++pos; } } @@ -375,28 +379,22 @@ namespace nana void erase(std::size_t pos) { - if (pos < items_.size()) + if (pos >= items_.size()) + return; + + if (pos == module_.index) { - if (pos == module_.index) - { - module_.index = nana::npos; - this->widget_->caption(L""); - } - else if ((nana::npos != module_.index) && (pos < module_.index)) - --module_.index; - - items_.erase(items_.begin() + pos); - - //Redraw, because the state of push button is changed when the last item is created. - if (items_.empty()) - API::refresh_window(*widget_); + module_.index = ::nana::npos; + this->widget_->caption(L""); } - } + else if ((::nana::npos != module_.index) && (pos < module_.index)) + --module_.index; - void text(nana::string&& str) - { - if (editor_) - editor_->text(std::move(str)); + items_.erase(items_.begin() + pos); + + //Redraw, because the state of push button is changed when the last item is removed. + if (items_.empty()) + API::refresh_window(*widget_); } void image(std::size_t pos, const nana::paint::image& img) @@ -414,12 +412,11 @@ namespace nana bool image_pixels(unsigned px) { - if(image_pixels_ != px) - { - image_pixels_ = px; - return true; - } - return false; + if (image_pixels_ == px) + return false; + + image_pixels_ = px; + return true; } private: void _m_lister_close_sig() @@ -439,69 +436,47 @@ namespace nana } } - void _m_draw_background(graph_reference graph, const nana::rectangle&, nana::color_t) + void _m_draw_background(graph_reference graph, const rectangle&, const ::nana::color&) { - nana::rectangle r(graph.size()); - nana::color_t color_start = color::button_face_shadow_start; - nana::color_t color_end = color::button_face_shadow_end; - if(state_.state == state_t::pressed) - { - r.pare_off(2); - std::swap(color_start, color_end); - } - else - r.pare_off(1); + auto clr_from = colors::button_face_shadow_start; + auto clr_to = colors::button_face_shadow_end; - graph.shadow_rectangle(r, color_start, color_end, true); + int pare_off_px = 1; + if (element_state::pressed == state_.button_state) + { + pare_off_px = 2; + std::swap(clr_from, clr_to); + } + + graph.gradual_rectangle(::nana::rectangle(graph.size()).pare_off(pare_off_px), clr_from, clr_to, true); } void _m_draw_push_button(bool enabled) { - using namespace nana::paint; + ::nana::rectangle r{graph_->size()}; + r.x = r.right() - 16; + r.y = 1; + r.width = 16; + r.height -= 2; - if (nullptr == graph_) return; - - int left = graph_->width() - 17; - int right = left + 16; - int top = 1; - int bottom = graph_->height() - 2; - int mid = top + (bottom - top) * 5 / 18; - - nana::color_t topcol, topcol_ln, botcol, botcol_ln; - nana::color_t arrow_color; - if (enabled && items_.size()) + auto estate = state_.button_state; + if (enabled && !items_.empty()) { - arrow_color = 0xFFFFFF; - double percent = 1; - if (has_lister() || (state_.state == state_t::pressed && state_.pointer_where == where_t::push_button)) - percent = 0.8; - else if (state_.state == state_t::mouse_over) - percent = 0.9; - - topcol_ln = graphics::mix(0x3F476C, 0xFFFFFF, percent); - botcol_ln = graphics::mix(0x031141, 0xFFFFFF, percent); - topcol = graphics::mix(0x3F83B4, 0xFFFFFF, percent); - botcol = graphics::mix(0x0C4A95, 0xFFFFFF, percent); + if (has_lister() || (element_state::pressed == estate && state_.pointer_where == parts::push_button)) + estate = element_state::pressed; } else - { - arrow_color = 0xFFFFFF; - topcol_ln = 0x7F7F7F; - botcol_ln = 0x505050; - topcol = 0xC3C3C3; - botcol = 0xA0A0A0; - } + estate = element_state::disabled; - graph_->line(left, top, left, mid, topcol_ln); - graph_->line(right - 1, top, right - 1, mid, topcol_ln); + facade button; + button.draw(*graph_, ::nana::color{ 3, 65, 140 }, colors::white, r, estate); - graph_->line(left, mid + 1, left, bottom, botcol_ln); - graph_->line(right - 1, mid + 1, right - 1, bottom, botcol_ln); + facade arrow("solid_triangle"); + arrow.direction(::nana::direction::south); - graph_->rectangle(left + 1, top, right - left - 2, mid - top + 1, topcol, true); - graph_->rectangle(left + 1, mid + 1, right - left - 2, bottom - mid, botcol, true); - - gadget::arrow_16_pixels(*graph_, left, top + ((bottom - top) / 2) - 7, arrow_color, 1, gadget::directions::to_south); + r.y += (r.height / 2) - 7; + r.width = r.height = 16; + arrow.draw(*graph_, {}, colors::white, r, element_state::normal); } void _m_draw_image() @@ -549,21 +524,21 @@ namespace nana img.stretch(img.size(), *graph_, nana::rectangle(pos, imgsz)); } private: - std::vector > items_; + std::vector> items_; nana::float_listbox::module_type module_; - ::nana::combox * widget_ = nullptr; - nana::paint::graphics * graph_ = nullptr; - drawerbase::float_listbox::item_renderer* item_renderer_ = nullptr; - - bool image_enabled_ = false; - unsigned image_pixels_ = 16; - widgets::skeletons::text_editor * editor_ = nullptr; + ::nana::combox * widget_{ nullptr }; + nana::paint::graphics * graph_{ nullptr }; + drawerbase::float_listbox::item_renderer* item_renderer_{ nullptr }; + bool image_enabled_{ false }; + unsigned image_pixels_{ 16 }; + widgets::skeletons::text_editor * editor_{ nullptr }; + std::unique_ptr evt_agent_; struct state_type { bool focused; - state_t state; - where_t pointer_where; + element_state button_state; + parts pointer_where; nana::float_listbox * lister; std::size_t item_index_before_selection; @@ -579,12 +554,6 @@ namespace nana trigger::~trigger() { delete drawer_; - drawer_ = nullptr; - } - - void trigger::set_accept(std::function&& pred) - { - pred_acceptive_ = std::move(pred); } drawer_impl& trigger::get_drawer_impl() @@ -599,7 +568,7 @@ namespace nana void trigger::attached(widget_reference wdg, graph_reference graph) { - wdg.background(0xFFFFFF); + wdg.bgcolor(colors::white); drawer_->attached(wdg, graph); API::effects_edge_nimbus(wdg, effects::edge_nimbus::active); @@ -655,8 +624,7 @@ namespace nana { auto * editor = drawer_->editor(); if(false == editor->mouse_down(arg.left_button, arg.pos)) - if(drawer_impl::where_t::push_button == drawer_->get_where()) - drawer_->open_lister(); + drawer_->open_lister_if_push_button_positioned(); drawer_->draw(); if(editor->attr().editable) @@ -668,15 +636,12 @@ namespace nana void trigger::mouse_up(graph_reference graph, const arg_mouse& arg) { - if(drawer_->widget_ptr()->enabled()) + if (drawer_->widget_ptr()->enabled() && !drawer_->has_lister()) { - if(false == drawer_->has_lister()) - { - drawer_->editor()->mouse_up(arg.left_button, arg.pos); - drawer_->set_mouse_press(false); - drawer_->draw(); - API::lazy_refresh(); - } + drawer_->editor()->mouse_up(arg.left_button, arg.pos); + drawer_->set_mouse_press(false); + drawer_->draw(); + API::lazy_refresh(); } } @@ -709,7 +674,7 @@ namespace nana void trigger::key_press(graph_reference, const arg_keyboard& arg) { - if(false == drawer_->widget_ptr()->enabled()) + if(!drawer_->widget_ptr()->enabled()) return; if(drawer_->editable()) @@ -748,8 +713,7 @@ namespace nana void trigger::key_char(graph_reference graph, const arg_keyboard& arg) { - bool enterable = drawer_->widget_ptr()->enabled() && (!pred_acceptive_ || pred_acceptive_(arg.key)); - if (drawer_->editor()->respone_keyboard(arg.key, enterable)) + if (drawer_->editor()->respone_keyboard(arg.key)) API::lazy_refresh(); } //end class trigger @@ -807,7 +771,7 @@ namespace nana { if (pos_ == nana::npos) return false; - return (impl_->at(pos_).item_text == static_cast(nana::charset(s))); + return (impl_->at(pos_).item_text == static_cast(nana::charset(s, nana::unicode::utf8))); } bool item_proxy::operator == (const wchar_t * s) const @@ -832,12 +796,11 @@ namespace nana /// Behavior of Iterator item_proxy & item_proxy::operator++() { - if (nana::npos == pos_) - return *this; - - if (++pos_ == impl_->the_number_of_options()) - pos_ = nana::npos; - + if (nana::npos != pos_) + { + if (++pos_ == impl_->the_number_of_options()) + pos_ = nana::npos; + } return *this; } @@ -906,10 +869,10 @@ namespace nana create(wd, rectangle(), visible); } - combox::combox(window wd, const nana::string& text, bool visible) + combox::combox(window wd, nana::string text, bool visible) { create(wd, rectangle(), visible); - caption(text); + caption(std::move(text)); } combox::combox(window wd, const nana::char_t* text, bool visible) @@ -925,69 +888,81 @@ namespace nana void combox::clear() { - internal_scope_guard sg; - get_drawer_trigger().get_drawer_impl().clear(); + internal_scope_guard lock; + _m_impl().clear(); API::refresh_window(handle()); } void combox::editable(bool eb) { - get_drawer_trigger().get_drawer_impl().editable(eb); + internal_scope_guard lock; + _m_impl().editable(eb); } bool combox::editable() const { - return get_drawer_trigger().get_drawer_impl().editable(); + internal_scope_guard lock; + return _m_impl().editable(); } void combox::set_accept(std::function pred) { internal_scope_guard lock; - get_drawer_trigger().set_accept(std::move(pred)); + auto editor = _m_impl().editor(); + if(editor) + editor->set_accept(std::move(pred)); } - combox& combox::push_back(const nana::string& text) + combox& combox::push_back(nana::string text) { - get_drawer_trigger().get_drawer_impl().insert(text); + internal_scope_guard lock; + _m_impl().insert(std::move(text)); return *this; } std::size_t combox::the_number_of_options() const { - return get_drawer_trigger().get_drawer_impl().the_number_of_options(); + internal_scope_guard lock; + return _m_impl().the_number_of_options(); } std::size_t combox::option() const { - return get_drawer_trigger().get_drawer_impl().option(); + internal_scope_guard lock; + return _m_impl().option(); } - void combox::option(std::size_t i) + void combox::option(std::size_t pos) { - get_drawer_trigger().get_drawer_impl().option(i, false); + internal_scope_guard lock; + _m_impl().option(pos, false); API::update_window(handle()); } - nana::string combox::text(std::size_t i) const + nana::string combox::text(std::size_t pos) const { - return get_drawer_trigger().get_drawer_impl().at(i).item_text; + internal_scope_guard lock; + return _m_impl().at(pos).item_text; } void combox::erase(std::size_t pos) { - get_drawer_trigger().get_drawer_impl().erase(pos); + internal_scope_guard lock; + _m_impl().erase(pos); } void combox::renderer(item_renderer* ir) { - get_drawer_trigger().get_drawer_impl().renderer(ir); + internal_scope_guard lock; + _m_impl().renderer(ir); } void combox::image(std::size_t i, const nana::paint::image& img) { + internal_scope_guard lock; if(empty()) return; - auto & impl = get_drawer_trigger().get_drawer_impl(); + auto & impl = _m_impl(); impl.image(i, img); if(i == impl.option()) API::refresh_window(*this); @@ -995,43 +970,62 @@ namespace nana nana::paint::image combox::image(std::size_t pos) const { - return get_drawer_trigger().get_drawer_impl().at(pos).item_image; + internal_scope_guard lock; + return _m_impl().at(pos).item_image; } void combox::image_pixels(unsigned px) { - if(get_drawer_trigger().get_drawer_impl().image_pixels(px)) + internal_scope_guard lock; + if (_m_impl().image_pixels(px)) API::refresh_window(*this); } nana::string combox::_m_caption() const { - internal_scope_guard isg; - auto editor = get_drawer_trigger().get_drawer_impl().editor(); + internal_scope_guard lock; + auto editor = _m_impl().editor(); return (editor ? editor->text() : nana::string()); } void combox::_m_caption(nana::string&& str) { - internal_scope_guard isg; - get_drawer_trigger().get_drawer_impl().text(std::move(str)); + internal_scope_guard lock; + + auto editor = _m_impl().editor(); + if (editor) + editor->text(std::move(str)); + API::refresh_window(*this); } nana::any * combox::_m_anyobj(std::size_t pos, bool alloc_if_empty) const { - return get_drawer_trigger().get_drawer_impl().anyobj(pos, alloc_if_empty); + internal_scope_guard lock; + return _m_impl().anyobj(pos, alloc_if_empty); } auto combox::_m_at_key(std::shared_ptr&& p) -> item_proxy { - auto & impl = get_drawer_trigger().get_drawer_impl(); + internal_scope_guard lock; + auto & impl = _m_impl(); return item_proxy(&impl, impl.at_key(std::move(p))); } void combox::_m_erase(nana::detail::key_interface* p) { - get_drawer_trigger().get_drawer_impl().erase(p); + internal_scope_guard lock; + _m_impl().erase(p); + } + + drawerbase::combox::drawer_impl & combox::_m_impl() + { + return get_drawer_trigger().get_drawer_impl(); + } + + const drawerbase::combox::drawer_impl& combox::_m_impl() const + { + return get_drawer_trigger().get_drawer_impl(); } //end class combox } diff --git a/source/gui/widgets/date_chooser.cpp b/source/gui/widgets/date_chooser.cpp index 52ec5708..bb0cede5 100644 --- a/source/gui/widgets/date_chooser.cpp +++ b/source/gui/widgets/date_chooser.cpp @@ -1,6 +1,7 @@ /* * A date chooser Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -10,6 +11,7 @@ */ #include +#include #include #include #include @@ -26,15 +28,17 @@ namespace nana : widget_(nullptr), chose_(false), page_(page::date), pos_(where::none) { const nana::string ws[] = {STR("S"), STR("M"), STR("T"), STR("W"), STR("T"), STR("F"), STR("S")}; - const nana::string ms[] = {STR("January"), STR("February"), STR("March"), STR("April"), STR("May"), STR("June"), STR("July"), STR("August"), STR("September"), STR("October"), STR("November"), STR("December")}; - for(int i = 0; i < 7; ++i) weekstr_[i] = ws[i]; - for(int i = 0; i < 12; ++i) monthstr_[i] = ms[i]; nana::date d; chdate_.year = chmonth_.year = d.read().year; chdate_.month = chmonth_.month = d.read().month; chdate_.day = d.read().day; + + color_.selected = { 0x2F, 0x36, 0x99 }; + color_.highlight = { 0x4D, 0x56, 0xC8 }; + color_.normal = colors::black; + color_.bgcolor = { 0x88, 0xC4, 0xFF }; } bool trigger::chose() const @@ -49,43 +53,28 @@ namespace nana void trigger::week_name(unsigned index, const nana::string& str) { - if(0 <= index && index < 7) + if(index < 7) this->weekstr_[index] = str; } - void trigger::month_name(unsigned index, const nana::string& str) - { - if(0 <= index && index < 12) - this->monthstr_[index] = str; - } - - void trigger::_m_init_color() - { - color_.selected = 0x2F3699; - color_.highlight = 0x4D56C8; - color_.normal = 0x0; - color_.bkcolor = 0x88C4FF; - } - - trigger::where trigger::_m_pos_where(graph_reference graph, int x, int y) + trigger::where trigger::_m_pos_where(graph_reference graph, const ::nana::point& pos) { int xend = static_cast(graph.width()) - 1; int yend = static_cast(graph.height()) - 1; - if(0 < y && y < static_cast(topbar_height)) + if(0 < pos.y && pos.y < static_cast(topbar_height)) { - if(static_cast(border_size) < x && x < xend) + if(static_cast(border_size) < pos.x && pos.x < xend) { - if(x < border_size + 16) + if(pos.x < border_size + 16) return where::left_button; - else if(xend - border_size - 16 < x) + else if(xend - border_size - 16 < pos.x) return where::right_button; return where::topbar; } } - else if(topbar_height < y && y < yend) + else if(topbar_height < pos.y && pos.y < yend) { - trace_pos_.x = x; - trace_pos_.y = y; + trace_pos_ = pos; return where::textarea; } return where::none; @@ -93,12 +82,10 @@ namespace nana void trigger::_m_draw(graph_reference graph) { - _m_init_color(); - const unsigned width = graph.width() - 2; - graph.rectangle(0xB0B0B0, false); - graph.rectangle(1, 1, width, topbar_height, 0xFFFFFF, true); + graph.rectangle(false, {0xb0, 0xb0, 0xb0}); + graph.rectangle({ 1, 1, width, static_cast(topbar_height) }, true, colors::white); _m_draw_topbar(graph); @@ -106,8 +93,8 @@ namespace nana { nana::point refpos(1, static_cast(topbar_height) + 1); - nana::paint::graphics gbuf(width, graph.height() - 2 - topbar_height); - gbuf.rectangle(0xF0F0F0, true); + nana::paint::graphics gbuf({ width, graph.height() - 2 - topbar_height }); + gbuf.rectangle(true, {0xf0, 0xf0, 0xf0}); switch(page_) { @@ -126,12 +113,17 @@ namespace nana void trigger::_m_draw_topbar(graph_reference graph) { - int ypos = (topbar_height - 16) / 2 + 1; + ::nana::color arrow_bgcolor; + ::nana::rectangle arrow_r{ static_cast(border_size), (topbar_height - 16) / 2 + 1, 16, 16 }; + facade arrow("solid_triangle"); + arrow.direction(::nana::direction::west); + arrow.draw(graph, arrow_bgcolor, (pos_ == where::left_button ? color_.highlight : color_.normal), arrow_r, element_state::normal); - const nana::color_t color = color_.normal; - - nana::paint::gadget::arrow_16_pixels(graph, border_size, ypos, (pos_ == where::left_button ? color_.highlight : color), 1, nana::paint::gadget::directions::to_west); - nana::paint::gadget::arrow_16_pixels(graph, graph.width() - (border_size + 16 + 1), ypos, (pos_ == where::right_button ? color_.highlight : color), 1, nana::paint::gadget::directions::to_east); + arrow_r.x = static_cast(graph.width()) - static_cast(border_size + 17); + arrow.direction(::nana::direction::east); + arrow.draw(graph, arrow_bgcolor, (pos_ == where::right_button ? color_.highlight : color_.normal), arrow_r, element_state::normal); + + const char * monthstr[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; if(graph.width() > 32 + border_size * 2) { @@ -140,19 +132,19 @@ namespace nana nana::string str; if(page_ == page::date) { - str += monthstr_[chmonth_.month - 1]; + str += ::nana::internationalization()(monthstr[chmonth_.month - 1]); str += STR(" "); } str += nana::charset(ss.str()); nana::size txt_s = graph.text_extent_size(str); - ypos = (topbar_height - txt_s.height) / 2 + 1; + int top = (topbar_height - static_cast(txt_s.height)) / 2 + 1; - int xpos = (graph.width() - txt_s.width) / 2; + int xpos = static_cast(graph.width() - txt_s.width) / 2; if(xpos < border_size + 16) xpos = 16 + border_size + 1; - graph.string(xpos, ypos, (pos_ == where::topbar ? color_.highlight : color), str); + graph.string({ xpos, top }, str, (pos_ == where::topbar ? color_.highlight : color_.normal)); } } @@ -181,9 +173,8 @@ namespace nana nana::rectangle r(static_cast(x * dbasis.row_s), static_cast(y * dbasis.line_s), static_cast(dbasis.row_s), static_cast(dbasis.line_s)); - nana::color_t color{ color_.normal }; - - nana::point tpos{ trace_pos_ - dbasis.refpos }; + auto color = color_.normal; + auto tpos = trace_pos_ - dbasis.refpos; if((pos_ == where::textarea) && (r.x <= tpos.x) @@ -194,22 +185,22 @@ namespace nana if((page_ != page::date) || y) { color = color_.highlight; - graph.rectangle(r, color_.bkcolor, true); + graph.rectangle(r, true, color_.bgcolor); } } if(sel) { color = color_.highlight; - graph.rectangle(r, color_.bkcolor, true); - graph.rectangle(r, color_.selected, false); + graph.rectangle(r, true, color_.bgcolor); + graph.rectangle(r, false, color_.selected); } - if(primary == false) - color = 0xB0B0B0; + if(false == primary) + color = { 0xB0, 0xB0, 0xB0 }; nana::size txt_s = graph.text_extent_size(str); - graph.string(r.x + static_cast(r.width - txt_s.width) / 2, r.y + static_cast(r.height - txt_s.height) / 2, color, str); + graph.string({ r.x + static_cast(r.width - txt_s.width) / 2, r.y + static_cast(r.height - txt_s.height) / 2 }, str, color); } void trigger::_m_draw_pos(drawing_basis & dbasis, graph_reference graph, int x, int y, int number, bool primary, bool sel) @@ -315,11 +306,13 @@ namespace nana drawing_basis dbasis; _m_make_drawing_basis(dbasis, graph, refpos); + const char * monthstr[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; + ::nana::internationalization i18n; for(int y = 0; y < 3; ++y) for(int x = 0; x < 4; ++x) { int index = x + y * 4; - _m_draw_pos(dbasis, graph, x, y, monthstr_[index], true, (chmonth_.year == chdate_.year) && (index + 1 == chdate_.month)); + _m_draw_pos(dbasis, graph, x, y, i18n(monthstr[index]), true, (chmonth_.year == chdate_.year) && (index + 1 == chdate_.month)); } } @@ -417,7 +410,7 @@ namespace nana r.x = static_cast(newbuf.width() - r.width) / 2; r.y = static_cast(newbuf.height() - r.height) / 2; - dzbuf.rectangle(0xFFFFFF, true); + dzbuf.rectangle(true, colors::white); dirtybuf.stretch(dzbuf, r); r.width = static_cast(newbuf.width() + delta * (count - i)); @@ -451,7 +444,7 @@ namespace nana r.height = static_cast(newbuf.height() - delta_h * (count - i)); r.x = static_cast(newbuf.width() - r.width) / 2; r.y = static_cast(newbuf.height() - r.height) / 2; - nzbuf.rectangle(0xFFFFFF, true); + nzbuf.rectangle(true, colors::white); newbuf.stretch(nzbuf, r); nzbuf.blend(nzbuf.size(), dzbuf, nana::point(), fade * (count - i)); @@ -477,7 +470,7 @@ namespace nana void trigger::mouse_move(graph_reference graph, const arg_mouse& arg) { - where pos = _m_pos_where(graph, arg.pos.x, arg.pos.y); + where pos = _m_pos_where(graph, arg.pos); if(pos == pos_ && pos_ != where::textarea) return; pos_ = pos; _m_draw(graph); @@ -495,7 +488,7 @@ namespace nana void trigger::mouse_up(graph_reference graph, const arg_mouse& arg) { bool redraw = true; - where pos = _m_pos_where(graph, arg.pos.x, arg.pos.y); + where pos = _m_pos_where(graph, arg.pos); transform_action tfid = transform_action::none; if(pos == where::topbar) @@ -604,12 +597,12 @@ namespace nana nana::point refpos(1, static_cast(topbar_height) + 1); nana::rectangle r(0, 0, graph.width() - 2, graph.height() - 2 - topbar_height); - nana::paint::graphics dirtybuf(r.width, r.height); + nana::paint::graphics dirtybuf({ r.width, r.height }); dirtybuf.bitblt(r, graph, refpos); _m_draw(graph); - nana::paint::graphics gbuf(r.width, r.height); + nana::paint::graphics gbuf({ r.width, r.height }); gbuf.bitblt(r, graph, refpos); _m_perf_transform(tfid, graph, dirtybuf, gbuf, refpos); @@ -665,11 +658,5 @@ namespace nana get_drawer_trigger().week_name(index, str); API::refresh_window(*this); } - - void date_chooser::monthstr(unsigned index, const nana::string& str) - { - get_drawer_trigger().month_name(index, str); - API::refresh_window(*this); - } //end class date_chooser }//end namespace nana diff --git a/source/gui/widgets/float_listbox.cpp b/source/gui/widgets/float_listbox.cpp index d1ca8171..3f569aee 100644 --- a/source/gui/widgets/float_listbox.cpp +++ b/source/gui/widgets/float_listbox.cpp @@ -1,7 +1,7 @@ /* * A float_listbox Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -18,10 +18,6 @@ namespace nana namespace drawerbase{ namespace float_listbox { - //class item_renderer - item_renderer::~item_renderer(){} - //end class item_renderer - class def_item_renderer : public item_renderer { @@ -36,26 +32,29 @@ namespace nana void render(widget_reference, graph_reference graph, const nana::rectangle& r, const item_interface* item, state_t state) { - if(state == StateHighlighted) + if (state == StateHighlighted) { - graph.rectangle(r, 0xAFC7E3, false); + ::nana::color clr{ 0xaf, 0xc7, 0xe3 }; + graph.rectangle(r, false, clr); - graph.set_pixel(r.x, r.y, 0xFFFFFF); - graph.set_pixel(r.x + r.width - 1, r.y, 0xFFFFFF); - graph.set_pixel(r.x, r.y + r.height - 1, 0xFFFFFF); - graph.set_pixel(r.x + r.width - 1, r.y + r.height - 1, 0xFFFFFF); + graph.set_color(colors::white); + graph.set_pixel(r.x, r.y); + graph.set_pixel(r.x + r.width - 1, r.y); + graph.set_pixel(r.x, r.y + r.height - 1); + graph.set_pixel(r.x + r.width - 1, r.y + r.height - 1); - graph.set_pixel(r.x + 1, r.y + 1, 0xAFC7E3); - graph.set_pixel(r.x + r.width - 2, r.y + 1, 0xAFC7E3); - graph.set_pixel(r.x + 1, r.y + r.height - 2, 0xAFC7E3); - graph.set_pixel(r.x + r.width - 2, r.y + r.height - 2, 0xAFC7E3); + graph.set_color(clr); + graph.set_pixel(r.x + 1, r.y + 1); + graph.set_pixel(r.x + r.width - 2, r.y + 1); + graph.set_pixel(r.x + 1, r.y + r.height - 2); + graph.set_pixel(r.x + r.width - 2, r.y + r.height - 2); nana::rectangle po_r(r); - graph.rectangle(po_r.pare_off(1), 0xEBF4FB, false); - graph.shadow_rectangle(po_r.pare_off(1), 0xDDECFD, 0xC2DCFD, true); + graph.rectangle(po_r.pare_off(1), false, { 0xEB, 0xF4, 0xFB }); + graph.gradual_rectangle(po_r.pare_off(1), { 0xDD, 0xEC, 0xFD }, { 0xC2, 0xDC, 0xFD }, true); } else - graph.rectangle(r, 0xFFFFFF, true); + graph.rectangle(r, true, colors::white); int x = r.x + 2; if(image_enabled_) @@ -100,7 +99,8 @@ namespace nana } x += (image_pixels_ + 2); } - graph.string(x, r.y + 2, 0x0, item->text()); + graph.set_text_color(colors::black); + graph.string({ x, r.y + 2 }, item->text()); } unsigned item_pixels(graph_reference graph) const @@ -109,12 +109,6 @@ namespace nana } };//end class item_renderer - //struct module_def - module_def::module_def() - :max_items(10), index(npos) - {} - //end struct module_def - //class drawer_impl class drawer_impl { @@ -248,7 +242,7 @@ namespace nana if(wd) { widget_ = wd; - wd->events().mouse_wheel.connect([this](const arg_wheel& arg){ + wd->events().mouse_wheel.connect_unignorable([this](const arg_wheel& arg){ scroll_items(arg.upwards); }); } @@ -339,11 +333,11 @@ namespace nana _m_open_scrollbar(*widget_, pages); } else - graph_->string(4, 4, 0x808080, STR("Empty Listbox, No Module!")); + graph_->string({ 4, 4 }, STR("Empty Listbox, No Module!"), {0x80, 0x80, 0x80}); //Draw border - graph_->rectangle(0x0, false); - graph_->rectangle(nana::rectangle(graph_->size()).pare_off(1), 0xFFFFFF, false); + graph_->rectangle(false, colors::black); + graph_->rectangle(nana::rectangle(graph_->size()).pare_off(1), false, colors::white); } private: bool _m_image_enabled() const diff --git a/source/gui/widgets/form.cpp b/source/gui/widgets/form.cpp index 823e47e7..0c8cfc43 100644 --- a/source/gui/widgets/form.cpp +++ b/source/gui/widgets/form.cpp @@ -18,8 +18,6 @@ namespace nana namespace form { //class trigger - trigger::trigger():wd_(nullptr){} - void trigger::attached(widget_reference widget, graph_reference graph) { wd_ = &widget; @@ -27,13 +25,7 @@ namespace nana void trigger::refresh(graph_reference graph) { - graph.rectangle(API::background(*wd_), true); - } - - void trigger::resized(graph_reference graph, const arg_resized&) - { - graph.rectangle(API::background(*wd_), true); - API::lazy_refresh(); + graph.rectangle(true, API::bgcolor(*wd_)); } }//end namespace form }//end namespace drawerbase @@ -57,6 +49,16 @@ namespace nana form::form(window owner, const rectangle& r, const appearance& apr) : form_base_t(owner, false, r, apr) {} + + void form::modality() const + { + API::modal_window(handle()); + } + + void form::wait_for_this() + { + API::wait_for(handle()); + } //end class form //class nested_form diff --git a/source/gui/widgets/label.cpp b/source/gui/widgets/label.cpp index 686596ff..8c534c67 100644 --- a/source/gui/widgets/label.cpp +++ b/source/gui/widgets/label.cpp @@ -74,7 +74,7 @@ namespace nana return true; } - void render(graph_reference graph, nana::color_t fgcolor, align th, align_v tv) + void render(graph_reference graph, const ::nana::color& fgcolor, align th, align_v tv) { traceable_.clear(); @@ -161,18 +161,18 @@ namespace nana return false; } - nana::size measure(graph_reference graph, unsigned limited, align th, align_v tv) + ::nana::size measure(graph_reference graph, unsigned limited, align th, align_v tv) { - nana::size retsize; + ::nana::size retsize; - nana::paint::font ft = graph.typeface(); //used for restoring the font + auto ft = graph.typeface(); //used for restoring the font const unsigned def_line_pixels = graph.text_extent_size(STR(" "), 1).height; font_ = ft; fblock_ = nullptr; - _m_set_default(ft, 0); + _m_set_default(ft, colors::black); _m_measure(graph); render_status rs; @@ -216,7 +216,7 @@ namespace nana } } - void _m_set_default(const nana::paint::font& ft, nana::color_t fgcolor) + void _m_set_default(const ::nana::paint::font& ft, const ::nana::color& fgcolor) { def_.font_name = ft.name(); def_.font_size = ft.size(); @@ -224,9 +224,9 @@ namespace nana def_.fgcolor = fgcolor; } - nana::color_t _m_fgcolor(nana::widgets::skeletons::fblock* fp) + const ::nana::color& _m_fgcolor(nana::widgets::skeletons::fblock* fp) { - while(fp->fgcolor == 0xFFFFFFFF) + while(fp->fgcolor.invisible()) { fp = fp->parent; if(nullptr == fp) @@ -562,12 +562,12 @@ namespace nana if (text_range.second == data_ptr->text().length()) { - graph.string(rs.pos.x, y, _m_fgcolor(fblock_ptr), data_ptr->text()); + graph.string({ rs.pos.x, y }, data_ptr->text(), _m_fgcolor(fblock_ptr)); } else { nana::string str = data_ptr->text().substr(text_range.first, text_range.second); - graph.string(rs.pos.x, y, _m_fgcolor(fblock_ptr), str); + graph.string({ rs.pos.x, y }, str, _m_fgcolor(fblock_ptr)); sz = graph.text_extent_size(str); } _m_inser_if_traceable(rs.pos.x, y, sz, fblock_ptr); @@ -600,16 +600,16 @@ namespace nana private: dstream dstream_; bool format_enabled_ = false; - nana::widgets::skeletons::fblock * fblock_ = nullptr; + ::nana::widgets::skeletons::fblock * fblock_ = nullptr; std::deque traceable_; - nana::paint::font font_; + ::nana::paint::font font_; struct def_font_tag { - nana::string font_name; + ::nana::string font_name; std::size_t font_size; bool font_bold; - nana::color_t fgcolor; + ::nana::color fgcolor; }def_; }; @@ -748,9 +748,9 @@ namespace nana window wd = impl_->wd->handle(); if(bground_mode::basic != API::effects_bground_mode(wd)) - graph.rectangle(API::background(wd), true); + graph.rectangle(true, API::bgcolor(wd)); - impl_->renderer.render(graph, impl_->wd->foreground(), impl_->text_align, impl_->text_align_v); + impl_->renderer.render(graph, API::fgcolor(wd), impl_->text_align, impl_->text_align_v); } //end class label_drawer @@ -831,12 +831,20 @@ namespace nana if(graph_ptr->empty()) { graph_ptr = &substitute; - graph_ptr->make(10, 10); + graph_ptr->make({ 10, 10 }); } return impl->renderer.measure(*graph_ptr, limited, impl->text_align, impl->text_align_v); } + ::nana::size label::measure(paint::graphics& graph, const ::nana::string& str, unsigned allowed_width_in_pixel, bool format_enabled, align h_align, align_v v_align) + { + drawerbase::label::renderer rd; + rd.format(format_enabled); + rd.parse(str); + return rd.measure(graph, allowed_width_in_pixel, h_align, v_align); + } + label& label::text_align(align th, align_v tv) { internal_scope_guard isg; diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index fb37ecb8..6d9b2650 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1,7 +1,7 @@ /* * A List Box Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -28,7 +28,7 @@ namespace nana namespace listbox { //struct cell - cell::format::format(color_t bgcolor, color_t fgcolor) + cell::format::format(const ::nana::color& bgcolor, const ::nana::color& fgcolor) : bgcolor{ bgcolor }, fgcolor{ fgcolor } {} @@ -53,7 +53,7 @@ namespace nana custom_format(new format{ fmt }) //make_unique {} - cell::cell(nana::string text, color_t bgcolor, color_t fgcolor) + cell::cell(nana::string text, const ::nana::color& bgcolor, const ::nana::color& fgcolor) : text(std::move(text)), custom_format{ new format{ bgcolor, fgcolor } } //make_unique {} @@ -476,35 +476,22 @@ namespace nana return npos; } - bool item_pos(size_type index, int& xpos, unsigned& pixels) const + int item_pos(size_type pos, unsigned * pixels) const { - xpos = 0; - for(auto & m : cont_) + int left = 0; + for (auto & m : cont_) { - if(m.index == index) + if (m.index == pos) { - pixels = m.pixels; - return true; - } - - if(m.visible) - xpos += m.pixels; - } - return true; - } - - int xpos(size_type index) const - { - int x = 0; - for(auto & m : cont_) - { - if(m.index == index) + if (pixels) + *pixels = m.pixels; break; - - if(m.visible) - x += m.pixels; + } + + if (m.visible) + left += m.pixels; } - return x; + return left; } size_type neighbor(size_type index, bool front) const @@ -549,18 +536,17 @@ namespace nana { if((index != to) && (index < cont_.size()) && (to < cont_.size())) { - column_t from; - for(auto i = cont_.begin();i != cont_.end(); ++i) - { - if(index == i->index) - { - from = *i; - cont_.erase(i); - break; - } - } + auto i = std::find_if(cont_.begin(), cont_.end(), [index](container::value_type& m){ + return (index == m.index); + }); - auto i = std::find_if(cont_.begin(), cont_.end(), [to](const container::value_type& m)->bool{ return (to == m.index); } ); + if (i == cont_.end()) + return; + + auto from = *i; + cont_.erase(i); + + i = std::find_if(cont_.begin(), cont_.end(), [to](const container::value_type& m)->bool{ return (to == m.index); } ); if(i != cont_.end()) cont_.insert((front ? i : ++i), from); } @@ -577,8 +563,8 @@ namespace nana typedef std::vector container; container cells; - color_t bgcolor{0xFF000000}; - color_t fgcolor{0xFF000000}; + nana::color bgcolor; + nana::color fgcolor; paint::image img; nana::size img_show_size; @@ -616,7 +602,7 @@ namespace nana cells.emplace_back(std::move(s)); } - item_t(nana::string&& s, color_t bg, color_t fg) + item_t(nana::string&& s, const nana::color& bg, const nana::color& fg) : bgcolor(bg), fgcolor(fg) { @@ -1400,6 +1386,173 @@ namespace nana } } + + void cancel_others_if_single_enabled(bool for_selection, const index_pair& except) + { + if (!(for_selection ? single_selection_ : single_check_)) + return; + + auto pred = [for_selection](category_t::container::value_type & m){ + return (for_selection ? m.flags.selected : m.flags.checked); + }; + + auto do_cancel = [this, for_selection](category_t::container::value_type& m, std::size_t cat_pos, std::size_t item_pos) + { + arg_listbox arg{ item_proxy(ess_, index_pair(cat_pos, item_pos)), false }; + if (for_selection) + { + m.flags.selected = false; + widget_->events().selected.emit(arg); + } + else + { + m.flags.checked = false; + widget_->events().checked.emit(arg); + } + }; + + if (for_selection ? single_selection_category_limited_ : single_check_category_limited_) + { + auto i = list_.begin(); + std::advance(i, except.cat); + + std::size_t item_pos = 0; + for (auto & m : i->items) + { + if ((item_pos != except.item) && pred(m)) + do_cancel(m, except.cat, item_pos); + + ++item_pos; + } + } + else + { + std::size_t cat_pos = 0; + for (auto & cat : list_) + { + if (cat_pos != except.cat) + { + std::size_t item_pos = 0; + for (auto & m : cat.items) + { + if (pred(m)) + do_cancel(m, cat_pos, item_pos); + ++item_pos; + } + } + else + { + std::size_t item_pos = 0; + for (auto & m : cat.items) + { + if ((item_pos != except.item) && pred(m)) + do_cancel(m, cat_pos, item_pos); + ++item_pos; + } + } + ++cat_pos; + } + } + } + + bool single_selection() const + { + return single_selection_; + } + + bool single_check() const + { + return single_check_; + } + + void enable_single(bool for_selection, bool category_limited) + { + bool & single = (for_selection ? single_selection_ : single_check_); + bool & limited = (for_selection ? single_selection_category_limited_ : single_check_category_limited_); + + if (single && (limited == category_limited)) + return; + + single = true; + limited = category_limited; + + auto pred = [for_selection](category_t::container::value_type & m){ + return (for_selection ? m.flags.selected : m.flags.checked); + }; + + auto cancel = [this, for_selection](category_t::container::value_type& m, std::size_t cat_pos, std::size_t item_pos) + { + arg_listbox arg{ item_proxy(ess_, index_pair(cat_pos, item_pos)), false }; + if (for_selection) + { + m.flags.selected = false; + widget_->events().selected.emit(arg); + } + else + { + m.flags.checked = false; + widget_->events().checked.emit(arg); + } + }; + + std::size_t cat_pos = 0; + if (category_limited) + { + for (auto & cat : list_) + { + auto i = std::find_if(cat.items.begin(), cat.items.end(), pred); + if (i != cat.items.end()) + { + ++i; + for (auto end = cat.items.end(); i != end; ++i) + { + if (pred(*i)) + cancel(*i, cat_pos, i - cat.items.begin()); + } + } + ++cat_pos; + } + } + else + { + bool selected = false; + for (auto & cat : list_) + { + if (!selected) + { + auto i = std::find_if(cat.items.begin(), cat.items.end(), pred); + if (i != cat.items.end()) + { + selected = true; + ++i; + for (auto end = cat.items.end(); i != end; ++i) + { + if (pred(*i)) + cancel(*i, cat_pos, i - cat.items.begin()); + } + } + } + else + { + std::size_t item_pos = 0; + for (auto & m : cat.items) + { + if (pred(m)) + cancel(m, cat_pos, item_pos); + + ++item_pos; + } + } + ++cat_pos; + } + } + } + + void disable_single(bool for_selection) + { + (for_selection ? single_selection_ : single_check_) = false; + } + size_type size_categ() const { return list_.size(); @@ -1686,6 +1839,11 @@ namespace nana bool ordered_categories_{false}; //A switch indicates whether the categories are ordered. //The ordered categories always creates a new category at a proper position(before the first one which is larger than it). container list_; + + bool single_selection_{ false }; + bool single_selection_category_limited_{ false }; + bool single_check_{ false }; + bool single_check_category_limited_{ false }; };//end class es_lister //struct essence_t @@ -1693,10 +1851,11 @@ namespace nana // the state of the struct does not effect on member funcions, therefore all data members are public. struct essence_t { - enum class state_t{normal, highlighted, pressed, grabed, floated}; - enum class where_t{unknown = -1, header, lister, checker}; + enum class item_state{normal, highlighted, pressed, grabbed, floated}; + enum class parts{unknown = -1, header, lister, checker}; - nana::paint::graphics *graph{nullptr}; + ::nana::listbox::scheme_type* scheme_ptr{nullptr}; + ::nana::paint::graphics *graph{nullptr}; bool auto_draw{true}; bool checkable{false}; bool if_image{false}; @@ -1708,8 +1867,8 @@ namespace nana es_header header; es_lister lister; // we have at least one emty cat. the #0 - state_t ptr_state{ state_t::normal }; - std::pair pointer_where; //The 'first' stands for which object, such as header and lister, 'second' stands for item + item_state ptr_state{ item_state::normal }; + std::pair pointer_where; //The 'first' stands for which object, such as header and lister, 'second' stands for item //if where == header, 'second' indicates the item //if where == lister || where == checker, 'second' indicates the offset to the scroll offset_y which stands for the first item displayed in lister. //if where == unknown, 'second' ignored. @@ -1727,7 +1886,7 @@ namespace nana essence_t() { scroll.offset_x = 0; - pointer_where.first = where_t::unknown; + pointer_where.first = parts::unknown; lister.fetch_ordering_comparer = std::bind(&es_header::fetch_comp, &header, std::placeholders::_1); } @@ -1800,12 +1959,6 @@ namespace nana adjust_scroll_value(); } - //Keep the LAST(first) selected item in the display area - void trace_last_selected_item() - { - - } - void update() { if(auto_draw && lister.wd_ptr()) @@ -1867,10 +2020,10 @@ namespace nana { scroll.h.create(wd, r); API::take_active(scroll.h.handle(), false, wd); - scroll.h.events().mouse_move.connect([this](const nana::arg_mouse& arg){ + scroll.h.events().mouse_move.connect_unignorable([this](const nana::arg_mouse& arg){ _m_answer_scroll(arg); }); - scroll.h.events().mouse_up.connect([this](const nana::arg_mouse& arg){ + scroll.h.events().mouse_up.connect_unignorable([this](const nana::arg_mouse& arg){ _m_answer_scroll(arg); }); } @@ -1887,12 +2040,12 @@ namespace nana { scroll.v.create(wd, r); API::take_active(scroll.v.handle(), false, wd); - scroll.v.events().mouse_move.connect([this](const ::nana::arg_mouse& arg) + scroll.v.events().mouse_move.connect_unignorable([this](const ::nana::arg_mouse& arg) { _m_answer_scroll(arg); }); - scroll.v.events().mouse_up.connect([this](const ::nana::arg_mouse& arg) + scroll.v.events().mouse_up.connect_unignorable([this](const ::nana::arg_mouse& arg) { _m_answer_scroll(arg); }); @@ -1943,7 +2096,7 @@ namespace nana { std::vector seq; header_seq(seq, r.width); - return (seq.size() ? (header.xpos(seq[0]) - scroll.offset_x + r.x) : 0); + return (seq.size() ? (header.item_pos(seq[0], nullptr) - scroll.offset_x + r.x) : 0); } bool calc_where(int x, int y) @@ -1955,13 +2108,13 @@ namespace nana if(header.visible() && y < static_cast(header_size + 1)) { x -= (2 - scroll.offset_x); - new_where.first = where_t::header; + new_where.first = parts::header; new_where.second = static_cast(header.item_by_x(x)); } else { new_where.second = (y - header_visible_px() + 1) / item_size; - new_where.first = where_t::lister; + new_where.first = parts::lister; if(checkable) { nana::rectangle r; @@ -1969,23 +2122,22 @@ namespace nana { std::size_t top = new_where.second * item_size + header_visible_px(); if(checkarea(item_xpos(r), static_cast(top)).is_hit(x, y)) - new_where.first = where_t::checker; + new_where.first = parts::checker; } } } } else { - new_where.first = where_t::unknown; + new_where.first = parts::unknown; new_where.second = npos; } - if(new_where != pointer_where) - { - pointer_where = new_where; - return true; - } - return false; + if (new_where == pointer_where) + return false; + + pointer_where = new_where; + return true; } void widget_to_header(nana::point& pos) @@ -2053,22 +2205,20 @@ namespace nana bool wheel(bool upwards) { - index_pair target; - if(scroll.v.empty() || !scroll.v.scrollable(upwards)) return false; + index_pair target; if(upwards == false) lister.forward(scroll.offset_y, 1, target); else lister.backward(scroll.offset_y, 1, target); - if (target != scroll.offset_y) - { - scroll.offset_y = target; - return true; - } - return false; + if (target == scroll.offset_y) + return false; + + scroll.offset_y = target; + return true; } void header_seq(std::vector &seqs, unsigned lister_w)const @@ -2119,7 +2269,9 @@ namespace nana class drawer_header_impl { public: - typedef nana::paint::graphics & graph_reference; + using graph_reference = nana::paint::graphics&; + using item_state = essence_t::item_state; + using parts = essence_t::parts; drawer_header_impl(essence_t* es): essence_(es){} @@ -2135,7 +2287,7 @@ namespace nana bool mouse_spliter(const nana::rectangle& r, int x) { - if(essence_->ptr_state == essence_t::state_t::highlighted) + if(essence_->ptr_state == item_state::highlighted) { x -= (r.x - essence_->scroll.offset_x); for(auto & hd : essence_->header.cont()) @@ -2151,7 +2303,7 @@ namespace nana } } } - else if(essence_->ptr_state == essence_t::state_t::normal) + else if(essence_->ptr_state == item_state::normal) item_spliter_ = npos; return false; } @@ -2207,9 +2359,14 @@ namespace nana _m_draw(essence_->header.cont(), r); const int y = r.y + r.height - 1; - essence_->graph->line(r.x, y, r.x + r.width, y, 0xDEDFE1); + essence_->graph->line({ r.x, y }, { r.x + static_cast(r.width), y }, _m_border_color()); } private: + ::nana::color _m_border_color() const + { + return essence_->scheme_ptr->header_bgcolor.get_color().blend(colors::black, 0.8); + } + size_type _m_target_strip(int x, const nana::rectangle& rect, size_type grab, bool& place_front) { //convert x to header logic coordinate. @@ -2221,24 +2378,23 @@ namespace nana size_type i = essence_->header.item_by_x(x); if(i == npos) { - i = (essence_->header.xpos(grab) < x ? essence_->header.last() : essence_->header.begin()); + i = (essence_->header.item_pos(grab, nullptr) < x ? essence_->header.last() : essence_->header.begin()); } if(grab != i) { - int item_xpos; - unsigned item_pixels; - if(essence_->header.item_pos(i, item_xpos, item_pixels)) - { - int midpos = item_xpos + static_cast(item_pixels / 2); + unsigned item_pixels = 0; + auto item_x = essence_->header.item_pos(i, &item_pixels); + + int midpos = item_x + static_cast(item_pixels / 2); - //Get the item pos - //if mouse pos is at left of an item middle, the pos of itself otherwise the pos of the next. - place_front = (x <= midpos); - x = (place_front ? item_xpos : essence_->header.xpos(essence_->header.neighbor(i, false))); + //Get the item pos + //if mouse pos is at left of an item middle, the pos of itself otherwise the pos of the next. + place_front = (x <= midpos); + x = (place_front ? item_x : essence_->header.item_pos(essence_->header.neighbor(i, false), nullptr)); + + if(i != npos) + essence_->graph->rectangle({ x - essence_->scroll.offset_x + rect.x, rect.y, 2, rect.height }, true, colors::red); - if(i != npos) - essence_->graph->rectangle(x - essence_->scroll.offset_x + rect.x, rect.y, 2, rect.height, 0xFF0000, true); - } return i; } return npos; @@ -2248,18 +2404,19 @@ namespace nana void _m_draw(const Container& cont, const nana::rectangle& rect) { graph_reference graph = *(essence_->graph); - int x = rect.x - essence_->scroll.offset_x; - unsigned height = rect.height - 1; + int txtop = (rect.height - essence_->text_height) / 2 + rect.y; - nana::color_t txtcolor = essence_->lister.wd_ptr()->foreground(); + auto txtcolor = essence_->lister.wd_ptr()->fgcolor(); - auto state = essence_t::state_t::normal; + auto state = item_state::normal; //check whether grabing an item, if item_spliter_ != npos, that indicates the grab item is a spliter. - if(essence_->pointer_where.first == essence_t::where_t::header && (item_spliter_ == npos)) + if(essence_->pointer_where.first == parts::header && (item_spliter_ == npos)) state = essence_->ptr_state; - int bottom_y = static_cast(rect.y + rect.height - 2); + const unsigned height = rect.height - 1; + const int bottom_y = rect.bottom() - 2; + int x = rect.x - essence_->scroll.offset_x; for(auto & i: cont) { if(i.visible) @@ -2267,39 +2424,42 @@ namespace nana int next_x = x + static_cast(i.pixels); if(next_x > rect.x) { - _m_draw_item(graph, x, rect.y, height, txtop, txtcolor, i, (i.index == essence_->pointer_where.second ? state : essence_t::state_t::normal)); - graph.line(next_x - 1, rect.y, next_x - 1, bottom_y, 0xDEDFE1); + _m_draw_item(graph, x, rect.y, height, txtop, txtcolor, i, (i.index == essence_->pointer_where.second ? state : item_state::normal)); + graph.line({ next_x - 1, rect.y }, { next_x - 1, bottom_y }, _m_border_color()); } + x = next_x; - if(x - rect.x > static_cast(rect.width)) break; + if (x > rect.right()) + break; } } - if(x - rect.x < static_cast(rect.width)) - graph.rectangle(x, rect.y, rect.width - x + rect.x, height, 0xF1F2F4, true); + if (x < rect.right()) + graph.rectangle({ x, rect.y, static_cast(rect.right() - x), height }, true, essence_->scheme_ptr->header_bgcolor); } template - void _m_draw_item(graph_reference graph, int x, int y, unsigned height, int txtop, nana::color_t txtcolor, const Item& item, essence_t::state_t state) + void _m_draw_item(graph_reference graph, int x, int y, unsigned height, int txtop, const ::nana::color& fgcolor, const Item& item, item_state state) { - nana::color_t bgcolor; - typedef essence_t::state_t state_t; + essence_->scheme_ptr->header_bgcolor.get_color(); + ::nana::color bgcolor; switch(state) { - case state_t::normal: bgcolor = 0xF1F2F4; break; - case state_t::highlighted: bgcolor = 0xFFFFFF; break; - case state_t::pressed: - case state_t::grabed: bgcolor = 0x8BD6F6; break; - case state_t::floated: bgcolor = 0xBABBBC; break; + case item_state::normal: bgcolor = essence_->scheme_ptr->header_bgcolor.get_color(); break; + case item_state::highlighted: bgcolor = essence_->scheme_ptr->header_bgcolor.get_color().blend(colors::white, 0.5); break; + case item_state::pressed: + case item_state::grabbed: bgcolor = essence_->scheme_ptr->header_grabbed.get_color(); break; + case item_state::floated: bgcolor = essence_->scheme_ptr->header_floated.get_color(); break; } - graph.rectangle(x, y, item.pixels, height, bgcolor, true); - graph.string(x + 5, txtop, txtcolor, item.text); + graph.gradual_rectangle({ x, y, item.pixels, height }, bgcolor.blend(colors::white, 0.9), bgcolor.blend(colors::black, 0.9), true); + graph.string({ x + 5, txtop }, item.text, fgcolor); if(item.index == essence_->lister.sort_index()) { - nana::paint::gadget::directions::t dir = essence_->lister.sort_reverse() ? nana::paint::gadget::directions::to_south : nana::paint::gadget::directions::to_north; - nana::paint::gadget::arrow_16_pixels(graph, x + (item.pixels - 16) / 2, -4, 0x0, 0, dir); + facade arrow("hollow_triangle"); + arrow.direction(essence_->lister.sort_reverse() ? ::nana::direction::south : ::nana::direction::north); + arrow.draw(graph, {}, colors::black, { x + static_cast(item.pixels - 16) / 2, -4, 16, 16 }, element_state::normal); } } @@ -2307,13 +2467,13 @@ namespace nana { const auto & item = essence_->header.column(essence_->pointer_where.second); - nana::paint::graphics ext_graph(item.pixels, essence_->header_size); + nana::paint::graphics ext_graph({ item.pixels, essence_->header_size }); ext_graph.typeface(essence_->graph->typeface()); int txtop = (essence_->header_size - essence_->text_height) / 2; - _m_draw_item(ext_graph, 0, 0, essence_->header_size, txtop, 0xFFFFFF, item, essence_t::state_t::floated); + _m_draw_item(ext_graph, 0, 0, essence_->header_size, txtop, colors::white, item, item_state::floated); - int xpos = essence_->header.xpos(item.index) + pos.x - ref_xpos_; + int xpos = essence_->header.item_pos(item.index, nullptr) + pos.x - ref_xpos_; ext_graph.blend(ext_graph.size(), *(essence_->graph), nana::point(xpos - essence_->scroll.offset_x + rect.x, rect.y), 0.5); } @@ -2332,6 +2492,9 @@ namespace nana class drawer_lister_impl { public: + using item_state = essence_t::item_state; + using parts = essence_t::parts; + drawer_lister_impl(essence_t * es) :essence_(es) {} @@ -2343,18 +2506,19 @@ namespace nana size_type n = essence_->number_of_lister_items(true); if(0 == n)return; widget * wdptr = essence_->lister.wd_ptr(); - nana::color_t bgcolor = wdptr->background(); - nana::color_t txtcolor = wdptr->foreground(); + auto bgcolor = wdptr->bgcolor(); + auto fgcolor = wdptr->fgcolor(); unsigned header_w = essence_->header.pixels(); + essence_->graph->set_color(bgcolor); if(header_w - essence_->scroll.offset_x < rect.width) - essence_->graph->rectangle(rect.x + header_w - essence_->scroll.offset_x, rect.y, rect.width - (header_w - essence_->scroll.offset_x), rect.height, bgcolor, true); + essence_->graph->rectangle(rectangle{ rect.x + static_cast(header_w)-essence_->scroll.offset_x, rect.y, rect.width - (header_w - essence_->scroll.offset_x), rect.height }, true); es_lister & lister = essence_->lister; //The Tracker indicates the item where mouse placed. index_pair tracker(npos, npos); auto & ptr_where = essence_->pointer_where; - if((ptr_where.first == essence_t::where_t::lister || ptr_where.first == essence_t::where_t::checker) && ptr_where.second != npos) + if((ptr_where.first == parts::lister || ptr_where.first == parts::checker) && ptr_where.second != npos) lister.forward(essence_->scroll.offset_y, ptr_where.second, tracker); std::vector subitems; @@ -2372,7 +2536,7 @@ namespace nana auto idx = essence_->scroll.offset_y; - auto state = essence_t::state_t::normal; + auto state = item_state::normal; //Here draws a root categ or a first drawing is not a categ. if(idx.cat == 0 || !idx.is_category()) { @@ -2389,9 +2553,9 @@ namespace nana for(std::size_t offs = essence_->scroll.offset_y.item; offs < size; ++offs, ++idx.item) { if(n-- == 0) break; - state = (tracker == idx ? essence_t::state_t::highlighted : essence_t::state_t::normal); + state = (tracker == idx ? item_state::highlighted : item_state::normal); - _m_draw_item(i_categ->items[lister.absolute(index_pair(idx.cat, offs))], x, y, txtoff, header_w, rect, subitems, bgcolor, txtcolor, state); + _m_draw_item(i_categ->items[lister.absolute(index_pair(idx.cat, offs))], x, y, txtoff, header_w, rect, subitems, bgcolor,fgcolor, state); y += essence_->item_size; } } @@ -2400,9 +2564,9 @@ namespace nana for(auto i = i_categ->items.cbegin() + essence_->scroll.offset_y.item; i != i_categ->items.cend(); ++i, ++idx.item) { if(n-- == 0) break; - state = (tracker == idx ? essence_t::state_t::highlighted : essence_t::state_t::normal); + state = (tracker == idx ? item_state::highlighted : item_state::normal); - _m_draw_item(*i, x, y, txtoff, header_w, rect, subitems, bgcolor, txtcolor, state); + _m_draw_item(*i, x, y, txtoff, header_w, rect, subitems, bgcolor, fgcolor, state); y += essence_->item_size; } } @@ -2415,7 +2579,7 @@ namespace nana if(n-- == 0) break; idx.item = 0; - state = (tracker.is_category() && (idx.cat == tracker.cat) ? essence_t::state_t::highlighted : essence_t::state_t::normal); + state = (tracker.is_category() && (idx.cat == tracker.cat) ? item_state::highlighted : item_state::normal); _m_draw_categ(*i_categ, rect.x - essence_->scroll.offset_x, y, txtoff, header_w, rect, bgcolor, state); y += essence_->item_size; @@ -2429,9 +2593,9 @@ namespace nana for(decltype(size) pos = 0; pos < size; ++pos) { if(n-- == 0) break; - state = (idx == tracker ? essence_t::state_t::highlighted : essence_t::state_t::normal); + state = (idx == tracker ? item_state::highlighted : item_state::normal); - _m_draw_item(i_categ->items[lister.absolute(index_pair(idx.cat, pos))], x, y, txtoff, header_w, rect, subitems, bgcolor, txtcolor, state); + _m_draw_item(i_categ->items[lister.absolute(index_pair(idx.cat, pos))], x, y, txtoff, header_w, rect, subitems, bgcolor, fgcolor, state); y += essence_->item_size; ++idx.item; } @@ -2442,9 +2606,9 @@ namespace nana { if(n-- == 0) break; - state = (idx == tracker ? essence_t::state_t::highlighted : essence_t::state_t::normal); + state = (idx == tracker ? item_state::highlighted : item_state::normal); - _m_draw_item(m, x, y, txtoff, header_w, rect, subitems, bgcolor, txtcolor, state); + _m_draw_item(m, x, y, txtoff, header_w, rect, subitems, bgcolor, fgcolor, state); y += essence_->item_size; ++idx.item; @@ -2452,25 +2616,32 @@ namespace nana } } - if(y < rect.y + static_cast(rect.height)) - essence_->graph->rectangle(rect.x, y, rect.width, rect.y + rect.height - y, bgcolor, true); + if (y < rect.y + static_cast(rect.height)) + { + essence_->graph->set_color(bgcolor); + essence_->graph->rectangle(rectangle{ rect.x, y, rect.width, rect.y + rect.height - y }, true); + } } private: - void _m_draw_categ(const category_t& categ, int x, int y, int txtoff, unsigned width, const nana::rectangle& r, nana::color_t bgcolor, essence_t::state_t state) const + void _m_draw_categ(const category_t& categ, int x, int y, int txtoff, unsigned width, const nana::rectangle& r, nana::color bgcolor, item_state state) const { bool sel = categ.selected(); if(sel && (categ.expand == false)) - bgcolor = 0xD5EFFC; + bgcolor = nana::color(0xD5, 0xEF, 0xFC); - if(state == essence_t::state_t::highlighted) - bgcolor = essence_->graph->mix(bgcolor, 0x99DEFD, 0.8); + if (state == item_state::highlighted) + bgcolor = bgcolor.blend(::nana::color(0x99, 0xde, 0xfd), 0.8); auto graph = essence_->graph; - graph->rectangle(x, y, width, essence_->item_size, bgcolor, true); + graph->set_color(bgcolor); + graph->rectangle(rectangle{ x, y, width, essence_->item_size }, true); - nana::paint::gadget::arrow_16_pixels(*graph, x + 5, y + (essence_->item_size - 16) /2, 0x3399, 2, (categ.expand ? nana::paint::gadget::directions::to_north : nana::paint::gadget::directions::to_south)); - nana::size text_s = graph->text_extent_size(categ.text); - graph->string(x + 20, y + txtoff, 0x3399, categ.text); + facade arrow("double"); + arrow.direction(categ.expand ? ::nana::direction::north : ::nana::direction::south); + ::nana::rectangle arrow_r{ x + 5, y + static_cast(essence_->item_size - 16) / 2, 16, 16 }; + arrow.draw(*graph, {}, static_cast(0x3399), arrow_r, element_state::normal); + + graph->string({ x + 20, y + txtoff }, categ.text, {0, 0x33, 0x99}); std::stringstream ss; ss<<'('<(categ.items.size())<<')'; @@ -2478,11 +2649,14 @@ namespace nana unsigned str_w = graph->text_extent_size(str).width; - graph->string(x + 25 + text_s.width, y + txtoff, 0x3399, str); - - if(x + 35 + text_s.width + str_w < x + width) - graph->line(x + 30 + text_s.width + str_w, y + essence_->item_size / 2, x + width - 5, y + essence_->item_size / 2, 0x3399); + auto text_s = graph->text_extent_size(categ.text); + graph->string({ x + 25 + static_cast(text_s.width), y + txtoff }, str); + if (x + 35 + text_s.width + str_w < x + width) + { + ::nana::point pos{ x + 30 + static_cast(text_s.width + str_w), y + static_cast(essence_->item_size) / 2 }; + graph->line(pos, { x + static_cast(width)-5, pos.y }, { 0x0, 0x33, 0x99 }); + } //Draw selecting inner rectangle if(sel && categ.expand == false) { @@ -2491,25 +2665,31 @@ namespace nana } } - void _m_draw_item(const item_t& item, int x, int y, int txtoff, unsigned width, const nana::rectangle& r, const std::vector& seqs, nana::color_t bgcolor, nana::color_t txtcolor, essence_t::state_t state) const + void _m_draw_item(const item_t& item, int x, int y, int txtoff, unsigned width, const nana::rectangle& r, const std::vector& seqs, nana::color bgcolor, nana::color fgcolor, item_state state) const { - if(item.flags.selected) - bgcolor = 0xD5EFFC; - else if ((item.bgcolor & 0xFF000000) == 0) + if (item.flags.selected) + bgcolor = essence_->scheme_ptr->item_selected; + else if (!item.bgcolor.invisible()) bgcolor = item.bgcolor; - if((item.fgcolor & 0xFF000000) == 0) - txtcolor = item.fgcolor; + if(!item.fgcolor.invisible()) + fgcolor = item.fgcolor; auto graph = essence_->graph; - if(essence_t::state_t::highlighted == state) - bgcolor = graph->mix(bgcolor, 0x99DEFD, 0.8); + if (item_state::highlighted == state) + { + if (item.flags.selected) + bgcolor = bgcolor.blend(colors::black, 0.98); + else + bgcolor = bgcolor.blend(essence_->scheme_ptr->item_selected, 0.7); + } unsigned show_w = width - essence_->scroll.offset_x; if(show_w >= r.width) show_w = r.width; //draw the background - graph->rectangle(r.x, y, show_w, essence_->item_size, bgcolor, true); + graph->set_color(bgcolor); + graph->rectangle(rectangle{ r.x, y, show_w, essence_->item_size }, true); int item_xpos = x; bool first = true; @@ -2520,33 +2700,47 @@ namespace nana if ((item.cells.size() > index) && (header.pixels > 5)) { + auto cell_txtcolor = fgcolor; + auto & m_cell = item.cells[index]; + nana::size ts = graph->text_extent_size(m_cell.text); + + if (m_cell.custom_format && (!m_cell.custom_format->bgcolor.invisible())) + { + if (!item.flags.selected) + { + if (item_state::highlighted == state) + graph->set_color(m_cell.custom_format->bgcolor.blend(::nana::color(0x99, 0xde, 0xfd), 0.8)); + else + graph->set_color(m_cell.custom_format->bgcolor); + graph->rectangle(rectangle{ item_xpos, y, header.pixels, essence_->item_size }, true); + } + + cell_txtcolor = m_cell.custom_format->fgcolor; + } + int ext_w = 5; if(first && essence_->checkable) { ext_w += 18; element_state estate = element_state::normal; - if(essence_->pointer_where.first == essence_t::where_t::checker) + if(essence_->pointer_where.first == parts::checker) { switch(state) { - case essence_t::state_t::highlighted: + case item_state::highlighted: estate = element_state::hovered; break; - case essence_t::state_t::grabed: + case item_state::grabbed: estate = element_state::pressed; break; default: break; } } - typedef std::remove_reference::type::state state; - + using state = facade::state; crook_renderer_.check(item.flags.checked ? state::checked : state::unchecked); - crook_renderer_.draw(*graph, bgcolor, txtcolor, essence_->checkarea(item_xpos, y), estate); + crook_renderer_.draw(*graph, bgcolor, fgcolor, essence_->checkarea(item_xpos, y), estate); } - auto & m_cell = item.cells[index]; - nana::size ts = graph->text_extent_size(m_cell.text); - if ((0 == index) && essence_->if_image) { if (item.img) @@ -2559,36 +2753,27 @@ namespace nana ext_w += 18; } - auto cell_txtcolor = txtcolor; - if (m_cell.custom_format) - { - if (!item.flags.selected && !(m_cell.custom_format->bgcolor & 0xFF000000)) - { - auto cell_bgcolor = m_cell.custom_format->bgcolor; - if (essence_t::state_t::highlighted == state) - cell_bgcolor = graph->mix(cell_bgcolor, 0x99DEFD, 0.8); - graph->rectangle(item_xpos, y, header.pixels, essence_->item_size, cell_bgcolor, true); - } + graph->set_text_color(cell_txtcolor); + graph->string(point{ item_xpos + ext_w, y + txtoff }, m_cell.text); - if (!(m_cell.custom_format->bgcolor & 0xFF000000)) - cell_txtcolor = m_cell.custom_format->fgcolor; - } - graph->string(item_xpos + ext_w, y + txtoff, cell_txtcolor, m_cell.text); - - if(ts.width + ext_w > header.pixels) + if (ts.width + ext_w > header.pixels) { //The text is painted over the next subitem int xpos = item_xpos + header.pixels - essence_->suspension_width; - graph->rectangle(xpos, y + 2, essence_->suspension_width, essence_->item_size - 4, bgcolor, true); - graph->string(xpos, y + 2, txtcolor, STR("...")); + + graph->set_color(bgcolor); + graph->rectangle(rectangle{ xpos, y + 2, essence_->suspension_width, essence_->item_size - 4 }, true); + graph->set_text_color(fgcolor); + graph->string(point{ xpos, y + 2 }, STR("...")); //Erase the part that over the next subitem. - auto erase_bgcolor = index + 1 < seqs.size() ? bgcolor : item.bgcolor; - graph->rectangle(item_xpos + header.pixels, y + 2, ts.width + ext_w - header.pixels, essence_->item_size - 4, erase_bgcolor, true); + if (index + 1 >= seqs.size()) + graph->set_color(item.bgcolor); + graph->rectangle(rectangle{item_xpos + static_cast(header.pixels), y + 2, ts.width + ext_w - header.pixels, essence_->item_size - 4}, true); } } - graph->line(item_xpos - 1, y, item_xpos - 1, y + essence_->item_size - 1, 0xEBF4F9); + graph->line({ item_xpos - 1, y }, { item_xpos - 1, y + static_cast(essence_->item_size) - 1 }, { 0xEB, 0xF4, 0xF9 }); item_xpos += header.pixels; first = false; @@ -2603,13 +2788,14 @@ namespace nana { //Draw selecting inner rectangle auto graph = essence_->graph; - graph->rectangle(x , y , width, essence_->item_size, 0x99DEFD, false); + graph->rectangle({ x, y, width, essence_->item_size }, false, { 0x99, 0xDE, 0xFD }); - graph->rectangle(x + 1, y + 1, width - 2, essence_->item_size - 2, 0xFFFFFF, false); - graph->set_pixel(x, y, 0xFFFFFF); - graph->set_pixel(x, y + essence_->item_size - 1, 0xFFFFFF); - graph->set_pixel(x + width - 1, y, 0xFFFFFF); - graph->set_pixel(x + width - 1, y + essence_->item_size - 1, 0xFFFFFF); + graph->set_color(colors::white); + graph->rectangle({ x + 1, y + 1, width - 2, essence_->item_size - 2 }, false); + graph->set_pixel(x, y); + graph->set_pixel(x, y + essence_->item_size - 1); + graph->set_pixel(x + width - 1, y); + graph->set_pixel(x + width - 1, y + essence_->item_size - 1); } private: essence_t * essence_; @@ -2659,21 +2845,26 @@ namespace nana auto & graph = *essence_->graph; auto size = graph.size(); //Draw Border - graph.rectangle(0x9CB6C5, false); - graph.line(1, 1, 1, size.height - 2, 0xFFFFFF); - graph.line(size.width - 2, 1, size.width - 2, size.height - 2, 0xFFFFFF); + graph.rectangle(false, {0x9c, 0xb6, 0xc5}); + graph.line({ 1, 1 }, {1, static_cast(size.height) - 2}, colors::white); + graph.line({ static_cast(size.width) - 2, 1 }, { static_cast(size.width) - 2, static_cast(size.height) - 2 }); if ((essence_->scroll.h.empty() == false) && (essence_->scroll.v.empty() == false)) - graph.rectangle(size.width - 1 - essence_->scroll.scale, size.height - 1 - essence_->scroll.scale, essence_->scroll.scale, essence_->scroll.scale, nana::color::button_face, true); + graph.rectangle({ static_cast(size.width - 1 - essence_->scroll.scale), + static_cast(size.height - 1 - essence_->scroll.scale), + essence_->scroll.scale, + essence_->scroll.scale }, + true, colors::button_face); } void trigger::attached(widget_reference widget, graph_reference graph) { + essence_->scheme_ptr = static_cast<::nana::listbox::scheme_type*>(API::dev::get_scheme(widget)); essence_->graph = &graph; typeface_changed(graph); essence_->lister.bind(essence_, widget); - widget.background(0xFFFFFF); + widget.bgcolor(colors::white); } void trigger::detached() @@ -2695,12 +2886,14 @@ namespace nana void trigger::mouse_move(graph_reference graph, const arg_mouse& arg) { + using item_state = essence_t::item_state; + using parts = essence_t::parts; int update = 0; //0 = nothing, 1 = update, 2 = refresh - if(essence_->ptr_state == essence_t::state_t::pressed) + if(essence_->ptr_state == item_state::pressed) { - if(essence_->pointer_where.first == essence_t::where_t::header) + if(essence_->pointer_where.first == parts::header) { - essence_->ptr_state = essence_t::state_t::grabed; + essence_->ptr_state = item_state::grabbed; nana::point pos = arg.pos; essence_->widget_to_header(pos); drawer_header_->grab(pos, true); @@ -2709,7 +2902,7 @@ namespace nana } } - if(essence_->ptr_state == essence_t::state_t::grabed) + if(essence_->ptr_state == item_state::grabbed) { nana::point pos = arg.pos; essence_->widget_to_header(pos); @@ -2720,12 +2913,12 @@ namespace nana } else if(essence_->calc_where(arg.pos.x, arg.pos.y)) { - essence_->ptr_state = essence_t::state_t::highlighted; + essence_->ptr_state = item_state::highlighted; update = 2; } bool set_spliter = false; - if(essence_->pointer_where.first == essence_t::where_t::header) + if(essence_->pointer_where.first == parts::header) { nana::rectangle r; if(essence_->rect_header(r)) @@ -2737,7 +2930,7 @@ namespace nana } } } - if(set_spliter == false && essence_->ptr_state != essence_t::state_t::grabed) + if(set_spliter == false && essence_->ptr_state != item_state::grabbed) { if((drawer_header_->item_spliter() != npos) || (essence_->lister.wd_ptr()->cursor() == cursor::size_we)) { @@ -2761,13 +2954,14 @@ namespace nana void trigger::mouse_leave(graph_reference graph, const arg_mouse&) { - typedef essence_t::state_t state_t; - if((essence_->pointer_where.first != essence_t::where_t::unknown) || (essence_->ptr_state != state_t::normal)) + using item_state = essence_t::item_state; + using parts = essence_t::parts; + if((essence_->pointer_where.first != parts::unknown) || (essence_->ptr_state != item_state::normal)) { - if(essence_->ptr_state != state_t::grabed) + if (essence_->ptr_state != item_state::grabbed) { - essence_->pointer_where.first = essence_t::where_t::unknown; - essence_->ptr_state = state_t::normal; + essence_->pointer_where.first = parts::unknown; + essence_->ptr_state = item_state::normal; } draw(); @@ -2777,11 +2971,13 @@ namespace nana void trigger::mouse_down(graph_reference, const arg_mouse& arg) { + using item_state = essence_t::item_state; + using parts = essence_t::parts; bool update = false; auto & ptr_where = essence_->pointer_where; - if((ptr_where.first == essence_t::where_t::header) && (ptr_where.second != npos || (drawer_header_->item_spliter() != npos))) + if((ptr_where.first == parts::header) && (ptr_where.second != npos || (drawer_header_->item_spliter() != npos))) { - essence_->ptr_state = essence_t::state_t::pressed; + essence_->ptr_state = item_state::pressed; nana::rectangle r; if(essence_->rect_header(r)) { @@ -2789,22 +2985,27 @@ namespace nana update = true; } } - else if(ptr_where.first == essence_t::where_t::lister || ptr_where.first == essence_t::where_t::checker) + else if(ptr_where.first == parts::lister || ptr_where.first == parts::checker) { auto & lister = essence_->lister; index_pair item_pos; if (lister.forward(essence_->scroll.offset_y, ptr_where.second, item_pos)) { auto * item_ptr = (item_pos.is_item() ? &lister.at(item_pos) : nullptr); - if(ptr_where.first == essence_t::where_t::lister) + if(ptr_where.first == parts::lister) { bool sel = true; - if (arg.shift) - lister.select_range(lister.last_selected, item_pos, sel); - else if (arg.ctrl) - sel = !item_proxy(essence_, item_pos).selected(); + if (!lister.single_selection()) + { + if (arg.shift) + lister.select_range(lister.last_selected, item_pos, sel); + else if (arg.ctrl) + sel = !item_proxy(essence_, item_pos).selected(); + else + lister.select_for_all(false); + } else - lister.select_for_all(false); + sel = !item_proxy(essence_, item_pos).selected(); if(item_ptr) { @@ -2812,14 +3013,18 @@ namespace nana index_pair last_selected(item_pos.cat, lister.absolute(item_pos)); arg_listbox arg{item_proxy{essence_, last_selected}, sel}; - essence_->lister.wd_ptr()->events().selected.emit(arg); + lister.wd_ptr()->events().selected.emit(arg); if (item_ptr->flags.selected) + { + lister.cancel_others_if_single_enabled(true, last_selected); essence_->lister.last_selected = last_selected; + + } else if (essence_->lister.last_selected == last_selected) essence_->lister.last_selected.set_both(npos); } - else + else if(!lister.single_selection()) lister.categ_selected(item_pos.cat, true); } else @@ -2828,10 +3033,14 @@ namespace nana { item_ptr->flags.checked = ! item_ptr->flags.checked; - arg_listbox arg{ item_proxy{ essence_, index_pair(item_pos.cat, lister.absolute(item_pos)) }, item_ptr->flags.checked }; + index_pair abs_pos{ item_pos.cat, lister.absolute(item_pos) }; + arg_listbox arg{ item_proxy{ essence_, abs_pos }, item_ptr->flags.checked }; lister.wd_ptr()->events().checked.emit(arg); + + if (item_ptr->flags.checked) + lister.cancel_others_if_single_enabled(false, abs_pos); } - else + else if (! lister.single_check()) lister.categ_checked_reverse(item_pos.cat); } update = true; @@ -2857,12 +3066,13 @@ namespace nana void trigger::mouse_up(graph_reference graph, const arg_mouse& arg) { - typedef essence_t::where_t where_t; - typedef essence_t::state_t state_t; - state_t prev_state = essence_->ptr_state; - essence_->ptr_state = state_t::highlighted; + using item_state = essence_t::item_state; + using parts = essence_t::parts; + + auto prev_state = essence_->ptr_state; + essence_->ptr_state = item_state::highlighted; //Do sort - if(essence_->pointer_where.first == where_t::header && prev_state == state_t::pressed) + if (essence_->pointer_where.first == parts::header && prev_state == item_state::pressed) { if(essence_->pointer_where.second < essence_->header.cont().size()) { @@ -2873,7 +3083,7 @@ namespace nana } } } - else if(prev_state == state_t::grabed) + else if (prev_state == item_state::grabbed) { nana::point pos = arg.pos; essence_->widget_to_header(pos); @@ -2896,7 +3106,7 @@ namespace nana void trigger::dbl_click(graph_reference graph, const arg_mouse&) { - if (essence_->pointer_where.first != essence_t::where_t::lister) + if (essence_->pointer_where.first != essence_t::parts::lister) return; index_pair item_pos; @@ -3009,7 +3219,10 @@ namespace nana ess_->lister.wd_ptr()->events().selected.emit(arg); if (m.flags.selected) + { + ess_->lister.cancel_others_if_single_enabled(true, pos_); //Cancel all selections except pos_ if single_selection is enabled. ess_->lister.last_selected = pos_; + } else if (ess_->lister.last_selected == pos_) ess_->lister.last_selected.set_both(npos); } @@ -3021,26 +3234,26 @@ namespace nana return cat_->items.at(pos_.item).flags.selected; } - item_proxy & item_proxy::bgcolor(nana::color_t col) + item_proxy & item_proxy::bgcolor(const nana::color& col) { - cat_->items.at(pos_.item).flags.selected; + cat_->items.at(pos_.item).bgcolor = col; ess_->update(); return *this; } - nana::color_t item_proxy::bgcolor() const + nana::color item_proxy::bgcolor() const { return cat_->items.at(pos_.item).bgcolor; } - item_proxy& item_proxy::fgcolor(nana::color_t col) + item_proxy& item_proxy::fgcolor(const nana::color& col) { cat_->items.at(pos_.item).fgcolor = col; ess_->update(); return *this; } - nana::color_t item_proxy::fgcolor() const + nana::color item_proxy::fgcolor() const { return cat_->items.at(pos_.item).fgcolor; } @@ -3265,8 +3478,8 @@ namespace nana if(wd && !(API::empty_window(wd->handle()))) { auto & m = cat_->items.back(); - m.bgcolor = wd->background(); - m.fgcolor = wd->foreground(); + m.bgcolor = wd->bgcolor(); + m.fgcolor = wd->fgcolor(); ess_->update(); } } @@ -3425,8 +3638,8 @@ namespace nana if (wd && !(API::empty_window(wd->handle()))) { auto & m = cat_->items.back(); - m.bgcolor = wd->background(); - m.fgcolor = wd->foreground(); + m.bgcolor = wd->bgcolor(); + m.fgcolor = wd->fgcolor(); ess_->update(); } } @@ -3450,6 +3663,12 @@ namespace nana } }//end namespace drawerbase + arg_listbox::arg_listbox(const drawerbase::listbox::item_proxy& m, bool selected) + : item(m), selected(selected) + { + + } + //class listbox listbox::listbox(window wd, bool visible) { @@ -3534,8 +3753,8 @@ namespace nana if (false == API::empty_window(wd)) { auto & item = ess.lister.at(pos); - item.bgcolor = API::background(wd); - item.fgcolor = API::foreground(wd); + item.bgcolor = bgcolor(); + item.fgcolor = fgcolor(); ess.update(); } } @@ -3701,6 +3920,17 @@ namespace nana return _m_ess().lister.size_item(categ); } + void listbox::enable_single(bool for_selection, bool category_limited) + { + internal_scope_guard lock; + _m_ess().lister.enable_single(for_selection, category_limited); + } + + void listbox::disable_single(bool for_selection) + { + _m_ess().lister.disable_single(for_selection); + } + drawerbase::listbox::essence_t & listbox::_m_ess() const { return get_drawer_trigger().essence(); diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 8be62a7a..129cb7bc 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -105,38 +105,42 @@ namespace nana nana::size sz = graph.size(); sz.width -= 30; sz.height -= 2; - graph.rectangle(color::gray_border, false); - graph.rectangle(1, 1, 28, sz.height, 0xF6F6F6, true); - graph.rectangle(29, 1, sz.width, sz.height, 0xFFFFFF, true); + graph.rectangle(false, colors::gray_border); + graph.rectangle({ 1, 1, 28, sz.height }, true, { 0xf6, 0xf6, 0xf6 }); + graph.rectangle({ 29, 1, sz.width, sz.height }, true, colors::white); } void item(graph_reference graph, const nana::rectangle& r, const attr& at) { if(at.item_state == state::active) { - graph.rectangle(r, 0xA8D8EB, false); + graph.rectangle(r, false, {0xa8, 0xd8, 0xeb}); nana::point points[4] = { nana::point(r.x, r.y), nana::point(r.x + r.width - 1, r.y), nana::point(r.x, r.y + r.height - 1), nana::point(r.x + r.width - 1, r.y + r.height - 1) }; + + graph.set_color({0xc0, 0xdd, 0xfc}); for(int i = 0; i < 4; ++i) - graph.set_pixel(points[i].x, points[i].y, 0xC0DDFC); + graph.set_pixel(points[i].x, points[i].y); if(at.enabled) - graph.shadow_rectangle(nana::rectangle(r).pare_off(1), 0xE8F0F4, 0xDBECF4, true); + graph.gradual_rectangle(nana::rectangle(r).pare_off(1), { 0xE8, 0xF0, 0xF4 }, { 0xDB,0xEC,0xF4 }, true); } if(at.checked && (checks::none != at.check_style)) { - graph.rectangle(r, 0xCDD3E6, false); - graph.rectangle(nana::rectangle(r).pare_off(1), 0xE6EFF4, true); + graph.rectangle(r, false, { 0xCD, 0xD3, 0xE6 }); + + ::nana::color clr(0xE6, 0xEF, 0xF4); + graph.rectangle(nana::rectangle(r).pare_off(1), true, clr); nana::rectangle crook_r = r; crook_r.width = 16; crook_.radio(at.check_style == checks::option); - crook_.draw(graph, 0xE6EFF4, 0x0, crook_r, element_state::normal); + crook_.draw(graph, clr, colors::black, crook_r, element_state::normal); } } @@ -147,24 +151,22 @@ namespace nana void item_text(graph_reference graph, const nana::point& pos, const nana::string& text, unsigned text_pixels, const attr& at) { + graph.set_color(at.enabled ? colors::black : colors::gray_border); nana::paint::text_renderer tr(graph); - tr.render(pos.x, pos.y, (at.enabled ? 0x0 : nana::color::gray_border), text.c_str(), text.length(), text_pixels, true); + tr.render(pos, text.c_str(), text.length(), text_pixels, true); } void sub_arrow(graph_reference graph, const nana::point& pos, unsigned pixels, const attr&) { - nana::paint::gadget::arrow_16_pixels(graph, pos.x, pos.y + static_cast(pixels - 16) / 2, 0x0, 0, nana::paint::gadget::directions::to_east); + facade arrow("hollow_triangle"); + arrow.direction(::nana::direction::east); + arrow.draw(graph, {}, colors::black, { pos.x, pos.y + static_cast(pixels - 16) / 2, 16, 16 }, element_state::normal); } private: facade crook_; }; - //class renderer_interface - renderer_interface::~renderer_interface() - {} - //end class renderer_interface - class menu_builder : noncopyable { @@ -177,7 +179,7 @@ namespace nana menu_builder() { - root_.max_pixels = API::screen_size().width * 2 / 3; + root_.max_pixels = screen::primary_monitor_size().width * 2 / 3; root_.item_pixels = 24; renderer_ = pat::cloneable(internal_renderer()); } @@ -537,7 +539,7 @@ namespace nana renderer->item(*graph_, item_r, attr); //Draw text, the text is transformed from orignal for hotkey character - nana::string::value_type hotkey; + nana::char_t hotkey; nana::string::size_type hotkey_pos; nana::string text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos); @@ -555,7 +557,9 @@ namespace nana nana::size hotkey_size = graph_->text_extent_size(text.c_str() + hotkey_pos, 1); int x = item_r.x + 40 + off_w; int y = item_r.y + text_top_off + hotkey_size.height; - graph_->line(x, y, x + hotkey_size.width - 1, y, 0x0); + + graph_->set_color(colors::black); + graph_->line({ x, y }, { x + static_cast(hotkey_size.width) - 1, y }); } } @@ -566,7 +570,8 @@ namespace nana } else { - graph_->line(item_r.x + 40, item_r.y, graph_->width() - 1, item_r.y, nana::color::gray_border); + graph_->set_color(colors::gray_border); + graph_->line({ item_r.x + 40, item_r.y }, { static_cast(graph_->width()) - 1, item_r.y }); item_r.y += 2; } @@ -654,7 +659,7 @@ namespace nana API::calc_screen_point(*widget_, pos); //get the screen coordinates of the widget pos. - auto scr_area = API::screen_area_from_point(detail_.monitor_pos); + auto scr_area = screen::from_point(detail_.monitor_pos)->area(); if(pos.x + size.width > scr_area.x + scr_area.width) pos.x = static_cast(scr_area.x + scr_area.width - size.width); @@ -736,21 +741,21 @@ namespace nana API::register_menu_window(this->handle(), !owner_menubar); } - events().destroy.connect([this]{ + events().destroy.connect_unignorable([this]{ _m_destroy(); }); - events().key_press.connect([this](const arg_keyboard& arg){ + events().key_press.connect_unignorable([this](const arg_keyboard& arg){ _m_key_down(arg); }); - events().mouse_up.connect([this]{ + events().mouse_up.connect_unignorable([this]{ pick(); }); if (want_focus_) { - event_focus_ = events().focus.connect([this](const arg_focus& arg) + event_focus_ = events().focus.connect_unignorable([this](const arg_focus& arg) { _m_focus_changed(arg); }); @@ -988,7 +993,7 @@ namespace nana void _m_make_mouse_event() { state_.mouse_pos = API::cursor_position(); - events().mouse_move.connect([this]{ + events().mouse_move.connect_unignorable([this]{ _m_mouse_event(); }); } @@ -1319,7 +1324,7 @@ namespace nana { close(); impl_->uiobj = &(form_loader()(wd, point(x, y), &(*impl_->mbuilder.renderer()))); - impl_->uiobj->events().destroy.connect([this]{ + impl_->uiobj->events().destroy.connect_unignorable([this]{ _m_destroy_menu_window(); }); impl_->uiobj->popup(impl_->mbuilder.data(), called_by_menubar); diff --git a/source/gui/widgets/menubar.cpp b/source/gui/widgets/menubar.cpp index 614055f3..3c584a9e 100644 --- a/source/gui/widgets/menubar.cpp +++ b/source/gui/widgets/menubar.cpp @@ -100,38 +100,39 @@ namespace nana void item_renderer::background(const nana::point& pos, const nana::size& size, state_t state) { - nana::color_t bground = API::background(handle_); - nana::color_t border, body, corner; + auto bground = API::fgcolor(handle_); + ::nana::color border, body, corner; switch(state) { case item_renderer::state_highlight: - border = nana::color::highlight; - body = 0xC0DDFC; - corner = paint::graphics::mix(body, bground, 0.5); + border = colors::highlight; + body.from_rgb(0xC0, 0xDD, 0xFC); + corner = body.blend(bground, 0.5); break; case item_renderer::state_selected: - border = nana::color::dark_border; - body = 0xFFFFFF; - corner = paint::graphics::mix(border, bground, 0.5); + border = colors::dark_border; + body = colors::white; + corner = body.blend(bground, 0.5); break; default: //Don't process other states. return; } nana::rectangle r(pos, size); - graph_.rectangle(r, border, false); + graph_.rectangle(r, false, border); - graph_.set_pixel(pos.x, pos.y, corner); - graph_.set_pixel(pos.x + size.width - 1, pos.y, corner); - graph_.set_pixel(pos.x, pos.y + size.height - 1, corner); - graph_.set_pixel(pos.x + size.width - 1, pos.y + size.height - 1, corner); - graph_.rectangle(r.pare_off(1), body, true); + graph_.set_color(corner); + graph_.set_pixel(pos.x, pos.y); + graph_.set_pixel(pos.x + size.width - 1, pos.y); + graph_.set_pixel(pos.x, pos.y + size.height - 1); + graph_.set_pixel(pos.x + size.width - 1, pos.y + size.height - 1); + graph_.rectangle(r.pare_off(1), true, body); } void item_renderer::caption(int x, int y, const nana::string& text) { - graph_.string(x, y, 0x0, text); + graph_.string({ x, y }, text, colors::black); } //end class item_renderer @@ -508,8 +509,8 @@ namespace nana void trigger::_m_draw() { - nana::color_t bground_color = API::background(*widget_); - graph_->rectangle(bground_color, true); + auto bgcolor = API::bgcolor(*widget_); + graph_->rectangle(true, bgcolor); item_renderer ird(*widget_, *graph_); @@ -538,8 +539,8 @@ namespace nana { int x = item_pos.x + item_s.width; int y1 = item_pos.y + 2, y2 = item_pos.y + item_s.height - 1; - graph_->line(x, y1, x, y2, paint::graphics::mix(color::gray_border, bground_color, 0.6)); - graph_->line(x + 1, y1, x + 1, y2, paint::graphics::mix(color::button_face_shadow_end, bground_color, 0.5)); + graph_->line({ x, y1 }, { x, y2 }, bgcolor.blend(colors::gray_border, 0.4)); + graph_->line({ x + 1, y1 }, { x + 1, y2 }, bgcolor.blend(colors::button_face_shadow_end, 0.5)); } //Draw text, the text is transformed from orignal for hotkey character @@ -555,7 +556,7 @@ namespace nana graph_->text_metrics(ascent, descent, inleading); int x = item_pos.x + 8 + off_w; int y = item_pos.y + text_top_off + ascent + 1; - graph_->line(x, y, x + hotkey_size.width - 1, y, 0x0); + graph_->line({ x, y }, { x + static_cast(hotkey_size.width) - 1, y }, ::nana::colors::black); } item_pos.x += i->size.width; diff --git a/source/gui/widgets/panel.cpp b/source/gui/widgets/panel.cpp index 1c3f1f5f..d360d916 100644 --- a/source/gui/widgets/panel.cpp +++ b/source/gui/widgets/panel.cpp @@ -20,10 +20,6 @@ namespace nana namespace panel { //class drawer - drawer::drawer() - :window_(nullptr) - {} - void drawer::attached(widget_reference widget, graph_reference) { widget.caption(STR("Nana Panel")); @@ -33,7 +29,7 @@ namespace nana void drawer::refresh(graph_reference graph) { if(bground_mode::basic != API::effects_bground_mode(window_)) - graph.rectangle(API::background(window_), true); + graph.rectangle(true, API::bgcolor(window_)); } //end class drawer }//end namespace panel diff --git a/source/gui/widgets/picture.cpp b/source/gui/widgets/picture.cpp index ecd546ca..7571d709 100644 --- a/source/gui/widgets/picture.cpp +++ b/source/gui/widgets/picture.cpp @@ -22,14 +22,11 @@ namespace nana //class picture_drawer picture_drawer::picture_drawer():graph_(nullptr) { + bground_.horizontal = true; backimg_.arg = nana::arrange::unknown; backimg_.beg = backimg_.end = 0; } - picture_drawer::runtime_type::runtime_type() - :background_shadow_start(0), background_shadow_end(0), horizontal(true) - {} - void picture_drawer::attached(widget_reference& widget, graph_reference graph) { widget_ = &widget; @@ -46,11 +43,11 @@ namespace nana backimg_.image = img; } - void picture_drawer::set_shadow_background(unsigned begin_color, unsigned end_color, bool horizontal) + void picture_drawer::set_shadow_background(const ::nana::color& from, const ::nana::color& to, bool horizontal) { - runtime_.background_shadow_end = end_color; - runtime_.background_shadow_start = begin_color; - runtime_.horizontal = horizontal; + bground_.gradual_from = from; + bground_.gradual_to = to; + bground_.horizontal = horizontal; _m_draw_background(); } @@ -244,10 +241,12 @@ namespace nana { if(graph_ && (bground_mode::basic != API::effects_bground_mode(*widget_))) { - if(runtime_.background_shadow_end == runtime_.background_shadow_start) - graph_->rectangle((runtime_.background_shadow_end ? runtime_.background_shadow_end : widget_->background()), true); + if (bground_.gradual_from.invisible() || bground_.gradual_to.invisible()) + graph_->rectangle(true, widget_->bgcolor()); + else if(bground_.gradual_from == bground_.gradual_to) + graph_->rectangle(true, bground_.gradual_from); else - graph_->shadow_rectangle(graph_->size(), runtime_.background_shadow_start, runtime_.background_shadow_end, !runtime_.horizontal); + graph_->gradual_rectangle(graph_->size(), bground_.gradual_from, bground_.gradual_to, !bground_.horizontal); } } //end class picture_drawer @@ -278,9 +277,9 @@ namespace nana API::refresh_window(*this); } - void picture::set_shadow_background(unsigned begin_color, unsigned end_color, bool horizontal) + void picture::set_gradual_background(const ::nana::color& from, const ::nana::color& to, bool horizontal) { - get_drawer_trigger().set_shadow_background(begin_color, end_color, horizontal); + get_drawer_trigger().set_shadow_background(from, to, horizontal); } void picture::transparent(bool enabled) diff --git a/source/gui/widgets/progress.cpp b/source/gui/widgets/progress.cpp index 2c89cbf5..a0219504 100644 --- a/source/gui/widgets/progress.cpp +++ b/source/gui/widgets/progress.cpp @@ -18,11 +18,6 @@ namespace nana namespace progress { //class trigger - trigger::trigger() - : graph_(nullptr), draw_width_(static_cast(-1)), has_value_(true), - unknown_(false), max_(100), value_(0) - {} - void trigger::attached(widget_reference wd, graph_reference graph) { widget_ = &wd; @@ -112,8 +107,9 @@ namespace nana void trigger::_m_draw_box(graph_reference graph) { rectangle r = graph.size(); - graph.shadow_rectangle(r, color::button_face_shadow_end, color::button_face_shadow_start, true); - graph.rectangle_line(r, 0x808080, 0x808080, 0xFFFFFF, 0xFFFFFF); + graph.gradual_rectangle(r, colors::button_face_shadow_end, colors::button_face_shadow_start, true); + ::nana::color lt{ 0x80, 0x80, 0x80 }, rb{colors::white}; + graph.frame_rectangle(r, lt, lt, rb, rb); } void trigger::_m_draw_progress(graph_reference graph) @@ -124,7 +120,7 @@ namespace nana if(false == unknown_) { if(draw_width_) - graph.shadow_rectangle(border, border, draw_width_, height, 0x6FFFA8, 0x107515, true); + graph.gradual_rectangle({ static_cast(border), static_cast(border), draw_width_, height }, { 0x6F, 0xFF, 0xA8 }, { 0x10, 0x75, 0x15 }, true); } else { @@ -134,7 +130,7 @@ namespace nana int right = (value_ >= width - 1 + border? width - 1 + border: value_); if(right >= left) - graph.shadow_rectangle(left, border, right - left + 1, height, 0x6FFFA8, 0x107515, true); + graph.gradual_rectangle({ left, static_cast(border), static_cast(right - left + 1), height }, { 0x6F, 0xFF, 0xA8 }, { 0x10, 0x75, 0x15 }, true); if(value_ >= width + block) value_ = 0; } diff --git a/source/gui/widgets/scroll.cpp b/source/gui/widgets/scroll.cpp index 780fce92..3b1d5acb 100644 --- a/source/gui/widgets/scroll.cpp +++ b/source/gui/widgets/scroll.cpp @@ -1,6 +1,7 @@ /* * A Scroll Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -10,6 +11,7 @@ */ #include +#include namespace nana { @@ -139,31 +141,26 @@ namespace nana _m_background(graph); - unsigned width, height; - int x, y; + ::nana::rectangle r(graph.size()); if(vertical_) { - x = 0; - y = graph.height() - fixedsize; - width = graph.width(); - height = fixedsize; + r.y = r.height - fixedsize; + r.height = fixedsize; } else { - x = graph.width() - fixedsize; - y = 0; - width = fixedsize; - height = graph.height(); + r.x = r.width - fixedsize; + r.width = fixedsize; } int state = ((_m_check() == false || what == buttons::none) ? states::none : states::highlight); int moused_state = (_m_check() ? (metrics_.pressed ? states::selected : states::actived) : states::none); //draw first - _m_draw_button(graph, 0, 0, width, height, buttons::first, (buttons::first == what ? moused_state : state)); + _m_draw_button(graph, { 0, 0, r.width, r.height }, buttons::first, (buttons::first == what ? moused_state : state)); //draw second - _m_draw_button(graph, x, y, width, height, buttons::second, (buttons::second == what ? moused_state : state)); + _m_draw_button(graph, r, buttons::second, (buttons::second == what ? moused_state : state)); //draw scroll _m_draw_scroll(graph, (buttons::scroll == what ? moused_state : states::highlight)); @@ -172,7 +169,7 @@ namespace nana //private: void drawer::_m_background(graph_reference graph) { - graph.rectangle(0xF0F0F0, true); + graph.rectangle(true, {0xf0, 0xf0, 0xf0}); if(metrics_.pressed && _m_check()) { @@ -193,45 +190,44 @@ namespace nana return; if(width && height) - graph.rectangle(x, y, width, height, 0xDCDCDC, true); + graph.rectangle({ x, y, width, height }, true, {0xDC, 0xDC, 0xDC}); } } - void drawer::_m_button_frame(graph_reference graph, int x, int y, unsigned width, unsigned height, int state) + void drawer::_m_button_frame(graph_reference graph, rectangle r, int state) { if(state) { - unsigned color = 0x979797; //highlight + ::nana::color clr{0x97, 0x97, 0x97}; //highlight switch(state) { case states::actived: - color = 0x86D5FD; break; + clr.from_rgb(0x86, 0xD5, 0xFD); break; case states::selected: - color = 0x3C7FB1; break; + clr.from_rgb(0x3C, 0x7F, 0xB1); break; } - graph.rectangle(rectangle(x, y, width, height), color, false); + graph.rectangle(r, false, clr); - unsigned color_x = graph.mix(color, 0xFFFFFF, 0.5); + clr = clr.blend(colors::white, 0.5); + graph.set_color(clr); - x += 2; - y += 2; - width -= 4; - height -= 4; + r.pare_off(2); if(vertical_) { - unsigned half = width / 2; - graph.rectangle(x + (width - half), y, half, height, color_x, true); - width -= half; + unsigned half = r.width / 2; + graph.rectangle({ r.x + static_cast(r.width - half), r.y, half, r.height }, true); + r.width -= half; } else { - unsigned half = height / 2; - graph.rectangle(x, y + height - half, width, half, color_x, true); - height -= half; + unsigned half = r.height / 2; + graph.rectangle({r.x, r.y + static_cast(r.height - half), r.width, half}, true); + r.height -= half; } - graph.shadow_rectangle(x, y, width, height, 0xFFFFFF, color_x, !vertical_); + //graph.shadow_rectangle(x, y, width, height, 0xFFFFFF, color_x, !vertical_); + graph.gradual_rectangle(r, colors::white, clr, !vertical_); } } @@ -275,63 +271,61 @@ namespace nana { if(_m_check()) { - int x, y; - unsigned width, height; + ::nana::rectangle r(graph.size()); if(vertical_) { - x = 0; - y = fixedsize + metrics_.scroll_pos; - - width = graph.width(); - height = static_cast(metrics_.scroll_length); + r.y = fixedsize + metrics_.scroll_pos; + r.height = static_cast(metrics_.scroll_length); } else { - x = fixedsize + metrics_.scroll_pos; - y = 0; - - width = static_cast(metrics_.scroll_length); - height = graph.height(); + r.x = fixedsize + metrics_.scroll_pos; + r.width = static_cast(metrics_.scroll_length); } - _m_button_frame(graph, x, y, width, height, state); + _m_button_frame(graph, r, state); } } - void drawer::_m_draw_button(graph_reference graph, int x, int y, unsigned width, unsigned height, buttons what, int state) + void drawer::_m_draw_button(graph_reference graph, rectangle r, buttons what, int state) { if(_m_check()) - _m_button_frame(graph, x, y, width, height, state); - - using namespace nana::paint::gadget; + _m_button_frame(graph, r, state); if(buttons::first == what || buttons::second == what) { - nana::size sz = graph.size(); - directions::t dir; - if(buttons::second == what) + auto sz = graph.size(); + int top = static_cast(sz.height - fixedsize); + int left = static_cast(sz.width - fixedsize); + + direction dir; + if (buttons::second == what) { - if(vertical_) + if (vertical_) { - y = static_cast(sz.height - fixedsize); - dir = directions::to_south; + r.y = top; + dir = direction::south; } else { - x = static_cast(sz.width - fixedsize); - dir = directions::to_east; + r.x = left; + dir = direction::east; } } else - dir = vertical_ ? directions::to_north : directions::to_west; + dir = vertical_ ? direction::north : direction::west; - if(vertical_) - x = (static_cast(sz.width) - 16) / 2; + if (vertical_) + r.x = left / 2; else - y = (static_cast(sz.height) - 16) / 2; - - arrow_16_pixels(graph, x, y, _m_check() ? 0x0 : 0x808080, (states::none == state ? 0 : 1), dir); + r.y = top / 2; + + r.width = r.height = 16; + + facade arrow(states::none == state ? "hollow_triangle" : "solid_triangle"); + arrow.direction(dir); + arrow.draw(graph, {}, (_m_check() ? colors::black : colors::gray), r, element_state::normal); } } //end class drawer diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index be087de0..f8ffa7f0 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1,7 +1,7 @@ /* * A text editor implementation * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -12,9 +12,12 @@ */ #include #include +#include #include #include #include +#include +#include namespace nana{ namespace widgets { @@ -216,7 +219,7 @@ namespace nana{ namespace widgets editor_._m_move_select(false); return; } - + editor_.select_.a = dest_a_; editor_.select_.b = dest_b_; editor_.points_.caret = sel_a_; @@ -248,14 +251,14 @@ namespace nana{ namespace widgets virtual std::size_t take_lines(std::size_t pos) const = 0; virtual void update_line(std::size_t textline, std::size_t secondary_before) = 0; - virtual void render(nana::color_t fgcolor) = 0; + virtual void render(const ::nana::color& fgcolor) = 0; virtual nana::point caret_to_screen(upoint) = 0; virtual nana::upoint screen_to_caret(point scrpos) = 0; virtual bool move_caret_ns(bool to_north) = 0; virtual bool adjust_caret_into_screen() = 0; }; - + class text_editor::behavior_normal : public editor_behavior_interface { @@ -282,25 +285,26 @@ namespace nana{ namespace widgets void update_line(std::size_t textline, std::size_t secondary_before) override { int top = editor_._m_text_top_base() + static_cast(editor_.line_height() * (textline - editor_.points_.offset.y)); - editor_.graph_.rectangle(editor_.text_area_.area.x, top, editor_.text_area_.area.width, editor_.line_height(), API::background(editor_.window_), true); - editor_._m_draw_string(top, API::foreground(editor_.window_), nana::upoint(0, editor_.points_.caret.y), editor_.textbase_.getline(textline), true); + editor_.graph_.rectangle({ editor_.text_area_.area.x, top, editor_.text_area_.area.width, editor_.line_height() }, true, API::bgcolor(editor_.window_)); + editor_._m_draw_string(top, API::fgcolor(editor_.window_), nana::upoint(0, editor_.points_.caret.y), editor_.textbase_.getline(textline), true); } - void render(nana::color_t fgcolor) override + void render(const ::nana::color& fgcolor) override { - auto & points = editor_.points_; + ::nana::upoint str_pos(0, static_cast(editor_.points_.offset.y)); - std::size_t scrlines = editor_.screen_lines() + static_cast(points.offset.y); + std::size_t scrlines = editor_.screen_lines() + str_pos.y; if (scrlines > editor_.textbase_.lines()) scrlines = editor_.textbase_.lines(); - int y = editor_._m_text_top_base(); - const unsigned pixles = editor_.line_height(); - nana::upoint str_pos(0, static_cast(points.offset.y)); - for (unsigned ln = points.offset.y; ln < scrlines; ++ln, y += pixles) + int top = editor_._m_text_top_base(); + const unsigned pixels = editor_.line_height(); + + while( str_pos.y < scrlines) { - editor_._m_draw_string(y, fgcolor, str_pos, editor_.textbase_.getline(ln), true); + editor_._m_draw_string(top, fgcolor, str_pos, editor_.textbase_.getline(str_pos.y), true); ++str_pos.y; + top += pixels; } } @@ -320,48 +324,36 @@ namespace nana{ namespace widgets nana::upoint screen_to_caret(point scrpos) override { - const auto & textbase = editor_.textbase_; - const auto & text_area = editor_.text_area_; - auto & points = editor_.points_; - - nana::upoint res(0, static_cast(_m_textline_from_screen(scrpos.y))); + nana::upoint res{ 0, static_cast(_m_textline_from_screen(scrpos.y)) }; //Convert the screen point to text caret point - const string_type& lnstr = textbase.getline(res.y); - res.x = static_cast(lnstr.size()); - if (res.x) + const string_type& lnstr = editor_.textbase_.getline(res.y); + if (lnstr.size() > 0) { - scrpos.x += (points.offset.x - text_area.area.x); + scrpos.x += (editor_.points_.offset.x - editor_.text_area_.area.x); if (scrpos.x > 0) { unicode_bidi bidi; std::vector reordered; - bidi.linestr(lnstr.c_str(), lnstr.size(), reordered); + bidi.linestr(lnstr.data(), lnstr.size(), reordered); - std::size_t pxbuf_size = 0; - std::unique_ptr pxbuf; - - int xbeg = 0; for (auto & ent : reordered) { std::size_t len = ent.end - ent.begin; - unsigned str_w = editor_._m_text_extent_size(ent.begin, len).width; - if (xbeg <= scrpos.x && scrpos.x < xbeg + static_cast(str_w)) + auto str_px = static_cast(editor_._m_text_extent_size(ent.begin, len).width); + if (scrpos.x < str_px) { - if (len > pxbuf_size) - { - pxbuf_size = len; - pxbuf.reset(new unsigned[len]); - } - res.x = editor_._m_char_by_pixels(ent.begin, len, pxbuf.get(), static_cast(str_w), scrpos.x - xbeg, _m_is_right_text(ent)); - res.x += static_cast(ent.begin - lnstr.c_str()); + std::unique_ptr pxbuf(new unsigned[len]); + + res.x = editor_._m_char_by_pixels(ent.begin, len, pxbuf.get(), str_px, scrpos.x, _m_is_right_text(ent)); + res.x += static_cast(ent.begin - lnstr.data()); return res; } - xbeg += static_cast(str_w); + scrpos.x -= str_px; } + + res.x = static_cast(lnstr.size()); } - else - res.x = 0; } return res; @@ -380,15 +372,11 @@ namespace nana{ namespace widgets if (points.xpos < points.caret.x) points.caret.x = points.xpos; - bool redraw_required = (static_cast(points.caret.y) < points.offset.y); - - if (static_cast(points.offset.y) > points.caret.y) + bool out_of_screen = (static_cast(points.caret.y) < points.offset.y); + if (out_of_screen) editor_._m_offset_y(static_cast(points.caret.y)); - if (adjust_caret_into_screen()) - redraw_required = true; - - return redraw_required; + return (adjust_caret_into_screen() || out_of_screen); } } else //South @@ -420,31 +408,29 @@ namespace nana{ namespace widgets editor_._m_get_scrollbar_size(); - const auto delta_pixels = editor_._m_text_extent_size(STR(" ")).width; + const auto delta_pixels = editor_._m_text_extent_size(STR(" "), 4).width; auto x = points.caret.x; const string_type& lnstr = textbase.getline(points.caret.y); if (x > lnstr.size()) x = static_cast(lnstr.size()); - unsigned text_w = editor_._m_pixels_by_char(textbase.getline(points.caret.y), x); + unsigned text_w = editor_._m_pixels_by_char(lnstr, x); unsigned area_w = editor_._m_text_area().width; - bool adjusted = true; + bool adjusted_cond = true; if (static_cast(text_w) < points.offset.x) - { points.offset.x = (text_w > delta_pixels ? text_w - delta_pixels : 0); - } else if (area_w && (text_w >= points.offset.x + area_w)) points.offset.x = text_w - area_w + 2; else - adjusted = false; + adjusted_cond = false; + bool adjusted_cond2 = true; int value = points.offset.y; if (scrlines && (points.caret.y >= points.offset.y + scrlines)) { value = static_cast(points.caret.y - scrlines) + 1; - adjusted = true; } else if (static_cast(points.caret.y) < points.offset.y) { @@ -452,39 +438,32 @@ namespace nana{ namespace widgets value = 0; else value = static_cast(points.offset.y - scrlines); - adjusted = true; } else if (points.offset.y && (textbase.lines() <= scrlines)) - { value = 0; - adjusted = true; - } + else + adjusted_cond2 = false; editor_._m_offset_y(value); editor_._m_scrollbar(); - return adjusted; + return (adjusted_cond || adjusted_cond2); } private: std::size_t _m_textline_from_screen(int y) const { - const auto & textbase = editor_.textbase_; - const auto & text_area = editor_.text_area_; - auto & points = editor_.points_; + const std::size_t textlines = editor_.textbase_.lines(); + if (0 == textlines) + return 0; - if (textbase.lines()) - { - if (y < static_cast(text_area.area.y)) - y = points.offset.y ? points.offset.y - 1 : 0; - else - y = (y - static_cast(text_area.area.y)) / static_cast(editor_.line_height()) + points.offset.y; + const int offset_top = editor_.points_.offset.y; + const int text_area_top = editor_.text_area_.area.y; - if (textbase.lines() <= static_cast(y)) - return textbase.lines() - 1; - else - return static_cast(y); - } + if (y < text_area_top) + y = offset_top ? offset_top - 1 : 0; + else + y = (y - text_area_top) / static_cast(editor_.line_height()) + offset_top; - return 0; + return (textlines <= static_cast(y) ? textlines - 1 : static_cast(y)); } private: text_editor& editor_; @@ -549,7 +528,7 @@ namespace nana{ namespace widgets if (pos < linemtr_.size()) { for (std::size_t i = 0; i < lines; ++i) - linemtr_.insert(linemtr_.begin() + pos + i, line_metrics()); + linemtr_.emplace(linemtr_.begin() + pos + i); //textbase is implement by using deque, and the linemtr holds the text pointers //If the textbase is changed, it will check the text pointers. @@ -600,7 +579,7 @@ namespace nana{ namespace widgets { if (text_px != str_w) { - line_sections.push_back(text_section(secondary_begin, ts.begin)); + line_sections.emplace_back(secondary_begin, ts.begin); line_sections.back().pixels = text_px - str_w; text_px = str_w; secondary_begin = ts.begin; @@ -643,7 +622,7 @@ namespace nana{ namespace widgets } auto & mtr = linemtr_[line]; - + mtr.take_lines = line_sections.size(); mtr.line_sections.swap(line_sections); @@ -660,11 +639,11 @@ namespace nana{ namespace widgets const auto lines = editor_.textbase_.lines(); linemtr_.resize(lines); - for (std::remove_const::type i = 0; i < lines; ++i) + for (std::size_t i = 0; i < lines; ++i) pre_calc_line(i, pixels); } - std::size_t take_lines() const + std::size_t take_lines() const override { std::size_t lines = 0; for (auto & mtr : linemtr_) @@ -673,7 +652,7 @@ namespace nana{ namespace widgets return lines; } - std::size_t take_lines(std::size_t pos) const + std::size_t take_lines(std::size_t pos) const override { return (pos < linemtr_.size() ? linemtr_[pos].take_lines : 0); } @@ -685,9 +664,9 @@ namespace nana{ namespace widgets int top = caret_to_screen(upoint{ 0, static_cast(textline) }).y; const unsigned pixels = editor_.line_height(); - editor_.graph_.rectangle(editor_.text_area_.area.x, top, editor_.width_pixels(), static_cast(pixels * secondary_before), API::background(editor_.window_), true); + editor_.graph_.rectangle({ editor_.text_area_.area.x, top, editor_.width_pixels(), static_cast(pixels * secondary_before) }, true, API::bgcolor(editor_.window_)); - auto fgcolor = API::foreground(editor_.window_); + auto fgcolor = API::fgcolor(editor_.window_); auto text_ptr = editor_.textbase_.getline(textline).data(); for (std::size_t pos = 0; pos < secondary_before; ++pos, top+=pixels) @@ -700,10 +679,8 @@ namespace nana{ namespace widgets editor_.render(API::is_focus_window(editor_.window_)); } - void render(nana::color_t fgcolor) override + void render(const ::nana::color& fgcolor) override { - std::size_t scrlines = editor_.screen_lines(); - std::size_t secondary; auto primary = _m_textline_from_screen(0, secondary); if (primary >= linemtr_.size() || secondary >= linemtr_[primary].line_sections.size()) @@ -715,6 +692,7 @@ namespace nana{ namespace widgets int top = editor_._m_text_top_base(); const unsigned pixels = editor_.line_height(); + const std::size_t scrlines = editor_.screen_lines(); for (std::size_t pos = 0; pos < scrlines; ++pos, top += pixels) { if ((primary < linemtr_.size()) && (secondary < linemtr_[primary].line_sections.size())) @@ -779,8 +757,6 @@ namespace nana{ namespace widgets } } } - else - scrpos.x = 0; scrpos.x += editor_.text_area_.area.x; scrpos.y = editor_.text_area_.area.y + static_cast((lines - editor_.points_.offset.y) * editor_.line_height()); @@ -803,31 +779,24 @@ namespace nana{ namespace widgets unicode_bidi bidi; bidi.linestr(str.begin, str.end - str.begin, reordered); - std::size_t pxbuf_size = 0; - std::unique_ptr pxbuf; - nana::upoint res(static_cast(str.begin - mtr.line_sections.front().begin), static_cast(primary)); scrpos.x -= editor_.text_area_.area.x; if (scrpos.x < 0) scrpos.x = 0; - int xbeg = 0; for (auto & ent : reordered) { std::size_t len = ent.end - ent.begin; - unsigned str_w = editor_._m_text_extent_size(ent.begin, len).width; - if (xbeg <= scrpos.x && scrpos.x < xbeg + static_cast(str_w)) + auto str_px = static_cast(editor_._m_text_extent_size(ent.begin, len).width); + if (scrpos.x < str_px) { - if (len > pxbuf_size) - { - pxbuf.reset(new unsigned[len]); - pxbuf_size = len; - } - res.x += editor_._m_char_by_pixels(ent.begin, len, pxbuf.get(), static_cast(str_w), scrpos.x - xbeg, _m_is_right_text(ent)); + std::unique_ptr pxbuf(new unsigned[len]); + + res.x += editor_._m_char_by_pixels(ent.begin, len, pxbuf.get(), str_px, scrpos.x, _m_is_right_text(ent)); res.x += static_cast(ent.begin - str.begin); return res; } - xbeg += static_cast(str_w); + scrpos.x -= str_px; } res.x = static_cast(editor_.textbase_.getline(res.y).size()); return res; @@ -890,7 +859,7 @@ namespace nana{ namespace widgets } //Use the caret line for the offset line when caret is in front of current offset line. - if (off_primary > points.caret.y || (off_primary == points.caret.y && (off_secondary > caret_secondary))) + if (off_primary > points.caret.y || ((off_primary == points.caret.y) && (off_secondary > caret_secondary))) { //Use the line which was specified by points.caret for the first line. _m_set_offset_by_secondary(points.caret.y, caret_secondary); @@ -904,7 +873,7 @@ namespace nana{ namespace widgets return false; //Do not adjust the offset line if the caret line does not reach the bottom line. - if (points.caret.y < bottom.x || (points.caret.y == bottom.x && caret_secondary <= bottom.y)) + if (points.caret.y < bottom.x || ((points.caret.y == bottom.x) && (caret_secondary <= bottom.y))) return false; _m_advance_secondary(points.caret.y, caret_secondary, -static_cast(scrlines - 1), bottom); @@ -950,14 +919,10 @@ namespace nana{ namespace widgets void _m_set_offset_by_secondary(std::size_t primary, std::size_t secondary) { - std::size_t lines = 0; - - for_each(linemtr_.begin(), linemtr_.begin() + primary, [&lines](const line_metrics& mtr) mutable - { - lines += mtr.take_lines; - }); + for (auto i = linemtr_.begin(), end = linemtr_.begin() + primary; i != end; ++i) + secondary += i->take_lines; - editor_.points_.offset.y = static_cast(lines + secondary); + editor_.points_.offset.y = static_cast(secondary); } bool _m_advance_secondary(std::size_t primary, std::size_t secondary, int distance, nana::upoint& new_sec) @@ -1059,15 +1024,14 @@ namespace nana{ namespace widgets secondary_pos.y = 0; unsigned len = 0; - auto & mtr = linemtr_[charpos.y]; - for (auto & ts : mtr.line_sections) + for (auto & ts : linemtr_[charpos.y].line_sections) { len = static_cast(ts.end - ts.begin); if (len >= secondary_pos.x) return true; ++secondary_pos.y; - secondary_pos.x -= static_cast(len); + secondary_pos.x -= len; } --secondary_pos.y; secondary_pos.x = len; @@ -1099,39 +1063,31 @@ namespace nana{ namespace widgets //secondary, index of line that the text was splitted into multilines. std::size_t _m_textline_from_screen(int y, std::size_t & secondary) const { - const auto & textbase = editor_.textbase_; - const auto & text_area = editor_.text_area_; - auto & points = editor_.points_; + const int text_area_top = editor_.text_area_.area.y; + const int offset_top = editor_.points_.offset.y; - secondary = 0; - - if (0 == textbase.lines()) - return 0; - std::size_t screen_line; - if (y < text_area.area.y) + if (0 == editor_.textbase_.lines()) { - screen_line = (text_area.area.y - y) / static_cast(editor_.line_height()); - if (screen_line > static_cast(points.offset.y)) + secondary = 0; + return 0; + } + + std::size_t screen_line; + if (y < text_area_top) + { + screen_line = (text_area_top - y) / static_cast(editor_.line_height()); + if (screen_line > static_cast(offset_top)) screen_line = 0; else - screen_line = static_cast(points.offset.y) - screen_line; + screen_line = static_cast(offset_top)-screen_line; } else - screen_line = static_cast((y - text_area.area.y) / static_cast(editor_.line_height()) + points.offset.y); - - std::size_t primary = 0; - for (auto & mtr : linemtr_) - { - if (mtr.take_lines > screen_line) - { - secondary = screen_line; - return primary; - } - else - screen_line -= mtr.take_lines; + screen_line = static_cast((y - text_area_top) / static_cast(editor_.line_height()) + offset_top); + + auto primary = _m_textline(screen_line, secondary); + if (primary < linemtr_.size()) + return primary; - ++primary; - } secondary = linemtr_.back().line_sections.size() - 1; return linemtr_.size() - 1; } @@ -1140,10 +1096,154 @@ namespace nana{ namespace widgets std::vector linemtr_; }; //end class behavior_linewrapped + + struct keyword_scheme + { + ::nana::color fgcolor; + ::nana::color bgcolor; + }; + + struct keyword_desc + { + ::nana::string text; + std::string scheme; + bool case_sensitive; + bool whole_word_matched; + + keyword_desc(const ::nana::string& txt, const std::string& schm, bool cs, bool wwm) + : text(txt), scheme(schm), case_sensitive(cs), whole_word_matched(wwm) + {} + }; + + struct text_editor::keywords + { + std::map> schemes; + std::deque kwbase; + }; + + struct entity + { + const ::nana::char_t* begin; + const ::nana::char_t* end; + const keyword_scheme * scheme; + }; + + class text_editor::keyword_parser + { + public: + void parse(const ::nana::string& text, const keywords* kwptr) + { + if (text.empty()) + return; + + std::vector entities; + + auto test_whole_word = [&text](std::size_t pos, std::size_t len) + { + if (pos) + { + auto chr = text[pos - 1]; + if ((std::iswalpha(chr) && !std::isspace(chr)) || chr == '_') + return false; + } + + if (pos + len < text.size()) + { + auto chr = text[pos + len]; + if ((std::iswalpha(chr) && !std::isspace(chr)) || chr == '_') + return false; + } + + return true; + }; + + ::nana::cistring cistr; + for (auto & ds : kwptr->kwbase) + { + std::size_t pos; + const ::nana::char_t* begin; + const ::nana::char_t* end; + if (ds.case_sensitive) + { + pos = text.find(ds.text); + if (pos == text.npos) + continue; + + if (ds.whole_word_matched) + { + if (!test_whole_word(pos, ds.text.size())) + continue; + } + + begin = text.data() + pos; + end = begin + ds.text.size(); + } + else + { + if (cistr.empty()) + cistr.append(text.data(), text.size()); + + pos = cistr.find(ds.text.data()); + if (pos == cistr.npos) + continue; + + if (ds.whole_word_matched) + { + if (!test_whole_word(pos, ds.text.size())) + continue; + } + + begin = text.data() + pos; + end = begin + ds.text.size(); + } + + auto ki = kwptr->schemes.find(ds.scheme); + if (ki != kwptr->schemes.end() && ki->second) + { + schemes_.emplace(ds.scheme, ki->second); + entities.emplace_back(); + auto & last = entities.back(); + last.begin = begin; + last.end = end; + last.scheme = ki->second.get(); + } + } + + if (!entities.empty()) + { + std::sort(entities.begin(), entities.end(), [](const entity& a, const entity& b) + { + return (a.begin < b.begin); + }); + + auto previous = entities.begin(); + auto i = previous + 1; + while(i != entities.end()) + { + if (previous->end > i->begin) + i = entities.erase(i); + else + ++i; + } + } + + entities_.swap(entities); + } + + const std::vector& entities() const + { + return entities_; + } + private: + std::vector entities_; + std::map> schemes_; + }; + //class text_editor - text_editor::text_editor(window wd, graph_reference graph) + text_editor::text_editor(window wd, graph_reference graph, const text_editor_scheme* schm) : behavior_(new behavior_normal(*this)), - window_(wd), graph_(graph) + window_(wd), graph_(graph), + scheme_(schm), keywords_(new keywords) { text_area_.area = graph.size(); text_area_.captured = false; @@ -1154,8 +1254,17 @@ namespace nana{ namespace widgets select_.dragged = false; API::create_caret(wd, 1, line_height()); - API::background(wd, 0xFFFFFF); - API::foreground(wd, 0x000000); + API::bgcolor(wd, colors::white); + API::fgcolor(wd, colors::black); + + text_area_.border_renderer = [this](graph_reference graph, const ::nana::color& bgcolor) + { + if (!API::widget_borderless(this->window_)) + { + ::nana::facade facade; + facade.draw(graph, bgcolor, API::fgcolor(this->window_), API::window_size(this->window_), API::element_state(this->window_)); + } + }; } text_editor::~text_editor() @@ -1163,15 +1272,73 @@ namespace nana{ namespace widgets //For instance of unique_ptr pimpl idiom. } - bool text_editor::respone_keyboard(nana::char_t key, bool enterable) //key is a character of ASCII code + void text_editor::set_highlight(const std::string& name, const ::nana::color& fgcolor, const ::nana::color& bgcolor) { - if (keyboard::end_of_text == key) + if (fgcolor.invisible() && fgcolor.invisible()) { - copy(); - return false; + keywords_->schemes.erase(name); + return; } - if (attributes_.editable && enterable) + auto sp = std::make_shared(); + sp->fgcolor = fgcolor; + sp->bgcolor = bgcolor; + keywords_->schemes[name] = sp; + } + + void text_editor::erase_highlight(const std::string& name) + { + keywords_->schemes.erase(name); + } + + void text_editor::set_keyword(const ::nana::string& kw, const std::string& name, bool case_sensitive, bool whole_word_matched) + { + for (auto & ds : keywords_->kwbase) + { + if (ds.text == kw) + { + ds.scheme = name; + ds.case_sensitive = case_sensitive; + ds.whole_word_matched = whole_word_matched; + return; + } + } + keywords_->kwbase.emplace_back(kw, name, case_sensitive, whole_word_matched); + } + + void text_editor::erase_keyword(const ::nana::string& kw) + { + auto i = std::find_if(keywords_->kwbase.begin(), keywords_->kwbase.end(), [&kw](keyword_desc& kd){ + return (kd.text == kw); + }); + + if (i != keywords_->kwbase.end()) + keywords_->kwbase.erase(i); + } + + void text_editor::set_accept(std::function pred) + { + attributes_.pred_acceptive = std::move(pred); + } + + void text_editor::set_accept(accepts acceptive) + { + attributes_.acceptive = acceptive; + } + + bool text_editor::respone_keyboard(char_type key) //key is a character of ASCII code + { + switch (key) + { + case keyboard::end_of_text: + copy(); + return false; + case keyboard::select_all: + select(true); + return true; + } + + if (attributes_.editable && API::window_enabled(window_) && (!attributes_.pred_acceptive || attributes_.pred_acceptive(key))) { switch (key) { @@ -1193,6 +1360,9 @@ namespace nana{ namespace widgets undo(false); break; default: + if (!_m_accepts(key)) + return false; + if (key > 0x7F || (32 <= key && key <= 126)) put(key); else if (sizeof(nana::char_t) == sizeof(char)) @@ -1243,7 +1413,7 @@ namespace nana{ namespace widgets return false; } - void text_editor::border_renderer(std::function f) + void text_editor::border_renderer(std::function f) { text_area_.border_renderer = f; } @@ -1252,7 +1422,7 @@ namespace nana{ namespace widgets { if (!textbase_.load(fs)) return false; - + _m_reset(); behavior_->pre_calc_lines(width_pixels()); render(API::is_focus_window(window_)); @@ -1267,7 +1437,7 @@ namespace nana{ namespace widgets text_area_.area = r; if(attributes_.enable_counterpart) - attributes_.counterpart.make(r.width, r.height); + attributes_.counterpart.make({ r.width, r.height }); behavior_->pre_calc_lines(width_pixels()); _m_scrollbar(); @@ -1299,7 +1469,7 @@ namespace nana{ namespace widgets if (attributes_.multi_lines == ml) return false; - + attributes_.multi_lines = ml; if (!ml) @@ -1323,7 +1493,7 @@ namespace nana{ namespace widgets { attributes_.enable_counterpart = enb; if(enb) - attributes_.counterpart.make(text_area_.area.width, text_area_.area.height); + attributes_.counterpart.make({ text_area_.area.width, text_area_.area.height }); else attributes_.counterpart.release(); } @@ -1332,7 +1502,7 @@ namespace nana{ namespace widgets { undo_.enable(enb); } - + bool text_editor::undo_enabled() const { return undo_.enabled(); @@ -1373,19 +1543,18 @@ namespace nana{ namespace widgets if((false == enter) && (false == text_area_.captured)) API::window_cursor(window_, nana::cursor::arrow); - if(API::focus_window() != window_) - { - render(false); - return true; - } - return false; + if(API::focus_window() == window_) + return false; + + render(false); + return true; } bool text_editor::mouse_down(bool left_button, const point& scrpos) { if (!hit_text_area(scrpos)) return false; - + if(left_button) { API::capture_window(window_, true); @@ -1405,6 +1574,7 @@ namespace nana{ namespace widgets else select_.mode_selection = selection::mode_no_selected; } + text_area_.border_renderer(graph_, _m_bgcolor()); return true; } @@ -1414,7 +1584,7 @@ namespace nana{ namespace widgets cursor cur = cursor::iterm; if ((!hit_text_area(scrpos)) && (!text_area_.captured)) cur = cursor::arrow; - + API::window_cursor(window_, cur); if(left_button) @@ -1472,12 +1642,11 @@ namespace nana{ namespace widgets bool text_editor::getline(std::size_t pos, nana::string& text) const { - if(pos < textbase_.lines()) - { - text = textbase_.getline(pos); - return true; - } - return false; + if (textbase_.lines() <= pos) + return false; + + text = textbase_.getline(pos); + return true; } void text_editor::text(nana::string str) @@ -1507,27 +1676,27 @@ namespace nana{ namespace widgets //Set caret position through text coordinate void text_editor::move_caret(const upoint& crtpos) { - if(API::is_focus_window(window_)) + if (!API::is_focus_window(window_)) + return; + + const unsigned line_pixels = line_height(); + auto pos = this->behavior_->caret_to_screen(crtpos); + const int end_y = pos.y + static_cast(line_pixels); + + bool visible = false; + if (hit_text_area(pos) && (end_y > text_area_.area.y)) { - const unsigned line_pixels = line_height(); - auto pos = this->behavior_->caret_to_screen(crtpos); - const int end_y = pos.y + static_cast(line_pixels); - - bool visible = false; - if (hit_text_area(pos) && (end_y > text_area_.area.y)) - { - visible = true; - if (end_y > _m_endy()) - API::caret_size(window_, nana::size(1, line_pixels - (end_y - _m_endy()))); - else if (API::caret_size(window_).height != line_pixels) - reset_caret_height(); - } - - API::caret_visible(window_, visible); - - if(visible) - API::caret_pos(window_, pos.x, pos.y); + visible = true; + if (end_y > _m_endy()) + API::caret_size(window_, nana::size(1, line_pixels - (end_y - _m_endy()))); + else if (API::caret_size(window_).height != line_pixels) + reset_caret_height(); } + + API::caret_visible(window_, visible); + + if(visible) + API::caret_pos(window_, pos); } void text_editor::move_caret_end() @@ -1577,11 +1746,12 @@ namespace nana{ namespace widgets if(select_.b.y) --select_.b.y; select_.b.x = static_cast(textbase_.getline(select_.b.y).size()); select_.mode_selection = selection::mode_method_selected; + render(true); return true; } select_.mode_selection = selection::mode_no_selected; - if(_m_cancel_select(0)) + if (_m_cancel_select(0)) { render(true); return true; @@ -1629,44 +1799,52 @@ namespace nana{ namespace widgets bool text_editor::mask(nana::char_t ch) { - if(mask_char_ != ch) - { - mask_char_ = ch; - return true; - } - return false; + if (mask_char_ == ch) + return false; + + mask_char_ = ch; + return true; } unsigned text_editor::width_pixels() const { + unsigned exclude_px; if (attributes_.line_wrapped) - return (text_area_.area.width > text_area_.vscroll ? text_area_.area.width - text_area_.vscroll : 0); + exclude_px = text_area_.vscroll; + else + exclude_px = API::caret_size(window_).width; - auto caret_px = API::caret_size(window_).width; - return (text_area_.area.width > caret_px ? text_area_.area.width - caret_px : 0); + return (text_area_.area.width > exclude_px ? text_area_.area.width - exclude_px : 0); + } + + window text_editor::window_handle() const + { + return window_; } void text_editor::draw_scroll_rectangle() { if(text_area_.vscroll && text_area_.hscroll) { - graph_.rectangle( text_area_.area.x + static_cast(text_area_.area.width - text_area_.vscroll), - text_area_.area.y + static_cast(text_area_.area.height - text_area_.hscroll), - text_area_.vscroll, text_area_.hscroll, nana::color::button_face, true); + graph_.rectangle({ text_area_.area.right() - static_cast(text_area_.vscroll), text_area_.area.bottom() - static_cast(text_area_.hscroll), text_area_.vscroll, text_area_.hscroll }, + true, colors::button_face); } } void text_editor::render(bool has_focus) { - const nana::color_t bgcolor = _m_bgcolor(); + const auto bgcolor = _m_bgcolor(); - nana::color_t fgcolor = API::foreground(window_); + auto fgcolor = scheme_->foreground.get_color(); if (!API::window_enabled(window_)) - fgcolor = nana::paint::graphics::mix(bgcolor, fgcolor, 0.5); + fgcolor.blend(bgcolor, 0.5); + + if (API::widget_borderless(window_)) + graph_.rectangle(false, bgcolor); //Draw background if(attributes_.enable_background) - graph_.rectangle(text_area_.area, bgcolor, true); + graph_.rectangle(text_area_.area, true, bgcolor); if(ext_renderer_.background) ext_renderer_.background(graph_, text_area_.area, bgcolor); @@ -1674,19 +1852,22 @@ namespace nana{ namespace widgets if(attributes_.counterpart && !text_area_.area.empty()) attributes_.counterpart.bitblt(nana::rectangle(0, 0, text_area_.area.width, text_area_.area.height), graph_, nana::point(text_area_.area.x, text_area_.area.y)); - if((false == textbase_.empty()) || has_focus) + //Render the content when the text isn't empty or the window has got focus, + //otherwise draw the tip string. + if ((false == textbase_.empty()) || has_focus) behavior_->render(fgcolor); - else - _m_draw_tip_string(); + else //Draw tip string + graph_.string({ text_area_.area.x - points_.offset.x, text_area_.area.y }, attributes_.tip_string, { 0x78, 0x78, 0x78 }); draw_scroll_rectangle(); + text_area_.border_renderer(graph_, bgcolor); } //public: void text_editor::put(nana::string text) { auto undo_ptr = std::unique_ptr{ new undo_input_text(*this, text) }; - + undo_ptr->set_selected_text(); //Do not forget to assign the _m_erase_select() to caret @@ -1713,11 +1894,11 @@ namespace nana{ namespace widgets { auto undo_ptr = std::unique_ptr < undo_input_text > {new undo_input_text(*this, nana::string(1, c))}; bool refresh = (select_.a != select_.b); - + undo_ptr->set_selected_text(); if(refresh) points_.caret = _m_erase_select(); - + undo_ptr->set_caret_pos(); undo_.push(std::move(undo_ptr)); @@ -1726,7 +1907,7 @@ namespace nana{ namespace widgets behavior_->pre_calc_line(points_.caret.y, width_pixels()); points_.caret.x ++; - if(refresh || _m_draw(c, secondary_before)) + if (refresh || _m_update_caret_line(secondary_before)) render(true); else draw_scroll_rectangle(); @@ -1753,7 +1934,20 @@ namespace nana{ namespace widgets { nana::string text; nana::system::dataexch().get(text); - + + //If it is required check the acceptable + if (accepts::no_restrict != attributes_.acceptive) + { + for (auto i = text.begin(); i != text.end(); ++i) + { + if (!_m_accepts(*i)) + { + text.erase(i, text.end()); + break; + } + } + } + if (!text.empty()) put(std::move(text)); } @@ -1818,9 +2012,9 @@ namespace nana{ namespace widgets { if(textbase_.getline(points_.caret.y).size() > points_.caret.x) { - points_.caret.x++; + ++points_.caret.x; } - else if(textbase_.lines() && (points_.caret.y < textbase_.lines() - 1)) + else if(points_.caret.y + 1 < textbase_.lines()) { //Move to next line points_.caret.x = 0; ++ points_.caret.y; @@ -1940,6 +2134,7 @@ namespace nana{ namespace widgets void text_editor::move_left() { + bool pending = true; if(_m_cancel_select(1) == false) { if(points_.caret.x) @@ -1949,27 +2144,19 @@ namespace nana{ namespace widgets if(is_incomplete(textbase_.getline(points_.caret.y), points_.caret.x)) --points_.caret.x; #endif - bool adjust_y = false; - if (attributes_.line_wrapped) - adjust_y = behavior_->adjust_caret_into_screen(); - - bool adjust_x = _m_move_offset_x_while_over_border(-2); - - if (adjust_x || adjust_y) - render(true); - } - else if(points_.caret.y) - { //Move to previous line - points_.caret.x = static_cast(textbase_.getline(-- points_.caret.y).size()); - if (behavior_->adjust_caret_into_screen()) + pending = false; + bool adjust_y = (attributes_.line_wrapped && behavior_->adjust_caret_into_screen()); + if (_m_move_offset_x_while_over_border(-2) || adjust_y) render(true); } + else if (points_.caret.y) //Move to previous line + points_.caret.x = static_cast(textbase_.getline(--points_.caret.y).size()); + else + pending = false; } - else - { - behavior_->adjust_caret_into_screen(); + + if (pending && behavior_->adjust_caret_into_screen()) render(true); - } _m_scrollbar(); points_.xpos = points_.caret.x; @@ -1977,6 +2164,7 @@ namespace nana{ namespace widgets void text_editor::move_right() { + bool do_render = false; if(_m_cancel_select(2) == false) { nana::string lnstr = textbase_.getline(points_.caret.y); @@ -1988,23 +2176,20 @@ namespace nana{ namespace widgets ++points_.caret.x; #endif bool adjust_y = (attributes_.line_wrapped && behavior_->adjust_caret_into_screen()); - if (_m_move_offset_x_while_over_border(2) || adjust_y) - render(true); + do_render = (_m_move_offset_x_while_over_border(2) || adjust_y); } else if(textbase_.lines() && (points_.caret.y < textbase_.lines() - 1)) { //Move to next line points_.caret.x = 0; ++ points_.caret.y; - - if (behavior_->adjust_caret_into_screen()) - render(true); + do_render = behavior_->adjust_caret_into_screen(); } } else - { - if (behavior_->adjust_caret_into_screen()) - render(true); - } + do_render = behavior_->adjust_caret_into_screen(); + + if (do_render) + render(true); _m_scrollbar(); points_.xpos = points_.caret.x; @@ -2040,9 +2225,26 @@ namespace nana{ namespace widgets return false; } - nana::color_t text_editor::_m_bgcolor() const + bool text_editor::_m_accepts(char_type ch) const { - return (!API::window_enabled(window_) ? 0xE0E0E0 : API::background(window_)); + if (accepts::no_restrict == attributes_.acceptive) + return true; + + //Checks the input whether it meets the requirement for a numeric. + auto str = text(); + + if ('+' == ch || '-' == ch) + return str.empty(); + + if ((accepts::real == attributes_.acceptive) && ('.' == ch)) + return (str.find(L'.') == str.npos); + + return ('0' <= ch && ch <= '9'); + } + + ::nana::color text_editor::_m_bgcolor() const + { + return (!API::window_enabled(window_) ? color{ 0xE0, 0xE0, 0xE0 } : API::bgcolor(window_)); } bool text_editor::_m_scroll_text(bool vert) @@ -2265,7 +2467,6 @@ namespace nana{ namespace widgets if(a.y != b.y) { textbase_.erase(a.y, a.x, nana::string::npos); - textbase_.erase(a.y + 1, b.y - a.y - 1); textbase_.erase(a.y + 1, 0, b.x); @@ -2291,7 +2492,7 @@ namespace nana{ namespace widgets nana::upoint a, b; if (!_m_get_sort_select_points(a, b)) return false; - + if(a.y != b.y) { text = textbase_.getline(a.y).substr(a.x); @@ -2326,9 +2527,10 @@ namespace nana{ namespace widgets begin = text.find_first_not_of(STR("\r\n"), pos + 1); //The number of new lines minus one - auto n = std::count(text.data() + pos, text.data() + (begin == text.npos ? text.size() : begin), '\n') - 1; - for (decltype(n) i = 0; i < n; ++i) - lines.emplace_back(0, 0); + const auto chp_end = text.data() + (begin == text.npos ? text.size() : begin); + for (auto chp = text.data() + (pos + 2); chp != chp_end; ++chp) + if (*chp == '\n') + lines.emplace_back(0, 0); if (text.npos == begin) { @@ -2371,25 +2573,18 @@ namespace nana{ namespace widgets return static_cast(tabs * graph_.text_extent_size(ws).width * text_area_.tab_space); } - nana::size text_editor::_m_text_extent_size(const char_type* str) const - { - return _m_text_extent_size(str, nana::strlen(str)); - } - nana::size text_editor::_m_text_extent_size(const char_type* str, size_type n) const { - if(graph_) + if (!graph_) + return{}; + + if(mask_char_) { - if(mask_char_) - { - nana::string maskstr; - maskstr.append(n, mask_char_); - return graph_.text_extent_size(maskstr); - } - else - return graph_.text_extent_size(str, static_cast(n)); + nana::string maskstr; + maskstr.append(n, mask_char_); + return graph_.text_extent_size(maskstr); } - return{}; + return graph_.text_extent_size(str, static_cast(n)); } //_m_move_offset_x_while_over_border @@ -2420,8 +2615,8 @@ namespace nana{ namespace widgets width += text_area_.area.x; if(static_cast(width) - points_.offset.x >= _m_endx()) { //Out of screen text area - points_.offset.x = width - _m_endx() + 1; - string_type::size_type rest_size = lnstr.size() - points_.caret.x; + points_.offset.x = static_cast(width) -_m_endx() + 1; + auto rest_size = lnstr.size() - points_.caret.x; points_.offset.x += static_cast(_m_text_extent_size(lnstr.c_str() + points_.caret.x, (rest_size >= static_cast(many) ? static_cast(many) : rest_size)).width); return true; } @@ -2500,21 +2695,85 @@ namespace nana{ namespace widgets return static_cast(text_area_.area.y + text_area_.area.height - text_area_.hscroll); } - void text_editor::_m_draw_tip_string() const + void text_editor::_m_draw_parse_string(const keyword_parser& parser, bool rtl, ::nana::point pos, const ::nana::color& fgcolor, const ::nana::char_t* str, std::size_t len) const { - graph_.string(text_area_.area.x - points_.offset.x, text_area_.area.y, 0x787878, attributes_.tip_string); + graph_.set_text_color(fgcolor); + graph_.string(pos, str, len); + if (parser.entities().empty()) + return; + + std::unique_ptr glyph_px(new unsigned[len]); + graph_.glyph_pixels(str, len, glyph_px.get()); + auto glyphs = glyph_px.get(); + + auto px_h = line_height(); + auto px_w = std::accumulate(glyphs, glyphs + len, unsigned{}); + + ::nana::paint::graphics canvas; + canvas.make({ px_w, px_h }); + canvas.typeface(graph_.typeface()); + ::nana::point canvas_text_pos; + + auto ent_pos = pos; + const auto str_end = str + len; + auto & entities = parser.entities(); + + for (auto & ent : entities) + { + const ::nana::char_t* ent_begin = nullptr; + + int ent_off = 0; + if (str <= ent.begin && ent.begin < str_end) + { + ent_begin = ent.begin; + ent_off = std::accumulate(glyphs, glyphs + (ent.begin - str), 0); + } + else if (ent.begin <= str && str < ent.end) + ent_begin = str; + + if (ent_begin) + { + auto ent_end = (ent.end < str_end ? ent.end : str_end); + auto ent_pixels = std::accumulate(glyphs + (ent_begin - str), glyphs + (ent_end - str), unsigned{}); + + if (ent.scheme->bgcolor.invisible()) + canvas.set_color(_m_bgcolor()); + else + canvas.set_color(ent.scheme->bgcolor); + canvas.rectangle(true); + + if (ent.scheme->fgcolor.invisible()) + canvas.set_text_color(fgcolor); + else + canvas.set_text_color(ent.scheme->fgcolor); + + ent_pos.x += ent_off; + + if (rtl) + { + //draw the whole text if it is a RTL text, because Arbic language is transformable. + canvas.string({}, str, len); + graph_.bitblt({ ent_pos, ::nana::size{ ent_pixels, canvas.height() } }, canvas, ::nana::point{ ent_off, 0 }); + } + else + { + canvas.string({}, ent_begin, ent_end - ent_begin); + graph_.bitblt({ ent_pos, ::nana::size{ ent_pixels, canvas.height() } }, canvas); + } + } + } } - void text_editor::_m_draw_string(int top, nana::color_t color, const nana::upoint& str_pos, const nana::string& linestr, bool if_mask) const + void text_editor::_m_draw_string(int top, const ::nana::color& clr, const nana::upoint& str_pos, const nana::string& linestr, bool if_mask) const { - int x = text_area_.area.x - points_.offset.x; - int xend = text_area_.area.x + static_cast(text_area_.area.width); + ::nana::point text_pos{ text_area_.area.x - points_.offset.x, top }; + const int xend = text_area_.area.x + static_cast(text_area_.area.width); if (if_mask && mask_char_) { nana::string maskstr; maskstr.append(linestr.size(), mask_char_); - graph_.string(x, top, color, maskstr); + graph_.string(text_pos, maskstr, clr); return; } @@ -2522,12 +2781,19 @@ namespace nana{ namespace widgets std::vector reordered; bidi.linestr(linestr.c_str(), linestr.size(), reordered); + //Parse highlight keywords + keyword_parser parser; + parser.parse(linestr, keywords_.get()); + auto whitespace_w = graph_.text_extent_size(STR(" "), 1).width; const auto line_h_pixels = line_height(); //The line of text is in the range of selection nana::upoint a, b; + graph_.set_text_color(clr); + + graph_.set_color(scheme_->selection.get_color()); //The text is not selected or the whole line text is selected if ((!_m_get_sort_select_points(a, b)) || (select_.a.y != str_pos.y && select_.b.y != str_pos.y)) @@ -2538,31 +2804,36 @@ namespace nana{ namespace widgets std::size_t len = ent.end - ent.begin; unsigned str_w = graph_.text_extent_size(ent.begin, len).width; - if ((x + static_cast(str_w) > text_area_.area.x) && (x < xend)) + if ((text_pos.x + static_cast(str_w) > text_area_.area.x) && (text_pos.x < xend)) { if (selected) { - color = 0xFFFFFF; - graph_.rectangle(x, top, str_w, line_h_pixels, 0x3399FF, true); + graph_.set_text_color(scheme_->selection_text.get_color()); + graph_.rectangle({ text_pos, { str_w, line_h_pixels } }, true); + graph_.string(text_pos, ent.begin, len); } - - graph_.string(x, top, color, ent.begin, len); + else + _m_draw_parse_string(parser, _m_is_right_text(ent), text_pos, clr, ent.begin, len); } - x += static_cast(str_w); + text_pos.x += static_cast(str_w); } if (selected) - graph_.rectangle(x, top, whitespace_w, line_h_pixels, 0x3399FF, true); + graph_.rectangle({ text_pos, { whitespace_w, line_h_pixels } }, true); } else { - auto rtl_string = [this,line_h_pixels](point strpos, nana::color_t color, const nana::char_t* str, std::size_t len, std::size_t str_px, unsigned glyph_front, unsigned glyph_selected){ - graph_.string(strpos.x, strpos.y, color, str, len); - paint::graphics graph(glyph_selected, line_h_pixels); + auto rtl_string = [this, line_h_pixels, &parser, &clr](point strpos, const nana::char_t* str, std::size_t len, std::size_t str_px, unsigned glyph_front, unsigned glyph_selected){ + this->_m_draw_parse_string(parser, true, strpos, clr, str, len); + + //Draw selected part + paint::graphics graph({ glyph_selected, line_h_pixels }); graph.typeface(this->graph_.typeface()); - graph.rectangle(0x3399FF, true); + graph.rectangle(true, scheme_->selection.get_color()); int sel_xpos = static_cast(str_px - (glyph_front + glyph_selected)); - graph.string(-sel_xpos, 0, 0xFFFFFF, str, len); + + graph_.set_text_color(scheme_->selection_text.get_color()); + graph.string({-sel_xpos, 0}, str, len); graph_.bitblt(nana::rectangle(strpos.x + sel_xpos, strpos.y, glyph_selected, line_h_pixels), graph); }; @@ -2573,24 +2844,27 @@ namespace nana{ namespace widgets { std::size_t len = ent.end - ent.begin; unsigned str_w = graph_.text_extent_size(ent.begin, len).width; - if ((x + static_cast(str_w) > text_area_.area.x) && (x < xend)) + if ((text_pos.x + static_cast(str_w) > text_area_.area.x) && (text_pos.x < xend)) { std::size_t pos = ent.begin - strbeg + str_pos.x; + const auto str_end = pos + len; - if (pos + len <= a.x || pos >= b.x) + //NOT selected or seleceted all + if ((str_end <= a.x || pos >= b.x) || (a.x <= pos && str_end <= b.x)) { - //NOT selected - graph_.string(x, top, color, ent.begin, len); + //selected all + if (a.x <= pos && str_end <= b.x) + { + graph_.rectangle({ text_pos, { str_w, line_h_pixels } }, true); + graph_.set_text_color(scheme_->selection_text.get_color()); + graph_.string(text_pos, ent.begin, len); + } + else + _m_draw_parse_string(parser, false, text_pos, clr, ent.begin, len); } - else if (a.x <= pos && pos + len <= b.x) - { - //Whole selected - graph_.rectangle(x, top, str_w, line_h_pixels, 0x3399FF, true); - graph_.string(x, top, 0xFFFFFF, ent.begin, len); - } - else if (pos <= a.x && a.x < pos + len) + else if (pos <= a.x && a.x < str_end) { //Partial selected - int endpos = static_cast(b.x < pos + len ? b.x : pos + len); + int endpos = static_cast(b.x < str_end ? b.x : str_end); std::unique_ptr pxbuf_ptr(new unsigned[len]); unsigned * pxbuf = pxbuf_ptr.get(); if (graph_.glyph_pixels(ent.begin, len, pxbuf)) @@ -2598,40 +2872,54 @@ namespace nana{ namespace widgets auto head_w = std::accumulate(pxbuf, pxbuf + (a.x - pos), unsigned()); auto sel_w = std::accumulate(pxbuf + (a.x - pos), pxbuf + (endpos - pos), unsigned()); + graph_.set_text_color(clr); if (_m_is_right_text(ent)) { //RTL - rtl_string(point{x, top}, color, ent.begin, len, str_w, head_w, sel_w); + rtl_string(text_pos, ent.begin, len, str_w, head_w, sel_w); } else { //LTR - graph_.string(x, top, color, ent.begin, a.x - pos); + _m_draw_parse_string(parser, false, text_pos, clr, ent.begin, a.x - pos); - graph_.rectangle(x + head_w, top, sel_w, line_h_pixels, 0x3399FF, true); - graph_.string(x + head_w, top, 0xFFFFFF, ent.begin + (a.x - pos), endpos - a.x); + auto part_pos = text_pos; + part_pos.x += static_cast(head_w); - if (static_cast(endpos) < pos + len) - graph_.string(x + static_cast(head_w + sel_w), top, color, ent.begin + (endpos - pos), pos + len - endpos); + //Draw selected part + graph_.rectangle({ part_pos, { sel_w, line_h_pixels } }, true); + graph_.set_text_color(scheme_->selection_text.get_color()); + graph_.string(part_pos, ent.begin + (a.x - pos), endpos - a.x); + + if (static_cast(endpos) < str_end) + { + part_pos.x += static_cast(sel_w); + _m_draw_parse_string(parser, false, part_pos, clr, ent.begin + (endpos - pos), str_end - endpos); + } } } } - else if (pos <= b.x && b.x < pos + len) + else if (pos <= b.x && b.x < str_end) { //Partial selected int endpos = b.x; unsigned sel_w = graph_.glyph_extent_size(ent.begin, len, 0, endpos - pos).width; + if (_m_is_right_text(ent)) { //RTL - rtl_string(point{x, top}, color, ent.begin, len, str_w, 0, sel_w); + graph_.set_text_color(clr); + rtl_string(text_pos, ent.begin, len, str_w, 0, sel_w); } else { //LTR - graph_.rectangle(x, top, sel_w, line_h_pixels, 0x3399FF, true); - graph_.string(x, top, 0xFFFFFF, ent.begin, endpos - pos); - graph_.string(x + sel_w, top, color, ent.begin + (endpos - pos), pos + len - endpos); + //Draw selected part + graph_.rectangle({ text_pos, { sel_w, line_h_pixels } }, true); + graph_.set_text_color(scheme_->selection_text.get_color()); + graph_.string(text_pos, ent.begin, endpos - pos); + + _m_draw_parse_string(parser, false, text_pos + ::nana::point(static_cast(sel_w), 0), clr, ent.begin + (endpos - pos), str_end - endpos); } } } - x += static_cast(str_w); - } + text_pos.x += static_cast(str_w); + }//end for } else if (a.y == str_pos.y) { @@ -2639,40 +2927,51 @@ namespace nana{ namespace widgets { std::size_t len = ent.end - ent.begin; unsigned str_w = graph_.text_extent_size(ent.begin, len).width; - if ((x + static_cast(str_w) > text_area_.area.x) && (x < xend)) + if ((text_pos.x + static_cast(str_w) > text_area_.area.x) && (text_pos.x < xend)) { + graph_.set_text_color(clr); std::size_t pos = ent.begin - strbeg + str_pos.x; - if (pos + len <= a.x) + if ((pos + len <= a.x) || (a.x < pos)) //Not selected or selected all { - //Not selected - graph_.string(x, top, color, ent.begin, len); - } - else if (a.x < pos) - { - //Whole selected - graph_.rectangle(x, top, str_w, line_h_pixels, 0x3399FF, true); - graph_.string(x, top, 0xFFFFFF, ent.begin, len); + if (a.x < pos) + { + //Draw selected all + graph_.rectangle({ text_pos, { str_w, line_h_pixels } }, true, { 0x33, 0x99, 0xFF }); + graph_.set_text_color(scheme_->selection_text.get_color()); + graph_.string(text_pos, ent.begin, len); + } + else + _m_draw_parse_string(parser, false, text_pos, clr, ent.begin, len); } else { unsigned head_w = graph_.glyph_extent_size(ent.begin, len, 0, a.x - pos).width; if (_m_is_right_text(ent)) { //RTL - rtl_string(point{x, top}, color, ent.begin, len, str_w, head_w, str_w - head_w); + rtl_string(text_pos, ent.begin, len, str_w, head_w, str_w - head_w); } else { //LTR - graph_.string(x, top, color, ent.begin, a.x - pos); - graph_.rectangle(x + head_w, top, str_w - head_w, line_h_pixels, 0x3399FF, true); - graph_.string(x + head_w, top, 0xFFFFFF, ent.begin + a.x - pos, len - (a.x - pos)); + graph_.string(text_pos, ent.begin, a.x - pos); + + ::nana::point part_pos{ text_pos.x + static_cast(head_w), text_pos.y }; + + //Draw selected part + graph_.rectangle({ part_pos, {str_w - head_w, line_h_pixels } }, true); + graph_.set_text_color(scheme_->selection_text.get_color()); + graph_.string(part_pos, ent.begin + a.x - pos, len - (a.x - pos)); } } } - x += static_cast(str_w); + text_pos.x += static_cast(str_w); + } + + if (str_pos.y < b.y) + { + if (a.y < str_pos.y || ((a.y == str_pos.y) && (a.x <= str_pos.x ))) + graph_.rectangle({ text_pos, { whitespace_w, line_h_pixels } }, true); } - if (a.y <= static_cast(str_pos.y) && static_cast(str_pos.y) < b.y) - graph_.rectangle(x, top, whitespace_w, line_h_pixels, 0x3399FF, true); } else if (b.y == str_pos.y) { @@ -2680,42 +2979,44 @@ namespace nana{ namespace widgets { std::size_t len = ent.end - ent.begin; unsigned str_w = graph_.text_extent_size(ent.begin, len).width; - if ((x + static_cast(str_w) > text_area_.area.x) && (x < xend)) + if ((text_pos.x + static_cast(str_w) > text_area_.area.x) && (text_pos.x < xend)) { std::size_t pos = ent.begin - strbeg + str_pos.x; - + graph_.set_text_color(clr); if (pos + len <= b.x) { - graph_.rectangle(x, top, str_w, line_h_pixels, 0x3399FF, true); - graph_.string(x, top, 0xFFFFFF, ent.begin, len); + //Draw selected part + graph_.rectangle({ text_pos, { str_w, line_h_pixels } }, true); + graph_.set_text_color(scheme_->selection_text.get_color()); + graph_.string(text_pos, ent.begin, len); } else if (pos <= b.x && b.x < pos + len) { unsigned sel_w = graph_.glyph_extent_size(ent.begin, len, 0, b.x - pos).width; if (_m_is_right_text(ent)) { //RTL - rtl_string(point{x, top}, color, ent.begin, len,str_w, 0, sel_w); + rtl_string(text_pos, ent.begin, len, str_w, 0, sel_w); } else { - graph_.rectangle(x, top, sel_w, line_h_pixels, 0x3399FF, true); - graph_.string(x, top, 0xFFFFFF, ent.begin, b.x - pos); - graph_.string(x + sel_w, top, color, ent.begin + b.x - pos, len - (b.x - pos)); + //draw selected part + graph_.rectangle({ text_pos, { sel_w, line_h_pixels } }, true); + graph_.set_text_color(scheme_->selection_text.get_color()); + graph_.string(text_pos, ent.begin, b.x - pos); + + _m_draw_parse_string(parser, false, text_pos + ::nana::point(static_cast(sel_w), 0), clr, ent.begin + b.x - pos, len - (b.x - pos)); } } else - graph_.string(x, top, color, ent.begin, len); + _m_draw_parse_string(parser, false, text_pos, clr, ent.begin, len); } - x += static_cast(str_w); + text_pos.x += static_cast(str_w); } } } } - //_m_draw - //@brief: Draw a character at a position specified by caret pos. - //@return: true if beyond the border - bool text_editor::_m_draw(nana::char_t c, std::size_t secondary_before) + bool text_editor::_m_update_caret_line(std::size_t secondary_before) { if (false == behavior_->adjust_caret_into_screen()) { @@ -2753,22 +3054,22 @@ namespace nana{ namespace widgets unsigned text_editor::_m_char_by_pixels(const nana::char_t* str, std::size_t len, unsigned * pxbuf, int str_px, int pixels, bool is_rtl) { - unsigned pos = 0; //Result if (graph_.glyph_pixels(str, len, pxbuf)) { if (is_rtl) { //RTL for (std::size_t u = 0; u < len; ++u) { - int chbeg = (str_px - pxbuf[u]); + auto px = static_cast(pxbuf[u]); + auto chbeg = str_px - px; if (chbeg <= pixels && pixels < str_px) { - pos = static_cast(u); - if ((pxbuf[u] <= 1) || (pixels <= chbeg + static_cast(pxbuf[u] >> 1))) - ++pos; - break; + if ((px < 2) || (pixels <= chbeg + (px >> 1))) + return static_cast(u + 1); + + return static_cast(u); } - str_px -= pxbuf[u]; + str_px = chbeg; } } else @@ -2776,31 +3077,30 @@ namespace nana{ namespace widgets //LTR for (std::size_t u = 0; u < len; ++u) { - if (pixels < static_cast(pxbuf[u])) + auto px = static_cast(pxbuf[u]); + if (pixels < px) { - pos = static_cast(u); - if ((pxbuf[u] > 1) && (pixels > static_cast(pxbuf[u] >> 1))) - ++pos; - - break; + if ((px > 1) && (pixels > (px >> 1))) + return static_cast(u + 1); + return static_cast(u); } - pixels -= static_cast(pxbuf[u]); + pixels -= px; } } } - return pos; + return 0; } unsigned text_editor::_m_pixels_by_char(const nana::string& lnstr, std::size_t pos) const { + if (pos > lnstr.size()) + return 0; + unicode_bidi bidi; std::vector reordered; - bidi.linestr(lnstr.c_str(), lnstr.size(), reordered); + bidi.linestr(lnstr.data(), lnstr.size(), reordered); - const nana::char_t * ch = (pos <= lnstr.size() ? lnstr.c_str() + pos : nullptr); - - std::size_t pxbuf_size = 0; - std::unique_ptr pxbuf; + auto ch = lnstr.data() + pos; unsigned text_w = 0; for (auto & ent : reordered) @@ -2810,22 +3110,14 @@ namespace nana{ namespace widgets { if (_m_is_right_text(ent)) { + //Characters of some bidi languages may transform in a word. //RTL - if (len > pxbuf_size) - { - pxbuf.reset(new unsigned[len]); - pxbuf_size = len; - } - + std::unique_ptr pxbuf(new unsigned[len]); graph_.glyph_pixels(ent.begin, len, pxbuf.get()); - text_w = std::accumulate(pxbuf.get() + (ch - ent.begin), pxbuf.get() + len, text_w); + return std::accumulate(pxbuf.get() + (ch - ent.begin), pxbuf.get() + len, text_w); } - else - { - //LTR - text_w += _m_text_extent_size(ent.begin, ch - ent.begin).width; - } - break; + //LTR + return text_w + _m_text_extent_size(ent.begin, ch - ent.begin).width; } else text_w += _m_text_extent_size(ent.begin, len).width; diff --git a/source/gui/widgets/slider.cpp b/source/gui/widgets/slider.cpp index 89a33900..e0ca0442 100644 --- a/source/gui/widgets/slider.cpp +++ b/source/gui/widgets/slider.cpp @@ -3,55 +3,54 @@ namespace nana { + arg_slider::arg_slider(slider& wdg) + : widget(wdg) + {} + namespace drawerbase { namespace slider { - provider::~provider(){} - - renderer::~renderer(){} - class interior_renderer : public renderer { private: virtual void background(window wd, graph_reference graph, bool isglass) { - if(isglass == false) - graph.rectangle(API::background(wd), true); + if(!isglass) + graph.rectangle(true, API::bgcolor(wd)); } virtual void bar(window, graph_reference graph, const bar_t& bi) { //draw border - const nana::color_t dark = 0x83909F; - const nana::color_t gray = 0x9DAEC2; - - graph.rectangle_line(bi.r, - dark, dark, gray, gray); + ::nana::color lt(0x83, 0x90, 0x97), rb(0x9d,0xae,0xc2); + graph.frame_rectangle(bi.r, lt, lt, rb, rb); } virtual void adorn(window, graph_reference graph, const adorn_t& ad) { - int len = ad.bound.y - ad.bound.x; - const unsigned upperblock = ad.block - ad.block / 2; + auto len = static_cast(ad.bound.y - ad.bound.x); + const auto upperblock = ad.block - ad.block / 2; + + ::nana::color clr_from(0x84, 0xc5, 0xff), clr_trans(0x0f, 0x41, 0xcd), clr_to(0x6e, 0x96, 0xff); if(ad.horizontal) { - graph.shadow_rectangle(ad.bound.x, ad.fixedpos, len, upperblock, 0x84C5FF, 0x0F41CD, true); - graph.shadow_rectangle(ad.bound.x, ad.fixedpos + upperblock, len, ad.block - upperblock, 0x0F41CD, 0x6E96FF, true); + graph.gradual_rectangle({ ad.bound.x, ad.fixedpos, len, upperblock }, clr_from, clr_trans, true); + graph.gradual_rectangle({ ad.bound.x, ad.fixedpos + static_cast(upperblock), len, ad.block - upperblock }, clr_trans, clr_to, true); } else { - graph.shadow_rectangle(ad.fixedpos, ad.bound.x, upperblock, len, 0x84C5FF, 0x0F41CD, false); - graph.shadow_rectangle(ad.fixedpos + upperblock, ad.bound.x, ad.block - upperblock, len, 0x0F41CD, 0x6E96FF, false); + graph.gradual_rectangle({ ad.fixedpos, ad.bound.x, upperblock, len }, clr_from, clr_trans, false); + graph.gradual_rectangle({ ad.fixedpos + static_cast(upperblock), ad.bound.x, ad.block - upperblock, len }, clr_trans, clr_to, false); } } virtual void adorn_textbox(window, graph_reference graph, const nana::string& str, const nana::rectangle & r) { - graph.rectangle(r, 0xFFFFFF, false); - graph.string(r.x + 2, r.y + 1, 0xFFFFFF, str); + graph.rectangle(r, false, colors::white); + graph.string({ r.x + 2, r.y + 1 }, str, colors::white); } virtual void slider(window, graph_reference graph, const slider_t& s) @@ -67,15 +66,15 @@ namespace nana r.y = s.pos; r.height = s.scale; } - graph.round_rectangle(r, 3, 3, 0x0, true, 0xF0F0F0); + graph.round_rectangle(r, 3, 3, colors::black, true, {0xf0,0xf0,0xf0}); } }; class controller { public: - enum dir_t{DirHorizontal, DirVertical}; - enum where_t{WhereNone, WhereBar, WhereSlider}; + enum class style{horizontal, vertical}; + enum class parts{none, bar, slider}; typedef drawer_trigger::graph_reference graph_reference; @@ -88,7 +87,7 @@ namespace nana proto_.renderer = pat::cloneable(interior_renderer()); attr_.skdir = seekdir::bilateral; - attr_.dir = this->DirHorizontal; + attr_.dir = style::horizontal; attr_.vcur = 0; attr_.vmax = 10; attr_.slider_scale = 8; @@ -147,7 +146,7 @@ namespace nana void vertical(bool v) { - dir_t dir = (v ? this->DirVertical : this->DirHorizontal); + auto dir = (v ? style::vertical : style::horizontal); if(dir != attr_.dir) { @@ -158,7 +157,7 @@ namespace nana bool vertical() const { - return (this->DirVertical == attr_.dir); + return (style::vertical == attr_.dir); } void vmax(unsigned m) @@ -208,56 +207,56 @@ namespace nana attr_.adorn_pos = attr_.pos; } - where_t seek_where(int x, int y) const + parts seek_where(::nana::point pos) const { nana::rectangle r = _m_bar_area(); - if(attr_.dir == this->DirVertical) + if(style::vertical == attr_.dir) { - std::swap(x, y); + std::swap(pos.x, pos.y); std::swap(r.width, r.height); } - int pos = _m_slider_pos(); - if(pos <= x && x < pos + static_cast(attr_.slider_scale)) - return WhereSlider; + int sdpos = _m_slider_pos(); + if (sdpos <= pos.x && pos.x < sdpos + static_cast(attr_.slider_scale)) + return parts::slider; - pos = static_cast(attr_.slider_scale) / 2; + sdpos = static_cast(attr_.slider_scale) / 2; - if(pos <= x && x < pos + static_cast(r.width)) + if (sdpos <= pos.x && pos.x < sdpos + static_cast(r.width)) { - if(y < r.y + static_cast(r.height)) - return WhereBar; + if(pos.y < r.y + static_cast(r.height)) + return parts::bar; } - return WhereNone; + return parts::none; } //set_slider_pos //move the slider to a position where a mouse click on WhereBar. - bool set_slider_pos(int x, int y) + bool set_slider_pos(::nana::point pos) { - if(this->DirVertical == attr_.dir) - std::swap(x, y); + if(style::vertical == attr_.dir) + std::swap(pos.x, pos.y); - x -= _m_slider_refpos(); - if(x < 0) + pos.x -= _m_slider_refpos(); + if(pos.x < 0) return false; - if(x > static_cast(_m_scale())) - x = static_cast(_m_scale()); + if(pos.x > static_cast(_m_scale())) + pos.x = static_cast(_m_scale()); - double pos = attr_.pos; - double dx = _m_evaluate_by_seekdir(x); + double attr_pos = attr_.pos; + double dx = _m_evaluate_by_seekdir(pos.x); attr_.pos = dx; attr_.adorn_pos = dx; _m_mk_slider_value_by_pos(); - return (attr_.pos != pos); + return (attr_.pos != attr_pos); } void set_slider_refpos(::nana::point pos) { - if(this->DirVertical == attr_.dir) + if(style::vertical == attr_.dir) std::swap(pos.x, pos.y); slider_state_.trace = slider_state_.TraceCapture; @@ -291,21 +290,21 @@ namespace nana return (slider_state_.trace == slider_state_.TraceCapture); } - bool move_slider(int x, int y) + bool move_slider(const ::nana::point& pos) { - int mpos = (this->DirHorizontal == attr_.dir ? x : y); - int pos = slider_state_.snap_pos + (mpos - slider_state_.refpos.x); + int mpos = (style::horizontal == attr_.dir ? pos.x : pos.y); + int adorn_pos = slider_state_.snap_pos + (mpos - slider_state_.refpos.x); - if(pos > 0) + if (adorn_pos > 0) { int scale = static_cast(_m_scale()); - if(pos > scale) - pos = scale; + if (adorn_pos > scale) + adorn_pos = scale; } else - pos = 0; + adorn_pos = 0; - double dstpos = _m_evaluate_by_seekdir(pos); + double dstpos = _m_evaluate_by_seekdir(adorn_pos); attr_.is_draw_adorn = true; if(dstpos != attr_.pos) @@ -317,15 +316,15 @@ namespace nana return false; } - bool move_adorn(int x, int y) + bool move_adorn(const ::nana::point& pos) { - double xpos = (this->DirHorizontal == attr_.dir ? x : y); + double xpos = (style::horizontal == attr_.dir ? pos.x : pos.y); xpos -= _m_slider_refpos(); if(xpos > static_cast(_m_scale())) xpos = static_cast(_m_scale()); - int pos = static_cast(attr_.adorn_pos); + int adorn_pos = static_cast(attr_.adorn_pos); xpos = _m_evaluate_by_seekdir(xpos); attr_.adorn_pos = xpos; @@ -334,7 +333,7 @@ namespace nana if(slider_state_.trace == slider_state_.TraceNone) slider_state_.trace = slider_state_.TraceOver; - return (pos != static_cast(xpos)); + return (adorn_pos != static_cast(xpos)); } unsigned move_step(bool forward) @@ -390,7 +389,7 @@ namespace nana { auto sz = other_.graph->size(); nana::rectangle r = sz; - if(this->DirHorizontal == attr_.dir) + if(style::horizontal == attr_.dir) { r.x = attr_.slider_scale / 2 - attr_.border; r.width = (static_cast(sz.width) > (r.x << 1) ? sz.width - (r.x << 1) : 0); @@ -406,7 +405,7 @@ namespace nana unsigned _m_scale() const { nana::rectangle r = _m_bar_area(); - return ((this->DirHorizontal == attr_.dir ? r.width : r.height) - attr_.border * 2); + return ((style::horizontal == attr_.dir ? r.width : r.height) - attr_.border * 2); } double _m_evaluate_by_seekdir(double pos) const @@ -470,7 +469,7 @@ namespace nana { renderer::bar_t bar; - bar.horizontal = (this->DirHorizontal == attr_.dir); + bar.horizontal = (style::horizontal == attr_.dir); bar.border_size = attr_.border; bar.r = _m_bar_area(); @@ -499,35 +498,23 @@ namespace nana nana::string str = proto_.provider->adorn_trace(attr_.vmax, vadorn); if(str.size()) { - nana::rectangle r; nana::size ts = other_.graph->text_extent_size(str); ts.width += 6; ts.height += 2; - r.width = ts.width; - r.height = ts.height; - + int x, y; const int room = static_cast(attr_.adorn_pos); if(bar.horizontal) { - r.y = adorn.fixedpos + static_cast(adorn.block - ts.height) / 2; - if(room > static_cast(ts.width + 2)) - r.x = room - static_cast(ts.width + 2); - else - r.x = room + 2; - - r.x += this->_m_slider_refpos(); + y = adorn.fixedpos + static_cast(adorn.block - ts.height) / 2; + x = (room > static_cast(ts.width + 2) ? room - static_cast(ts.width + 2) : room + 2) + _m_slider_refpos(); } else { - r.x = (other_.graph->width() - ts.width) / 2; - if(room > static_cast(ts.height + 2)) - r.y = room - static_cast(ts.height + 2); - else - r.y = room + 2; - r.y += this->_m_slider_refpos(); + x = (other_.graph->width() - ts.width) / 2; + y = (room > static_cast(ts.height + 2) ? room - static_cast(ts.height + 2) : room + 2) + _m_slider_refpos(); } - proto_.renderer->adorn_textbox(other_.wd, *other_.graph, str, r); + proto_.renderer->adorn_textbox(other_.wd, *other_.graph, str, {x, y, ts.width, ts.height}); } } } @@ -536,7 +523,7 @@ namespace nana { renderer::slider_t s; s.pos = static_cast(attr_.pos); - s.horizontal = (this->DirHorizontal == attr_.dir); + s.horizontal = (style::horizontal == attr_.dir); s.scale = attr_.slider_scale; s.border = attr_.border; proto_.renderer->slider(other_.wd, *other_.graph, s); @@ -558,7 +545,7 @@ namespace nana struct attr_tag { seekdir skdir; - dir_t dir; + style dir; unsigned border; unsigned vmax; unsigned vcur; @@ -612,10 +599,11 @@ namespace nana void trigger::mouse_down(graph_reference, const arg_mouse& arg) { - controller_t::where_t what = impl_->seek_where(arg.pos.x, arg.pos.y); - if(controller_t::WhereBar == what || controller_t::WhereSlider == what) + using parts = controller_t::parts; + auto what = impl_->seek_where(arg.pos); + if(parts::bar == what || parts::slider == what) { - bool mkdir = impl_->set_slider_pos(arg.pos.x, arg.pos.y); + bool mkdir = impl_->set_slider_pos(arg.pos); impl_->set_slider_refpos(arg.pos); if(mkdir) { @@ -640,13 +628,13 @@ namespace nana bool mkdraw = false; if(impl_->if_trace_slider()) { - mkdraw = impl_->move_slider(arg.pos.x, arg.pos.y); + mkdraw = impl_->move_slider(arg.pos); } else { - controller_t::where_t what = impl_->seek_where(arg.pos.x, arg.pos.y); - if(controller_t::WhereNone != what) - mkdraw = impl_->move_adorn(arg.pos.x, arg.pos.y); + auto what = impl_->seek_where(arg.pos); + if(controller_t::parts::none != what) + mkdraw = impl_->move_adorn(arg.pos); else mkdraw = impl_->reset_adorn(); } diff --git a/source/gui/widgets/spinbox.cpp b/source/gui/widgets/spinbox.cpp new file mode 100644 index 00000000..94a11715 --- /dev/null +++ b/source/gui/widgets/spinbox.cpp @@ -0,0 +1,703 @@ +/* + * A Spin box widget + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 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/gui/widgets/spinbox.cpp + */ + +#include +#include +#include +#include + +namespace nana +{ + arg_spinbox::arg_spinbox(spinbox& wdg): widget(wdg) + {} + + namespace drawerbase + { + namespace spinbox + { + class event_agent + : public widgets::skeletons::textbase_event_agent_interface + { + public: + event_agent(::nana::spinbox& wdg) + : widget_(wdg) + {} + + void first_change() override{} //empty, because spinbox does not have this event. + + void text_changed() override + { + widget_.events().text_changed.emit(::nana::arg_spinbox{ widget_ }); + } + private: + ::nana::spinbox & widget_; + }; + + enum class buttons + { + none, increase, decrease + }; + + class range_interface + { + public: + virtual ~range_interface() = default; + + virtual std::wstring value() const = 0; + + //sets a new value, the diff indicates whether the new value is different from the current value. + //returns true if the new value is acceptable. + virtual bool value(const std::wstring& new_value, bool& diff) = 0; + + virtual bool check_value(const std::wstring&) const = 0; + virtual void spin(bool increase) = 0; + }; + + template + class range_numeric + : public range_interface + { + public: + range_numeric(T vbegin, T vlast, T step) + : begin_{ vbegin }, last_{ vlast }, step_{ step }, value_{ vbegin } + {} + + std::wstring value() const override + { + std::wstringstream ss; + ss << value_; + return ss.str(); + } + + bool value(const std::wstring& value_str, bool & diff) override + { + std::wstringstream ss; + ss << value_str; + + T v; + ss >> v; + if (v < begin_ || last_ < v) + return false; + + diff = (value_ != v); + value_ = v; + return true; + } + + bool check_value(const std::wstring& str) const override + { + if (str.empty()) + return true; + + auto size = str.size(); + std::size_t pos = 0; + if (str[0] == '+' || str[0] == '-') + pos = 1; + + if (std::is_same::value) + { + for (; pos < size; ++pos) + { + auto ch = str[pos]; + if (ch < '0' || '9' < ch) + return false; + } + } + else + { + bool dot = false; + for (; pos < size; ++pos) + { + auto ch = str[pos]; + if (('.' == ch) && (!dot)) + { + dot = true; + continue; + } + + if (ch < '0' || '9' < ch) + return false; + } + } + return true; + } + + void spin(bool increase) override + { + if (increase) + { + value_ += step_; + if (value_ > last_) + value_ = last_; + } + else + { + value_ -= step_; + if (value_ < begin_) + value_ = begin_; + } + } + private: + T begin_; + T last_; + T step_; + T value_; + }; + + class range_text + : public range_interface + { + public: + range_text(std::initializer_list & initlist) + { + for (auto & s : initlist) + { + texts_.emplace_back(::nana::charset(s, ::nana::unicode::utf8)); + } + } + + range_text(std::initializer_list& initlist) + : texts_(initlist) + {} + + std::wstring value() const override + { + if (texts_.empty()) + return{}; + + return texts_[pos_]; + } + + bool value(const std::wstring& value_str, bool & diff) override + { + auto i = std::find(texts_.cbegin(), texts_.cend(), value_str); + if (i != texts_.cend()) + { + diff = (*i == value_str); + pos_ = i - texts_.cbegin(); + return true; + } + return false; + } + + bool check_value(const std::wstring& str) const override + { + if (str.empty()) + return true; + + auto i = std::find_if(texts_.cbegin(), texts_.cend(), [&str](const std::wstring& value) + { + return (value.find(str) != value.npos); + }); + + return (i != texts_.cend()); + } + + void spin(bool increase) override + { + if (texts_.empty()) + return; + + if (increase) + { + ++pos_; + if (texts_.size() <= pos_) + pos_ = texts_.size() - 1; + } + else + { + --pos_; + if (texts_.size() <= pos_) + pos_ = 0; + } + } + private: + std::vector texts_; + std::size_t pos_{0}; + }; + + class implementation + { + public: + implementation() + { + //Sets a timer for continous spin when mouse button is pressed. + timer_.elapse([this] + { + range_->spin(buttons::increase == spin_stated_); + reset_text(); + API::update_window(editor_->window_handle()); + + auto intv = timer_.interval(); + if (intv > 50) + timer_.interval(intv / 2); + }); + + timer_.interval(600); + } + + void attach(::nana::widget& wdg, ::nana::paint::graphics& graph) + { + auto wd = wdg.handle(); + graph_ = &graph; + auto scheme = static_cast<::nana::widgets::skeletons::text_editor_scheme*>(API::dev::get_scheme(wd)); + editor_ = new ::nana::widgets::skeletons::text_editor(wd, graph, scheme); + editor_->multi_lines(false); + editor_->set_accept([this](::nana::char_t ch) + { + auto str = editor_->text(); + auto pos = editor_->caret().x; + if (ch == '\b') + { + if (pos > 0) + str.erase(pos - 1, 1); + } + else + str.insert(pos, 1, ch); + + return range_->check_value(str); + }); + + evt_agent_.reset(new event_agent(static_cast(wdg))); + editor_->textbase().set_event_agent(evt_agent_.get()); + + if (!range_) + range_.reset(new range_numeric(0, 100, 1)); + + reset_text(); + + API::tabstop(wd); + API::eat_tabstop(wd, true); + API::effects_edge_nimbus(wd, effects::edge_nimbus::active); + API::effects_edge_nimbus(wd, effects::edge_nimbus::over); + reset_text_area(); + } + + void detach() + { + delete editor_; + editor_ = nullptr; + } + + ::nana::string value() const + { + return range_->value(); + } + + bool value(const ::nana::string& value_str) + { + bool diff; + if (!range_->value(value_str, diff)) + return false; + + if (diff) + reset_text(); + return true; + } + + void set_range(std::unique_ptr ptr) + { + range_.swap(ptr); + + reset_text(); + } + + void modifier(std::wstring&& prefix, std::wstring&& suffix) + { + modifier_.prefix = std::move(prefix); + modifier_.suffix = std::move(suffix); + + if (editor_) + { + reset_text(); + API::update_window(editor_->window_handle()); + } + } + + void draw_spins() + { + _m_draw_spins(buttons::none); + } + + void render() + { + editor_->render(API::is_focus_window(editor_->window_handle())); + _m_draw_spins(spin_stated_); + } + + ::nana::widgets::skeletons::text_editor* editor() const + { + return editor_; + } + + void mouse_wheel(bool upwards) + { + range_->spin(!upwards); + reset_text(); + } + + bool mouse_button(const ::nana::arg_mouse& arg, bool pressed) + { + if (!pressed) + { + API::capture_window(editor_->window_handle(), false); + timer_.stop(); + timer_.interval(600); + } + + if (buttons::none != spin_stated_) + { + //Spins the value when mouse button is released + if (pressed) + { + API::capture_window(editor_->window_handle(), true); + range_->spin(buttons::increase == spin_stated_); + reset_text(); + timer_.start(); + } + else + _m_draw_spins(spin_stated_); + return true; + } + + + bool refreshed = false; + if (pressed) + refreshed = editor_->mouse_down(arg.left_button, arg.pos); + else + refreshed = editor_->mouse_up(arg.left_button, arg.pos); + + if (refreshed) + _m_draw_spins(buttons::none); + + return refreshed; + } + + bool mouse_move(bool left_button, const ::nana::point& pos) + { + if (editor_->mouse_move(left_button, pos)) + { + editor_->reset_caret(); + render(); + return true; + } + + auto btn = _m_where(pos); + if (buttons::none != btn) + { + spin_stated_ = btn; + _m_draw_spins(btn); + return true; + } + else if (buttons::none != spin_stated_) + { + spin_stated_ = buttons::none; + _m_draw_spins(buttons::none); + return true; + } + + return false; + } + + void reset_text_area() + { + auto spins_r = _m_spins_area(); + if (spins_r.x == 0) + editor_->text_area({}); + else + editor_->text_area({ 2, 2, graph_->width() - spins_r.width - 2, spins_r.height - 2 }); + } + + void reset_text() + { + if (!editor_) + return; + + if (API::is_focus_window(editor_->window_handle())) + editor_->text(range_->value()); + else + editor_->text(modifier_.prefix + range_->value() + modifier_.suffix); + + _m_draw_spins(spin_stated_); + } + private: + + ::nana::rectangle _m_spins_area() const + { + auto size = API::window_size(editor_->window_handle()); + if (size.width > 18) + return{ static_cast(size.width - 16), 0, 16, size.height }; + + return{ 0, 0, size.width, size.height }; + } + + buttons _m_where(const ::nana::point& pos) const + { + auto spins_r = _m_spins_area(); + if (spins_r.is_hit(pos)) + { + if (pos.y < spins_r.y + static_cast(spins_r.height / 2)) + return buttons::increase; + + return buttons::decrease; + } + return buttons::none; + } + + void _m_draw_spins(buttons spins) + { + auto estate = API::element_state(editor_->window_handle()); + + auto spin_r0 = _m_spins_area(); + spin_r0.height /= 2; + + auto spin_r1 = spin_r0; + spin_r1.y += static_cast(spin_r0.height); + spin_r1.height = _m_spins_area().height - spin_r0.height; + + ::nana::color bgcolor{ 3, 65, 140 }; + facade arrow; + facade button; + + auto spin_state = (buttons::increase == spins ? estate : element_state::normal); + button.draw(*graph_, bgcolor, colors::white, spin_r0, spin_state); + spin_r0.x += 5; + arrow.draw(*graph_, bgcolor, colors::white, spin_r0, spin_state); + + spin_state = (buttons::decrease == spins ? estate : element_state::normal); + button.draw(*graph_, bgcolor, colors::white, spin_r1, spin_state); + spin_r1.x += 5; + arrow.direction(direction::south); + arrow.draw(*graph_, bgcolor, colors::white, spin_r1, spin_state); + } + private: + ::nana::paint::graphics * graph_{nullptr}; + ::nana::widgets::skeletons::text_editor * editor_{nullptr}; + std::unique_ptr evt_agent_; + buttons spin_stated_{ buttons::none }; + std::unique_ptr range_; + ::nana::timer timer_; + + struct modifiers + { + std::wstring prefix; + std::wstring suffix; + }modifier_; + }; + + //class drawer + drawer::drawer() + : impl_(new implementation) + {} + + drawer::~drawer() + { + delete impl_; + } + + implementation* drawer::impl() const + { + return impl_; + } + + //Overrides drawer_trigger + void drawer::attached(widget_reference wdg, graph_reference graph) + { + impl_->attach(wdg, graph); + } + + void drawer::refresh(graph_reference) + { + impl_->render(); + } + + void drawer::focus(graph_reference, const arg_focus& arg) + { + impl_->reset_text(); + impl_->render(); + impl_->editor()->reset_caret(); + API::lazy_refresh(); + } + + void drawer::mouse_wheel(graph_reference, const arg_wheel& arg) + { + impl_->mouse_wheel(arg.upwards); + impl_->editor()->reset_caret(); + API::lazy_refresh(); + } + + void drawer::mouse_down(graph_reference, const arg_mouse& arg) + { + if (impl_->mouse_button(arg, true)) + API::lazy_refresh(); + } + + void drawer::mouse_up(graph_reference, const arg_mouse& arg) + { + if (impl_->mouse_button(arg, false)) + API::lazy_refresh(); + } + + void drawer::mouse_move(graph_reference, const arg_mouse& arg) + { + if (impl_->mouse_move(arg.left_button, arg.pos)) + API::lazy_refresh(); + } + + void drawer::mouse_leave(graph_reference, const arg_mouse&) + { + impl_->render(); + API::lazy_refresh(); + } + + void drawer::key_press(graph_reference, const arg_keyboard& arg) + { + if (impl_->editor()->move(arg.key)) + { + impl_->editor()->reset_caret(); + impl_->draw_spins(); + API::lazy_refresh(); + } + } + + void drawer::key_char(graph_reference, const arg_keyboard& arg) + { + if (impl_->editor()->respone_keyboard(arg.key)) + { + if (!impl_->value(impl_->editor()->text())) + impl_->draw_spins(); + + API::lazy_refresh(); + } + } + + void drawer::resized(graph_reference graph, const arg_resized& arg) + { + impl_->reset_text_area(); + impl_->render(); + impl_->editor()->reset_caret(); + API::lazy_refresh(); + } + } + }//end namespace drawerbase + + spinbox::spinbox() + {} + + spinbox::spinbox(window wd, bool visible) + { + this->create(wd, visible); + } + + spinbox::spinbox(window wd, const nana::rectangle& r, bool visible) + { + this->create(wd, r, visible); + } + + void spinbox::editable(bool accept) + { + internal_scope_guard lock; + auto editor = get_drawer_trigger().impl()->editor(); + if (editor) + editor->editable(accept); + } + + bool spinbox::editable() const + { + auto editor = get_drawer_trigger().impl()->editor(); + return (editor ? editor->attr().editable : false); + } + + void spinbox::range(int begin, int last, int step) + { + using namespace drawerbase::spinbox; + get_drawer_trigger().impl()->set_range(std::unique_ptr(new range_numeric(begin, last, step))); + API::refresh_window(handle()); + } + + void spinbox::range(double begin, double last, double step) + { + using namespace drawerbase::spinbox; + get_drawer_trigger().impl()->set_range(std::unique_ptr(new range_numeric(begin, last, step))); + API::refresh_window(handle()); + } + + void spinbox::range(std::initializer_list steps_utf8) + { + using namespace drawerbase::spinbox; + get_drawer_trigger().impl()->set_range(std::unique_ptr(new range_text(steps_utf8))); + API::refresh_window(handle()); + } + + void spinbox::range(std::initializer_list steps) + { + using namespace drawerbase::spinbox; + get_drawer_trigger().impl()->set_range(std::unique_ptr(new range_text(steps))); + API::refresh_window(handle()); + } + + ::nana::string spinbox::value() const + { + internal_scope_guard lock; + if (handle()) + return get_drawer_trigger().impl()->value(); + return{}; + } + + void spinbox::value(const ::nana::string& s) + { + internal_scope_guard lock; + if (handle()) + { + if (get_drawer_trigger().impl()->value(s)) + API::refresh_window(handle()); + } + } + + int spinbox::to_int() const + { + return ::nana::stoi(value()); + } + + double spinbox::to_double() const + { + return ::nana::stod(value()); + } + + void spinbox::modifier(std::wstring prefix, std::wstring suffix) + { + get_drawer_trigger().impl()->modifier(std::move(prefix), std::move(suffix)); + } + + void spinbox::modifier(const std::string & prefix_utf8, const std::string& suffix_utf8) + { + modifier(static_cast(::nana::charset(prefix_utf8, ::nana::unicode::utf8)), static_cast(::nana::charset(suffix_utf8, ::nana::unicode::utf8))); + } + + ::nana::string spinbox::_m_caption() const + { + internal_scope_guard lock; + auto editor = get_drawer_trigger().impl()->editor(); + return (editor ? editor->text() : nana::string()); + } + + void spinbox::_m_caption(::nana::string&& text) + { + internal_scope_guard lock; + auto editor = get_drawer_trigger().impl()->editor(); + if (editor) + { + editor->text(std::move(text)); + API::refresh_window(*this); + } + } +}//end namespace nana diff --git a/source/gui/widgets/tabbar.cpp b/source/gui/widgets/tabbar.cpp index 8f3df11e..9d69b7b6 100644 --- a/source/gui/widgets/tabbar.cpp +++ b/source/gui/widgets/tabbar.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -20,55 +21,44 @@ namespace nana { namespace tabbar { - event_agent_interface::~event_agent_interface() - {} - struct item_t { - window relative; + window relative{nullptr}; paint::image img; nana::string text; any value; - color_t bgcolor; - color_t fgcolor; - - item_t() - :relative(nullptr), bgcolor(nana::null_color), fgcolor(nana::null_color) - {} + ::nana::color bgcolor; + ::nana::color fgcolor; }; class def_renderer : public item_renderer { - public: - def_renderer() - : bgcolor_(0xFF000000) - {} - private: - virtual void background(graph_reference graph, const nana::rectangle& r, nana::color_t bgcolor) + virtual void background(graph_reference graph, const nana::rectangle& r, const ::nana::color& bgcolor) { if(bgcolor_ != bgcolor) { bgcolor_ = bgcolor; - dark_bgcolor_ = nana::paint::graphics::mix(bgcolor, 0, 0.9); - blcolor_ = nana::paint::graphics::mix(bgcolor, 0, 0.5); - ilcolor_ = nana::paint::graphics::mix(bgcolor, 0xFFFFFF, 0.5); + + dark_bgcolor_ = bgcolor.blend(colors::black, 0.9); + blcolor_ = bgcolor.blend(colors::black, 0.5); + ilcolor_ = bgcolor.blend(colors::white, 0.9); } - graph.rectangle(bgcolor, true); + graph.rectangle(true, bgcolor); } virtual void item(graph_reference graph, const item_t& m, bool active, state_t sta) { //* const nana::rectangle & r = m.r; - nana::color_t bgcolor; - nana::color_t blcolor; - nana::color_t dark_bgcolor; + color bgcolor; + color blcolor; + color dark_bgcolor; - if(m.bgcolor == nana::null_color) + if(m.bgcolor.invisible()) { bgcolor = bgcolor_; blcolor = blcolor_; @@ -77,122 +67,124 @@ namespace nana else { bgcolor = m.bgcolor; - blcolor = graph.mix(m.bgcolor, 0, 0.5); - dark_bgcolor = nana::paint::graphics::mix(m.bgcolor, 0, 0.9); + blcolor = m.bgcolor.blend(colors::black, 0.5); + dark_bgcolor = m.bgcolor.blend(colors::black, 0.9); } - graph.round_rectangle(r.x, r.y, r.width, r.height + 2, 3, 3, blcolor, true, 0xFFFFFF); + auto round_r = r; + round_r.height += 2; + graph.round_rectangle(round_r, 3, 3, blcolor, true, colors::white); - nana::color_t beg = bgcolor; - nana::color_t end = dark_bgcolor; + auto beg = bgcolor; + auto end = dark_bgcolor; if(active) { - if(m.bgcolor == nana::null_color) + if (m.bgcolor.invisible()) beg = ilcolor_; else - beg = nana::paint::graphics::mix(m.bgcolor, 0xFFFFFF, 0.5); + beg = m.bgcolor.blend(colors::white, 0.5); end = bgcolor; } - if(sta == item_renderer::highlight) - beg = nana::paint::graphics::mix(beg, 0xFFFFFF, 0.5); + if (sta == item_renderer::highlight) + beg = beg.blend(colors::white, 0.5); - graph.shadow_rectangle(r.x + 2, r.y + 2, r.width - 4, r.height - 2, beg, end, true); + graph.gradual_rectangle(round_r.pare_off(2), beg, end, true); } virtual void add(graph_reference graph, const nana::rectangle& r, state_t sta) { int x = r.x + (static_cast(r.width) - 14) / 2; int y = r.y + (static_cast(r.height) - 14) / 2; - nana::color_t color; + + ::nana::color clr; switch(sta) { case item_renderer::highlight: - color = 0xFFFFFF; break; + clr = { colors::white }; break; case item_renderer::press: - color = 0xA0A0A0; break; + clr = { 0xA0, 0xA0, 0xA0 }; break; case item_renderer::disable: - color = 0x808080; break; + clr = { 0x80, 0x80, 0x80 }; break; default: - color = 0xF0F0F0; + clr = { 0xF0, 0xF0, 0xF0 }; } - graph.rectangle(r, bgcolor_, true); - nana::paint::gadget::cross(graph, x, y, 14, 6, color); + graph.rectangle(r, true, bgcolor_); + nana::paint::gadget::cross(graph, x, y, 14, 6, clr); } virtual void close(graph_reference graph, const nana::rectangle& r, state_t sta) { - nana::paint::gadget::close_16_pixels(graph, r.x + (r.width - 16) / 2, r.y + (r.height - 16) / 2, 1, 0x0); - if(sta == item_renderer::highlight) - { - graph.rectangle(r, 0xA0A0A0, false); - } + nana::paint::gadget::close_16_pixels(graph, r.x + (r.width - 16) / 2, r.y + (r.height - 16) / 2, 1, colors::black); + if(item_renderer::highlight == sta) + graph.rectangle(r, false, {0xa0, 0xa0, 0xa0}); } virtual void close_fly(graph_reference graph, const nana::rectangle& r, bool active, state_t sta) { using namespace nana::paint; - nana::color_t color = (active ? 0x0 : 0x9299A4); + ::nana::color clr{ colors::black }; - if(item_renderer::highlight == sta) + if (sta == item_renderer::highlight) { - nana::color_t bgcolor = 0xCCD2DD; - graph.round_rectangle(r.x, r.y, r.width, r.height, 1, 1, 0x9DA3AB, false, 0); + ::nana::color bgcolor{ 0xCC, 0xD2, 0xDD }; + ::nana::color rect_clr{0x9d, 0xa3, 0xab}; + graph.round_rectangle(r, 1, 1, rect_clr, false, {}); nana::rectangle draw_r(r); - graph.rectangle(draw_r.pare_off(1), graph.mix(0x9DA3AB, bgcolor, 0.8), false); - graph.rectangle(draw_r.pare_off(1), graph.mix(0x9DA3AB, bgcolor, 0.4), false); - graph.rectangle(draw_r.pare_off(1), graph.mix(0x9DA3AB, bgcolor, 0.2), false); - color = 0x0; + graph.rectangle(draw_r.pare_off(1), false, rect_clr.blend(bgcolor, 0.8)); + graph.rectangle(draw_r.pare_off(1), false, rect_clr.blend(bgcolor, 0.4)); + graph.rectangle(draw_r.pare_off(1), false, rect_clr.blend(bgcolor, 0.2)); } + else if (!active) + clr = ::nana::color{ 0x92, 0x99, 0xA4 }; - int x = r.x - (16 - r.width) / 2; - int y = r.y - (16 - r.height) / 2; - - gadget::close_16_pixels(graph, x, y, 1, color); + gadget::close_16_pixels(graph, r.x - (16 - r.width) / 2, r.y - (16 - r.height) / 2, 1, clr); } virtual void back(graph_reference graph, const nana::rectangle& r, state_t sta) { using namespace nana::paint::gadget; - _m_draw_arrow(graph, r, sta, directions::to_west); + _m_draw_arrow(graph, r, sta, direction::west); } virtual void next(graph_reference graph, const nana::rectangle& r, state_t sta) { using namespace nana::paint::gadget; - _m_draw_arrow(graph, r, sta, directions::to_east); + _m_draw_arrow(graph, r, sta, direction::east); } virtual void list(graph_reference graph, const nana::rectangle& r, state_t sta) { using namespace nana::paint::gadget; - _m_draw_arrow(graph, r, sta, directions::to_south); + _m_draw_arrow(graph, r, sta, direction::south); } private: - void _m_draw_arrow(graph_reference graph, const nana::rectangle& r, state_t sta, nana::paint::gadget::directions::t dir) + void _m_draw_arrow(graph_reference graph, const nana::rectangle& r, state_t sta, ::nana::direction dir) { - using namespace nana::paint::gadget; + facade arrow("solid_triangle"); + arrow.direction(dir); + colors fgcolor = colors::black; + if (item_renderer::disable == sta) + { + arrow.switch_to("hollow_triangle"); + fgcolor = colors::gray; + } + auto arrow_r = r; + arrow_r.x += static_cast(arrow_r.width - 16) / 2; + arrow_r.y += static_cast(arrow_r.height - 16) / 2; + arrow_r.width = arrow_r.height = 16; + arrow.draw(graph, bgcolor_, fgcolor, arrow_r, element_state::normal); - nana::color_t fgcolor = 0x0; - int style = 1; - if(sta == item_renderer::disable) - { - style = 0; - fgcolor = 0x808080; - } - arrow_16_pixels(graph, r.x + (r.width - 16) / 2, r.y + (r.height - 16) / 2, fgcolor, style, dir); - if(sta == item_renderer::highlight) - { - graph.rectangle(r, 0xA0A0A0, false); - } + if(item_renderer::highlight == sta) + graph.rectangle(r, false, colors::dark_gray); } private: - nana::color_t bgcolor_; - nana::color_t dark_bgcolor_; - nana::color_t blcolor_; - nana::color_t ilcolor_; + ::nana::color bgcolor_; + ::nana::color dark_bgcolor_; + ::nana::color blcolor_; + ::nana::color ilcolor_; }; class toolbox @@ -606,26 +598,16 @@ namespace nana } } - bool tab_color(std::size_t pos, bool is_bgcolor, nana::color_t color) + bool tab_color(std::size_t pos, bool is_bgcolor, const ::nana::color& clr) { if(pos < list_.size()) { auto & m = *iterator_at(pos); - if(is_bgcolor) + auto & m_clr = (is_bgcolor ? m.bgcolor : m.fgcolor); + if (m_clr != clr) { - if(m.bgcolor != color) - { - m.bgcolor = color; - return true; - } - } - else - { - if(m.fgcolor != color) - { - m.fgcolor = color; - return true; - } + m_clr = clr; + return true; } } return false; @@ -959,15 +941,15 @@ namespace nana void _m_render() { - if(basis_.renderer == 0 || basis_.graph == 0) return; - nana::color_t bgcolor = API::background(basis_.wd); + if(!basis_.renderer || (nullptr == basis_.graph)) + return; - item_renderer::item_t m; - m.r.width = basis_.graph->width(); - m.r.height = basis_.graph->height(); + auto bgcolor = API::bgcolor(basis_.wd); + auto fgcolor = API::fgcolor(basis_.wd); + + item_renderer::item_t m = { basis_.graph->size() }; basis_.renderer->background(*basis_.graph, m.r, bgcolor); - nana::color_t fgcolor = API::foreground(basis_.wd); //the max number of pixels of tabs. int pixels = static_cast(m.r.width - _m_toolbox_pixels()); @@ -1008,8 +990,10 @@ namespace nana if(item.text.size()) { nana::size ts = basis_.graph->text_extent_size(item.text); + basis_.graph->set_text_color(m.fgcolor.invisible() ? fgcolor : m.fgcolor); nana::paint::text_renderer tr(*basis_.graph); - tr.render(m.r.x + 24, m.r.y + (m.r.height - ts.height) / 2, (m.fgcolor == nana::null_color ? fgcolor : m.fgcolor), item.text.c_str(), item.text.length(), basis_.item_pixels - 24 - 18, true); + tr.render({ m.r.x + 24, m.r.y + static_cast(m.r.height - ts.height) / 2 }, + item.text.c_str(), item.text.length(), basis_.item_pixels - 24 - 18, true); } } @@ -1023,26 +1007,28 @@ namespace nana if(_m_nextable()) { int x = _m_itembar_right(); - if(x > 0) + if (x > 0) { - basis_.graph->line(x - 2, 0, x - 2, bottom, 0x808080); - basis_.graph->line(x - 1, 0, x - 1, bottom, 0xF0F0F0); + basis_.graph->line({ x - 2, 0 }, { x - 2, bottom }, { 0x80, 0x80, 0x80 }); + basis_.graph->line({ x - 1, 0 }, { x - 1, bottom }, {0xf0, 0xf0, 0xf0}); } } + basis_.graph->set_color({ 0x80, 0x80, 0x80 }); + int right = static_cast(basis_.graph->width()); int end = active_m.r.x + static_cast(active_m.r.width); if(0 < active_m.r.x && active_m.r.x < right) - basis_.graph->line(0, bottom, active_m.r.x, bottom, 0x808080); + basis_.graph->line({ 0, bottom }, { active_m.r.x, bottom }); if(0 <= end && end < right) - basis_.graph->line(end, bottom, right, bottom, 0x808080); + basis_.graph->line({ end, bottom }, { right, bottom }); } - void _m_render_toolbox(nana::color_t bgcolor) + void _m_render_toolbox(const ::nana::color& bgcolor) { bool backable = (basis_.scroll_pixels != 0); int xbase = _m_toolbox_pos(); - basis_.graph->rectangle(xbase, 0, _m_toolbox_pixels(), basis_.graph->height(), bgcolor, true); + basis_.graph->rectangle({ xbase, 0, _m_toolbox_pixels(), basis_.graph->height() }, true, bgcolor); for(int i = toolbox::ButtonAdd; i < toolbox::ButtonSize; ++i) { toolbox::button_t btn = static_cast(i); @@ -1104,27 +1090,20 @@ namespace nana struct basis_tag { - window wd; - nana::paint::graphics * graph; + window wd{nullptr}; + nana::paint::graphics * graph{nullptr}; pat::cloneable renderer; - unsigned max_pixels; - unsigned min_pixels; - unsigned item_pixels; - unsigned scroll_pixels; - std::size_t active; + unsigned max_pixels{250}; + unsigned min_pixels{100}; + unsigned item_pixels{max_pixels}; + unsigned scroll_pixels{0}; + std::size_t active{npos}; - basis_tag() - : wd(nullptr), graph(nullptr), - renderer(def_renderer()), - max_pixels(250), min_pixels(100), item_pixels(max_pixels), scroll_pixels(0), - active(npos) - { - } + basis_tag():renderer{ def_renderer() } + {} }basis_; }; - item_renderer::~item_renderer(){} - //class trigger trigger::trigger() : layouter_(new layouter) @@ -1191,9 +1170,9 @@ namespace nana layouter_->relate(i, wd); } - void trigger::tab_color(std::size_t i, bool is_bgcolor, nana::color_t color) + void trigger::tab_color(std::size_t i, bool is_bgcolor, const ::nana::color& clr) { - if(layouter_->tab_color(i, is_bgcolor, color)) + if(layouter_->tab_color(i, is_bgcolor, clr)) API::refresh_window(layouter_->widget_handle()); } diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index bea084eb..fc4a7d1b 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -1,7 +1,7 @@ /* * A Textbox Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -15,7 +15,13 @@ #include #include -namespace nana{ namespace drawerbase { +namespace nana +{ + arg_textbox::arg_textbox(textbox& wdg) + : widget(wdg) + {} + +namespace drawerbase { namespace textbox { //class event_agent @@ -27,13 +33,17 @@ namespace nana{ namespace drawerbase { { widget_.events().first_change.emit(::nana::arg_textbox{ widget_ }); } - // + + void event_agent::text_changed() + { + widget_.events().text_changed.emit(::nana::arg_textbox{ widget_ }); + } + //end class event_agent //class draweer drawer::drawer() : widget_(nullptr), editor_(nullptr) { - status_.has_focus = false; } drawer::text_editor* drawer::editor() @@ -46,22 +56,16 @@ namespace nana{ namespace drawerbase { return editor_; } - void drawer::set_accept(std::function && fn) - { - pred_acceptive_ = std::move(fn); - } - void drawer::attached(widget_reference wdg, graph_reference graph) { auto wd = wdg.handle(); widget_ = &wdg; evt_agent_.reset(new event_agent(static_cast< ::nana::textbox&>(wdg))); - editor_ = new text_editor(wd, graph); + auto scheme = API::dev::get_scheme(wdg); + + editor_ = new text_editor(wd, graph, dynamic_cast<::nana::widgets::skeletons::text_editor_scheme*>(scheme)); editor_->textbase().set_event_agent(evt_agent_.get()); - editor_->border_renderer([this](graph_reference graph, nana::color_t color){ - this->_m_draw_border(graph, color); - }); _m_text_area(graph.width(), graph.height()); @@ -79,15 +83,14 @@ namespace nana{ namespace drawerbase { void drawer::refresh(graph_reference graph) { - editor_->render(status_.has_focus); + editor_->render(API::is_focus_window(*widget_)); } void drawer::focus(graph_reference graph, const arg_focus& arg) { - status_.has_focus = arg.getting; refresh(graph); - editor_->show_caret(status_.has_focus); + editor_->show_caret(arg.getting); editor_->reset_caret(); API::lazy_refresh(); } @@ -142,8 +145,7 @@ namespace nana{ namespace drawerbase { void drawer::key_char(graph_reference, const arg_keyboard& arg) { - bool enterable = widget_->enabled() && (!pred_acceptive_ || pred_acceptive_(arg.key)); - if (editor_->respone_keyboard(arg.key, enterable)) + if (editor_->respone_keyboard(arg.key)) API::lazy_refresh(); } @@ -151,6 +153,7 @@ namespace nana{ namespace drawerbase { { _m_text_area(arg.width, arg.height); refresh(graph); + editor_->reset_caret(); API::lazy_refresh(); } @@ -176,16 +179,6 @@ namespace nana{ namespace drawerbase { editor_->text_area(r); } } - - void drawer::_m_draw_border(graph_reference graph, nana::color_t bgcolor) - { - if (!API::widget_borderless(widget_->handle())) - { - nana::rectangle r(graph.size()); - graph.rectangle(r, (status_.has_focus ? 0x0595E2 : 0x999A9E), false); - graph.rectangle(r.pare_off(1), bgcolor, false); - } - } //end class drawer }//end namespace textbox }//end namespace drawerbase @@ -361,7 +354,9 @@ namespace nana{ namespace drawerbase { void textbox::set_accept(std::function fn) { internal_scope_guard lock; - get_drawer_trigger().set_accept(std::move(fn)); + auto editor = get_drawer_trigger().editor(); + if(editor) + editor->set_accept(std::move(fn)); } textbox& textbox::tip_string(nana::string str) @@ -483,6 +478,47 @@ namespace nana{ namespace drawerbase { return *this; } + void textbox::set_highlight(const std::string& name, const ::nana::color& fgcolor, const ::nana::color& bgcolor) + { + auto editor = get_drawer_trigger().editor(); + if (editor) + editor->set_highlight(name, fgcolor, bgcolor); + } + + void textbox::erase_highlight(const std::string& name) + { + auto editor = get_drawer_trigger().editor(); + if (editor) + editor->erase_highlight(name); + } + + void textbox::set_keywords(const std::string& name, bool case_sensitive, bool whole_word_match, std::initializer_list kw_list) + { + auto editor = get_drawer_trigger().editor(); + if (editor) + { + for (auto & kw : kw_list) + editor->set_keyword(kw, name, case_sensitive, whole_word_match); + } + } + + void textbox::set_keywords(const std::string& name, bool case_sensitive, bool whole_word_match, std::initializer_list kw_list_utf8) + { + auto editor = get_drawer_trigger().editor(); + if (editor) + { + for (auto & kw : kw_list_utf8) + editor->set_keyword(::nana::charset(kw, ::nana::unicode::utf8), name, case_sensitive, whole_word_match); + } + } + + void textbox::erase_keyword(const nana::string& kw) + { + auto editor = get_drawer_trigger().editor(); + if (editor) + editor->erase_keyword(kw); + } + //Override _m_caption for caption() nana::string textbox::_m_caption() const { diff --git a/source/gui/widgets/toolbar.cpp b/source/gui/widgets/toolbar.cpp index 2ba3d9bf..3936cfce 100644 --- a/source/gui/widgets/toolbar.cpp +++ b/source/gui/widgets/toolbar.cpp @@ -1,6 +1,7 @@ /* * A Toolbar Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -16,6 +17,10 @@ namespace nana { + arg_toolbar::arg_toolbar(toolbar& tbar, std::size_t btn) + : widget(tbar), button{btn} + {} + namespace drawerbase { namespace toolbar @@ -29,45 +34,43 @@ namespace nana struct item_type { - enum{TypeButton, TypeContainer}; + enum kind{ button, container}; typedef std::size_t size_type; nana::string text; nana::paint::image image; - unsigned pixels; + unsigned pixels{0}; nana::size textsize; - bool enable; - window other; + bool enable{true}; + window other{nullptr}; - int type; + kind type; std::function answer; std::vector children; - item_type(const nana::string& text, const nana::paint::image& img, int type) - :text(text), image(img), pixels(0), enable(true), other(nullptr), type(type) + item_type(const nana::string& text, const nana::paint::image& img, kind type) + :text(text), image(img), type(type) {} }; class container { - container(const container&); - container& operator=(const container&); + container(const container&) = delete; + container& operator=(const container&) = delete; public: typedef std::vector::size_type size_type; typedef std::vector::iterator iterator; typedef std::vector::const_iterator const_iterator; - container() - {} - + container() = default; ~container() { for(auto ptr : cont_) delete ptr; } - void insert(size_type pos, const nana::string& text, const nana::paint::image& img, int type) + void insert(size_type pos, const nana::string& text, const nana::paint::image& img, item_type::kind type) { item_type* m = new item_type(text, img, type); @@ -79,12 +82,12 @@ namespace nana void push_back(const nana::string& text, const nana::paint::image& img) { - insert(cont_.size(), text, img, item_type::TypeButton); + insert(cont_.size(), text, img, item_type::kind::button); } void push_back(const nana::string& text) { - insert(cont_.size(), text, nana::paint::image(), item_type::TypeButton); + insert(cont_.size(), text, nana::paint::image(), item_type::kind::button); } void insert(size_type pos) @@ -142,22 +145,22 @@ namespace nana enum class state_t{normal, highlighted, selected}; const static unsigned extra_size = 6; - item_renderer(nana::paint::graphics& graph, bool textout, unsigned scale, nana::color_t color) - :graph(graph), textout(textout), scale(scale), color(color) + item_renderer(nana::paint::graphics& graph, bool textout, unsigned scale, const ::nana::color& bgcolor) + :graph(graph), textout(textout), scale(scale), bgcolor(bgcolor) {} void operator()(int x, int y, unsigned width, unsigned height, item_type& item, state_t state) { //draw background if(state != state_t::normal) - graph.rectangle(x, y, width, height, 0x3399FF, false); + graph.rectangle({ x, y, width, height }, false, { 0x33, 0x99, 0xFF }); switch(state) { case state_t::highlighted: - graph.shadow_rectangle(x + 1, y + 1, width - 2, height - 2, color, /*graph.mix(color, 0xC0DDFC, 0.5)*/ 0xC0DDFC, true); + graph.gradual_rectangle({ x + 1, y + 1, width - 2, height - 2 }, bgcolor, { 0xC0, 0xDD, 0xFC }, true); break; case state_t::selected: - graph.shadow_rectangle(x + 1, y + 1, width - 2, height - 2, color, /*graph.mix(color, 0x99CCFF, 0.5)*/0x99CCFF, true); + graph.gradual_rectangle({ x + 1, y + 1, width - 2, height - 2 }, bgcolor, { 0x99, 0xCC, 0xFF }, true); default: break; } @@ -174,13 +177,13 @@ namespace nana item.image.paste(size, graph, pos); if(item.enable == false) { - nana::paint::graphics gh(size.width, size.height); + nana::paint::graphics gh(size); gh.bitblt(size, graph, pos); gh.rgb_to_wb(); gh.paste(graph, pos.x, pos.y); } else if(state == state_t::normal) - graph.blend(nana::rectangle(pos, size), graph.mix(color, 0xC0DDFC, 0.5), 0.25); + graph.blend(nana::rectangle(pos, size), ::nana::color(0xc0, 0xdd, 0xfc).blend(bgcolor, 0.5), 0.25); x += scale; width -= scale; @@ -188,7 +191,7 @@ namespace nana if(textout) { - graph.string(x + (width - item.textsize.width) / 2, y + (height - item.textsize.height) / 2, 0x0, item.text); + graph.string({ x + static_cast(width - item.textsize.width) / 2, y + static_cast(height - item.textsize.height) / 2 }, item.text); } } @@ -196,27 +199,19 @@ namespace nana nana::paint::graphics& graph; bool textout; unsigned scale; - nana::color_t color; + ::nana::color bgcolor; }; struct drawer::drawer_impl_type { - event_handle event_size; - unsigned scale; - bool textout; - size_type which; - item_renderer::state_t state; + event_handle event_size{nullptr}; + unsigned scale{16}; + bool textout{false}; + size_type which{npos}; + item_renderer::state_t state{item_renderer::state_t::normal}; container cont; - nana::tooltip tooltip; - - drawer_impl_type() - : event_size(nullptr), - scale(16), - textout(false), - which(npos), - state(item_renderer::state_t::normal) - {} + ::nana::tooltip tooltip; }; //class drawer @@ -283,7 +278,7 @@ namespace nana widget_ = static_cast< ::nana::toolbar*>(&widget); widget.caption(STR("Nana Toolbar")); - impl_->event_size = widget.events().resized.connect(std::bind(&drawer::_m_owner_sized, this, std::placeholders::_1)); + impl_->event_size = widget.events().resized.connect_unignorable(std::bind(&drawer::_m_owner_sized, this, std::placeholders::_1)); } @@ -403,19 +398,20 @@ namespace nana return npos; } - void drawer::_m_draw_background(nana::color_t color) + void drawer::_m_draw_background(const ::nana::color& clr) { - graph_->shadow_rectangle(graph_->size(), graph_->mix(color, 0xFFFFFF, 0.9), graph_->mix(color, 0x0, 0.95), true); + graph_->gradual_rectangle(graph_->size(), clr.blend(colors::white, 0.9), clr.blend(colors::black, 0.95), true); } void drawer::_m_draw() { int x = 2, y = 2; - unsigned color = API::background(widget_->handle()); - _m_draw_background(color); + auto bgcolor = API::bgcolor(widget_->handle()); + graph_->set_text_color(bgcolor); + _m_draw_background(bgcolor); - item_renderer ir(*graph_, impl_->textout, impl_->scale, color); + item_renderer ir(*graph_, impl_->textout, impl_->scale, bgcolor); size_type index = 0; for(auto item : impl_->cont) @@ -428,7 +424,7 @@ namespace nana } else { - graph_->line(x + 2, y + 2, x + 2, y + impl_->scale + ir.extra_size - 4, 0x808080); + graph_->line({ x + 2, y + 2 }, { x + 2, y + static_cast(impl_->scale + ir.extra_size) - 4 }, { 0x80, 0x80, 0x80 }); x += 6; } ++index; @@ -463,9 +459,6 @@ namespace nana }//end namespace drawerbase //class toolbar - toolbar::toolbar() - {} - toolbar::toolbar(window wd, bool visible) { create(wd, rectangle(), visible); diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index 9135e364..a4e51a0b 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -1,7 +1,7 @@ /* * A Treebox Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -18,6 +18,10 @@ namespace nana { + arg_treebox::arg_treebox(treebox& wdg, drawerbase::treebox::item_proxy& m, bool op) + : widget(wdg), item(m), operated{op} + {} + namespace drawerbase { //Here defines some function objects @@ -25,53 +29,137 @@ namespace nana { typedef trigger::node_type node_type; - bool no_sensitive_compare(const nana::string& text, const nana::char_t *pattern, std::size_t len) + bool no_sensitive_compare(const nana::string& text, const nana::char_t *pattern, std::size_t len) + { + if(len <= text.length()) { - if(len <= text.length()) + const nana::char_t * s = text.c_str(); + for(std::size_t i = 0; i < len; ++i) { - const nana::char_t * s = text.c_str(); - for(std::size_t i = 0; i < len; ++i) + if('a' <= s[i] && s[i] <= 'z') { - if('a' <= s[i] && s[i] <= 'z') - { - if(pattern[i] != s[i] - ('a' - 'A')) - return false; - } - else - if(pattern[i] != s[i]) return false; + if(pattern[i] != s[i] - ('a' - 'A')) + return false; } - return true; + else + if(pattern[i] != s[i]) return false; + } + return true; + } + return false; + } + + const node_type* find_track_child_node(const node_type* node, const node_type * end, const nana::char_t* pattern, std::size_t len, bool &finish) + { + if(node->value.second.expanded) + { + node = node->child; + while(node) + { + if(no_sensitive_compare(node->value.second.text, pattern, len)) return node; + + if(node == end) break; + + if(node->value.second.expanded) + { + auto t = find_track_child_node(node, end, pattern, len, finish); + if(t || finish) + return t; + } + node = node->next; } - return false; } - const node_type* find_track_child_node(const node_type* node, const node_type * end, const nana::char_t* pattern, std::size_t len, bool &finish) + finish = (node && (node == end)); + return nullptr; + } + + class tlwnd_drawer + : public drawer_trigger, public compset_interface + { + public: + typedef drawer_trigger::graph_reference graph_reference; + + void assign(const item_attribute_t & item_attr, const pat::cloneable* renderer, const pat::cloneable * compset_placer) { - if(node->value.second.expanded) + if(renderer && compset_placer) { - node = node->child; + renderer_ = *renderer; + placer_ = *compset_placer; - while(node) - { - if(no_sensitive_compare(node->value.second.text, pattern, len)) return node; + item_attr_ = item_attr; - if(node == end) break; - - if(node->value.second.expanded) - { - auto t = find_track_child_node(node, end, pattern, len, finish); - if(t || finish) - return t; - } - node = node->next; - } + _m_draw(); } + } + private: + void _m_draw() + { + item_r_.x = item_r_.y = 0; + item_r_.width = placer_->item_width(*this->graph_, item_attr_); + item_r_.height = placer_->item_height(*this->graph_); - finish = (node && (node == end)); - return nullptr; + comp_attribute_t attr; + if(comp_attribute(component::text, attr)) + { + nana::paint::graphics item_graph({ item_r_.width, item_r_.height }); + item_graph.typeface(graph_->typeface()); + + renderer_->set_color(widget_->bgcolor(), widget_->fgcolor()); + renderer_->bground(item_graph, this); + renderer_->expander(item_graph, this); + renderer_->crook(item_graph, this); + renderer_->icon(item_graph, this); + renderer_->text(item_graph, this); + + item_graph.paste(attr.area, *graph_, 1, 1); + graph_->rectangle(false, colors::black); + } + } + private: + // Implementation of drawer_trigger + void attached(widget_reference wd, graph_reference graph) override + { + widget_ = &wd; + graph_ = &graph; + graph.typeface(widget_->typeface()); + } + private: + // Implementation of compset_interface + virtual const item_attribute_t& item_attribute() const override + { + return item_attr_; } - class tooltip_window; + virtual bool comp_attribute(component_t comp, comp_attribute_t& comp_attr) const override + { + comp_attr.area = item_r_; + return placer_->locate(comp, item_attr_, &comp_attr.area); + } + private: + ::nana::paint::graphics * graph_; + ::nana::pat::cloneable renderer_; + ::nana::pat::cloneable placer_; + widget *widget_; + item_attribute_t item_attr_; + nana::rectangle item_r_; + };//end class tlwnd_drawer + + class tooltip_window + : public widget_object + { + public: + tooltip_window(window wd, const rectangle& r) + : widget_object(wd, false, rectangle(r).pare_off(-1), appear::bald()) + { + API::take_active(handle(), false, nullptr); + } + + drawer_trigger_t & impl() + { + return get_drawer_trigger(); + } + };//end class tooltip_window //item_locator should be defined before the definition of basic_implement class trigger::item_locator @@ -223,7 +311,7 @@ namespace nana show_scroll(); //Draw background - data.graph->rectangle(data.widget_ptr->background(), true); + data.graph->rectangle(true, data.widget_ptr->bgcolor()); //Draw tree attr.tree_cont.for_each(shape.first, Renderer(this, nana::point(static_cast(attr.tree_cont.indent_size(shape.first) * shape.indent_pixels) - shape.offset_x, 1))); @@ -1078,66 +1166,76 @@ namespace nana class internal_renderer : public renderer_interface { - void bground(graph_reference graph, nana::color_t bgcolor, nana::color_t fgcolor, const compset_interface * compset) const override + nana::color bgcolor_; + nana::color fgcolor_; + + void set_color(const nana::color & bgcolor, const nana::color& fgcolor) override + { + bgcolor_ = bgcolor; + fgcolor_ = fgcolor; + } + + void bground(graph_reference graph, const compset_interface * compset) const override { comp_attribute_t attr; if(compset->comp_attribute(component::bground, attr)) { - const nana::color_t color_table[][2] = { {0xE8F5FD, 0xD8F0FA}, //highlighted - {0xC4E8FA, 0xB6E6FB}, //Selected and highlighted - {0xD5EFFC, 0x99DEFD} //Selected but not highlighted + const ::nana::color color_table[][2] = { { { 0xE8, 0xF5, 0xFD }, { 0xD8, 0xF0, 0xFA } }, //highlighted + { { 0xC4, 0xE8, 0xFA }, { 0xB6, 0xE6, 0xFB } }, //Selected and highlighted + { { 0xD5, 0xEF, 0xFC }, {0x99, 0xDE, 0xFD } } //Selected but not highlighted }; - const nana::color_t *colptr = nullptr; + const ::nana::color *clrptr = nullptr; if(compset->item_attribute().mouse_pointed) { if(compset->item_attribute().selected) - colptr = color_table[1]; + clrptr = color_table[1]; else - colptr = color_table[0]; + clrptr = color_table[0]; } else if(compset->item_attribute().selected) - colptr = color_table[2]; + clrptr = color_table[2]; - if(colptr) + if (clrptr) { - graph.rectangle(attr.area, colptr[1], false); - graph.rectangle(attr.area.pare_off(1), *colptr, true); + graph.rectangle(attr.area, false, clrptr[1]); + graph.rectangle(attr.area.pare_off(1), true, *clrptr); } } } - void expander(graph_reference graph, nana::color_t bgcolor, nana::color_t fgcolor, const compset_interface * compset) const override + void expander(graph_reference graph, const compset_interface * compset) const override { comp_attribute_t attr; if(compset->comp_attribute(component::expender, attr)) { - using namespace nana::paint; - - uint32_t style = 1; - gadget::directions::t dir = gadget::directions::to_southeast; - if(! compset->item_attribute().expended) + facade arrow("solid_triangle"); + arrow.direction(direction::southeast); + if (!compset->item_attribute().expended) { - style = 0; - dir = gadget::directions::to_east; + arrow.switch_to("hollow_triangle"); + arrow.direction(direction::east); } - gadget::arrow_16_pixels(graph, attr.area.x, attr.area.y + (attr.area.height - 16) / 2, (attr.mouse_pointed ? 0x1CC4F7 : 0x0), style, dir); + auto r = attr.area; + r.y += (attr.area.height - 16) / 2; + r.width = r.height = 16; + arrow.draw(graph, bgcolor_, (attr.mouse_pointed ? colors::deep_sky_blue : colors::black), r, element_state::normal); } } - void crook(graph_reference graph, nana::color_t bgcolor, nana::color_t fgcolor, const compset_interface * compset) const override + void crook(graph_reference graph, const compset_interface * compset) const override { comp_attribute_t attr; if(compset->comp_attribute(component::crook, attr)) { attr.area.y += (attr.area.height - 16) / 2; crook_.check(compset->item_attribute().checked); - crook_.draw(graph, bgcolor, fgcolor, attr.area, attr.mouse_pointed ? element_state::hovered : element_state::normal); + crook_.draw(graph, bgcolor_, fgcolor_, attr.area, attr.mouse_pointed ? element_state::hovered : element_state::normal); } } - virtual void icon(graph_reference graph, nana::color_t bgcolor, nana::color_t fgcolor, const compset_interface * compset) const override + virtual void icon(graph_reference graph, const compset_interface * compset) const override { comp_attribute_t attr; if(compset->comp_attribute(component::icon, attr)) @@ -1170,11 +1268,14 @@ namespace nana } } - virtual void text(graph_reference graph, nana::color_t bgcolor, nana::color_t fgcolor, const compset_interface * compset) const override + virtual void text(graph_reference graph, const compset_interface * compset) const override { comp_attribute_t attr; - if(compset->comp_attribute(component::text, attr)) - graph.string(attr.area.x, attr.area.y + 3, fgcolor, compset->item_attribute().text); + if (compset->comp_attribute(component::text, attr)) + { + graph.set_text_color(fgcolor_); + graph.string(point{ attr.area.x, attr.area.y + 3 }, compset->item_attribute().text); + } } private: @@ -1213,9 +1314,7 @@ namespace nana if(pos_.y < item_pos_.y + static_cast(node_r.height)) { - int logic_x = pos_.x - item_pos_.x; - int logic_y = pos_.y - item_pos_.y; - + auto logic_pos = pos_ - item_pos_; node_ = &node; for(int comp = static_cast(component::begin); comp != static_cast(component::end); ++comp) @@ -1223,7 +1322,7 @@ namespace nana nana::rectangle r = node_r; if(comp_placer->locate(static_cast(comp), node_attr_, &r)) { - if(r.is_hit(logic_x, logic_y)) + if(r.is_hit(logic_pos)) { what_ = static_cast(comp); if(component::expender == what_ && (false == node_attr_.has_children)) @@ -1263,10 +1362,7 @@ namespace nana nana::rectangle trigger::item_locator::text_pos() const { - auto r = node_text_r_; - r.x += item_pos_.x; - r.y += item_pos_.y; - return r; + return{node_text_r_.x + item_pos_.x, node_text_r_.y + item_pos_.y, node_text_r_.width, node_text_r_.height}; } //end class item_locator @@ -1277,10 +1373,11 @@ namespace nana typedef tree_cont_type::node_type node_type; item_renderer(implement * impl, const nana::point& pos) - :impl_(impl), pos_(pos) + : impl_(impl), + bgcolor_(impl->data.widget_ptr->bgcolor()), + fgcolor_(impl->data.widget_ptr->fgcolor()), + pos_(pos) { - bgcolor_ = impl_->data.widget_ptr->background(); - fgcolor_ = impl_->data.widget_ptr->foreground(); } //affect @@ -1310,11 +1407,12 @@ namespace nana node_r_.height = comp_placer->item_height(*impl_->data.graph); auto renderer = draw_impl->data.renderer; - renderer->bground(*draw_impl->data.graph, bgcolor_, fgcolor_, this); - renderer->expander(*draw_impl->data.graph, bgcolor_, fgcolor_, this); - renderer->crook(*draw_impl->data.graph, bgcolor_, fgcolor_, this); - renderer->icon(*draw_impl->data.graph, bgcolor_, fgcolor_, this); - renderer->text(*draw_impl->data.graph, bgcolor_, fgcolor_, this); + renderer->set_color(bgcolor_, fgcolor_); + renderer->bground(*draw_impl->data.graph, this); + renderer->expander(*draw_impl->data.graph, this); + renderer->crook(*draw_impl->data.graph, this); + renderer->icon(*draw_impl->data.graph, this); + renderer->text(*draw_impl->data.graph, this); pos_.y += node_r_.height; @@ -1343,107 +1441,18 @@ namespace nana } private: trigger::implement * impl_; - nana::color_t bgcolor_; - nana::color_t fgcolor_; - nana::point pos_; + ::nana::color bgcolor_; + ::nana::color fgcolor_; + ::nana::point pos_; const node_type * iterated_node_; item_attribute_t node_attr_; - nana::rectangle node_r_; + ::nana::rectangle node_r_; }; } //Treebox Implementation namespace treebox { - class tlwnd_drawer - : public drawer_trigger, public compset_interface - { - public: - typedef drawer_trigger::graph_reference graph_reference; - - void assign(const item_attribute_t & item_attr, const pat::cloneable* renderer, const pat::cloneable * compset_placer) - { - if(renderer && compset_placer) - { - renderer_ = *renderer; - placer_ = *compset_placer; - - item_attr_ = item_attr; - - _m_draw(); - } - } - private: - void _m_draw() - { - item_r_.x = item_r_.y = 0; - item_r_.width = placer_->item_width(*this->graph_, item_attr_); - item_r_.height = placer_->item_height(*this->graph_); - - comp_attribute_t attr; - if(comp_attribute(component::text, attr)) - { - nana::paint::graphics item_graph(item_r_.width, item_r_.height); - item_graph.typeface(graph_->typeface()); - - auto bgcolor = widget_->background(); - auto fgcolor = widget_->foreground(); - renderer_->bground(item_graph, bgcolor, fgcolor, this); - renderer_->expander(item_graph, bgcolor, fgcolor, this); - renderer_->crook(item_graph, bgcolor, fgcolor, this); - renderer_->icon(item_graph, bgcolor, fgcolor, this); - renderer_->text(item_graph, bgcolor, fgcolor, this); - - item_graph.paste(attr.area, *graph_, 1, 1); - graph_->rectangle(0x0, false); - } - } - private: - // Implementation of drawer_trigger - void attached(widget_reference wd, graph_reference graph) override - { - widget_ = &wd; - graph_ = &graph; - graph.typeface(widget_->typeface()); - } - private: - // Implementation of compset_interface - virtual const item_attribute_t& item_attribute() const override - { - return item_attr_; - } - - virtual bool comp_attribute(component_t comp, comp_attribute_t& comp_attr) const override - { - comp_attr.area = item_r_; - return placer_->locate(comp, item_attr_, &comp_attr.area); - } - private: - ::nana::paint::graphics * graph_; - ::nana::pat::cloneable renderer_; - ::nana::pat::cloneable placer_; - widget *widget_; - item_attribute_t item_attr_; - nana::rectangle item_r_; - };//end class tlwnd_drawer - - class tooltip_window - : public widget_object - { - public: - tooltip_window(window wd, const rectangle& r) - : widget_object(wd, false, rectangle(r).pare_off(-1), appear::bald()) - { - API::take_active(handle(), false, nullptr); - } - - drawer_trigger_t & impl() - { - return get_drawer_trigger(); - } - };//end class tooltip_window - - //class trigger //struct treebox_node_type trigger::treebox_node_type::treebox_node_type() @@ -1750,7 +1759,6 @@ namespace nana unsigned trigger::node_width(const node_type *node) const { - //return (static_cast(impl_->data.graph->text_extent_size(node->value.second.text).width) + impl_->shape.text_offset * 2 + static_cast(impl_->shape.crook_pixels + impl_->shape.image_pixels)); node_attribute node_attr; impl_->assign_node_attr(node_attr, node); return impl_->data.comp_placer->item_width(*impl_->data.graph, node_attr); @@ -1784,7 +1792,7 @@ namespace nana { impl_->data.graph = &graph; - widget.background(0xFFFFFF); + widget.bgcolor(colors::white); impl_->data.widget_ptr = static_cast< ::nana::treebox*>(&widget); widget.caption(STR("Nana Treebox")); } diff --git a/source/gui/widgets/widget.cpp b/source/gui/widgets/widget.cpp index 4e1b2c2b..f573c6b6 100644 --- a/source/gui/widgets/widget.cpp +++ b/source/gui/widgets/widget.cpp @@ -20,13 +20,16 @@ namespace nana } //class widget //@brief:The definition of class widget - widget::~widget(){} - nana::string widget::caption() const { return this->_m_caption(); } + void widget::caption(std::string utf8) + { + _m_caption(std::wstring(::nana::charset(utf8, ::nana::unicode::utf8))); + } + void widget::caption(nana::string str) { _m_caption(std::move(str)); @@ -141,24 +144,24 @@ namespace nana _m_move(r); } - void widget::foreground(nana::color_t value) + void widget::fgcolor(const nana::color& col) { - _m_foreground(value); + _m_fgcolor(col); } - nana::color_t widget::foreground() const + nana::color widget::fgcolor() const { - return _m_foreground(); + return _m_fgcolor(); } - void widget::background(nana::color_t value) + void widget::bgcolor(const nana::color& col) { - _m_background(value); + _m_bgcolor(col); } - nana::color_t widget::background() const + nana::color widget::bgcolor() const { - return _m_background(); + return _m_bgcolor(); } general_events& widget::events() const @@ -171,6 +174,21 @@ namespace nana API::umake_event(eh); } + widget& widget::register_shortkey(char_t key) + { + if (key) + API::register_shortkey(handle(), static_cast(key)); + else + API::unregister_shortkey(handle()); + return *this; + } + + widget& widget::take_active(bool activated, window take_if_not_activated) + { + API::take_active(handle(), activated, take_if_not_activated); + return *this; + } + widget& widget::tooltip(const nana::string& text) { nana::tooltip::set(*this, text); @@ -261,24 +279,24 @@ namespace nana return API::typeface(handle()); } - void widget::_m_foreground(nana::color_t value) + void widget::_m_fgcolor(const nana::color& col) { - API::foreground(handle(), value); + API::fgcolor(handle(), col); } - nana::color_t widget::_m_foreground() const + nana::color widget::_m_fgcolor() const { - return API::foreground(handle()); + return API::fgcolor(handle()); } - void widget::_m_background(nana::color_t value) + void widget::_m_bgcolor(const nana::color& col) { - API::background(handle(), value); + API::bgcolor(handle(), col); } - nana::color_t widget::_m_background() const + nana::color widget::_m_bgcolor() const { - return API::background(handle()); + return API::bgcolor(handle()); } //end class widget diff --git a/source/internationalization.cpp b/source/internationalization.cpp index e36e6312..30908ce7 100644 --- a/source/internationalization.cpp +++ b/source/internationalization.cpp @@ -144,6 +144,9 @@ namespace nana static std::shared_ptr& get_data_ptr() { static std::shared_ptr data_ptr; + if (!data_ptr) + data_ptr = std::make_shared(); + return data_ptr; } @@ -208,6 +211,16 @@ namespace nana impl->table[std::move(msgid)].swap(str); } + //Assign all language texts to the new table. + auto & cur_table = get_data_ptr()->table; + auto & new_table = impl->table; + for (auto & m : cur_table) + { + auto & value = new_table[m.first]; + if (value.empty()) + value = m.second; + } + get_data_ptr().swap(impl); use_eval(); } @@ -288,22 +301,17 @@ namespace nana void internationalization::set(std::string msgid, nana::string msgstr) { auto & ptr = internationalization_parts::get_data_ptr(); - if (!ptr) - ptr = std::make_shared(); ptr->table[msgid].swap(msgstr); } bool internationalization::_m_get(std::string& msgid, nana::string& msgstr) const { - auto impl = internationalization_parts::get_data_ptr(); - if (impl) + auto & impl = internationalization_parts::get_data_ptr(); + auto i = impl->table.find(msgid); + if (i != impl->table.end()) { - auto i = impl->table.find(msgid); - if (i != impl->table.end()) - { - msgstr = i->second; - return true; - } + msgstr = i->second; + return true; } msgstr = nana::charset(std::move(msgid), nana::unicode::utf8); @@ -335,12 +343,7 @@ namespace nana erase_n = str.size() - offset; //If there is not a parameter for %argNNN, the %argNNN will be erased. - - //a workaround, MinGW does not provide std::stoi - std::wstringstream ss; - std::size_t arg; - ss<>arg; + std::size_t arg = static_cast(::nana::stoi(str.substr(offset + 4, arg_n))); if (arg_strs && arg < arg_strs->size()) str.replace(offset, erase_n, (*arg_strs)[arg]); diff --git a/source/paint/detail/image_process_provider.cpp b/source/paint/detail/image_process_provider.cpp index 4a710884..1c0c61ab 100644 --- a/source/paint/detail/image_process_provider.cpp +++ b/source/paint/detail/image_process_provider.cpp @@ -6,16 +6,6 @@ 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 diff --git a/source/paint/detail/native_paint_interface.cpp b/source/paint/detail/native_paint_interface.cpp index 0a7e7f99..7c96f7b6 100644 --- a/source/paint/detail/native_paint_interface.cpp +++ b/source/paint/detail/native_paint_interface.cpp @@ -49,9 +49,10 @@ namespace detail } - unsigned char * alloc_fade_table(double fade_rate) + std::unique_ptr alloc_fade_table(double fade_rate) { - unsigned char* tablebuf = new unsigned char[0x100 * 2]; + std::unique_ptr ptr(new unsigned char[0x100 * 2]); + unsigned char* tablebuf = ptr.get(); unsigned char* d_table = tablebuf; unsigned char* s_table = d_table + 0x100; @@ -77,54 +78,27 @@ namespace detail d_table += 4; s_table += 4; } - return tablebuf; + return ptr; } - 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(bgcolor.u.element.red * fade_rate + fgcolor.u.element.red * lrate); - ret.u.element.green = static_cast(bgcolor.u.element.green * fade_rate + fgcolor.u.element.green * lrate); - ret.u.element.blue = static_cast(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) + nana::pixel_color_t fade_color_intermedia(nana::pixel_color_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]; + fgcolor.element.red = fade_table[fgcolor.element.red]; + fgcolor.element.green = fade_table[fgcolor.element.green]; + fgcolor.element.blue = fade_table[fgcolor.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) + nana::pixel_color_t fade_color_by_intermedia(nana::pixel_color_t bgcolor, nana::pixel_color_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; + bgcolor.element.red = fade_table[bgcolor.element.red] + fgcolor_intermedia.element.red; + bgcolor.element.green = fade_table[bgcolor.element.green] + fgcolor_intermedia.element.green; + bgcolor.element.blue = fade_table[bgcolor.element.blue] + fgcolor_intermedia.element.blue; return bgcolor; } - void blend(drawable_type dw, const nana::rectangle& area, unsigned color, double fade_rate) + void blend(drawable_type dw, const nana::rectangle& area, pixel_color_t color, double fade_rate) { if(fade_rate <= 0) return; if(fade_rate > 1) fade_rate = 1; @@ -133,23 +107,23 @@ namespace detail if(false == nana::overlap(drawable_size(dw), area, r)) return; - unsigned red = static_cast((color & 0xFF0000) * fade_rate); - unsigned green = static_cast((color & 0xFF00) * fade_rate); - unsigned blue = static_cast((color & 0xFF) * fade_rate); + unsigned red = static_cast((color.value & 0xFF0000) * fade_rate); + unsigned green = static_cast((color.value & 0xFF00) * fade_rate); + unsigned blue = static_cast((color.value & 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; + auto i = pixbuf.raw_ptr(row) + r.x; + const auto end = i + r.width; for(; i < end; ++i) { - unsigned px_r = ((static_cast((i->u.color & 0xFF0000) * lrate) + red) & 0xFF0000); - unsigned px_g = ((static_cast((i->u.color & 0xFF00) * lrate) + green) & 0xFF00); - unsigned px_b = ((static_cast((i->u.color & 0xFF) * lrate) + blue) & 0xFF); - i->u.color = (px_r | px_g | px_b); + unsigned px_r = ((static_cast((i->value & 0xFF0000) * lrate) + red) & 0xFF0000); + unsigned px_g = ((static_cast((i->value & 0xFF00) * lrate) + green) & 0xFF00); + unsigned px_b = ((static_cast((i->value & 0xFF) * lrate) + blue) & 0xFF); + i->value = (px_r | px_g | px_b); } } pixbuf.paste(nana::rectangle(r.x, 0, r.width, r.height), dw, r.x, r.y); @@ -196,17 +170,17 @@ namespace detail return extents; } - void draw_string(drawable_type dw, int x, int y, const nana::char_t * str, std::size_t len) + void draw_string(drawable_type dw, const nana::point& pos, const nana::char_t * str, std::size_t len) { #if defined(NANA_WINDOWS) - ::TextOut(dw->context, x, y, str, static_cast(len)); + ::TextOut(dw->context, pos.x, pos.y, str, static_cast(len)); #elif defined(NANA_X11) auto disp = ::nana::detail::platform_spec::instance().open_display(); #if defined(NANA_UNICODE) /* std::string utf8str = nana::charset(nana::string(str, len)); XftFont * fs = reinterpret_cast(dw->font->handle); - ::XftDrawStringUtf8(dw->xftdraw, &(dw->xft_fgcolor), fs, x, y + fs->ascent, + ::XftDrawStringUtf8(dw->xftdraw, &(dw->xft_fgcolor), fs, pos.x, pos.y + fs->ascent, reinterpret_cast(const_cast(utf8str.c_str())), utf8str.size()); */ auto fs = reinterpret_cast(dw->font->handle); @@ -217,7 +191,7 @@ namespace detail { (*glyphs++) = XftCharIndex(disp, fs, *chr); } - XftDrawGlyphs(dw->xftdraw, &(dw->xft_fgcolor), fs, x, y + fs->ascent, glyphs_ptr.get(), len); + XftDrawGlyphs(dw->xftdraw, &(dw->xft_fgcolor), fs, pos.x, pos.y + fs->ascent, glyphs_ptr.get(), len); #else XFontSet fs = reinterpret_cast(dw->font->handle); XFontSetExtents * ext = ::XExtentsOfFontSet(fs); @@ -234,7 +208,7 @@ namespace detail if(descent < (*i)->descent) descent = (*i)->descent; } - XmbDrawString(disp, dw->pixmap, reinterpret_cast(dw->font->handle), dw->context, x, y + ascent + descent, buf, len); + XmbDrawString(display, dw->pixmap, reinterpret_cast(dw->font->handle), dw->context, pos.x, pos.y + ascent + descent, buf, len); #endif #endif } diff --git a/source/paint/gadget.cpp b/source/paint/gadget.cpp index 9e2d5a38..c6da79e6 100644 --- a/source/paint/gadget.cpp +++ b/source/paint/gadget.cpp @@ -1,6 +1,7 @@ /* * Graphics Gadget Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -18,250 +19,40 @@ 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) + void close_16_pixels(::nana::paint::graphics& graph, int x, int y, unsigned style, const ::nana::color& clr) { + graph.set_color(clr); 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, y }, { x + 9, y + 9 }); + graph.line({ x + 1, y }, { x + 9, y + 8 }); + graph.line({ x, y + 1 }, { x + 8, y + 9 }); - 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); + graph.line({ x + 9, y }, { x, y + 9 }); + graph.line({ x + 8, y }, { x, y + 8 }); + graph.line({ x + 9, y + 1 }, { x + 1, y + 9 }); } 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, y }, { x + 7, y + 7 }); + graph.line({ x + 1, y }, { x + 7, y + 6 }); + graph.line({ x, y + 1 }, { x + 6, y + 7 }); - 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); + graph.line({ x + 7, y }, { x, y + 7 }); + graph.line({ x + 6, y }, { x, y + 6 }); + graph.line({ x + 7, y + 1 }, { x + 1, y + 7 }); } } - void cross(graphics& graph, int x, int y, uint32_t size, uint32_t thickness, nana::color_t color) + void cross(graphics& graph, int x, int y, unsigned size, unsigned thickness, const ::nana::color& clr) { - if(thickness + 2 <= size) + if (thickness + 2 <= size) { int gap = (size - thickness) / 2; @@ -300,14 +91,15 @@ namespace gadget 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.set_color(clr.blend(colors::black, true)); - 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); + for (int i = 0; i < 11; ++i) + graph.line(ps[i], ps[i + 1]); + graph.line(ps[11], ps[0]); + graph.set_color(clr); + graph.rectangle(rectangle{ ps[10].x + 1, ps[10].y + 1, (gap << 1) + thickness - 2, thickness - 2 }, true); + graph.rectangle(rectangle{ ps[0].x + 1, ps[0].y + 1, thickness - 2, (gap << 1) + thickness - 2 }, true); } } }//end namespace gadget diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index 23ee377b..f8649ca5 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -12,7 +12,7 @@ #include #include PLATFORM_SPEC_HPP -#include GUI_BEDROCK_HPP +#include #include #include #include @@ -198,16 +198,10 @@ namespace paint :handle_(nullptr), changed_(false) {} - graphics::graphics(unsigned width, unsigned height) - :handle_(nullptr), changed_(true) - { - make(width, height); - } - graphics::graphics(const nana::size& sz) :handle_(nullptr), changed_(true) { - make(sz.width, sz.height); + make(sz); } graphics::graphics(const graphics& rhs) @@ -255,9 +249,9 @@ namespace paint return (handle_? handle_->context : nullptr); } - void graphics::make(unsigned width, unsigned height) + void graphics::make(const ::nana::size& sz) { - if(handle_ == nullptr || size_ != nana::size(width, height)) + if(handle_ == nullptr || size_ != sz) { //The object will be delete while dwptr_ is performing a release. drawable_type dw = new nana::detail::drawable_impl_type; @@ -277,12 +271,12 @@ namespace paint BITMAPINFO bmi; bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = width; - bmi.bmiHeader.biHeight = -static_cast(height); + bmi.bmiHeader.biWidth = sz.width; + bmi.bmiHeader.biHeight = -static_cast(sz.height); bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; // four 8-bit components bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biSizeImage = (width * height) << 2; + bmi.bmiHeader.biSizeImage = (sz.width * sz.height) << 2; HBITMAP bmp = ::CreateDIBSection(cdc, &bmi, DIB_RGB_COLORS, reinterpret_cast(&(dw->pixbuf_ptr)), 0, 0); @@ -310,7 +304,7 @@ namespace paint Display* disp = spec.open_display(); int screen = DefaultScreen(disp); Window root = ::XRootWindow(disp, screen); - dw->pixmap = ::XCreatePixmap(disp, root, (width ? width : 1), (height ? height : 1), DefaultDepth(disp, screen)); + dw->pixmap = ::XCreatePixmap(disp, root, (sz.width ? sz.width : 1), (sz.height ? sz.height : 1), DefaultDepth(disp, screen)); dw->context = ::XCreateGC(disp, dw->pixmap, 0, 0); #if defined(NANA_UNICODE) dw->xftdraw = ::XftDrawCreate(disp, dw->pixmap, spec.screen_visual(), spec.colormap()); @@ -318,14 +312,16 @@ namespace paint #endif if(dw) { - dw->fgcolor(0); + dw->set_color(colors::black); + dw->set_text_color(colors::black); #if defined(NANA_WINDOWS) - dw->bytes_per_line = width * sizeof(pixel_rgb_t); + dw->bytes_per_line = sz.width * sizeof(pixel_argb_t); +#else + dw->update_text_color(); #endif - dwptr_ = std::shared_ptr(dw, detail::drawable_deleter()); + dwptr_.reset(dw, detail::drawable_deleter{}); handle_ = dw; - size_.width = width; - size_.height = height; + size_ = sz; handle_->string.tab_pixels = detail::raw_text_extent_size(handle_, STR("\t"), 1).width; handle_->string.whitespace_pixels = detail::raw_text_extent_size(handle_, STR(" "), 1).width; @@ -335,10 +331,10 @@ namespace paint if(changed_ == false) changed_ = true; } - void graphics::resize(unsigned width, unsigned height) + void graphics::resize(const ::nana::size& sz) { graphics duplicate(*this); - make(width, height); + make(sz); bitblt(0, 0, duplicate); } @@ -519,296 +515,6 @@ namespace paint return false; } - unsigned graphics::bidi_string(int x, int y, color_t col, const nana::char_t* str, std::size_t len) - { - int origin_x = x; - unicode_bidi bidi; - std::vector reordered; - bidi.linestr(str, len, reordered); - for(auto & i : reordered) - { - string(x, y, col, i.begin, i.end - i.begin); - x += static_cast(text_extent_size(i.begin, i.end - i.begin).width); - } - return static_cast(x - origin_x); - } - - void graphics::string(int x, int y, color_t color, const nana::string& str, std::size_t len) - { - string(x, y, color, str.c_str(), len); - } - - void graphics::string(int x, int y, color_t color, const nana::string& str) - { - string(x, y, color, str.c_str(), str.size()); - } - - void graphics::string(int x, int y, color_t color, const nana::char_t* str, std::size_t len) - { - if(handle_ && str && len) - { - handle_->fgcolor(color); - const nana::char_t * end = str + len; - const nana::char_t * i = std::find(str, end, '\t'); - if(i != end) - { - std::size_t tab_pixels = handle_->string.tab_length * handle_->string.tab_pixels; - while(true) - { - len = i - str; - if(len) - { - //Render a part that does not contains a tab - detail::draw_string(handle_, x, y, str, len); - x += detail::raw_text_extent_size(handle_, str, len).width; - } - - str = i; - while(str != end && (*str == '\t')) - ++str; - - if(str != end) - { - //Now i_tab is not a tab, but a non-tab character following the previous tabs - x += static_cast(tab_pixels * (str - i)); - i = std::find(str, end, '\t'); - } - else - break; - } - } - else - detail::draw_string(handle_, x, y, str, len); - if(changed_ == false) changed_ = true; - } - } - - void graphics::string(int x, int y, color_t c, const nana::char_t* str) - { - string(x, y, c, str, nana::strlen(str)); - } - - void graphics::set_pixel(int x, int y, color_t color) - { - if(handle_) - { -#if defined(NANA_WINDOWS) - ::SetPixel(handle_->context, x, y, NANA_RGB(color)); -#elif defined(NANA_X11) - Display* disp = nana::detail::platform_spec::instance().open_display(); - handle_->fgcolor(color); - ::XDrawPoint(disp, handle_->pixmap, handle_->context,x, y); -#endif - if(changed_ == false) changed_ = true; - } - } - - void graphics::rectangle(int x, int y, unsigned width, unsigned height, color_t color, bool solid) - { - if((static_cast(width) > -x) && (static_cast(height) > -y) && width && height && handle_) - { -#if defined(NANA_WINDOWS) - ::RECT r = {x, y, static_cast(x + width), static_cast(y + height)}; - handle_->brush.set(handle_->context, handle_->brush.Solid, color); - (solid ? ::FillRect : ::FrameRect)(handle_->context, &r, handle_->brush.handle); -#elif defined(NANA_X11) - Display* disp = nana::detail::platform_spec::instance().open_display(); - handle_->fgcolor(color); - if(solid) - ::XFillRectangle(disp, handle_->pixmap, handle_->context, x, y, width, height); - else - ::XDrawRectangle(disp, handle_->pixmap, handle_->context, x, y, width - 1, height - 1); -#endif - if(changed_ == false) changed_ = true; - } - } - - void graphics::rectangle(nana::color_t color, bool solid) - { - rectangle(0, 0, size_.width, size_.height, color, solid); - } - - void graphics::rectangle(const nana::rectangle & r, color_t color, bool solid) - { - rectangle(r.x, r.y, r.width, r.height, color, solid); - } - - void graphics::rectangle_line(const nana::rectangle& r, color_t color_left, color_t color_top, color_t color_right, color_t color_bottom) - { - int right = r.x + r.width - 1; - int bottom = r.y + r.height -1; - line_begin(r.x, r.y); - line_to(right, r.y, color_top); - line_to(right, bottom, color_right); - line_to(r.x, bottom, color_bottom); - line_to(r.x, r.y, color_left); - } - - void graphics::round_rectangle(int x, int y, unsigned width, unsigned height, unsigned radius_x, unsigned radius_y, color_t color, bool solid, color_t color_if_solid) - { - if(handle_) - { -#if defined(NANA_WINDOWS) - handle_->pen.set(handle_->context, PS_SOLID, 1, color); - if(solid) - { - handle_->brush.set(handle_->context, handle_->brush.Solid, color_if_solid); - ::RoundRect(handle_->context, x, y, x + static_cast(width), y + static_cast(height), static_cast(radius_x * 2), static_cast(radius_y * 2)); - } - else - { - handle_->brush.set(handle_->context, handle_->brush.Solid, color); - handle_->round_region.set(nana::rectangle(x, y, width, height), radius_x , radius_y); - ::FrameRgn(handle_->context, handle_->round_region.handle, handle_->brush.handle, 1, 1); - } - if(changed_ == false) changed_ = true; -#elif defined(NANA_X11) - if(solid && (color == color_if_solid)) - { - rectangle(x, y, width, height, color, true); - } - else - { - rectangle(x, y, width, height, color, false); - if(solid) - rectangle(x + 1, y + 1, width - 2, height - 2, color_if_solid, true); - } -#endif - } - } - - void graphics::round_rectangle(const nana::rectangle& r, unsigned radius_x, unsigned radius_y, color_t color, bool solid, color_t color_if_solid) - { - round_rectangle(r.x, r.y, r.width, r.height, radius_x, radius_y, color, solid, color_if_solid); - } - - void graphics::shadow_rectangle(const nana::rectangle& r, color_t beg_color, color_t end_color, bool vertical) - { -#if defined(NANA_WINDOWS) - if(pxbuf_.open(handle_)) - { - pxbuf_.shadow_rectangle(r, beg_color, end_color, 0.0, vertical); - pxbuf_.paste(handle_, 0, 0); - } -#elif defined(NANA_X11) - shadow_rectangle(r.x, r.y, r.width, r.height, beg_color, end_color, vertical); -#endif - } - - void graphics::shadow_rectangle(int x, int y, unsigned width, unsigned height, color_t color_begin, color_t color_end, bool vertical) - { -#if defined(NANA_WINDOWS) - if(pxbuf_.open(handle_)) - { - pxbuf_.shadow_rectangle(nana::rectangle(x, y, width, height), color_begin, color_end, 0.0, vertical); - pxbuf_.paste(handle_, 0, 0); - } -#elif defined(NANA_X11) - if(0 == handle_) return; - - int deltapx = int(vertical ? height : width); - double r, g, b; - const double delta_r = int(((color_end & 0xFF0000) >> 16) - (r = ((color_begin & 0xFF0000) >> 16))) / double(deltapx); - const double delta_g = int(((color_end & 0xFF00) >> 8) - (g = ((color_begin & 0xFF00) >> 8))) / double(deltapx); - const double delta_b = int((color_end & 0xFF) - (b = (color_begin & 0xFF))) / double(deltapx); - - unsigned last_color = (int(r) << 16) | (int(g) << 8) | int(b); - - Display * disp = nana::detail::platform_spec::instance().open_display(); - handle_->fgcolor(last_color); - const int endpos = deltapx + (vertical ? y : x); - if(endpos > 0) - { - if(vertical) - { - int x1 = x, x2 = x + static_cast(width); - for(; y < endpos; ++y) - { - ::XDrawLine(disp, handle_->pixmap, handle_->context, x1, y, x2, y); - unsigned new_color = (int(r += delta_r) << 16) | (int(g += delta_g) << 8) | int(b += delta_b); - if(new_color != last_color) - { - last_color = new_color; - handle_->fgcolor(last_color); - } - } - } - else - { - int y1 = y, y2 = y + static_cast(height); - for(; x < endpos; ++x) - { - ::XDrawLine(disp, handle_->pixmap, handle_->context, x, y1, x, y2); - unsigned new_color = (int(r += delta_r) << 16) | (int(g += delta_g) << 8) | int(b += delta_b); - if(new_color != last_color) - { - last_color = new_color; - handle_->fgcolor(last_color); - } - } - } - } -#endif - if(changed_ == false) changed_ = true; - } - - void graphics::line(int x1, int y1, int x2, int y2, color_t color) - { - if(!handle_) return; -#if defined(NANA_WINDOWS) - if(x1 != x2 || y1 != y2) - { - handle_->pen.set(handle_->context, PS_SOLID, 1, color); - - ::MoveToEx(handle_->context, x1, y1, 0); - ::LineTo(handle_->context, x2, y2); - } - ::SetPixel(handle_->context, x2, y2, NANA_RGB(color)); -#elif defined(NANA_X11) - Display* disp = nana::detail::platform_spec::instance().open_display(); - handle_->fgcolor(color); - ::XDrawLine(disp, handle_->pixmap, handle_->context, x1, y1, x2, y2); -#endif - if(changed_ == false) changed_ = true; - } - - void graphics::line(const point& beg, const point& end, color_t color) - { - line(beg.x, beg.y, end.x, end.y, color); - } - - void graphics::lines(const point* points, std::size_t n_of_points, color_t color) - { - if(!handle_ || nullptr == points || 0 == n_of_points) return; -#if defined(NANA_WINDOWS) - - handle_->pen.set(handle_->context, PS_SOLID, 1, color); - - ::MoveToEx(handle_->context, points->x, points->y, nullptr); - const point * end = points + n_of_points; - for(const point * i = points + 1; i != end; ++i) - ::LineTo(handle_->context, i->x, i->y); - - if(*points != *(end - 1)) - ::SetPixel(handle_->context, (end-1)->x, (end-1)->y, NANA_RGB(color)); -#elif defined(NANA_X11) - Display* disp = nana::detail::platform_spec::instance().open_display(); - handle_->fgcolor(color); - - XPoint * const x11points = new XPoint[n_of_points]; - XPoint * end = x11points + n_of_points; - for(XPoint * i = x11points; i != end; ++i) - { - i->x = points->x; - i->y = points->y; - ++points; - } - ::XDrawLines(disp, handle_->pixmap, handle_->context, x11points, static_cast(n_of_points), CoordModePrevious); - delete [] x11points; -#endif - if(changed_ == false) changed_ = true; - } - void graphics::line_begin(int x, int y) { if(!handle_) return; @@ -821,24 +527,6 @@ namespace paint #endif } - void graphics::line_to(int x, int y, color_t color) - { - if(!handle_) return; -#if defined(NANA_WINDOWS) - handle_->pen.set(handle_->context, PS_SOLID, 1, color); - ::LineTo(handle_->context, x, y); -#elif defined(NANA_X11) - Display* disp = nana::detail::platform_spec::instance().open_display(); - handle_->fgcolor(color); - ::XDrawLine(disp, handle_->pixmap, handle_->context, - handle_->line_begin_pos.x, handle_->line_begin_pos.y, - x, y); - handle_->line_begin_pos.x = x; - handle_->line_begin_pos.y = y; -#endif - if(changed_ == false) changed_ = true; - } - void graphics::bitblt(int x, int y, const graphics& src) { nana::rectangle r(src.size()); @@ -924,15 +612,6 @@ namespace paint } } - void graphics::blend(const nana::rectangle& r, nana::color_t color, double fade_rate) - { - if(handle_) - { - nana::paint::detail::blend(handle_, r, color, fade_rate); - if(changed_ == false) changed_ = true; - } - } - void graphics::blur(const nana::rectangle& r, std::size_t radius) { if(handle_) @@ -962,7 +641,7 @@ namespace paint pixel_buffer pixbuf(handle_, 0, 0); - nana::pixel_rgb_t * pixels = pixbuf.raw_ptr(0); + auto pixels = pixbuf.raw_ptr(0); const nana::size sz = paint::detail::drawable_size(handle_); const int rest = sz.width % 4; @@ -970,28 +649,28 @@ namespace paint for(unsigned y = 0; y < sz.height; ++y) { - pixel_rgb_t * end = pixels + length_align4; + const auto end = pixels + length_align4; for(; pixels < end; pixels += 4) { - unsigned char gray = static_cast(table_red[pixels[0].u.element.red] + table_green[pixels[0].u.element.green] + table_blue[pixels[0].u.element.blue] + 0.5f); - pixels[0].u.color = gray << 16 | gray << 8| gray; + unsigned char gray = static_cast(table_red[pixels[0].element.red] + table_green[pixels[0].element.green] + table_blue[pixels[0].element.blue] + 0.5f); + pixels[0].value = gray << 16 | gray << 8| gray; - gray = static_cast(table_red[pixels[1].u.element.red] + table_green[pixels[1].u.element.green] + table_blue[pixels[1].u.element.blue] + 0.5f); - pixels[1].u.color = gray << 16 | gray << 8| gray; + gray = static_cast(table_red[pixels[1].element.red] + table_green[pixels[1].element.green] + table_blue[pixels[1].element.blue] + 0.5f); + pixels[1].value = gray << 16 | gray << 8 | gray; - gray = static_cast(table_red[pixels[2].u.element.red] + table_green[pixels[2].u.element.green] + table_blue[pixels[2].u.element.blue] + 0.5f); - pixels[2].u.color = gray << 16 | gray << 8| gray; + gray = static_cast(table_red[pixels[2].element.red] + table_green[pixels[2].element.green] + table_blue[pixels[2].element.blue] + 0.5f); + pixels[2].value = gray << 16 | gray << 8 | gray; - gray = static_cast(table_red[pixels[3].u.element.red] + table_green[pixels[3].u.element.green] + table_blue[pixels[3].u.element.blue] + 0.5f); - pixels[3].u.color = gray << 16 | gray << 8| gray; + gray = static_cast(table_red[pixels[3].element.red] + table_green[pixels[3].element.green] + table_blue[pixels[3].element.blue] + 0.5f); + pixels[3].value = gray << 16 | gray << 8 | gray; } for(int i = 0; i < rest; ++i) { - unsigned char gray = static_cast(table_red[pixels[i].u.element.red] + table_green[pixels[i].u.element.green] + table_blue[pixels[i].u.element.blue] + 0.5f); - pixels[i].u.element.red = gray; - pixels[i].u.element.green = gray; - pixels[i].u.element.blue = gray; + unsigned char gray = static_cast(table_red[pixels[i].element.red] + table_green[pixels[i].element.green] + table_blue[pixels[i].element.blue] + 0.5f); + pixels[i].element.red = gray; + pixels[i].element.green = gray; + pixels[i].element.blue = gray; } pixels += rest; @@ -1170,18 +849,311 @@ namespace paint } } - color_t graphics::mix(color_t a, color_t b, double fade_rate) + void graphics::set_color(const ::nana::color& col) { - pixel_rgb_t pa, pb, ret; - ret.u.color = 0; - pa.u.color = a; - pb.u.color = b; + if (handle_) + handle_->set_color(col); + } - ret.u.element.red = static_cast(pa.u.element.red * fade_rate + pb.u.element.red * (1 - fade_rate)); - ret.u.element.green = static_cast(pa.u.element.green * fade_rate + pb.u.element.green * (1 - fade_rate)); - ret.u.element.blue = static_cast(pa.u.element.blue * fade_rate + pb.u.element.blue * (1 - fade_rate)); + void graphics::set_text_color(const ::nana::color& col) + { + if (handle_) + handle_->set_text_color(col); + } - return ret.u.color; + unsigned graphics::bidi_string(const nana::point& pos, const char_t * str, std::size_t len) + { + auto moved_pos = pos; + unicode_bidi bidi; + std::vector reordered; + bidi.linestr(str, len, reordered); + for (auto & i : reordered) + { + string(moved_pos, i.begin, i.end - i.begin); + moved_pos.x += static_cast(text_extent_size(i.begin, i.end - i.begin).width); + } + return static_cast(moved_pos.x - pos.x); + } + + void graphics::blend(const nana::rectangle& r, const ::nana::color& clr, double fade_rate) + { + if (handle_) + { + nana::paint::detail::blend(handle_, r, clr.px_color(), fade_rate); + if (changed_ == false) changed_ = true; + } + } + + void graphics::set_pixel(int x, int y, const ::nana::color& clr) + { + if (handle_) + { + handle_->set_color(clr); + set_pixel(x, y); + } + } + + void graphics::set_pixel(int x, int y) + { + if (handle_) + { +#if defined(NANA_WINDOWS) + ::SetPixel(handle_->context, x, y, NANA_RGB(handle_->get_color())); +#elif defined(NANA_X11) + Display* disp = nana::detail::platform_spec::instance().open_display(); + handle_->update_color(); + ::XDrawPoint(disp, handle_->pixmap, handle_->context, x, y); +#endif + if (changed_ == false) changed_ = true; + } + } + + void graphics::string(nana::point pos, const char_t* str, std::size_t len) + { + if (handle_ && str && len) + { + const nana::char_t * end = str + len; + const nana::char_t * i = std::find(str, end, '\t'); +#if defined(NANA_LINUX) + handle_->update_text_color(); +#endif + if (i != end) + { + std::size_t tab_pixels = handle_->string.tab_length * handle_->string.tab_pixels; + while (true) + { + len = i - str; + if (len) + { + //Render a part that does not contains a tab + detail::draw_string(handle_, pos, str, len); + pos.x += detail::raw_text_extent_size(handle_, str, len).width; + } + + str = i; + while (str != end && (*str == '\t')) + ++str; + + if (str != end) + { + //Now i_tab is not a tab, but a non-tab character following the previous tabs + pos.x += static_cast(tab_pixels * (str - i)); + i = std::find(str, end, '\t'); + } + else + break; + } + } + else + detail::draw_string(handle_, pos, str, len); + if (changed_ == false) changed_ = true; + } + } + + void graphics::string(const nana::point& pos, const char_t* str) + { + string(pos, str, nana::strlen(str)); + } + + void graphics::string(const nana::point& pos, const nana::string& str) + { + string(pos, str.data(), str.size()); + } + + void graphics::string(const point& pos, const ::nana::string& text, const color& clr) + { + set_text_color(clr); + string(pos, text.data(), text.size()); + } + + void graphics::line(const nana::point& pos1, const nana::point& pos2) + { + if (!handle_) return; +#if defined(NANA_WINDOWS) + handle_->update_pen(); + if (pos1 != pos2) + { + ::MoveToEx(handle_->context, pos1.x, pos1.y, 0); + ::LineTo(handle_->context, pos2.x, pos2.y); + } + ::SetPixel(handle_->context, pos2.x, pos2.y, NANA_RGB(handle_->pen.color)); +#elif defined(NANA_X11) + Display* disp = nana::detail::platform_spec::instance().open_display(); + handle_->update_color(); + ::XDrawLine(disp, handle_->pixmap, handle_->context, pos1.x, pos1.y, pos2.x, pos2.y); +#endif + if (changed_ == false) changed_ = true; + } + + void graphics::line(const point& pos_a, const point& pos_b, const color& clr) + { + set_color(clr); + line(pos_a, pos_b); + } + + void graphics::line_to(const point& pos, const color& clr) + { + if (!handle_) return; + handle_->set_color(clr); + line_to(pos); + } + + void graphics::line_to(const point& pos) + { + if (!handle_) return; +#if defined(NANA_WINDOWS) + handle_->update_pen(); + ::LineTo(handle_->context, pos.x, pos.y); +#elif defined(NANA_X11) + Display* disp = nana::detail::platform_spec::instance().open_display(); + handle_->update_color(); + ::XDrawLine(disp, handle_->pixmap, handle_->context, + handle_->line_begin_pos.x, handle_->line_begin_pos.y, + pos.x, pos.y); + handle_->line_begin_pos = pos; +#endif + if (changed_ == false) changed_ = true; + } + + void graphics::rectangle(bool solid) + { + rectangle(size(), solid); + } + + void graphics::rectangle(bool solid, const ::nana::color& clr) + { + set_color(clr); + rectangle(size(), solid); + } + + void graphics::rectangle(const ::nana::rectangle& r, bool solid) + { + if (r.width && r.height && handle_ && r.right() > 0 && r.bottom() > 0) + { +#if defined(NANA_WINDOWS) + ::RECT native_r = { r.x, r.y, r.right(), r.bottom()}; + handle_->update_brush(); + (solid ? ::FillRect : ::FrameRect)(handle_->context, &native_r, handle_->brush.handle); +#elif defined(NANA_X11) + Display* disp = nana::detail::platform_spec::instance().open_display(); + handle_->update_color(); + if (solid) + ::XFillRectangle(disp, handle_->pixmap, handle_->context, r.x, r.y, r.width, r.height); + else + ::XDrawRectangle(disp, handle_->pixmap, handle_->context, r.x, r.y, r.width - 1, r.height - 1); +#endif + if (changed_ == false) changed_ = true; + } + } + + void graphics::rectangle(const ::nana::rectangle& r, bool solid, const color& clr) + { + set_color(clr); + rectangle(r, solid); + } + + void graphics::frame_rectangle(const ::nana::rectangle& r, const ::nana::color& left_clr, const ::nana::color& top_clr, const ::nana::color& right_clr, const ::nana::color& bottom_clr) + { + int right = r.right() - 1; + int bottom = r.bottom() - 1; + line_begin(r.x, r.y); + line_to({ right, r.y }, top_clr); + line_to({ right, bottom }, right_clr); + line_to({ r.x, bottom }, bottom_clr); + line_to({ r.x, r.y }, left_clr); + } + + void graphics::gradual_rectangle(const ::nana::rectangle& rct, const ::nana::color& from, const ::nana::color& to, bool vertical) + { +#if defined(NANA_WINDOWS) + if (pxbuf_.open(handle_)) + { + pxbuf_.gradual_rectangle(rct, from, to, 0.0, vertical); + pxbuf_.paste(handle_, 0, 0); + } +#elif defined(NANA_X11) + if (nullptr == handle_) return; + + double deltapx = double(vertical ? rct.height : rct.width); + double r, g, b; + const double delta_r = (to.r() - (r = from.r())) / deltapx; + const double delta_g = (to.g() - (g = from.g())) / deltapx; + const double delta_b = (to.b() - (b = from.b())) / deltapx; + + unsigned last_color = (int(r) << 16) | (int(g) << 8) | int(b); + + Display * disp = nana::detail::platform_spec::instance().open_display(); + handle_->fgcolor(static_cast(last_color)); + const int endpos = deltapx + (vertical ? rct.y : rct.x); + if (endpos > 0) + { + if (vertical) + { + int x1 = rct.x, x2 = rct.right(); + auto y = rct.y; + for (; y < endpos; ++y) + { + ::XDrawLine(disp, handle_->pixmap, handle_->context, x1, y, x2, y); + unsigned new_color = (int(r += delta_r) << 16) | (int(g += delta_g) << 8) | int(b += delta_b); + if (new_color != last_color) + { + last_color = new_color; + handle_->fgcolor(static_cast(last_color)); + } + } + } + else + { + int y1 = rct.y, y2 = rct.bottom(); + auto x = rct.x; + for (; x < endpos; ++x) + { + ::XDrawLine(disp, handle_->pixmap, handle_->context, x, y1, x, y2); + unsigned new_color = (int(r += delta_r) << 16) | (int(g += delta_g) << 8) | int(b += delta_b); + if (new_color != last_color) + { + last_color = new_color; + handle_->fgcolor(static_cast(last_color)); + } + } + } + } +#endif + if (changed_ == false) changed_ = true; + } + + void graphics::round_rectangle(const ::nana::rectangle& r, unsigned radius_x, unsigned radius_y, const color& clr, bool solid, const color& solid_clr) + { + if (handle_) + { +#if defined(NANA_WINDOWS) + handle_->set_color(clr); + if (solid) + { + handle_->update_pen(); + handle_->brush.set(handle_->context, handle_->brush.Solid, solid_clr.px_color().value); + ::RoundRect(handle_->context, r.x, r.y, r.right(), r.bottom(), static_cast(radius_x * 2), static_cast(radius_y * 2)); + } + else + { + handle_->update_brush(); + handle_->round_region.set(r, radius_x, radius_y); + ::FrameRgn(handle_->context, handle_->round_region.handle, handle_->brush.handle, 1, 1); + } + if(changed_ == false) changed_ = true; +#elif defined(NANA_X11) + if(solid && (clr == solid_clr)) + { + rectangle(r, true, clr); + } + else + { + rectangle(r, false, clr); + if(solid) + rectangle(::nana::rectangle(r).pare_off(1), true, solid_clr); + } +#endif + } } //end class graphics diff --git a/source/paint/image.cpp b/source/paint/image.cpp index 8385fd10..ec471d6a 100644 --- a/source/paint/image.cpp +++ b/source/paint/image.cpp @@ -1,6 +1,7 @@ /* * Paint Image Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -62,6 +63,8 @@ namespace paint ::DeleteObject(info.hbmMask); return true; } +#else + if(is_ico_){} //kill the unused compiler warning in Linux. #endif return false; } diff --git a/source/paint/pixel_buffer.cpp b/source/paint/pixel_buffer.cpp index ea8590d9..bbb34b59 100644 --- a/source/paint/pixel_buffer.cpp +++ b/source/paint/pixel_buffer.cpp @@ -1,6 +1,7 @@ /* * Pixel Buffer Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -21,7 +22,6 @@ namespace nana{ namespace paint { - nana::rectangle valid_rectangle(const nana::size& s, const nana::rectangle& r) { nana::rectangle good_r; @@ -29,6 +29,21 @@ namespace nana{ namespace paint return good_r; } +#if defined(NANA_WINDOWS) + void assign_windows_bitmapinfo(const size& sz, BITMAPINFO& bi) + { + bi.bmiHeader.biSize = sizeof(bi.bmiHeader); + bi.bmiHeader.biWidth = sz.width; + bi.bmiHeader.biHeight = -static_cast(sz.height); + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 32; + bi.bmiHeader.biCompression = BI_RGB; + bi.bmiHeader.biSizeImage = static_cast(sz.width * sz.height * sizeof(pixel_color_t)); + bi.bmiHeader.biClrUsed = 0; + bi.bmiHeader.biClrImportant = 0; + } +#endif + struct pixel_buffer::pixel_buffer_storage : private nana::noncopyable { @@ -36,9 +51,9 @@ namespace nana{ namespace paint const drawable_type drawable; //Attached handle const nana::rectangle valid_r; const nana::size pixel_size; - pixel_rgb_t * raw_pixel_buffer; + pixel_color_t * raw_pixel_buffer; const std::size_t bytes_per_line; - bool alpha_channel; + bool alpha_channel{false}; #if defined(NANA_X11) struct x11_members { @@ -49,25 +64,20 @@ namespace nana{ namespace paint struct image_processor_tag { - paint::image_process::stretch_interface * stretch_receptacle; + paint::image_process::stretch_interface * stretch_receptacle{nullptr}; paint::image_process::stretch_interface * const * stretch; - paint::image_process::alpha_blend_interface * alpha_blend_receptacle; + paint::image_process::alpha_blend_interface * alpha_blend_receptacle{nullptr}; paint::image_process::alpha_blend_interface * const * alpha_blend; - paint::image_process::blend_interface * blend_receptacle; + paint::image_process::blend_interface * blend_receptacle{nullptr}; paint::image_process::blend_interface * const * blend; - paint::image_process::line_interface * line_receptacle; + paint::image_process::line_interface * line_receptacle{nullptr}; paint::image_process::line_interface * const * line; - paint::image_process::blur_interface * blur_receptacle; + paint::image_process::blur_interface * blur_receptacle{nullptr}; paint::image_process::blur_interface * const * blur; image_processor_tag() - : stretch_receptacle(nullptr), - alpha_blend_receptacle(nullptr), - blend_receptacle(nullptr), - line_receptacle(nullptr), - blur_receptacle(nullptr) { - detail::image_process_provider & provider = detail::image_process_provider::instance(); + auto & provider = detail::image_process_provider::instance(); stretch = provider.stretch(); alpha_blend = provider.alpha_blend(); blend = provider.blend(); @@ -80,9 +90,8 @@ namespace nana{ namespace paint : drawable(nullptr), valid_r(0, 0, static_cast(width), static_cast(height)), pixel_size(static_cast(width), static_cast(height)), - raw_pixel_buffer(new pixel_rgb_t[width * height]), - bytes_per_line(width * sizeof(pixel_rgb_t)), - alpha_channel(false) + raw_pixel_buffer(new pixel_color_t[width * height]), + bytes_per_line(width * sizeof(pixel_color_t)) { #if defined(NANA_X11) nana::detail::platform_spec & spec = nana::detail::platform_spec::instance(); @@ -93,7 +102,7 @@ namespace nana{ namespace paint delete [] raw_pixel_buffer; throw std::runtime_error("Nana.pixel_buffer: XCreateImage failed"); } - + if(static_cast(bytes_per_line) != x11.image->bytes_per_line) { x11.image->data = nullptr; @@ -109,17 +118,16 @@ namespace nana{ namespace paint valid_r(valid_rectangle(paint::detail::drawable_size(drawable), want_r)), pixel_size(valid_r), #if defined(NANA_WINDOWS) - raw_pixel_buffer(reinterpret_cast(reinterpret_cast(drawable->pixbuf_ptr + valid_r.x) + drawable->bytes_per_line * valid_r.y)), - bytes_per_line(drawable->bytes_per_line), + raw_pixel_buffer(reinterpret_cast(reinterpret_cast(drawable->pixbuf_ptr + valid_r.x) + drawable->bytes_per_line * valid_r.y)), + bytes_per_line(drawable->bytes_per_line) #else raw_pixel_buffer(nullptr), - bytes_per_line(sizeof(pixel_rgb_t) * valid_r.width), + bytes_per_line(sizeof(pixel_color_t) * valid_r.width) #endif - alpha_channel(false) { #if defined(NANA_X11) nana::detail::platform_spec & spec = nana::detail::platform_spec::instance(); - + //Ensure that the pixmap is updated before we copy its content. ::XFlush(spec.open_display()); x11.image = ::XGetImage(spec.open_display(), drawable->pixmap, valid_r.x, valid_r.y, valid_r.width, valid_r.height, AllPlanes, ZPixmap); @@ -134,12 +142,12 @@ namespace nana{ namespace paint XDestroyImage(x11.image); throw std::runtime_error("Nana.pixel_buffer: Invalid pixel buffer context."); } - raw_pixel_buffer = reinterpret_cast(x11.image->data); + raw_pixel_buffer = reinterpret_cast(x11.image->data); } else if(16 == x11.image->depth) { //565 to 32 - raw_pixel_buffer = new pixel_rgb_t[valid_r.width * valid_r.height]; + raw_pixel_buffer = new pixel_color_t[valid_r.width * valid_r.height]; assign(reinterpret_cast(x11.image->data), valid_r.width, valid_r.height, 16, x11.image->bytes_per_line, false); } else @@ -160,7 +168,7 @@ namespace nana{ namespace paint if(x11.image->data != reinterpret_cast(raw_pixel_buffer)) delete [] raw_pixel_buffer; - + XDestroyImage(x11.image); #else if(nullptr == drawable) //not attached @@ -170,160 +178,119 @@ namespace nana{ namespace paint void assign(const unsigned char* rawbits, std::size_t width, std::size_t height, std::size_t bits_per_pixel, std::size_t bytes_per_line, bool is_negative) { - pixel_rgb_t * rawptr = raw_pixel_buffer; - if(rawptr) + if (!raw_pixel_buffer) + return; + + auto rawptr = raw_pixel_buffer; + if(32 == bits_per_pixel) { - if(32 == bits_per_pixel) + if((pixel_size.width == width) && (pixel_size.height == height) && is_negative) { - if((pixel_size.width == width) && (pixel_size.height == height) && is_negative) - { - memcpy(rawptr, rawbits, (pixel_size.width * pixel_size.height) * 4); - } - else - { - std::size_t line_bytes = (pixel_size.width < width ? pixel_size.width : width) * sizeof(pixel_rgb_t); - - if(pixel_size.height < height) - height = pixel_size.height; - - pixel_rgb_t * d = rawptr; - if(is_negative) - { - const unsigned char* s = rawbits; - for(std::size_t i = 0; i < height; ++i) - { - memcpy(d, s, line_bytes); - d += pixel_size.width; - s += bytes_per_line; - } - } - else - { - const unsigned char* s = rawbits + bytes_per_line * (height - 1); - for(std::size_t i = 0; i < height; ++i) - { - memcpy(d, s, line_bytes); - d += pixel_size.width; - s -= bytes_per_line; - } - } - } + memcpy(rawptr, rawbits, (pixel_size.width * pixel_size.height) * 4); } - else if(24 == bits_per_pixel) + else { - if(pixel_size.width < width) - width = pixel_size.width; + std::size_t line_bytes = (pixel_size.width < width ? pixel_size.width : width) * sizeof(pixel_color_t); if(pixel_size.height < height) height = pixel_size.height; - pixel_rgb_t * d = rawptr; - if(is_negative) + auto d = rawptr; + const unsigned char* s; + int src_line_bytes; + + if (is_negative) { - const unsigned char* s = rawbits; - for(std::size_t i = 0; i < height; ++i) - { - pixel_rgb_t * p = d; - pixel_rgb_t * end = p + width; - std::size_t s_index = 0; - for(; p < end; ++p) - { - const unsigned char * s_p = s + s_index; - p->u.element.blue = s_p[0]; - p->u.element.green = s_p[1]; - p->u.element.red = s_p[2]; - s_index += 3; - } - d += pixel_size.width; - s += bytes_per_line; - } + s = rawbits; + src_line_bytes = -static_cast(bytes_per_line); } else { - const unsigned char* s = rawbits + bytes_per_line * (height - 1); - for(std::size_t i = 0; i < height; ++i) - { - pixel_rgb_t * p = d; - pixel_rgb_t * end = p + width; - const unsigned char* s_p = s; - for(; p < end; ++p) - { - p->u.element.blue = s_p[0]; - p->u.element.green = s_p[1]; - p->u.element.red = s_p[2]; - s_p += 3; - } - d += pixel_size.width; - s -= bytes_per_line; - } + s = rawbits + bytes_per_line * (height - 1); + src_line_bytes = static_cast(bytes_per_line); + } + + for(std::size_t i = 0; i < height; ++i) + { + memcpy(d, s, line_bytes); + d += pixel_size.width; + s -= src_line_bytes; } } - else if(16 == bits_per_pixel) + } + else if(24 == bits_per_pixel) + { + if(pixel_size.width < width) + width = pixel_size.width; + + if(pixel_size.height < height) + height = pixel_size.height; + + auto d = rawptr; + const unsigned char* s; + + if (is_negative) + s = rawbits; + else + s = rawbits + bytes_per_line * (height - 1); + + for(std::size_t i = 0; i < height; ++i) { - if(pixel_size.width < width) - width = pixel_size.width; - - if(pixel_size.height < height) - height = pixel_size.height; - - pixel_rgb_t * d = rawptr; - - unsigned char * rgb_table = new unsigned char[32]; - - for(std::size_t i =0; i < 32; ++i) - rgb_table[i] = static_cast(i * 255 / 31); - - if(is_negative) + auto p = d; + const auto end = p + width; + const unsigned char* s_p = s; + for(; p < end; ++p) { - //const unsigned short* s = reinterpret_cast(rawbits); - for(std::size_t i = 0; i < height; ++i) - { - pixel_rgb_t * p = d; - const pixel_rgb_t * const end = p + width; - const unsigned short* s_p = reinterpret_cast(rawbits); - for(; p < end; ++p) - { - p->u.element.red = rgb_table[(*s_p >> 11) & 0x1F]; -#if defined(NANA_X11) - p->u.element.green = (*s_p >> 5) & 0x3F; - p->u.element.blue = rgb_table[*s_p & 0x1F]; -#else - p->u.element.green = rgb_table[(*s_p>> 6) & 0x1F]; - p->u.element.blue = rgb_table[(*s_p >> 1) & 0x1F]; -#endif - ++s_p; - } - d += pixel_size.width; - rawbits += bytes_per_line; - } + p->element.blue = s_p[0]; + p->element.green = s_p[1]; + p->element.red = s_p[2]; + s_p += 3; } - else + d += pixel_size.width; + s -= bytes_per_line; + } + } + else if(16 == bits_per_pixel) + { + if(pixel_size.width < width) + width = pixel_size.width; + + if(pixel_size.height < height) + height = pixel_size.height; + + unsigned char rgb_table[32]; + for(std::size_t i =0; i < 32; ++i) + rgb_table[i] = static_cast(i * 255 / 31); + + int src_bytes_per_line; + if (!is_negative) + { + rawbits += bytes_per_line * (height - 1); + src_bytes_per_line = static_cast(bytes_per_line); + } + else + src_bytes_per_line = -static_cast(bytes_per_line); + + auto d = rawptr; + for (std::size_t i = 0; i < height; ++i) + { + auto p = d; + const auto end = p + width; + auto s_p = reinterpret_cast(rawbits); + for (; p < end; ++p) { - // const unsigned short* s = reinterpret_cast(rawbits + bytes_per_line * (height - 1)); - rawbits += bytes_per_line * (height - 1); - for(std::size_t i = 0; i < height; ++i) - { - pixel_rgb_t * p = d; - const pixel_rgb_t * const end = p + width; - const unsigned short* s_p = reinterpret_cast(rawbits); - for(; p < end; ++p) - { - p->u.element.red = rgb_table[(*s_p >> 11) & 0x1F]; + p->element.red = rgb_table[(*s_p >> 11) & 0x1F]; #if defined(NANA_X11) - p->u.element.green = ((*s_p >> 5) & 0x3F); - p->u.element.blue = rgb_table[*s_p & 0x1F]; + p->element.green = (*s_p >> 5) & 0x3F; + p->element.blue = rgb_table[*s_p & 0x1F]; #else - p->u.element.green = rgb_table[(*s_p & 0x7C0) >> 6]; - p->u.element.blue = rgb_table[(*s_p >> 1) & 0x1F]; + p->element.green = rgb_table[(*s_p >> 6) & 0x1F]; + p->element.blue = rgb_table[(*s_p >> 1) & 0x1F]; #endif - ++s_p; - } - d += pixel_size.width; - //s -= bytes_per_line; - rawbits -= bytes_per_line; - } + ++s_p; } - delete [] rgb_table; + d += pixel_size.width; + rawbits -= src_bytes_per_line; } } } @@ -337,14 +304,14 @@ namespace nana{ namespace paint } void put(Drawable dw, GC gc, int src_x, int src_y, int x, int y, unsigned width, unsigned height) - { + { auto & spec = nana::detail::platform_spec::instance(); Display * disp = spec.open_display(); const int depth = spec.screen_depth(); XImage* img = ::XCreateImage(disp, spec.screen_visual(), depth, ZPixmap, 0, 0, pixel_size.width, pixel_size.height, (16 == depth ? 16 : 32), 0); - if(sizeof(pixel_rgb_t) * 8 == depth || 24 == depth) - { + if(sizeof(pixel_color_t) * 8 == depth || 24 == depth) + { img->data = reinterpret_cast(raw_pixel_buffer); ::XPutImage(disp, dw, gc, img, src_x, src_y, x, y, width, height); @@ -356,7 +323,7 @@ namespace nana{ namespace paint unsigned short * const fast_table = table_holder.get(); for(int i = 0; i < 256; ++i) fast_table[i] = i * 31 / 255; - + std::size_t length = width * height; std::unique_ptr px_holder(new unsigned short[length]); @@ -366,20 +333,20 @@ namespace nana{ namespace paint { for(auto i = raw_pixel_buffer, end = raw_pixel_buffer + length; i != end; ++i) { - *(pixbuf_16bits++) = (fast_table[i->u.element.red] << 11) | ( (i->u.element.green * 63 / 255) << 6) | fast_table[i->u.element.blue]; + *(pixbuf_16bits++) = (fast_table[i->element.red] << 11) | ( (i->element.green * 63 / 255) << 6) | fast_table[i->element.blue]; } } else if(height) { unsigned sp_line_len = pixel_size.width; auto sp = raw_pixel_buffer + (src_x + sp_line_len * src_y); - + unsigned top = 0; while(true) { for(auto i = sp, end = sp + width; i != end; ++i) { - *(pixbuf_16bits++) = (fast_table[i->u.element.red] << 11) | ((i->u.element.green * 63 / 255) << 6) | fast_table[i->u.element.blue]; + *(pixbuf_16bits++) = (fast_table[i->element.red] << 11) | ((i->element.green * 63 / 255) << 6) | fast_table[i->element.blue]; } if(++top < height) @@ -389,7 +356,7 @@ namespace nana{ namespace paint img->data = reinterpret_cast(px_holder.get()); ::XPutImage(disp, dw, gc, - img, src_x, src_y, x, y, width, height); + img, src_x, src_y, x, y, width, height); } img->data = nullptr; //Set null pointer to avoid XDestroyImage destroyes the buffer. XDestroyImage(img); @@ -397,9 +364,6 @@ namespace nana{ namespace paint #endif }; - pixel_buffer::pixel_buffer() - {} - pixel_buffer::pixel_buffer(drawable_type drawable, const nana::rectangle& want_rectangle) { open(drawable, want_rectangle); @@ -445,15 +409,7 @@ namespace nana{ namespace paint } BITMAPINFO bmpinfo; - bmpinfo.bmiHeader.biSize = sizeof(bmpinfo.bmiHeader); - bmpinfo.bmiHeader.biWidth = sz.width; - bmpinfo.bmiHeader.biHeight = -static_cast(sz.height); - bmpinfo.bmiHeader.biPlanes = 1; - bmpinfo.bmiHeader.biBitCount = 32; - bmpinfo.bmiHeader.biCompression = BI_RGB; - bmpinfo.bmiHeader.biSizeImage = static_cast(sz.width * sz.height * sizeof(pixel_rgb_t)); - bmpinfo.bmiHeader.biClrUsed = 0; - bmpinfo.bmiHeader.biClrImportant = 0; + assign_windows_bitmapinfo(sz, bmpinfo); std::size_t read_lines = ::GetDIBits(drawable->context, drawable->pixmap, 0, static_cast(sz.height), sp->raw_pixel_buffer, &bmpinfo, DIB_RGB_COLORS); @@ -486,15 +442,7 @@ namespace nana{ namespace paint return false; #if defined(NANA_WINDOWS) BITMAPINFO bmpinfo; - bmpinfo.bmiHeader.biSize = sizeof(bmpinfo.bmiHeader); - bmpinfo.bmiHeader.biWidth = want_r.width; - bmpinfo.bmiHeader.biHeight = -static_cast(want_r.height); - bmpinfo.bmiHeader.biPlanes = 1; - bmpinfo.bmiHeader.biBitCount = 32; - bmpinfo.bmiHeader.biCompression = BI_RGB; - bmpinfo.bmiHeader.biSizeImage = static_cast(want_r.width * want_r.height * sizeof(pixel_rgb_t)); - bmpinfo.bmiHeader.biClrUsed = 0; - bmpinfo.bmiHeader.biClrImportant = 0; + assign_windows_bitmapinfo({want_r.width, want_r.height}, bmpinfo); bool need_dup = (r.width != sz.width || r.height != sz.height); @@ -532,7 +480,7 @@ namespace nana{ namespace paint XImage * image = ::XGetImage(spec.open_display(), drawable->pixmap, r.x, r.y, r.width, r.height, AllPlanes, ZPixmap); storage_ = std::make_shared(want_r.width, want_r.height); - pixel_rgb_t * pixbuf = storage_->raw_pixel_buffer; + auto pixbuf = storage_->raw_pixel_buffer; if(image->depth == 32 || (image->depth == 24 && image->bitmap_pad == 32)) { if(want_r.width != static_cast(image->width) || want_r.height != static_cast(image->height)) @@ -567,14 +515,14 @@ namespace nana{ namespace paint for(int x = 0; x < image->width; ++x) { - pixbuf[x].u.element.red = fast_table[(px_data[x] >> 11) & 0x1F]; - pixbuf[x].u.element.green = (px_data[x] >> 5) & 0x3F; - pixbuf[x].u.element.blue = fast_table[px_data[x] & 0x1F]; - pixbuf[x].u.element.alpha_channel = 0; + pixbuf[x].element.red = fast_table[(px_data[x] >> 11) & 0x1F]; + pixbuf[x].element.green = (px_data[x] >> 5) & 0x3F; + pixbuf[x].element.blue = fast_table[px_data[x] & 0x1F]; + pixbuf[x].element.alpha_channel = 0; } img_data += image->bytes_per_line; pixbuf += want_r.width; - } + } } else { @@ -627,7 +575,7 @@ namespace nana{ namespace paint { auto sp = storage_.get(); if(sp) - return sizeof(pixel_rgb_t) * (static_cast(sp->pixel_size.width) * static_cast(sp->pixel_size.height)); + return sizeof(pixel_color_t) * (static_cast(sp->pixel_size.width) * static_cast(sp->pixel_size.height)); return 0; } @@ -641,26 +589,26 @@ namespace nana{ namespace paint return (storage_ ? storage_->pixel_size : nana::size()); } - pixel_rgb_t * pixel_buffer::at(const point& pos) const + pixel_color_t * pixel_buffer::at(const point& pos) const { - pixel_buffer_storage * sp = storage_.get(); + auto sp = storage_.get(); if (sp && (pos.y < static_cast(sp->pixel_size.height) + sp->valid_r.y)) - return reinterpret_cast(reinterpret_cast(sp->raw_pixel_buffer) + sp->bytes_per_line * (pos.y - sp->valid_r.y)) + (pos.x - sp->valid_r.x); + return reinterpret_cast(reinterpret_cast(sp->raw_pixel_buffer) + sp->bytes_per_line * (pos.y - sp->valid_r.y)) + (pos.x - sp->valid_r.x); return nullptr; } - pixel_rgb_t * pixel_buffer::raw_ptr(std::size_t row) const + pixel_color_t * pixel_buffer::raw_ptr(std::size_t row) const { - pixel_buffer_storage * sp = storage_.get(); + auto sp = storage_.get(); if(sp && (row < sp->pixel_size.height)) - return reinterpret_cast(reinterpret_cast(sp->raw_pixel_buffer) + sp->bytes_per_line * row); + return reinterpret_cast(reinterpret_cast(sp->raw_pixel_buffer) + sp->bytes_per_line * row); return nullptr; } - pixel_rgb_t * pixel_buffer::operator[](std::size_t row) const + pixel_color_t * pixel_buffer::operator[](std::size_t row) const { - pixel_buffer_storage * sp = storage_.get(); - return reinterpret_cast(reinterpret_cast(sp->raw_pixel_buffer) + sp->bytes_per_line * row); + auto sp = storage_.get(); + return reinterpret_cast(reinterpret_cast(sp->raw_pixel_buffer) + sp->bytes_per_line * row); } void pixel_buffer::put(const unsigned char* rawbits, std::size_t width, std::size_t height, std::size_t bits_per_pixel, std::size_t bytes_per_line, bool is_negative) @@ -669,20 +617,20 @@ namespace nana{ namespace paint storage_->assign(rawbits, width, height, bits_per_pixel, bytes_per_line, is_negative); } - pixel_rgb_t pixel_buffer::pixel(int x, int y) const + pixel_color_t pixel_buffer::pixel(int x, int y) const { - pixel_buffer_storage * sp = storage_.get(); + auto sp = storage_.get(); if(sp && 0 <= x && x < static_cast(sp->pixel_size.width) && 0 <= y && y < static_cast(sp->pixel_size.height)) - return *reinterpret_cast(reinterpret_cast(sp->raw_pixel_buffer + x) + y * sp->bytes_per_line); + return *reinterpret_cast(reinterpret_cast(sp->raw_pixel_buffer + x) + y * sp->bytes_per_line); - return pixel_rgb_t(); + return pixel_color_t(); } - void pixel_buffer::pixel(int x, int y, pixel_rgb_t px) + void pixel_buffer::pixel(int x, int y, pixel_color_t px) { - pixel_buffer_storage * sp = storage_.get(); + auto sp = storage_.get(); if(sp && 0 <= x && x < static_cast(sp->pixel_size.width) && 0 <= y && y < static_cast(sp->pixel_size.height)) - *reinterpret_cast(reinterpret_cast(sp->raw_pixel_buffer + x) + y * sp->bytes_per_line) = px; + *reinterpret_cast(reinterpret_cast(sp->raw_pixel_buffer + x) + y * sp->bytes_per_line) = px; } void pixel_buffer::paste(drawable_type drawable, int x, int y) const @@ -693,7 +641,7 @@ namespace nana{ namespace paint void pixel_buffer::paste(const nana::rectangle& src_r, drawable_type drawable, int x, int y) const { - pixel_buffer_storage * sp = storage_.get(); + auto sp = storage_.get(); if(drawable && sp) { if(sp->alpha_channel) @@ -709,15 +657,7 @@ namespace nana{ namespace paint } #if defined(NANA_WINDOWS) BITMAPINFO bi; - bi.bmiHeader.biSize = sizeof(bi.bmiHeader); - bi.bmiHeader.biWidth = sp->pixel_size.width; - bi.bmiHeader.biHeight = -static_cast(sp->pixel_size.height); - bi.bmiHeader.biPlanes = 1; - bi.bmiHeader.biBitCount = sizeof(pixel_rgb_t) * 8; - bi.bmiHeader.biCompression = BI_RGB; - bi.bmiHeader.biSizeImage = static_cast(sizeof(pixel_rgb_t) * sp->pixel_size.width * sp->pixel_size.height); - bi.bmiHeader.biClrUsed = 0; - bi.bmiHeader.biClrImportant = 0; + assign_windows_bitmapinfo(sp->pixel_size, bi); ::SetDIBitsToDevice(drawable->context, x, y, src_r.width, src_r.height, @@ -731,22 +671,14 @@ namespace nana{ namespace paint void pixel_buffer::paste(native_window_type wd, int x, int y) const { - pixel_buffer_storage * sp = storage_.get(); + auto sp = storage_.get(); if(nullptr == wd || nullptr == sp) return; #if defined(NANA_WINDOWS) HDC handle = ::GetDC(reinterpret_cast(wd)); if(handle) { BITMAPINFO bi; - bi.bmiHeader.biSize = sizeof(bi.bmiHeader); - bi.bmiHeader.biWidth = sp->pixel_size.width; - bi.bmiHeader.biHeight = -static_cast(sp->pixel_size.height); - bi.bmiHeader.biPlanes = 1; - bi.bmiHeader.biBitCount = sizeof(pixel_rgb_t) * 8; - bi.bmiHeader.biCompression = BI_RGB; - bi.bmiHeader.biSizeImage = static_cast(sizeof(pixel_rgb_t) * sp->pixel_size.width * sp->pixel_size.height); - bi.bmiHeader.biClrUsed = 0; - bi.bmiHeader.biClrImportant = 0; + assign_windows_bitmapinfo(sp->pixel_size, bi); ::SetDIBitsToDevice(handle, x, y, sp->pixel_size.width, sp->pixel_size.height, @@ -760,57 +692,60 @@ namespace nana{ namespace paint Display * disp = spec.open_display(); sp->put(reinterpret_cast(wd), XDefaultGC(disp, XDefaultScreen(disp)), 0, 0, x, y, sp->pixel_size.width, sp->pixel_size.height); #endif - } void pixel_buffer::line(const std::string& name) { - pixel_buffer_storage * sp = storage_.get(); - if(sp && name.size()) + if (storage_ && name.size()) { - sp->img_pro.line_receptacle = detail::image_process_provider::instance().ref_line(name); - if(sp->img_pro.line_receptacle == *detail::image_process_provider::instance().line()) - sp->img_pro.line = detail::image_process_provider::instance().line(); + auto & img_pro = storage_->img_pro; + img_pro.line_receptacle = detail::image_process_provider::instance().ref_line(name); + if(img_pro.line_receptacle == *detail::image_process_provider::instance().line()) + img_pro.line = detail::image_process_provider::instance().line(); else - sp->img_pro.line = & sp->img_pro.line_receptacle; + img_pro.line = &img_pro.line_receptacle; } } - void pixel_buffer::line(const nana::point &pos_beg, const nana::point &pos_end, nana::color_t color, double fade_rate) + void pixel_buffer::line(const point &pos_beg, const point &pos_end, const ::nana::color& clr, double fade_rate) { - pixel_buffer_storage * sp = storage_.get(); + auto sp = storage_.get(); if(nullptr == sp) return; //Test if the line intersects the rectangle, and retrive the two points that //are always in the area of rectangle, good_pos_beg is left point, good_pos_end is right. nana::point good_pos_beg, good_pos_end; if(intersection(nana::rectangle(sp->pixel_size), pos_beg, pos_end, good_pos_beg, good_pos_end)) - (*(sp->img_pro.line))->process(*this, good_pos_beg, good_pos_end, color, fade_rate); + (*(sp->img_pro.line))->process(*this, good_pos_beg, good_pos_end, clr, fade_rate); } - void pixel_buffer::rectangle(const nana::rectangle &r, nana::color_t col, double fade_rate, bool solid) + void pixel_buffer::rectangle(const nana::rectangle &r, const ::nana::color& clr, double fade_rate, bool solid) { - pixel_buffer_storage * sp = storage_.get(); + auto sp = storage_.get(); if((nullptr == sp) || (fade_rate == 1.0)) return; bool fade = (fade_rate != 0.0); unsigned char * fade_table = nullptr; - nana::pixel_rgb_t rgb_imd; + std::unique_ptr autoptr; + + auto rgb_color = clr.px_color().value; + nana::pixel_color_t rgb_imd; if(fade) { - fade_table = detail::alloc_fade_table(1 - fade_rate); - rgb_imd.u.color = col; + autoptr = detail::alloc_fade_table(1 - fade_rate); + fade_table = autoptr.get(); + rgb_imd.value = rgb_color; rgb_imd = detail::fade_color_intermedia(rgb_imd, fade_table); } int xbeg = (0 <= r.x ? r.x : 0); int xend = static_cast(r.x + r.width < sp->pixel_size.width ? r.x + r.width : sp->pixel_size.width); - int ybeg = (0 <= r.y ? r.y : 0); + const int ybeg = (0 <= r.y ? r.y : 0); int yend = static_cast(r.y + r.height < sp->pixel_size.height ? r.y + r.height : sp->pixel_size.height); + const auto p_rgb = sp->raw_pixel_buffer + ybeg * sp->pixel_size.width; if (solid) { - nana::pixel_rgb_t * p_rgb = sp->raw_pixel_buffer + ybeg * sp->pixel_size.width; auto lineptr = p_rgb + xbeg; auto end = p_rgb + xend; if (fade) @@ -830,9 +765,8 @@ namespace nana{ namespace paint for (int top = ybeg; top < yend; ++top) { for (auto i = lineptr; i != end; ++i) - { - i->u.color = col; - } + i->value = rgb_color; + lineptr += sp->pixel_size.width; end = lineptr + (xend - xbeg); } @@ -842,10 +776,9 @@ namespace nana{ namespace paint if((ybeg == r.y) && (r.y + static_cast(r.height) == yend)) { - nana::pixel_rgb_t * p_rgb = sp->raw_pixel_buffer + ybeg * sp->pixel_size.width; - nana::pixel_rgb_t * i = p_rgb + xbeg; - nana::pixel_rgb_t * end = p_rgb + xend; - nana::pixel_rgb_t * i_other = sp->raw_pixel_buffer + (yend - 1) * sp->pixel_size.width + xbeg; + auto i = p_rgb + xbeg; + auto end = p_rgb + xend; + auto i_other = sp->raw_pixel_buffer + (yend - 1) * sp->pixel_size.width + xbeg; if(fade) { for(;i != end; ++i, ++i_other) @@ -858,8 +791,8 @@ namespace nana{ namespace paint { for(;i != end; ++i, ++i_other) { - i->u.color = col; - i_other->u.color = col; + i->value = rgb_color; + i_other->value = rgb_color; } } } @@ -867,9 +800,8 @@ namespace nana{ namespace paint { if(ybeg == r.y) { - nana::pixel_rgb_t * p_rgb = sp->raw_pixel_buffer + ybeg * sp->pixel_size.width; - nana::pixel_rgb_t * i = p_rgb; - nana::pixel_rgb_t * end = p_rgb + xend; + auto i = p_rgb; + auto end = p_rgb + xend; if(fade) { for(; i != end; ++i) @@ -878,15 +810,15 @@ namespace nana{ namespace paint else { for(;i != end; ++i) - i->u.color = col; + i->value = rgb_color; } } if(r.y + static_cast(r.height) == yend) { - nana::pixel_rgb_t * p_rgb = sp->raw_pixel_buffer + (yend - 1) * sp->pixel_size.width; - nana::pixel_rgb_t * i = p_rgb; - nana::pixel_rgb_t * end = p_rgb + xend; + auto p_rgb = sp->raw_pixel_buffer + (yend - 1) * sp->pixel_size.width; + auto i = p_rgb; + auto end = p_rgb + xend; if(fade) { @@ -896,18 +828,16 @@ namespace nana{ namespace paint else { for(;i != end; ++i) - i->u.color = col; + i->value = rgb_color; } } } if((xbeg == r.x) && (r.x + static_cast(r.width) == xend)) { - nana::pixel_rgb_t * p_rgb = sp->raw_pixel_buffer + ybeg * sp->pixel_size.width; - nana::pixel_rgb_t * i = p_rgb + xbeg; - nana::pixel_rgb_t * end = sp->raw_pixel_buffer + (yend - 1) * sp->pixel_size.width + xbeg; - - nana::pixel_rgb_t * i_other = p_rgb + (xend - 1); + auto i = p_rgb + xbeg; + auto end = sp->raw_pixel_buffer + (yend - 1) * sp->pixel_size.width + xbeg; + auto i_other = p_rgb + (xend - 1); if(fade) { @@ -926,8 +856,8 @@ namespace nana{ namespace paint { while(true) { - i->u.color = col; - i_other->u.color = col; + i->value = rgb_color; + i_other->value = rgb_color; if(i == end) break; @@ -940,9 +870,8 @@ namespace nana{ namespace paint { if(xbeg == r.x) { - nana::pixel_rgb_t * p_rgb = sp->raw_pixel_buffer + ybeg * sp->pixel_size.width; - nana::pixel_rgb_t * i = p_rgb + xbeg; - nana::pixel_rgb_t * end = sp->raw_pixel_buffer + (yend - 1) * sp->pixel_size.width + xbeg; + auto i = p_rgb + xbeg; + auto end = sp->raw_pixel_buffer + (yend - 1) * sp->pixel_size.width + xbeg; if(fade) { while(true) @@ -957,7 +886,7 @@ namespace nana{ namespace paint { while(true) { - i->u.color = col; + i->value = rgb_color; if(i == end) break; i += sp->pixel_size.width; @@ -967,9 +896,8 @@ namespace nana{ namespace paint if(r.x + static_cast(r.width) == xend) { - nana::pixel_rgb_t * p_rgb = sp->raw_pixel_buffer + ybeg * sp->pixel_size.width; - nana::pixel_rgb_t * i = p_rgb + (xend - 1); - nana::pixel_rgb_t * end = sp->raw_pixel_buffer + (yend - 1) * sp->pixel_size.width + (xend - 1); + auto i = p_rgb + (xend - 1); + auto end = sp->raw_pixel_buffer + (yend - 1) * sp->pixel_size.width + (xend - 1); if(fade) { while(true) @@ -983,78 +911,72 @@ namespace nana{ namespace paint { while(true) { - i->u.color = col; + i->value = rgb_color; if(i == end) break; i += sp->pixel_size.width; } } } } - - detail::free_fade_table(fade_table); } - void pixel_buffer::shadow_rectangle(const nana::rectangle& draw_rct, nana::color_t beg, nana::color_t end, double fade_rate, bool vertical) + void pixel_buffer::gradual_rectangle(const ::nana::rectangle& draw_rct, const ::nana::color& from, const ::nana::color& to, double fade_rate, bool vertical) { - pixel_buffer_storage * sp = storage_.get(); - if(nullptr == sp) return; + auto sp = storage_.get(); + if (nullptr == sp) return; nana::rectangle rct; - if(false == overlap(nana::rectangle(sp->pixel_size), draw_rct, rct)) + if (false == overlap(nana::rectangle(sp->pixel_size), draw_rct, rct)) return; int deltapx = int(vertical ? rct.height : rct.width); - if(sp && deltapx) + if (sp && deltapx) { - nana::color_t r, g, b; + auto beg = from.px_color().value; + auto end = to.px_color().value; + unsigned r, g, b; const int delta_r = (int(end & 0xFF0000) - int(r = (beg & 0xFF0000))) / deltapx; const int delta_g = (int((end & 0xFF00) << 8) - int(g = ((beg & 0xFF00) << 8))) / deltapx; - const int delta_b = (int((end & 0xFF) << 16 ) - int(b = ((beg & 0xFF)<< 16))) / deltapx; + const int delta_b = (int((end & 0xFF) << 16) - int(b = ((beg & 0xFF) << 16))) / deltapx; - nana::pixel_rgb_t * pxbuf = sp->raw_pixel_buffer + rct.x + rct.y * sp->pixel_size.width; - if(vertical) + auto pxbuf = sp->raw_pixel_buffer + rct.x + rct.y * sp->pixel_size.width; + if (vertical) { - if(deltapx + rct.y > 0) + unsigned align_4 = (rct.width & ~3); + unsigned align_reset = rct.width & 3; + while (deltapx--) { - unsigned align_4 = (rct.width & ~3); - unsigned align_reset = rct.width & 3; - while(deltapx--) + nana::pixel_color_t px; + px.value = ((r += delta_r) & 0xFF0000) | (((g += delta_g) & 0xFF0000) >> 8) | (((b += delta_b) & 0xFF0000) >> 16); + + auto dpx = pxbuf; + for (auto dpx_end = pxbuf + align_4; dpx != dpx_end; dpx += 4) { - nana::pixel_rgb_t px; - - px.u.color = ((r += delta_r) & 0xFF0000) | (((g += delta_g) & 0xFF0000) >> 8) | (((b += delta_b) & 0xFF0000) >> 16); - - nana::pixel_rgb_t * dpx = pxbuf; - for(nana::pixel_rgb_t *dpx_end = pxbuf + align_4; dpx != dpx_end; dpx += 4) - { - *dpx = px; - dpx[1] = px; - dpx[2] = px; - dpx[3] = px; - } - - for(nana::pixel_rgb_t * dpx_end = dpx + align_reset; dpx != dpx_end; ++dpx) - *dpx = px; - - pxbuf += sp->pixel_size.width; + *dpx = px; + dpx[1] = px; + dpx[2] = px; + dpx[3] = px; } + + for (auto dpx_end = dpx + align_reset; dpx != dpx_end; ++dpx) + *dpx = px; + + pxbuf += sp->pixel_size.width; } } else { - if(deltapx + rct.x > 0) - { - nana::pixel_rgb_t * pxbuf_end = pxbuf + rct.width; + auto pxbuf_end = pxbuf + rct.width; - for(; pxbuf != pxbuf_end; ++pxbuf) - { - nana::pixel_rgb_t px; - px.u.color = ((r += delta_r) & 0xFF0000) | (((g += delta_g) & 0xFF0000) >> 8) | (((b += delta_b) & 0xFF0000) >> 16); - nana::pixel_rgb_t * dpx_end = pxbuf + rct.height * sp->pixel_size.width; - for(nana::pixel_rgb_t * dpx = pxbuf; dpx != dpx_end; dpx += sp->pixel_size.width) - *dpx = px; - } - } + auto dpx_end = pxbuf + rct.height * sp->pixel_size.width; + for (; pxbuf != pxbuf_end; ++pxbuf) + { + nana::pixel_color_t px; + px.value = ((r += delta_r) & 0xFF0000) | (((g += delta_g) & 0xFF0000) >> 8) | (((b += delta_b) & 0xFF0000) >> 16); + for (auto dpx = pxbuf; dpx != dpx_end; dpx += sp->pixel_size.width) + *dpx = px; + ++dpx_end; + } } } } @@ -1062,21 +984,21 @@ namespace nana{ namespace paint //stretch void pixel_buffer::stretch(const std::string& name) { - pixel_buffer_storage * sp = storage_.get(); - if(sp && name.size()) + if (storage_ && name.size()) { + auto& img_pro = storage_->img_pro; auto op_default = detail::image_process_provider::instance().stretch(); - sp->img_pro.stretch_receptacle = detail::image_process_provider::instance().ref_stretch(name); - if(sp->img_pro.stretch_receptacle == *op_default) - sp->img_pro.stretch = op_default; + img_pro.stretch_receptacle = detail::image_process_provider::instance().ref_stretch(name); + if(img_pro.stretch_receptacle == *op_default) + img_pro.stretch = op_default; else - sp->img_pro.stretch = & sp->img_pro.stretch_receptacle; + img_pro.stretch = &img_pro.stretch_receptacle; } } void pixel_buffer::stretch(const nana::rectangle& src_r, drawable_type drawable, const nana::rectangle& r) const { - pixel_buffer_storage * sp = storage_.get(); + auto sp = storage_.get(); if(nullptr == sp) return; nana::rectangle good_src_r, good_dst_r; @@ -1091,21 +1013,21 @@ namespace nana{ namespace paint //blend void pixel_buffer::blend(const std::string& name) { - pixel_buffer_storage * sp = storage_.get(); - if(sp && name.size()) + if (storage_ && name.size()) { + auto& img_pro = storage_->img_pro; auto op_default = detail::image_process_provider::instance().blend(); - sp->img_pro.blend_receptacle = detail::image_process_provider::instance().ref_blend(name); - if(sp->img_pro.blend_receptacle == *op_default) - sp->img_pro.blend = op_default; + img_pro.blend_receptacle = detail::image_process_provider::instance().ref_blend(name); + if(img_pro.blend_receptacle == *op_default) + img_pro.blend = op_default; else - sp->img_pro.blend = & sp->img_pro.blend_receptacle; + img_pro.blend = &img_pro.blend_receptacle; } } void pixel_buffer::blend(const nana::rectangle& s_r, drawable_type dw_dst, const nana::point& d_pos, double fade_rate) const { - pixel_buffer_storage * sp = storage_.get(); + auto sp = storage_.get(); if(nullptr == sp) return; nana::rectangle s_good_r, d_good_r; diff --git a/source/paint/text_renderer.cpp b/source/paint/text_renderer.cpp index 005a3edb..9fbcf8f6 100644 --- a/source/paint/text_renderer.cpp +++ b/source/paint/text_renderer.cpp @@ -40,9 +40,9 @@ namespace nana : dw(dw), x(x), endpos(endpos), text_align(ta) {} - unsigned operator()(int top, const nana::char_t * buf, std::size_t bufsize) + unsigned operator()(const int top, const nana::char_t * buf, std::size_t bufsize) { - int xpos = x; + nana::point pos{ x, top }; unsigned pixels = 0; bidi.linestr(buf, bufsize, reordered); switch(text_align) @@ -54,11 +54,11 @@ namespace nana nana::size ts = detail::text_extent_size(dw, ent.begin, len); if(ts.height > pixels) pixels = ts.height; - if(xpos + static_cast(ts.width) > 0) - detail::draw_string(dw, xpos, top, ent.begin, len); + if(pos.x + static_cast(ts.width) > 0) + detail::draw_string(dw, pos, ent.begin, len); - xpos += static_cast(ts.width); - if(xpos >= endpos) + pos.x += static_cast(ts.width); + if(pos.x >= endpos) break; } break; @@ -74,15 +74,15 @@ namespace nana widths.push_back(ts.width); } - xpos += (endpos - xpos - static_cast(lenpx))/2; + pos.x += (endpos - pos.x - static_cast(lenpx))/2; auto ipx = widths.begin(); for(auto & ent : reordered) { - if(xpos + static_cast(*ipx) > 0) - detail::draw_string(dw, xpos, top, ent.begin, ent.end - ent.begin); + if(pos.x + static_cast(*ipx) > 0) + detail::draw_string(dw, pos, ent.begin, ent.end - ent.begin); - xpos += static_cast(*ipx); - if(xpos >= endpos) + pos.x += static_cast(*ipx); + if(pos.x >= endpos) break; } } @@ -90,7 +90,7 @@ namespace nana case align::right: { int xend = endpos; - std::swap(xpos, xend); + std::swap(pos.x, xend); for(auto i = reordered.rbegin(), end = reordered.rend(); i != end; ++i) { auto & ent = *i; @@ -98,13 +98,13 @@ namespace nana nana::size ts = detail::text_extent_size(dw, ent.begin, len); if(ts.height > pixels) pixels = ts.height; - if(xpos > xend) + if(pos.x > xend) { - xpos -= static_cast(ts.width); - detail::draw_string(dw, xpos, top, i->begin, len); + pos.x -= static_cast(ts.width); + detail::draw_string(dw, pos, i->begin, len); } - if(xpos <= xend || xpos <= 0) + if(pos.x <= xend || pos.x <= 0) break; } } @@ -118,13 +118,13 @@ namespace nana { graphics & graph; int x, endpos; - nana::color_t color; + ::nana::color fgcolor; unsigned omitted_pixels; nana::unicode_bidi bidi; std::vector reordered; - draw_string_omitted(graphics& graph, int x, int endpos, nana::color_t color, bool omitted) - : graph(graph), x(x), endpos(endpos), color(color) + draw_string_omitted(graphics& graph, int x, int endpos, const ::nana::color& fgcolor, bool omitted) + : graph(graph), x(x), endpos(endpos), fgcolor(fgcolor) { omitted_pixels = (omitted ? graph.text_extent_size(STR("..."), 3).width : 0); if(endpos - x > static_cast(omitted_pixels)) @@ -133,10 +133,20 @@ namespace nana this->endpos = x; } - unsigned operator()(int top, const nana::char_t * buf, std::size_t bufsize) + draw_string_omitted(graphics& graph, int x, int endpos, bool omitted) + : graph(graph), x(x), endpos(endpos) + { + omitted_pixels = (omitted ? graph.text_extent_size(STR("..."), 3).width : 0); + if (endpos - x > static_cast(omitted_pixels)) + this->endpos -= omitted_pixels; + else + this->endpos = x; + } + + unsigned operator()(const int top, const nana::char_t * buf, std::size_t bufsize) { drawable_type dw = graph.handle(); - int xpos = x; + ::nana::point pos{ x, top }; unsigned pixels = 0; bidi.linestr(buf, bufsize, reordered); for(auto & i : reordered) @@ -145,27 +155,28 @@ namespace nana nana::size ts = detail::text_extent_size(dw, i.begin, len); if(ts.height > pixels) pixels = ts.height; - if(xpos + static_cast(ts.width) <= endpos) + if(pos.x + static_cast(ts.width) <= endpos) { - detail::draw_string(dw, xpos, top, i.begin, len); - xpos += static_cast(ts.width); + detail::draw_string(dw, pos, i.begin, len); + pos.x += static_cast(ts.width); } else { nana::rectangle r; - r.width = endpos - xpos; + r.width = endpos - pos.x; r.height = ts.height; - nana::paint::graphics dum_graph(r.width, r.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); + dum_graph.bitblt(r, graph, pos); + dum_graph.set_text_color(fgcolor); + dum_graph.string({}, i.begin, len); - r.x = xpos; + r.x = pos.x; r.y = top; graph.bitblt(r, dum_graph); if(omitted_pixels) - detail::draw_string(dw, endpos, top, STR("..."), 3); + detail::draw_string(dw, point{ endpos, top }, STR("..."), 3); break; } } @@ -187,7 +198,7 @@ namespace nana : graph(graph), x(x), endpos(endpos), text_align(ta) {} - unsigned operator()(int top, const nana::char_t * buf, std::size_t bufsize) + unsigned operator()(const int top, const nana::char_t * buf, std::size_t bufsize) { unsigned pixels = 0; @@ -208,7 +219,7 @@ namespace nana { pixels = 0; unsigned line_pixels = 0; - int xpos = x; + nana::point pos{ x, top }; int orig_top = top; auto i_ts_keeper = ts_keeper.cbegin(); for(auto & i : reordered) @@ -216,7 +227,7 @@ namespace nana if(line_pixels < i_ts_keeper->height) line_pixels = i_ts_keeper->height; - bool beyond_edge = (xpos + static_cast(i_ts_keeper->width) > endpos); + bool beyond_edge = (pos.x + static_cast(i_ts_keeper->width) > endpos); if(beyond_edge) { std::size_t len = i.end - i.begin; @@ -229,21 +240,21 @@ namespace nana do { - idx_splitted = find_splitted(idx_head, len, xpos, endpos, pxbuf); + idx_splitted = find_splitted(idx_head, len, pos.x, endpos, pxbuf); if(idx_splitted == len) { - detail::draw_string(dw, xpos, top, i.begin + idx_head, idx_splitted - idx_head); + detail::draw_string(dw, pos, i.begin + idx_head, idx_splitted - idx_head); for(std::size_t i = idx_head; i < len; ++i) - xpos += static_cast(pxbuf[i]); + pos.x += static_cast(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); + detail::draw_string(dw, pos, i.begin + idx_head, idx_splitted - idx_head); idx_head = idx_splitted; - xpos = x; - top += line_pixels; + pos.x = x; + pos.y += line_pixels; line_pixels = i_ts_keeper->height; } else @@ -260,10 +271,10 @@ namespace nana if(u != head) { - detail::draw_string(dw, xpos, top, head, u - head); + detail::draw_string(dw, pos, head, u - head); idx_head += u - head; - xpos = x; - top += line_pixels; + pos.x = x; + pos.y += static_cast(line_pixels); line_pixels = i_ts_keeper->height; } else @@ -276,17 +287,17 @@ namespace nana break; } std::size_t splen = u - head; - top += line_pixels; - xpos = x; - detail::draw_string(dw, x, top, head, splen); + pos.y += static_cast(line_pixels); + pos.x = x; + detail::draw_string(dw, pos, head, splen); line_pixels = i_ts_keeper->height; for(std::size_t k = idx_head; k < idx_head + splen; ++k) - xpos += static_cast(pxbuf[k]); - if(xpos >= endpos) + pos.x += static_cast(pxbuf[k]); + if (pos.x >= endpos) { - xpos = x; - top += line_pixels; + pos.x = x; + pos.y += static_cast(line_pixels); line_pixels = i_ts_keeper->height; } idx_head += splen; @@ -298,15 +309,17 @@ namespace nana } else { - detail::draw_string(dw, x, top += static_cast(line_pixels), i.begin, 1); - xpos = x + static_cast(i_ts_keeper->width); + pos.x = x; + pos.y += static_cast(line_pixels); + detail::draw_string(dw, pos, i.begin, 1); + pos.x += static_cast(i_ts_keeper->width); } line_pixels = 0; } else { - detail::draw_string(dw, xpos, top, i.begin, i.end - i.begin); - xpos += static_cast(i_ts_keeper->width); + detail::draw_string(dw, pos, i.begin, i.end - i.begin); + pos.x += static_cast(i_ts_keeper->width); } ++i_ts_keeper; @@ -319,24 +332,24 @@ namespace nana //The text could be drawn in a line. if((align::left == text_align) || (align::center == text_align)) { - int xpos = x; + point pos{ x, top }; if(align::center == text_align) - xpos += (endpos - x - static_cast(str_w)) / 2; + pos.x += (endpos - x - static_cast(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(ts.width) > 0) - detail::draw_string(dw, xpos, top, ent.begin, ent.end - ent.begin); + if (pos.x + static_cast(ts.width) > 0) + detail::draw_string(dw, pos, ent.begin, ent.end - ent.begin); - xpos += static_cast(ts.width); + pos.x += static_cast(ts.width); ++i_ts_keeper; } } else if(align::right == text_align) { - int xpos = endpos; + point pos{ endpos, top }; auto i_ts_keeper = ts_keeper.crbegin(); for(auto i = reordered.crbegin(), end = reordered.crend(); i != end; ++i) { @@ -344,9 +357,9 @@ namespace nana 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); + pos.x -= static_cast(ts.width); + if (pos.x >= 0) + detail::draw_string(dw, pos, ent.begin, len); ++i_ts_keeper; } } @@ -438,7 +451,8 @@ namespace nana std::size_t len = i.end - i.begin; if(len > 1) { - unsigned * pxbuf = new unsigned[len]; + std::unique_ptr scope_res(new unsigned[len]); + auto pxbuf = scope_res.get(); //Find the char that should be splitted graph.glyph_pixels(i.begin, len, pxbuf); std::size_t idx_head = 0, idx_splitted; @@ -506,8 +520,6 @@ namespace nana } } }while(idx_head < len); - - delete [] pxbuf; } else xpos = x + static_cast(i_ts_keeper->width); @@ -541,37 +553,7 @@ namespace nana : 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(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(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(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 text_renderer::extent_size(int x, int y, const char_t* str, std::size_t len, unsigned restricted_pixels) const { nana::size extents; if(graph_) @@ -583,8 +565,33 @@ namespace nana } return extents; } + + void text_renderer::render(const point& pos, const char_t * str, std::size_t len) + { + if (graph_) + { + helper::draw_string ds(graph_.handle(), pos.x, static_cast(graph_.width()), text_align_); + helper::for_each_line(str, len, pos.y, ds); + } + } + + void text_renderer::render(const point& pos, const char_t* str, std::size_t len, unsigned restricted_pixels, bool omitted) + { + if (graph_) + { + helper::draw_string_omitted dso(graph_, pos.x, pos.x + static_cast(restricted_pixels), omitted); + helper::for_each_line(str, len, pos.y, dso); + } + } + + void text_renderer::render(const point& pos, const char_t * str, std::size_t len, unsigned restricted_pixels) + { + if (graph_) + { + helper::draw_string_auto_changing_lines dsacl(graph_, pos.x, pos.x + static_cast(restricted_pixels), text_align_); + helper::for_each_line(str, len, pos.y, dsacl); + } + } //end class text_renderer - - } } diff --git a/source/system/dataexch.cpp b/source/system/dataexch.cpp index bfd89668..926e6f98 100644 --- a/source/system/dataexch.cpp +++ b/source/system/dataexch.cpp @@ -16,7 +16,7 @@ #include #elif defined(NANA_X11) #include PLATFORM_SPEC_HPP - #include GUI_BEDROCK_HPP + #include #include #endif diff --git a/source/unicode_bidi.cpp b/source/unicode_bidi.cpp index 889e7c4c..ab90f538 100644 --- a/source/unicode_bidi.cpp +++ b/source/unicode_bidi.cpp @@ -958,8 +958,7 @@ namespace nana unsigned level_of_run = begin_character->level; bool head_of_run = true; - std::vector::iterator last = end - 1; - std::vector::iterator begin_neutral = end; + auto begin_neutral = end; //N1. A sequence of neutrals takes the direction of the surrounding strong text if the text on both sides has the same direction. //European and Arabic numbers act as if they were R in terms of their influence on neutrals.