first init of 0.9

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

View File

@@ -0,0 +1,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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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
}

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

1389
source/gui/widgets/menu.cpp Normal file

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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