first init of 0.9
This commit is contained in:
492
source/gui/widgets/button.cpp
Normal file
492
source/gui/widgets/button.cpp
Normal file
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
* A Button Implementation
|
||||
* 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/widgets/button.cpp
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/button.hpp>
|
||||
#include <nana/paint/text_renderer.hpp>
|
||||
|
||||
namespace nana{ namespace drawerbase
|
||||
{
|
||||
namespace button
|
||||
{
|
||||
//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;
|
||||
}
|
||||
|
||||
trigger::~trigger()
|
||||
{
|
||||
delete attr_.icon;
|
||||
}
|
||||
|
||||
void trigger::attached(widget_reference widget, graph_reference graph)
|
||||
{
|
||||
graph_ = &graph;
|
||||
|
||||
widget_ = &widget;
|
||||
window wd = widget;
|
||||
|
||||
API::tabstop(wd);
|
||||
API::effects_edge_nimbus(wd, effects::edge_nimbus::active);
|
||||
API::effects_edge_nimbus(wd, effects::edge_nimbus::over);
|
||||
}
|
||||
|
||||
bool trigger::enable_pushed(bool eb)
|
||||
{
|
||||
attr_.enable_pushed = eb;
|
||||
return((eb == false) && pushed(false));
|
||||
}
|
||||
|
||||
bool trigger::pushed(bool pshd)
|
||||
{
|
||||
if(pshd != attr_.pushed)
|
||||
{
|
||||
attr_.pushed = pshd;
|
||||
if(false == pshd)
|
||||
{
|
||||
if (API::find_window(API::cursor_position()) == widget_->handle())
|
||||
attr_.e_state = element_state::hovered;
|
||||
else
|
||||
attr_.e_state = element_state::normal;
|
||||
}
|
||||
else
|
||||
attr_.e_state = element_state::pressed;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool trigger::pushed() const
|
||||
{
|
||||
return attr_.pushed;
|
||||
}
|
||||
|
||||
void trigger::omitted(bool om)
|
||||
{
|
||||
attr_.omitted = om;
|
||||
}
|
||||
|
||||
bool trigger::focus_color(bool eb)
|
||||
{
|
||||
if(eb != attr_.focus_color)
|
||||
{
|
||||
attr_.focus_color = eb;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
element::cite_bground & trigger::cite()
|
||||
{
|
||||
return cite_;
|
||||
}
|
||||
|
||||
void trigger::refresh(graph_reference graph)
|
||||
{
|
||||
_m_draw(graph);
|
||||
}
|
||||
|
||||
|
||||
void trigger::mouse_enter(graph_reference graph, const arg_mouse&)
|
||||
{
|
||||
attr_.e_state = (attr_.pushed || attr_.keep_pressed ? element_state::pressed : element_state::hovered);
|
||||
_m_draw(graph);
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void trigger::mouse_leave(graph_reference graph, const arg_mouse&)
|
||||
{
|
||||
if(attr_.enable_pushed && attr_.pushed)
|
||||
return;
|
||||
|
||||
attr_.e_state = element_state::normal;
|
||||
_m_draw(graph);
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void trigger::mouse_down(graph_reference graph, const arg_mouse&)
|
||||
{
|
||||
attr_.e_state = element_state::pressed;
|
||||
attr_.keep_pressed = true;
|
||||
|
||||
_m_draw(graph);
|
||||
API::capture_window(*widget_, true);
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void trigger::mouse_up(graph_reference graph, const arg_mouse&)
|
||||
{
|
||||
API::capture_window(*widget_, false);
|
||||
attr_.keep_pressed = false;
|
||||
if(attr_.enable_pushed && (false == attr_.pushed))
|
||||
{
|
||||
attr_.pushed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (element_state::pressed == attr_.e_state)
|
||||
attr_.e_state = element_state::hovered;
|
||||
else
|
||||
attr_.e_state = element_state::normal;
|
||||
|
||||
attr_.pushed = false;
|
||||
_m_draw(graph);
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void trigger::key_char(graph_reference, const arg_keyboard& arg)
|
||||
{
|
||||
if(arg.key == static_cast<char_t>(keyboard::enter))
|
||||
emit_click();
|
||||
}
|
||||
|
||||
void trigger::key_press(graph_reference, const arg_keyboard& arg)
|
||||
{
|
||||
bool ch_tabstop_next;
|
||||
switch(arg.key)
|
||||
{
|
||||
case keyboard::os_arrow_left: case keyboard::os_arrow_up:
|
||||
ch_tabstop_next = false;
|
||||
break;
|
||||
case keyboard::os_arrow_right: case keyboard::os_arrow_down:
|
||||
ch_tabstop_next = true;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
API::move_tabstop(widget_->handle(), ch_tabstop_next);
|
||||
}
|
||||
|
||||
void trigger::focus(graph_reference graph, const arg_focus& arg)
|
||||
{
|
||||
attr_.focused = arg.getting;
|
||||
_m_draw(graph);
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void trigger::_m_draw_title(graph_reference graph, bool enabled)
|
||||
{
|
||||
nana::string text = widget_->caption();
|
||||
|
||||
nana::string::value_type shortkey;
|
||||
nana::string::size_type shortkey_pos;
|
||||
nana::string str = API::transform_shortkey_text(text, shortkey, &shortkey_pos);
|
||||
|
||||
nana::size ts = graph.text_extent_size(str);
|
||||
nana::size gsize = graph.size();
|
||||
|
||||
nana::size icon_sz;
|
||||
if(attr_.icon)
|
||||
{
|
||||
icon_sz = attr_.icon->size();
|
||||
icon_sz.width += 5;
|
||||
}
|
||||
|
||||
int x = (static_cast<int>(gsize.width - 1 - ts.width) >> 1);
|
||||
int y = (static_cast<int>(gsize.height - 1 - ts.height) >> 1);
|
||||
|
||||
if(x < static_cast<int>(icon_sz.width))
|
||||
x = static_cast<int>(icon_sz.width);
|
||||
|
||||
unsigned omitted_pixels = gsize.width - icon_sz.width;
|
||||
std::size_t txtlen = str.size();
|
||||
const nana::char_t* txtptr = str.c_str();
|
||||
if(ts.width)
|
||||
{
|
||||
nana::paint::text_renderer tr(graph);
|
||||
if(enabled)
|
||||
{
|
||||
if (element_state::pressed == attr_.e_state)
|
||||
{
|
||||
++x;
|
||||
++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);
|
||||
else
|
||||
graph.bidi_string(x, y, fgcolor, txtptr, txtlen);
|
||||
|
||||
if(shortkey)
|
||||
{
|
||||
unsigned off_w = (shortkey_pos ? graph.text_extent_size(str, static_cast<unsigned>(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);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
graph.bidi_string(x + 1, y + 1, 0xFFFFFF, txtptr, txtlen);
|
||||
graph.bidi_string(x, y, 0x808080, txtptr, txtlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(attr_.icon)
|
||||
attr_.icon->paste(graph, 3, (gsize.height - icon_sz.height) / 2);
|
||||
}
|
||||
|
||||
void trigger::_m_draw(graph_reference graph)
|
||||
{
|
||||
window wd = widget_->handle();
|
||||
bool eb = API::window_enabled(wd);
|
||||
|
||||
attr_.bgcolor = API::background(wd);
|
||||
attr_.fgcolor = API::foreground(wd);
|
||||
|
||||
element_state e_state = attr_.e_state;
|
||||
if (eb)
|
||||
{
|
||||
if (attr_.focused)
|
||||
{
|
||||
if (element_state::normal == e_state)
|
||||
e_state = element_state::focus_normal;
|
||||
else if (element_state::hovered == e_state)
|
||||
e_state = element_state::focus_hovered;
|
||||
}
|
||||
}
|
||||
else
|
||||
e_state = element_state::disabled;
|
||||
|
||||
if (false == cite_.draw(graph, attr_.bgcolor, attr_.fgcolor, graph.size(), e_state))
|
||||
{
|
||||
if (bground_mode::basic != API::effects_bground_mode(wd))
|
||||
{
|
||||
_m_draw_background(graph);
|
||||
_m_draw_border(graph);
|
||||
}
|
||||
}
|
||||
_m_draw_title(graph, eb);
|
||||
}
|
||||
|
||||
void trigger::_m_draw_background(graph_reference graph)
|
||||
{
|
||||
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);
|
||||
|
||||
if (element_state::pressed == attr_.e_state)
|
||||
{
|
||||
r.x = r.y = 2;
|
||||
std::swap(color_start, color_end);
|
||||
}
|
||||
graph.shadow_rectangle(r, color_start, color_end, true);
|
||||
}
|
||||
|
||||
void trigger::_m_draw_border(graph_reference graph)
|
||||
{
|
||||
nana::rectangle r(graph.size());
|
||||
int right = r.width - 1;
|
||||
int bottom = r.height - 1;
|
||||
|
||||
graph.rectangle_line(r,
|
||||
0x7F7F7F, 0x7F7F7F, 0x707070, 0x707070);
|
||||
|
||||
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_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);
|
||||
|
||||
if (element_state::pressed == attr_.e_state)
|
||||
graph.rectangle(r.pare_off(1), 0xC3C3C3, false);
|
||||
}
|
||||
|
||||
void trigger::emit_click()
|
||||
{
|
||||
arg_mouse arg;
|
||||
arg.evt_code = event_code::click;
|
||||
arg.window_handle = widget_->handle();
|
||||
arg.ctrl = arg.shift = false;
|
||||
arg.mid_button = arg.right_button = false;
|
||||
arg.left_button = true;
|
||||
arg.pos.x = arg.pos.y = 1;
|
||||
API::emit_event(event_code::click, arg.window_handle, arg);
|
||||
}
|
||||
|
||||
void trigger::icon(const nana::paint::image& img)
|
||||
{
|
||||
if(img.empty()) return;
|
||||
|
||||
if(nullptr == attr_.icon)
|
||||
attr_.icon = new paint::image;
|
||||
*attr_.icon = img;
|
||||
}
|
||||
//end class trigger
|
||||
}//end namespace button
|
||||
}//end namespace drawerbase
|
||||
|
||||
//button
|
||||
//@brief: Defaine a button widget and it provides the interfaces to be operational
|
||||
button::button(){}
|
||||
|
||||
button::button(window wd, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
}
|
||||
|
||||
button::button(window wd, const nana::string& text, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
caption(text);
|
||||
}
|
||||
|
||||
button::button(window wd, const nana::char_t* text, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
caption(text);
|
||||
}
|
||||
|
||||
button::button(window wd, const rectangle& r, bool visible)
|
||||
{
|
||||
create(wd, r, visible);
|
||||
}
|
||||
|
||||
button& button::icon(const nana::paint::image& img)
|
||||
{
|
||||
internal_scope_guard isg;
|
||||
get_drawer_trigger().icon(img);
|
||||
API::refresh_window(handle());
|
||||
return *this;
|
||||
}
|
||||
|
||||
button& button::enable_pushed(bool eb)
|
||||
{
|
||||
internal_scope_guard isg;
|
||||
if(get_drawer_trigger().enable_pushed(eb))
|
||||
API::refresh_window(handle());
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool button::pushed() const
|
||||
{
|
||||
return get_drawer_trigger().pushed();
|
||||
}
|
||||
|
||||
button& button::pushed(bool psd)
|
||||
{
|
||||
internal_scope_guard isg;
|
||||
if(get_drawer_trigger().pushed(psd))
|
||||
API::refresh_window(handle());
|
||||
return *this;
|
||||
}
|
||||
|
||||
button& button::omitted(bool om)
|
||||
{
|
||||
internal_scope_guard isg;
|
||||
get_drawer_trigger().omitted(om);
|
||||
API::refresh_window(handle());
|
||||
return *this;
|
||||
}
|
||||
|
||||
button& button::enable_focus_color(bool eb)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
if(get_drawer_trigger().focus_color(eb))
|
||||
API::refresh_window(handle());
|
||||
return *this;
|
||||
}
|
||||
|
||||
button& button::set_bground(const pat::cloneable<element::element_interface>& rv)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
get_drawer_trigger().cite().set(rv);
|
||||
return *this;
|
||||
}
|
||||
|
||||
button& button::set_bground(const std::string& name)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
get_drawer_trigger().cite().set(name.data());
|
||||
return *this;
|
||||
}
|
||||
|
||||
button& button::transparent(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
API::effects_bground(*this, effects::bground_transparent(0), 0.0);
|
||||
else
|
||||
API::effects_bground_remove(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool button::transparent() const
|
||||
{
|
||||
return (bground_mode::basic == API::effects_bground_mode(*this));
|
||||
}
|
||||
|
||||
button& button::edge_effects(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
API::effects_edge_nimbus(*this, effects::edge_nimbus::active);
|
||||
API::effects_edge_nimbus(*this, effects::edge_nimbus::over);
|
||||
}
|
||||
else
|
||||
API::effects_edge_nimbus(*this, effects::edge_nimbus::none);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void button::_m_shortkey()
|
||||
{
|
||||
get_drawer_trigger().emit_click();
|
||||
}
|
||||
|
||||
void button::_m_complete_creation()
|
||||
{
|
||||
events().shortkey.connect([this]
|
||||
{
|
||||
_m_shortkey();
|
||||
});
|
||||
}
|
||||
|
||||
void button::_m_caption(nana::string&& text)
|
||||
{
|
||||
API::unregister_shortkey(handle());
|
||||
|
||||
nana::char_t shortkey;
|
||||
API::transform_shortkey_text(text, shortkey, 0);
|
||||
if (shortkey)
|
||||
API::register_shortkey(handle(), shortkey);
|
||||
|
||||
base_type::_m_caption(std::move(text));
|
||||
}
|
||||
//end class button
|
||||
}//end namespace nana
|
||||
|
||||
942
source/gui/widgets/categorize.cpp
Normal file
942
source/gui/widgets/categorize.cpp
Normal file
@@ -0,0 +1,942 @@
|
||||
/*
|
||||
* A Categorize Implementation
|
||||
* 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/widgets/categorize.cpp
|
||||
*/
|
||||
|
||||
#include <nana/gui/wvl.hpp>
|
||||
#include <nana/gui/widgets/categorize.hpp>
|
||||
#include <nana/gui/widgets/float_listbox.hpp>
|
||||
#include <nana/paint/gadget.hpp>
|
||||
#include <nana/gui/widgets/detail/tree_cont.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
namespace drawerbase
|
||||
{
|
||||
namespace categorize
|
||||
{
|
||||
struct event_agent_holder
|
||||
{
|
||||
std::function<void(nana::any&)> selected;
|
||||
};
|
||||
|
||||
struct item
|
||||
: public float_listbox::item_interface
|
||||
{
|
||||
nana::paint::image item_image;
|
||||
nana::string item_text;
|
||||
public:
|
||||
item(const nana::string& s)
|
||||
: item_text(s)
|
||||
{}
|
||||
public:
|
||||
//Implement item_interface methods
|
||||
const nana::paint::image& image() const override
|
||||
{
|
||||
return item_image;
|
||||
}
|
||||
|
||||
const nana::char_t * text() const override
|
||||
{
|
||||
return item_text.data();
|
||||
}
|
||||
};
|
||||
|
||||
struct item_tag
|
||||
{
|
||||
nana::size scale;
|
||||
unsigned pixels;
|
||||
nana::any value;
|
||||
};
|
||||
|
||||
//class renderer
|
||||
renderer::ui_element::ui_element()
|
||||
: what(none), index(0)
|
||||
{}
|
||||
renderer::~renderer(){}
|
||||
//end class renderer
|
||||
|
||||
//interior_renderer
|
||||
|
||||
class interior_renderer
|
||||
: public renderer
|
||||
{
|
||||
private:
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
graph.rectangle(r, style_.bgcolor, true);
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
if(state == mouse_action::pressed)
|
||||
{
|
||||
++x;
|
||||
++y;
|
||||
}
|
||||
}
|
||||
else
|
||||
graph.rectangle(r, style_.bgcolor, true);
|
||||
|
||||
nana::paint::gadget::arrow_16_pixels(graph, x, y,
|
||||
style_.fgcolor, 3, nana::paint::gadget::directions::to_west);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
nana::point strpos(r.x + 5, r.y + static_cast<int>(r.height - txtheight) / 2);
|
||||
|
||||
if((ui_el_.what == ui_el_.item_arrow || ui_el_.what == ui_el_.item_name) && (ui_el_.index == index))
|
||||
{
|
||||
mouse_action state_arrow, state_name;
|
||||
if(mouse_action::pressed != state)
|
||||
{
|
||||
state_arrow = (ui_el_.what == ui_el_.item_arrow ? mouse_action::over : mouse_action::normal);
|
||||
state_name = (ui_el_.what == ui_el_.item_name ? mouse_action::over : mouse_action::normal);
|
||||
}
|
||||
else
|
||||
{
|
||||
state_name = state_arrow = mouse_action::pressed;
|
||||
++strpos.x;
|
||||
++strpos.y;
|
||||
}
|
||||
|
||||
int top = r.y + 1;
|
||||
unsigned width = r.width - 2;
|
||||
unsigned height = r.height - 2;
|
||||
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);
|
||||
}
|
||||
_m_item_bground(graph, r.x + 1, top, width, height, state_name);
|
||||
graph.rectangle(r, 0x3C7FB1, false);
|
||||
}
|
||||
graph.string(strpos.x, strpos.y, style_.fgcolor, name);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void border(graph_reference graph)
|
||||
{
|
||||
graph.rectangle(0xF0F0F0, false);
|
||||
graph.rectangle_line(nana::rectangle(graph.size()).pare_off(1),
|
||||
0x9DABB9, 0x484E55, 0x484E55, 0x9DABB9);
|
||||
}
|
||||
private:
|
||||
void _m_item_bground(graph_reference graph, int x, int y, unsigned width, unsigned height, mouse_action state)
|
||||
{
|
||||
const unsigned half = (height - 2) / 2;
|
||||
int left = x + 1;
|
||||
int top = y + 1;
|
||||
nana::color_t upcol, downcol;
|
||||
switch(state)
|
||||
{
|
||||
case mouse_action::over:
|
||||
upcol = 0x0DFF2FC;
|
||||
downcol = 0xA9DAF5;
|
||||
break;
|
||||
case mouse_action::pressed:
|
||||
upcol = 0xA6D7F2;
|
||||
downcol = 0x92C4F6;
|
||||
++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<int>(half), width - 2, (height - 2) - half, downcol, true);
|
||||
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);
|
||||
++x;
|
||||
++y;
|
||||
graph.line(x, y, right, y, 0xA6C7D9);
|
||||
graph.line(x, y + 1, x, bottom, 0xA6C7D9);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ui_element ui_el_;
|
||||
struct style_tag
|
||||
{
|
||||
nana::color_t bgcolor;
|
||||
nana::color_t fgcolor;
|
||||
}style_;
|
||||
};
|
||||
|
||||
class tree_wrapper
|
||||
{
|
||||
public:
|
||||
typedef widgets::detail::tree_cont<item_tag> container;
|
||||
typedef container::node_type * node_handle;
|
||||
|
||||
tree_wrapper()
|
||||
:splitstr_(STR("\\")), cur_(nullptr)
|
||||
{}
|
||||
|
||||
bool seq(std::size_t index, std::vector<node_handle> & seqv) const
|
||||
{
|
||||
_m_read_node_path(seqv);
|
||||
|
||||
if(index < seqv.size())
|
||||
{
|
||||
if(index)
|
||||
seqv.erase(seqv.begin(), seqv.begin() + index);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void splitstr(const nana::string& ss)
|
||||
{
|
||||
if(ss.size())
|
||||
splitstr_ = ss;
|
||||
}
|
||||
|
||||
const nana::string& splitstr() const
|
||||
{
|
||||
return splitstr_;
|
||||
}
|
||||
|
||||
nana::string path() const
|
||||
{
|
||||
std::vector<node_handle> v;
|
||||
_m_read_node_path(v);
|
||||
|
||||
nana::string str;
|
||||
bool not_head = false;
|
||||
for(auto i : v)
|
||||
{
|
||||
if(not_head)
|
||||
str += splitstr_;
|
||||
else
|
||||
not_head = true;
|
||||
str += i->value.first;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
void path(const nana::string& key)
|
||||
{
|
||||
cur_ = tree_.ref(key);
|
||||
}
|
||||
|
||||
node_handle at(std::size_t index) const
|
||||
{
|
||||
std::vector<node_handle> v;
|
||||
_m_read_node_path(v);
|
||||
return (index < v.size() ? v[index] : nullptr);
|
||||
}
|
||||
|
||||
node_handle tail(std::size_t index)
|
||||
{
|
||||
node_handle i = at(index);
|
||||
if(i) cur_ = i;
|
||||
return i;
|
||||
}
|
||||
|
||||
node_handle cur() const
|
||||
{
|
||||
return cur_;
|
||||
}
|
||||
|
||||
void cur(node_handle i)
|
||||
{
|
||||
cur_ = i;
|
||||
}
|
||||
|
||||
void insert(const nana::string& name, const nana::any& value)
|
||||
{
|
||||
item_tag m;
|
||||
m.pixels = 0;
|
||||
m.value = value;
|
||||
cur_ = tree_.insert(cur_, name, m);
|
||||
}
|
||||
|
||||
bool childset(const nana::string& name, const nana::any& value)
|
||||
{
|
||||
if(cur_)
|
||||
{
|
||||
item_tag m;
|
||||
m.pixels = 0;
|
||||
m.value = value;
|
||||
tree_.insert(cur_, name, m);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool childset_erase(const nana::string& name)
|
||||
{
|
||||
if(cur_)
|
||||
{
|
||||
for(node_handle i = cur_->child; i; i = i->next)
|
||||
{
|
||||
if(i->value.first == name)
|
||||
{
|
||||
tree_.remove(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
node_handle find_child(const nana::string& name) const
|
||||
{
|
||||
if(cur_)
|
||||
{
|
||||
for(node_handle i = cur_->child; i; i = i->next)
|
||||
{
|
||||
if(i->value.first == name)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool clear()
|
||||
{
|
||||
if(tree_.get_root()->child)
|
||||
{
|
||||
tree_.clear();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
void _m_read_node_path(std::vector<node_handle>& v) const
|
||||
{
|
||||
node_handle root = tree_.get_root();
|
||||
for(node_handle i = cur_; i && (i != root); i = i->owner)
|
||||
v.insert(v.begin(), i);
|
||||
}
|
||||
private:
|
||||
container tree_;
|
||||
nana::string splitstr_;
|
||||
node_handle cur_;
|
||||
};
|
||||
|
||||
//class scheme
|
||||
class trigger::scheme
|
||||
{
|
||||
public:
|
||||
typedef tree_wrapper container;
|
||||
typedef container::node_handle node_handle;
|
||||
typedef renderer::ui_element ui_element;
|
||||
|
||||
enum class mode
|
||||
{
|
||||
normal, floatlist
|
||||
};
|
||||
|
||||
scheme()
|
||||
: graph_(nullptr)
|
||||
{
|
||||
proto_.ui_renderer = pat::cloneable<renderer>(interior_renderer());
|
||||
style_.mode = mode::normal;
|
||||
style_.listbox = nullptr;
|
||||
}
|
||||
|
||||
void attach(window wd, nana::paint::graphics* graph)
|
||||
{
|
||||
window_ = wd;
|
||||
API::background(wd, 0xFFFFFF);
|
||||
graph_ = graph;
|
||||
}
|
||||
|
||||
void detach()
|
||||
{
|
||||
window_ = nullptr;
|
||||
graph_ = nullptr;
|
||||
}
|
||||
|
||||
window window_handle() const
|
||||
{
|
||||
return window_;
|
||||
}
|
||||
|
||||
const container& tree() const
|
||||
{
|
||||
return treebase_;
|
||||
}
|
||||
|
||||
container& tree()
|
||||
{
|
||||
return treebase_;
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
_m_calc_scale();
|
||||
|
||||
nana::rectangle r = _m_make_rectangle(); //_m_make_rectangle must be called after _m_calc_scale()
|
||||
_m_calc_pixels(r);
|
||||
|
||||
proto_.ui_renderer->background(*graph_, window_, r, ui_el_);
|
||||
if(head_)
|
||||
proto_.ui_renderer->root_arrow(*graph_, _m_make_root_rectangle(), style_.state);
|
||||
_m_draw_items(r);
|
||||
proto_.ui_renderer->border(*graph_);
|
||||
}
|
||||
|
||||
bool locate(int x, int y) const
|
||||
{
|
||||
if(graph_)
|
||||
{
|
||||
if(head_)
|
||||
{
|
||||
auto r = _m_make_root_rectangle();
|
||||
if (r.is_hit(x, y))
|
||||
{
|
||||
style_.active_item_rectangle = r;
|
||||
if(ui_el_.what == ui_el_.item_root)
|
||||
return false;
|
||||
ui_el_.what = ui_el_.item_root;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
nana::rectangle r = _m_make_rectangle();
|
||||
std::vector<node_handle> seq;
|
||||
if(r.is_hit(x, y) && treebase_.seq(head_, seq))
|
||||
{
|
||||
const int xbase = r.x;
|
||||
const int xend = static_cast<int>(r.width) + r.x;
|
||||
|
||||
//Change the meaning of variable r. Now, r indicates the area of a item
|
||||
r.height = item_height_;
|
||||
|
||||
std::size_t seq_index = 0;
|
||||
for(auto i : seq)
|
||||
{
|
||||
r.width = i->value.second.pixels;
|
||||
//If the item is over the right border of widget, the item would be painted at
|
||||
//the begining of the next line.
|
||||
if(static_cast<int>(r.width) + r.x > xend)
|
||||
{
|
||||
r.x = xbase;
|
||||
r.y += r.height;
|
||||
}
|
||||
|
||||
if(r.is_hit(x, y))
|
||||
{
|
||||
style_.active_item_rectangle = r;
|
||||
std::size_t index = seq_index + head_;
|
||||
|
||||
ui_element::t what = ((i->child && (r.x + static_cast<int>(r.width) - 16 < x))
|
||||
? ui_el_.item_arrow : ui_el_.item_name);
|
||||
if(what == ui_el_.what && index == ui_el_.index)
|
||||
return false;
|
||||
|
||||
ui_el_.what = what;
|
||||
ui_el_.index = index;
|
||||
return true;
|
||||
}
|
||||
r.x += r.width;
|
||||
++seq_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ui_el_.what == ui_el_.somewhere) return false;
|
||||
ui_el_.what = ui_el_.somewhere;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool erase_locate()
|
||||
{
|
||||
ui_el_.index = npos;
|
||||
if(ui_el_.what != ui_el_.none)
|
||||
{
|
||||
ui_el_.what = ui_el_.none;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ui_element locate() const
|
||||
{
|
||||
return ui_el_;
|
||||
}
|
||||
|
||||
void mouse_pressed()
|
||||
{
|
||||
style_.state = mouse_action::pressed;
|
||||
switch(ui_el_.what)
|
||||
{
|
||||
case ui_element::item_root:
|
||||
case ui_element::item_arrow:
|
||||
_m_show_list();
|
||||
style_.mode = mode::floatlist;
|
||||
break;
|
||||
default: //Don't take care about other elements
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void mouse_release()
|
||||
{
|
||||
if(style_.mode != mode::floatlist)
|
||||
{
|
||||
style_.state = mouse_action::normal;
|
||||
switch(ui_el_.what)
|
||||
{
|
||||
case ui_element::item_name:
|
||||
_m_selected(treebase_.tail(ui_el_.index));
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_list_shown() const
|
||||
{
|
||||
return (nullptr != style_.listbox);
|
||||
}
|
||||
|
||||
event_agent_holder& evt_holder() const
|
||||
{
|
||||
return evt_holder_;
|
||||
}
|
||||
private:
|
||||
void _m_selected(node_handle node)
|
||||
{
|
||||
if(node)
|
||||
{
|
||||
API::dev::window_caption(window_handle(), tree().path());
|
||||
if(evt_holder_.selected)
|
||||
evt_holder_.selected(node->value.second.value);
|
||||
}
|
||||
}
|
||||
|
||||
void _m_show_list()
|
||||
{
|
||||
if(style_.listbox)
|
||||
style_.listbox->close();
|
||||
|
||||
style_.module.items.clear();
|
||||
|
||||
nana::rectangle r;
|
||||
style_.list_trigger = ui_el_.what;
|
||||
if(ui_el_.what == ui_el_.item_arrow)
|
||||
{
|
||||
style_.active = ui_el_.index;
|
||||
node_handle i = treebase_.at(ui_el_.index);
|
||||
if(i)
|
||||
{
|
||||
for(node_handle child = i->child; child; child = child->next)
|
||||
style_.module.items.emplace_back(std::make_shared<item>(child->value.first));
|
||||
}
|
||||
r = style_.active_item_rectangle;
|
||||
}
|
||||
else if(ui_el_.item_root == ui_el_.what)
|
||||
{
|
||||
std::vector<node_handle> v;
|
||||
if(treebase_.seq(0, v))
|
||||
{
|
||||
auto end = v.cbegin() + head_;
|
||||
for(auto i = v.cbegin(); i != end; ++i)
|
||||
style_.module.items.emplace_back(std::make_shared<item>((*i)->value.first));
|
||||
}
|
||||
r = style_.active_item_rectangle;
|
||||
}
|
||||
r.y += r.height;
|
||||
r.width = r.height = 100;
|
||||
style_.listbox = &(form_loader<nana::float_listbox>()(window_, r, true));
|
||||
style_.listbox->set_module(style_.module, 16);
|
||||
style_.listbox->events().destroy.connect([this]
|
||||
{
|
||||
_m_list_closed();
|
||||
});
|
||||
}
|
||||
|
||||
void _m_list_closed()
|
||||
{
|
||||
style_.mode = mode::normal;
|
||||
style_.state = mouse_action::normal;
|
||||
|
||||
bool is_draw = false;
|
||||
if((style_.module.index != npos) && style_.module.have_selected)
|
||||
{
|
||||
switch(style_.list_trigger)
|
||||
{
|
||||
case ui_element::item_arrow:
|
||||
{
|
||||
treebase_.tail(style_.active);
|
||||
nana::string name = style_.module.items[style_.module.index]->text();
|
||||
node_handle node = treebase_.find_child(name);
|
||||
if(node)
|
||||
{
|
||||
treebase_.cur(node);
|
||||
_m_selected(node);
|
||||
is_draw = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ui_element::item_root:
|
||||
_m_selected(treebase_.tail(style_.module.index));
|
||||
is_draw = true;
|
||||
break;
|
||||
default: //Don't take care about other elements
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
is_draw = true;
|
||||
|
||||
if(is_draw)
|
||||
{
|
||||
draw();
|
||||
API::update_window(window_);
|
||||
}
|
||||
style_.listbox = nullptr;
|
||||
}
|
||||
private:
|
||||
unsigned _m_item_fix_scale() const
|
||||
{
|
||||
return graph_->height() - 2;
|
||||
}
|
||||
|
||||
nana::rectangle _m_make_root_rectangle() const
|
||||
{
|
||||
return nana::rectangle(1, 1, 16, _m_item_fix_scale());
|
||||
}
|
||||
|
||||
//_m_make_rectangle
|
||||
//@brief: This function calculate the items area. This must be called after _m_calc_scale()
|
||||
nana::rectangle _m_make_rectangle() const
|
||||
{
|
||||
nana::rectangle r(1, 1, graph_->width() - 2, _m_item_fix_scale());
|
||||
|
||||
unsigned px = r.width;
|
||||
std::size_t lines = item_lines_;
|
||||
std::vector<node_handle> v;
|
||||
treebase_.seq(0, v);
|
||||
for(auto node : v)
|
||||
{
|
||||
if(node->value.second.scale.width > px)
|
||||
{
|
||||
if(lines > 1)
|
||||
{
|
||||
--lines;
|
||||
px = r.width;
|
||||
if(px < node->value.second.scale.width)
|
||||
{
|
||||
--lines;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Too many items, so some of items cann't be displayed
|
||||
r.x += 16;
|
||||
r.width -= 16;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
px -= node->value.second.scale.width;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void _m_calc_scale()
|
||||
{
|
||||
nana::size tsz;
|
||||
unsigned highest = 0;
|
||||
std::vector<node_handle> v;
|
||||
treebase_.seq(0, v);
|
||||
for(auto node : v)
|
||||
{
|
||||
node->value.second.scale = graph_->text_extent_size(node->value.first);
|
||||
|
||||
if(highest < node->value.second.scale.height)
|
||||
highest = node->value.second.scale.height;
|
||||
|
||||
node->value.second.scale.width += (node->child ? 26 : 10);
|
||||
}
|
||||
|
||||
highest += 6; //the default height of item.
|
||||
|
||||
item_lines_ = (graph_->height() - 2) / highest;
|
||||
if(item_lines_ == 0)
|
||||
item_lines_ = 1;
|
||||
item_height_ = (1 != item_lines_ ? highest : _m_item_fix_scale());
|
||||
}
|
||||
|
||||
void _m_calc_pixels(const nana::rectangle& r)
|
||||
{
|
||||
std::size_t lines = item_lines_;
|
||||
|
||||
unsigned px = 0;
|
||||
head_ = 0;
|
||||
std::vector<node_handle> v;
|
||||
treebase_.seq(0, v);
|
||||
for(auto vi = v.rbegin(); vi != v.rend(); ++vi)
|
||||
{
|
||||
item_tag & m = (*vi)->value.second;
|
||||
if(r.width >= px + m.scale.width)
|
||||
{
|
||||
px += m.scale.width;
|
||||
m.pixels = m.scale.width;
|
||||
continue;
|
||||
}
|
||||
|
||||
//In fact, this item must be in the font of a line.
|
||||
m.pixels = (r.width >= m.scale.width ? m.scale.width : _m_minimial_pixels());
|
||||
if(0 == px) //This line is empty, NOT a newline
|
||||
{
|
||||
px = m.pixels;
|
||||
continue;
|
||||
}
|
||||
|
||||
//Newline, and check here whether is more lines.
|
||||
if(0 == --lines)
|
||||
{
|
||||
head_ = std::distance(vi, v.rend());
|
||||
break;
|
||||
}
|
||||
px = m.pixels;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned _m_minimial_pixels()
|
||||
{
|
||||
return 46;
|
||||
}
|
||||
|
||||
void _m_draw_items(const nana::rectangle& r)
|
||||
{
|
||||
nana::rectangle item_r = r;
|
||||
item_r.height = item_height_;
|
||||
std::size_t index = head_;
|
||||
const int xend = static_cast<int>(r.width) + r.x;
|
||||
std::vector<node_handle> v;
|
||||
treebase_.seq(0, v);
|
||||
for(auto vi = v.begin() + head_; vi != v.end(); ++vi)
|
||||
{
|
||||
node_handle i = (*vi);
|
||||
if(static_cast<int>(i->value.second.pixels) + item_r.x > xend)
|
||||
{
|
||||
item_r.x = r.x;
|
||||
item_r.y += item_height_;
|
||||
}
|
||||
item_r.width = i->value.second.pixels;
|
||||
proto_.ui_renderer->item(*graph_, item_r, index++, i->value.first, i->value.second.scale.height, i->child != 0, style_.state);
|
||||
item_r.x += item_r.width;
|
||||
}
|
||||
}
|
||||
private:
|
||||
window window_;
|
||||
nana::paint::graphics * graph_;
|
||||
nana::string splitstr_;
|
||||
std::size_t head_;
|
||||
unsigned item_height_;
|
||||
std::size_t item_lines_;
|
||||
container treebase_;
|
||||
|
||||
mutable ui_element ui_el_;
|
||||
struct style_tag
|
||||
{
|
||||
ui_element::t list_trigger;
|
||||
std::size_t active; //It indicates the item corresponding listbox.
|
||||
mutable ::nana::rectangle active_item_rectangle;
|
||||
::nana::float_listbox::module_type module;
|
||||
::nana::float_listbox * listbox;
|
||||
scheme::mode mode;
|
||||
mouse_action state; //The state of mouse
|
||||
}style_;
|
||||
|
||||
struct proto_tag
|
||||
{
|
||||
pat::cloneable<renderer> ui_renderer;
|
||||
}proto_;
|
||||
|
||||
mutable event_agent_holder evt_holder_;
|
||||
};
|
||||
|
||||
//class trigger
|
||||
trigger::trigger()
|
||||
: scheme_(new scheme)
|
||||
{}
|
||||
|
||||
trigger::~trigger()
|
||||
{
|
||||
delete scheme_;
|
||||
}
|
||||
|
||||
void trigger::insert(const nana::string& str, nana::any value)
|
||||
{
|
||||
scheme_->tree().insert(str, value);
|
||||
API::dev::window_caption(scheme_->window_handle(), scheme_->tree().path());
|
||||
scheme_->draw();
|
||||
}
|
||||
|
||||
bool trigger::childset(const nana::string& str, nana::any value)
|
||||
{
|
||||
if(scheme_->tree().childset(str, value))
|
||||
{
|
||||
scheme_->draw();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool trigger::childset_erase(const nana::string& str)
|
||||
{
|
||||
if(scheme_->tree().childset_erase(str))
|
||||
{
|
||||
scheme_->draw();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool trigger::clear()
|
||||
{
|
||||
if(scheme_->tree().clear())
|
||||
{
|
||||
scheme_->draw();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void trigger::splitstr(const nana::string& sstr)
|
||||
{
|
||||
scheme_->tree().splitstr(sstr);
|
||||
}
|
||||
|
||||
const nana::string& trigger::splitstr() const
|
||||
{
|
||||
return scheme_->tree().splitstr();
|
||||
}
|
||||
|
||||
void trigger::path(const nana::string& str)
|
||||
{
|
||||
scheme_->tree().path(str);
|
||||
}
|
||||
|
||||
nana::string trigger::path() const
|
||||
{
|
||||
return scheme_->tree().path();
|
||||
}
|
||||
|
||||
nana::any& trigger::value() const
|
||||
{
|
||||
auto node = scheme_->tree().cur();
|
||||
if(node)
|
||||
return node->value.second.value;
|
||||
|
||||
throw std::runtime_error("Nana.GUI.categorize::value(), current category is empty");
|
||||
}
|
||||
|
||||
void trigger::_m_event_agent_ready() const
|
||||
{
|
||||
auto & evt = scheme_->evt_holder();
|
||||
auto evt_agent = event_agent_.get();
|
||||
evt.selected = [evt_agent](::nana::any& val){
|
||||
evt_agent->selected(val);
|
||||
};
|
||||
}
|
||||
|
||||
void trigger::attached(widget_reference widget, graph_reference graph)
|
||||
{
|
||||
scheme_->attach(widget, &graph);
|
||||
}
|
||||
|
||||
void trigger::detached()
|
||||
{
|
||||
scheme_->detach();
|
||||
}
|
||||
|
||||
void trigger::refresh(graph_reference)
|
||||
{
|
||||
scheme_->draw();
|
||||
}
|
||||
|
||||
void trigger::mouse_down(graph_reference, const arg_mouse&)
|
||||
{
|
||||
if(scheme_->locate().what > ui_element::somewhere)
|
||||
{
|
||||
if(API::window_enabled(scheme_->window_handle()))
|
||||
{
|
||||
scheme_->mouse_pressed();
|
||||
scheme_->draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void trigger::mouse_up(graph_reference, const arg_mouse&)
|
||||
{
|
||||
if(scheme_->locate().what > ui_element::somewhere)
|
||||
{
|
||||
if(API::window_enabled(scheme_->window_handle()))
|
||||
{
|
||||
scheme_->mouse_release();
|
||||
scheme_->draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void trigger::mouse_move(graph_reference, const arg_mouse& arg)
|
||||
{
|
||||
if(scheme_->locate(arg.pos.x, arg.pos.y) && API::window_enabled(scheme_->window_handle()))
|
||||
{
|
||||
scheme_->draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void trigger::mouse_leave(graph_reference, const arg_mouse&)
|
||||
{
|
||||
if(API::window_enabled(scheme_->window_handle()) && (scheme_->is_list_shown() == false) && scheme_->erase_locate())
|
||||
{
|
||||
scheme_->draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
//end class trigger
|
||||
}//end namespace categorize
|
||||
}//end namespace draerbase
|
||||
}//end namespace nana
|
||||
243
source/gui/widgets/checkbox.cpp
Normal file
243
source/gui/widgets/checkbox.cpp
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* A CheckBox Implementation
|
||||
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: nana/gui/widgets/checkbox.cpp
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/checkbox.hpp>
|
||||
#include <nana/paint/gadget.hpp>
|
||||
#include <nana/paint/text_renderer.hpp>
|
||||
#include <nana/gui/element.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
namespace nana{ namespace drawerbase
|
||||
{
|
||||
namespace checkbox
|
||||
{
|
||||
typedef element::crook_interface::state crook_state;
|
||||
|
||||
struct drawer::implement
|
||||
{
|
||||
bool react;
|
||||
bool radio;
|
||||
facade<element::crook> crook;
|
||||
};
|
||||
|
||||
drawer::drawer()
|
||||
: widget_(nullptr),
|
||||
imptr_(new drawer::implement),
|
||||
impl_(imptr_.get())
|
||||
{
|
||||
impl_->react = true;
|
||||
impl_->radio = false;
|
||||
}
|
||||
|
||||
drawer::~drawer()
|
||||
{}
|
||||
|
||||
void drawer::attached(widget_reference widget, graph_reference)
|
||||
{
|
||||
widget_ = &widget;
|
||||
}
|
||||
|
||||
void drawer::refresh(graph_reference graph)
|
||||
{
|
||||
_m_draw(graph);
|
||||
}
|
||||
|
||||
void drawer::mouse_down(graph_reference graph, const arg_mouse&)
|
||||
{
|
||||
_m_draw(graph);
|
||||
}
|
||||
|
||||
void drawer::mouse_up(graph_reference graph, const arg_mouse&)
|
||||
{
|
||||
if(impl_->react)
|
||||
impl_->crook.reverse();
|
||||
_m_draw(graph);
|
||||
}
|
||||
|
||||
void drawer::mouse_enter(graph_reference graph, const arg_mouse&)
|
||||
{
|
||||
_m_draw(graph);
|
||||
}
|
||||
|
||||
void drawer::mouse_leave(graph_reference graph, const arg_mouse&)
|
||||
{
|
||||
_m_draw(graph);
|
||||
}
|
||||
|
||||
drawer::implement * drawer::impl() const
|
||||
{
|
||||
return impl_;
|
||||
}
|
||||
|
||||
void drawer::_m_draw(graph_reference graph)
|
||||
{
|
||||
_m_draw_background(graph);
|
||||
_m_draw_title(graph);
|
||||
_m_draw_checkbox(graph, graph.text_extent_size(STR("jN"), 2).height + 2);
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void drawer::_m_draw_background(graph_reference graph)
|
||||
{
|
||||
if(bground_mode::basic != API::effects_bground_mode(*widget_))
|
||||
graph.rectangle(API::background(*widget_), true);
|
||||
}
|
||||
|
||||
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_));
|
||||
}
|
||||
|
||||
void drawer::_m_draw_title(graph_reference graph)
|
||||
{
|
||||
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)
|
||||
{
|
||||
tr.render(17 + interval, 2, 0xFFFFFF, title.c_str(), title.length(), pixels);
|
||||
fgcolor = 0x808080;
|
||||
}
|
||||
|
||||
tr.render(16 + interval, 1, fgcolor, title.c_str(), title.length(), pixels);
|
||||
}
|
||||
}
|
||||
//end class drawer
|
||||
} //end namespace checkbox
|
||||
}//end namespace drawerbase
|
||||
|
||||
//class checkbox
|
||||
|
||||
checkbox::checkbox(){}
|
||||
|
||||
checkbox::checkbox(window wd, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
}
|
||||
|
||||
checkbox::checkbox(window wd, const nana::string& text, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
caption(text);
|
||||
}
|
||||
|
||||
checkbox::checkbox(window wd, const nana::char_t* text, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
caption(text);
|
||||
}
|
||||
|
||||
checkbox::checkbox(window wd, const nana::rectangle& r, bool visible)
|
||||
{
|
||||
create(wd, r, visible);
|
||||
}
|
||||
|
||||
void checkbox::element_set(const char* name)
|
||||
{
|
||||
get_drawer_trigger().impl()->crook.switch_to(name);
|
||||
}
|
||||
|
||||
void checkbox::react(bool want)
|
||||
{
|
||||
get_drawer_trigger().impl()->react = want;
|
||||
}
|
||||
|
||||
bool checkbox::checked() const
|
||||
{
|
||||
return (get_drawer_trigger().impl()->crook.checked() != drawerbase::checkbox::crook_state::unchecked);
|
||||
}
|
||||
|
||||
void checkbox::check(bool chk)
|
||||
{
|
||||
typedef drawerbase::checkbox::crook_state crook_state;
|
||||
get_drawer_trigger().impl()->crook.check(chk ? crook_state::checked : crook_state::unchecked);
|
||||
API::refresh_window(handle());
|
||||
}
|
||||
|
||||
void checkbox::radio(bool is_radio)
|
||||
{
|
||||
get_drawer_trigger().impl()->crook.radio(is_radio);
|
||||
}
|
||||
|
||||
void checkbox::transparent(bool enabled)
|
||||
{
|
||||
if(enabled)
|
||||
API::effects_bground(*this, effects::bground_transparent(0), 0.0);
|
||||
else
|
||||
API::effects_bground_remove(*this);
|
||||
}
|
||||
|
||||
bool checkbox::transparent() const
|
||||
{
|
||||
return (bground_mode::basic == API::effects_bground_mode(*this));
|
||||
}
|
||||
//end class checkbox
|
||||
|
||||
//class radio_group
|
||||
radio_group::~radio_group()
|
||||
{
|
||||
for(auto & i : ui_container_)
|
||||
{
|
||||
API::umake_event(i.eh_checked);
|
||||
API::umake_event(i.eh_destroy);
|
||||
}
|
||||
}
|
||||
|
||||
void radio_group::add(checkbox& uiobj)
|
||||
{
|
||||
uiobj.radio(true);
|
||||
uiobj.check(false);
|
||||
uiobj.react(false);
|
||||
|
||||
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));
|
||||
ui_container_.push_back(el);
|
||||
}
|
||||
|
||||
std::size_t radio_group::checked() const
|
||||
{
|
||||
auto i = std::find_if(ui_container_.cbegin(), ui_container_.cend(), [](decltype(*ui_container_.cbegin())& x)
|
||||
{
|
||||
return (x.uiobj->checked());
|
||||
});
|
||||
return static_cast<std::size_t>(i - ui_container_.cbegin());
|
||||
}
|
||||
|
||||
std::size_t radio_group::size() const
|
||||
{
|
||||
return ui_container_.size();
|
||||
}
|
||||
|
||||
void radio_group::_m_checked(const arg_mouse& arg)
|
||||
{
|
||||
for (auto & i : ui_container_)
|
||||
i.uiobj->check(arg.window_handle == i.uiobj->handle());
|
||||
}
|
||||
|
||||
void radio_group::_m_destroy(const arg_destroy& arg)
|
||||
{
|
||||
auto i = std::find_if(ui_container_.begin(), ui_container_.end(), [&arg](decltype(*ui_container_.begin()) & x)
|
||||
{
|
||||
return (arg.window_handle == x.uiobj->handle());
|
||||
});
|
||||
if(i != ui_container_.end())
|
||||
ui_container_.erase(i);
|
||||
}
|
||||
//end class radio_group
|
||||
}//end namespace nana
|
||||
1037
source/gui/widgets/combox.cpp
Normal file
1037
source/gui/widgets/combox.cpp
Normal file
File diff suppressed because it is too large
Load Diff
675
source/gui/widgets/date_chooser.cpp
Normal file
675
source/gui/widgets/date_chooser.cpp
Normal file
@@ -0,0 +1,675 @@
|
||||
/*
|
||||
* A date chooser Implementation
|
||||
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: nana/gui/widgets/date_chooser.cpp
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/date_chooser.hpp>
|
||||
#include <nana/paint/gadget.hpp>
|
||||
#include <nana/system/platform.hpp>
|
||||
#include <sstream>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
namespace drawerbase
|
||||
{
|
||||
namespace date_chooser
|
||||
{
|
||||
//class trigger: public drawer_trigger
|
||||
|
||||
trigger::trigger()
|
||||
: 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;
|
||||
}
|
||||
|
||||
bool trigger::chose() const
|
||||
{
|
||||
return chose_;
|
||||
}
|
||||
|
||||
nana::date trigger::read() const
|
||||
{
|
||||
return nana::date(chdate_.year, chdate_.month, chdate_.day);
|
||||
}
|
||||
|
||||
void trigger::week_name(unsigned index, const nana::string& str)
|
||||
{
|
||||
if(0 <= index && 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)
|
||||
{
|
||||
int xend = static_cast<int>(graph.width()) - 1;
|
||||
int yend = static_cast<int>(graph.height()) - 1;
|
||||
if(0 < y && y < static_cast<int>(topbar_height))
|
||||
{
|
||||
if(static_cast<int>(border_size) < x && x < xend)
|
||||
{
|
||||
if(x < border_size + 16)
|
||||
return where::left_button;
|
||||
else if(xend - border_size - 16 < x)
|
||||
return where::right_button;
|
||||
return where::topbar;
|
||||
}
|
||||
}
|
||||
else if(topbar_height < y && y < yend)
|
||||
{
|
||||
trace_pos_.x = x;
|
||||
trace_pos_.y = y;
|
||||
return where::textarea;
|
||||
}
|
||||
return where::none;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
_m_draw_topbar(graph);
|
||||
|
||||
if(graph.height() > 2 + topbar_height)
|
||||
{
|
||||
nana::point refpos(1, static_cast<int>(topbar_height) + 1);
|
||||
|
||||
nana::paint::graphics gbuf(width, graph.height() - 2 - topbar_height);
|
||||
gbuf.rectangle(0xF0F0F0, true);
|
||||
|
||||
switch(page_)
|
||||
{
|
||||
case page::date:
|
||||
_m_draw_days(refpos, gbuf);
|
||||
break;
|
||||
case page::month:
|
||||
_m_draw_months(refpos, gbuf);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
graph.bitblt(refpos.x, refpos.y, gbuf);
|
||||
}
|
||||
}
|
||||
|
||||
void trigger::_m_draw_topbar(graph_reference graph)
|
||||
{
|
||||
int ypos = (topbar_height - 16) / 2 + 1;
|
||||
|
||||
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);
|
||||
|
||||
if(graph.width() > 32 + border_size * 2)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss<<chmonth_.year;
|
||||
nana::string str;
|
||||
if(page_ == page::date)
|
||||
{
|
||||
str += 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 xpos = (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);
|
||||
}
|
||||
}
|
||||
|
||||
void trigger::_m_make_drawing_basis(drawing_basis& dbasis, graph_reference graph, const nana::point& refpos)
|
||||
{
|
||||
dbasis.refpos = refpos;
|
||||
const unsigned width = graph.width();
|
||||
const unsigned height = graph.height();
|
||||
|
||||
if(page::date == page_)
|
||||
{
|
||||
dbasis.line_s = height / 7.0;
|
||||
dbasis.row_s = width / 7.0;
|
||||
}
|
||||
else if(page::month == page_)
|
||||
{
|
||||
dbasis.line_s = height / 3.0;
|
||||
dbasis.row_s = width / 4.0;
|
||||
}
|
||||
|
||||
dbasis_ = dbasis;
|
||||
}
|
||||
|
||||
void trigger::_m_draw_pos(drawing_basis & dbasis, graph_reference graph, int x, int y, const nana::string& str, bool primary, bool sel)
|
||||
{
|
||||
nana::rectangle r(static_cast<int>(x * dbasis.row_s), static_cast<int>(y * dbasis.line_s),
|
||||
static_cast<int>(dbasis.row_s), static_cast<int>(dbasis.line_s));
|
||||
|
||||
nana::color_t color{ color_.normal };
|
||||
|
||||
nana::point tpos{ trace_pos_ - dbasis.refpos };
|
||||
|
||||
if((pos_ == where::textarea)
|
||||
&& (r.x <= tpos.x)
|
||||
&& (tpos.x < r.x + static_cast<int>(r.width))
|
||||
&& (r.y <= tpos.y)
|
||||
&& (tpos.y < r.y + static_cast<int>(r.height)))
|
||||
{
|
||||
if((page_ != page::date) || y)
|
||||
{
|
||||
color = color_.highlight;
|
||||
graph.rectangle(r, color_.bkcolor, true);
|
||||
}
|
||||
}
|
||||
|
||||
if(sel)
|
||||
{
|
||||
color = color_.highlight;
|
||||
graph.rectangle(r, color_.bkcolor, true);
|
||||
graph.rectangle(r, color_.selected, false);
|
||||
}
|
||||
|
||||
if(primary == false)
|
||||
color = 0xB0B0B0;
|
||||
|
||||
nana::size txt_s = graph.text_extent_size(str);
|
||||
graph.string(r.x + static_cast<int>(r.width - txt_s.width) / 2, r.y + static_cast<int>(r.height - txt_s.height) / 2, color, str);
|
||||
}
|
||||
|
||||
void trigger::_m_draw_pos(drawing_basis & dbasis, graph_reference graph, int x, int y, int number, bool primary, bool sel)
|
||||
{
|
||||
//The C++ library comes with MinGW does not provide std::to_wstring() conversion
|
||||
std::wstringstream ss;
|
||||
ss<<number;
|
||||
_m_draw_pos(dbasis, graph, x, y, nana::charset(ss.str()), primary, sel);
|
||||
}
|
||||
|
||||
void trigger::_m_draw_ex_days(drawing_basis & dbasis, graph_reference graph, int begx, int begy, bool before)
|
||||
{
|
||||
int x = nana::date::day_of_week(chmonth_.year, chmonth_.month, 1);
|
||||
int y = (x ? 1 : 2);
|
||||
|
||||
if(before)
|
||||
{
|
||||
int year = chmonth_.year;
|
||||
int month = chmonth_.month - 1;
|
||||
if(month == 0)
|
||||
{
|
||||
--year;
|
||||
month = 12;
|
||||
}
|
||||
bool same = (chdate_.year == year && chdate_.month == month);
|
||||
int days = nana::date::month_days(year, month);
|
||||
|
||||
int size = (x ? x : 7);
|
||||
int beg = days - size + 1;
|
||||
|
||||
for(int i = 0; i < size; ++i)
|
||||
{
|
||||
this->_m_draw_pos(dbasis, graph, i, 1, beg + i, false, same && (chdate_.day == beg + i));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int year = chmonth_.year;
|
||||
int month = chmonth_.month + 1;
|
||||
if(month == 13)
|
||||
{
|
||||
++year;
|
||||
month = 1;
|
||||
}
|
||||
bool same = (chdate_.year == year && chdate_.month == month);
|
||||
|
||||
int day = 1;
|
||||
x = begx;
|
||||
for(y = begy; y < 7; ++y)
|
||||
{
|
||||
for(; x < 7; ++x)
|
||||
{
|
||||
_m_draw_pos(dbasis, graph, x, y, day, false, same && (chdate_.day == day));
|
||||
++day;
|
||||
}
|
||||
x = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void trigger::_m_draw_days(const nana::point& refpos, graph_reference graph)
|
||||
{
|
||||
drawing_basis dbasis;
|
||||
_m_make_drawing_basis(dbasis, graph, refpos);
|
||||
|
||||
for(int i = 0; i < 7; ++i)
|
||||
_m_draw_pos(dbasis, graph, i, 0, weekstr_[i], true, false);
|
||||
|
||||
int day = 1;
|
||||
int x = nana::date::day_of_week(chmonth_.year, chmonth_.month, 1);
|
||||
int y = (x ? 1 : 2);
|
||||
|
||||
//draw the days that before the first day of this month
|
||||
_m_draw_ex_days(dbasis, graph, 0, 0, true);
|
||||
//
|
||||
int days = static_cast<int>(nana::date::month_days(chmonth_.year, chmonth_.month));
|
||||
|
||||
bool same = (chdate_.year == chmonth_.year && chdate_.month == chmonth_.month);
|
||||
while(day <= days)
|
||||
{
|
||||
for(; x < 7; ++x)
|
||||
{
|
||||
_m_draw_pos(dbasis, graph, x, y, day, true, (same && chdate_.day == day));
|
||||
if(++day > days) break;
|
||||
}
|
||||
if(day > days) break;
|
||||
y++;
|
||||
x = 0;
|
||||
}
|
||||
|
||||
++x;
|
||||
if(x >= 7)
|
||||
{
|
||||
x = 0;
|
||||
++y;
|
||||
}
|
||||
|
||||
_m_draw_ex_days(dbasis, graph, x, y, false);
|
||||
}
|
||||
|
||||
void trigger::_m_draw_months(const nana::point& refpos, graph_reference graph)
|
||||
{
|
||||
drawing_basis dbasis;
|
||||
_m_make_drawing_basis(dbasis, graph, refpos);
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
bool trigger::_m_get_trace(point pos, int & res)
|
||||
{
|
||||
pos -= dbasis_.refpos;
|
||||
|
||||
int lines = 7, rows = 7; //defaultly for page::date
|
||||
|
||||
if(page_ == page::month)
|
||||
{
|
||||
lines = 3;
|
||||
rows = 4;
|
||||
}
|
||||
|
||||
int width = static_cast<int>(dbasis_.row_s * rows);
|
||||
int height = static_cast<int>(dbasis_.line_s * lines);
|
||||
|
||||
if(0 <= pos.x && pos.x < width && 0 <= pos.y && pos.y < height)
|
||||
{
|
||||
pos.x = static_cast<int>(pos.x / dbasis_.row_s);
|
||||
pos.y = static_cast<int>(pos.y / dbasis_.line_s);
|
||||
|
||||
int n = pos.y * rows + pos.x + 1;
|
||||
if(page_ == page::date)
|
||||
{
|
||||
if(n < 8) return false; //Here is week title bar
|
||||
int dw = nana::date::day_of_week(chmonth_.year, chmonth_.month, 1);
|
||||
n -= (dw ? dw + 7 : 14);
|
||||
}
|
||||
res = n;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void trigger::_m_perf_transform(transform_action tfid, graph_reference graph, graph_reference dirtybuf, graph_reference newbuf, const nana::point& refpos)
|
||||
{
|
||||
const int sleep_time = 15;
|
||||
const int count = 20;
|
||||
double delta = dirtybuf.width() / double(count);
|
||||
double delta_h = dirtybuf.height() / double(count);
|
||||
double fade = 1.0 / count;
|
||||
|
||||
if(tfid == transform_action::to_right)
|
||||
{
|
||||
nana::rectangle dr(0, refpos.y, 0, dirtybuf.height());
|
||||
nana::rectangle nr(refpos.x, refpos.y, 0, newbuf.height());
|
||||
for(int i = 1; i < count; ++i)
|
||||
{
|
||||
int off_x = static_cast<int>(delta * i);
|
||||
dr.x = refpos.x + off_x;
|
||||
dr.width = dirtybuf.width() - off_x;
|
||||
|
||||
graph.bitblt(dr, dirtybuf);
|
||||
|
||||
nr.width = off_x;
|
||||
graph.bitblt(nr, newbuf, nana::point(static_cast<int>(dr.width), 0));
|
||||
|
||||
API::update_window(*widget_);
|
||||
nana::system::sleep(sleep_time);
|
||||
}
|
||||
}
|
||||
else if(tfid == transform_action::to_left)
|
||||
{
|
||||
double delta = dirtybuf.width() / double(count);
|
||||
nana::rectangle dr(refpos.x, refpos.y, 0, dirtybuf.height());
|
||||
nana::rectangle nr(0, refpos.y, 0, newbuf.height());
|
||||
|
||||
for(int i = 1; i < count; ++i)
|
||||
{
|
||||
int off_x = static_cast<int>(delta * i);
|
||||
dr.width = dirtybuf.width() - off_x;
|
||||
|
||||
graph.bitblt(dr, dirtybuf, nana::point(off_x, 0));
|
||||
|
||||
nr.x = refpos.x + static_cast<int>(dr.width);
|
||||
nr.width = off_x;
|
||||
graph.bitblt(nr, newbuf);
|
||||
|
||||
API::update_window(*widget_);
|
||||
nana::system::sleep(sleep_time);
|
||||
}
|
||||
}
|
||||
else if(tfid == transform_action::to_leave)
|
||||
{
|
||||
nana::paint::graphics dzbuf(newbuf.size());
|
||||
nana::paint::graphics nzbuf(newbuf.size());
|
||||
|
||||
nana::rectangle r;
|
||||
for(int i = 1; i < count; ++i)
|
||||
{
|
||||
r.width = static_cast<int>(newbuf.width() - delta * i);
|
||||
r.height = static_cast<int>(newbuf.height() - delta_h * i);
|
||||
r.x = static_cast<int>(newbuf.width() - r.width) / 2;
|
||||
r.y = static_cast<int>(newbuf.height() - r.height) / 2;
|
||||
|
||||
dzbuf.rectangle(0xFFFFFF, true);
|
||||
dirtybuf.stretch(dzbuf, r);
|
||||
|
||||
r.width = static_cast<int>(newbuf.width() + delta * (count - i));
|
||||
r.height = static_cast<int>(newbuf.height() + delta_h * (count - i));
|
||||
r.x = static_cast<int>(newbuf.width() - r.width) / 2;
|
||||
r.y = static_cast<int>(newbuf.height() - r.height) / 2;
|
||||
newbuf.stretch(nzbuf, r);
|
||||
|
||||
nzbuf.blend(nzbuf.size(), dzbuf, nana::point(), fade * (count - i));
|
||||
graph.bitblt(refpos.x, refpos.y, dzbuf);
|
||||
|
||||
API::update_window(*widget_);
|
||||
nana::system::sleep(sleep_time);
|
||||
}
|
||||
}
|
||||
else if(tfid == transform_action::to_enter)
|
||||
{
|
||||
nana::paint::graphics dzbuf(newbuf.size());
|
||||
nana::paint::graphics nzbuf(newbuf.size());
|
||||
|
||||
nana::rectangle r;
|
||||
for(int i = 1; i < count; ++i)
|
||||
{
|
||||
r.width = static_cast<int>(newbuf.width() + delta * i);
|
||||
r.height = static_cast<int>(newbuf.height() + delta_h * i);
|
||||
r.x = static_cast<int>(newbuf.width() - r.width) / 2;
|
||||
r.y = static_cast<int>(newbuf.height() - r.height) / 2;
|
||||
dirtybuf.stretch(dzbuf, r);
|
||||
|
||||
r.width = static_cast<int>(newbuf.width() - delta * (count - i));
|
||||
r.height = static_cast<int>(newbuf.height() - delta_h * (count - i));
|
||||
r.x = static_cast<int>(newbuf.width() - r.width) / 2;
|
||||
r.y = static_cast<int>(newbuf.height() - r.height) / 2;
|
||||
nzbuf.rectangle(0xFFFFFF, true);
|
||||
newbuf.stretch(nzbuf, r);
|
||||
|
||||
nzbuf.blend(nzbuf.size(), dzbuf, nana::point(), fade * (count - i));
|
||||
graph.bitblt(refpos.x, refpos.y, dzbuf);
|
||||
|
||||
API::update_window(*widget_);
|
||||
nana::system::sleep(sleep_time);
|
||||
}
|
||||
}
|
||||
|
||||
graph.bitblt(nana::rectangle(refpos, newbuf.size()), newbuf);
|
||||
}
|
||||
|
||||
void trigger::refresh(graph_reference graph)
|
||||
{
|
||||
_m_draw(graph);
|
||||
}
|
||||
|
||||
void trigger::attached(widget_reference widget, graph_reference)
|
||||
{
|
||||
widget_ = &widget;
|
||||
}
|
||||
|
||||
void trigger::mouse_move(graph_reference graph, const arg_mouse& arg)
|
||||
{
|
||||
where pos = _m_pos_where(graph, arg.pos.x, arg.pos.y);
|
||||
if(pos == pos_ && pos_ != where::textarea) return;
|
||||
pos_ = pos;
|
||||
_m_draw(graph);
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void trigger::mouse_leave(graph_reference graph, const arg_mouse&)
|
||||
{
|
||||
if(where::none == pos_) return;
|
||||
pos_ = where::none;
|
||||
_m_draw(graph);
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
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);
|
||||
transform_action tfid = transform_action::none;
|
||||
|
||||
if(pos == where::topbar)
|
||||
{
|
||||
switch(page_)
|
||||
{
|
||||
case page::date:
|
||||
page_ = page::month;
|
||||
tfid = transform_action::to_leave;
|
||||
break;
|
||||
default:
|
||||
redraw = false;
|
||||
}
|
||||
}
|
||||
else if(pos == where::textarea)
|
||||
{
|
||||
int ret = 0;
|
||||
switch(page_)
|
||||
{
|
||||
case page::date:
|
||||
if(_m_get_trace(arg.pos, ret))
|
||||
{
|
||||
if(ret < 1)
|
||||
{
|
||||
if(--chmonth_.month == 0)
|
||||
{
|
||||
--chmonth_.year;
|
||||
chmonth_.month = 12;
|
||||
}
|
||||
tfid = transform_action::to_right;
|
||||
}
|
||||
else
|
||||
{
|
||||
int days = nana::date::month_days(chmonth_.year, chmonth_.month);
|
||||
if(ret > days)
|
||||
{
|
||||
if(++chmonth_.month == 13)
|
||||
{
|
||||
++chmonth_.year;
|
||||
chmonth_.month = 1;
|
||||
}
|
||||
tfid = transform_action::to_left;
|
||||
}
|
||||
else //Selecting a day in this month
|
||||
{
|
||||
chdate_.year = chmonth_.year;
|
||||
chdate_.month = chmonth_.month;
|
||||
chdate_.day = ret;
|
||||
chose_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case page::month:
|
||||
if(_m_get_trace(arg.pos, ret))
|
||||
chmonth_.month = ret;
|
||||
page_ = page::date;
|
||||
tfid = transform_action::to_enter;
|
||||
break;
|
||||
default:
|
||||
redraw = false;
|
||||
}
|
||||
}
|
||||
else if(pos == where::left_button || pos == where::right_button)
|
||||
{
|
||||
int end_m;
|
||||
int beg_m;
|
||||
int step;
|
||||
if(pos == where::left_button)
|
||||
{
|
||||
end_m = 1;
|
||||
beg_m = 12;
|
||||
step = -1;
|
||||
tfid = transform_action::to_right;
|
||||
}
|
||||
else
|
||||
{
|
||||
end_m = 12;
|
||||
beg_m = 1;
|
||||
step = 1;
|
||||
tfid = transform_action::to_left;
|
||||
}
|
||||
switch(page_)
|
||||
{
|
||||
case page::date:
|
||||
if(chmonth_.month == end_m)
|
||||
{
|
||||
chmonth_.month = beg_m;
|
||||
chmonth_.year += step;
|
||||
}
|
||||
else
|
||||
chmonth_.month += step;
|
||||
break;
|
||||
case page::month:
|
||||
chmonth_.year += step;
|
||||
break;
|
||||
default:
|
||||
redraw = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(redraw)
|
||||
{
|
||||
if(tfid != transform_action::none)
|
||||
{
|
||||
nana::point refpos(1, static_cast<int>(topbar_height) + 1);
|
||||
nana::rectangle r(0, 0, graph.width() - 2, graph.height() - 2 - topbar_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);
|
||||
gbuf.bitblt(r, graph, refpos);
|
||||
|
||||
_m_perf_transform(tfid, graph, dirtybuf, gbuf, refpos);
|
||||
}
|
||||
else
|
||||
_m_draw(graph);
|
||||
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
//end class trigger
|
||||
}//end namespace date_chooser
|
||||
}//end namespace drawerbase
|
||||
|
||||
//class date_chooser
|
||||
date_chooser::date_chooser()
|
||||
{}
|
||||
|
||||
date_chooser::date_chooser(window wd, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
}
|
||||
|
||||
date_chooser::date_chooser(window wd, const nana::string& text, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
caption(text);
|
||||
}
|
||||
|
||||
date_chooser::date_chooser(window wd, const nana::char_t* text, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
caption(text);
|
||||
}
|
||||
|
||||
date_chooser::date_chooser(window wd, const rectangle& r, bool visible)
|
||||
{
|
||||
create(wd, r, visible);
|
||||
}
|
||||
|
||||
bool date_chooser::chose() const
|
||||
{
|
||||
return get_drawer_trigger().chose();
|
||||
}
|
||||
|
||||
nana::date date_chooser::read() const
|
||||
{
|
||||
return get_drawer_trigger().read();
|
||||
}
|
||||
|
||||
void date_chooser::weekstr(unsigned index, const nana::string& str)
|
||||
{
|
||||
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
|
||||
520
source/gui/widgets/float_listbox.cpp
Normal file
520
source/gui/widgets/float_listbox.cpp
Normal file
@@ -0,0 +1,520 @@
|
||||
/*
|
||||
* A float_listbox Implementation
|
||||
* 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/widgets/float_listbox.cpp
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/float_listbox.hpp>
|
||||
#include <nana/gui/widgets/scroll.hpp>
|
||||
|
||||
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
|
||||
{
|
||||
bool image_enabled_;
|
||||
unsigned image_pixels_;
|
||||
|
||||
void image(bool enb, unsigned px)
|
||||
{
|
||||
image_enabled_ = enb;
|
||||
image_pixels_ = px;
|
||||
}
|
||||
|
||||
void render(widget_reference, graph_reference graph, const nana::rectangle& r, const item_interface* item, state_t state)
|
||||
{
|
||||
if(state == StateHighlighted)
|
||||
{
|
||||
graph.rectangle(r, 0xAFC7E3, false);
|
||||
|
||||
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_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);
|
||||
|
||||
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);
|
||||
}
|
||||
else
|
||||
graph.rectangle(r, 0xFFFFFF, true);
|
||||
|
||||
int x = r.x + 2;
|
||||
if(image_enabled_)
|
||||
{
|
||||
unsigned vpix = (r.height - 4);
|
||||
if(item->image())
|
||||
{
|
||||
nana::size imgsz = item->image().size();
|
||||
if(imgsz.width > image_pixels_)
|
||||
{
|
||||
unsigned new_h = image_pixels_ * imgsz.height / imgsz.width;
|
||||
if(new_h > vpix)
|
||||
{
|
||||
imgsz.width = vpix * imgsz.width / imgsz.height;
|
||||
imgsz.height = vpix;
|
||||
}
|
||||
else
|
||||
{
|
||||
imgsz.width = image_pixels_;
|
||||
imgsz.height = new_h;
|
||||
}
|
||||
}
|
||||
else if(imgsz.height > vpix)
|
||||
{
|
||||
unsigned new_w = vpix * imgsz.width / imgsz.height;
|
||||
if(new_w > image_pixels_)
|
||||
{
|
||||
imgsz.height = image_pixels_ * imgsz.height / imgsz.width;
|
||||
imgsz.width = image_pixels_;
|
||||
}
|
||||
else
|
||||
{
|
||||
imgsz.height = vpix;
|
||||
imgsz.width = new_w;
|
||||
}
|
||||
}
|
||||
|
||||
nana::point to_pos(x, r.y + 2);
|
||||
to_pos.x += (image_pixels_ - imgsz.width) / 2;
|
||||
to_pos.y += (vpix - imgsz.height) / 2;
|
||||
item->image().stretch(item->image().size(), graph, nana::rectangle(to_pos, imgsz));
|
||||
}
|
||||
x += (image_pixels_ + 2);
|
||||
}
|
||||
graph.string(x, r.y + 2, 0x0, item->text());
|
||||
}
|
||||
|
||||
unsigned item_pixels(graph_reference graph) const
|
||||
{
|
||||
return graph.text_extent_size(STR("jHWn/?\\{[(0569")).height + 4;
|
||||
}
|
||||
};//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
|
||||
{
|
||||
public:
|
||||
typedef widget& widget_reference;
|
||||
typedef nana::paint::graphics& graph_reference;
|
||||
|
||||
drawer_impl()
|
||||
: widget_(nullptr), graph_(nullptr), image_pixels_(16),
|
||||
ignore_first_mouseup_(true), module_(nullptr)
|
||||
{}
|
||||
|
||||
void clear_state()
|
||||
{
|
||||
state_.offset_y = 0;
|
||||
state_.index = npos;
|
||||
}
|
||||
|
||||
void ignore_first_mouse_up(bool value)
|
||||
{
|
||||
ignore_first_mouseup_ = value;
|
||||
}
|
||||
|
||||
bool ignore_emitting_mouseup()
|
||||
{
|
||||
if(ignore_first_mouseup_)
|
||||
{
|
||||
ignore_first_mouseup_ = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void renderer(item_renderer* ir)
|
||||
{
|
||||
state_.renderer = (ir ? ir : state_.orig_renderer);
|
||||
}
|
||||
|
||||
void scroll_items(bool upwards)
|
||||
{
|
||||
if(scrollbar_.empty()) return;
|
||||
|
||||
bool update = false;
|
||||
if(upwards)
|
||||
{
|
||||
if(state_.offset_y)
|
||||
{
|
||||
--(state_.offset_y);
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if((state_.offset_y + module_->max_items) < module_->items.size())
|
||||
{
|
||||
++(state_.offset_y);
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(update)
|
||||
{
|
||||
draw();
|
||||
scrollbar_.value(state_.offset_y);
|
||||
API::update_window(*widget_);
|
||||
}
|
||||
}
|
||||
|
||||
void move_items(bool upwards, bool recycle)
|
||||
{
|
||||
if(module_ && module_->items.size())
|
||||
{
|
||||
std::size_t init_index = state_.index;
|
||||
if(state_.index != npos)
|
||||
{
|
||||
unsigned last_offset_y = 0;
|
||||
if(module_->items.size() > module_->max_items)
|
||||
last_offset_y = static_cast<unsigned>(module_->items.size() - module_->max_items);
|
||||
|
||||
if(upwards)
|
||||
{
|
||||
if(state_.index)
|
||||
--(state_.index);
|
||||
else if(recycle)
|
||||
{
|
||||
state_.index = static_cast<unsigned>(module_->items.size() - 1);
|
||||
state_.offset_y = last_offset_y;
|
||||
}
|
||||
|
||||
if(state_.index < state_.offset_y)
|
||||
state_.offset_y = state_.index;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(state_.index < module_->items.size() - 1)
|
||||
++(state_.index);
|
||||
else if(recycle)
|
||||
{
|
||||
state_.index = 0;
|
||||
state_.offset_y = 0;
|
||||
}
|
||||
|
||||
if(state_.index >= state_.offset_y + module_->max_items)
|
||||
state_.offset_y = static_cast<unsigned>(state_.index - module_->max_items + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
state_.index = 0;
|
||||
|
||||
if(init_index != state_.index)
|
||||
{
|
||||
draw();
|
||||
scrollbar_.value(state_.offset_y);
|
||||
API::update_window(*widget_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t index() const
|
||||
{
|
||||
return state_.index;
|
||||
}
|
||||
|
||||
widget* widget_ptr()
|
||||
{
|
||||
return widget_;
|
||||
}
|
||||
|
||||
void attach(widget* wd, nana::paint::graphics* graph)
|
||||
{
|
||||
if(wd)
|
||||
{
|
||||
widget_ = wd;
|
||||
wd->events().mouse_wheel.connect([this](const arg_wheel& arg){
|
||||
scroll_items(arg.upwards);
|
||||
});
|
||||
}
|
||||
if(graph) graph_ = graph;
|
||||
}
|
||||
|
||||
void detach()
|
||||
{
|
||||
graph_ = nullptr;
|
||||
}
|
||||
|
||||
void resize()
|
||||
{
|
||||
if(module_)
|
||||
{
|
||||
std::size_t items = (module_->max_items <= module_->items.size() ? module_->max_items : module_->items.size());
|
||||
std::size_t h = items * state_.renderer->item_pixels(*graph_);
|
||||
widget_->size(size{ widget_->size().width, static_cast<unsigned>(h + 4) });
|
||||
}
|
||||
}
|
||||
|
||||
void set_module(const module_def& md, unsigned pixels)
|
||||
{
|
||||
module_ = &md;
|
||||
md.have_selected = false;
|
||||
if(md.index >= md.items.size())
|
||||
md.index = npos;
|
||||
|
||||
image_pixels_ = pixels;
|
||||
}
|
||||
|
||||
void set_result()
|
||||
{
|
||||
if(module_)
|
||||
{
|
||||
module_->index = state_.index;
|
||||
module_->have_selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool right_area(graph_reference graph, int x, int y) const
|
||||
{
|
||||
return ((1 < x && 1 < y) &&
|
||||
x < static_cast<int>(graph.width()) - 2 &&
|
||||
y < static_cast<int>(graph.height()) - 2);
|
||||
}
|
||||
|
||||
bool set_mouse(graph_reference graph, int x, int y)
|
||||
{
|
||||
if(this->right_area(graph, x, y))
|
||||
{
|
||||
const unsigned n = (y - 2) / state_.renderer->item_pixels(graph) + static_cast<unsigned>(state_.offset_y);
|
||||
if(n != state_.index)
|
||||
{
|
||||
state_.index = n;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
if(module_)
|
||||
{
|
||||
bool pages = (module_->max_items < module_->items.size());
|
||||
const unsigned outter_w = (pages ? 20 : 4);
|
||||
|
||||
if(graph_->width() > outter_w && graph_->height() > 4 )
|
||||
{
|
||||
//Draw items
|
||||
std::size_t items = (pages ? module_->max_items : module_->items.size());
|
||||
items += state_.offset_y;
|
||||
|
||||
const unsigned item_pixels = state_.renderer->item_pixels(*graph_);
|
||||
nana::rectangle item_r(2, 2, graph_->width() - outter_w, item_pixels);
|
||||
|
||||
state_.renderer->image(_m_image_enabled(), image_pixels_);
|
||||
for(std::size_t i = state_.offset_y; i < items; ++i)
|
||||
{
|
||||
item_renderer::state_t state = item_renderer::StateNone;
|
||||
if(i == state_.index) state = item_renderer::StateHighlighted;
|
||||
|
||||
state_.renderer->render(*widget_, *graph_, item_r, module_->items[i].get(), state);
|
||||
item_r.y += item_pixels;
|
||||
}
|
||||
}
|
||||
_m_open_scrollbar(*widget_, pages);
|
||||
}
|
||||
else
|
||||
graph_->string(4, 4, 0x808080, STR("Empty Listbox, No Module!"));
|
||||
|
||||
//Draw border
|
||||
graph_->rectangle(0x0, false);
|
||||
graph_->rectangle(nana::rectangle(graph_->size()).pare_off(1), 0xFFFFFF, false);
|
||||
}
|
||||
private:
|
||||
bool _m_image_enabled() const
|
||||
{
|
||||
for(auto & i : module_->items)
|
||||
{
|
||||
if(false == i->image().empty())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void _m_open_scrollbar(widget_reference wd, bool v)
|
||||
{
|
||||
if(v)
|
||||
{
|
||||
if(scrollbar_.empty() && module_)
|
||||
{
|
||||
scrollbar_.create(wd, rectangle(static_cast<int>(wd.size().width - 18), 2, 16, wd.size().height - 4));
|
||||
scrollbar_.amount(module_->items.size());
|
||||
scrollbar_.range(module_->max_items);
|
||||
scrollbar_.value(state_.offset_y);
|
||||
|
||||
auto & events = scrollbar_.events();
|
||||
events.mouse_wheel.connect([this](const arg_wheel& arg)
|
||||
{
|
||||
scroll_items(arg.upwards);
|
||||
});
|
||||
|
||||
auto fn = [this](const arg_mouse& arg)
|
||||
{
|
||||
if (arg.left_button && (scrollbar_.value() != state_.offset_y))
|
||||
{
|
||||
state_.offset_y = static_cast<unsigned>(scrollbar_.value());
|
||||
draw();
|
||||
API::update_window(*widget_);
|
||||
}
|
||||
};
|
||||
events.mouse_move.connect(fn);
|
||||
events.mouse_up.connect(fn);
|
||||
}
|
||||
}
|
||||
else
|
||||
scrollbar_.close();
|
||||
}
|
||||
private:
|
||||
widget * widget_;
|
||||
nana::paint::graphics * graph_;
|
||||
unsigned image_pixels_; //Define the width pixels of the image area
|
||||
|
||||
bool ignore_first_mouseup_;
|
||||
struct state_type
|
||||
{
|
||||
std::size_t offset_y;
|
||||
std::size_t index; //The index of the selected item.
|
||||
|
||||
item_renderer * const orig_renderer;
|
||||
item_renderer * renderer;
|
||||
|
||||
state_type(): offset_y(0), index(npos), orig_renderer(new def_item_renderer), renderer(orig_renderer){}
|
||||
~state_type()
|
||||
{
|
||||
delete orig_renderer;
|
||||
}
|
||||
}state_;
|
||||
nana::scroll<true> scrollbar_;
|
||||
|
||||
const module_def* module_;
|
||||
};
|
||||
|
||||
//class drawer_impl;
|
||||
|
||||
|
||||
//class trigger
|
||||
trigger::trigger()
|
||||
:drawer_(new drawer_impl)
|
||||
{}
|
||||
|
||||
trigger::~trigger()
|
||||
{
|
||||
delete drawer_;
|
||||
}
|
||||
|
||||
drawer_impl& trigger::get_drawer_impl()
|
||||
{
|
||||
return *drawer_;
|
||||
}
|
||||
|
||||
const drawer_impl& trigger::get_drawer_impl() const
|
||||
{
|
||||
return *drawer_;
|
||||
}
|
||||
|
||||
void trigger::attached(widget_reference widget, graph_reference graph)
|
||||
{
|
||||
drawer_->attach(&widget, &graph);
|
||||
}
|
||||
|
||||
void trigger::detached()
|
||||
{
|
||||
drawer_->detach();
|
||||
}
|
||||
|
||||
void trigger::refresh(graph_reference)
|
||||
{
|
||||
drawer_->draw();
|
||||
}
|
||||
|
||||
void trigger::mouse_move(graph_reference graph, const arg_mouse& arg)
|
||||
{
|
||||
if(drawer_->set_mouse(graph, arg.pos.x, arg.pos.y))
|
||||
{
|
||||
drawer_->draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void trigger::mouse_up(graph_reference graph, const arg_mouse& arg)
|
||||
{
|
||||
if(drawer_->right_area(graph, arg.pos.x, arg.pos.y))
|
||||
{
|
||||
drawer_->set_result();
|
||||
drawer_->widget_ptr()->close();
|
||||
}
|
||||
else if(false == drawer_->ignore_emitting_mouseup())
|
||||
drawer_->widget_ptr()->close();
|
||||
}
|
||||
//end class trigger
|
||||
}
|
||||
}//end namespace drawerbase
|
||||
|
||||
//class float_listbox
|
||||
float_listbox::float_listbox(window wd, const rectangle & r, bool is_ignore_first_mouse_up)
|
||||
:base_type(wd, false, r, appear::bald<appear::floating, appear::no_activate>())
|
||||
{
|
||||
API::capture_window(handle(), true);
|
||||
API::capture_ignore_children(false);
|
||||
API::take_active(handle(), false, parent());
|
||||
auto & impl = get_drawer_trigger().get_drawer_impl();
|
||||
impl.clear_state();
|
||||
impl.ignore_first_mouse_up(is_ignore_first_mouse_up);
|
||||
}
|
||||
|
||||
void float_listbox::set_module(const float_listbox::module_type& md, unsigned pixels)
|
||||
{
|
||||
auto & impl = get_drawer_trigger().get_drawer_impl();
|
||||
impl.set_module(md, pixels);
|
||||
impl.resize();
|
||||
show();
|
||||
}
|
||||
|
||||
void float_listbox::scroll_items(bool upwards)
|
||||
{
|
||||
get_drawer_trigger().get_drawer_impl().scroll_items(upwards);
|
||||
}
|
||||
|
||||
void float_listbox::move_items(bool upwards, bool circle)
|
||||
{
|
||||
get_drawer_trigger().get_drawer_impl().move_items(upwards, circle);
|
||||
}
|
||||
|
||||
void float_listbox::renderer(item_renderer* ir)
|
||||
{
|
||||
auto & impl = get_drawer_trigger().get_drawer_impl();
|
||||
impl.renderer(ir);
|
||||
impl.resize();
|
||||
}
|
||||
|
||||
std::size_t float_listbox::index() const
|
||||
{
|
||||
return get_drawer_trigger().get_drawer_impl().index();
|
||||
}
|
||||
//end class float_listbox
|
||||
}
|
||||
81
source/gui/widgets/form.cpp
Normal file
81
source/gui/widgets/form.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* A Form Implementation
|
||||
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: nana/gui/widgets/form.cpp
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/form.hpp>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
namespace drawerbase
|
||||
{
|
||||
namespace form
|
||||
{
|
||||
//class trigger
|
||||
trigger::trigger():wd_(nullptr){}
|
||||
|
||||
void trigger::attached(widget_reference widget, graph_reference graph)
|
||||
{
|
||||
wd_ = &widget;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}//end namespace form
|
||||
}//end namespace drawerbase
|
||||
|
||||
//class form
|
||||
typedef widget_object<category::root_tag, drawerbase::form::trigger, ::nana::detail::events_root_extension> form_base_t;
|
||||
|
||||
form::form(const form& fm, const ::nana::size& sz, const appearance& apr)
|
||||
: form_base_t(fm.handle(), false, API::make_center(fm.handle(), sz.width, sz.height), apr)
|
||||
{
|
||||
}
|
||||
|
||||
form::form(const rectangle& r, const appearance& apr)
|
||||
: form_base_t(nullptr, false, r, apr)
|
||||
{}
|
||||
|
||||
form::form(window owner, const ::nana::size& sz, const appearance& apr)
|
||||
: form_base_t(owner, false, API::make_center(owner, sz.width, sz.height), apr)
|
||||
{}
|
||||
|
||||
form::form(window owner, const rectangle& r, const appearance& apr)
|
||||
: form_base_t(owner, false, r, apr)
|
||||
{}
|
||||
//end class form
|
||||
|
||||
//class nested_form
|
||||
nested_form::nested_form(const form& fm, const rectangle& r, const appearance& apr)
|
||||
: form_base_t(fm.handle(), true, r, apr)
|
||||
{
|
||||
}
|
||||
|
||||
nested_form::nested_form(const nested_form& fm, const rectangle& r, const appearance& apr)
|
||||
: form_base_t(fm.handle(), true, r, apr)
|
||||
{
|
||||
}
|
||||
|
||||
nested_form::nested_form(window owner, const appearance& apr)
|
||||
: form_base_t(owner, true, rectangle(), apr)
|
||||
{}
|
||||
|
||||
nested_form::nested_form(window owner, const rectangle& r, const appearance& apr)
|
||||
: form_base_t(owner, true, r, apr)
|
||||
{}
|
||||
//end nested_form
|
||||
}//end namespace nana
|
||||
47
source/gui/widgets/frame.cpp
Normal file
47
source/gui/widgets/frame.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* A Frame Implementation
|
||||
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: nana/gui/widgets/frame.cpp
|
||||
*
|
||||
* A frame provides a way to contain the platform window in a stdex GUI Window
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/frame.hpp>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
//class frame:: public widget_object<category::frame_tag>
|
||||
frame::frame(){}
|
||||
|
||||
frame::frame(window wd, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
}
|
||||
|
||||
frame::frame(window wd, const nana::rectangle& r, bool visible)
|
||||
{
|
||||
create(wd, r, visible);
|
||||
}
|
||||
|
||||
bool frame::insert(native_window_type wd)
|
||||
{
|
||||
return API::insert_frame(handle(), wd);
|
||||
}
|
||||
|
||||
native_window_type frame::element(unsigned index)
|
||||
{
|
||||
return API::frame_element(handle(), index);
|
||||
}
|
||||
|
||||
native_window_type frame::container() const
|
||||
{
|
||||
return API::frame_container(handle());
|
||||
}
|
||||
//end class frame
|
||||
}//end namespace nana
|
||||
|
||||
872
source/gui/widgets/label.cpp
Normal file
872
source/gui/widgets/label.cpp
Normal file
@@ -0,0 +1,872 @@
|
||||
/*
|
||||
* A Label Control Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: source/gui/widgets/label.cpp
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/label.hpp>
|
||||
#include <nana/unicode_bidi.hpp>
|
||||
#include <nana/gui/widgets/skeletons/text_token_stream.hpp>
|
||||
#include <nana/system/platform.hpp>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
namespace drawerbase
|
||||
{
|
||||
namespace label
|
||||
{
|
||||
class renderer
|
||||
{
|
||||
typedef widgets::skeletons::dstream::linecontainer::iterator iterator;
|
||||
|
||||
struct pixel_tag
|
||||
{
|
||||
int x_base; //The x position where this line starts.
|
||||
std::size_t pixels;
|
||||
std::size_t baseline; //The baseline for drawing text.
|
||||
std::vector<iterator> values; //line values
|
||||
};
|
||||
|
||||
//this is a helper variable, it just keeps the status while drawing.
|
||||
struct render_status
|
||||
{
|
||||
unsigned allowed_width;
|
||||
align text_align;
|
||||
align_v text_align_v;
|
||||
|
||||
nana::point pos;
|
||||
std::vector<pixel_tag> pixels;
|
||||
std::size_t index;
|
||||
};
|
||||
|
||||
struct traceable
|
||||
{
|
||||
nana::rectangle r;
|
||||
nana::string target;
|
||||
nana::string url;
|
||||
};
|
||||
|
||||
public:
|
||||
typedef nana::paint::graphics& graph_reference;
|
||||
typedef widgets::skeletons::dstream dstream;
|
||||
typedef widgets::skeletons::fblock fblock;
|
||||
typedef widgets::skeletons::data data;
|
||||
|
||||
void parse(const nana::string& s)
|
||||
{
|
||||
dstream_.parse(s, format_enabled_);
|
||||
}
|
||||
|
||||
bool format(bool fm)
|
||||
{
|
||||
if (fm == format_enabled_)
|
||||
return false;
|
||||
|
||||
format_enabled_ = fm;
|
||||
return true;
|
||||
}
|
||||
|
||||
void render(graph_reference graph, nana::color_t fgcolor, align th, align_v tv)
|
||||
{
|
||||
traceable_.clear();
|
||||
|
||||
nana::paint::font 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, fgcolor);
|
||||
|
||||
_m_measure(graph);
|
||||
|
||||
render_status rs;
|
||||
|
||||
rs.allowed_width = graph.size().width;
|
||||
rs.text_align = th;
|
||||
rs.text_align_v = tv;
|
||||
|
||||
std::deque<std::vector<pixel_tag> > pixel_lines;
|
||||
|
||||
std::size_t extent_v_pixels = 0; //the pixels, in height, that text will be painted.
|
||||
|
||||
for (auto & line : dstream_)
|
||||
{
|
||||
_m_line_pixels(line, def_line_pixels, rs);
|
||||
|
||||
for (auto & m : rs.pixels)
|
||||
extent_v_pixels += m.pixels;
|
||||
|
||||
pixel_lines.emplace_back(std::move(rs.pixels));
|
||||
|
||||
if(extent_v_pixels >= graph.height())
|
||||
break;
|
||||
}
|
||||
|
||||
if((tv != align_v::top) && extent_v_pixels < graph.height())
|
||||
{
|
||||
if(align_v::center == tv)
|
||||
rs.pos.y = static_cast<int>(graph.height() - extent_v_pixels) >> 1;
|
||||
else if(align_v::bottom == tv)
|
||||
rs.pos.y = static_cast<int>(graph.height() - extent_v_pixels);
|
||||
}
|
||||
else
|
||||
rs.pos.y = 0;
|
||||
|
||||
auto pixels_iterator = pixel_lines.begin();
|
||||
|
||||
for (auto & line : dstream_)
|
||||
{
|
||||
if (rs.pos.y >= static_cast<int>(graph.height()))
|
||||
break;
|
||||
|
||||
rs.index = 0;
|
||||
rs.pixels.clear();
|
||||
|
||||
rs.pixels.swap(*pixels_iterator++);
|
||||
|
||||
rs.pos.x = rs.pixels.front().x_base;
|
||||
|
||||
//Stop drawing when it goes out of range.
|
||||
if(false == _m_each_line(graph, line, rs))
|
||||
break;
|
||||
|
||||
rs.pos.y += static_cast<int>(rs.pixels.back().pixels);
|
||||
}
|
||||
|
||||
graph.typeface(ft);
|
||||
}
|
||||
|
||||
bool find(int x, int y, nana::string& target, nana::string& url) const
|
||||
{
|
||||
for (auto & t : traceable_)
|
||||
{
|
||||
if(t.r.is_hit(x, y))
|
||||
{
|
||||
target = t.target;
|
||||
url = t.url;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nana::size measure(graph_reference graph, unsigned limited, align th, align_v tv)
|
||||
{
|
||||
nana::size retsize;
|
||||
|
||||
nana::paint::font 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_measure(graph);
|
||||
|
||||
render_status rs;
|
||||
|
||||
rs.allowed_width = limited;
|
||||
rs.text_align = th;
|
||||
rs.text_align_v = tv;
|
||||
|
||||
for(auto i = dstream_.begin(), end = dstream_.end(); i != end; ++i)
|
||||
{
|
||||
rs.pixels.clear();
|
||||
unsigned w = _m_line_pixels(*i, def_line_pixels, rs);
|
||||
|
||||
if(limited && (w > limited))
|
||||
w = limited;
|
||||
|
||||
if(retsize.width < w)
|
||||
retsize.width = w;
|
||||
|
||||
for (auto & px : rs.pixels)
|
||||
retsize.height += static_cast<unsigned>(px.pixels);
|
||||
}
|
||||
|
||||
return retsize;
|
||||
}
|
||||
private:
|
||||
//Manage the fblock for a specified rectangle if it is a traceable fblock.
|
||||
void _m_inser_if_traceable(int x, int y, const nana::size& sz, widgets::skeletons::fblock* fbp)
|
||||
{
|
||||
if(fbp->target.size() || fbp->url.size())
|
||||
{
|
||||
traceable tr;
|
||||
tr.r.x = x;
|
||||
tr.r.y = y;
|
||||
tr.r.width = sz.width;
|
||||
tr.r.height = sz.height;
|
||||
tr.target = fbp->target;
|
||||
tr.url = fbp->url;
|
||||
|
||||
traceable_.push_back(tr);
|
||||
}
|
||||
}
|
||||
|
||||
void _m_set_default(const nana::paint::font& ft, nana::color_t fgcolor)
|
||||
{
|
||||
def_.font_name = ft.name();
|
||||
def_.font_size = ft.size();
|
||||
def_.font_bold = ft.bold();
|
||||
def_.fgcolor = fgcolor;
|
||||
}
|
||||
|
||||
nana::color_t _m_fgcolor(nana::widgets::skeletons::fblock* fp)
|
||||
{
|
||||
while(fp->fgcolor == 0xFFFFFFFF)
|
||||
{
|
||||
fp = fp->parent;
|
||||
if(nullptr == fp)
|
||||
return def_.fgcolor;
|
||||
}
|
||||
return fp->fgcolor;
|
||||
}
|
||||
|
||||
std::size_t _m_font_size(nana::widgets::skeletons::fblock* fp)
|
||||
{
|
||||
while(fp->font_size == 0xFFFFFFFF)
|
||||
{
|
||||
fp = fp->parent;
|
||||
if(nullptr == fp)
|
||||
return def_.font_size;
|
||||
}
|
||||
return fp->font_size;
|
||||
}
|
||||
|
||||
bool _m_bold(nana::widgets::skeletons::fblock* fp)
|
||||
{
|
||||
while(fp->bold_empty)
|
||||
{
|
||||
fp = fp->parent;
|
||||
if(nullptr == fp)
|
||||
return def_.font_bold;
|
||||
}
|
||||
return fp->bold;
|
||||
}
|
||||
|
||||
const nana::string& _m_fontname(nana::widgets::skeletons::fblock* fp)
|
||||
{
|
||||
while(fp->font.empty())
|
||||
{
|
||||
fp = fp->parent;
|
||||
if(nullptr == fp)
|
||||
return def_.font_name;
|
||||
}
|
||||
return fp->font;
|
||||
}
|
||||
|
||||
void _m_change_font(graph_reference graph, nana::widgets::skeletons::fblock* fp)
|
||||
{
|
||||
if(fp != fblock_)
|
||||
{
|
||||
const nana::string& name = _m_fontname(fp);
|
||||
auto fontsize = static_cast<unsigned>(_m_font_size(fp));
|
||||
bool bold = _m_bold(fp);
|
||||
|
||||
if((fontsize != font_.size()) || bold != font_.bold() || name != font_.name())
|
||||
{
|
||||
font_.make(name.data(), fontsize, bold);
|
||||
graph.typeface(font_);
|
||||
}
|
||||
fblock_ = fp;
|
||||
}
|
||||
}
|
||||
|
||||
void _m_measure(graph_reference graph)
|
||||
{
|
||||
nana::paint::font ft = font_;
|
||||
for (auto & line : dstream_)
|
||||
{
|
||||
for (auto & value : line)
|
||||
{
|
||||
_m_change_font(graph, value.fblock_ptr);
|
||||
value.data_ptr->measure(graph);
|
||||
}
|
||||
}
|
||||
if(font_ != ft)
|
||||
{
|
||||
font_ = ft;
|
||||
graph.typeface(ft);
|
||||
fblock_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void _m_align_x_base(const render_status& rs, pixel_tag & px, unsigned w)
|
||||
{
|
||||
switch(rs.text_align)
|
||||
{
|
||||
case align::left:
|
||||
px.x_base = 0;
|
||||
break;
|
||||
case align::center:
|
||||
px.x_base = (static_cast<int>(rs.allowed_width - w) >> 1);
|
||||
break;
|
||||
case align::right:
|
||||
px.x_base = static_cast<int>(rs.allowed_width - w);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned _m_line_pixels(dstream::linecontainer& line, unsigned def_line_pixels, render_status & rs)
|
||||
{
|
||||
if (line.empty())
|
||||
{
|
||||
pixel_tag px;
|
||||
px.baseline = 0;
|
||||
px.pixels = def_line_pixels;
|
||||
px.x_base = 0;
|
||||
|
||||
rs.pixels.push_back(px);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned total_w = 0;
|
||||
unsigned w = 0;
|
||||
unsigned max_ascent = 0;
|
||||
unsigned max_descent = 0;
|
||||
unsigned max_px = 0;
|
||||
|
||||
//Bidi reorder is requried here
|
||||
|
||||
std::vector<iterator> line_values;
|
||||
|
||||
for(auto i = line.begin(), end = line.end(); i != end; ++i)
|
||||
{
|
||||
data * data_ptr = i->data_ptr;
|
||||
nana::size sz = data_ptr->size();
|
||||
total_w += sz.width;
|
||||
|
||||
unsigned as = 0; //ascent
|
||||
unsigned ds = 0; //descent
|
||||
|
||||
if(fblock::aligns::baseline == i->fblock_ptr->text_align)
|
||||
{
|
||||
as = static_cast<unsigned>(data_ptr->ascent());
|
||||
ds = static_cast<unsigned>(sz.height - as);
|
||||
|
||||
if(max_descent < ds)
|
||||
max_descent = ds;
|
||||
|
||||
if((false == data_ptr->is_text()) && (sz.height < max_ascent + max_descent))
|
||||
sz.height = max_ascent + max_descent;
|
||||
}
|
||||
|
||||
if(w + sz.width <= rs.allowed_width)
|
||||
{
|
||||
w += sz.width;
|
||||
|
||||
if(max_ascent < as) max_ascent = as;
|
||||
if(max_descent < ds) max_descent = ds;
|
||||
if(max_px < sz.height) max_px = sz.height;
|
||||
line_values.push_back(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(w)
|
||||
{
|
||||
pixel_tag px;
|
||||
|
||||
_m_align_x_base(rs, px, w);
|
||||
|
||||
if(max_ascent + max_descent > max_px)
|
||||
max_px = max_descent + max_ascent;
|
||||
else
|
||||
max_ascent = max_px - max_descent;
|
||||
|
||||
px.pixels = max_px;
|
||||
px.baseline = max_ascent;
|
||||
px.values.swap(line_values);
|
||||
|
||||
rs.pixels.push_back(px);
|
||||
|
||||
w = sz.width;
|
||||
max_px = sz.height;
|
||||
max_ascent = as;
|
||||
max_descent = ds;
|
||||
line_values.push_back(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel_tag px;
|
||||
|
||||
_m_align_x_base(rs, px, sz.width);
|
||||
px.pixels = sz.height;
|
||||
px.baseline = as;
|
||||
|
||||
px.values.push_back(i);
|
||||
|
||||
rs.pixels.push_back(px);
|
||||
max_px = 0;
|
||||
max_ascent = max_descent = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (max_px)
|
||||
{
|
||||
pixel_tag px;
|
||||
|
||||
_m_align_x_base(rs, px, w);
|
||||
|
||||
if (max_ascent + max_descent > max_px)
|
||||
max_px = max_descent + max_ascent;
|
||||
else
|
||||
max_ascent = max_px - max_descent;
|
||||
|
||||
px.pixels = max_px;
|
||||
px.baseline = max_ascent;
|
||||
px.values.swap(line_values);
|
||||
rs.pixels.push_back(px);
|
||||
}
|
||||
return total_w;
|
||||
}
|
||||
|
||||
bool _m_each_line(graph_reference graph, dstream::linecontainer& line, render_status& rs)
|
||||
{
|
||||
nana::string text;
|
||||
iterator block_start;
|
||||
|
||||
const int lastpos = static_cast<int>(graph.height()) - 1;
|
||||
|
||||
for(auto i = rs.pixels.begin(), end = rs.pixels.end(); i != end; ++i)
|
||||
{
|
||||
for (auto & render_iterator : i->values)
|
||||
{
|
||||
auto & value = *render_iterator;
|
||||
if(false == value.data_ptr->is_text())
|
||||
{
|
||||
if(text.size())
|
||||
{
|
||||
_m_draw_block(graph, text, block_start, rs);
|
||||
if(lastpos <= rs.pos.y)
|
||||
return false;
|
||||
text.clear();
|
||||
}
|
||||
nana::size sz = value.data_ptr->size();
|
||||
|
||||
pixel_tag px = rs.pixels[rs.index];
|
||||
if ((rs.allowed_width < rs.pos.x + sz.width) && (rs.pos.x != px.x_base))
|
||||
{
|
||||
//Change a line.
|
||||
rs.pos.y += static_cast<int>(px.pixels);
|
||||
px = rs.pixels[++rs.index];
|
||||
rs.pos.x = px.x_base;
|
||||
}
|
||||
|
||||
int y = rs.pos.y + _m_text_top(px, value.fblock_ptr, value.data_ptr);
|
||||
|
||||
value.data_ptr->nontext_render(graph, rs.pos.x, y);
|
||||
_m_inser_if_traceable(rs.pos.x, y, sz, value.fblock_ptr);
|
||||
rs.pos.x += static_cast<int>(sz.width);
|
||||
|
||||
if(lastpos < y)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//hold the block while the text is empty,
|
||||
//it stands for the first block
|
||||
if(text.empty())
|
||||
block_start = render_iterator;
|
||||
|
||||
text += value.data_ptr->text();
|
||||
}
|
||||
}
|
||||
|
||||
if(text.size())
|
||||
{
|
||||
_m_draw_block(graph, text, block_start, rs);
|
||||
text.clear();
|
||||
}
|
||||
}
|
||||
return (rs.pos.y <= lastpos);
|
||||
}
|
||||
|
||||
static bool _m_overline(const render_status& rs, int right, bool equal_required)
|
||||
{
|
||||
if(align::left == rs.text_align)
|
||||
return (equal_required ? right >= static_cast<int>(rs.allowed_width) : right > static_cast<int>(rs.allowed_width));
|
||||
|
||||
return (equal_required ? rs.pixels[rs.index].x_base <= 0 : rs.pixels[rs.index].x_base < 0);
|
||||
}
|
||||
|
||||
static int _m_text_top(const pixel_tag& px, fblock* fblock_ptr, const data* data_ptr)
|
||||
{
|
||||
switch(fblock_ptr->text_align)
|
||||
{
|
||||
case fblock::aligns::center:
|
||||
return static_cast<int>(px.pixels - data_ptr->size().height) / 2;
|
||||
case fblock::aligns::bottom:
|
||||
return static_cast<int>(px.pixels - data_ptr->size().height);
|
||||
case fblock::aligns::baseline:
|
||||
return static_cast<int>(px.baseline - (data_ptr->is_text() ? data_ptr->ascent() : data_ptr->size().height));
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _m_draw_block(graph_reference graph, const nana::string& s, dstream::linecontainer::iterator block_start, render_status& rs)
|
||||
{
|
||||
nana::unicode_bidi bidi;
|
||||
std::vector<nana::unicode_bidi::entity> reordered;
|
||||
bidi.linestr(s.data(), s.length(), reordered);
|
||||
|
||||
pixel_tag px = rs.pixels[rs.index];
|
||||
|
||||
for(auto & bidi : reordered)
|
||||
{
|
||||
std::size_t pos = bidi.begin - s.data();
|
||||
std::size_t len = bidi.end - bidi.begin;
|
||||
|
||||
while (true)
|
||||
{
|
||||
auto i = block_start;
|
||||
|
||||
//Text range indicates the position of text where begin to output
|
||||
//The output length is the min between len and the second of text range.
|
||||
auto text_range = _m_locate(i, pos);
|
||||
|
||||
if (text_range.second > len)
|
||||
text_range.second = len;
|
||||
|
||||
fblock * fblock_ptr = i->fblock_ptr;
|
||||
data * data_ptr = i->data_ptr;
|
||||
|
||||
const int w = static_cast<int>(rs.allowed_width) - rs.pos.x;
|
||||
nana::size sz = data_ptr->size();
|
||||
if ((static_cast<int>(sz.width) > w) && (rs.pos.x != px.x_base))
|
||||
{
|
||||
//Change a new line
|
||||
rs.pos.y += static_cast<int>(px.pixels);
|
||||
px = rs.pixels[++rs.index];
|
||||
rs.pos.x = px.x_base;
|
||||
}
|
||||
|
||||
const int y = rs.pos.y + _m_text_top(px, fblock_ptr, data_ptr);
|
||||
|
||||
_m_change_font(graph, fblock_ptr);
|
||||
|
||||
if (text_range.second == data_ptr->text().length())
|
||||
{
|
||||
graph.string(rs.pos.x, y, _m_fgcolor(fblock_ptr), data_ptr->text());
|
||||
}
|
||||
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);
|
||||
sz = graph.text_extent_size(str);
|
||||
}
|
||||
_m_inser_if_traceable(rs.pos.x, y, sz, fblock_ptr);
|
||||
rs.pos.x += static_cast<int>(sz.width);
|
||||
|
||||
if(text_range.second < len)
|
||||
{
|
||||
len -= text_range.second;
|
||||
pos += text_range.second;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<std::size_t, std::size_t> _m_locate(dstream::linecontainer::iterator& i, std::size_t pos)
|
||||
{
|
||||
std::pair<std::size_t, std::size_t> r;
|
||||
|
||||
std::size_t n = i->data_ptr->text().length();
|
||||
while(pos >= n)
|
||||
{
|
||||
pos -= n;
|
||||
n = (++i)->data_ptr->text().length();
|
||||
}
|
||||
|
||||
return{ pos, n - pos };
|
||||
}
|
||||
private:
|
||||
dstream dstream_;
|
||||
bool format_enabled_ = false;
|
||||
nana::widgets::skeletons::fblock * fblock_ = nullptr;
|
||||
std::deque<traceable> traceable_;
|
||||
|
||||
nana::paint::font font_;
|
||||
struct def_font_tag
|
||||
{
|
||||
nana::string font_name;
|
||||
std::size_t font_size;
|
||||
bool font_bold;
|
||||
nana::color_t fgcolor;
|
||||
}def_;
|
||||
};
|
||||
|
||||
//class trigger
|
||||
//@brief: Draw the label
|
||||
struct trigger::impl_t
|
||||
{
|
||||
widget * wd{nullptr};
|
||||
paint::graphics * graph{nullptr};
|
||||
|
||||
align text_align{align::left};
|
||||
align_v text_align_v;
|
||||
|
||||
class renderer renderer;
|
||||
|
||||
nana::string target; //It indicates which target is tracing.
|
||||
nana::string url;
|
||||
|
||||
void add_listener(std::function<void(command, const nana::string&)>&& fn)
|
||||
{
|
||||
listener_.emplace_back(std::move(fn));
|
||||
}
|
||||
|
||||
void call_listener(command cmd, const nana::string& tar)
|
||||
{
|
||||
for (auto & fn : listener_)
|
||||
fn(cmd, tar);
|
||||
}
|
||||
private:
|
||||
std::vector<std::function<void(command, const nana::string&)>> listener_;
|
||||
};
|
||||
|
||||
trigger::trigger()
|
||||
:impl_(new impl_t)
|
||||
{}
|
||||
|
||||
trigger::~trigger()
|
||||
{
|
||||
delete impl_;
|
||||
}
|
||||
|
||||
trigger::impl_t * trigger::impl() const
|
||||
{
|
||||
return impl_;
|
||||
}
|
||||
|
||||
void trigger::attached(widget_reference widget, graph_reference graph)
|
||||
{
|
||||
impl_->graph = &graph;
|
||||
impl_->wd = &widget;
|
||||
}
|
||||
|
||||
void trigger::mouse_move(graph_reference, const arg_mouse& arg)
|
||||
{
|
||||
nana::string target, url;
|
||||
|
||||
if(impl_->renderer.find(arg.pos.x, arg.pos.y, target, url))
|
||||
{
|
||||
int cur_state = 0;
|
||||
if(target != impl_->target)
|
||||
{
|
||||
if(impl_->target.size())
|
||||
{
|
||||
impl_->call_listener(command::leave, impl_->target);
|
||||
cur_state = 1; //Set arrow
|
||||
}
|
||||
|
||||
impl_->target = target;
|
||||
|
||||
if(target.size())
|
||||
{
|
||||
impl_->call_listener(command::enter, impl_->target);
|
||||
cur_state = 2; //Set hand
|
||||
}
|
||||
}
|
||||
if (url != impl_->url)
|
||||
{
|
||||
if (impl_->url.size())
|
||||
cur_state = 1; //Set arrow
|
||||
|
||||
impl_->url = url;
|
||||
|
||||
if (url.size())
|
||||
cur_state = 2; //Set hand
|
||||
}
|
||||
|
||||
if (cur_state)
|
||||
impl_->wd->cursor(1 == cur_state ? cursor::arrow : cursor::hand);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool restore = false;
|
||||
if (impl_->target.size())
|
||||
{
|
||||
impl_->call_listener(command::leave, impl_->target);
|
||||
impl_->target.clear();
|
||||
restore = true;
|
||||
}
|
||||
|
||||
if (impl_->url.size())
|
||||
{
|
||||
impl_->url.clear();
|
||||
restore = true;
|
||||
}
|
||||
|
||||
if(restore)
|
||||
impl_->wd->cursor(cursor::arrow);
|
||||
}
|
||||
}
|
||||
|
||||
void trigger::mouse_leave(graph_reference, const arg_mouse&)
|
||||
{
|
||||
if(impl_->target.size())
|
||||
{
|
||||
impl_->call_listener(command::leave, impl_->target);
|
||||
impl_->target.clear();
|
||||
impl_->wd->cursor(cursor::arrow);
|
||||
}
|
||||
}
|
||||
|
||||
void trigger::click(graph_reference, const arg_mouse&)
|
||||
{
|
||||
//make a copy, because the listener may popup a window, and then
|
||||
//user moves the mouse. it will reset the url when the mouse is moving out from the element.
|
||||
auto url = impl_->url;
|
||||
|
||||
if(impl_->target.size())
|
||||
impl_->call_listener(command::click, impl_->target);
|
||||
|
||||
system::open_url(url);
|
||||
}
|
||||
|
||||
void trigger::refresh(graph_reference graph)
|
||||
{
|
||||
if(nullptr == impl_->wd) return;
|
||||
|
||||
window wd = impl_->wd->handle();
|
||||
if(bground_mode::basic != API::effects_bground_mode(wd))
|
||||
graph.rectangle(API::background(wd), true);
|
||||
|
||||
impl_->renderer.render(graph, impl_->wd->foreground(), impl_->text_align, impl_->text_align_v);
|
||||
}
|
||||
|
||||
//end class label_drawer
|
||||
}//end namespace label
|
||||
}//end namespace drawerbase
|
||||
|
||||
|
||||
//
|
||||
//class label
|
||||
label::label(){}
|
||||
|
||||
label::label(window wd, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
}
|
||||
|
||||
label::label(window wd, const nana::string& text, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
caption(text);
|
||||
}
|
||||
|
||||
label::label(window wd, const nana::char_t* text, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
caption(text);
|
||||
}
|
||||
|
||||
label::label(window wd, const rectangle& r, bool visible)
|
||||
{
|
||||
create(wd, r, visible);
|
||||
}
|
||||
|
||||
label& label::transparent(bool enabled)
|
||||
{
|
||||
if(enabled)
|
||||
API::effects_bground(*this, effects::bground_transparent(0), 0.0);
|
||||
else
|
||||
API::effects_bground_remove(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool label::transparent() const
|
||||
{
|
||||
return (bground_mode::basic == API::effects_bground_mode(*this));
|
||||
}
|
||||
|
||||
label& label::format(bool f)
|
||||
{
|
||||
auto impl = get_drawer_trigger().impl();
|
||||
|
||||
if(impl->renderer.format(f))
|
||||
{
|
||||
window wd = *this;
|
||||
impl->renderer.parse(API::dev::window_caption(wd));
|
||||
API::refresh_window(wd);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
label& label::add_format_listener(std::function<void(command, const nana::string&)> f)
|
||||
{
|
||||
get_drawer_trigger().impl()->add_listener(std::move(f));
|
||||
return *this;
|
||||
}
|
||||
|
||||
nana::size label::measure(unsigned limited) const
|
||||
{
|
||||
if(empty())
|
||||
return nana::size();
|
||||
|
||||
auto impl = get_drawer_trigger().impl();
|
||||
|
||||
//First Check the graph of label
|
||||
//Then take a substitute for graph when the graph of label is zero-sized.
|
||||
nana::paint::graphics * graph_ptr = impl->graph;
|
||||
nana::paint::graphics substitute;
|
||||
if(graph_ptr->empty())
|
||||
{
|
||||
graph_ptr = &substitute;
|
||||
graph_ptr->make(10, 10);
|
||||
}
|
||||
|
||||
return impl->renderer.measure(*graph_ptr, limited, impl->text_align, impl->text_align_v);
|
||||
}
|
||||
|
||||
label& label::text_align(align th, align_v tv)
|
||||
{
|
||||
internal_scope_guard isg;
|
||||
auto impl = get_drawer_trigger().impl();
|
||||
|
||||
bool to_update = false;
|
||||
if(impl->text_align != th)
|
||||
{
|
||||
impl->text_align = th;
|
||||
to_update = true;
|
||||
}
|
||||
|
||||
if(impl->text_align_v != tv)
|
||||
{
|
||||
impl->text_align_v = tv;
|
||||
to_update = true;
|
||||
}
|
||||
|
||||
if(to_update)
|
||||
API::refresh_window(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void label::_m_caption(nana::string&& str)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
window wd = *this;
|
||||
get_drawer_trigger().impl()->renderer.parse(str);
|
||||
API::dev::window_caption(wd, std::move(str));
|
||||
API::refresh_window(wd);
|
||||
}
|
||||
//end class label
|
||||
}//end namespace nana
|
||||
3761
source/gui/widgets/listbox.cpp
Normal file
3761
source/gui/widgets/listbox.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1389
source/gui/widgets/menu.cpp
Normal file
1389
source/gui/widgets/menu.cpp
Normal file
File diff suppressed because it is too large
Load Diff
608
source/gui/widgets/menubar.cpp
Normal file
608
source/gui/widgets/menubar.cpp
Normal file
@@ -0,0 +1,608 @@
|
||||
/*
|
||||
* A Menubar implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2009-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/widgets/menubar.cpp
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/menubar.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
class menu_accessor
|
||||
{
|
||||
public:
|
||||
static void popup(menu& m, window wd, int x, int y)
|
||||
{
|
||||
m._m_popup(wd, x, y, true);
|
||||
}
|
||||
};
|
||||
|
||||
namespace drawerbase
|
||||
{
|
||||
namespace menubar
|
||||
{
|
||||
struct item_type
|
||||
{
|
||||
item_type(const nana::string& text, unsigned long shortkey)
|
||||
: text(text), shortkey(shortkey)
|
||||
{}
|
||||
|
||||
nana::string text;
|
||||
unsigned long shortkey;
|
||||
nana::menu menu_obj;
|
||||
nana::point pos;
|
||||
nana::size size;
|
||||
};
|
||||
|
||||
class trigger::itembase
|
||||
{
|
||||
public:
|
||||
typedef std::vector<item_type*> container;
|
||||
|
||||
~itembase()
|
||||
{
|
||||
for(auto i : cont_)
|
||||
delete i;
|
||||
}
|
||||
|
||||
void append(const nana::string& text, unsigned long shortkey)
|
||||
{
|
||||
if(shortkey && shortkey < 0x61) shortkey += (0x61 - 0x41);
|
||||
cont_.push_back(new item_type(text, shortkey));
|
||||
}
|
||||
|
||||
nana::menu* get_menu(std::size_t index) const
|
||||
{
|
||||
return (index < cont_.size() ? &(cont_[index]->menu_obj) : nullptr);
|
||||
}
|
||||
|
||||
const item_type& at(std::size_t index) const
|
||||
{
|
||||
return *cont_.at(index);
|
||||
}
|
||||
|
||||
std::size_t find(unsigned long shortkey) const
|
||||
{
|
||||
if(shortkey)
|
||||
{
|
||||
if(shortkey < 0x61) shortkey += (0x61 - 0x41);
|
||||
|
||||
std::size_t index = 0;
|
||||
for(auto i : cont_)
|
||||
{
|
||||
if(i->shortkey == shortkey)
|
||||
return index;
|
||||
++index;
|
||||
}
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
const container& cont() const
|
||||
{
|
||||
return cont_;
|
||||
}
|
||||
private:
|
||||
container cont_;
|
||||
};
|
||||
|
||||
//class item_renderer
|
||||
item_renderer::item_renderer(window wd, graph_reference graph)
|
||||
:handle_(wd), graph_(graph)
|
||||
{}
|
||||
|
||||
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;
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case item_renderer::state_highlight:
|
||||
border = nana::color::highlight;
|
||||
body = 0xC0DDFC;
|
||||
corner = paint::graphics::mix(body, bground, 0.5);
|
||||
break;
|
||||
case item_renderer::state_selected:
|
||||
border = nana::color::dark_border;
|
||||
body = 0xFFFFFF;
|
||||
corner = paint::graphics::mix(border, bground, 0.5);
|
||||
break;
|
||||
default: //Don't process other states.
|
||||
return;
|
||||
}
|
||||
|
||||
nana::rectangle r(pos, size);
|
||||
graph_.rectangle(r, border, false);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void item_renderer::caption(int x, int y, const nana::string& text)
|
||||
{
|
||||
graph_.string(x, y, 0x0, text);
|
||||
}
|
||||
//end class item_renderer
|
||||
|
||||
//class trigger
|
||||
trigger::trigger()
|
||||
: items_(new itembase)
|
||||
{}
|
||||
|
||||
trigger::~trigger()
|
||||
{
|
||||
delete items_;
|
||||
}
|
||||
|
||||
nana::menu* trigger::push_back(const nana::string& text)
|
||||
{
|
||||
nana::string::value_type shkey;
|
||||
API::transform_shortkey_text(text, shkey, nullptr);
|
||||
|
||||
if(shkey)
|
||||
API::register_shortkey(widget_->handle(), shkey);
|
||||
|
||||
auto i = items_->cont().size();
|
||||
items_->append(text, shkey);
|
||||
_m_draw();
|
||||
return items_->get_menu(i);
|
||||
}
|
||||
|
||||
nana::menu* trigger::at(std::size_t index) const
|
||||
{
|
||||
return items_->get_menu(index);
|
||||
}
|
||||
|
||||
std::size_t trigger::size() const
|
||||
{
|
||||
return items_->cont().size();
|
||||
}
|
||||
|
||||
void trigger::attached(widget_reference widget, graph_reference graph)
|
||||
{
|
||||
graph_ = &graph;
|
||||
widget_ = &widget;
|
||||
}
|
||||
|
||||
void trigger::refresh(graph_reference)
|
||||
{
|
||||
_m_draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void trigger::mouse_move(graph_reference, const arg_mouse& arg)
|
||||
{
|
||||
if (arg.pos != state_.mouse_pos)
|
||||
state_.nullify_mouse = false;
|
||||
|
||||
bool popup = false;
|
||||
if(state_.behavior == state_type::behavior_focus)
|
||||
{
|
||||
std::size_t index = _m_item_by_pos(arg.pos);
|
||||
if(index != npos && state_.active != index)
|
||||
{
|
||||
state_.active = index;
|
||||
popup = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
popup = _m_track_mouse(arg.pos);
|
||||
|
||||
if(popup)
|
||||
{
|
||||
_m_popup_menu();
|
||||
_m_draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
state_.mouse_pos = arg.pos;
|
||||
}
|
||||
|
||||
void trigger::mouse_leave(graph_reference graph, const arg_mouse& arg)
|
||||
{
|
||||
state_.nullify_mouse = false;
|
||||
mouse_move(graph, arg);
|
||||
}
|
||||
|
||||
void trigger::mouse_down(graph_reference graph, const arg_mouse& arg)
|
||||
{
|
||||
state_.nullify_mouse = false;
|
||||
|
||||
state_.active = _m_item_by_pos(arg.pos);
|
||||
if(state_.menu_active == false)
|
||||
{
|
||||
if(state_.active != npos)
|
||||
{
|
||||
state_.menu_active = true;
|
||||
_m_popup_menu();
|
||||
}
|
||||
else
|
||||
_m_total_close();
|
||||
}
|
||||
else if(npos == state_.active)
|
||||
_m_total_close();
|
||||
else
|
||||
_m_popup_menu();
|
||||
|
||||
_m_draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void trigger::mouse_up(graph_reference graph, const arg_mouse&)
|
||||
{
|
||||
state_.nullify_mouse = false;
|
||||
|
||||
if(state_.behavior != state_.behavior_menu)
|
||||
{
|
||||
if(state_.menu_active)
|
||||
state_.behavior = state_.behavior_menu;
|
||||
}
|
||||
else
|
||||
{
|
||||
state_.behavior = state_.behavior_none;
|
||||
_m_total_close();
|
||||
_m_draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void trigger::focus(graph_reference, const arg_focus& arg)
|
||||
{
|
||||
if((arg.getting == false) && (state_.active != npos))
|
||||
{
|
||||
state_.behavior = state_type::behavior_none;
|
||||
state_.nullify_mouse = true;
|
||||
state_.menu_active = false;
|
||||
_m_close_menu();
|
||||
state_.active = npos;
|
||||
_m_draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void trigger::key_press(graph_reference, const arg_keyboard& arg)
|
||||
{
|
||||
state_.nullify_mouse = true;
|
||||
if(state_.menu)
|
||||
{
|
||||
switch(arg.key)
|
||||
{
|
||||
case keyboard::os_arrow_down:
|
||||
state_.menu->goto_next(true); break;
|
||||
case keyboard::backspace:
|
||||
case keyboard::os_arrow_up:
|
||||
state_.menu->goto_next(false); break;
|
||||
case keyboard::os_arrow_right:
|
||||
if(state_.menu->goto_submen() == false)
|
||||
_m_move(false);
|
||||
break;
|
||||
case keyboard::os_arrow_left:
|
||||
if(state_.menu->exit_submenu() == false)
|
||||
_m_move(true);
|
||||
break;
|
||||
case keyboard::escape:
|
||||
if(state_.menu->exit_submenu() == false)
|
||||
{
|
||||
_m_close_menu();
|
||||
state_.behavior = state_.behavior_focus;
|
||||
state_.menu_active = false;
|
||||
}
|
||||
break;
|
||||
case keyboard::enter:
|
||||
state_.menu->pick();
|
||||
break;
|
||||
default:
|
||||
if(2 != state_.menu->send_shortkey(arg.key))
|
||||
{
|
||||
if(state_.active != npos)
|
||||
{
|
||||
_m_total_close();
|
||||
if(arg.key == 18) //ALT
|
||||
state_.behavior = state_.behavior_focus;
|
||||
}
|
||||
}
|
||||
else
|
||||
state_.menu->goto_submen();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(arg.key)
|
||||
{
|
||||
case keyboard::os_arrow_right:
|
||||
_m_move(false);
|
||||
break;
|
||||
case keyboard::backspace:
|
||||
case keyboard::os_arrow_left:
|
||||
_m_move(true);
|
||||
break;
|
||||
case keyboard::escape:
|
||||
if(state_.behavior == state_.behavior_focus)
|
||||
{
|
||||
state_.active= npos;
|
||||
state_.behavior = state_.behavior_none;
|
||||
API::restore_menubar_taken_window();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_m_draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void trigger::key_release(graph_reference, const arg_keyboard& arg)
|
||||
{
|
||||
if(arg.key == 18)
|
||||
{
|
||||
if(state_.behavior == state_type::behavior_none)
|
||||
{
|
||||
state_.behavior = state_type::behavior_focus;
|
||||
state_.active = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
state_.behavior = state_type::behavior_none;
|
||||
nana::point pos = API::cursor_position();
|
||||
API::calc_window_point(widget_->handle(), pos);
|
||||
state_.active = _m_item_by_pos(pos);
|
||||
}
|
||||
|
||||
state_.menu_active = false;
|
||||
_m_draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void trigger::shortkey(graph_reference graph, const arg_keyboard& arg)
|
||||
{
|
||||
API::focus_window(widget_->handle());
|
||||
|
||||
std::size_t index = items_->find(arg.key);
|
||||
if(index != npos && (index != state_.active || nullptr == state_.menu))
|
||||
{
|
||||
_m_close_menu();
|
||||
state_.menu_active = true;
|
||||
state_.nullify_mouse = true;
|
||||
state_.active = index;
|
||||
|
||||
if(_m_popup_menu())
|
||||
state_.menu->goto_next(true);
|
||||
|
||||
_m_draw();
|
||||
API::lazy_refresh();
|
||||
state_.behavior = state_.behavior_menu;
|
||||
}
|
||||
}
|
||||
|
||||
void trigger::_m_move(bool to_left)
|
||||
{
|
||||
if(items_->cont().empty()) return;
|
||||
|
||||
const std::size_t last_pos = items_->cont().size() - 1;
|
||||
std::size_t index = state_.active;
|
||||
if(to_left)
|
||||
{
|
||||
--index;
|
||||
if (index > last_pos)
|
||||
index = last_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
++index;
|
||||
if(index > last_pos)
|
||||
index = 0;
|
||||
}
|
||||
|
||||
if(index != state_.active)
|
||||
{
|
||||
state_.active = index;
|
||||
_m_draw();
|
||||
API::lazy_refresh();
|
||||
|
||||
if(_m_popup_menu())
|
||||
state_.menu->goto_next(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool trigger::_m_popup_menu()
|
||||
{
|
||||
if(state_.menu_active && (state_.menu != items_->get_menu(state_.active)))
|
||||
{
|
||||
std::size_t index = state_.active;
|
||||
_m_close_menu();
|
||||
state_.active = index;
|
||||
|
||||
state_.menu = items_->get_menu(state_.active);
|
||||
if(state_.menu)
|
||||
{
|
||||
const item_type &m = items_->at(state_.active);
|
||||
state_.menu->destroy_answer(std::bind(&trigger::_m_unload_menu_window, this));
|
||||
menu_accessor::popup(*state_.menu, widget_->handle(), m.pos.x, m.pos.y + m.size.height);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void trigger::_m_total_close()
|
||||
{
|
||||
_m_close_menu();
|
||||
state_.menu_active = false;
|
||||
state_.behavior = state_.behavior_none;
|
||||
|
||||
API::restore_menubar_taken_window();
|
||||
|
||||
auto pos = API::cursor_position();
|
||||
API::calc_window_point(widget_->handle(), pos);
|
||||
state_.active = _m_item_by_pos(pos);
|
||||
}
|
||||
|
||||
bool trigger::_m_close_menu()
|
||||
{
|
||||
if(state_.menu)
|
||||
{
|
||||
state_.passive_close = false;
|
||||
state_.menu->close();
|
||||
state_.passive_close = true;
|
||||
state_.menu = nullptr;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void trigger::_m_unload_menu_window()
|
||||
{
|
||||
state_.menu = nullptr;
|
||||
if(state_.passive_close)
|
||||
{
|
||||
_m_total_close();
|
||||
_m_draw();
|
||||
API::update_window(widget_->handle());
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t trigger::_m_item_by_pos(const ::nana::point& pos)
|
||||
{
|
||||
if((2 <= pos.x) && (2 <= pos.y) && (pos.y < 25))
|
||||
{
|
||||
int item_x = 2;
|
||||
std::size_t index = 0;
|
||||
for(auto i : items_->cont())
|
||||
{
|
||||
if(item_x <= pos.x && pos.x < item_x + static_cast<int>(i->size.width))
|
||||
return index;
|
||||
|
||||
item_x += i->size.width;
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
return npos;
|
||||
}
|
||||
|
||||
bool trigger::_m_track_mouse(const ::nana::point& pos)
|
||||
{
|
||||
if(state_.nullify_mouse == false)
|
||||
{
|
||||
std::size_t which = _m_item_by_pos(pos);
|
||||
if((which != state_.active) && (which != npos || (false == state_.menu_active)))
|
||||
{
|
||||
state_.active = which;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void trigger::_m_draw()
|
||||
{
|
||||
nana::color_t bground_color = API::background(*widget_);
|
||||
graph_->rectangle(bground_color, true);
|
||||
|
||||
item_renderer ird(*widget_, *graph_);
|
||||
|
||||
nana::point item_pos(2, 2);
|
||||
nana::size item_s(0, 23);
|
||||
|
||||
unsigned long index = 0;
|
||||
for(auto i : items_->cont())
|
||||
{
|
||||
//Transform the text if it contains the hotkey character
|
||||
nana::string::value_type hotkey;
|
||||
nana::string::size_type hotkey_pos;
|
||||
nana::string text = API::transform_shortkey_text(i->text, hotkey, &hotkey_pos);
|
||||
|
||||
nana::size text_s = graph_->text_extent_size(text);
|
||||
|
||||
item_s.width = text_s.width + 16;
|
||||
|
||||
i->pos = item_pos;
|
||||
i->size = item_s;
|
||||
|
||||
item_renderer::state_t state = (index != state_.active ? ird.state_normal : (state_.menu_active ? ird.state_selected : ird.state_highlight));
|
||||
ird.background(item_pos, item_s, state);
|
||||
|
||||
if(state == ird.state_selected)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
//Draw text, the text is transformed from orignal for hotkey character
|
||||
int text_top_off = (item_s.height - text_s.height) / 2;
|
||||
ird.caption(item_pos.x + 8, item_pos.y + text_top_off, text);
|
||||
|
||||
if(hotkey)
|
||||
{
|
||||
unsigned off_w = (hotkey_pos ? graph_->text_extent_size(text, static_cast<unsigned>(hotkey_pos)).width : 0);
|
||||
nana::size hotkey_size = graph_->text_extent_size(text.c_str() + hotkey_pos, 1);
|
||||
|
||||
unsigned ascent, descent, inleading;
|
||||
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);
|
||||
}
|
||||
|
||||
item_pos.x += i->size.width;
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
//struct state_type
|
||||
trigger::state_type::state_type()
|
||||
:active(npos), behavior(behavior_none), menu_active(false), passive_close(true), nullify_mouse(false), menu(nullptr)
|
||||
{}
|
||||
//end struct state_type
|
||||
//end class trigger
|
||||
}//end namespace menubar
|
||||
}//end namespace drawerbase
|
||||
|
||||
|
||||
//class menubar
|
||||
menubar::menubar(){}
|
||||
menubar::menubar(window wd)
|
||||
{
|
||||
create(wd);
|
||||
}
|
||||
|
||||
void menubar::create(window wd)
|
||||
{
|
||||
widget_object<category::widget_tag, drawerbase::menubar::trigger>
|
||||
::create(wd, rectangle(nana::size(API::window_size(wd).width, 28)));
|
||||
API::attach_menubar(handle());
|
||||
}
|
||||
|
||||
menu& menubar::push_back(const nana::string& text)
|
||||
{
|
||||
return *(get_drawer_trigger().push_back(text));
|
||||
}
|
||||
|
||||
menu& menubar::at(std::size_t index) const
|
||||
{
|
||||
menu* p = get_drawer_trigger().at(index);
|
||||
if(nullptr == p)
|
||||
throw std::out_of_range("menubar::at, out of range");
|
||||
return *p;
|
||||
}
|
||||
|
||||
std::size_t menubar::length() const
|
||||
{
|
||||
return get_drawer_trigger().size();
|
||||
}
|
||||
//end class menubar
|
||||
}//end namespace nana
|
||||
42
source/gui/widgets/panel.cpp
Normal file
42
source/gui/widgets/panel.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* A Panel Implementation
|
||||
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: source/gui/widgets/panel.cpp
|
||||
*
|
||||
* @brief: panel is a widget used for placing some widgets.
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/panel.hpp>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
namespace drawerbase
|
||||
{
|
||||
namespace panel
|
||||
{
|
||||
//class drawer
|
||||
drawer::drawer()
|
||||
:window_(nullptr)
|
||||
{}
|
||||
|
||||
void drawer::attached(widget_reference widget, graph_reference)
|
||||
{
|
||||
widget.caption(STR("Nana Panel"));
|
||||
window_ = widget.handle();
|
||||
}
|
||||
|
||||
void drawer::refresh(graph_reference graph)
|
||||
{
|
||||
if(bground_mode::basic != API::effects_bground_mode(window_))
|
||||
graph.rectangle(API::background(window_), true);
|
||||
}
|
||||
//end class drawer
|
||||
}//end namespace panel
|
||||
|
||||
}//end namespace drawerbase
|
||||
}//end namespace nana
|
||||
299
source/gui/widgets/picture.cpp
Normal file
299
source/gui/widgets/picture.cpp
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* A Picture Implementation
|
||||
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: nana/gui/widgets/picture.cpp
|
||||
* @description:
|
||||
* Used for showing a picture
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/picture.hpp>
|
||||
#include <nana/paint/image.hpp>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
namespace xpicture
|
||||
{
|
||||
|
||||
//class picture_drawer
|
||||
picture_drawer::picture_drawer():graph_(nullptr)
|
||||
{
|
||||
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;
|
||||
graph_ = &graph;
|
||||
}
|
||||
|
||||
void picture_drawer::load(const nana::char_t* file)
|
||||
{
|
||||
backimg_.image.open(file);
|
||||
}
|
||||
|
||||
void picture_drawer::load(const nana::paint::image& img)
|
||||
{
|
||||
backimg_.image = img;
|
||||
}
|
||||
|
||||
void picture_drawer::set_shadow_background(unsigned begin_color, unsigned end_color, bool horizontal)
|
||||
{
|
||||
runtime_.background_shadow_end = end_color;
|
||||
runtime_.background_shadow_start = begin_color;
|
||||
runtime_.horizontal = horizontal;
|
||||
|
||||
_m_draw_background();
|
||||
}
|
||||
|
||||
bool picture_drawer::bgstyle(bool is_stretch, nana::arrange arg, int beg, int end)
|
||||
{
|
||||
if(backimg_.image)
|
||||
{
|
||||
backimg_.is_stretch = is_stretch;
|
||||
backimg_.arg = arg;
|
||||
|
||||
if(arg == nana::arrange::horizontal_vertical) return false;
|
||||
|
||||
if(beg < 0) beg = 0;
|
||||
if(end < beg) end = beg;
|
||||
if((backimg_.beg == beg) && (backimg_.end == end)) return false;
|
||||
|
||||
nana::size imgsize = backimg_.image.size();
|
||||
unsigned scale = (arg == nana::arrange::horizontal ? imgsize.width : imgsize.height);
|
||||
|
||||
if(beg < 0)
|
||||
beg = 0;
|
||||
else if(static_cast<unsigned>(beg) >= scale)
|
||||
beg = static_cast<int>(scale) - 1;
|
||||
|
||||
if(end < beg)
|
||||
end = beg;
|
||||
else if(static_cast<unsigned>(end) >= scale)
|
||||
end = static_cast<int>(scale) - 1;
|
||||
|
||||
backimg_.beg = beg;
|
||||
backimg_.end = end;
|
||||
return true;
|
||||
}
|
||||
|
||||
backimg_.arg = nana::arrange::unknown;
|
||||
return false;
|
||||
}
|
||||
|
||||
void picture_drawer::refresh(graph_reference graph)
|
||||
{
|
||||
if(graph.changed())
|
||||
{
|
||||
_m_draw_background();
|
||||
if(backimg_.image.empty() == false)
|
||||
{
|
||||
nana::size imgsize = backimg_.image.size();
|
||||
nana::size gsize = graph.size();
|
||||
|
||||
switch(backimg_.arg)
|
||||
{
|
||||
case nana::arrange::unknown:
|
||||
backimg_.image.paste(graph, 0, 0);
|
||||
break;
|
||||
case nana::arrange::horizontal:
|
||||
if(backimg_.beg < backimg_.end)
|
||||
{
|
||||
unsigned block_tail = imgsize.width - backimg_.end;
|
||||
|
||||
if(backimg_.beg)
|
||||
backimg_.image.paste(nana::rectangle(0, 0, backimg_.beg, imgsize.height), graph, nana::point());
|
||||
|
||||
if(block_tail)
|
||||
backimg_.image.paste(nana::rectangle(static_cast<int>(imgsize.width - block_tail), 0, block_tail, imgsize.height), graph, nana::point(gsize.width - block_tail, 0));
|
||||
|
||||
if(backimg_.beg < backimg_.end)
|
||||
{
|
||||
unsigned fixed_size = backimg_.beg + block_tail;
|
||||
if(fixed_size < gsize.width)
|
||||
{
|
||||
if(false == backimg_.is_stretch)
|
||||
{
|
||||
unsigned imgarea = backimg_.end - backimg_.beg;
|
||||
fixed_size = gsize.width - fixed_size;
|
||||
|
||||
nana::rectangle r(backimg_.beg, 0, imgarea, imgsize.height);
|
||||
nana::point p_dst(backimg_.beg, 0);
|
||||
|
||||
while(imgarea < fixed_size)
|
||||
{
|
||||
backimg_.image.paste(r, graph, p_dst);
|
||||
p_dst.x += static_cast<int>(imgarea);
|
||||
fixed_size -= imgarea;
|
||||
}
|
||||
if(fixed_size)
|
||||
{
|
||||
r.width = fixed_size;
|
||||
backimg_.image.paste(r, graph, p_dst);
|
||||
}
|
||||
}
|
||||
else
|
||||
backimg_.image.stretch(nana::rectangle(backimg_.beg, 0, imgsize.width - fixed_size, imgsize.height), graph, nana::rectangle(backimg_.beg, 0, gsize.width - fixed_size, imgsize.height));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(false == backimg_.is_stretch)
|
||||
{
|
||||
int x = 0;
|
||||
while(x < static_cast<int>(gsize.width))
|
||||
{
|
||||
backimg_.image.paste(graph, x, 0);
|
||||
x += static_cast<int>(imgsize.width);
|
||||
}
|
||||
}
|
||||
else
|
||||
backimg_.image.stretch(imgsize, graph, nana::size(gsize.width, imgsize.height));
|
||||
}
|
||||
break;
|
||||
case nana::arrange::vertical:
|
||||
if(backimg_.beg < backimg_.end)
|
||||
{
|
||||
unsigned block_tail = imgsize.height - backimg_.end;
|
||||
|
||||
if(backimg_.beg)
|
||||
backimg_.image.paste(nana::rectangle(0, 0, imgsize.width, static_cast<unsigned>(backimg_.beg)), graph, nana::point());
|
||||
|
||||
if(block_tail)
|
||||
backimg_.image.paste(nana::rectangle(0, static_cast<int>(imgsize.height - block_tail), imgsize.width, block_tail), graph, nana::point(0, gsize.height - block_tail));
|
||||
|
||||
if(backimg_.beg < backimg_.end)
|
||||
{
|
||||
unsigned fixed_size = backimg_.beg + block_tail;
|
||||
if(fixed_size < gsize.height)
|
||||
{
|
||||
if(false == backimg_.is_stretch)
|
||||
{
|
||||
unsigned imgarea = backimg_.end - backimg_.beg;
|
||||
fixed_size = gsize.height - fixed_size;
|
||||
|
||||
nana::rectangle r(0, backimg_.beg, imgsize.width, imgarea);
|
||||
nana::point pos(0, backimg_.beg);
|
||||
|
||||
while(imgarea < fixed_size)
|
||||
{
|
||||
backimg_.image.paste(r, graph, pos);
|
||||
pos.y += static_cast<int>(imgarea);
|
||||
fixed_size -= imgarea;
|
||||
}
|
||||
if(fixed_size)
|
||||
{
|
||||
r.height = fixed_size;
|
||||
backimg_.image.paste(r, graph, pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
backimg_.image.stretch(nana::rectangle(0, backimg_.beg, imgsize.width, imgsize.height - fixed_size), graph, nana::rectangle(0, backimg_.beg, imgsize.width, gsize.height - fixed_size));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(false == backimg_.is_stretch)
|
||||
{
|
||||
int y = 0;
|
||||
while(y < static_cast<int>(gsize.height))
|
||||
{
|
||||
backimg_.image.paste(graph, 0, y);
|
||||
y += static_cast<int>(imgsize.height);
|
||||
}
|
||||
}
|
||||
else
|
||||
backimg_.image.stretch(imgsize, graph, nana::rectangle(0, 0, imgsize.width, gsize.height));
|
||||
}
|
||||
break;
|
||||
case nana::arrange::horizontal_vertical:
|
||||
if(backimg_.is_stretch == false)
|
||||
{
|
||||
int y = 0;
|
||||
while(y < static_cast<int>(gsize.height))
|
||||
{
|
||||
int x = 0;
|
||||
while(x < static_cast<int>(gsize.width))
|
||||
{
|
||||
backimg_.image.paste(graph, x, y);
|
||||
x += static_cast<int>(imgsize.width);
|
||||
}
|
||||
y += static_cast<int>(imgsize.height);
|
||||
}
|
||||
}
|
||||
else
|
||||
backimg_.image.stretch(imgsize, graph, gsize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void picture_drawer::_m_draw_background()
|
||||
{
|
||||
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);
|
||||
else
|
||||
graph_->shadow_rectangle(graph_->size(), runtime_.background_shadow_start, runtime_.background_shadow_end, !runtime_.horizontal);
|
||||
}
|
||||
}
|
||||
//end class picture_drawer
|
||||
}//end namespace xpicture
|
||||
|
||||
//class picture
|
||||
picture::picture(){}
|
||||
|
||||
picture::picture(window wd, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
}
|
||||
|
||||
picture::picture(window wd, const nana::rectangle& r, bool visible)
|
||||
{
|
||||
create(wd, r, visible);
|
||||
}
|
||||
|
||||
void picture::load(const nana::paint::image& img)
|
||||
{
|
||||
get_drawer_trigger().load(img);
|
||||
API::refresh_window(*this);
|
||||
}
|
||||
|
||||
void picture::bgstyle(bool stretchable, nana::arrange arg, int beg, int end)
|
||||
{
|
||||
if(get_drawer_trigger().bgstyle(stretchable, arg, beg, end))
|
||||
API::refresh_window(*this);
|
||||
}
|
||||
|
||||
void picture::set_shadow_background(unsigned begin_color, unsigned end_color, bool horizontal)
|
||||
{
|
||||
get_drawer_trigger().set_shadow_background(begin_color, end_color, horizontal);
|
||||
}
|
||||
|
||||
void picture::transparent(bool enabled)
|
||||
{
|
||||
if(enabled)
|
||||
API::effects_bground(*this, effects::bground_transparent(0), 0.0);
|
||||
else
|
||||
API::effects_bground_remove(*this);
|
||||
}
|
||||
|
||||
bool picture::transparent() const
|
||||
{
|
||||
return (bground_mode::basic == API::effects_bground_mode(*this));
|
||||
}
|
||||
//end class picture
|
||||
}//end namespace nana
|
||||
205
source/gui/widgets/progress.cpp
Normal file
205
source/gui/widgets/progress.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* A Progress Indicator Implementation
|
||||
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: nana/gui/widgets/progress.cpp
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/progress.hpp>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
namespace drawerbase
|
||||
{
|
||||
namespace progress
|
||||
{
|
||||
//class trigger
|
||||
trigger::trigger()
|
||||
: graph_(nullptr), draw_width_(static_cast<unsigned>(-1)), has_value_(true),
|
||||
unknown_(false), max_(100), value_(0)
|
||||
{}
|
||||
|
||||
void trigger::attached(widget_reference wd, graph_reference graph)
|
||||
{
|
||||
widget_ = &wd;
|
||||
graph_ = &graph;
|
||||
}
|
||||
|
||||
unsigned trigger::value() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
unsigned trigger::value(unsigned v)
|
||||
{
|
||||
internal_scope_guard isg;
|
||||
if(false == unknown_)
|
||||
{
|
||||
if(value_ != v)
|
||||
value_ = v > max_?max_:v;
|
||||
}
|
||||
else
|
||||
value_ += (v?10:v);
|
||||
|
||||
if(_m_check_changing(value_))
|
||||
{
|
||||
_m_draw();
|
||||
API::update_window(widget_->handle());
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
unsigned trigger::inc()
|
||||
{
|
||||
internal_scope_guard isg;
|
||||
if(false == unknown_)
|
||||
{
|
||||
if(value_ < max_)
|
||||
++value_;
|
||||
}
|
||||
else
|
||||
value_ += 5;
|
||||
|
||||
if(_m_check_changing(value_))
|
||||
API::refresh_window(widget_->handle());
|
||||
return value_;
|
||||
}
|
||||
|
||||
unsigned trigger::Max() const
|
||||
{
|
||||
return max_;
|
||||
}
|
||||
|
||||
unsigned trigger::Max(unsigned value)
|
||||
{
|
||||
max_ = value;
|
||||
if(max_ == 0) ++max_;
|
||||
|
||||
API::refresh_window(widget_->handle());
|
||||
return max_;
|
||||
}
|
||||
|
||||
void trigger::unknown(bool enb)
|
||||
{
|
||||
unknown_ = enb;
|
||||
if(enb)
|
||||
draw_width_ = static_cast<unsigned>(-1);
|
||||
}
|
||||
|
||||
bool trigger::unknown() const
|
||||
{
|
||||
return unknown_;
|
||||
}
|
||||
|
||||
void trigger::refresh(graph_reference)
|
||||
{
|
||||
_m_draw();
|
||||
}
|
||||
|
||||
void trigger::_m_draw()
|
||||
{
|
||||
if(false == unknown_)
|
||||
draw_width_ = static_cast<unsigned>((graph_->width() - border * 2) * (double(value_) / max_));
|
||||
|
||||
_m_draw_box(*graph_);
|
||||
_m_draw_progress(*graph_);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void trigger::_m_draw_progress(graph_reference graph)
|
||||
{
|
||||
unsigned width = graph.width() - border * 2;
|
||||
unsigned height = graph.height() - border * 2;
|
||||
|
||||
if(false == unknown_)
|
||||
{
|
||||
if(draw_width_)
|
||||
graph.shadow_rectangle(border, border, draw_width_, height, 0x6FFFA8, 0x107515, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned block = width / 3;
|
||||
|
||||
int left = (value_ < block ? 0 : value_ - block) + border;
|
||||
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);
|
||||
|
||||
if(value_ >= width + block) value_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool trigger::_m_check_changing(unsigned newvalue) const
|
||||
{
|
||||
if(graph_)
|
||||
return (((graph_->width() - border * 2) * newvalue / max_) != draw_width_);
|
||||
return false;
|
||||
}
|
||||
//end class drawer
|
||||
}//end namespace progress
|
||||
}//end namespace drawerbase
|
||||
|
||||
//class progress
|
||||
progress::progress(){}
|
||||
|
||||
progress::progress(window wd, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
}
|
||||
|
||||
progress::progress(window wd, const rectangle & r, bool visible)
|
||||
{
|
||||
create(wd, r, visible);
|
||||
}
|
||||
|
||||
unsigned progress::value() const
|
||||
{
|
||||
return get_drawer_trigger().value();
|
||||
}
|
||||
|
||||
unsigned progress::value(unsigned val)
|
||||
{
|
||||
internal_scope_guard isg;
|
||||
if(API::empty_window(this->handle()) == false)
|
||||
return get_drawer_trigger().value(val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned progress::inc()
|
||||
{
|
||||
internal_scope_guard isg;
|
||||
return get_drawer_trigger().inc();
|
||||
}
|
||||
|
||||
unsigned progress::amount() const
|
||||
{
|
||||
return get_drawer_trigger().Max();
|
||||
}
|
||||
|
||||
unsigned progress::amount(unsigned value)
|
||||
{
|
||||
return get_drawer_trigger().Max(value);
|
||||
}
|
||||
|
||||
void progress::unknown(bool enb)
|
||||
{
|
||||
get_drawer_trigger().unknown(enb);
|
||||
}
|
||||
|
||||
bool progress::unknown() const
|
||||
{
|
||||
return get_drawer_trigger().unknown();
|
||||
}
|
||||
//end class progress
|
||||
}//end namespace nana
|
||||
341
source/gui/widgets/scroll.cpp
Normal file
341
source/gui/widgets/scroll.cpp
Normal file
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* A Scroll Implementation
|
||||
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: nana/gui/widgets/scroll.cpp
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/scroll.hpp>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
namespace drawerbase
|
||||
{
|
||||
namespace scroll
|
||||
{
|
||||
//struct metrics_type
|
||||
metrics_type::metrics_type()
|
||||
:peak(1), range(1), step(1), value(0),
|
||||
what(buttons::none), pressed(false), scroll_length(0), scroll_pos(0)
|
||||
{}
|
||||
//end struct metrics_type
|
||||
|
||||
//class drawer
|
||||
drawer::drawer(metrics_type& m)
|
||||
:metrics_(m)
|
||||
{}
|
||||
|
||||
void drawer::set_vertical(bool v)
|
||||
{
|
||||
vertical_ = v;
|
||||
}
|
||||
|
||||
buttons drawer::what(graph_reference graph, const point& screen_pos)
|
||||
{
|
||||
unsigned scale;
|
||||
int pos;
|
||||
|
||||
if(vertical_)
|
||||
{
|
||||
scale = graph.height();
|
||||
pos = screen_pos.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
scale = graph.width();
|
||||
pos = screen_pos.x;
|
||||
}
|
||||
|
||||
if(scale >= fixedsize * 2)
|
||||
{
|
||||
if(pos < static_cast<int>(fixedsize))
|
||||
return buttons::first;
|
||||
if(pos > static_cast<int>(scale - fixedsize))
|
||||
return buttons::second;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(pos < static_cast<int>(scale / 2))
|
||||
return buttons::first;
|
||||
if(pos > static_cast<int>(scale / 2))
|
||||
return buttons::second;
|
||||
}
|
||||
|
||||
if(metrics_.scroll_length)
|
||||
{
|
||||
if(metrics_.scroll_pos + static_cast<int>(fixedsize) <= pos && pos < metrics_.scroll_pos + static_cast<int>(fixedsize + metrics_.scroll_length))
|
||||
return buttons::scroll;
|
||||
}
|
||||
|
||||
if(static_cast<int>(fixedsize) <= pos && pos < metrics_.scroll_pos)
|
||||
return buttons::forward;
|
||||
else if(metrics_.scroll_pos + static_cast<int>(metrics_.scroll_length) <= pos && pos < static_cast<int>(scale - fixedsize))
|
||||
return buttons::backward;
|
||||
|
||||
return buttons::none;
|
||||
}
|
||||
|
||||
void drawer::scroll_delta_pos(graph_reference graph, int mouse_pos)
|
||||
{
|
||||
if(mouse_pos + metrics_.scroll_mouse_offset == metrics_.scroll_pos) return;
|
||||
|
||||
unsigned scale = vertical_ ? graph.height() : graph.width();
|
||||
|
||||
if(scale > fixedsize * 2)
|
||||
{
|
||||
int pos = mouse_pos - metrics_.scroll_mouse_offset;
|
||||
const unsigned scroll_area = static_cast<unsigned>(scale - fixedsize * 2 - metrics_.scroll_length);
|
||||
|
||||
if(pos < 0)
|
||||
pos = 0;
|
||||
else if(pos > static_cast<int>(scroll_area))
|
||||
pos = static_cast<int>(scroll_area);
|
||||
|
||||
metrics_.scroll_pos = pos;
|
||||
auto value_max = metrics_.peak - metrics_.range;
|
||||
metrics_.value = pos * value_max / scroll_area;
|
||||
if(metrics_.value < metrics_.peak - metrics_.range)
|
||||
{
|
||||
int selfpos = static_cast<int>(metrics_.value * scroll_area / value_max);
|
||||
int nextpos = static_cast<int>((metrics_.value + 1) * scroll_area / value_max);
|
||||
|
||||
if(selfpos != nextpos && (pos - selfpos > nextpos - pos))
|
||||
++metrics_.value;
|
||||
}
|
||||
else
|
||||
metrics_.value = value_max;
|
||||
}
|
||||
}
|
||||
|
||||
void drawer::auto_scroll()
|
||||
{
|
||||
if(_m_check())
|
||||
{
|
||||
if(buttons::forward == metrics_.what)
|
||||
{ //backward
|
||||
if(metrics_.value <= metrics_.range)
|
||||
metrics_.value = 0;
|
||||
else
|
||||
metrics_.value -= metrics_.range;
|
||||
}
|
||||
else if(buttons::backward == metrics_.what)
|
||||
{
|
||||
if(metrics_.peak - metrics_.range - metrics_.value <= metrics_.range)
|
||||
metrics_.value = metrics_.peak - metrics_.range;
|
||||
else
|
||||
metrics_.value += metrics_.range;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawer::draw(graph_reference graph, buttons what)
|
||||
{
|
||||
if(false == metrics_.pressed || metrics_.what != buttons::scroll)
|
||||
_m_adjust_scroll(graph);
|
||||
|
||||
_m_background(graph);
|
||||
|
||||
unsigned width, height;
|
||||
int x, y;
|
||||
if(vertical_)
|
||||
{
|
||||
x = 0;
|
||||
y = graph.height() - fixedsize;
|
||||
width = graph.width();
|
||||
height = fixedsize;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = graph.width() - fixedsize;
|
||||
y = 0;
|
||||
width = fixedsize;
|
||||
height = graph.height();
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
//draw second
|
||||
_m_draw_button(graph, x, y, width, height, buttons::second, (buttons::second == what ? moused_state : state));
|
||||
|
||||
//draw scroll
|
||||
_m_draw_scroll(graph, (buttons::scroll == what ? moused_state : states::highlight));
|
||||
|
||||
}
|
||||
//private:
|
||||
void drawer::_m_background(graph_reference graph)
|
||||
{
|
||||
graph.rectangle(0xF0F0F0, true);
|
||||
|
||||
if(metrics_.pressed && _m_check())
|
||||
{
|
||||
int x = 0, y = 0;
|
||||
unsigned width = graph.width(), height = graph.height();
|
||||
|
||||
if(metrics_.what == buttons::forward)
|
||||
{
|
||||
*(vertical_ ? &y : &x) = fixedsize;
|
||||
*(vertical_ ? &height: &width) = metrics_.scroll_pos;
|
||||
}
|
||||
else if(buttons::backward == metrics_.what)
|
||||
{
|
||||
*(vertical_ ? &y : &x) = static_cast<int>(fixedsize + metrics_.scroll_pos + metrics_.scroll_length);
|
||||
*(vertical_ ? &height: &width) = static_cast<unsigned>((vertical_ ? graph.height() : graph.width()) - (fixedsize * 2 + metrics_.scroll_pos + metrics_.scroll_length));
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
if(width && height)
|
||||
graph.rectangle(x, y, width, height, 0xDCDCDC, true);
|
||||
}
|
||||
}
|
||||
|
||||
void drawer::_m_button_frame(graph_reference graph, int x, int y, unsigned width, unsigned height, int state)
|
||||
{
|
||||
if(state)
|
||||
{
|
||||
unsigned color = 0x979797; //highlight
|
||||
switch(state)
|
||||
{
|
||||
case states::actived:
|
||||
color = 0x86D5FD; break;
|
||||
case states::selected:
|
||||
color = 0x3C7FB1; break;
|
||||
}
|
||||
|
||||
graph.rectangle(rectangle(x, y, width, height), color, false);
|
||||
|
||||
unsigned color_x = graph.mix(color, 0xFFFFFF, 0.5);
|
||||
|
||||
x += 2;
|
||||
y += 2;
|
||||
width -= 4;
|
||||
height -= 4;
|
||||
|
||||
if(vertical_)
|
||||
{
|
||||
unsigned half = width / 2;
|
||||
graph.rectangle(x + (width - half), y, half, height, color_x, true);
|
||||
width -= half;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned half = height / 2;
|
||||
graph.rectangle(x, y + height - half, width, half, color_x, true);
|
||||
height -= half;
|
||||
}
|
||||
graph.shadow_rectangle(x, y, width, height, 0xFFFFFF, color_x, !vertical_);
|
||||
}
|
||||
}
|
||||
|
||||
bool drawer::_m_check() const
|
||||
{
|
||||
return (metrics_.scroll_length && metrics_.range && (metrics_.peak > metrics_.range));
|
||||
}
|
||||
|
||||
void drawer::_m_adjust_scroll(graph_reference graph)
|
||||
{
|
||||
if(metrics_.range == 0 || metrics_.peak <= metrics_.range) return;
|
||||
|
||||
unsigned pixels = vertical_ ? graph.height() : graph.width();
|
||||
|
||||
int pos = 0;
|
||||
unsigned len = 0;
|
||||
|
||||
if(pixels > fixedsize * 2)
|
||||
{
|
||||
pixels -= (fixedsize * 2);
|
||||
len = static_cast<unsigned>(pixels * metrics_.range / metrics_.peak);
|
||||
|
||||
if(len < fixedsize)
|
||||
len = fixedsize;
|
||||
|
||||
if(metrics_.value)
|
||||
{
|
||||
pos = static_cast<int>(pixels - len);
|
||||
if(metrics_.value + metrics_.range >= metrics_.peak)
|
||||
metrics_.value = metrics_.peak - metrics_.range;
|
||||
else
|
||||
pos = static_cast<int>((metrics_.value * pos) /(metrics_.peak - metrics_.range));
|
||||
}
|
||||
}
|
||||
|
||||
metrics_.scroll_pos = pos;
|
||||
metrics_.scroll_length = len;
|
||||
}
|
||||
|
||||
void drawer::_m_draw_scroll(graph_reference graph, int state)
|
||||
{
|
||||
if(_m_check())
|
||||
{
|
||||
int x, y;
|
||||
unsigned width, height;
|
||||
|
||||
if(vertical_)
|
||||
{
|
||||
x = 0;
|
||||
y = fixedsize + metrics_.scroll_pos;
|
||||
|
||||
width = graph.width();
|
||||
height = static_cast<unsigned>(metrics_.scroll_length);
|
||||
}
|
||||
else
|
||||
{
|
||||
x = fixedsize + metrics_.scroll_pos;
|
||||
y = 0;
|
||||
|
||||
width = static_cast<unsigned>(metrics_.scroll_length);
|
||||
height = graph.height();
|
||||
}
|
||||
|
||||
_m_button_frame(graph, x, y, width, height, state);
|
||||
}
|
||||
}
|
||||
|
||||
void drawer::_m_draw_button(graph_reference graph, int x, int y, unsigned width, unsigned height, buttons what, int state)
|
||||
{
|
||||
if(_m_check())
|
||||
_m_button_frame(graph, x, y, width, height, state);
|
||||
|
||||
using namespace nana::paint::gadget;
|
||||
|
||||
if(buttons::first == what || buttons::second == what)
|
||||
{
|
||||
nana::size sz = graph.size();
|
||||
directions::t dir;
|
||||
if(buttons::second == what)
|
||||
{
|
||||
if(vertical_)
|
||||
{
|
||||
y = static_cast<int>(sz.height - fixedsize);
|
||||
dir = directions::to_south;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = static_cast<int>(sz.width - fixedsize);
|
||||
dir = directions::to_east;
|
||||
}
|
||||
}
|
||||
else
|
||||
dir = vertical_ ? directions::to_north : directions::to_west;
|
||||
|
||||
if(vertical_)
|
||||
x = (static_cast<int>(sz.width) - 16) / 2;
|
||||
else
|
||||
y = (static_cast<int>(sz.height) - 16) / 2;
|
||||
|
||||
arrow_16_pixels(graph, x, y, _m_check() ? 0x0 : 0x808080, (states::none == state ? 0 : 1), dir);
|
||||
}
|
||||
}
|
||||
//end class drawer
|
||||
}//end namespace scroll
|
||||
}//end namespace drawerbase
|
||||
}//end namespace nana
|
||||
|
||||
2845
source/gui/widgets/skeletons/text_editor.cpp
Normal file
2845
source/gui/widgets/skeletons/text_editor.cpp
Normal file
File diff suppressed because it is too large
Load Diff
788
source/gui/widgets/slider.cpp
Normal file
788
source/gui/widgets/slider.cpp
Normal file
@@ -0,0 +1,788 @@
|
||||
|
||||
#include <nana/gui/widgets/slider.hpp>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
virtual void slider(window, graph_reference graph, const slider_t& s)
|
||||
{
|
||||
nana::rectangle r = graph.size();
|
||||
if(s.horizontal)
|
||||
{
|
||||
r.x = s.pos;
|
||||
r.width = s.scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
r.y = s.pos;
|
||||
r.height = s.scale;
|
||||
}
|
||||
graph.round_rectangle(r, 3, 3, 0x0, true, 0xF0F0F0);
|
||||
}
|
||||
};
|
||||
|
||||
class controller
|
||||
{
|
||||
public:
|
||||
enum dir_t{DirHorizontal, DirVertical};
|
||||
enum where_t{WhereNone, WhereBar, WhereSlider};
|
||||
|
||||
typedef drawer_trigger::graph_reference graph_reference;
|
||||
|
||||
controller()
|
||||
{
|
||||
other_.wd = nullptr;
|
||||
other_.widget = nullptr;
|
||||
other_.graph = nullptr;
|
||||
|
||||
proto_.renderer = pat::cloneable<renderer>(interior_renderer());
|
||||
|
||||
attr_.skdir = seekdir::bilateral;
|
||||
attr_.dir = this->DirHorizontal;
|
||||
attr_.vcur = 0;
|
||||
attr_.vmax = 10;
|
||||
attr_.slider_scale = 8;
|
||||
attr_.border = 1;
|
||||
attr_.is_draw_adorn = false;
|
||||
}
|
||||
|
||||
void seek(seekdir sd)
|
||||
{
|
||||
attr_.skdir = sd;
|
||||
}
|
||||
|
||||
window handle() const
|
||||
{
|
||||
return other_.wd;
|
||||
}
|
||||
|
||||
void attached(nana::slider& wd, graph_reference graph)
|
||||
{
|
||||
other_.wd = wd.handle();
|
||||
other_.widget = &wd;
|
||||
|
||||
other_.graph = &graph;
|
||||
_m_mk_slider_pos_by_value();
|
||||
}
|
||||
|
||||
void detached()
|
||||
{
|
||||
other_.graph = nullptr;
|
||||
}
|
||||
|
||||
pat::cloneable<renderer>& ext_renderer()
|
||||
{
|
||||
return proto_.renderer;
|
||||
}
|
||||
|
||||
void ext_renderer(const pat::cloneable<renderer>& rd)
|
||||
{
|
||||
proto_.renderer = rd;
|
||||
}
|
||||
|
||||
void ext_provider(const pat::cloneable<provider>& pd)
|
||||
{
|
||||
proto_.provider = pd;
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
if(other_.graph && !other_.graph->size().empty())
|
||||
{
|
||||
bool is_transparent = (bground_mode::basic == API::effects_bground_mode(other_.wd));
|
||||
proto_.renderer->background(other_.wd, *other_.graph, is_transparent);
|
||||
_m_draw_objects();
|
||||
}
|
||||
}
|
||||
|
||||
void vertical(bool v)
|
||||
{
|
||||
dir_t dir = (v ? this->DirVertical : this->DirHorizontal);
|
||||
|
||||
if(dir != attr_.dir)
|
||||
{
|
||||
attr_.dir = dir;
|
||||
this->draw();
|
||||
}
|
||||
}
|
||||
|
||||
bool vertical() const
|
||||
{
|
||||
return (this->DirVertical == attr_.dir);
|
||||
}
|
||||
|
||||
void vmax(unsigned m)
|
||||
{
|
||||
if(m == 0) m = 1;
|
||||
|
||||
if(attr_.vmax != m)
|
||||
{
|
||||
attr_.vmax = m;
|
||||
if(attr_.vcur > m)
|
||||
{
|
||||
attr_.vcur = m;
|
||||
_m_emit_value_changed();
|
||||
}
|
||||
|
||||
_m_mk_slider_pos_by_value();
|
||||
draw();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned vmax() const
|
||||
{
|
||||
return attr_.vmax;
|
||||
}
|
||||
|
||||
void vcur(unsigned v)
|
||||
{
|
||||
if(attr_.vmax < v)
|
||||
v = attr_.vmax;
|
||||
|
||||
if(attr_.vcur != v)
|
||||
{
|
||||
attr_.vcur = v;
|
||||
this->_m_mk_slider_pos_by_value();
|
||||
draw();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned vcur() const
|
||||
{
|
||||
return attr_.vcur;
|
||||
}
|
||||
|
||||
void resize()
|
||||
{
|
||||
this->_m_mk_slider_pos_by_value();
|
||||
attr_.adorn_pos = attr_.pos;
|
||||
}
|
||||
|
||||
where_t seek_where(int x, int y) const
|
||||
{
|
||||
nana::rectangle r = _m_bar_area();
|
||||
if(attr_.dir == this->DirVertical)
|
||||
{
|
||||
std::swap(x, y);
|
||||
std::swap(r.width, r.height);
|
||||
}
|
||||
|
||||
int pos = _m_slider_pos();
|
||||
if(pos <= x && x < pos + static_cast<int>(attr_.slider_scale))
|
||||
return WhereSlider;
|
||||
|
||||
pos = static_cast<int>(attr_.slider_scale) / 2;
|
||||
|
||||
if(pos <= x && x < pos + static_cast<int>(r.width))
|
||||
{
|
||||
if(y < r.y + static_cast<int>(r.height))
|
||||
return WhereBar;
|
||||
}
|
||||
return WhereNone;
|
||||
}
|
||||
|
||||
//set_slider_pos
|
||||
//move the slider to a position where a mouse click on WhereBar.
|
||||
bool set_slider_pos(int x, int y)
|
||||
{
|
||||
if(this->DirVertical == attr_.dir)
|
||||
std::swap(x, y);
|
||||
|
||||
x -= _m_slider_refpos();
|
||||
if(x < 0)
|
||||
return false;
|
||||
|
||||
if(x > static_cast<int>(_m_scale()))
|
||||
x = static_cast<int>(_m_scale());
|
||||
|
||||
double pos = attr_.pos;
|
||||
double dx = _m_evaluate_by_seekdir(x);
|
||||
|
||||
attr_.pos = dx;
|
||||
attr_.adorn_pos = dx;
|
||||
_m_mk_slider_value_by_pos();
|
||||
|
||||
return (attr_.pos != pos);
|
||||
}
|
||||
|
||||
void set_slider_refpos(::nana::point pos)
|
||||
{
|
||||
if(this->DirVertical == attr_.dir)
|
||||
std::swap(pos.x, pos.y);
|
||||
|
||||
slider_state_.trace = slider_state_.TraceCapture;
|
||||
slider_state_.snap_pos = static_cast<int>(attr_.pos);
|
||||
slider_state_.refpos = pos;
|
||||
API::capture_window(other_.wd, true);
|
||||
}
|
||||
|
||||
bool release_slider()
|
||||
{
|
||||
if(slider_state_.trace == slider_state_.TraceCapture)
|
||||
{
|
||||
API::capture_window(other_.wd, false);
|
||||
if(other_.wd != API::find_window(API::cursor_position()))
|
||||
{
|
||||
slider_state_.trace = slider_state_.TraceNone;
|
||||
attr_.is_draw_adorn = false;
|
||||
}
|
||||
else
|
||||
slider_state_.trace = slider_state_.TraceOver;
|
||||
|
||||
_m_mk_slider_value_by_pos();
|
||||
_m_mk_slider_pos_by_value();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool if_trace_slider() const
|
||||
{
|
||||
return (slider_state_.trace == slider_state_.TraceCapture);
|
||||
}
|
||||
|
||||
bool move_slider(int x, int y)
|
||||
{
|
||||
int mpos = (this->DirHorizontal == attr_.dir ? x : y);
|
||||
int pos = slider_state_.snap_pos + (mpos - slider_state_.refpos.x);
|
||||
|
||||
if(pos > 0)
|
||||
{
|
||||
int scale = static_cast<int>(_m_scale());
|
||||
if(pos > scale)
|
||||
pos = scale;
|
||||
}
|
||||
else
|
||||
pos = 0;
|
||||
|
||||
double dstpos = _m_evaluate_by_seekdir(pos);
|
||||
attr_.is_draw_adorn = true;
|
||||
|
||||
if(dstpos != attr_.pos)
|
||||
{
|
||||
attr_.pos = dstpos;
|
||||
attr_.adorn_pos = dstpos;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool move_adorn(int x, int y)
|
||||
{
|
||||
double xpos = (this->DirHorizontal == attr_.dir ? x : y);
|
||||
|
||||
xpos -= _m_slider_refpos();
|
||||
if(xpos > static_cast<int>(_m_scale()))
|
||||
xpos = static_cast<int>(_m_scale());
|
||||
|
||||
int pos = static_cast<int>(attr_.adorn_pos);
|
||||
xpos = _m_evaluate_by_seekdir(xpos);
|
||||
|
||||
attr_.adorn_pos = xpos;
|
||||
attr_.is_draw_adorn = true;
|
||||
|
||||
if(slider_state_.trace == slider_state_.TraceNone)
|
||||
slider_state_.trace = slider_state_.TraceOver;
|
||||
|
||||
return (pos != static_cast<int>(xpos));
|
||||
}
|
||||
|
||||
unsigned move_step(bool forward)
|
||||
{
|
||||
unsigned cmpvalue = attr_.vcur;
|
||||
if(forward)
|
||||
{
|
||||
if(attr_.vcur)
|
||||
--attr_.vcur;
|
||||
}
|
||||
else if(attr_.vcur < attr_.vmax)
|
||||
++attr_.vcur;
|
||||
|
||||
if(cmpvalue != attr_.vcur)
|
||||
{
|
||||
_m_mk_slider_pos_by_value();
|
||||
draw();
|
||||
_m_emit_value_changed();
|
||||
}
|
||||
|
||||
return cmpvalue;
|
||||
}
|
||||
|
||||
unsigned adorn() const
|
||||
{
|
||||
return _m_value_by_pos(attr_.adorn_pos);
|
||||
}
|
||||
|
||||
bool reset_adorn()
|
||||
{
|
||||
//Test if the slider is captured, the operation should be ignored. Because the mouse_leave always be generated even through
|
||||
//the slider is captured.
|
||||
if(slider_state_.trace == slider_state_.TraceCapture && (nana::API::capture_window() == this->other_.wd))
|
||||
return false;
|
||||
|
||||
slider_state_.trace = slider_state_.TraceNone;
|
||||
attr_.is_draw_adorn = false;
|
||||
if(attr_.adorn_pos != attr_.pos)
|
||||
{
|
||||
attr_.adorn_pos = attr_.pos;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
void _m_emit_value_changed() const
|
||||
{
|
||||
other_.widget->events().value_changed.emit(::nana::arg_slider{ *other_.widget });
|
||||
}
|
||||
|
||||
nana::rectangle _m_bar_area() const
|
||||
{
|
||||
auto sz = other_.graph->size();
|
||||
nana::rectangle r = sz;
|
||||
if(this->DirHorizontal == attr_.dir)
|
||||
{
|
||||
r.x = attr_.slider_scale / 2 - attr_.border;
|
||||
r.width = (static_cast<int>(sz.width) > (r.x << 1) ? sz.width - (r.x << 1) : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
r.y = attr_.slider_scale / 2 - attr_.border;
|
||||
r.height = (static_cast<int>(sz.height) > (r.y << 1) ? sz.height - (r.y << 1) : 0);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
unsigned _m_scale() const
|
||||
{
|
||||
nana::rectangle r = _m_bar_area();
|
||||
return ((this->DirHorizontal == attr_.dir ? r.width : r.height) - attr_.border * 2);
|
||||
}
|
||||
|
||||
double _m_evaluate_by_seekdir(double pos) const
|
||||
{
|
||||
switch(attr_.skdir)
|
||||
{
|
||||
case seekdir::backward:
|
||||
if(pos < attr_.pos)
|
||||
pos = attr_.pos;
|
||||
break;
|
||||
case seekdir::forward:
|
||||
if(pos > attr_.pos)
|
||||
pos = attr_.pos;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
int _m_slider_refpos() const
|
||||
{
|
||||
return static_cast<int>(attr_.slider_scale / 2);
|
||||
}
|
||||
|
||||
int _m_slider_pos() const
|
||||
{
|
||||
return static_cast<int>(_m_scale() * attr_.vcur / attr_.vmax);
|
||||
}
|
||||
|
||||
unsigned _m_mk_slider_value_by_pos()
|
||||
{
|
||||
if(_m_scale())
|
||||
{
|
||||
auto cmpvalue = attr_.vcur;
|
||||
attr_.vcur = static_cast<unsigned>(attr_.pos * attr_.vmax / _m_scale());
|
||||
if (cmpvalue != attr_.vcur)
|
||||
_m_emit_value_changed();
|
||||
}
|
||||
return attr_.vcur;
|
||||
}
|
||||
|
||||
int _m_mk_slider_pos_by_value()
|
||||
{
|
||||
attr_.pos = double(_m_scale()) * attr_.vcur / attr_.vmax;
|
||||
|
||||
if(slider_state_.trace == slider_state_.TraceNone)
|
||||
attr_.adorn_pos = attr_.pos;
|
||||
|
||||
return static_cast<int>(attr_.pos);
|
||||
}
|
||||
|
||||
unsigned _m_value_by_pos(double pos) const
|
||||
{
|
||||
if(_m_scale())
|
||||
return static_cast<int>(pos * attr_.vmax / _m_scale());
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _m_draw_objects()
|
||||
{
|
||||
renderer::bar_t bar;
|
||||
|
||||
bar.horizontal = (this->DirHorizontal == attr_.dir);
|
||||
bar.border_size = attr_.border;
|
||||
bar.r = _m_bar_area();
|
||||
|
||||
if (bar.r.empty())
|
||||
return;
|
||||
|
||||
proto_.renderer->bar(other_.wd, *other_.graph, bar);
|
||||
|
||||
//adorn
|
||||
renderer::adorn_t adorn;
|
||||
adorn.horizontal = bar.horizontal;
|
||||
adorn.bound.x = (bar.horizontal ? bar.r.x : bar.r.y) + attr_.border;
|
||||
adorn.bound.y = adorn.bound.x + static_cast<int>(attr_.adorn_pos);
|
||||
adorn.vcur_scale = static_cast<unsigned>(attr_.pos);
|
||||
adorn.block = (bar.horizontal ? bar.r.height : bar.r.width) - attr_.border * 2;
|
||||
adorn.fixedpos = static_cast<int>((bar.horizontal ? bar.r.y : bar.r.x) + attr_.border);
|
||||
|
||||
proto_.renderer->adorn(other_.wd, *other_.graph, adorn);
|
||||
|
||||
_m_draw_slider();
|
||||
|
||||
//adorn textbox
|
||||
if(proto_.provider && attr_.is_draw_adorn)
|
||||
{
|
||||
unsigned vadorn = _m_value_by_pos(attr_.adorn_pos);
|
||||
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;
|
||||
|
||||
const int room = static_cast<int>(attr_.adorn_pos);
|
||||
if(bar.horizontal)
|
||||
{
|
||||
r.y = adorn.fixedpos + static_cast<int>(adorn.block - ts.height) / 2;
|
||||
if(room > static_cast<int>(ts.width + 2))
|
||||
r.x = room - static_cast<int>(ts.width + 2);
|
||||
else
|
||||
r.x = room + 2;
|
||||
|
||||
r.x += this->_m_slider_refpos();
|
||||
}
|
||||
else
|
||||
{
|
||||
r.x = (other_.graph->width() - ts.width) / 2;
|
||||
if(room > static_cast<int>(ts.height + 2))
|
||||
r.y = room - static_cast<int>(ts.height + 2);
|
||||
else
|
||||
r.y = room + 2;
|
||||
r.y += this->_m_slider_refpos();
|
||||
}
|
||||
proto_.renderer->adorn_textbox(other_.wd, *other_.graph, str, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _m_draw_slider()
|
||||
{
|
||||
renderer::slider_t s;
|
||||
s.pos = static_cast<int>(attr_.pos);
|
||||
s.horizontal = (this->DirHorizontal == attr_.dir);
|
||||
s.scale = attr_.slider_scale;
|
||||
s.border = attr_.border;
|
||||
proto_.renderer->slider(other_.wd, *other_.graph, s);
|
||||
}
|
||||
private:
|
||||
struct other_tag
|
||||
{
|
||||
window wd;
|
||||
nana::slider * widget;
|
||||
paint::graphics * graph;
|
||||
}other_;
|
||||
|
||||
struct prototype_tag
|
||||
{
|
||||
pat::cloneable<slider::renderer> renderer;
|
||||
pat::cloneable<slider::provider> provider;
|
||||
}proto_;
|
||||
|
||||
struct attr_tag
|
||||
{
|
||||
seekdir skdir;
|
||||
dir_t dir;
|
||||
unsigned border;
|
||||
unsigned vmax;
|
||||
unsigned vcur;
|
||||
double pos;
|
||||
bool is_draw_adorn;
|
||||
double adorn_pos;
|
||||
unsigned slider_scale;
|
||||
}attr_;
|
||||
|
||||
struct slider_state_tag
|
||||
{
|
||||
enum t{TraceNone, TraceOver, TraceCapture};
|
||||
|
||||
t trace; //true if the mouse press on slider.
|
||||
int snap_pos;
|
||||
nana::point refpos; //a point for slider when the mouse was clicking on slider.
|
||||
|
||||
slider_state_tag(): trace(TraceNone){}
|
||||
}slider_state_;
|
||||
};
|
||||
|
||||
//class trigger
|
||||
trigger::trigger()
|
||||
: impl_(new controller_t)
|
||||
{}
|
||||
|
||||
trigger::~trigger()
|
||||
{
|
||||
delete impl_;
|
||||
}
|
||||
|
||||
trigger::controller_t* trigger::ctrl() const
|
||||
{
|
||||
return impl_;
|
||||
}
|
||||
|
||||
void trigger::attached(widget_reference widget, graph_reference graph)
|
||||
{
|
||||
impl_->attached(static_cast<nana::slider&>(widget), graph);
|
||||
}
|
||||
|
||||
void trigger::detached()
|
||||
{
|
||||
impl_->detached();
|
||||
}
|
||||
|
||||
void trigger::refresh(graph_reference)
|
||||
{
|
||||
impl_->draw();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
bool mkdir = impl_->set_slider_pos(arg.pos.x, arg.pos.y);
|
||||
impl_->set_slider_refpos(arg.pos);
|
||||
if(mkdir)
|
||||
{
|
||||
impl_->draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void trigger::mouse_up(graph_reference, const arg_mouse&)
|
||||
{
|
||||
bool mkdraw = impl_->release_slider();
|
||||
if(mkdraw)
|
||||
{
|
||||
impl_->draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void trigger::mouse_move(graph_reference, const arg_mouse& arg)
|
||||
{
|
||||
bool mkdraw = false;
|
||||
if(impl_->if_trace_slider())
|
||||
{
|
||||
mkdraw = impl_->move_slider(arg.pos.x, arg.pos.y);
|
||||
}
|
||||
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);
|
||||
else
|
||||
mkdraw = impl_->reset_adorn();
|
||||
}
|
||||
|
||||
if(mkdraw)
|
||||
{
|
||||
impl_->draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void trigger::mouse_leave(graph_reference, const arg_mouse&)
|
||||
{
|
||||
if(impl_->reset_adorn())
|
||||
{
|
||||
impl_->draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void trigger::resized(graph_reference, const arg_resized&)
|
||||
{
|
||||
impl_->resize();
|
||||
impl_->draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
//end class trigger
|
||||
}//end namespace slider
|
||||
}//end namespace drawerbase
|
||||
|
||||
//class slider
|
||||
slider::slider(){}
|
||||
|
||||
slider::slider(window wd, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
}
|
||||
|
||||
slider::slider(window wd, const rectangle& r, bool visible)
|
||||
{
|
||||
create(wd, r, visible);
|
||||
}
|
||||
|
||||
void slider::seek(slider::seekdir sd)
|
||||
{
|
||||
get_drawer_trigger().ctrl()->seek(sd);
|
||||
}
|
||||
|
||||
void slider::vertical(bool v)
|
||||
{
|
||||
get_drawer_trigger().ctrl()->vertical(v);
|
||||
API::update_window(this->handle());
|
||||
}
|
||||
|
||||
bool slider::vertical() const
|
||||
{
|
||||
return get_drawer_trigger().ctrl()->vertical();
|
||||
}
|
||||
|
||||
void slider::vmax(unsigned m)
|
||||
{
|
||||
if(this->handle())
|
||||
{
|
||||
get_drawer_trigger().ctrl()->vmax(m);
|
||||
API::update_window(handle());
|
||||
}
|
||||
}
|
||||
|
||||
unsigned slider::vmax() const
|
||||
{
|
||||
if(handle())
|
||||
return get_drawer_trigger().ctrl()->vmax();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void slider::value(unsigned v)
|
||||
{
|
||||
if(handle())
|
||||
{
|
||||
get_drawer_trigger().ctrl()->vcur(v);
|
||||
API::update_window(handle());
|
||||
}
|
||||
}
|
||||
|
||||
unsigned slider::value() const
|
||||
{
|
||||
if(handle())
|
||||
return get_drawer_trigger().ctrl()->vcur();
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned slider::move_step(bool forward)
|
||||
{
|
||||
if(handle())
|
||||
{
|
||||
drawerbase::slider::controller* ctrl = this->get_drawer_trigger().ctrl();
|
||||
unsigned val = ctrl->move_step(forward);
|
||||
if(val != ctrl->vcur())
|
||||
API::update_window(handle());
|
||||
return val;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned slider::adorn() const
|
||||
{
|
||||
if(empty()) return 0;
|
||||
return get_drawer_trigger().ctrl()->adorn();
|
||||
}
|
||||
|
||||
pat::cloneable<slider::renderer>& slider::ext_renderer()
|
||||
{
|
||||
return get_drawer_trigger().ctrl()->ext_renderer();
|
||||
}
|
||||
|
||||
void slider::ext_renderer(const pat::cloneable<slider::renderer>& di)
|
||||
{
|
||||
get_drawer_trigger().ctrl()->ext_renderer(di);
|
||||
}
|
||||
|
||||
void slider::ext_provider(const pat::cloneable<slider::provider>& pi)
|
||||
{
|
||||
get_drawer_trigger().ctrl()->ext_provider(pi);
|
||||
}
|
||||
|
||||
void slider::transparent(bool enabled)
|
||||
{
|
||||
if(enabled)
|
||||
API::effects_bground(*this, effects::bground_transparent(0), 0.0);
|
||||
else
|
||||
API::effects_bground_remove(*this);
|
||||
}
|
||||
|
||||
bool slider::transparent() const
|
||||
{
|
||||
return (bground_mode::basic == API::effects_bground_mode(*this));
|
||||
}
|
||||
//end class slider
|
||||
}//end namespace nana
|
||||
1293
source/gui/widgets/tabbar.cpp
Normal file
1293
source/gui/widgets/tabbar.cpp
Normal file
File diff suppressed because it is too large
Load Diff
515
source/gui/widgets/textbox.cpp
Normal file
515
source/gui/widgets/textbox.cpp
Normal file
@@ -0,0 +1,515 @@
|
||||
/*
|
||||
* A Textbox Implementation
|
||||
* 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/widgets/textbox.hpp
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/textbox.hpp>
|
||||
#include <nana/gui/widgets/skeletons/text_editor.hpp>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
|
||||
namespace nana{ namespace drawerbase {
|
||||
namespace textbox
|
||||
{
|
||||
//class event_agent
|
||||
event_agent::event_agent(::nana::textbox& wdg)
|
||||
:widget_(wdg)
|
||||
{}
|
||||
|
||||
void event_agent::first_change()
|
||||
{
|
||||
widget_.events().first_change.emit(::nana::arg_textbox{ widget_ });
|
||||
}
|
||||
//
|
||||
|
||||
//class draweer
|
||||
drawer::drawer()
|
||||
: widget_(nullptr), editor_(nullptr)
|
||||
{
|
||||
status_.has_focus = false;
|
||||
}
|
||||
|
||||
drawer::text_editor* drawer::editor()
|
||||
{
|
||||
return editor_;
|
||||
}
|
||||
|
||||
const drawer::text_editor* drawer::editor() const
|
||||
{
|
||||
return editor_;
|
||||
}
|
||||
|
||||
void drawer::set_accept(std::function<bool(nana::char_t)> && 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);
|
||||
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());
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void drawer::detached()
|
||||
{
|
||||
delete editor_;
|
||||
editor_ = nullptr;
|
||||
}
|
||||
|
||||
void drawer::refresh(graph_reference graph)
|
||||
{
|
||||
editor_->render(status_.has_focus);
|
||||
}
|
||||
|
||||
void drawer::focus(graph_reference graph, const arg_focus& arg)
|
||||
{
|
||||
status_.has_focus = arg.getting;
|
||||
refresh(graph);
|
||||
|
||||
editor_->show_caret(status_.has_focus);
|
||||
editor_->reset_caret();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void drawer::mouse_down(graph_reference, const arg_mouse& arg)
|
||||
{
|
||||
if(editor_->mouse_down(arg.left_button, arg.pos))
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void drawer::mouse_move(graph_reference, const arg_mouse& arg)
|
||||
{
|
||||
if(editor_->mouse_move(arg.left_button, arg.pos))
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void drawer::mouse_up(graph_reference graph, const arg_mouse& arg)
|
||||
{
|
||||
if(editor_->mouse_up(arg.left_button, arg.pos))
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void drawer::mouse_wheel(graph_reference, const arg_wheel& arg)
|
||||
{
|
||||
if(editor_->scroll(arg.upwards, true))
|
||||
{
|
||||
editor_->reset_caret();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void drawer::mouse_enter(graph_reference, const arg_mouse&)
|
||||
{
|
||||
if(editor_->mouse_enter(true))
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void drawer::mouse_leave(graph_reference, const arg_mouse&)
|
||||
{
|
||||
if(editor_->mouse_enter(false))
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void drawer::key_press(graph_reference, const arg_keyboard& arg)
|
||||
{
|
||||
if(editor_->move(arg.key))
|
||||
{
|
||||
editor_->reset_caret();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void drawer::resized(graph_reference graph, const arg_resized& arg)
|
||||
{
|
||||
_m_text_area(arg.width, arg.height);
|
||||
refresh(graph);
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void drawer::typeface_changed(graph_reference graph)
|
||||
{
|
||||
editor_->typeface_changed();
|
||||
refresh(graph);
|
||||
API::update_window(widget_->handle());
|
||||
}
|
||||
|
||||
void drawer::_m_text_area(unsigned width, unsigned height)
|
||||
{
|
||||
if(editor_)
|
||||
{
|
||||
nana::rectangle r(0, 0, width, height);
|
||||
|
||||
if (!API::widget_borderless(widget_->handle()))
|
||||
{
|
||||
r.x = r.y = 2;
|
||||
r.width = (width > 4 ? width - 4 : 0);
|
||||
r.height = (height > 4 ? height - 4 : 0);
|
||||
}
|
||||
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
|
||||
|
||||
//class textbox
|
||||
textbox::textbox()
|
||||
{}
|
||||
|
||||
textbox::textbox(window wd, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
}
|
||||
|
||||
textbox::textbox(window wd, const nana::string& text, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
caption(text);
|
||||
}
|
||||
|
||||
textbox::textbox(window wd, const nana::char_t* text, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
caption(text);
|
||||
}
|
||||
|
||||
textbox::textbox(window wd, const rectangle& r, bool visible)
|
||||
{
|
||||
create(wd, r, visible);
|
||||
}
|
||||
|
||||
void textbox::load(nana::string file)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if (editor && editor->load(file.data()))
|
||||
API::update_window(handle());
|
||||
}
|
||||
|
||||
void textbox::store(nana::string file)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if (editor)
|
||||
editor->textbase().store(std::move(file));
|
||||
}
|
||||
|
||||
void textbox::store(nana::string file, nana::unicode encoding)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if (editor)
|
||||
editor->textbase().store(std::move(file), encoding);
|
||||
}
|
||||
|
||||
textbox& textbox::reset(nana::string str)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if (editor)
|
||||
{
|
||||
editor->text(std::move(str));
|
||||
editor->textbase().reset();
|
||||
API::update_window(this->handle());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
nana::string textbox::filename() const
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if(editor)
|
||||
return editor->textbase().filename();
|
||||
|
||||
return{};
|
||||
}
|
||||
|
||||
bool textbox::edited() const
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
return (editor ? editor->textbase().edited() : false);
|
||||
}
|
||||
|
||||
textbox& textbox::edited_reset()
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if (editor)
|
||||
editor->textbase().edited_reset();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool textbox::saved() const
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
return (editor ? editor->textbase().saved() : false);
|
||||
}
|
||||
|
||||
bool textbox::getline(std::size_t line_index, nana::string& text) const
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
return (editor ? editor->getline(line_index, text) : false);
|
||||
}
|
||||
|
||||
textbox& textbox::append(const nana::string& text, bool at_caret)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if(editor)
|
||||
{
|
||||
if(at_caret == false)
|
||||
editor->move_caret_end();
|
||||
|
||||
editor->put(text);
|
||||
API::update_window(this->handle());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Determine wheter the text is auto-line changed.
|
||||
bool textbox::line_wrapped() const
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
return get_drawer_trigger().editor()->line_wrapped();
|
||||
}
|
||||
|
||||
textbox& textbox::line_wrapped(bool autl)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if (editor->line_wrapped(autl))
|
||||
editor->render(API::is_focus_window(handle()));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool textbox::multi_lines() const
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
return (editor ? editor->attr().multi_lines : false);
|
||||
}
|
||||
|
||||
textbox& textbox::multi_lines(bool ml)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if(editor && editor->multi_lines(ml))
|
||||
API::update_window(handle());
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool textbox::editable() const
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
return (editor ? editor->attr().editable : false);
|
||||
}
|
||||
|
||||
textbox& textbox::editable(bool able)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if(editor)
|
||||
editor->editable(able);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void textbox::set_accept(std::function<bool(nana::char_t)> fn)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
get_drawer_trigger().set_accept(std::move(fn));
|
||||
}
|
||||
|
||||
textbox& textbox::tip_string(nana::string str)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if(editor && editor->tip_string(std::move(str)))
|
||||
API::refresh_window(handle());
|
||||
return *this;
|
||||
}
|
||||
|
||||
textbox& textbox::mask(nana::char_t ch)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if(editor && editor->mask(ch))
|
||||
API::refresh_window(handle());
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool textbox::selected() const
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
return (editor ? editor->selected() : false);
|
||||
}
|
||||
|
||||
void textbox::select(bool yes)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if(editor && editor->select(yes))
|
||||
API::refresh_window(*this);
|
||||
}
|
||||
|
||||
void textbox::copy() const
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if(editor)
|
||||
editor->copy();
|
||||
}
|
||||
|
||||
void textbox::paste()
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if(editor)
|
||||
{
|
||||
editor->paste();
|
||||
API::refresh_window(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void textbox::del()
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if(editor)
|
||||
{
|
||||
editor->del();
|
||||
API::refresh_window(*this);
|
||||
}
|
||||
}
|
||||
|
||||
int textbox::to_int() const
|
||||
{
|
||||
nana::string s = _m_caption();
|
||||
if (s.empty()) return 0;
|
||||
|
||||
#ifdef NANA_UNICODE
|
||||
std::wstringstream ss;
|
||||
#else
|
||||
std::stringstream ss;
|
||||
#endif
|
||||
int value;
|
||||
ss << s;
|
||||
ss >> value;
|
||||
return value;
|
||||
}
|
||||
|
||||
double textbox::to_double() const
|
||||
{
|
||||
nana::string s = _m_caption();
|
||||
if (s.empty()) return 0;
|
||||
|
||||
#ifdef NANA_UNICODE
|
||||
std::wstringstream ss;
|
||||
#else
|
||||
std::stringstream ss;
|
||||
#endif
|
||||
double value;
|
||||
ss << s;
|
||||
ss >> value;
|
||||
return value;
|
||||
}
|
||||
|
||||
textbox& textbox::from(int n)
|
||||
{
|
||||
#ifdef NANA_UNICODE
|
||||
std::wstringstream ss;
|
||||
#else
|
||||
std::stringstream ss;
|
||||
#endif
|
||||
ss << n;
|
||||
_m_caption(ss.str());
|
||||
return *this;
|
||||
}
|
||||
|
||||
textbox& textbox::from(double d)
|
||||
{
|
||||
#ifdef NANA_UNICODE
|
||||
std::wstringstream ss;
|
||||
#else
|
||||
std::stringstream ss;
|
||||
#endif
|
||||
ss << d;
|
||||
_m_caption(ss.str());
|
||||
return *this;
|
||||
}
|
||||
|
||||
//Override _m_caption for caption()
|
||||
nana::string textbox::_m_caption() const
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
return (editor ? editor->text() : nana::string());
|
||||
}
|
||||
|
||||
void textbox::_m_caption(nana::string&& str)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if (editor)
|
||||
{
|
||||
editor->text(std::move(str));
|
||||
API::update_window(this->handle());
|
||||
}
|
||||
}
|
||||
|
||||
//Override _m_typeface for changing the caret
|
||||
void textbox::_m_typeface(const nana::paint::font& font)
|
||||
{
|
||||
widget::_m_typeface(font);
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if(editor)
|
||||
editor->reset_caret_height();
|
||||
}
|
||||
//end class textbox
|
||||
}//end namespace nana
|
||||
|
||||
514
source/gui/widgets/toolbar.cpp
Normal file
514
source/gui/widgets/toolbar.cpp
Normal file
@@ -0,0 +1,514 @@
|
||||
/*
|
||||
* A Toolbar Implementation
|
||||
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: nana/gui/widgets/toolbar.cpp
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/toolbar.hpp>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <nana/gui/tooltip.hpp>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
namespace drawerbase
|
||||
{
|
||||
namespace toolbar
|
||||
{
|
||||
struct listitem
|
||||
{
|
||||
nana::string text;
|
||||
nana::paint::image image;
|
||||
bool enable;
|
||||
};
|
||||
|
||||
struct item_type
|
||||
{
|
||||
enum{TypeButton, TypeContainer};
|
||||
|
||||
typedef std::size_t size_type;
|
||||
|
||||
nana::string text;
|
||||
nana::paint::image image;
|
||||
unsigned pixels;
|
||||
nana::size textsize;
|
||||
bool enable;
|
||||
window other;
|
||||
|
||||
int type;
|
||||
std::function<void(size_type, size_type)> answer;
|
||||
std::vector<listitem> 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)
|
||||
{}
|
||||
};
|
||||
|
||||
class container
|
||||
{
|
||||
container(const container&);
|
||||
container& operator=(const container&);
|
||||
public:
|
||||
typedef std::vector<item_type*>::size_type size_type;
|
||||
typedef std::vector<item_type*>::iterator iterator;
|
||||
typedef std::vector<item_type*>::const_iterator const_iterator;
|
||||
|
||||
container()
|
||||
{}
|
||||
|
||||
~container()
|
||||
{
|
||||
for(auto ptr : cont_)
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
void insert(size_type pos, const nana::string& text, const nana::paint::image& img, int type)
|
||||
{
|
||||
item_type* m = new item_type(text, img, type);
|
||||
|
||||
if(pos < cont_.size())
|
||||
cont_.insert(cont_.begin() + pos, m);
|
||||
else
|
||||
cont_.push_back(m);
|
||||
}
|
||||
|
||||
void push_back(const nana::string& text, const nana::paint::image& img)
|
||||
{
|
||||
insert(cont_.size(), text, img, item_type::TypeButton);
|
||||
}
|
||||
|
||||
void push_back(const nana::string& text)
|
||||
{
|
||||
insert(cont_.size(), text, nana::paint::image(), item_type::TypeButton);
|
||||
}
|
||||
|
||||
void insert(size_type pos)
|
||||
{
|
||||
if(pos < cont_.size())
|
||||
cont_.insert(cont_.begin() + pos, static_cast<item_type*>(nullptr)); //both works in C++0x and C++2003
|
||||
else
|
||||
cont_.push_back(nullptr);
|
||||
}
|
||||
|
||||
void push_back()
|
||||
{
|
||||
cont_.push_back(nullptr);
|
||||
}
|
||||
|
||||
size_type size() const
|
||||
{
|
||||
return cont_.size();
|
||||
}
|
||||
|
||||
item_type* at(size_type n)
|
||||
{
|
||||
if(n < cont_.size())
|
||||
return cont_[n];
|
||||
|
||||
throw std::out_of_range("toolbar: bad index!");
|
||||
}
|
||||
|
||||
iterator begin()
|
||||
{
|
||||
return cont_.begin();
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
return cont_.end();
|
||||
}
|
||||
|
||||
const_iterator begin() const
|
||||
{
|
||||
return cont_.cbegin();
|
||||
}
|
||||
|
||||
const_iterator end() const
|
||||
{
|
||||
return cont_.cend();
|
||||
}
|
||||
private:
|
||||
std::vector<item_type*> cont_;
|
||||
};
|
||||
|
||||
class item_renderer
|
||||
{
|
||||
public:
|
||||
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)
|
||||
{}
|
||||
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
default: break;
|
||||
}
|
||||
|
||||
if(item.image.empty() == false)
|
||||
{
|
||||
nana::size size = item.image.size();
|
||||
if(size.width > scale) size.width = scale;
|
||||
if(size.height > scale) size.height = scale;
|
||||
|
||||
nana::point pos(x, y);
|
||||
pos.x += static_cast<int>(scale + extra_size - size.width) / 2;
|
||||
pos.y += static_cast<int>(height - size.height) / 2;
|
||||
|
||||
item.image.paste(size, graph, pos);
|
||||
if(item.enable == false)
|
||||
{
|
||||
nana::paint::graphics gh(size.width, size.height);
|
||||
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);
|
||||
|
||||
x += scale;
|
||||
width -= scale;
|
||||
}
|
||||
|
||||
if(textout)
|
||||
{
|
||||
graph.string(x + (width - item.textsize.width) / 2, y + (height - item.textsize.height) / 2, 0x0, item.text);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
nana::paint::graphics& graph;
|
||||
bool textout;
|
||||
unsigned scale;
|
||||
nana::color_t color;
|
||||
};
|
||||
|
||||
struct drawer::drawer_impl_type
|
||||
{
|
||||
event_handle event_size;
|
||||
unsigned scale;
|
||||
bool textout;
|
||||
size_type which;
|
||||
item_renderer::state_t state;
|
||||
|
||||
container cont;
|
||||
nana::tooltip tooltip;
|
||||
|
||||
drawer_impl_type()
|
||||
: event_size(nullptr),
|
||||
scale(16),
|
||||
textout(false),
|
||||
which(npos),
|
||||
state(item_renderer::state_t::normal)
|
||||
{}
|
||||
};
|
||||
|
||||
//class drawer
|
||||
drawer::drawer()
|
||||
: impl_(new drawer_impl_type)
|
||||
{
|
||||
}
|
||||
|
||||
drawer::~drawer()
|
||||
{
|
||||
delete impl_;
|
||||
}
|
||||
|
||||
void drawer::append(const nana::string& text, const nana::paint::image& img)
|
||||
{
|
||||
impl_->cont.push_back(text, img);
|
||||
}
|
||||
|
||||
void drawer::append()
|
||||
{
|
||||
impl_->cont.push_back();
|
||||
}
|
||||
|
||||
bool drawer::enable(drawer::size_type n) const
|
||||
{
|
||||
if(impl_->cont.size() > n)
|
||||
{
|
||||
auto item = impl_->cont.at(n);
|
||||
return (item && item->enable);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool drawer::enable(size_type n, bool eb)
|
||||
{
|
||||
if(impl_->cont.size() > n)
|
||||
{
|
||||
item_type * item = impl_->cont.at(n);
|
||||
if(item && (item->enable != eb))
|
||||
{
|
||||
item->enable = eb;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void drawer::scale(unsigned s)
|
||||
{
|
||||
impl_->scale = s;
|
||||
|
||||
for(auto m : impl_->cont)
|
||||
_m_fill_pixels(m, true);
|
||||
}
|
||||
|
||||
void drawer::refresh(graph_reference)
|
||||
{
|
||||
_m_draw();
|
||||
}
|
||||
|
||||
void drawer::attached(widget_reference widget, graph_reference graph)
|
||||
{
|
||||
graph_ = &graph;
|
||||
|
||||
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));
|
||||
|
||||
}
|
||||
|
||||
void drawer::detached()
|
||||
{
|
||||
API::umake_event(impl_->event_size);
|
||||
impl_->event_size = nullptr;
|
||||
}
|
||||
|
||||
void drawer::mouse_move(graph_reference graph, const arg_mouse& arg)
|
||||
{
|
||||
if(arg.left_button == false)
|
||||
{
|
||||
size_type which = _m_which(arg.pos.x, arg.pos.y, true);
|
||||
if(impl_->which != which)
|
||||
{
|
||||
if (impl_->which != npos && impl_->cont.at(impl_->which)->enable)
|
||||
{
|
||||
::nana::arg_toolbar arg{ *widget_, impl_->which };
|
||||
widget_->events().leave.emit(arg);
|
||||
}
|
||||
|
||||
impl_->which = which;
|
||||
if(which == npos || impl_->cont.at(which)->enable)
|
||||
{
|
||||
impl_->state = (arg.left_button ? item_renderer::state_t::selected : item_renderer::state_t::highlighted);
|
||||
|
||||
_m_draw();
|
||||
API::lazy_refresh();
|
||||
|
||||
if (impl_->state == item_renderer::state_t::highlighted)
|
||||
{
|
||||
::nana::arg_toolbar arg{ *widget_, which };
|
||||
widget_->events().enter.emit(arg);
|
||||
}
|
||||
}
|
||||
|
||||
if(which != npos)
|
||||
impl_->tooltip.show(widget_->handle(), nana::point(arg.pos.x, arg.pos.y + 20), (*(impl_->cont.begin() + which))->text, 0);
|
||||
else
|
||||
impl_->tooltip.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawer::mouse_leave(graph_reference, const arg_mouse&)
|
||||
{
|
||||
if(impl_->which != npos)
|
||||
{
|
||||
size_type which = impl_->which;
|
||||
|
||||
impl_->which = npos;
|
||||
_m_draw();
|
||||
API::lazy_refresh();
|
||||
|
||||
if (which != npos && impl_->cont.at(which)->enable)
|
||||
{
|
||||
::nana::arg_toolbar arg{ *widget_, which };
|
||||
widget_->events().leave.emit(arg);
|
||||
}
|
||||
}
|
||||
impl_->tooltip.close();
|
||||
}
|
||||
|
||||
void drawer::mouse_down(graph_reference, const arg_mouse&)
|
||||
{
|
||||
impl_->tooltip.close();
|
||||
if(impl_->which != npos && (impl_->cont.at(impl_->which)->enable))
|
||||
{
|
||||
impl_->state = item_renderer::state_t::selected;
|
||||
_m_draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void drawer::mouse_up(graph_reference, const arg_mouse& arg)
|
||||
{
|
||||
if(impl_->which != npos)
|
||||
{
|
||||
size_type which = _m_which(arg.pos.x, arg.pos.y, false);
|
||||
if(impl_->which == which)
|
||||
{
|
||||
::nana::arg_toolbar arg{ *widget_, which };
|
||||
widget_->events().selected.emit(arg);
|
||||
|
||||
impl_->state = item_renderer::state_t::highlighted;
|
||||
}
|
||||
else
|
||||
{
|
||||
impl_->which = which;
|
||||
impl_->state = (which == npos ? item_renderer::state_t::normal : item_renderer::state_t::highlighted);
|
||||
}
|
||||
|
||||
_m_draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
|
||||
drawer::size_type drawer::_m_which(int x, int y, bool want_if_disabled) const
|
||||
{
|
||||
if(x < 2 || y < 2 || y >= static_cast<int>(impl_->scale + item_renderer::extra_size + 2)) return npos;
|
||||
|
||||
x -= 2;
|
||||
|
||||
size_type pos = 0;
|
||||
for(auto m: impl_->cont)
|
||||
{
|
||||
bool compart = (nullptr == m);
|
||||
|
||||
if(x < static_cast<int>(compart ? 3 : m->pixels))
|
||||
return ((compart || (m->enable == false && want_if_disabled == false)) ? npos : pos);
|
||||
|
||||
x -= (compart ? 3 : m->pixels);
|
||||
|
||||
++pos;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
void drawer::_m_draw_background(nana::color_t color)
|
||||
{
|
||||
graph_->shadow_rectangle(graph_->size(), graph_->mix(color, 0xFFFFFF, 0.9), graph_->mix(color, 0x0, 0.95), true);
|
||||
}
|
||||
|
||||
void drawer::_m_draw()
|
||||
{
|
||||
int x = 2, y = 2;
|
||||
|
||||
unsigned color = API::background(widget_->handle());
|
||||
_m_draw_background(color);
|
||||
|
||||
item_renderer ir(*graph_, impl_->textout, impl_->scale, color);
|
||||
size_type index = 0;
|
||||
|
||||
for(auto item : impl_->cont)
|
||||
{
|
||||
if(item)
|
||||
{
|
||||
_m_fill_pixels(item, false);
|
||||
ir(x, y, item->pixels, impl_->scale + ir.extra_size, *item, (index == impl_->which ? impl_->state : item_renderer::state_t::normal));
|
||||
x += item->pixels;
|
||||
}
|
||||
else
|
||||
{
|
||||
graph_->line(x + 2, y + 2, x + 2, y + impl_->scale + ir.extra_size - 4, 0x808080);
|
||||
x += 6;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
void drawer::_m_owner_sized(const arg_resized& arg)
|
||||
{
|
||||
auto wd = widget_->handle();
|
||||
API::window_size(wd, nana::size(arg.width, widget_->size().height));
|
||||
_m_draw();
|
||||
API::update_window(wd);
|
||||
}
|
||||
|
||||
void drawer::_m_fill_pixels(item_type* item, bool force)
|
||||
{
|
||||
if(item && (force || (0 == item->pixels)))
|
||||
{
|
||||
if(item->text.size())
|
||||
item->textsize = graph_->text_extent_size(item->text);
|
||||
|
||||
if(item->image.empty() == false)
|
||||
item->pixels = impl_->scale + item_renderer::extra_size;
|
||||
|
||||
if(item->textsize.width && impl_->textout)
|
||||
item->pixels += item->textsize.width + 8;
|
||||
}
|
||||
}
|
||||
//};//class drawer
|
||||
|
||||
}//end namespace toolbar
|
||||
}//end namespace drawerbase
|
||||
|
||||
//class toolbar
|
||||
toolbar::toolbar()
|
||||
{}
|
||||
|
||||
toolbar::toolbar(window wd, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
}
|
||||
|
||||
toolbar::toolbar(window wd, const rectangle& r, bool visible)
|
||||
{
|
||||
create(wd, r, visible);
|
||||
}
|
||||
|
||||
void toolbar::append()
|
||||
{
|
||||
get_drawer_trigger().append();
|
||||
API::refresh_window(handle());
|
||||
}
|
||||
|
||||
void toolbar::append(const nana::string& text, const nana::paint::image& img)
|
||||
{
|
||||
get_drawer_trigger().append(text, img);
|
||||
API::refresh_window(handle());
|
||||
}
|
||||
|
||||
void toolbar::append(const nana::string& text)
|
||||
{
|
||||
get_drawer_trigger().append(text, nana::paint::image());
|
||||
API::refresh_window(this->handle());
|
||||
}
|
||||
|
||||
bool toolbar::enable(size_type n) const
|
||||
{
|
||||
return get_drawer_trigger().enable(n);
|
||||
}
|
||||
|
||||
void toolbar::enable(size_type n, bool eb)
|
||||
{
|
||||
if(get_drawer_trigger().enable(n, eb))
|
||||
API::refresh_window(this->handle());
|
||||
}
|
||||
|
||||
void toolbar::scale(unsigned s)
|
||||
{
|
||||
get_drawer_trigger().scale(s);
|
||||
API::refresh_window(handle());
|
||||
}
|
||||
//}; class toolbar
|
||||
}//end namespace nana
|
||||
2248
source/gui/widgets/treebox.cpp
Normal file
2248
source/gui/widgets/treebox.cpp
Normal file
File diff suppressed because it is too large
Load Diff
286
source/gui/widgets/widget.cpp
Normal file
286
source/gui/widgets/widget.cpp
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* The fundamental widget class implementation
|
||||
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: nana/gui/widgets/widget.cpp
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/widget.hpp>
|
||||
#include <nana/gui/tooltip.hpp>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
namespace internationalization_parts
|
||||
{
|
||||
void set_eval(window, i18n_eval&&);
|
||||
}
|
||||
//class widget
|
||||
//@brief:The definition of class widget
|
||||
widget::~widget(){}
|
||||
|
||||
nana::string widget::caption() const
|
||||
{
|
||||
return this->_m_caption();
|
||||
}
|
||||
|
||||
void widget::caption(nana::string str)
|
||||
{
|
||||
_m_caption(std::move(str));
|
||||
}
|
||||
|
||||
void widget::i18n(i18n_eval eval)
|
||||
{
|
||||
if (handle())
|
||||
{
|
||||
_m_caption(eval());
|
||||
internationalization_parts::set_eval(handle(), std::move(eval));
|
||||
}
|
||||
}
|
||||
|
||||
nana::cursor widget::cursor() const
|
||||
{
|
||||
return _m_cursor();
|
||||
}
|
||||
|
||||
void widget::cursor(nana::cursor cur)
|
||||
{
|
||||
_m_cursor(cur);
|
||||
}
|
||||
|
||||
void widget::typeface(const nana::paint::font& font)
|
||||
{
|
||||
_m_typeface(font);
|
||||
}
|
||||
|
||||
nana::paint::font widget::typeface() const
|
||||
{
|
||||
return _m_typeface();
|
||||
}
|
||||
|
||||
void widget::close()
|
||||
{
|
||||
_m_close();
|
||||
}
|
||||
|
||||
window widget::parent() const
|
||||
{
|
||||
return API::get_parent_window(handle());
|
||||
}
|
||||
|
||||
bool widget::enabled() const
|
||||
{
|
||||
return API::window_enabled(handle());
|
||||
}
|
||||
|
||||
void widget::enabled(bool value)
|
||||
{
|
||||
_m_enabled(value);
|
||||
}
|
||||
|
||||
void widget::enable_dropfiles(bool enb)
|
||||
{
|
||||
API::enable_dropfiles(handle(), enb);
|
||||
}
|
||||
|
||||
bool widget::empty() const
|
||||
{
|
||||
return (nullptr == handle());
|
||||
}
|
||||
|
||||
void widget::focus()
|
||||
{
|
||||
API::focus_window(handle());
|
||||
}
|
||||
|
||||
bool widget::focused() const
|
||||
{
|
||||
return API::is_focus_window(handle());
|
||||
}
|
||||
|
||||
void widget::show()
|
||||
{
|
||||
_m_show(true);
|
||||
}
|
||||
|
||||
void widget::hide()
|
||||
{
|
||||
_m_show(false);
|
||||
}
|
||||
|
||||
bool widget::visible() const
|
||||
{
|
||||
return _m_visible();
|
||||
}
|
||||
|
||||
nana::size widget::size() const
|
||||
{
|
||||
return API::window_size(handle());
|
||||
}
|
||||
|
||||
void widget::size(const nana::size& sz)
|
||||
{
|
||||
_m_size(sz);
|
||||
}
|
||||
|
||||
nana::point widget::pos() const
|
||||
{
|
||||
return API::window_position(handle());
|
||||
}
|
||||
|
||||
void widget::move(int x, int y)
|
||||
{
|
||||
_m_move(x, y);
|
||||
}
|
||||
|
||||
void widget::move(const rectangle& r)
|
||||
{
|
||||
_m_move(r);
|
||||
}
|
||||
|
||||
void widget::foreground(nana::color_t value)
|
||||
{
|
||||
_m_foreground(value);
|
||||
}
|
||||
|
||||
nana::color_t widget::foreground() const
|
||||
{
|
||||
return _m_foreground();
|
||||
}
|
||||
|
||||
void widget::background(nana::color_t value)
|
||||
{
|
||||
_m_background(value);
|
||||
}
|
||||
|
||||
nana::color_t widget::background() const
|
||||
{
|
||||
return _m_background();
|
||||
}
|
||||
|
||||
general_events& widget::events() const
|
||||
{
|
||||
return _m_get_general_events();
|
||||
}
|
||||
|
||||
void widget::umake_event(event_handle eh) const
|
||||
{
|
||||
API::umake_event(eh);
|
||||
}
|
||||
|
||||
widget& widget::tooltip(const nana::string& text)
|
||||
{
|
||||
nana::tooltip::set(*this, text);
|
||||
return *this;
|
||||
}
|
||||
|
||||
widget::operator widget::dummy_bool_type() const
|
||||
{
|
||||
return (handle()? dummy_bool_type(1):0);
|
||||
}
|
||||
|
||||
widget::operator window() const
|
||||
{
|
||||
return handle();
|
||||
}
|
||||
|
||||
void widget::_m_complete_creation()
|
||||
{}
|
||||
|
||||
nana::string widget::_m_caption() const
|
||||
{
|
||||
return API::dev::window_caption(handle());
|
||||
}
|
||||
|
||||
void widget::_m_caption(nana::string&& str)
|
||||
{
|
||||
API::dev::window_caption(handle(), std::move(str));
|
||||
}
|
||||
|
||||
nana::cursor widget::_m_cursor() const
|
||||
{
|
||||
return API::window_cursor(handle());
|
||||
}
|
||||
|
||||
void widget::_m_cursor(nana::cursor cur)
|
||||
{
|
||||
API::window_cursor(handle(), cur);
|
||||
}
|
||||
|
||||
void widget::_m_close()
|
||||
{
|
||||
API::close_window(handle());
|
||||
}
|
||||
|
||||
bool widget::_m_enabled() const
|
||||
{
|
||||
return API::window_enabled(handle());
|
||||
}
|
||||
|
||||
void widget::_m_enabled(bool value)
|
||||
{
|
||||
API::window_enabled(handle(), value);
|
||||
}
|
||||
|
||||
bool widget::_m_show(bool visible)
|
||||
{
|
||||
API::show_window(handle(), visible);
|
||||
return visible;
|
||||
}
|
||||
|
||||
bool widget::_m_visible() const
|
||||
{
|
||||
return API::visible(handle());
|
||||
}
|
||||
|
||||
void widget::_m_size(const nana::size& sz)
|
||||
{
|
||||
API::window_size(handle(), sz);
|
||||
}
|
||||
|
||||
void widget::_m_move(int x, int y)
|
||||
{
|
||||
API::move_window(handle(), x, y);
|
||||
}
|
||||
|
||||
void widget::_m_move(const rectangle& r)
|
||||
{
|
||||
API::move_window(handle(), r);
|
||||
}
|
||||
|
||||
void widget::_m_typeface(const paint::font& font)
|
||||
{
|
||||
API::typeface(handle(), font);
|
||||
}
|
||||
|
||||
nana::paint::font widget::_m_typeface() const
|
||||
{
|
||||
return API::typeface(handle());
|
||||
}
|
||||
|
||||
void widget::_m_foreground(nana::color_t value)
|
||||
{
|
||||
API::foreground(handle(), value);
|
||||
}
|
||||
|
||||
nana::color_t widget::_m_foreground() const
|
||||
{
|
||||
return API::foreground(handle());
|
||||
}
|
||||
|
||||
void widget::_m_background(nana::color_t value)
|
||||
{
|
||||
API::background(handle(), value);
|
||||
}
|
||||
|
||||
nana::color_t widget::_m_background() const
|
||||
{
|
||||
return API::background(handle());
|
||||
}
|
||||
|
||||
//end class widget
|
||||
}//end namespace nana
|
||||
|
||||
Reference in New Issue
Block a user