diff --git a/include/nana/gui/detail/drawer.hpp b/include/nana/gui/detail/drawer.hpp index 472f822e..5a202438 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-2015 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -126,8 +126,7 @@ namespace nana void* draw(std::function &&, bool diehard); void erase(void* diehard); private: - void _m_effect_bground(bool before); - bool _m_lazy_decleared() const; + void _m_effect_bground_subsequent(); method_state& _m_mth_state(int pos); template @@ -140,8 +139,6 @@ namespace nana if (realizer && (method_state::not_overrided != mth_state)) { - _m_effect_bground(true); - if (method_state::pending == mth_state) { (realizer->*mfptr)(graphics, arg); @@ -154,8 +151,7 @@ namespace nana else (realizer->*mfptr)(graphics, arg); - if (_m_lazy_decleared()) - _m_effect_bground(false); + _m_effect_bground_subsequent(); } } public: diff --git a/include/nana/gui/programming_interface.hpp b/include/nana/gui/programming_interface.hpp index b7e4a524..0a1d55d8 100644 --- a/include/nana/gui/programming_interface.hpp +++ b/include/nana/gui/programming_interface.hpp @@ -54,6 +54,8 @@ namespace API effects::edge_nimbus effects_edge_nimbus(window); void effects_bground(window, const effects::bground_factory_interface&, double fade_rate); + void effects_bground(std::initializer_list wdgs, const effects::bground_factory_interface&, double fade_rate); + bground_mode effects_bground_mode(window); void effects_bground_remove(window); @@ -96,6 +98,9 @@ namespace API void enable_space_click(window, bool enable); + bool copy_transparent_background(window, paint::graphics&); + bool copy_transparent_background(window, const rectangle& src_r, paint::graphics&, const point& dst_pt); + /// Refreshs a widget surface /* * This function will copy the drawer surface into system window after the event process finished. @@ -195,6 +200,8 @@ namespace API bool is_destroying(window); ///< Determines whether a window is destroying void enable_dropfiles(window, bool); + bool is_transparent_background(window); + /// \brief Retrieves the native window of a Nana.GUI window. /// /// The native window type is platform-dependent. Under Microsoft Windows, a conversion can be employed between diff --git a/include/nana/gui/widgets/panel.hpp b/include/nana/gui/widgets/panel.hpp index 648880ec..b159fa35 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-2015 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -57,7 +57,7 @@ namespace nana bool transparent() const { - return (bground_mode::basic == API::effects_bground_mode(*this)); + return API::is_transparent_background(*this); } void transparent(bool tr) diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index 87d2a970..19e58978 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -139,7 +139,7 @@ namespace nana{ namespace widgets void clear_undo(); ///< same with undo_max_steps(0) unsigned line_height() const; - unsigned screen_lines() const; + unsigned screen_lines(bool completed_line = false) const; bool getline(std::size_t pos, ::std::wstring&) const; void text(std::wstring, bool end_caret); @@ -153,7 +153,7 @@ namespace nana{ namespace widgets bool move_caret(const upoint& pos, bool reset = false); void move_caret_end(bool update); void reset_caret_pixels() const; - void reset_caret(); + void reset_caret(bool stay_in_view = false); void show_caret(bool isshow); bool selected() const; @@ -204,10 +204,12 @@ namespace nana{ namespace widgets bool focus_changed(const arg_focus&); bool mouse_enter(bool entering); bool mouse_move(bool left_button, const point& screen_pos); - bool mouse_pressed(const arg_mouse& arg); + void mouse_pressed(const arg_mouse& arg); skeletons::textbase& textbase(); const skeletons::textbase& textbase() const; + + bool try_refresh(); private: std::vector _m_render_text(const ::nana::color& text_color); void _m_pre_calc_lines(std::size_t line_off, std::size_t lines); @@ -223,7 +225,7 @@ namespace nana{ namespace widgets bool _m_accepts(char_type) const; ::nana::color _m_bgcolor() const; - void _m_reset_content_size(); + void _m_reset_content_size(bool calc_lines = false); void _m_reset(); ::nana::upoint _m_put(::std::wstring); ::nana::upoint _m_erase_select(); @@ -258,6 +260,7 @@ namespace nana{ namespace widgets unsigned _m_pixels_by_char(const ::std::wstring&, ::std::size_t pos) const; void _m_handle_move_key(const arg_keyboard& arg); + unsigned _m_width_px(bool exclude_vs) const; void _m_draw_border(); private: struct implementation; diff --git a/include/nana/gui/widgets/treebox.hpp b/include/nana/gui/widgets/treebox.hpp index a7e1bc77..a05f52f3 100644 --- a/include/nana/gui/widgets/treebox.hpp +++ b/include/nana/gui/widgets/treebox.hpp @@ -73,8 +73,8 @@ namespace nana typedef compset_interface::comp_attribute_t comp_attribute_t; virtual ~renderer_interface() = default; - virtual void set_color(const nana::color& bgcolor, const nana::color& fgcolor) = 0; + virtual void begin_paint(::nana::widget&) = 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; diff --git a/include/nana/paint/detail/native_paint_interface.hpp b/include/nana/paint/detail/native_paint_interface.hpp index 4a3dba44..2afa8056 100644 --- a/include/nana/paint/detail/native_paint_interface.hpp +++ b/include/nana/paint/detail/native_paint_interface.hpp @@ -30,7 +30,8 @@ namespace detail 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, pixel_color_t, double fade_rate); + //dw color = dw color * fade_rate + bdcolor * (1 - fade_rate) + void blend(drawable_type dw, const nana::rectangle& r, pixel_color_t bdcolor, double fade_rate); nana::size raw_text_extent_size(drawable_type, const wchar_t*, std::size_t len); nana::size text_extent_size(drawable_type, const wchar_t*, std::size_t len); diff --git a/source/gui/detail/drawer.cpp b/source/gui/detail/drawer.cpp index 48ded14c..2ef6e8c6 100644 --- a/source/gui/detail/drawer.cpp +++ b/source/gui/detail/drawer.cpp @@ -1,7 +1,7 @@ /* * A Drawer Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -297,9 +297,8 @@ namespace nana if (data_impl_->realizer && !data_impl_->refreshing) { data_impl_->refreshing = true; - _m_effect_bground(true); data_impl_->realizer->refresh(graphics); - _m_effect_bground(false); + _m_effect_bground_subsequent(); graphics.flush(); data_impl_->refreshing = false; } @@ -372,27 +371,20 @@ namespace nana } } - void drawer::_m_effect_bground(bool before) + void drawer::_m_effect_bground_subsequent() { + auto & effect = data_impl_->window_handle->effect; + for (auto * dw : data_impl_->draws) dw->draw(graphics); - auto & effect = data_impl_->window_handle->effect; + if (effect.bground) { - if (before) - { - if (effect.bground_fade_rate < 0.01) - data_impl_->window_handle->other.glass_buffer.paste(graphics, 0, 0); - } - else if (effect.bground_fade_rate >= 0.01) + if (effect.bground_fade_rate >= 0.01) data_impl_->window_handle->other.glass_buffer.blend(::nana::rectangle{ data_impl_->window_handle->other.glass_buffer.size() }, graphics, nana::point(), effect.bground_fade_rate); } - } - - bool drawer::_m_lazy_decleared() const - { - return (basic_window::update_state::refreshed == data_impl_->window_handle->other.upd_state); + } drawer::method_state& drawer::_m_mth_state(int pos) diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index cc68ff4c..49f3adf8 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -155,6 +155,12 @@ namespace API } } + void effects_bground(std::initializer_list wdgs, const effects::bground_factory_interface& factory, double fade_rate) + { + for (auto wd : wdgs) + effects_bground(wd, factory, fade_rate); + } + bground_mode effects_bground_mode(window wd) { auto const iwd = reinterpret_cast(wd); @@ -329,6 +335,32 @@ namespace API iwd->flags.space_click_enabled = enable; } + bool copy_transparent_background(window wd, paint::graphics& graph) + { + auto & buf = reinterpret_cast(wd)->other.glass_buffer; + internal_scope_guard lock; + + if (bground_mode::basic != API::effects_bground_mode(wd)) + return false; + + buf.paste(rectangle{ buf.size() }, graph, 0, 0); + + return true; + } + + bool copy_transparent_background(window wd, const rectangle& src_r, paint::graphics& graph, const point& dst_pt) + { + auto iwd = reinterpret_cast(wd); + internal_scope_guard lock; + + if (bground_mode::basic != API::effects_bground_mode(wd)) + return false; + + iwd->other.glass_buffer.paste(src_r, graph, dst_pt.x, dst_pt.y); + + return true; + } + void lazy_refresh() { restrict::bedrock.thread_context_lazy_refresh(); @@ -469,6 +501,11 @@ namespace API } } + bool is_transparent_background(window wd) + { + return (bground_mode::basic == effects_bground_mode(wd)); + } + native_window_type root(window wd) { internal_scope_guard lock; diff --git a/source/gui/widgets/button.cpp b/source/gui/widgets/button.cpp index 2e2d4d9f..a81a5393 100644 --- a/source/gui/widgets/button.cpp +++ b/source/gui/widgets/button.cpp @@ -155,7 +155,7 @@ namespace nana{ namespace drawerbase if (false == cite_.draw(graph, attr_.bgcolor, attr_.fgcolor, ::nana::rectangle{ graph.size() }, e_state)) { - if (bground_mode::basic != API::effects_bground_mode(wdg_->handle())) + if (!API::is_transparent_background(*wdg_)) { _m_draw_background(graph); _m_draw_border(graph); @@ -492,7 +492,7 @@ namespace nana{ namespace drawerbase bool button::transparent() const { - return (bground_mode::basic == API::effects_bground_mode(*this)); + return API::is_transparent_background(*this); } button& button::edge_effects(bool enable) diff --git a/source/gui/widgets/checkbox.cpp b/source/gui/widgets/checkbox.cpp index b1a2fe88..a1b2fe5c 100644 --- a/source/gui/widgets/checkbox.cpp +++ b/source/gui/widgets/checkbox.cpp @@ -1,7 +1,7 @@ /* * A CheckBox Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -55,7 +55,7 @@ namespace nana{ namespace drawerbase auto wdg = impl_->widget_ptr; //draw background - if (bground_mode::basic != API::effects_bground_mode(*wdg)) + if (!API::dev::copy_transparent_background(*wdg, graph)) graph.rectangle(true, wdg->bgcolor()); //draw title @@ -193,7 +193,7 @@ namespace nana{ namespace drawerbase bool checkbox::transparent() const { - return (bground_mode::basic == API::effects_bground_mode(*this)); + return API::is_transparent_background(*this); } //end class checkbox diff --git a/source/gui/widgets/combox.cpp b/source/gui/widgets/combox.cpp index 84965aec..c19b310d 100644 --- a/source/gui/widgets/combox.cpp +++ b/source/gui/widgets/combox.cpp @@ -193,6 +193,7 @@ namespace nana if(r.width > place) r.width -= place; } editor_->text_area(r); + editor_->render(state_.focused); } widgets::skeletons::text_editor * editor() const @@ -233,6 +234,12 @@ namespace nana } graph.gradual_rectangle(::nana::rectangle(graph.size()).pare_off(pare_off_px), clr_from, clr_to, true); + if (API::is_transparent_background(this->widget_ptr()->handle())) + { + paint::graphics trns_graph{ graph.size() }; + if (API::dev::copy_transparent_background(this->widget_ptr()->handle(), trns_graph)) + trns_graph.blend(rectangle{ trns_graph.size() }, graph, { 0, 0 }, 0.5); + } }; } else @@ -362,7 +369,6 @@ namespace nana if(editor_) { text_area(widget_->size()); - editor_->render(state_.focused); } _m_draw_push_button(enb); _m_draw_image(); @@ -397,7 +403,8 @@ namespace nana if (calc_where(*graph_, pos.x, pos.y)) state_.button_state = element_state::normal; - editor_->text(::nana::charset(items_[index]->item_text, ::nana::unicode::utf8), false); + editor_->text(to_wstring(items_[index]->item_text), false); + editor_->try_refresh(); _m_draw_push_button(widget_->enabled()); _m_draw_image(); @@ -511,9 +518,10 @@ namespace nana facade button; button.draw(*graph_, ::nana::color{ 3, 65, 140 }, colors::white, r, estate); - facade arrow("solid_triangle"); + facade arrow;// ("solid_triangle"); arrow.direction(::nana::direction::south); + r.x += 4; r.y += (r.height / 2) - 7; r.width = r.height = 16; arrow.draw(*graph_, {}, colors::white, r, element_state::normal); @@ -664,7 +672,6 @@ namespace nana void trigger::mouse_down(graph_reference, const arg_mouse& arg) { - //drawer_->set_mouse_press(true); drawer_->set_button_state(element_state::pressed, false); if(drawer_->widget_ptr()->enabled()) { @@ -762,12 +769,14 @@ namespace nana if (call_other_keys) drawer_->editor()->respond_key(arg); + drawer_->editor()->try_refresh(); API::dev::lazy_refresh(); } void trigger::key_char(graph_reference, const arg_keyboard& arg) { - if (drawer_->editor()->respond_char(arg)) + drawer_->editor()->respond_char(arg); + if (drawer_->editor()->try_refresh()) API::dev::lazy_refresh(); } //end class trigger diff --git a/source/gui/widgets/label.cpp b/source/gui/widgets/label.cpp index c83a09f5..35222859 100644 --- a/source/gui/widgets/label.cpp +++ b/source/gui/widgets/label.cpp @@ -784,7 +784,7 @@ namespace nana if(nullptr == impl_->wd) return; window wd = impl_->wd->handle(); - if(bground_mode::basic != API::effects_bground_mode(wd)) + if (!API::dev::copy_transparent_background(wd, graph)) graph.rectangle(true, API::bgcolor(wd)); impl_->renderer.render(graph, API::fgcolor(wd), impl_->text_align, impl_->text_align_v); @@ -830,7 +830,7 @@ namespace nana bool label::transparent() const throw() { - return (bground_mode::basic == API::effects_bground_mode(*this)); + return API::is_transparent_background(*this); } label& label::format(bool f) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 4830508d..20010e2a 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -3168,7 +3168,10 @@ namespace nana if (column_r.x < r.right()) { column_r.width = (r.right() - column_r.x); - graph.rectangle(column_r, true, essence_->scheme_ptr->header_bgcolor); + if(API::dev::copy_transparent_background(essence_->listbox_ptr->handle(), column_r, graph, column_r.position())) + graph.blend(column_r, essence_->scheme_ptr->header_bgcolor, 0.8); + else + graph.rectangle(column_r, true, essence_->scheme_ptr->header_bgcolor); } const int y = r.bottom() - 1; @@ -3229,7 +3232,15 @@ namespace nana case item_state::floated: bgcolor = essence_->scheme_ptr->header_floated.get_color(); break; } - graph.gradual_rectangle(column_r, bgcolor.blend(colors::white, 0.9), bgcolor.blend(colors::black, 0.9), true); + if(API::dev::copy_transparent_background(essence_->listbox_ptr->handle(), column_r, graph, column_r.position())) + { + paint::graphics grad_graph{column_r.dimension()}; + grad_graph.gradual_rectangle(rectangle{column_r.dimension()}, bgcolor.blend(colors::white, 0.1), bgcolor.blend(colors::black, 0.1), true); + + grad_graph.blend(rectangle{column_r.dimension()}, graph, column_r.position(), 0.3); + } + else + graph.gradual_rectangle(column_r, bgcolor.blend(colors::white, 0.9), bgcolor.blend(colors::black, 0.9), true); paint::aligner text_aligner{ graph, column.alignment, column.alignment }; @@ -3329,23 +3340,28 @@ namespace nana essence_->graph->palette(false, bgcolor); auto const header_w = essence_->header.pixels(); + auto const item_height_px = essence_->item_height(); auto origin = essence_->content_view->origin(); if (header_w < origin.x + rect.width) - essence_->graph->rectangle(rectangle{ point{ rect.x + static_cast(header_w) - origin.x, rect.y }, - size{ rect.width + origin.x - header_w, rect.height } }, true); + { + rectangle r{ point{ rect.x + static_cast(header_w)-origin.x, rect.y }, + size{ rect.width + origin.x - header_w, rect.height } }; + + if (!API::dev::copy_transparent_background(essence_->listbox_ptr->handle(), r, *essence_->graph, r.position())) + essence_->graph->rectangle(r, true); + } es_lister & lister = essence_->lister; auto & ptr_where = essence_->pointer_where; - int item_top = rect.y - (origin.y % essence_->item_height()); + int item_top = rect.y - (origin.y % item_height_px); auto first_disp = essence_->first_display(); // The first display is empty when the listbox is empty. if (!first_disp.empty()) { - index_pair hoverred_pos(npos, npos); //the hoverred item. //if where == lister || where == checker, 'second' indicates the offset to the relative display-order pos of the scroll offset_y which stands for the first item to be displayed in lister. @@ -3397,7 +3413,7 @@ namespace nana (hoverred_pos == idx ? item_state::highlighted : item_state::normal) ); - item_top += essence_->item_height(); + item_top += item_height_px; } ++i_categ; @@ -3414,7 +3430,7 @@ namespace nana _m_draw_categ(*i_categ, rect.x - origin.x, item_top, txtoff, header_w, rect, bgcolor, (hoverred_pos.is_category() && (idx.cat == hoverred_pos.cat) ? item_state::highlighted : item_state::normal) ); - item_top += essence_->item_height(); + item_top += item_height_px; if (false == i_categ->expand) continue; @@ -3431,7 +3447,7 @@ namespace nana (idx == hoverred_pos ? item_state::highlighted : item_state::normal) ); - item_top += essence_->item_height(); + item_top += item_height_px; if (item_top >= rect.bottom()) break; @@ -3443,7 +3459,11 @@ namespace nana } if (item_top < rect.bottom()) - essence_->graph->rectangle(rectangle{ rect.x, item_top, rect.width, static_cast(rect.bottom() - item_top) }, true, bgcolor); + { + rectangle bground_r{ rect.x, item_top, rect.width, static_cast(rect.bottom() - item_top) }; + if (!API::dev::copy_transparent_background(essence_->listbox_ptr->handle(), bground_r, *essence_->graph, bground_r.position())) + essence_->graph->rectangle(bground_r, true, bgcolor); + } //Draw mouse selection //Check if the mouse selection box is present. @@ -3459,26 +3479,24 @@ namespace nana }; paint::graphics box_graph{ box_size }; - box_graph.rectangle(true, essence_->scheme_ptr->selection_box.get_color().blend(colors::white, 0.6)); + box_graph.rectangle(true, essence_->scheme_ptr->selection_box.get_color().blend(colors::white, 0.4)); box_graph.rectangle(false, essence_->scheme_ptr->selection_box.get_color()); box_graph.blend(rectangle{ box_size }, *essence_->graph, essence_->coordinate_cast(box_position, false), 0.5); } } private: - 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 + 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 = static_cast(0xD5EFFC); - - if (state == item_state::highlighted) - bgcolor = bgcolor.blend(static_cast(0x99defd), 0.8); - const auto item_height = essence_->item_height(); + rectangle bground_r{ x, y, width, item_height }; auto graph = essence_->graph; - graph->rectangle(rectangle{ x, y, width, item_height }, true, bgcolor); + + item_data item; + item.flags.selected = categ.selected(); + + this->_m_draw_item_bground(bground_r, bgcolor, {}, state, item); color txt_color{ static_cast(0x3399) }; @@ -3506,10 +3524,53 @@ namespace nana } //Draw selecting inner rectangle - if (sel && (categ.expand == false)) + if (item.flags.selected && (categ.expand == false)) _m_draw_item_border(r.x, y, (std::min)(r.width, width - essence_->content_view->origin().x)); } + color _m_draw_item_bground(const rectangle& bground_r, color bgcolor, color cell_color, item_state state, const item_data& item) + { + auto graph = essence_->graph; + + auto const is_transparent = API::dev::copy_transparent_background(essence_->listbox_ptr->handle(), bground_r, *graph, bground_r.position()); + + if (is_transparent) + bgcolor = color{}; + + if (item.flags.selected) + { + bgcolor = essence_->scheme_ptr->item_selected; + + if (!cell_color.invisible()) + bgcolor = bgcolor.blend(cell_color, 0.5); + } + else if (!cell_color.invisible()) + bgcolor = cell_color; + else if (!item.bgcolor.invisible()) + bgcolor = item.bgcolor; + + if (item_state::highlighted == state) + { + if (item.flags.selected) + bgcolor = bgcolor.blend(colors::black, 0.9); + else + bgcolor = bgcolor.blend(essence_->scheme_ptr->item_highlighted, 0.3); + } + + if (is_transparent) + { + if(!bgcolor.invisible()) + graph->blend(bground_r, bgcolor, 0.2); + } + else + { + graph->rectangle(bground_r, true, bgcolor); + + } + + return bgcolor; + } + /// Draws an item void _m_draw_item(const category_t& cat, const index_pair& item_pos, @@ -3534,28 +3595,16 @@ namespace nana auto & cells = (cat.model_ptr ? model_cells : *item.cells); - if (item.flags.selected) // fetch the "def" colors - bgcolor = essence_->scheme_ptr->item_selected; - else if (!item.bgcolor.invisible()) - bgcolor = item.bgcolor; - if(!item.fgcolor.invisible()) fgcolor = item.fgcolor; - if (item_state::highlighted == state) // and blend it if "highlighted" - { - if (item.flags.selected) - bgcolor = bgcolor.blend(colors::black, 0.98); // or "selected" - else - bgcolor = bgcolor.blend(essence_->scheme_ptr->item_highlighted, 0.7);/// \todo create a parametre for amount of blend - } - const unsigned show_w = (std::min)(content_r.width, width - essence_->content_view->origin().x); auto graph = essence_->graph; //draw the background for the whole item - graph->rectangle(rectangle{ content_r.x, y, show_w, essence_->item_height() }, true, bgcolor); + rectangle bground_r{ content_r.x, y, show_w, essence_->item_height() }; + auto const state_bgcolor = this->_m_draw_item_bground(bground_r, bgcolor, {}, state, item); int column_x = x; @@ -3563,7 +3612,6 @@ namespace nana { const auto column_pos = seqs[display_order]; const auto & col = essence_->header.at(column_pos); // deduce the corresponding header which is in a kind of dislay order - auto it_bgcolor = bgcolor; if (col.width_px > essence_->scheme_ptr->text_margin) { @@ -3664,7 +3712,8 @@ namespace nana } } - auto cell_txtcolor = fgcolor; + auto col_bgcolor = bgcolor; + auto col_fgcolor = fgcolor; if (cells.size() > column_pos) // process only if the cell is visible { @@ -3673,24 +3722,13 @@ namespace nana if (m_cell.custom_format) // adapt to costum format if need { - if (!item.bgcolor.invisible()) - cell_txtcolor = m_cell.custom_format->bgcolor; - - if (item.flags.selected) // fetch the "def" colors - it_bgcolor = essence_->scheme_ptr->item_selected; + col_fgcolor = m_cell.custom_format->fgcolor; - cell_txtcolor = m_cell.custom_format->fgcolor; - - if (item_state::highlighted == state) // and blend it if "highlighted" - { - if (item.flags.selected) - it_bgcolor = it_bgcolor.blend(colors::black, 0.98); // or "selected" - else - it_bgcolor = it_bgcolor.blend(essence_->scheme_ptr->item_highlighted, 0.7); /// \todo create a parametre for amount of blend - } - - graph->rectangle(rectangle{ column_x, y, col.width_px, essence_->item_height() }, true, it_bgcolor); + bground_r = rectangle{ column_x, y, col.width_px, essence_->item_height() }; + col_bgcolor = this->_m_draw_item_bground(bground_r, bgcolor, m_cell.custom_format->bgcolor, state, item); } + else + col_bgcolor = state_bgcolor; if (draw_column) { @@ -3702,7 +3740,7 @@ namespace nana else if (align::right == col.alignment) text_margin_right = essence_->scheme_ptr->text_margin; - graph->palette(true, cell_txtcolor); + graph->palette(true, col_fgcolor); text_aligner.draw(m_cell.text, { column_x + content_pos, y + txtoff }, col.width_px - content_pos - text_margin_right); } } @@ -3710,7 +3748,7 @@ namespace nana if (0 == display_order) { if (essence_->checkable) - crook_renderer_.draw(*graph, it_bgcolor, cell_txtcolor, essence_->checkarea(column_x, y), estate); + crook_renderer_.draw(*graph, col_bgcolor, col_fgcolor, essence_->checkarea(column_x, y), estate); if (item.img) item.img.stretch(rectangle{ item.img.size() }, *graph, img_r); } @@ -4196,16 +4234,6 @@ namespace nana bool do_expand = (lister.expand(item_pos.cat) == false); lister.expand(item_pos.cat, do_expand); - if(false == do_expand) - { - auto last = lister.advance(lister.last(), -static_cast(essence_->count_of_exposed(false))); - if (!last.empty()) - { - auto px = lister.distance(lister.first(), last) * essence_->item_height(); - essence_->content_view->change_position(static_cast(px), true, false); - } - } - essence_->calc_content_size(false); essence_->content_view->sync(false); refresh(graph); @@ -4727,20 +4755,6 @@ namespace nana return to_utf8(cat_->text); } - bool assign_colors_for_last(essence* ess, category_t* cat) - { - auto wd = ess->lister.wd_ptr(); - if (wd && !API::empty_window(wd->handle())) - { - auto & m = cat->items.back(); - m.bgcolor = wd->bgcolor(); - m.fgcolor = wd->fgcolor(); - - return true; - } - return false; - } - void cat_proxy::push_back(std::string s) { internal_scope_guard lock; @@ -4766,8 +4780,7 @@ namespace nana else cat_->items.emplace_back(std::move(s)); - if (assign_colors_for_last(ess_, cat_)) - ess_->update(); + ess_->update(); } //Behavior of a container @@ -4947,8 +4960,6 @@ namespace nana } cat_->sorted.push_back(cat_->items.size() - 1); - - assign_colors_for_last(ess_, cat_); } void cat_proxy::_m_try_append_model(const const_virtual_pointer& dptr) @@ -4964,7 +4975,6 @@ namespace nana cat_->sorted.push_back(cat_->items.size()); cat_->items.emplace_back(); - assign_colors_for_last(ess_, cat_); } void cat_proxy::_m_cat_by_pos() noexcept diff --git a/source/gui/widgets/panel.cpp b/source/gui/widgets/panel.cpp index 5c1fdee1..2592a3dd 100644 --- a/source/gui/widgets/panel.cpp +++ b/source/gui/widgets/panel.cpp @@ -1,6 +1,6 @@ /* * A Panel Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -31,7 +31,7 @@ namespace nana void drawer::refresh(graph_reference graph) { - if(bground_mode::basic != API::effects_bground_mode(window_)) + if (!API::dev::copy_transparent_background(window_, graph)) graph.rectangle(true, API::bgcolor(window_)); } //end class drawer diff --git a/source/gui/widgets/picture.cpp b/source/gui/widgets/picture.cpp index b07f68d9..b1e40aae 100644 --- a/source/gui/widgets/picture.cpp +++ b/source/gui/widgets/picture.cpp @@ -194,9 +194,9 @@ namespace nana { auto graph = impl_->graph_ptr; - if (graph && (bground_mode::basic != API::effects_bground_mode(*impl_->wdg_ptr))) + if (graph && (!API::dev::copy_transparent_background(*impl_->wdg_ptr, *graph))) { - if (w < graph->size().width || h < graph->size().height /* .width ??? */ || impl_->backimg.image.alpha()) + if (w < graph->size().width || h < graph->size().height || impl_->backimg.image.alpha()) { auto & bground = impl_->gradual_bground; if (bground.gradual_from.invisible() || bground.gradual_to.invisible()) @@ -320,7 +320,7 @@ namespace nana bool picture::transparent() const { - return (bground_mode::basic == API::effects_bground_mode(*this)); + return API::is_transparent_background(*this); } //end class picture }//end namespace nana diff --git a/source/gui/widgets/skeletons/content_view.cpp b/source/gui/widgets/skeletons/content_view.cpp index f3becf9a..704f438b 100644 --- a/source/gui/widgets/skeletons/content_view.cpp +++ b/source/gui/widgets/skeletons/content_view.cpp @@ -209,7 +209,10 @@ namespace nana { vert.value(origin.y); } else + { vert.close(); + origin.y = 0; + } if (imd_area.height != disp_area.height) { @@ -233,7 +236,10 @@ namespace nana { horz.value(origin.x); } else + { horz.close(); + origin.x = 0; + } this->enable_update = true; } @@ -308,7 +314,31 @@ namespace nana { void content_view::content_size(const size& sz, bool try_update) { + if (sz.height < impl_->content_size.height) + { + if (impl_->origin.y + impl_->disp_area.height > sz.height) + { + if (impl_->disp_area.height > sz.height) + impl_->origin.y = 0; + else + impl_->origin.y = sz.height - impl_->disp_area.height; + } + } + + if (sz.width < impl_->content_size.width) + { + if (impl_->origin.x + impl_->disp_area.width > sz.width) + { + if (impl_->disp_area.width > sz.width) + impl_->origin.x = 0; + else + impl_->origin.x = sz.width - impl_->disp_area.width; + } + } + + impl_->content_size = sz; + impl_->size_changed(try_update); } diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 09bc0997..168a4635 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -388,6 +388,13 @@ namespace nana{ namespace widgets const keyword_scheme * scheme; }; + enum class sync_graph + { + none, + refresh, + lazy_refresh + }; + struct text_editor::implementation { @@ -397,6 +404,8 @@ namespace nana{ namespace widgets skeletons::textbase textbase; + sync_graph try_refresh{ sync_graph::none }; + struct inner_capacities { editor_behavior_interface * behavior; @@ -411,14 +420,12 @@ namespace nana{ namespace widgets paint::graphics buffer; //A offscreen buffer which keeps the background that painted by external part. }counterpart; - struct indent_rep { bool enabled{ false }; std::function generator; }indent; - struct inner_keywords { std::map> schemes; @@ -487,13 +494,10 @@ namespace nana{ namespace widgets if ((0 == textlines) || (0 == line_px)) return{}; - auto const offset_top = editor_._m_text_topline(); - const int text_area_top = editor_.text_area_.area.y; - - if (top < text_area_top) - top = offset_top ? offset_top - 1 : 0; + if (top < editor_.text_area_.area.y) + top = (std::max)(editor_._m_text_topline() - 1, 0); else - top = (top - text_area_top) / line_px + offset_top; + top = (top - editor_.text_area_.area.y + editor_.impl_->cview->origin().y) / line_px; return{ (textlines <= static_cast(top) ? textlines - 1 : static_cast(top)), 0 }; @@ -676,16 +680,9 @@ namespace nana{ namespace widgets if ((0 == editor_.textbase().lines()) || (0 == line_px)) return coord; - const int text_area_top = editor_.text_area_.area.y; - auto const offset_top = editor_._m_text_topline(); + auto screen_rows = (top - editor_.text_area_.area.y + editor_.impl_->cview->origin().y) / line_px; - auto screen_line = (text_area_top - top) / line_px; - if ((top < text_area_top) && (screen_line > offset_top)) - screen_line = 0; - else - screen_line = offset_top - screen_line; - - coord = _m_textline(static_cast(screen_line)); + coord = _m_textline(static_cast(screen_rows)); if (linemtr_.size() <= coord.first) { coord.first = linemtr_.size() - 1; @@ -1261,6 +1258,7 @@ namespace nana{ namespace widgets put(key); } reset_caret(); + impl_->try_refresh = sync_graph::refresh; return true; } return false; @@ -1289,6 +1287,7 @@ namespace nana{ namespace widgets default: return false; } + impl_->try_refresh = sync_graph::refresh; return true; } @@ -1316,8 +1315,7 @@ namespace nana{ namespace widgets _m_reset(); impl_->capacities.behavior->pre_calc_lines(width_pixels()); - render(API::is_focus_ready(window_)); - + impl_->try_refresh = sync_graph::refresh; _m_reset_content_size(); return true; } @@ -1326,7 +1324,7 @@ namespace nana{ namespace widgets { this->attributes_.alignment = alignment; this->reset_caret(); - render(API::is_focus_ready(window_)); + impl_->try_refresh = sync_graph::refresh; _m_reset_content_size(); } @@ -1340,11 +1338,9 @@ namespace nana{ namespace widgets if (impl_->counterpart.enabled) impl_->counterpart.buffer.make(r.dimension()); - impl_->capacities.behavior->pre_calc_lines(width_pixels()); - impl_->cview->disp_area(r, { -1, 1 }, { 1, -1 }, { 2, 2 }); if (impl_->cview->content_size().empty() || this->attributes_.line_wrapped) - _m_reset_content_size(); + _m_reset_content_size(true); move_caret(points_.caret); return true; @@ -1381,14 +1377,12 @@ namespace nana{ namespace widgets else impl_->capacities.behavior = new behavior_normal(*this); - impl_->capacities.behavior->pre_calc_lines(width_pixels()); + _m_reset_content_size(true); impl_->cview->move_origin(point{} -impl_->cview->origin()); move_caret(upoint{}); - _m_reset_content_size(); - - render(API::is_focus_ready(window_)); + impl_->try_refresh = sync_graph::refresh; return true; } return false; @@ -1478,14 +1472,19 @@ namespace nana{ namespace widgets return px; } - unsigned text_editor::screen_lines() const + unsigned text_editor::screen_lines(bool completed_line) const { auto const line_px = line_height(); if (line_px) { auto h = impl_->cview->view_area().height; if (graph_ && h) + { + if (completed_line) + return (h / line_px); + return (h / line_px + (h % line_px ? 1 : 0)); + } } return 0; } @@ -1559,23 +1558,23 @@ namespace nana{ namespace widgets else if (selection::mode::move_selected == select_.mode_selection) select_.mode_selection = selection::mode::move_selected_take_effect; - _m_draw_border(); + impl_->try_refresh = sync_graph::refresh; return true; } return false; } - bool text_editor::mouse_pressed(const arg_mouse& arg) + void text_editor::mouse_pressed(const arg_mouse& arg) { if(!attributes_.enable_caret) - return false; + return; if (event_code::mouse_down == arg.evt_code) { if (select_.ignore_press || (!hit_text_area(arg.pos))) { select_.ignore_press = false; - return false; + return; } if (::nana::mouse::left_button == arg.button) @@ -1614,13 +1613,11 @@ namespace nana{ namespace widgets } } - _m_draw_border(); - return true; + impl_->try_refresh = sync_graph::refresh; } else if (event_code::mouse_up == arg.evt_code) { select_.ignore_press = false; - bool updated = false; if (select_.mode_selection == selection::mode::mouse_selected) { @@ -1630,13 +1627,18 @@ namespace nana{ namespace widgets else if (selection::mode::move_selected == select_.mode_selection || selection::mode::move_selected_take_effect == select_.mode_selection) { //move_selected indicates the mouse is pressed on the selected text, but the mouse has not moved. So the text_editor should cancel the selection. - //move_selected_take_effect indicates the mouse is pressed on the selected text, and the mouse has moved. So the text_editor should try move the selection. + //move_selected_take_effect indicates the text_editor should try to move the selection. - if((selection::mode::move_selected == select_.mode_selection) || !move_select()) + if ((selection::mode::move_selected == select_.mode_selection) || !move_select()) + { + //no move occurs select(false); + move_caret(_m_screen_to_caret(arg.pos)); + } + select_.mode_selection = selection::mode::no_selected; - updated = true; + impl_->try_refresh = sync_graph::refresh; } API::release_capture(window_); @@ -1644,12 +1646,7 @@ namespace nana{ namespace widgets text_area_.captured = false; if (hit_text_area(arg.pos) == false) API::window_cursor(window_, nana::cursor::arrow); - - _m_draw_border(); - - return updated; } - return false; } textbase & text_editor::textbase() @@ -1662,6 +1659,19 @@ namespace nana{ namespace widgets return impl_->textbase; } + bool text_editor::try_refresh() + { + if (sync_graph::none != impl_->try_refresh) + { + if (sync_graph::refresh == impl_->try_refresh) + render(API::is_focus_ready(window_)); + + impl_->try_refresh = sync_graph::none; + return true; + } + return false; + } + bool text_editor::getline(std::size_t pos, std::wstring& text) const { if (impl_->textbase.lines() <= pos) @@ -1677,7 +1687,8 @@ namespace nana{ namespace widgets impl_->textbase.erase_all(); _m_reset(); - impl_->capacities.behavior->pre_calc_lines(width_pixels()); + _m_reset_content_size(true); + if (!end_caret) { auto undo_ptr = std::unique_ptr{ new undo_input_text(*this, str) }; @@ -1691,9 +1702,7 @@ namespace nana{ namespace widgets { impl_->capacities.behavior->adjust_caret_into_screen(); reset_caret(); - render(API::is_focus_ready(window_)); - - _m_reset_content_size(); + impl_->try_refresh = sync_graph::refresh; points_.xpos = 0; } } @@ -1755,7 +1764,7 @@ namespace nana{ namespace widgets if (reset_caret && (!hit_text_area(pos))) { impl_->capacities.behavior->adjust_caret_into_screen(); - render(true); + impl_->try_refresh = sync_graph::refresh; caret->visible(true); return true; } @@ -1777,9 +1786,9 @@ namespace nana{ namespace widgets API::open_caret(window_, true).get()->dimension({ 1, line_height() }); } - void text_editor::reset_caret() + void text_editor::reset_caret(bool stay_in_view) { - move_caret(points_.caret); + move_caret(points_.caret, stay_in_view); } void text_editor::show_caret(bool isshow) @@ -1821,14 +1830,14 @@ namespace nana{ namespace widgets if(select_.b.y) --select_.b.y; select_.b.x = static_cast(impl_->textbase.getline(select_.b.y).size()); select_.mode_selection = selection::mode::method_selected; - render(true); + impl_->try_refresh = sync_graph::refresh; return true; } - + select_.mode_selection = selection::mode::no_selected; if (_m_cancel_select(0)) { - render(true); + impl_->try_refresh = sync_graph::refresh; return true; } return false; @@ -1840,8 +1849,8 @@ namespace nana{ namespace widgets select_.b = points_.caret; points_.xpos = points_.caret.x; - if (new_sel_end || (stay_in_view && impl_->capacities.behavior->adjust_caret_into_screen())) - render(true); + if(new_sel_end || (stay_in_view && impl_->capacities.behavior->adjust_caret_into_screen())) + impl_->try_refresh = sync_graph::refresh; } bool text_editor::hit_text_area(const point& pos) const @@ -1877,7 +1886,7 @@ namespace nana{ namespace widgets points_.caret = select_.b; if (impl_->capacities.behavior->adjust_caret_into_screen()) - render(true); + impl_->try_refresh = sync_graph::refresh; reset_caret(); return true; @@ -1886,7 +1895,7 @@ namespace nana{ namespace widgets if (_m_move_select(true)) { impl_->capacities.behavior->adjust_caret_into_screen(); - render(true); + impl_->try_refresh = sync_graph::refresh; return true; } return false; @@ -1906,7 +1915,7 @@ namespace nana{ namespace widgets unsigned exclude_px = API::open_caret(window_, true).get()->dimension().width; if (attributes_.line_wrapped) - exclude_px += impl_->cview->space(); + exclude_px += impl_->cview->extra_space(false); return (text_area_.area.width > exclude_px ? text_area_.area.width - exclude_px : 0); } @@ -1948,8 +1957,11 @@ namespace nana{ namespace widgets graph_.rectangle(false, bgcolor); //Draw background - if(attributes_.enable_background) - graph_.rectangle(text_area_.area, true, bgcolor); + if (!API::dev::copy_transparent_background(window_, graph_)) + { + if (attributes_.enable_background) + graph_.rectangle(text_area_.area, true, bgcolor); + } if (impl_->customized_renderers.background) impl_->customized_renderers.background(graph_, text_area_.area, bgcolor); @@ -1982,6 +1994,7 @@ namespace nana{ namespace widgets impl_->text_position.emplace_back(upoint{}); _m_draw_border(); + impl_->try_refresh = sync_graph::none; } //public: void text_editor::put(std::wstring text) @@ -2006,7 +2019,7 @@ namespace nana{ namespace widgets { impl_->capacities.behavior->adjust_caret_into_screen(); reset_caret(); - render(API::is_focus_ready(window_)); + impl_->try_refresh = sync_graph::refresh; _m_reset_content_size(); points_.xpos = points_.caret.x; } @@ -2033,10 +2046,14 @@ namespace nana{ namespace widgets points_.caret.x ++; - if (refresh || _m_update_caret_line(secondary_before)) - render(true); + + if (!refresh) + { + if (!_m_update_caret_line(secondary_before)) + draw_corner(); + } else - draw_corner(); + impl_->try_refresh = sync_graph::refresh; _m_reset_content_size(); points_.xpos = points_.caret.x; @@ -2232,14 +2249,13 @@ namespace nana{ namespace widgets if (record_undo) impl_->undo.push(std::move(undo_ptr)); + _m_reset_content_size(has_to_redraw); + if(has_to_redraw) { - impl_->capacities.behavior->pre_calc_lines(width_pixels()); impl_->capacities.behavior->adjust_caret_into_screen(); - render(true); + impl_->try_refresh = sync_graph::refresh; } - - _m_reset_content_size(); } void text_editor::undo(bool reverse) @@ -2249,11 +2265,10 @@ namespace nana{ namespace widgets else impl_->undo.undo(); - impl_->capacities.behavior->pre_calc_lines(width_pixels()); - impl_->capacities.behavior->adjust_caret_into_screen(); - render(true); + _m_reset_content_size(true); - _m_reset_content_size(); + impl_->capacities.behavior->adjust_caret_into_screen(); + impl_->try_refresh = sync_graph::refresh; } void text_editor::set_undo_queue_length(std::size_t len) @@ -2265,7 +2280,7 @@ namespace nana{ namespace widgets { const bool redraw_required = _m_cancel_select(0); if (_m_move_caret_ns(to_north) || redraw_required) - render(true); + impl_->try_refresh = sync_graph::refresh; } void text_editor::move_left() @@ -2280,7 +2295,7 @@ namespace nana{ namespace widgets pending = false; bool adjust_y = (attributes_.line_wrapped && impl_->capacities.behavior->adjust_caret_into_screen()); if (_m_move_offset_x_while_over_border(-2) || adjust_y) - render(true); + impl_->try_refresh = sync_graph::refresh; } else if (points_.caret.y) //Move to previous line points_.caret.x = static_cast(textbase().getline(--points_.caret.y).size()); @@ -2289,7 +2304,7 @@ namespace nana{ namespace widgets } if (pending && impl_->capacities.behavior->adjust_caret_into_screen()) - render(true); + impl_->try_refresh = sync_graph::refresh; points_.xpos = points_.caret.x; } @@ -2318,7 +2333,7 @@ namespace nana{ namespace widgets do_render = impl_->capacities.behavior->adjust_caret_into_screen(); if (do_render) - render(true); + impl_->try_refresh = sync_graph::refresh; points_.xpos = points_.caret.x; } @@ -2477,9 +2492,20 @@ namespace nana{ namespace widgets impl_->cview->move_origin(origin - impl_->cview->origin()); impl_->cview->sync(true); points_.xpos = points_.caret.x; + impl_->try_refresh = sync_graph::refresh; } } + unsigned text_editor::_m_width_px(bool include_vs) const + { + unsigned exclude_px = API::open_caret(window_, true).get()->dimension().width; + + if (!include_vs) + exclude_px += impl_->cview->space(); + + return (text_area_.area.width > exclude_px ? text_area_.area.width - exclude_px : 0); + } + void text_editor::_m_draw_border() { if (!API::widget_borderless(this->window_)) @@ -2510,7 +2536,7 @@ namespace nana{ namespace widgets points_.caret = _m_screen_to_caret(scrpos); if (stay_in_view && impl_->capacities.behavior->adjust_caret_into_screen()) - render(true); + impl_->try_refresh = sync_graph::refresh; move_caret(points_.caret); return points_.caret; @@ -2790,7 +2816,9 @@ namespace nana{ namespace widgets auto top = _m_caret_to_screen(upoint{ 0, static_cast(pos) }).y; const unsigned pixels = line_height(); - graph_.rectangle({ text_area_.area.x, top, width_pixels(), static_cast(pixels * secondary_count_before) }, true, API::bgcolor(window_)); + const rectangle update_area = { text_area_.area.x, top, width_pixels(), static_cast(pixels * secondary_count_before) }; + if (!API::dev::copy_transparent_background(window_, update_area, graph_, update_area.position())) + graph_.rectangle(update_area, true, API::bgcolor(window_)); auto fgcolor = API::fgcolor(window_); auto text_ptr = textbase().getline(pos).c_str(); @@ -2803,9 +2831,10 @@ namespace nana{ namespace widgets } _m_draw_border(); + impl_->try_refresh = sync_graph::lazy_refresh; } else - render(API::is_focus_ready(window_)); + impl_->try_refresh = sync_graph::refresh; } bool text_editor::_m_accepts(char_type ch) const @@ -2835,22 +2864,58 @@ namespace nana{ namespace widgets return (!API::window_enabled(window_) ? static_cast(0xE0E0E0) : API::bgcolor(window_)); } - void text_editor::_m_reset_content_size() + void text_editor::_m_reset_content_size(bool calc_lines) { - auto const height = static_cast(impl_->capacities.behavior->take_lines() * line_height()); + size csize; - unsigned width = 0; if (this->attributes_.line_wrapped) { - width = width_pixels(); + if (calc_lines) + { + //detect if vertical scrollbar is required + auto const max_lines = screen_lines(true); + auto const text_lines = textbase().lines(); + + csize.width = _m_width_px(true); + if (text_lines > max_lines) + { + //enable vertical scrollbar + csize.width = _m_width_px(false); + } + else + { + std::size_t lines = 0; + for (std::size_t i = 0; i < text_lines; ++i) + { + impl_->capacities.behavior->pre_calc_line(i, csize.width); + lines += impl_->capacities.behavior->take_lines(i); + + if (lines > max_lines) + { + //enable vertical scrollbar + csize.width = _m_width_px(false); + break; + } + } + } + + impl_->capacities.behavior->pre_calc_lines(csize.width); + } + else + csize.width = impl_->cview->content_size().width; } else { + if (calc_lines) + impl_->capacities.behavior->pre_calc_lines(0); + auto maxline = textbase().max_line(); - width = _m_text_extent_size(textbase().getline(maxline.first).c_str(), maxline.second).width; + csize.width = _m_text_extent_size(textbase().getline(maxline.first).c_str(), maxline.second).width; } - impl_->cview->content_size({ width, height }); + csize.height = static_cast(impl_->capacities.behavior->take_lines() * line_height()); + + impl_->cview->content_size(csize); } void text_editor::_m_reset() @@ -3188,10 +3253,7 @@ namespace nana{ namespace widgets int text_editor::_m_text_topline() const { auto px = static_cast(line_height()); - if (0 == px) - return 0; - - return (impl_->cview->origin().y / px); + return (px ? (impl_->cview->origin().y / px) : px); } int text_editor::_m_text_x(const text_section& sct) const @@ -3508,6 +3570,7 @@ namespace nana{ namespace widgets return false; } } + impl_->try_refresh = sync_graph::refresh; return true; } diff --git a/source/gui/widgets/slider.cpp b/source/gui/widgets/slider.cpp index b66b141c..9c656d31 100644 --- a/source/gui/widgets/slider.cpp +++ b/source/gui/widgets/slider.cpp @@ -300,7 +300,7 @@ namespace nana { if(!graph.size().empty()) { - proto_.renderer->background(other_.wd, graph, (bground_mode::basic == API::effects_bground_mode(other_.wd)), other_.widget->scheme()); + proto_.renderer->background(other_.wd, graph, API::dev::copy_transparent_background(other_.wd, graph), other_.widget->scheme()); _m_draw_elements(graph); } } @@ -897,7 +897,7 @@ namespace nana bool slider::transparent() const { - return (bground_mode::basic == API::effects_bground_mode(*this)); + return API::is_transparent_background(*this); } //end class slider }//end namespace nana diff --git a/source/gui/widgets/spinbox.cpp b/source/gui/widgets/spinbox.cpp index ca87855a..d678950f 100644 --- a/source/gui/widgets/spinbox.cpp +++ b/source/gui/widgets/spinbox.cpp @@ -372,7 +372,8 @@ namespace nana return true; } - if (editor_->mouse_pressed(arg)) + editor_->mouse_pressed(arg); + if(editor_->try_refresh()) { _m_draw_spins(buttons::none); return true; @@ -383,10 +384,11 @@ namespace nana bool mouse_move(bool left_button, const ::nana::point& pos) { - if (editor_->mouse_move(left_button, pos)) + editor_->mouse_move(left_button, pos); + if(editor_->try_refresh()) { editor_->reset_caret(); - render(); + _m_draw_spins(spin_stated_); return true; } @@ -570,10 +572,11 @@ namespace nana void drawer::key_char(graph_reference, const arg_keyboard& arg) { - if (impl_->editor()->respond_char(arg)) + impl_->editor()->respond_char(arg); + if (impl_->editor()->try_refresh()) { - if (!impl_->value(to_utf8(impl_->editor()->text()), false)) - impl_->draw_spins(); + impl_->value(to_utf8(impl_->editor()->text()), false); + impl_->draw_spins(); API::dev::lazy_refresh(); } diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index 36e01043..6fc29494 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -103,22 +103,22 @@ namespace drawerbase { void drawer::mouse_down(graph_reference, const arg_mouse& arg) { - if (editor_->mouse_pressed(arg)) - { - editor_->render(true); + editor_->mouse_pressed(arg); + if(editor_->try_refresh()) API::dev::lazy_refresh(); - } } void drawer::mouse_move(graph_reference, const arg_mouse& arg) { - if(editor_->mouse_move(arg.left_button, arg.pos)) + editor_->mouse_move(arg.left_button, arg.pos); + if(editor_->try_refresh()) API::dev::lazy_refresh(); } void drawer::mouse_up(graph_reference, const arg_mouse& arg) { - if(editor_->mouse_pressed(arg)) + editor_->mouse_pressed(arg); + if(editor_->try_refresh()) API::dev::lazy_refresh(); } @@ -145,16 +145,16 @@ namespace drawerbase { void drawer::key_press(graph_reference, const arg_keyboard& arg) { - if(editor_->respond_key(arg)) - { - editor_->reset_caret(); + editor_->respond_key(arg); + editor_->reset_caret(true); + if(editor_->try_refresh()) API::dev::lazy_refresh(); - } } void drawer::key_char(graph_reference, const arg_keyboard& arg) { - if (editor_->respond_char(arg)) + editor_->respond_char(arg); + if(editor_->try_refresh()) API::dev::lazy_refresh(); } @@ -163,6 +163,10 @@ namespace drawerbase { _m_text_area(arg.width, arg.height); refresh(graph); editor_->reset_caret(); + + if (!editor_->try_refresh()) + refresh(graph); + API::dev::lazy_refresh(); } @@ -225,7 +229,10 @@ namespace drawerbase { internal_scope_guard lock; auto editor = get_drawer_trigger().editor(); if (editor && editor->load(file.data())) - API::update_window(handle()); + { + if (editor->try_refresh()) + API::update_window(handle()); + } } void textbox::store(std::string file) @@ -267,7 +274,9 @@ namespace drawerbase { editor->move_caret_end(true); editor->textbase().reset(); - API::update_window(this->handle()); + + if (editor->try_refresh()) + API::update_window(this->handle()); } return *this; } @@ -383,6 +392,8 @@ namespace drawerbase { editor->move_caret_end(false); editor->put(to_wstring(text)); + + editor->try_refresh(); API::update_window(this->handle()); } return *this; @@ -399,8 +410,11 @@ namespace drawerbase { { internal_scope_guard lock; auto editor = get_drawer_trigger().editor(); - if (editor->line_wrapped(autl)) + if (editor && editor->line_wrapped(autl)) + { + editor->try_refresh(); API::update_window(handle()); + } return *this; } @@ -420,6 +434,8 @@ namespace drawerbase { { auto wd = handle(); API::eat_tabstop(wd, ml); //textbox handles the Tab pressing when it is multi-line. + + editor->try_refresh(); API::update_window(wd); } return *this; @@ -495,7 +511,7 @@ namespace drawerbase { internal_scope_guard lock; auto editor = get_drawer_trigger().editor(); if(editor && editor->select(yes)) - API::update_window(*this); + API::refresh_window(*this); } std::pair textbox::selection() const @@ -525,7 +541,8 @@ namespace drawerbase { if(editor) { editor->paste(); - API::update_window(*this); + if (editor->try_refresh()) + API::update_window(*this); } } @@ -578,7 +595,10 @@ namespace drawerbase { internal_scope_guard lock; auto editor = get_drawer_trigger().editor(); if (editor) + { editor->set_highlight(name, fgcolor, bgcolor); + API::refresh_window(handle()); + } } void textbox::erase_highlight(const std::string& name) @@ -586,7 +606,10 @@ namespace drawerbase { internal_scope_guard lock; auto editor = get_drawer_trigger().editor(); if (editor) + { editor->erase_highlight(name); + API::refresh_window(handle()); + } } void textbox::set_keywords(const std::string& name, bool case_sensitive, bool whole_word_match, std::initializer_list kw_list) @@ -597,6 +620,7 @@ namespace drawerbase { { for (auto & kw : kw_list) editor->set_keyword(kw, name, case_sensitive, whole_word_match); + API::refresh_window(handle()); } } @@ -608,6 +632,7 @@ namespace drawerbase { { for (auto & kw : kw_list_utf8) editor->set_keyword(::nana::charset(kw, ::nana::unicode::utf8), name, case_sensitive, whole_word_match); + API::refresh_window(handle()); } } @@ -616,7 +641,10 @@ namespace drawerbase { internal_scope_guard lock; auto editor = get_drawer_trigger().editor(); if (editor) + { editor->erase_keyword(to_wstring(kw)); + API::refresh_window(handle()); + } } textbox& textbox::text_align(::nana::align alignment) @@ -626,7 +654,7 @@ namespace drawerbase { if (editor) { editor->text_align(alignment); - API::update_window(this->handle()); + API::refresh_window(handle()); } return *this; diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index e62e728f..023471ae 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -105,7 +105,7 @@ namespace nana nana::paint::graphics item_graph({ item_r_.width, item_r_.height }); item_graph.typeface(graph_->typeface()); - renderer_->set_color(widget_->bgcolor(), widget_->fgcolor()); + renderer_->begin_paint(*widget_); renderer_->bground(item_graph, this); renderer_->expander(item_graph, this); renderer_->crook(item_graph, this); @@ -343,7 +343,9 @@ namespace nana if (attr.auto_draw || ignore_auto_draw) { //Draw background - data.graph->rectangle(true, data.widget_ptr->bgcolor()); + rectangle bground_r{ data.graph->size() }; + if (!API::dev::copy_transparent_background(data.widget_ptr->handle(), bground_r, *data.graph, {})) + 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))); @@ -1201,13 +1203,11 @@ namespace nana class internal_renderer : public renderer_interface { - nana::color bgcolor_; - nana::color fgcolor_; + window window_handle_; - void set_color(const nana::color & bgcolor, const nana::color& fgcolor) override + void begin_paint(::nana::widget& wdg) override { - bgcolor_ = bgcolor; - fgcolor_ = fgcolor; + window_handle_ = wdg.handle(); } void bground(graph_reference graph, const compset_interface * compset) const override @@ -1234,8 +1234,19 @@ namespace nana if (clrptr) { - graph.rectangle(attr.area, false, clrptr[1]); - graph.rectangle(attr.area.pare_off(1), true, *clrptr); + if (API::is_transparent_background(window_handle_)) + { + paint::graphics item_graph{ attr.area.dimension() }; + item_graph.rectangle(false, clrptr[1]); + item_graph.rectangle(rectangle{attr.area.dimension()}.pare_off(1), true, *clrptr); + + item_graph.blend(rectangle{ attr.area.dimension() }, graph, attr.area.position(), 0.5); + } + else + { + graph.rectangle(attr.area, false, clrptr[1]); + graph.rectangle(attr.area.pare_off(1), true, *clrptr); + } } } } @@ -1255,7 +1266,7 @@ namespace nana 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); + arrow.draw(graph, API::bgcolor(window_handle_), (attr.mouse_pointed ? colors::deep_sky_blue : colors::black), r, element_state::normal); } } @@ -1266,7 +1277,7 @@ namespace nana { 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, API::bgcolor(window_handle_), API::fgcolor(window_handle_), attr.area, attr.mouse_pointed ? element_state::hovered : element_state::normal); } } @@ -1308,7 +1319,7 @@ namespace nana { comp_attribute_t attr; if (compset->comp_attribute(component::text, attr)) - graph.string(point{ attr.area.x, attr.area.y + 3 }, compset->item_attribute().text, fgcolor_); + graph.string(point{ attr.area.x, attr.area.y + 3 }, compset->item_attribute().text, API::fgcolor(window_handle_)); } private: mutable facade crook_; @@ -1408,8 +1419,6 @@ namespace nana item_renderer(implement * impl, const nana::point& pos) : impl_(impl), - bgcolor_(impl->data.widget_ptr->bgcolor()), - fgcolor_(impl->data.widget_ptr->fgcolor()), pos_(pos) { } @@ -1441,7 +1450,7 @@ namespace nana node_r_.height = comp_placer->item_height(*impl_->data.graph); auto renderer = draw_impl->data.renderer; - renderer->set_color(bgcolor_, fgcolor_); + renderer->begin_paint(*draw_impl->data.widget_ptr); renderer->bground(*draw_impl->data.graph, this); renderer->expander(*draw_impl->data.graph, this); renderer->crook(*draw_impl->data.graph, this); @@ -1476,8 +1485,6 @@ namespace nana } private: trigger::implement * impl_; - ::nana::color bgcolor_; - ::nana::color fgcolor_; ::nana::point pos_; const node_type * iterated_node_; item_attribute_t node_attr_; diff --git a/source/paint/detail/image_ico_resource.hpp b/source/paint/detail/image_ico_resource.hpp index a7dbaa03..dd451bf0 100644 --- a/source/paint/detail/image_ico_resource.hpp +++ b/source/paint/detail/image_ico_resource.hpp @@ -36,11 +36,13 @@ namespace nana{ namespace paint ::SHGetFileInfo(filename.c_str(), 0, &sfi, sizeof sfi, SHGFI_ICON); native_handle_ = sfi.hIcon; +#else + static_cast(filename); //eliminate unused parameter compiler warnings #endif return (nullptr != native_handle_); } - bool open(const void* data, std::size_t bytes) override + bool open(const void* /*data*/, std::size_t /*bytes*/) override { return false; } @@ -92,6 +94,7 @@ namespace nana{ namespace paint ::DrawIconEx(graph.handle()->context, p_dst.x, p_dst.y, reinterpret_cast(native_handle_), src_r.width, src_r.height, 0, 0, DI_NORMAL); #else static_cast(src_r); //eliminate unused parameter compiler warning. + static_cast(graph); static_cast(p_dst); #endif @@ -105,7 +108,8 @@ namespace nana{ namespace paint #if defined(NANA_WINDOWS) ::DrawIconEx(graph.handle()->context, r.x, r.y, reinterpret_cast(native_handle_), r.width, r.height, 0, 0, DI_NORMAL); #else - static_cast(r); //eliminate unused parameter compiler warning. + static_cast(graph); //eliminate unused parameter compiler warning. + static_cast(r); #endif } diff --git a/source/paint/detail/native_paint_interface.cpp b/source/paint/detail/native_paint_interface.cpp index 4d2caf0d..6a2b66ee 100644 --- a/source/paint/detail/native_paint_interface.cpp +++ b/source/paint/detail/native_paint_interface.cpp @@ -1,7 +1,7 @@ /* * Platform Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -100,18 +100,23 @@ namespace detail void blend(drawable_type dw, const rectangle& area, pixel_color_t color, double fade_rate) { - if (fade_rate <= 0) return; - if (fade_rate > 1) fade_rate = 1; + if (fade_rate < 0) + fade_rate = 0; + else if (fade_rate >= 1) + return; rectangle r; if (false == ::nana::overlap(rectangle{ drawable_size(dw) }, area, r)) return; - 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); + auto const color_fd_rate = (double(color.element.alpha_channel) / 255.0) * (1 - fade_rate); + + fade_rate = (1 - color_fd_rate); + + unsigned red = static_cast((color.value & 0xFF0000) * color_fd_rate); + unsigned green = static_cast((color.value & 0xFF00) * color_fd_rate); + unsigned blue = static_cast((color.value & 0xFF) * color_fd_rate); - double lrate = 1 - fade_rate; pixel_buffer pixbuf(dw, r.y, r.height); for (std::size_t row = 0; row < r.height; ++row) @@ -120,9 +125,9 @@ namespace detail const auto end = i + r.width; for (; i < end; ++i) { - 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); + unsigned px_r = ((static_cast((i->value & 0xFF0000) * fade_rate) + red) & 0xFF0000); + unsigned px_g = ((static_cast((i->value & 0xFF00) * fade_rate) + green) & 0xFF00); + unsigned px_b = ((static_cast((i->value & 0xFF) * fade_rate) + blue) & 0xFF); i->value = (px_r | px_g | px_b); } } diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index 201d18a8..b47907f1 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -672,6 +672,15 @@ namespace paint } } + void graphics::blend(const nana::rectangle& r, const ::nana::color& clr, double fade_rate) + { + if (impl_->handle) + { + nana::paint::detail::blend(impl_->handle, r, clr.px_color(), fade_rate); + if (impl_->changed == false) impl_->changed = true; + } + } + void graphics::blur(const nana::rectangle& r, std::size_t radius) { if(impl_->handle) @@ -968,15 +977,6 @@ namespace paint return bidi_string(pos, wstr.data(), wstr.size()); } - void graphics::blend(const nana::rectangle& r, const ::nana::color& clr, double fade_rate) - { - if (impl_->handle) - { - nana::paint::detail::blend(impl_->handle, r, clr.px_color(), fade_rate); - if (impl_->changed == false) impl_->changed = true; - } - } - void graphics::set_pixel(int x, int y, const ::nana::color& clr) { if (impl_->handle)