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

642
source/gui/animation.cpp Normal file
View File

@@ -0,0 +1,642 @@
/*
* An Animation 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/animation.cpp
*/
#include <nana/gui/animation.hpp>
#include <nana/gui/drawing.hpp>
#include <nana/system/timepiece.hpp>
#include <nana/system/platform.hpp>
#include <vector>
#include <list>
#include <algorithm>
#if defined(NANA_MINGW) && defined(STD_THREAD_NOT_SUPPORTED)
#include <nana/std_thread.hpp>
#include <nana/std_mutex.hpp>
#include <nana/std_condition_variable.hpp>
#else
#include <mutex>
#include <condition_variable>
#include <thread>
#endif //NANA_MINGW
namespace nana
{
class animation;
struct output_t
{
drawing::diehard_t diehard;
std::vector<nana::point> points;
output_t()
: diehard(nullptr)
{}
};
struct framebuilder
{
std::size_t length;
std::function<bool(std::size_t, paint::graphics&, nana::size&)> frbuilder;
framebuilder(const std::function<bool(std::size_t, paint::graphics&, nana::size&)>& f, std::size_t l)
: length(l), frbuilder(f)
{}
framebuilder(std::size_t l, std::function<bool(std::size_t, paint::graphics&, nana::size)>&& f)
: length(l), frbuilder(std::move(f))
{}
};
struct frame
{
enum class kind
{
oneshot,
framebuilder
};
frame(const paint::image& r)
: type(kind::oneshot)
{
u.oneshot = new paint::image(r);
}
frame(paint::image&& r)
: type(kind::oneshot)
{
u.oneshot = new paint::image(std::move(r));
}
frame(const std::function<bool(std::size_t, paint::graphics&, nana::size&)>& frbuilder, std::size_t length)
: type(kind::framebuilder)
{
u.frbuilder = new framebuilder(frbuilder, length);
}
frame(std::function<bool(std::size_t, paint::graphics&, nana::size&)>&& frbuilder, std::size_t length)
: type(kind::framebuilder)
{
u.frbuilder = new framebuilder(frbuilder, length);
}
frame(const frame& r)
: type(r.type)
{
switch(type)
{
case kind::oneshot:
u.oneshot = new paint::image(*r.u.oneshot);
break;
case kind::framebuilder:
u.frbuilder = new framebuilder(*r.u.frbuilder);
break;
}
}
frame(frame&& r)
: type(r.type)
{
u = r.u;
r.u.oneshot = nullptr;
}
~frame()
{
switch(type)
{
case kind::oneshot:
delete u.oneshot;
break;
case kind::framebuilder:
delete u.frbuilder;
break;
}
}
frame& operator=(const frame& r)
{
if(this != &r)
{
switch(type)
{
case kind::oneshot:
delete u.oneshot;
break;
case kind::framebuilder:
delete u.frbuilder;
break;
}
type = r.type;
switch(type)
{
case kind::oneshot:
u.oneshot = new paint::image(*r.u.oneshot);
break;
case kind::framebuilder:
u.frbuilder = new framebuilder(*r.u.frbuilder);
break;
}
}
return *this;
}
frame& operator=(frame&& r)
{
if(this != &r)
{
switch(type)
{
case kind::oneshot:
delete u.oneshot;
break;
case kind::framebuilder:
delete u.frbuilder;
break;
}
type = r.type;
u = r.u;
r.u.oneshot = nullptr;
}
return *this;
}
std::size_t length() const
{
switch(type)
{
case kind::oneshot:
return 1;
case kind::framebuilder:
return u.frbuilder->length;
}
return 0;
}
//
kind type;
union uframes
{
paint::image * oneshot;
framebuilder * frbuilder;
}u;
};
//class frameset
//struct frameset::impl
struct frameset::impl
{
//Only list whos iterator would not invalided after a insertion.
std::list<frame> frames;
std::list<frame>::iterator this_frame;
std::size_t pos_in_this_frame;
mutable bool good_frame_by_frmbuilder; //It indicates the state of frame whether is valid.
impl()
: this_frame(frames.end()), pos_in_this_frame(0),
good_frame_by_frmbuilder(false)
{}
//Render A frame on the set of windows.
void render_this(std::map<window, output_t>& outs, paint::graphics& framegraph, nana::size& framegraph_dimension) const
{
if(this_frame == frames.end())
return;
frame & frmobj = *this_frame;
switch(frmobj.type)
{
case frame::kind::oneshot:
_m_render(outs, [&frmobj](paint::graphics& tar, const nana::point& pos)
{
frmobj.u.oneshot->paste(tar, pos.x, pos.y);
});
break;
case frame::kind::framebuilder:
good_frame_by_frmbuilder = frmobj.u.frbuilder->frbuilder(pos_in_this_frame, framegraph, framegraph_dimension);
if(good_frame_by_frmbuilder)
{
nana::rectangle r = framegraph_dimension;
_m_render(outs, [&r, &framegraph](paint::graphics& tar, const nana::point& pos) mutable
{
r.x = pos.x;
r.y = pos.y;
tar.bitblt(r, framegraph);
});
}
break;
}
}
//Render a frame on a specified window graph
void render_this(paint::graphics& graph, const nana::point& pos, paint::graphics& framegraph, nana::size& framegraph_dimension, bool rebuild_frame) const
{
if(this_frame == frames.end())
return;
frame & frmobj = *this_frame;
switch(frmobj.type)
{
case frame::kind::oneshot:
frmobj.u.oneshot->paste(graph, pos.x, pos.y);
break;
case frame::kind::framebuilder:
if(rebuild_frame)
good_frame_by_frmbuilder = frmobj.u.frbuilder->frbuilder(pos_in_this_frame, framegraph, framegraph_dimension);
if(good_frame_by_frmbuilder)
{
nana::rectangle r(pos, framegraph_dimension);
graph.bitblt(r, framegraph);
}
break;
}
}
bool eof() const
{
return (frames.end() == this_frame);
}
void next_frame()
{
if(frames.end() == this_frame)
return;
frame & frmobj = *this_frame;
switch(frmobj.type)
{
case frame::kind::oneshot:
++this_frame;
pos_in_this_frame = 0;
break;
case frame::kind::framebuilder:
if(pos_in_this_frame >= frmobj.u.frbuilder->length)
{
pos_in_this_frame = 0;
++this_frame;
}
else
++pos_in_this_frame;
break;
default:
throw std::runtime_error("Nana.GUI.Animation: Bad frame type");
}
}
//Seek to the first frame
void reset()
{
this_frame = frames.begin();
pos_in_this_frame = 0;
}
private:
template<typename Renderer>
void _m_render(std::map<window, output_t>& outs, Renderer renderer) const
{
for(auto & tar: outs)
{
auto graph = API::dev::window_graphics(tar.first);
if(nullptr == graph)
continue;
for(auto & outp : tar.second.points)
renderer(*graph, outp);
API::update_window(tar.first);
}
}
};//end struct frameset::impl
//public:
frameset::frameset()
: impl_(new impl)
{}
void frameset::push_back(const paint::image& m)
{
bool located = impl_->this_frame != impl_->frames.end();
impl_->frames.emplace_back(m);
if(false == located)
impl_->this_frame = impl_->frames.begin();
}
void frameset::push_back(paint::image&& m)
{
impl_->frames.emplace_back(std::move(m));
if(1 == impl_->frames.size())
impl_->this_frame = impl_->frames.begin();
}
void frameset::push_back(framebuilder&fb, std::size_t length)
{
impl_->frames.emplace_back(fb, length);
if(1 == impl_->frames.size())
impl_->this_frame = impl_->frames.begin();
}
void frameset::push_back(framebuilder&& fb, std::size_t length)
{
impl_->frames.emplace_back(std::move(fb), length);
if(1 == impl_->frames.size())
impl_->this_frame = impl_->frames.begin();
}
//end class frameset
//class animation
class animation::performance_manager
{
public:
struct thread_variable
{
std::mutex mutex;
std::condition_variable condvar;
std::vector<impl*> animations;
std::size_t active; //The number of active animations
std::shared_ptr<std::thread> thread;
double performance_parameter;
};
thread_variable * insert(impl* p);
void close(impl* p);
bool empty() const;
private:
void _m_perf_thread(thread_variable* thrvar);
private:
mutable std::recursive_mutex mutex_;
std::vector<thread_variable*> threads_;
}; //end class animation::performance_manager
struct animation::impl
{
bool looped;
volatile bool paused;
std::list<frameset> framesets;
std::map<std::string, branch_t> branches;
std::map<window, output_t> outputs;
paint::graphics framegraph; //framegraph will be created by framebuilder
nana::size framegraph_dimension;
struct state_t
{
std::list<frameset>::iterator this_frameset;
}state;
performance_manager::thread_variable * thr_variable;
static performance_manager * perf_manager;
impl()
: looped(false), paused(true)
{
state.this_frameset = framesets.begin();
{
nana::internal_scope_guard lock;
if(nullptr == perf_manager)
perf_manager = new performance_manager;
}
thr_variable = perf_manager->insert(this);
}
~impl()
{
perf_manager->close(this);
{
nana::internal_scope_guard lock;
if(perf_manager->empty())
{
delete perf_manager;
perf_manager = nullptr;
}
}
}
void render_this_specifically(paint::graphics& graph, const nana::point& pos)
{
if(state.this_frameset != framesets.end())
state.this_frameset->impl_->render_this(graph, pos, framegraph, framegraph_dimension, false);
}
void render_this_frame()
{
if(state.this_frameset != framesets.end())
state.this_frameset->impl_->render_this(outputs, framegraph, framegraph_dimension);
}
bool move_to_next()
{
if(state.this_frameset != framesets.end())
{
state.this_frameset->impl_->next_frame();
return (!state.this_frameset->impl_->eof());
}
return false;
}
//Seek to the first frameset
void reset()
{
state.this_frameset = framesets.begin();
if(state.this_frameset != framesets.end())
state.this_frameset->impl_->reset();
}
};//end struct animation::impl
//class animation::performance_manager
auto animation::performance_manager::insert(impl* p) -> thread_variable *
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
for(auto thr : threads_)
{
std::lock_guard<decltype(thr->mutex)> privlock(thr->mutex);
if(thr->performance_parameter / (thr->animations.size() + 1) <= 43.3)
{
thr->animations.push_back(p);
return thr;
}
}
auto thr = new thread_variable;
thr->animations.push_back(p);
thr->performance_parameter = 0.0;
thr->thread = std::make_shared<std::thread>([this, thr]()
{
_m_perf_thread(thr);
});
threads_.push_back(thr);
return thr;
}
void animation::performance_manager::close(impl* p)
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
for(auto thr : threads_)
{
std::lock_guard<decltype(thr->mutex)> privlock(thr->mutex);
auto i = std::find(thr->animations.begin(), thr->animations.end(), p);
if(i != thr->animations.end())
{
thr->animations.erase(i);
return;
}
}
}
bool animation::performance_manager::empty() const
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
for(auto thr : threads_)
{
if(thr->animations.size())
return false;
}
return true;
}
void animation::performance_manager::_m_perf_thread(thread_variable* thrvar)
{
nana::system::timepiece tmpiece;
while(true)
{
thrvar->active = 0;
tmpiece.start();
{
std::lock_guard<decltype(thrvar->mutex)> lock(thrvar->mutex);
for(auto ani : thrvar->animations)
{
if(ani->paused)
continue;
ani->render_this_frame();
if(false == ani->move_to_next())
{
if(ani->looped)
{
ani->reset();
++thrvar->active;
}
}
else
++thrvar->active;
}
}
if(thrvar->active)
{
thrvar->performance_parameter = tmpiece.calc();
if(thrvar->performance_parameter < 43.4)
nana::system::sleep(static_cast<unsigned>(43.4 - thrvar->performance_parameter));
}
else
{
//There isn't an active frame, then let the thread
//wait for a signal for an active animation
std::unique_lock<std::mutex> lock(thrvar->mutex);
if(0 == thrvar->active)
thrvar->condvar.wait(lock);
}
}
}
//end class animation::performance_manager
animation::animation()
: impl_(new impl)
{
}
void animation::push_back(const frameset& frms)
{
impl_->framesets.emplace_back(frms);
if(1 == impl_->framesets.size())
impl_->state.this_frameset = impl_->framesets.begin();
}
/*
void branch(const std::string& name, const frameset& frms)
{
impl_->branches[name].frames = frms;
}
void branch(const std::string& name, const frameset& frms, std::function<std::size_t(const std::string&, std::size_t, std::size_t&)> condition)
{
auto & br = impl_->branches[name];
br.frames = frms;
br.condition = condition;
}
*/
void animation::looped(bool enable)
{
if(impl_->looped != enable)
{
impl_->looped = enable;
if(enable)
{
std::unique_lock<std::mutex> lock(impl_->thr_variable->mutex);
if(0 == impl_->thr_variable->active)
{
impl_->thr_variable->active = 1;
impl_->thr_variable->condvar.notify_one();
}
}
}
}
void animation::play()
{
impl_->paused = false;
std::unique_lock<std::mutex> lock(impl_->thr_variable->mutex);
if(0 == impl_->thr_variable->active)
{
impl_->thr_variable->active = 1;
impl_->thr_variable->condvar.notify_one();
}
}
void animation::pause()
{
impl_->paused = true;
}
void animation::output(window wd, const nana::point& pos)
{
auto & output = impl_->outputs[wd];
if(nullptr == output.diehard)
{
drawing dw(wd);
output.diehard = dw.draw_diehard([this, pos](paint::graphics& tar){
impl_->render_this_specifically(tar, pos);
});
API::events(wd).destroy.connect([this](const arg_destroy& arg){
std::lock_guard<decltype(impl_->thr_variable->mutex)> lock(impl_->thr_variable->mutex);
impl_->outputs.erase(arg.window_handle);
});
}
output.points.push_back(pos);
}
//end class animation
animation::performance_manager * animation::impl::perf_manager;
} //end namespace nana

33
source/gui/basis.cpp Normal file
View File

@@ -0,0 +1,33 @@
/*
* Basis 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/basis.cpp
*
* This file provides basis class and data structrue that required by gui
*/
#include <nana/gui/basis.hpp>
namespace nana
{
//struct appearance
//@brief: Window appearance structure
appearance::appearance()
:taskbar(true), floating(false), no_activate(false),
minimize(true), maximize(true), sizable(true),
decoration(true)
{}
appearance::appearance(bool has_decorate, bool taskbar, bool is_float, bool no_activate, bool min, bool max, bool sizable)
: taskbar(taskbar), floating(is_float), no_activate(no_activate),
minimize(min), maximize(max), sizable(sizable),
decoration(has_decorate)
{}
//end struct appearance
}//end namespace nana

View File

@@ -0,0 +1,385 @@
#include <nana/gui/detail/basic_window.hpp>
#include <nana/gui/detail/native_window_interface.hpp>
namespace nana
{
namespace detail
{
//class caret_descriptor
caret_descriptor::caret_descriptor(core_window_t* wd, unsigned width, unsigned height)
:wd_(wd), size_(width, height), visible_(false), real_visible_state_(false), out_of_range_(false)
{}
caret_descriptor::~caret_descriptor()
{
if(wd_) native_interface::caret_destroy(wd_->root);
}
void caret_descriptor::set_active(bool active)
{
if(wd_)
{
if(active)
{
native_interface::caret_create(wd_->root, size_.width, size_.height);
real_visible_state_ = false;
visible_ = false;
this->position(point_.x, point_.y);
}
else
native_interface::caret_destroy(wd_->root);
wd_->root_widget->other.attribute.root->ime_enabled = active;
}
}
auto caret_descriptor::window() const ->core_window_t*
{
return wd_;
}
void caret_descriptor::position(int x, int y)
{
point_.x = x;
point_.y = y;
update();
}
void caret_descriptor::effective_range(nana::rectangle rect)
{
//Chech rect
if( (rect.width && rect.height) &&
(rect.x + rect.width > 0) &&
(rect.y + rect.height > 0))
{
if(rect.x < 0)
{
rect.width += rect.x;
rect.x = 0;
}
if(rect.y < 0)
{
rect.height += rect.y;
rect.y = 0;
}
if(effective_range_ != rect)
{
effective_range_ = rect;
update();
}
}
}
nana::point caret_descriptor::position() const
{
return point_;
}
void caret_descriptor::visible(bool isshow)
{
if(visible_ != isshow)
{
visible_ = isshow;
if(visible_ == false || false == out_of_range_)
_m_visible(isshow);
}
}
bool caret_descriptor::visible() const
{
return visible_;
}
nana::size caret_descriptor::size() const
{
return size_;
}
void caret_descriptor::size(const nana::size& s)
{
size_ = s;
update();
if(visible_) this->visible(true);
}
void caret_descriptor::_m_visible(bool isshow)
{
if(real_visible_state_ != isshow)
{
real_visible_state_ = isshow;
native_interface::caret_visible(wd_->root, isshow);
}
}
void caret_descriptor::update()
{
nana::point pos = point_;
nana::size size = size_;
nana::rectangle rect = effective_range_;
if(0 == effective_range_.width || 0 == effective_range_.height)
{
rect.x = rect.y = 0;
rect = wd_->dimension;
}
else
{
pos.x += effective_range_.x;
pos.y += effective_range_.y;
}
if( (pos.x + static_cast<int>(size.width) <= rect.x) || (pos.x >= rect.x + static_cast<int>(rect.width)) ||
(pos.y + static_cast<int>(size.height) <= rect.y) || (pos.y >= rect.y + static_cast<int>(rect.height))
)
{//Out of Range without overlap
if(false == out_of_range_)
{
out_of_range_ = true;
if(visible_)
_m_visible(false);
}
}
else
{
if(pos.x < rect.x)
{
size.width -= (rect.x - pos.x);
pos.x = rect.x;
}
else if(pos.x + size.width > rect.x + rect.width)
{
size.width -= pos.x + size.width - (rect.x + rect.width);
}
if(pos.y < rect.y)
{
size.width -= (rect.y - pos.y);
pos.y = rect.y;
}
else if(pos.y + size.height > rect.y + rect.height)
size.height -= pos.y + size.height - (rect.y + rect.height);
if(out_of_range_)
{
if(paint_size_ == size)
_m_visible(true);
out_of_range_ = false;
}
if(paint_size_ != size)
{
native_interface::caret_destroy(wd_->root);
native_interface::caret_create(wd_->root, size.width, size.height);
real_visible_state_ = false;
if(visible_)
_m_visible(true);
paint_size_ = size;
}
native_interface::caret_pos(wd_->root, wd_->pos_root.x + pos.x, wd_->pos_root.y + pos.y);
}
}
//end class caret_descriptor
//struct basic_window
//struct basic_window::other_tag
basic_window::other_tag::other_tag(category::flags categ)
: category(categ), active_window(nullptr), upd_state(update_state::none)
{
switch(categ)
{
case category::root_tag::value:
attribute.root = new attr_root_tag;
attribute.root->context.focus_changed = false;
break;
case category::frame_tag::value:
attribute.frame = new attr_frame_tag;
break;
default:
attribute.root = nullptr;
}
}
basic_window::other_tag::~other_tag()
{
switch(category)
{
case category::root_tag::value:
delete attribute.root;
break;
case category::frame_tag::value:
delete attribute.frame;
break;
default: break;
}
}
//end struct basic_window::other_tag
//basic_window
//@brief: constructor for the root window
basic_window::basic_window(basic_window* owner, widget* wdg, category::root_tag**)
: widget_ptr(wdg), other(category::root_tag::value)
{
drawer.bind(this);
_m_init_pos_and_size(0, rectangle());
this->_m_initialize(owner);
}
basic_window::~basic_window()
{
delete together.caret;
together.caret = nullptr;
delete effect.bground;
effect.bground = nullptr;
}
//bind_native_window
//@brief: bind a native window and baisc_window
void basic_window::bind_native_window(native_window_type wd, unsigned width, unsigned height, unsigned extra_width, unsigned extra_height, nana::paint::graphics& graphics)
{
if(category::root_tag::value == this->other.category)
{
this->root = wd;
dimension.width = width;
dimension.height = height;
this->extra_width = extra_width;
this->extra_height = extra_height;
this->root_widget = this;
this->root_graph = &graphics;
}
}
void basic_window::frame_window(native_window_type wd)
{
if(category::frame_tag::value == this->other.category)
other.attribute.frame->container = wd;
}
bool basic_window::is_ancestor_of(const basic_window* wd) const
{
while (wd)
{
if (this == wd->parent)
return true;
wd = wd->parent;
}
return false;
}
bool basic_window::visible_parents() const
{
for (auto pnt = parent; pnt; pnt = pnt->parent)
{
if (!pnt->visible)
return false;
}
return true;
}
bool basic_window::belong_to_lazy() const
{
for (auto wd = this; wd; wd = wd->parent)
{
if (basic_window::update_state::refresh == wd->other.upd_state)
return true;
}
return false;
}
void basic_window::_m_init_pos_and_size(basic_window* parent, const rectangle& r)
{
pos_owner = pos_root = r;
dimension = r;
if(parent)
{
pos_root.x += parent->pos_root.x;
pos_root.y += parent->pos_root.y;
}
}
void basic_window::_m_initialize(basic_window* agrparent)
{
if(other.category == category::root_tag::value)
{
if(agrparent && (nana::system::this_thread_id() != agrparent->thread_id))
agrparent = nullptr;
while(agrparent && (agrparent->other.category != category::root_tag::value))
agrparent = agrparent->parent;
owner = agrparent;
parent = nullptr;
index = 0;
}
else
{
parent = agrparent;
owner = nullptr;
root_widget = agrparent->root_widget;
root = agrparent->root;
root_graph = agrparent->root_graph;
index = static_cast<unsigned>(agrparent->children.size());
agrparent->children.push_back(this);
}
predef_cursor = cursor::arrow;
flags.capture = false;
flags.dbl_click = true;
flags.enabled = true;
flags.modal = false;
flags.take_active = true;
flags.dropable = false;
flags.fullscreen = false;
flags.tab = nana::detail::tab_type::none;
flags.action = mouse_action::normal;
flags.refreshing = false;
flags.destroying = false;
flags.borderless = false;
visible = false;
color.foreground = 0x0;
color.background = nana::color::button_face;
color.active = 0x60C8FD;
effect.edge_nimbus = effects::edge_nimbus::none;
effect.bground = nullptr;
effect.bground_fade_rate = 0;
together.caret = nullptr;
together.attached_events = nullptr;
extra_width = extra_height = 0;
//The window must keep its thread_id same as its parent if it is a child.
//Otherwise, its root buffer would be mapped repeatly if it is in its parent thread.
thread_id = nana::system::this_thread_id();
if(agrparent && (thread_id != agrparent->thread_id))
thread_id = agrparent->thread_id;
}
bool basic_window::set_events(const std::shared_ptr<general_events>& p)
{
if (together.attached_events)
return false;
together.events_ptr = p;
together.attached_events = p.get();
return true;
}
general_events * basic_window::get_events() const
{
return together.attached_events;
}
//end struct basic_window
}//end namespace detail
}//end namespace nana

View File

@@ -0,0 +1,331 @@
/*
* A Bedrock Platform-Independent 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/detail/bedrock_pi.cpp
*/
#include <nana/config.hpp>
#include PLATFORM_SPEC_HPP
#include GUI_BEDROCK_HPP
#include <nana/gui/detail/event_code.hpp>
#include <nana/system/platform.hpp>
#include <sstream>
#include <nana/system/timepiece.hpp>
#include <nana/gui/wvl.hpp>
#include <nana/gui/detail/inner_fwd_implement.hpp>
#include <nana/gui/detail/native_window_interface.hpp>
#include <nana/gui/layout_utility.hpp>
#include <nana/gui/detail/element_store.hpp>
namespace nana
{
namespace detail
{
void events_operation_register(event_handle evt)
{
bedrock::instance().evt_operation.register_evt(evt);
}
void events_operation_cancel(event_handle evt)
{
bedrock::instance().evt_operation.cancel(evt);
}
void bedrock::event_expose(core_window_t * wd, bool exposed)
{
if (nullptr == wd) return;
wd->visible = exposed;
arg_expose arg;
arg.exposed = exposed;
arg.window_handle = reinterpret_cast<window>(wd);
if (emit(event_code::expose, wd, arg, false, get_thread_context()))
{
if (!exposed)
{
if (category::flags::root != wd->other.category)
{
//If the wd->parent is a lite_widget then find a parent until it is not a lite_widget
wd = wd->parent;
while (category::flags::lite_widget == wd->other.category)
wd = wd->parent;
}
else if (category::flags::frame == wd->other.category)
wd = wd_manager.find_window(wd->root, wd->pos_root.x, wd->pos_root.y);
}
wd_manager.refresh_tree(wd);
wd_manager.map(wd);
}
}
void bedrock::event_move(core_window_t* wd, int x, int y)
{
if (wd)
{
arg_move arg;
arg.window_handle = reinterpret_cast<window>(wd);
arg.x = x;
arg.y = y;
if (emit(event_code::move, wd, arg, false, get_thread_context()))
wd_manager.update(wd, true, true);
}
}
bool bedrock::event_msleave(core_window_t* hovered)
{
if (wd_manager.available(hovered) && hovered->flags.enabled)
{
hovered->flags.action = mouse_action::normal;
arg_mouse arg;
arg.evt_code = event_code::mouse_leave;
arg.window_handle = reinterpret_cast<window>(hovered);
arg.pos.x = arg.pos.y = 0;
arg.left_button = arg.right_button = arg.mid_button = false;
arg.ctrl = arg.shift = false;
emit(event_code::mouse_leave, hovered, arg, true, get_thread_context());
return true;
}
return false;
}
void bedrock::update_cursor(core_window_t * wd)
{
internal_scope_guard isg;
if (wd_manager.available(wd))
{
auto * thrd = get_thread_context(wd->thread_id);
if (nullptr == thrd)
return;
auto pos = native_interface::cursor_position();
auto native_handle = native_interface::find_window(pos.x, pos.y);
if (!native_handle)
return;
native_interface::calc_window_point(native_handle, pos);
if (wd != wd_manager.find_window(native_handle, pos.x, pos.y))
return;
set_cursor(wd, wd->predef_cursor, thrd);
}
}
void bedrock::_m_emit_core(event_code evt_code, core_window_t* wd, bool draw_only, const ::nana::detail::event_arg_interface& event_arg)
{
switch (evt_code)
{
case event_code::click:
case event_code::dbl_click:
case event_code::mouse_enter:
case event_code::mouse_move:
case event_code::mouse_leave:
case event_code::mouse_down:
case event_code::mouse_up:
{
auto arg = dynamic_cast<const arg_mouse*>(&event_arg);
if (nullptr == arg)
return;
void(::nana::detail::drawer::*drawer_event_fn)(const arg_mouse&);
::nana::basic_event<arg_mouse>* evt_addr;
switch (evt_code)
{
case event_code::click:
drawer_event_fn = &drawer::click;
evt_addr = &wd->together.attached_events->click;
break;
case event_code::dbl_click:
drawer_event_fn = &drawer::dbl_click;
evt_addr = &wd->together.attached_events->dbl_click;
break;
case event_code::mouse_enter:
drawer_event_fn = &drawer::mouse_enter;
evt_addr = &wd->together.attached_events->mouse_enter;
break;
case event_code::mouse_move:
drawer_event_fn = &drawer::mouse_move;
evt_addr = &wd->together.attached_events->mouse_move;
break;
case event_code::mouse_leave:
drawer_event_fn = &drawer::mouse_leave;
evt_addr = &wd->together.attached_events->mouse_leave;
break;
case event_code::mouse_down:
drawer_event_fn = &drawer::mouse_down;
evt_addr = &wd->together.attached_events->mouse_down;
break;
case event_code::mouse_up:
drawer_event_fn = &drawer::mouse_up;
evt_addr = &wd->together.attached_events->mouse_up;
break;
default:
throw std::runtime_error("Invalid mouse event code");
}
(wd->drawer.*drawer_event_fn)(*arg);
if (!draw_only)
evt_addr->emit(*arg);
break;
}
case event_code::mouse_wheel:
{
auto arg = dynamic_cast<const arg_wheel*>(&event_arg);
if (arg)
{
wd->drawer.mouse_wheel(*arg);
if (!draw_only)
wd->together.attached_events->mouse_wheel.emit(*arg);
}
break;
}
case event_code::key_press:
case event_code::key_char:
case event_code::key_release:
case event_code::shortkey:
{
auto arg = dynamic_cast<const arg_keyboard*>(&event_arg);
if (nullptr == arg)
return;
void(::nana::detail::drawer::*drawer_event_fn)(const arg_keyboard&);
::nana::basic_event<arg_keyboard>* evt_addr;
switch (evt_code)
{
case event_code::key_press:
drawer_event_fn = &drawer::key_press;
evt_addr = &wd->together.attached_events->key_press;
break;
case event_code::key_char:
drawer_event_fn = &drawer::key_char;
evt_addr = &wd->together.attached_events->key_char;
break;
case event_code::key_release:
drawer_event_fn = &drawer::key_release;
evt_addr = &wd->together.attached_events->key_release;
break;
case event_code::shortkey:
drawer_event_fn = &drawer::shortkey;
evt_addr = &wd->together.attached_events->shortkey;
break;
default:
throw std::runtime_error("Invalid keyboard event code");
}
(wd->drawer.*drawer_event_fn)(*arg);
if (!draw_only)
evt_addr->emit(*arg);
break;
}
case event_code::expose:
if (!draw_only)
{
auto arg = dynamic_cast<const arg_expose*>(&event_arg);
if (arg)
wd->together.attached_events->expose.emit(*arg);
}
break;
case event_code::focus:
{
auto arg = dynamic_cast<const arg_focus*>(&event_arg);
if (arg)
{
wd->drawer.focus(*arg);
if (!draw_only)
wd->together.attached_events->focus.emit(*arg);
}
break;
}
case event_code::move:
{
auto arg = dynamic_cast<const arg_move*>(&event_arg);
if (arg)
{
wd->drawer.move(*arg);
if (!draw_only)
wd->together.attached_events->move.emit(*arg);
}
break;
}
case event_code::resizing:
{
auto arg = dynamic_cast<const arg_resizing*>(&event_arg);
if (arg)
{
wd->drawer.resizing(*arg);
if (!draw_only)
wd->together.attached_events->resizing.emit(*arg);
}
break;
}
case event_code::resized:
{
auto arg = dynamic_cast<const arg_resized*>(&event_arg);
if (arg)
{
wd->drawer.resized(*arg);
if (!draw_only)
wd->together.attached_events->resized.emit(*arg);
}
break;
}
case event_code::unload:
if (!draw_only)
{
auto arg = dynamic_cast<const arg_unload*>(&event_arg);
if (arg && (wd->other.category == category::flags::root))
{
auto evt_ptr = dynamic_cast<events_root_extension*>(wd->together.attached_events);
if (evt_ptr)
evt_ptr->unload.emit(*arg);
}
}
break;
case event_code::destroy:
if (!draw_only)
{
auto arg = dynamic_cast<const arg_destroy*>(&event_arg);
if (arg)
wd->together.attached_events->destroy.emit(*arg);
}
break;
default:
throw std::runtime_error("Invalid event code");
}
}
void bedrock::_m_except_handler()
{
std::vector<core_window_t*> v;
wd_manager.all_handles(v);
if (v.size())
{
std::vector<native_window_type> roots;
native_window_type root = nullptr;
unsigned tid = nana::system::this_thread_id();
for (auto wd : v)
{
if ((wd->thread_id == tid) && (wd->root != root))
{
root = wd->root;
if (roots.cend() == std::find(roots.cbegin(), roots.cend(), root))
roots.push_back(root);
}
}
for (auto i : roots)
interface_type::close_window(i);
}
}
}//end namespace detail
}//end namespace nana

View File

@@ -0,0 +1,23 @@
/*
* Bedrock Selector
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Nana Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://nanapro.sourceforge.net/LICENSE_1_0.txt)
*
* @file: nana/gui/detail/bedrock_selector.cpp
*
* This file is used to support the Nana project of some cross-platform IDE,
*
*/
#include <nana/config.hpp>
#if defined(NANA_WINDOWS)
#include "win32/bedrock.cpp"
#elif defined(NANA_LINUX)
#include "linux_X11/bedrock.cpp"
#endif

View File

@@ -0,0 +1,388 @@
/*
* A Drawer 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/detail/drawer.cpp
*/
#include <nana/config.hpp>
#include GUI_BEDROCK_HPP
#include <nana/gui/detail/drawer.hpp>
#include <nana/gui/detail/dynamic_drawing_object.hpp>
#include <nana/gui/detail/effects_renderer.hpp>
#include <nana/gui/detail/basic_window.hpp>
#if defined(NANA_X11)
#include <nana/detail/linux_X11/platform_spec.hpp>
#endif
#include <algorithm>
namespace nana
{
typedef detail::edge_nimbus_renderer<detail::bedrock::core_window_t> edge_nimbus_renderer_t;
//class drawer_trigger
drawer_trigger::~drawer_trigger(){}
void drawer_trigger::attached(widget_reference, graph_reference){}
void drawer_trigger::detached(){} //none-const
void drawer_trigger::typeface_changed(graph_reference){}
void drawer_trigger::refresh(graph_reference){}
void drawer_trigger::resizing(graph_reference, const arg_resizing&)
{
overrided_ = false;
}
void drawer_trigger::resized(graph_reference graph, const arg_resized&)
{
overrided_ = true;
this->refresh(graph);
detail::bedrock::instance().thread_context_lazy_refresh();
}
void drawer_trigger::move(graph_reference, const arg_move&)
{
overrided_ = false;
}
void drawer_trigger::click(graph_reference, const arg_mouse&)
{
overrided_ = false;
}
void drawer_trigger::dbl_click(graph_reference, const arg_mouse&)
{
overrided_ = false;
}
void drawer_trigger::mouse_enter(graph_reference, const arg_mouse&)
{
overrided_ = false;
}
void drawer_trigger::mouse_move(graph_reference, const arg_mouse&)
{
overrided_ = false;
}
void drawer_trigger::mouse_leave(graph_reference, const arg_mouse&)
{
overrided_ = false;
}
void drawer_trigger::mouse_down(graph_reference, const arg_mouse&)
{
overrided_ = false;
}
void drawer_trigger::mouse_up(graph_reference, const arg_mouse&)
{
overrided_ = false;
}
void drawer_trigger::mouse_wheel(graph_reference, const arg_wheel&)
{
overrided_ = false;
}
void drawer_trigger::mouse_dropfiles(graph_reference, const arg_dropfiles&)
{
overrided_ = false;
}
void drawer_trigger::focus(graph_reference, const arg_focus&)
{
overrided_ = false;
}
void drawer_trigger::key_press(graph_reference, const arg_keyboard&)
{
overrided_ = false;
}
void drawer_trigger::key_char(graph_reference, const arg_keyboard&)
{
overrided_ = false;
}
void drawer_trigger::key_release(graph_reference, const arg_keyboard&)
{
overrided_ = false;
}
void drawer_trigger::shortkey(graph_reference, const arg_keyboard&)
{
overrided_ = false;
}
void drawer_trigger::_m_reset_overrided()
{
overrided_ = true;
}
bool drawer_trigger::_m_overrided() const
{
return overrided_;
}
//end class drawer_trigger
namespace detail
{
typedef bedrock bedrock_type;
//class drawer
drawer::~drawer()
{
for(auto p : dynamic_drawing_objects_)
{
delete p;
}
}
void drawer::bind(basic_window* cw)
{
core_window_ = cw;
}
void drawer::typeface_changed()
{
if(realizer_)
realizer_->typeface_changed(graphics);
}
void drawer::click(const arg_mouse& arg)
{
_m_emit(event_code::click, arg, &drawer_trigger::click);
}
void drawer::dbl_click(const arg_mouse& arg)
{
_m_emit(event_code::dbl_click, arg, &drawer_trigger::dbl_click);
}
void drawer::mouse_enter(const arg_mouse& arg)
{
_m_emit(event_code::mouse_enter, arg, &drawer_trigger::mouse_enter);
}
void drawer::mouse_move(const arg_mouse& arg)
{
_m_emit(event_code::mouse_move, arg, &drawer_trigger::mouse_move);
}
void drawer::mouse_leave(const arg_mouse& arg)
{
_m_emit(event_code::mouse_leave, arg, &drawer_trigger::mouse_leave);
}
void drawer::mouse_down(const arg_mouse& arg)
{
_m_emit(event_code::mouse_down, arg, &drawer_trigger::mouse_down);
}
void drawer::mouse_up(const arg_mouse& arg)
{
_m_emit(event_code::mouse_up, arg, &drawer_trigger::mouse_up);
}
void drawer::mouse_wheel(const arg_wheel& arg)
{
_m_emit(event_code::mouse_wheel, arg, &drawer_trigger::mouse_wheel);
}
void drawer::mouse_dropfiles(const arg_dropfiles& arg)
{
_m_emit(event_code::mouse_drop, arg, &drawer_trigger::mouse_dropfiles);
}
void drawer::resizing(const arg_resizing& arg)
{
_m_emit(event_code::resizing, arg, &drawer_trigger::resizing);
}
void drawer::resized(const arg_resized& arg)
{
_m_emit(event_code::resized, arg, &drawer_trigger::resized);
}
void drawer::move(const arg_move& arg)
{
_m_emit(event_code::move, arg, &drawer_trigger::move);
}
void drawer::focus(const arg_focus& arg)
{
_m_emit(event_code::focus, arg, &drawer_trigger::focus);
}
void drawer::key_press(const arg_keyboard& arg)
{
_m_emit(event_code::key_press, arg, &drawer_trigger::key_press);
}
void drawer::key_char(const arg_keyboard& arg)
{
_m_emit(event_code::key_char, arg, &drawer_trigger::key_char);
}
void drawer::key_release(const arg_keyboard& arg)
{
_m_emit(event_code::key_release, arg, &drawer_trigger::key_release);
}
void drawer::shortkey(const arg_keyboard& arg)
{
_m_emit(event_code::shortkey, arg, &drawer_trigger::shortkey);
}
void drawer::map(window wd) //Copy the root buffer to screen
{
if(wd)
{
bedrock_type::core_window_t* iwd = reinterpret_cast<bedrock_type::core_window_t*>(wd);
bedrock_type::core_window_t * caret_wd = iwd->root_widget->other.attribute.root->focus;
bool owns_caret = (caret_wd && (caret_wd->together.caret) && (caret_wd->together.caret->visible()));
//The caret in X11 is implemented by Nana, it is different from Windows'
//the caret in X11 is asynchronous, it is hard to hide and show the caret
//immediately, and therefore the caret always be flickering when the graphics
//buffer is mapping to the window.
if(owns_caret)
{
#ifndef NANA_X11
caret_wd->together.caret->visible(false);
#else
owns_caret = nana::detail::platform_spec::instance().caret_update(iwd->root, *iwd->root_graph, false);
#endif
}
if(false == edge_nimbus_renderer_t::instance().render(iwd))
{
nana::rectangle vr;
if(bedrock_type::window_manager_t::wndlayout_type::read_visual_rectangle(iwd, vr))
iwd->root_graph->paste(iwd->root, vr, vr.x, vr.y);
}
if(owns_caret)
{
#ifndef NANA_X11
caret_wd->together.caret->visible(true);
#else
nana::detail::platform_spec::instance().caret_update(iwd->root, *iwd->root_graph, true);
#endif
}
}
}
void drawer::refresh()
{
if(realizer_ && (refreshing_ == false))
{
refreshing_ = true;
_m_bground_pre();
realizer_->refresh(graphics);
_m_draw_dynamic_drawing_object();
_m_bground_end();
graphics.flush();
refreshing_ = false;
}
}
drawer_trigger* drawer::realizer() const
{
return realizer_;
}
void drawer::attached(widget& wd, drawer_trigger& realizer)
{
for (auto i = std::begin(mth_state_), end = std::end(mth_state_); i != end; ++i)
*i = method_state::unknown;
realizer_ = &realizer;
realizer.attached(wd, graphics);
}
drawer_trigger* drawer::detached()
{
if(realizer_)
{
auto rmp = realizer_;
realizer_ = nullptr;
rmp->detached();
return rmp;
}
return nullptr;
}
void drawer::clear()
{
std::vector<dynamic_drawing::object*> then;
for(auto p : dynamic_drawing_objects_)
{
if(p->diehard())
then.push_back(p);
else
delete p;
}
then.swap(dynamic_drawing_objects_);
}
void* drawer::draw(std::function<void(paint::graphics&)> && f, bool diehard)
{
if(f)
{
auto p = new dynamic_drawing::user_draw_function(std::move(f), diehard);
dynamic_drawing_objects_.push_back(p);
return (diehard ? p : nullptr);
}
return nullptr;
}
void drawer::erase(void * p)
{
if(p)
{
auto i = std::find(dynamic_drawing_objects_.begin(), dynamic_drawing_objects_.end(), p);
if (i != dynamic_drawing_objects_.end())
{
delete (*i);
dynamic_drawing_objects_.erase(i);
}
}
}
void drawer::_m_bground_pre()
{
if(core_window_->effect.bground && core_window_->effect.bground_fade_rate < 0.01)
core_window_->other.glass_buffer.paste(graphics, 0, 0);
}
void drawer::_m_bground_end()
{
if(core_window_->effect.bground && core_window_->effect.bground_fade_rate >= 0.01)
core_window_->other.glass_buffer.blend(core_window_->other.glass_buffer.size(), graphics, nana::point(), core_window_->effect.bground_fade_rate);
}
void drawer::_m_draw_dynamic_drawing_object()
{
for(auto * dw : dynamic_drawing_objects_)
dw->draw(graphics);
}
//If the drawer_trigger didn't declear a lazy refresh, then use the refresh().
void drawer::_m_use_refresh()
{
if (basic_window::update_state::refresh != core_window_->other.upd_state)
refresh();
}
}//end namespace detail
}//end namespace nana

View File

@@ -0,0 +1,45 @@
/*
* The Store for the Storage Of Elements
* 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/detail/element_store.cpp
*/
#include <nana/gui/detail/element_store.hpp>
namespace nana
{
namespace detail
{
//class element_store
element_store::data::data()
: fast_ptr(nullptr)
{}
nana::element::element_interface * const * element_store::bground(const std::string& name)
{
element_interface * const * addr = &(bground_.table[name].fast_ptr);
return addr;
}
void element_store::bground(const std::string& name, const pat::cloneable<element_interface>& rhs)
{
auto & store = bground_.table[name];
store.object = rhs;
store.fast_ptr = store.object.get();
}
void element_store::bground(const std::string& name, pat::cloneable<element_interface>&& rv)
{
auto & store = bground_.table[name];
store.object = std::move(rv);
store.fast_ptr = store.object.get();
}
}//end namespace detail
}

View File

@@ -0,0 +1,52 @@
#include <nana/gui/detail/events_operation.hpp>
namespace nana
{
namespace detail
{
//class events_operation
typedef std::lock_guard<std::recursive_mutex> lock_guard;
void events_operation::make(window wd, const std::shared_ptr<general_events>& sp)
{
lock_guard lock(mutex_);
evt_table_[wd] = sp;
}
void events_operation::umake(window wd)
{
lock_guard lock(mutex_);
evt_table_.erase(wd);
}
void events_operation::register_evt(event_handle evt)
{
lock_guard lock(mutex_);
register_.insert(evt);
}
void events_operation::cancel(event_handle evt)
{
lock_guard lock(mutex_);
register_.erase(evt);
}
void events_operation::erase(event_handle evt)
{
lock_guard lock(mutex_);
auto i = register_.find(evt);
if (i != register_.end())
{
reinterpret_cast<detail::docker_interface*>(evt)->get_event()->remove(evt);
}
}
std::size_t events_operation::size() const
{
lock_guard lock(mutex_);
return register_.size();
}
//end namespace events_operation
}//end namespace detail
}//end namespace nana

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,391 @@
/*
* Window Layout 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/detail/window_layout.hpp
*
*/
#include <nana/gui/detail/window_layout.hpp>
#include <nana/gui/detail/basic_window.hpp>
#include <nana/gui/detail/native_window_interface.hpp>
#include <nana/gui/layout_utility.hpp>
#include <algorithm>
namespace nana
{
namespace detail
{
//class window_layout
void window_layout::paint(core_window_t* wd, bool is_redraw, bool is_child_refreshed)
{
if (nullptr == wd->effect.bground)
{
if (is_redraw)
{
if (wd->flags.refreshing) return;
wd->flags.refreshing = true;
wd->drawer.refresh();
wd->flags.refreshing = false;
}
maproot(wd, is_redraw, is_child_refreshed);
}
else
_m_paint_glass_window(wd, is_redraw, is_child_refreshed, false, true);
}
bool window_layout::maproot(core_window_t* wd, bool have_refreshed, bool is_child_refreshed)
{
nana::rectangle vr;
if (read_visual_rectangle(wd, vr))
{
//get the root graphics
auto& graph = *(wd->root_graph);
if (wd->other.category != category::lite_widget_tag::value)
graph.bitblt(vr, wd->drawer.graphics, nana::point(vr.x - wd->pos_root.x, vr.y - wd->pos_root.y));
_m_paste_children(wd, is_child_refreshed, have_refreshed, vr, graph, nana::point());
if (wd->parent)
{
std::vector<wd_rectangle> blocks;
blocks.reserve(10);
if (read_overlaps(wd, vr, blocks))
{
nana::point p_src;
for (auto & el : blocks)
{
if (el.window->other.category == category::frame_tag::value)
{
native_window_type container = el.window->other.attribute.frame->container;
native_interface::refresh_window(container);
graph.bitblt(el.r, container);
}
else
{
p_src.x = el.r.x - el.window->pos_root.x;
p_src.y = el.r.y - el.window->pos_root.y;
graph.bitblt(el.r, (el.window->drawer.graphics), p_src);
}
_m_paste_children(el.window, is_child_refreshed, false, el.r, graph, nana::point{});
}
}
}
_m_notify_glasses(wd, vr);
return true;
}
return false;
}
void window_layout::paste_children_to_graphics(core_window_t* wd, nana::paint::graphics& graph)
{
_m_paste_children(wd, false, false, rectangle{ wd->pos_root, wd->dimension }, graph, wd->pos_root);
}
//read_visual_rectangle
//@brief: Reads the visual rectangle of a window, the visual rectangle's reference frame is to root widget,
// the visual rectangle is a rectangular block that a window should be displayed on screen.
// The result is a rectangle that is a visible area for its ancesters.
bool window_layout::read_visual_rectangle(core_window_t* wd, nana::rectangle& visual)
{
if (false == wd->visible) return false;
visual = rectangle{ wd->pos_root, wd->dimension };
if (wd->root_widget != wd)
{
//Test if the root widget is overlapped the specified widget
//the pos of root widget is (0, 0)
if (overlap(visual, rectangle{ wd->root_widget->pos_owner, wd->root_widget->dimension }) == false)
return false;
}
for (auto* parent = wd->parent; parent; parent = parent->parent)
{
overlap(rectangle{ parent->pos_root, parent->dimension }, visual, visual);
}
return true;
}
//read_overlaps
// reads the overlaps that are overlapped a rectangular block
bool window_layout::read_overlaps(core_window_t* wd, const nana::rectangle& vis_rect, std::vector<wd_rectangle>& blocks)
{
wd_rectangle block;
while (wd->parent)
{
auto & siblings = wd->parent->children;
//It should be checked that whether the window is still a chlid of its parent.
if (siblings.size())
{
auto i = &(siblings[0]);
auto *end = i + siblings.size();
i = std::find(i, end, wd);
if (i != end)
{
//find the widget that next to wd.
for (++i; i < end; ++i)
{
core_window_t* cover = *i;
if (cover->visible && (nullptr == cover->effect.bground))
{
if (overlap(vis_rect, rectangle{ cover->pos_root, cover->dimension }, block.r))
{
block.window = cover;
blocks.push_back(block);
}
}
}
}
}
wd = wd->parent;
}
return (!blocks.empty());
}
bool window_layout::enable_effects_bground(core_window_t * wd, bool enabled)
{
if (wd->other.category != category::widget_tag::value)
return false;
if (false == enabled)
{
delete wd->effect.bground;
wd->effect.bground = nullptr;
wd->effect.bground_fade_rate = 0;
}
//Find the window whether it is registered for the bground effects
auto i = std::find(data_sect.effects_bground_windows.begin(), data_sect.effects_bground_windows.end(), wd);
if (i != data_sect.effects_bground_windows.end())
{
//If it has already registered, do nothing.
if (enabled)
return false;
//Disable the effect.
data_sect.effects_bground_windows.erase(i);
wd->other.glass_buffer.release();
return true;
}
//No such effect has registered.
if (false == enabled)
return false;
//Enable the effect.
data_sect.effects_bground_windows.push_back(wd);
wd->other.glass_buffer.make(wd->dimension.width, wd->dimension.height);
make_bground(wd);
return true;
}
//make_bground
// update the glass buffer of a glass window.
void window_layout::make_bground(core_window_t* const wd)
{
nana::point rpos{ wd->pos_root };
auto & glass_buffer = wd->other.glass_buffer;
if (wd->parent->other.category == category::lite_widget_tag::value)
{
std::vector<core_window_t*> layers;
core_window_t * beg = wd->parent;
while (beg && (beg->other.category == category::lite_widget_tag::value))
{
layers.push_back(beg);
beg = beg->parent;
}
glass_buffer.bitblt(wd->dimension, beg->drawer.graphics, wd->pos_root - beg->pos_root);
nana::rectangle r(wd->pos_owner, wd->dimension);
for (auto i = layers.rbegin(), layers_rend = layers.rend(); i != layers_rend; ++i)
{
core_window_t * pre = *i;
if (false == pre->visible)
continue;
core_window_t * term = ((i + 1 != layers_rend) ? *(i + 1) : wd);
r.x = wd->pos_root.x - pre->pos_root.x;
r.y = wd->pos_root.y - pre->pos_root.y;
for (auto child : pre->children)
{
if (child->index >= term->index)
break;
nana::rectangle ovlp;
if (child->visible && overlap(r, rectangle(child->pos_owner, child->dimension), ovlp))
{
if (child->other.category != category::lite_widget_tag::value)
glass_buffer.bitblt(nana::rectangle(ovlp.x - pre->pos_owner.x, ovlp.y - pre->pos_owner.y, ovlp.width, ovlp.height), child->drawer.graphics, nana::point(ovlp.x - child->pos_owner.x, ovlp.y - child->pos_owner.y));
ovlp.x += pre->pos_root.x;
ovlp.y += pre->pos_root.y;
_m_paste_children(child, false, false, ovlp, glass_buffer, rpos);
}
}
}
}
else
glass_buffer.bitblt(wd->dimension, wd->parent->drawer.graphics, wd->pos_owner);
const rectangle r_of_wd{ wd->pos_owner, wd->dimension };
for (auto child : wd->parent->children)
{
if (child->index >= wd->index)
break;
nana::rectangle ovlp;
if (child->visible && overlap(r_of_wd, rectangle{ child->pos_owner, child->dimension }, ovlp))
{
if (child->other.category != category::lite_widget_tag::value)
glass_buffer.bitblt(nana::rectangle{ ovlp.x - wd->pos_owner.x, ovlp.y - wd->pos_owner.y, ovlp.width, ovlp.height }, child->drawer.graphics, nana::point(ovlp.x - child->pos_owner.x, ovlp.y - child->pos_owner.y));
ovlp.x += wd->pos_root.x;
ovlp.y += wd->pos_root.y;
_m_paste_children(child, false, false, ovlp, glass_buffer, rpos);
}
}
if (wd->effect.bground)
wd->effect.bground->take_effect(reinterpret_cast<window>(wd), glass_buffer);
}
//_m_paste_children
//@brief:paste children window to the root graphics directly. just paste the visual rectangle
void window_layout::_m_paste_children(core_window_t* wd, bool is_child_refreshed, bool have_refreshed, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos)
{
nana::rectangle rect;
for (auto child : wd->children)
{
//it will not past children if no drawer and visible is false.
if ((false == child->visible) || ((child->other.category != category::lite_widget_tag::value) && child->drawer.graphics.empty()))
continue;
if (nullptr == child->effect.bground)
{
if (overlap(nana::rectangle{ child->pos_root, child->dimension }, parent_rect, rect))
{
bool have_child_refreshed = false;
if (child->other.category != category::lite_widget_tag::value)
{
if (is_child_refreshed && (false == child->flags.refreshing))
{
have_child_refreshed = true;
child->flags.refreshing = true;
child->drawer.refresh();
child->flags.refreshing = false;
}
graph.bitblt(nana::rectangle(rect.x - graph_rpos.x, rect.y - graph_rpos.y, rect.width, rect.height),
child->drawer.graphics, nana::point(rect.x - child->pos_root.x, rect.y - child->pos_root.y));
}
_m_paste_children(child, is_child_refreshed, have_child_refreshed, rect, graph, graph_rpos);
}
}
else
{
//If have_refreshed, the glass should be notified.
_m_paint_glass_window(child, false, is_child_refreshed, have_refreshed, false);
}
}
}
void window_layout::_m_paint_glass_window(core_window_t* wd, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other)
{
if (wd->flags.refreshing && is_redraw) return;
nana::rectangle vr;
if (read_visual_rectangle(wd, vr))
{
if (is_redraw || called_by_notify)
{
if (called_by_notify)
make_bground(wd);
wd->flags.refreshing = true;
wd->drawer.refresh();
wd->flags.refreshing = false;
}
auto & root_graph = *(wd->root_graph);
//Map root
root_graph.bitblt(vr, wd->drawer.graphics, nana::point(vr.x - wd->pos_root.x, vr.y - wd->pos_root.y));
_m_paste_children(wd, is_child_refreshed, (is_redraw || called_by_notify), vr, root_graph, nana::point());
if (wd->parent)
{
std::vector<wd_rectangle> blocks;
read_overlaps(wd, vr, blocks);
for (auto & n : blocks)
{
root_graph.bitblt(n.r, (n.window->drawer.graphics), nana::point(n.r.x - n.window->pos_root.x, n.r.y - n.window->pos_root.y));
}
}
if (notify_other)
_m_notify_glasses(wd, vr);
}
}
//_m_notify_glasses
//@brief: Notify the glass windows that are overlapped with the specified vis_rect
void window_layout::_m_notify_glasses(core_window_t* const sigwd, const nana::rectangle& r_visual)
{
typedef category::flags cat_flags;
nana::rectangle r_of_sigwd(sigwd->pos_root, sigwd->dimension);
for (auto wd : data_sect.effects_bground_windows)
{
if (wd == sigwd || !wd->visible || !wd->visible_parents() ||
(false == overlap(nana::rectangle{ wd->pos_root, wd->dimension }, r_of_sigwd)))
continue;
if (sigwd->parent == wd->parent)
{
if (sigwd->index >= wd->index)
continue;
}
else if (sigwd != wd->parent)
{
if (wd->parent && (cat_flags::lite_widget == wd->parent->other.category))
{
//Test if sigwd is an ancestor of the glass window, and there are lite widgets
//between sigwd and glass window.
auto ancestor = wd->parent->parent;
while (ancestor && (ancestor != sigwd) && (cat_flags::lite_widget == ancestor->other.category))
ancestor = ancestor->parent;
if ((ancestor != sigwd) || (cat_flags::lite_widget == ancestor->other.category))
continue;
}
else
{
//test if sigwnd is a parent of glass window x, or a slibing of the glass window, or a child of the slibing of the glass window.
core_window_t *p = wd->parent, *signode = sigwd;
while (signode->parent && (signode->parent != p))
signode = signode->parent;
if ((!signode->parent) || (signode->index >= wd->index))
continue;
}
}
else
continue;
_m_paint_glass_window(wd, true, false, true, true);
}
}
//end class window_layout
window_layout::data_section window_layout::data_sect;
}//end namespace detail
}//end namespace nana

File diff suppressed because it is too large Load Diff

219
source/gui/dragger.cpp Normal file
View File

@@ -0,0 +1,219 @@
#include <nana/gui/dragger.hpp>
namespace nana
{
class dragger::dragger_impl_t
{
struct drag_target_t
{
window wd;
rectangle restrict_area;
arrange move_direction;
point origin;
drag_target_t(window w, const rectangle& r, arrange m)
: wd(w), restrict_area(r), move_direction(m)
{}
};
struct trigger_t
{
window wd;
event_handle press;
event_handle over;
event_handle release;
event_handle destroy;
};
public:
dragger_impl_t()
: dragging_(false)
{}
~dragger_impl_t()
{
_m_clear_triggers();
}
void drag_target(window wd, const rectangle& restrict_area, arrange arg)
{
for (auto & td : targets_)
{
if (td.wd == wd)
{
td.restrict_area = restrict_area;
td.move_direction = arg;
return;
}
}
targets_.emplace_back(wd, restrict_area, arg);
}
void remove_target(window wd)
{
for (auto i = targets_.begin(); i != targets_.end(); ++i)
{
if (i->wd == wd)
{
targets_.erase(i);
return;
}
}
}
void trigger(window wd)
{
trigger_t tg;
tg.wd = wd;
auto fn = std::bind(&dragger_impl_t::_m_trace, this, std::placeholders::_1);
auto & events = API::events(wd);
tg.press = events.mouse_down.connect(fn);
tg.over = events.mouse_move.connect(fn);
tg.release = events.mouse_up.connect(fn);
tg.destroy = events.destroy.connect([this](const arg_destroy& arg){
_m_destroy(arg.window_handle);
});
triggers_.push_back(tg);
}
private:
void _m_clear_triggers()
{
for(auto & t : triggers_)
{
API::umake_event(t.press);
API::umake_event(t.over);
API::umake_event(t.release);
API::umake_event(t.destroy);
API::capture_window(t.wd, false);
}
triggers_.clear();
}
void _m_destroy(::nana::window wd)
{
for(auto i = triggers_.begin(), end = triggers_.end(); i != end; ++i)
{
if(i->wd == wd)
{
triggers_.erase(i);
API::capture_window(wd, false);
return;
}
}
}
void _m_check_restrict_area(nana::point & pos, const nana::size & size, const nana::rectangle& restr_area)
{
if ((pos.x > 0) && (static_cast<int>(size.width) + pos.x > restr_area.right()))
pos.x = restr_area.right() - static_cast<int>(size.width);
if (pos.x < restr_area.x)
pos.x = restr_area.x;
if ((pos.y > 0) && (static_cast<int>(size.height) + pos.y > restr_area.bottom()))
pos.y = restr_area.bottom() - static_cast<int>(size.height);
if (pos.y < restr_area.y)
pos.y = restr_area.y;
}
void _m_trace(const arg_mouse& arg)
{
switch(arg.evt_code)
{
case event_code::mouse_down:
dragging_ = true;
API::capture_window(arg.window_handle, true);
origin_ = API::cursor_position();
for(auto & t : targets_)
{
t.origin = API::window_position(t.wd);
window owner = API::get_owner_window(t.wd);
if(owner)
API::calc_screen_point(owner, t.origin);
}
break;
case event_code::mouse_move:
if(dragging_ && arg.left_button)
{
auto pos = API::cursor_position();
pos -= origin_;
for(auto & t : targets_)
{
if(API::is_window_zoomed(t.wd, true) == false)
{
auto owner = API::get_owner_window(t.wd);
auto wdps = t.origin;
if (owner)
API::calc_window_point(owner, wdps);
switch (t.move_direction)
{
case nana::arrange::horizontal:
wdps.x += pos.x;
break;
case nana::arrange::vertical:
wdps.y += pos.y;
break;
default:
wdps += pos;
}
if (!t.restrict_area.empty())
_m_check_restrict_area(wdps, API::window_size(t.wd), t.restrict_area);
API::move_window(t.wd, wdps.x, wdps.y);
}
}
}
break;
case event_code::mouse_up:
API::capture_window(arg.window_handle, false);
dragging_ = false;
break;
default:
break;
}
}
private:
bool dragging_;
nana::point origin_;
std::vector<drag_target_t> targets_;
std::vector<trigger_t> triggers_;
};
//class dragger
dragger::dragger()
: impl_(new dragger_impl_t)
{
}
dragger::~dragger()
{
delete impl_;
}
void dragger::target(window wd)
{
impl_->drag_target(wd, rectangle(), nana::arrange::horizontal_vertical);
}
void dragger::target(window wd, const rectangle& restrict_area, nana::arrange arg)
{
impl_->drag_target(wd, restrict_area, arg);
}
void dragger::remove_target(window wd)
{
impl_->remove_target(wd);
}
void dragger::trigger(window tg)
{
impl_->trigger(tg);
}
//end class dragger
}//end namespace nana

86
source/gui/drawing.cpp Normal file
View File

@@ -0,0 +1,86 @@
/*
* A Drawing 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/drawing.cpp
*/
#include <nana/gui/drawing.hpp>
#include <nana/gui/programming_interface.hpp>
#include <nana/gui/detail/basic_window.hpp>
namespace nana
{
//restrict
//@brief: This name is only visible for this compiling-unit
namespace restrict
{
typedef detail::bedrock::core_window_t core_window_t;
extern detail::bedrock& bedrock;
inline detail::drawer& get_drawer(window wd)
{
return reinterpret_cast<core_window_t*>(wd)->drawer;
}
}
//class drawing
drawing::drawing(window wd)
:handle_(wd)
{}
drawing::~drawing(){} //Just for polymorphism
bool drawing::empty() const
{
return API::empty_window(handle_) || reinterpret_cast<restrict::core_window_t*>(handle_)->root_graph->empty();
}
void drawing::update() const
{
API::refresh_window(handle_);
}
void drawing::draw(const draw_fn_t& f)
{
if(API::empty_window(handle_)) return;
restrict::get_drawer(handle_).draw(draw_fn_t(f), false);
}
void drawing::draw(draw_fn_t&& f)
{
if(API::empty_window(handle_)) return;
restrict::get_drawer(handle_).draw(std::move(f), false);
}
drawing::diehard_t drawing::draw_diehard(const draw_fn_t& f)
{
if(API::empty_window(handle_)) return nullptr;
return reinterpret_cast<diehard_t>(restrict::get_drawer(handle_).draw(draw_fn_t(f), true));
}
drawing::diehard_t drawing::draw_diehard(draw_fn_t&& f)
{
if(API::empty_window(handle_)) return nullptr;
return reinterpret_cast<diehard_t>(restrict::get_drawer(handle_).draw(std::move(f), true));
}
void drawing::erase(diehard_t d)
{
if(API::empty_window(handle_))
restrict::get_drawer(handle_).erase(d);
}
void drawing::clear()
{
if(API::empty_window(handle_)) return;
restrict::get_drawer(handle_).clear();
}
//end class drawing
}//end namespace nana

78
source/gui/effects.cpp Normal file
View File

@@ -0,0 +1,78 @@
#include <nana/gui/effects.hpp>
#include <nana/gui/programming_interface.hpp>
namespace nana
{
namespace effects
{
bground_interface::~bground_interface()
{}
bground_factory_interface::~bground_factory_interface()
{}
//Here defines some effect implementations.
namespace impl
{
class transparent
: public bground_interface
{
public:
transparent(std::size_t percent)
: fade_rate_( percent <= 100 ? double(percent) / 100.0 : 0)
{}
void take_effect(window wd, graph_reference graph) const
{
if(fade_rate_ < 0.001)
return;
nana::color_t color = API::background(wd);
graph.blend(graph.size(), color, fade_rate_);
}
private:
const double fade_rate_;
};
class blur
: public bground_interface
{
public:
blur(std::size_t radius)
:radius_(radius)
{}
void take_effect(window, graph_reference graph) const
{
graph.blur(graph.size(), radius_);
}
private:
const std::size_t radius_;
};
}//end namespace impl
//class bground_transparent
bground_transparent::bground_transparent(std::size_t percent)
: percent_(percent)
{}
bground_interface* bground_transparent::create() const
{
return new impl::transparent(percent_);
}
//end class bgroun_transparent
//class bground_blur
bground_blur::bground_blur(std::size_t radius)
: radius_(radius)
{}
bground_interface * bground_blur::create() const
{
return new impl::blur(radius_);
}
//end class bground_blur
}
}//end namespace nana

820
source/gui/element.cpp Normal file
View File

@@ -0,0 +1,820 @@
#include <nana/gui/element.hpp>
#include <nana/gui/detail/bedrock.hpp>
#include <nana/gui/detail/element_store.hpp>
#include <nana/paint/image.hpp>
#include <map>
#include <string>
#if defined(STD_THREAD_NOT_SUPPORTED)
#include <nana/std_mutex.hpp>
#else
#include <mutex>
#endif
namespace nana
{
//Element definitions
namespace element
{
class crook
: public crook_interface
{
bool draw(graph_reference graph, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle& r, element_state es, const data& crook_data) override
{
if(crook_data.radio)
{
unsigned bmp_unchecked[12][12] = {
{0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xCFD0D0, 0xAAABAB, 0x919292, 0x919292, 0xAAABAB, 0xCFD0D0, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF},
{0xFFFFFF, 0xFFFFFF, 0xA3A4A4, 0xB9BABA, 0xDBDBDB, 0xF2F2F2, 0xF2F2F2, 0xDBDBDB, 0xB9BABA, 0xA3A4A4, 0xFFFFFF, 0xFFFFFF},
{0xFFFFFF, 0xA2A3A3, 0xC3C3C3, 0xEDEDEE, 0xC6C9CD, 0xB5BABF, 0xB5BABF, 0xC8CBCE, 0xEDEEEE, 0xC3C3C3, 0xA2A3A3, 0xFFFFFF},
{0xCFD0D0, 0xB9BABA, 0xE9EAEB, 0xB3B8BD, 0xBDC2C7, 0xC8CDD2, 0xC9CED3, 0xC5C8CC, 0xBEC1C5, 0xEBECEC, 0xB9BABA, 0xCFD0D0},
{0xA9A9A9, 0xDCDCDC, 0xC5C8CC, 0xBEC3C9, 0xCBCFD5, 0xCED2D7, 0xD5D8DC, 0xDCDEE0, 0xD3D4D7, 0xD4D5D5, 0xDCDCDC, 0xA9A9A9},
{0x919292, 0xF2F2F2, 0xB4B9BD, 0xCDD1D6, 0xD3D6DA, 0xDBDDDF, 0xE4E4E5, 0xE9E9E9, 0xE8E8E9, 0xD0D1D2, 0xF2F2F2, 0x919292},
{0x919292, 0xF2F2F2, 0xBBBEC2, 0xD7DADD, 0xE0E1E3, 0xE9E9E9, 0xEFEFEF, 0xF0F0F0, 0xEFEFF0, 0xDBDCDC, 0xEFEFEF, 0x939494},
{0xA7A8A8, 0xDDDDDD, 0xCFD1D3, 0xD5D6D8, 0xE9E9E9, 0xEFEFEF, 0xF4F4F4, 0xF5F5F5, 0xEEEEEE, 0xE8E8E8, 0xDDDDDD, 0xA7A8A8},
{0xCECECE, 0xBABBBB, 0xECECED, 0xCDCECF, 0xE1E2E2, 0xF0F0F0, 0xF4F4F4, 0xF1F1F1, 0xEBEBEB, 0xF2F2F2, 0xBABBBB, 0xCECECE},
{0xFFFFFF, 0xA2A3A3, 0xC3C3C3, 0xF0F0F1, 0xE2E3E3, 0xE4E4E5, 0xE9EAEA, 0xEEEEEF, 0xF3F3F3, 0xC3C3C3, 0xA2A3A3, 0xFFFFFF},
{0xFFFFFF, 0xFFFFFF, 0xA2A3A3, 0xBABBBB, 0xDBDBDB, 0xF4F4F4, 0xF4F4F4, 0xDCDCDC, 0xBABBBB, 0xA2A3A3, 0xFFFFFF, 0xFFFFFF},
{0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xCECECE, 0xAAABAB, 0x8E8F8F, 0x8E8F8F, 0xA9A9A9, 0xCECECE, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF}
};
unsigned bmp_unchecked_highlight[12][12] = {
{0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xB7CCD8, 0x7FA4BA, 0x5989A5, 0x5989A5, 0x7FA4BA, 0xB7CCD8, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF},
{0xFFFFFF, 0xFFFFFF, 0x759DB4, 0x8FB7C8, 0xBCDDE5, 0xDBF6F8, 0xDBF6F8, 0xBCDDE5, 0x8FB7C8, 0x759DB4, 0xFFFFFF, 0xFFFFFF},
{0xFFFFFF, 0x739BB3, 0x9CC2D0, 0xD3F4FA, 0x9BD7F9, 0x84CBF9, 0x84CBF9, 0x9CD8F9, 0xD4F4FA, 0x9CC2D0, 0x739BB3, 0xFFFFFF},
{0xB7CCD8, 0x8FB7C8, 0xCFF1FA, 0x80CAF9, 0x96D3FB, 0xAADDFD, 0xABDDFD, 0x9AD5FB, 0x86CEF9, 0xCFF2FA, 0x8FB7C8, 0xB7CCD8},
{0x7DA2B9, 0xBEDEE6, 0x9AD7F9, 0x98D5FB, 0xB1DFFD, 0xB2E0FD, 0xB7E3FD, 0xBCE5FD, 0xA6DCFB, 0xA1DCF9, 0xBEDEE6, 0x7DA2B9},
{0x5989A5, 0xDBF6F8, 0x80CAF9, 0xAFDEFD, 0xB6E2FD, 0xBBE5FD, 0xC1E8FD, 0xC5EAFD, 0xC7EBFD, 0x99D8FA, 0xDBF6F8, 0x5989A5},
{0x5989A5, 0xDBF6F8, 0x84CDF9, 0xB6E2FD, 0xBFE7FD, 0xC7EBFD, 0xD5F0FE, 0xDAF2FE, 0xD8F1FE, 0xB1E1FB, 0xD8F4F6, 0x5D8CA7},
{0x7BA1B8, 0xBFDFE7, 0x9FDBF9, 0xA7DDFB, 0xC8EBFD, 0xD6F1FE, 0xE2F5FE, 0xE5F6FE, 0xD8F0FD, 0xCAEDFB, 0xBFDFE7, 0x7BA1B8},
{0xB5CAD7, 0x91B8C9, 0xCFF2FA, 0x92D5F9, 0xBAE5FC, 0xDAF2FE, 0xE4F5FE, 0xDFF3FE, 0xD2EEFD, 0xDBF7FA, 0x91B8C9, 0xB5CAD7},
{0xFFFFFF, 0x739BB3, 0x9CC2D0, 0xD7F6FA, 0xBDE8FB, 0xC2E8FC, 0xD0EDFD, 0xD7F2FC, 0xDDF8FA, 0x9CC2D0, 0x739BB3, 0xFFFFFF},
{0xFFFFFF, 0xFFFFFF, 0x739BB3, 0x91B8C9, 0xBCDDE5, 0xDEF9FA, 0xDEF9FA, 0xBEDEE6, 0x91B8C9, 0x739BB3, 0xFFFFFF, 0xFFFFFF},
{0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xB5CAD7, 0x7FA4BA, 0x5586A3, 0x5586A3, 0x7DA2B9, 0xB5CAD7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF}
};
unsigned bmp_checked[12][12] = {
{0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xCFD0D0, 0xAAABAB, 0x919292, 0x919292, 0xAAABAB, 0xCFD0D0, 0xFCFCFC, 0xFFFFFF, 0xFFFFFF},
{0xFFFFFF, 0xFFFFFF, 0xA3A4A4, 0xB9BABA, 0xDBDBDB, 0xF2F2F2, 0xF2F2F2, 0xDBDBDB, 0xB9BABA, 0xA3A4A4, 0xF3F3F3, 0xFFFFFF},
{0xFFFFFF, 0xA2A3A3, 0xC3C3C3, 0xEDEDEE, 0xBABFC5, 0x85939F, 0x85939F, 0xBCC1C5, 0xEDEEEE, 0xC3C3C3, 0xA2A3A3, 0xFCFCFC},
{0xCFD0D0, 0xB9BABA, 0xE9EAEB, 0x8997A2, 0x274760, 0x486378, 0x365166, 0x204058, 0x8E9AA4, 0xEBECEC, 0xB9BABA, 0xCFD0D0},
{0xA9A9A9, 0xDCDCDC, 0xB9BEC4, 0x24445D, 0x91B2C6, 0xC7EBFD, 0x69C2D4, 0x14405C, 0x1E3F57, 0xC9CCCD, 0xDCDCDC, 0xA9A9A9},
{0x919292, 0xF2F2F2, 0x7D8D98, 0x304B5F, 0x90D5E5, 0x5DCEDD, 0x28A2D1, 0x178AC7, 0x183348, 0x8F9CA6, 0xF2F2F2, 0x919292},
{0x919292, 0xF2F2F2, 0x82909C, 0x183347, 0x228FC6, 0x209DD1, 0x1898D1, 0x0E84C6, 0x183348, 0x97A3AC, 0xEFEFEF, 0x939494},
{0xA7A8A8, 0xDDDDDD, 0xC0C5C9, 0x1E3F57, 0x0F3F5D, 0x0F83C7, 0x0B82C7, 0x0C3D5D, 0x1F3F58, 0xD9DCDE, 0xDDDDDD, 0xA7A8A8},
{0xCECECE, 0xBABBBB, 0xECECED, 0x99A3AB, 0x1D3E57, 0x18354A, 0x19344A, 0x1E3E57, 0xAEB8BF, 0xF2F2F2, 0xBABBBB, 0xCECECE},
{0xFFFFFF, 0xA2A3A3, 0xC3C3C3, 0xF0F0F1, 0xD1D5D7, 0xA6B0B9, 0xA9B4BC, 0xDCDFE2, 0xF3F3F3, 0xC3C3C3, 0xA2A3A3, 0xFFFFFF},
{0xFFFFFF, 0xFFFFFF, 0xA2A3A3, 0xBABBBB, 0xDBDBDB, 0xF4F4F4, 0xF4F4F4, 0xDCDCDC, 0xBABBBB, 0xA2A3A3, 0xFFFFFF, 0xFFFFFF},
{0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xCECECE, 0xAAABAB, 0x8E8F8F, 0x8E8F8F, 0xA9A9A9, 0xCECECE, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF}
};
unsigned bmp_checked_highlight[12][12] = {
{0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xB7CCD8, 0x7FA4BA, 0x5989A5, 0x5989A5, 0x7FA4BA, 0xB7CCD8, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF},
{0xFFFFFF, 0xFFFFFF, 0x759DB4, 0x8FB7C8, 0xBCDDE5, 0xDBF6F8, 0xDBF6F8, 0xBCDDE5, 0x8FB7C8, 0x759DB4, 0xFFFFFF, 0xFFFFFF},
{0xFFFFFF, 0x739BB3, 0x9CC2D0, 0xD3F4FA, 0x92CCED, 0x639FC7, 0x639FC7, 0x93CDED, 0xD4F4FA, 0x9CC2D0, 0x739BB3, 0xFFFFFF},
{0xB7CCD8, 0x8FB7C8, 0xCFF1FA, 0x66A3CC, 0x264862, 0x47647A, 0x355268, 0x1E405A, 0x66A3C9, 0xCFF2FA, 0x8FB7C8, 0xB7CCD8},
{0x7DA2B9, 0xBEDEE6, 0x91CCED, 0x22445E, 0x9DBBCD, 0xE9F7FE, 0x7FE6EE, 0x154664, 0x1D3F58, 0x99D3EF, 0xBEDEE6, 0x7DA2B9},
{0x5989A5, 0xDBF6F8, 0x5C98BF, 0x2F4B60, 0xB1F6FA, 0x74FFFF, 0x32CAFF, 0x1DAAF3, 0x173348, 0x6CA1C0, 0xDBF6F8, 0x5989A5},
{0x5989A5, 0xDBF6F8, 0x5E99BF, 0x173348, 0x2AB0F2, 0x28C4FF, 0x1EBEFF, 0x11A3F2, 0x173348, 0x7BA6C0, 0xD8F4F6, 0x5D8CA7},
{0x7BA1B8, 0xBFDFE7, 0x94CEEB, 0x1D3F58, 0x114567, 0x13A2F3, 0x0DA0F3, 0x0D4367, 0x1E3F58, 0xBEE0EF, 0xBFDFE7, 0x7BA1B8},
{0xB5CAD7, 0x91B8C9, 0xCFF2FA, 0x6FA8C9, 0x1C3E58, 0x18354B, 0x18354B, 0x1D3E58, 0x9CBACC, 0xDBF7FA, 0x91B8C9, 0xB5CAD7},
{0xFFFFFF, 0x739BB3, 0x9CC2D0, 0xD7F6FA, 0xAFDAED, 0x8EB3C9, 0x98B7CA, 0xC7E3EE, 0xDDF8FA, 0x9CC2D0, 0x739BB3, 0xFFFFFF},
{0xFFFFFF, 0xFFFFFF, 0x739BB3, 0x91B8C9, 0xBCDDE5, 0xDEF9FA, 0xDEF9FA, 0xBEDEE6, 0x91B8C9, 0x739BB3, 0xFFFFFF, 0xFFFFFF},
{0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xB5CAD7, 0x7FA4BA, 0x5586A3, 0x5586A3, 0x7DA2B9, 0xB5CAD7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF}
};
unsigned bmp_checked_press[12][12] = {
{0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xA6BDCE, 0x6089A8, 0x31668E, 0x31668E, 0x6089A8, 0xA6BDCE, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF},
{0xFFFFFF, 0xFFFFFF, 0x5480A1, 0x6C99B8, 0x9DC4DC, 0xBEE1F3, 0xBEE1F3, 0x9DC4DC, 0x6C99B8, 0x5480A1, 0xFFFFFF, 0xFFFFFF},
{0xFFFFFF, 0x517E9F, 0x7AA5C2, 0xB6DDF3, 0x73B2D6, 0x4A8AB0, 0x4A8AB0, 0x74B3D8, 0xB7DEF3, 0x7AA5C2, 0x517E9F, 0xFFFFFF},
{0xA6BDCE, 0x6C99B8, 0xB1DBF1, 0x4B8DB4, 0x244660, 0x456279, 0x335167, 0x1D3F59, 0x4C90B7, 0xB1DCF3, 0x6C99B8, 0xA6BDCE},
{0x5E87A6, 0x9FC5DD, 0x71B1D6, 0x21435D, 0x7EA5BC, 0x95D9FC, 0x478BAE, 0x113858, 0x1B3E58, 0x78BDE2, 0x9FC5DD, 0x5E87A6},
{0x31668E, 0xBEE1F3, 0x4484AA, 0x2E4A60, 0x5DA2C6, 0x3A84AA, 0x19658D, 0x0F5984, 0x153248, 0x5794B7, 0xBEE1F3, 0x31668E},
{0x31668E, 0xBEE1F3, 0x4687AE, 0x153247, 0x165D84, 0x14628D, 0x0F5F8D, 0x095684, 0x163248, 0x6B9DB9, 0xBBDEF1, 0x366990},
{0x5B85A5, 0xA0C7DE, 0x74B7DC, 0x1B3E58, 0x0D3659, 0x0A5583, 0x075483, 0x0A3459, 0x1E3F58, 0xA9D2E9, 0xA0C7DE, 0x5B85A5},
{0xA3BBCD, 0x6D9BBA, 0xB2DDF3, 0x5599BE, 0x1C3E57, 0x17344A, 0x17344B, 0x1D3E57, 0x91B3C7, 0xC1E4F6, 0x6D9BBA, 0xA3BBCD},
{0xFFFFFF, 0x517E9F, 0x7AA5C2, 0xBBE1F5, 0x98CAE4, 0x80AAC3, 0x8CAFC5, 0xB7D7EA, 0xC2E4F6, 0x7AA5C2, 0x517E9F, 0xFFFFFF},
{0xFFFFFF, 0xFFFFFF, 0x517E9F, 0x6D9BBA, 0x9DC4DC, 0xC2E4F6, 0xC2E4F6, 0x9FC5DD, 0x6D9BBA, 0x517E9F, 0xFFFFFF, 0xFFFFFF},
{0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xA3BBCD, 0x6089A8, 0x2C628B, 0x2C628B, 0x5E87A6, 0xA3BBCD, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF}
};
unsigned (*colormap)[12][12] = &bmp_unchecked;
switch(es)
{
case element_state::normal:
case element_state::focus_normal:
colormap = (crook_data.check_state != state::unchecked ? &bmp_checked : &bmp_unchecked);
break;
case element_state::hovered:
case element_state::focus_hovered:
colormap = (crook_data.check_state != state::unchecked ? &bmp_checked_highlight : &bmp_unchecked_highlight);
break;
case element_state::pressed:
colormap = &bmp_checked_press;
break;
default:
break;
}
const int x = r.x + 2;
const int y = r.y + 2;
for(int top = 0; top < 12; ++top)
{
for(int left = 0; left < 12; ++left)
{
if((*colormap)[top][left] != 0xFFFFFF)
graph.set_pixel(left + x, top + y, (*colormap)[top][left]);
}
}
}
else
{
const nana::color_t highlighted = 0x5EB6F7;
switch(es)
{
case element_state::hovered:
case element_state::focus_hovered:
bgcolor = graph.mix(bgcolor, highlighted, 0.8);
fgcolor = graph.mix(fgcolor, highlighted, 0.8);
break;
case element_state::pressed:
bgcolor = graph.mix(bgcolor, highlighted, 0.4);
fgcolor = graph.mix(fgcolor, highlighted, 0.4);
break;
case element_state::disabled:
bgcolor = fgcolor = 0xB2B7BC;
break;
default:
//Leave things as they are
break;
}
const int x = r.x + 1;
const int y = r.y + 1;
graph.rectangle(x, y, 13, 13, fgcolor, false);
graph.rectangle(x + 1, y + 1, 11, 11, bgcolor, true);
switch(crook_data.check_state)
{
case state::checked:
{
int sx = x + 2;
int sy = y + 4;
for(int i = 0; i < 3; i++)
{
sx++;
sy++;
graph.line(sx, sy, sx, sy + 3, fgcolor);
}
for(int i = 0; i < 4; i++)
{
sx++;
sy--;
graph.line(sx, sy, sx, sy + 3, fgcolor);
}
}
break;
case state::partial:
graph.rectangle(x + 2, y + 2, 9, 9, fgcolor, true);
break;
default:
break;
}
}
return true;
}
}; //end class crook
class menu_crook
: public crook_interface
{
bool draw(graph_reference graph, nana::color_t, nana::color_t fgcolor, const nana::rectangle& r, element_state es, const data& crook_data) override
{
if(crook_data.check_state == state::unchecked)
return true;
if(crook_data.radio)
{
unsigned colormap[8][8] = {
{0xFF000000,0xdee7ef,0x737baa,0x232674,0x3c3f84,0x8d96ba,0xe0e9ef,0xFF000000},
{0xdce4ed,0x242875,0x6f71b3,0x9fa0d6,0xc3c4e9,0xb1b2da,0x5c6098,0xdbe4ed},
{0x7b81ad,0x4f5199,0x8182c1,0xa1a2d4,0xccccea,0xcccced,0x9c9dcf,0x7981ae},
{0x2b2d77,0x4f509a,0x696baf,0x7879ba,0xa4a6d4,0xa9aad9,0x9193ce,0x1e2271},
{0x36387f,0x383a87,0x52549c,0x6162a8,0x6f71b3,0x7e7fbf,0x7879ba,0x282c78},
{0x9094ba,0x1b1c71,0x3c3e8b,0x4a4b96,0x585aa1,0x6768ac,0x464893,0x828bb6},
{0xe2eaf1,0x4b4d8d,0x16186d,0x292b7c,0x333584,0x2c2e7f,0x454b8c,0xdfe9f0},
{0xFF000000,0xe4ecf2,0x9599bd,0x454688,0x414386,0x9095bb,0xe3ebf2,0xFF000000}
};
int x = r.x + (static_cast<int>(r.width) - 8) / 2;
int y = r.y + (static_cast<int>(r.height) - 8) / 2;
for(int u = 0; u < 8; ++u)
{
for(int v = 0; v < 8; ++v)
{
if(colormap[u][v] & 0xFF000000)
continue;
graph.set_pixel(x + v, y, colormap[u][v]);
}
++y;
}
}
else
{
int x = r.x + (static_cast<int>(r.width) - 16) / 2;
int y = r.y + (static_cast<int>(r.height) - 16) / 2;
nana::color_t light = graph.mix(fgcolor, 0xFFFFFF, 0.5);
graph.line(x + 3, y + 7, x + 6, y + 10, fgcolor);
graph.line(x + 7, y + 9, x + 12, y + 4, fgcolor);
graph.line(x + 3, y + 8, x + 6, y + 11, light);
graph.line(x + 7, y + 10, x + 12, y + 5, light);
graph.line(x + 4, y + 7, x + 6, y + 9, light);
graph.line(x + 7, y + 8, x + 11, y + 4, light);
}
return true;
}
};
}
template<typename ElementInterface>
class element_object
: nana::noncopyable, nana::nonmovable
{
typedef ElementInterface element_t;
typedef pat::cloneable<element::provider::factory_interface<element_t>> factory_interface;
public:
element_object()
: element_ptr_(nullptr)
{
}
~element_object()
{
if(factory_)
factory_->destroy(element_ptr_);
}
void push(const factory_interface& rhs)
{
auto keep_f = factory_;
auto keep_e = element_ptr_;
factory_ = rhs;
element_ptr_ = factory_->create();
if(nullptr == factory_ || nullptr == element_ptr_)
{
if(element_ptr_)
factory_->destroy(element_ptr_);
factory_.reset();
factory_ = keep_f;
element_ptr_ = keep_e;
}
else
spare_.emplace_back(keep_e, keep_f);
}
element_t * const * keeper() const
{
return &element_ptr_;
}
private:
factory_interface factory_; //Keep the factory for destroying the element
element_t * element_ptr_;
std::vector<std::pair<element_t*, factory_interface>> spare_;
};
class element_manager
: nana::noncopyable, nana::nonmovable
{
//VC2012 does not support alias declaration.
//template<typename E> using factory_interface = element::provider::factory_interface<E>;
template<typename ElementInterface>
struct item
{
element_object<ElementInterface> * employee;
std::map<std::string, std::shared_ptr<element_object<ElementInterface>>> table;
};
element_manager()
{
crook_.employee = nullptr;
}
public:
static element_manager& instance()
{
static bool initial = true;
static element_manager obj;
if(initial)
{
initial = false;
element::add_crook<element::crook>("");
element::add_crook<element::menu_crook>("menu_crook");
}
return obj;
}
void crook(const std::string& name, const pat::cloneable<element::provider::factory_interface<element::crook_interface>>& factory)
{
_m_add(name, crook_, factory);
}
element::crook_interface * const * crook(const std::string& name) const
{
return _m_get(name, crook_).keeper();
}
private:
typedef std::lock_guard<std::recursive_mutex> lock_guard;
template<typename ElementInterface>
void _m_add(const std::string& name, item<ElementInterface>& m, const pat::cloneable<element::provider::factory_interface<ElementInterface>>& factory)
{
typedef element_object<ElementInterface> element_object_t;
lock_guard lock(mutex_);
auto & eop = m.table[name];
if(nullptr == eop)
eop = std::make_shared<element_object_t>();
eop->push(factory);
if(nullptr == m.employee)
m.employee = eop.get();
}
template<typename ElementInterface>
const element_object<ElementInterface>& _m_get(const std::string& name, const item<ElementInterface>& m) const
{
lock_guard lock(mutex_);
auto i = m.table.find(name);
if(i != m.table.end())
return *(i->second);
return *m.employee;
}
private:
mutable std::recursive_mutex mutex_;
item<element::crook_interface> crook_;
};
namespace element
{
//class provider
void provider::add_crook(const std::string& name, const pat::cloneable<factory_interface<crook_interface>>& factory)
{
element_manager::instance().crook(name, factory);
}
crook_interface* const * provider::keeper_crook(const std::string& name)
{
return element_manager::instance().crook(name);
}
}//end namespace element
//facades
//template<> class facade<element::crook>
facade<element::crook>::facade()
: keeper_(element::provider().keeper_crook(""))
{
data_.check_state = state::unchecked;
data_.radio = false;
}
facade<element::crook>::facade(const char* name)
: keeper_(element::provider().keeper_crook(name ? name : ""))
{
data_.check_state = state::unchecked;
data_.radio = false;
}
facade<element::crook> & facade<element::crook>::reverse()
{
data_.check_state = (data_.check_state == facade<element::crook>::state::unchecked ? facade<element::crook>::state::checked : facade<element::crook>::state::unchecked);
return *this;
}
facade<element::crook> & facade<element::crook>::check(state s)
{
data_.check_state = s;
return *this;
}
facade<element::crook>::state facade<element::crook>::checked() const
{
return data_.check_state;
}
facade<element::crook> & facade<element::crook>::radio(bool r)
{
data_.radio = r;
return *this;
}
bool facade<element::crook>::radio() const
{
return data_.radio;
}
void facade<element::crook>::switch_to(const char* name)
{
keeper_ = element::provider().keeper_crook(name);
}
bool facade<element::crook>::draw(graph_reference graph, nana::color_t bgcol, nana::color_t fgcol, const nana::rectangle& r, element_state es)
{
return (*keeper_)->draw(graph, bgcol, fgcol, r, es, data_);
}
//end class facade<element::crook>
namespace element
{
void set_bground(const char* name, const pat::cloneable<element_interface>& obj)
{
detail::bedrock::instance().get_element_store().bground(name, obj);
}
void set_bground(const char* name, pat::cloneable<element_interface> && obj)
{
detail::bedrock::instance().get_element_store().bground(name, std::move(obj));
}
//class cite
cite_bground::cite_bground(const char* name)
: ref_ptr_(detail::bedrock::instance().get_element_store().bground(name))
{
}
void cite_bground::set(const cloneable_element& rhs)
{
holder_ = rhs;
place_ptr_ = holder_.get();
ref_ptr_ = &place_ptr_;
}
void cite_bground::set(const char* name)
{
holder_.reset();
ref_ptr_ = detail::bedrock::instance().get_element_store().bground(name);
}
bool cite_bground::draw(graph_reference dst, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle& r, element_state state)
{
if (ref_ptr_ && *ref_ptr_)
return (*ref_ptr_)->draw(dst, bgcolor, fgcolor, r, state);
return false;
}
//end class cite
//class bground
struct bground::draw_method
{
virtual ~draw_method(){}
virtual draw_method * clone() const = 0;
virtual void paste(const nana::rectangle& from_r, graph_reference, const nana::point& dst_pos) = 0;
virtual void stretch(const nana::rectangle& from_r, graph_reference dst, const nana::rectangle & to_r) = 0;
};
struct bground::draw_image
: public draw_method
{
nana::paint::image image;
draw_image(const nana::paint::image& img)
: image(img)
{}
draw_method * clone() const override
{
return new draw_image(image);
}
void paste(const nana::rectangle& from_r, graph_reference dst, const nana::point& dst_pos) override
{
image.paste(from_r, dst, dst_pos);
}
void stretch(const nana::rectangle& from_r, graph_reference dst, const nana::rectangle& to_r) override
{
image.stretch(from_r, dst, to_r);
}
};
struct bground::draw_graph
: public draw_method
{
nana::paint::graphics graph;
draw_graph()
{}
draw_graph(const nana::paint::graphics& g)
: graph(g)
{}
draw_method * clone() const override
{
auto p = new draw_graph;
p->graph.make(graph.width(), graph.height());
graph.paste(p->graph, 0, 0);
return p;
}
void paste(const nana::rectangle& from_r, graph_reference dst, const nana::point& dst_pos) override
{
graph.paste(from_r, dst, dst_pos.x, dst_pos.y);
}
void stretch(const nana::rectangle& from_r, graph_reference dst, const nana::rectangle& to_r) override
{
graph.stretch(from_r, dst, to_r);
}
};
bground::bground()
: method_(nullptr),
vertical_(false),
stretch_all_(true),
left_(0), top_(0), right_(0), bottom_(0)
{
reset_states();
}
bground::bground(const bground& rhs)
: method_(rhs.method_ ? rhs.method_->clone() : nullptr),
vertical_(rhs.vertical_),
valid_area_(rhs.valid_area_),
states_(rhs.states_),
join_(rhs.join_),
stretch_all_(rhs.stretch_all_),
left_(rhs.left_), top_(rhs.top_), right_(rhs.right_), bottom_(rhs.bottom_)
{
}
bground::~bground()
{
delete method_;
}
bground& bground::operator=(const bground& rhs)
{
if (this != &rhs)
{
delete method_;
method_ = (rhs.method_ ? rhs.method_->clone() : nullptr);
vertical_ = rhs.vertical_;
valid_area_ = rhs.valid_area_;
states_ = rhs.states_;
join_ = rhs.join_;
stretch_all_ = rhs.stretch_all_;
left_ = rhs.left_;
top_ = rhs.top_;
right_ = rhs.right_;
bottom_ = rhs.bottom_;
}
return *this;
}
//Set a picture for the background
bground& bground::image(const paint::image& img, bool vertical, const nana::rectangle& valid_area)
{
delete method_;
method_ = new draw_image(img);
vertical_ = vertical;
if (valid_area.width && valid_area.height)
valid_area_ = valid_area;
else
valid_area_ = nana::rectangle(img.size());
return *this;
}
bground& bground::image(const paint::graphics& graph, bool vertical, const nana::rectangle& valid_area)
{
delete method_;
method_ = new draw_graph(graph);
vertical_ = vertical;
if (valid_area.width && valid_area.height)
valid_area_ = valid_area;
else
valid_area_ = nana::rectangle(graph.size());
return *this;
}
//Set the state sequence of the background picture.
void bground::states(const std::vector<element_state> & s)
{
states_ = s;
}
void bground::states(std::vector<element_state> && s)
{
states_ = std::move(s);
}
void bground::reset_states()
{
states_.clear();
states_.push_back(element_state::normal);
states_.push_back(element_state::hovered);
states_.push_back(element_state::focus_normal);
states_.push_back(element_state::focus_hovered);
states_.push_back(element_state::pressed);
states_.push_back(element_state::disabled);
join_.clear();
}
void bground::join(element_state target, element_state joiner)
{
join_[joiner] = target;
}
void bground::stretch_parts(unsigned left, unsigned top, unsigned right, unsigned bottom)
{
left_ = left;
top_ = top;
right_ = right;
bottom_ = bottom;
stretch_all_ = !(left || right || top || bottom);
}
//Implement the methods of bground_interface.
bool bground::draw(graph_reference dst, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle& to_r, element_state state)
{
if (nullptr == method_)
return false;
auto mi = join_.find(state);
if (mi != join_.end())
state = mi->second;
std::size_t pos = 0;
for (; pos < states_.size(); ++pos)
{
if (states_[pos] == state)
break;
}
if (pos == states_.size())
return false;
nana::rectangle from_r = valid_area_;
if (vertical_)
{
from_r.height /= static_cast<unsigned>(states_.size());
from_r.y += static_cast<int>(from_r.height * pos);
}
else
{
from_r.width /= static_cast<unsigned>(states_.size());
from_r.x += static_cast<int>(from_r.width * pos);
}
if (stretch_all_)
{
if (from_r.width == to_r.width && from_r.height == to_r.height)
method_->paste(from_r, dst, to_r);
else
method_->stretch(from_r, dst, to_r);
return true;
}
auto perf_from_r = from_r;
auto perf_to_r = to_r;
if (left_ + right_ < to_r.width)
{
nana::rectangle src_r = from_r;
src_r.y += static_cast<int>(top_);
src_r.height -= top_ + bottom_;
nana::rectangle dst_r = to_r;
dst_r.y += static_cast<int>(top_);
dst_r.height -= top_ + bottom_;
if (left_)
{
src_r.width = left_;
dst_r.width = left_;
method_->stretch(src_r, dst, dst_r);
perf_from_r.x += static_cast<int>(left_);
perf_from_r.width -= left_;
perf_to_r.x += static_cast<int>(left_);
perf_to_r.width -= left_;
}
if (right_)
{
src_r.x += (static_cast<int>(from_r.width) - static_cast<int>(right_));
src_r.width = right_;
dst_r.x += (static_cast<int>(to_r.width) - static_cast<int>(right_));
dst_r.width = right_;
method_->stretch(src_r, dst, dst_r);
perf_from_r.width -= right_;
perf_to_r.width -= right_;
}
}
if (top_ + bottom_ < to_r.height)
{
nana::rectangle src_r = from_r;
src_r.x += static_cast<int>(left_);
src_r.width -= left_ + right_;
nana::rectangle dst_r = to_r;
dst_r.x += static_cast<int>(left_);
dst_r.width -= left_ + right_;
if (top_)
{
src_r.height = top_;
dst_r.height = top_;
method_->stretch(src_r, dst, dst_r);
perf_from_r.y += static_cast<int>(top_);
perf_to_r.y += static_cast<int>(top_);
}
if (bottom_)
{
src_r.y += static_cast<int>(from_r.height - bottom_);
src_r.height = bottom_;
dst_r.y += static_cast<int>(to_r.height - bottom_);
dst_r.height = bottom_;
method_->stretch(src_r, dst, dst_r);
}
perf_from_r.height -= (top_ + bottom_);
perf_to_r.height -= (top_ + bottom_);
}
if (left_)
{
nana::rectangle src_r = from_r;
src_r.width = left_;
if (top_)
{
src_r.height = top_;
method_->paste(src_r, dst, to_r);
}
if (bottom_)
{
src_r.y += static_cast<int>(from_r.height) - static_cast<int>(bottom_);
src_r.height = bottom_;
method_->paste(src_r, dst, nana::point(to_r.x, to_r.y + static_cast<int>(to_r.height - bottom_)));
}
}
if (right_)
{
const int to_x = to_r.x + int(to_r.width - right_);
nana::rectangle src_r = from_r;
src_r.x += static_cast<int>(src_r.width) - static_cast<int>(right_);
src_r.width = right_;
if (top_)
{
src_r.height = top_;
method_->paste(src_r, dst, nana::point(to_x, to_r.y));
}
if (bottom_)
{
src_r.y += (static_cast<int>(from_r.height) - static_cast<int>(bottom_));
src_r.height = bottom_;
method_->paste(src_r, dst, nana::point(to_x, to_r.y + int(to_r.height - bottom_)));
}
}
method_->stretch(perf_from_r, dst, perf_to_r);
return true;
}
//end class bground
}//end namespace element
}//end namespace nana

1011
source/gui/filebox.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,264 @@
/*
* Utility 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/layout_utility.hpp
*
*
*/
#include <nana/gui/layout_utility.hpp>
namespace nana
{
//overlap test if overlaped between r1 and r2
bool overlap(const rectangle& r1, const rectangle& r2)
{
if(r1.y + int(r1.height) <= r2.y) return false;
if(r1.y >= int(r2.y + r2.height)) return false;
if(int(r1.x + r1.width) <= r2.x) return false;
if(r1.x >= int(r2.x + r2.width)) return false;
return true;
}
//overlap, compute the overlap area between r1 and r2. the rect is for root
bool overlap(const rectangle& r1, const rectangle& r2, rectangle& r)
{
if(overlap(r1, r2))
{
auto l1 = static_cast<long long>(r1.x) + r1.width;
auto l2 = static_cast<long long>(r2.x) + r2.width;
auto b1 = static_cast<long long>(r1.y) + r1.height;
auto b2 = static_cast<long long>(r2.y) + r2.height;
r.x = r1.x < r2.x ? r2.x : r1.x;
r.y = r1.y < r2.y ? r2.y : r1.y;
r.width = static_cast<unsigned>(l1 < l2 ? l1 - r.x: l2 - r.x);
r.height = static_cast<unsigned>(b1 < b2 ? b1 - r.y: b2 - r.y);
return true;
}
return false;
}
bool overlap(const rectangle& ir, const size& valid_input_area, const rectangle & dr, const size& valid_dst_area, rectangle& op_ir, rectangle& op_dr)
{
if(overlap(ir, valid_input_area, op_ir) == false)
return false;
rectangle good_dr;
if(overlap(dr, valid_dst_area, good_dr) == false)
return false;
zoom(ir, op_ir, dr, op_dr);
if(false == covered(op_dr, good_dr))
{
op_dr = good_dr;
zoom(dr, good_dr, ir, op_ir);
}
return true;
}
bool intersection(const rectangle & r, point pos_beg, point pos_end, point& good_pos_beg, point& good_pos_end)
{
const int right = r.right();
const int bottom = r.bottom();
if(pos_beg.x > pos_end.x)
std::swap(pos_beg, pos_end);
bool good_beg = (0 <= pos_beg.x && pos_beg.x < right && 0 <= pos_beg.y && pos_beg.y < bottom);
bool good_end = (0 <= pos_end.x && pos_end.x < right && 0 <= pos_end.y && pos_end.y < bottom);
if(good_beg && good_end)
{
good_pos_beg = pos_beg;
good_pos_end = pos_end;
return true;
}
else if(pos_beg.x == pos_end.x)
{
if(r.x <= pos_beg.x && pos_beg.x < right)
{
if(pos_beg.y < r.y)
{
if(pos_end.y < r.y)
return false;
good_pos_beg.y = r.y;
good_pos_end.y = (pos_end.y < bottom ? pos_end.y : bottom - 1);
}
else if(pos_beg.y >= bottom)
{
if(pos_end.y >= bottom)
return false;
good_pos_beg.y = bottom - 1;
good_pos_end.y = (pos_end.y < r.y ? r.y : pos_end.y);
}
good_pos_beg.x = good_pos_end.x = r.x;
return true;
}
return false;
}
else if(pos_beg.y == pos_end.y)
{
if(r.y <= pos_beg.y && pos_beg.y < bottom)
{
if(pos_beg.x < r.x)
{
if(pos_end.x < r.x)
return false;
good_pos_beg.x = r.x;
good_pos_end.x = (pos_end.x < right ? pos_end.x : right - 1);
}
else if(pos_beg.x >= right)
{
if(pos_end.x >= right)
return false;
good_pos_beg.x = right - 1;
good_pos_end.x = (pos_end.x < r.x ? r.x : pos_end.x);
}
good_pos_beg.y = good_pos_end.y = r.y;
return true;
}
return false;
}
double m = (pos_end.y - pos_beg.y ) / double(pos_end.x - pos_beg.x);
bool is_nw_to_se = (m >= 0.0);
//The formulas for the line.
//y = m * (x - pos_beg.x) + pos_beg.y
//x = (y - pos_beg.y) / m + pos_beg.x
if(!good_beg)
{
good_pos_beg.y = static_cast<int>(m * (r.x - pos_beg.x)) + pos_beg.y;
if(r.y <= good_pos_beg.y && good_pos_beg.y < bottom)
{
good_pos_beg.x = r.x;
}
else
{
bool cond;
int y;
if(is_nw_to_se)
{
y = r.y;
cond = good_pos_beg.y < y;
}
else
{
y = bottom - 1;
cond = good_pos_beg.y > y;
}
if(cond)
{
good_pos_beg.x = static_cast<int>((y - pos_beg.y) / m) + pos_beg.x;
if(r.x <= good_pos_beg.x && good_pos_beg.x < right)
good_pos_beg.y = y;
else
return false;
}
else
return false;
}
if(good_pos_beg.x < pos_beg.x)
return false;
}
else
good_pos_beg = pos_beg;
if(!good_end)
{
good_pos_end.y = static_cast<int>(m * (right - 1 - pos_beg.x)) + pos_beg.y;
if(r.y <= good_pos_end.y && good_pos_end.y < bottom)
{
good_pos_end.x = right - 1;
}
else
{
bool cond;
int y;
if(is_nw_to_se)
{
y = bottom - 1;
cond = good_pos_end.y > y;
}
else
{
y = r.y;
cond = good_pos_end.y < y;
}
if(cond)
{
good_pos_end.x = static_cast<int>((y - pos_beg.y) / m) + pos_beg.x;
if(r.x <= good_pos_end.x && good_pos_end.x < right)
good_pos_end.y = y;
else
return false;
}
else
return false;
}
if(good_pos_end.x > pos_end.x)
return false;
}
else
good_pos_end = pos_end;
return true;
}
void fit_zoom(const size& input_s, const size& ref_s, size& result_s)
{
double rate_input = double(input_s.width) / double(input_s.height);
double rate_ref = double(ref_s.width) / double(ref_s.height);
if(rate_input < rate_ref)
{
result_s.height = ref_s.height;
result_s.width = static_cast<unsigned>(ref_s.height * rate_input);
}
else if(rate_input > rate_ref)
{
result_s.width = ref_s.width;
result_s.height = static_cast<unsigned>(ref_s.width / rate_input);
}
else
result_s = ref_s;
}
void zoom(const rectangle& ref, const rectangle& scaled, const rectangle& ref_dst, rectangle& r)
{
double rate_x = (scaled.x - ref.x) / double(ref.width);
double rate_y = (scaled.y - ref.y) / double(ref.height);
r.x = static_cast<int>(rate_x * ref_dst.width) + ref_dst.x;
r.y = static_cast<int>(rate_y * ref_dst.height) + ref_dst.y;
r.width = static_cast<unsigned>(scaled.width / double(ref.width) * ref_dst.width);
r.height = static_cast<unsigned>(scaled.height / double(ref.height) * ref_dst.height);
}
//covered test if r2 covers r1.
bool covered(const rectangle& r1, //Rectangle 1 is must under rectangle 2
const rectangle& r2) //Rectangle 2
{
if(r1.x < r2.x || r1.right() > r2.right()) return false;
if(r1.y < r2.y || r1.bottom() > r2.bottom()) return false;
return true;
}
}

464
source/gui/msgbox.cpp Normal file
View File

@@ -0,0 +1,464 @@
/*
* A Message Box Class
* 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/msgbox.hpp
*/
#include <nana/gui/msgbox.hpp>
#include <nana/gui/programming_interface.hpp>
#if defined(NANA_WINDOWS)
#include <windows.h>
#elif defined(NANA_X11)
#include <nana/gui/wvl.hpp>
#include <nana/gui/widgets/label.hpp>
#include <nana/gui/widgets/button.hpp>
#include <nana/gui/widgets/picture.hpp>
#include <nana/paint/pixel_buffer.hpp>
#include <nana/gui/place.hpp>
#endif
namespace nana
{
#if defined(NANA_X11)
class msgbox_window
: public form
{
public:
msgbox_window(window wd, const nana::string& title, msgbox::button_t btn, msgbox::icon_t ico)
: form(wd, nana::rectangle(1, 1, 1, 1), appear::decorate<>()),
owner_(wd), pick_(msgbox::pick_yes)
{
this->caption(title);
drawing dw(*this);
dw.draw([this](::nana::paint::graphics& graph)
{
graph.rectangle(nana::rectangle{0, 0, graph.width(), graph.height() - 50}, 0xFFFFFF, true);
if(ico_.empty() == false)
ico_.stretch(ico_.size(), graph, ::nana::rectangle{12, 25, 32, 32});
});
unsigned width_pixel = 45;
unsigned height_pixel = 110;
place_.bind(*this);
yes_.create(*this);
yes_.events().click([this](const arg_mouse& arg)
{
_m_click(arg);
});
yes_.caption(STR("OK"));
width_pixel += 77;
if(msgbox::yes_no == btn || msgbox::yes_no_cancel == btn)
{
yes_.caption(STR("Yes"));
no_.create(*this);
no_.caption(STR("No"));
no_.events().click([this](const arg_mouse& arg)
{
_m_click(arg);
});
width_pixel += 77;
if(msgbox::yes_no_cancel == btn)
{
cancel_.create(*this);
cancel_.caption(STR("Cancel"));
cancel_.events().click([this](const arg_mouse& arg)
{
_m_click(arg);
});
width_pixel += 77;
pick_ = msgbox::pick_cancel;
}
else
pick_ = msgbox::pick_no;
}
std::stringstream ss;
ss<<"vert<><weight=50 margin=[10,0,15,0]<><buttons arrange=70 gap=7 weight="<<(width_pixel - 45)<<">>";
place_.div(ss.str().data());
auto & field = place_.field("buttons");
field<<yes_;
if(!no_.empty())
{
field<<no_;
if(!cancel_.empty())
field<<cancel_;
}
this->size(nana::size{width_pixel, height_pixel});
_m_icon(ico);
}
void prompt(const nana::string& text)
{
if(text.size())
{
const unsigned ico_pixels = (ico_.empty() ? 0 : 44);
const unsigned text_pixels = 500 - ico_pixels;
text_.create(*this, nana::rectangle(12 + ico_pixels, 25, 1, 1));
text_.background(0xFFFFFF);
text_.caption(text);
nana::size ts = text_.measure(text_pixels);
if(ts.height <= 32)
text_.move(12 + ico_pixels, 25 + (32 - ts.height) / 2);
text_.size(ts);
nana::size sz = this->size();
if(sz.width < 48 + ts.width + ico_pixels)
sz.width = 48 + ts.width + ico_pixels;
nana::rectangle r = API::make_center(owner_, sz.width, sz.height + ts.height);
this->move(r);
}
API::modal_window(*this);
}
msgbox::pick_t pick() const
{
return pick_;
}
private:
void _m_icon(msgbox::icon_t ico)
{
if(ico == msgbox::icon_none) return;
const unsigned pic_information[] = {
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xE9E9E9, 0xC7C6C6, 0xA9A8A8, 0x8F8E8E, 0x7C7B7B, 0x6F6E6E, 0x6F6E6E, 0x7C7B7B, 0x8F8E8E, 0xA9A8A8, 0xC7C6C6, 0xE9E9E9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD9D9D9, 0xAAA9A9, 0x807F7F, 0xA2A2A2, 0xC0C0C0, 0xDADADA, 0xEDEDED, 0xFBFBFB, 0xFBFBFB, 0xEDEDED, 0xDADADA, 0xC0C0C0, 0xA2A2A2, 0x807F7F, 0xAAA9A9, 0xD9D9D9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0xB0B0B0, 0x8F8F8F, 0xBFBFBF, 0xEBEBEB, 0xDADADB, 0xBDBFC4, 0xA9AFBE, 0x99A3BF, 0x8D9ABF, 0x8895B8, 0x8691AC, 0x8F95A6, 0xA8AAB0, 0xD5D6D7, 0xEBEBEB, 0xBFBFBF, 0x8F8F8F, 0xB0B0B0, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x959595, 0xB9B8B8, 0xEDEDED, 0xC7C8CA, 0xB8BFD2, 0x9CB1E6, 0x7C99E2, 0x7191E1, 0x6C8DE0, 0x6789DE, 0x6487DC, 0x6285D7, 0x6381D0, 0x617EC8, 0x687EB7, 0x7F889F, 0xB9BABE, 0xEDEDED, 0xB9B8B8, 0x959595, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD1D1D1, 0x919090, 0xD3D3D3, 0xDDDEDE, 0xBABFCC, 0x9AB2EE, 0x7494E5, 0x698DE7, 0x668CE8, 0x628AE9, 0x5D85E7, 0x527CE4, 0x4D79E1, 0x527BDF, 0x577DDD, 0x567BD7, 0x577ACF, 0x5878C6, 0x5E77B5, 0x80889B, 0xDADADB, 0xD3D3D3, 0x919090, 0xD1D1D1, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x919090, 0xE1E1E1, 0xCACBCB, 0xAFBBD8, 0x7C99E6, 0x688BE5, 0x638AEA, 0x6187E9, 0x5C85E9, 0x5B83E7, 0x5781E7, 0x91ADF2, 0xA5BDF5, 0x688CE6, 0x4A74DA, 0x4F78DA, 0x4D76D6, 0x4D73D1, 0x4F72C7, 0x5472B9, 0x66759A, 0xC1C2C4, 0xE1E1E1, 0x919090, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0x959595, 0xD3D3D3, 0xCACBCB, 0xA2B2D9, 0x6E8FE0, 0x6287E3, 0x5D85E8, 0x5B84E7, 0x5A83E8, 0x5982E6, 0x527CE3, 0xB8CBF9, 0xFFFFFF, 0xFFFFFF, 0xF4FAFF, 0x6587DF, 0x466FD6, 0x4972D5, 0x4770D1, 0x456DCE, 0x476CC7, 0x4E6DB8, 0x5E709A, 0xC1C2C4, 0xD3D3D3, 0x959595, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xB0B0B0, 0xB9B8B8, 0xDDDEDE, 0x9FABCB, 0x6D8DDF, 0x5E84E1, 0x5982E5, 0x5981E3, 0x5780E3, 0x5780E3, 0x527CE1, 0x5C83E3, 0xFCFEFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xA7BAE8, 0x3965D0, 0x4770D2, 0x436CD0, 0x4269CC, 0x4068C9, 0x4267C2, 0x4968B4, 0x5E6C91, 0xD9D9DA, 0xB9B8B8, 0xB0B0B0, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xD9D9D9, 0x8F8F8F, 0xEDEDED, 0x9CA2AE, 0x7493E0, 0x5A80DD, 0x557EE0, 0x547DE1, 0x537DE1, 0x547CE0, 0x537CE0, 0x507ADF, 0x4F78DC, 0xDBE4FB, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0x7B92CF, 0x3C65D0, 0x456CD0, 0x4169CE, 0x3F67CB, 0x3D64C8, 0x3D63C6, 0x3E62BE, 0x4663AC, 0x757D90, 0xEDEDED, 0x8F8F8F, 0xD9D9D9, 0xFFFFFF,
0xFFFFFF, 0xAAA9A9, 0xBFBFBF, 0xBFC0C1, 0x7D95D2, 0x5B7FD8, 0x527ADC, 0x5279DD, 0x5179DC, 0x5079DC, 0x5079DC, 0x5078DC, 0x4F78DB, 0x4771D9, 0x6485DA, 0xCDD5EA, 0xE0E4ED, 0x92A2CB, 0x3C61C1, 0x436AD2, 0x4168CE, 0x3F65CB, 0x3C63C9, 0x3962C7, 0x3960C4, 0x385DC0, 0x3C5EB7, 0x475F9F, 0xB4B6B9, 0xBFBFBF, 0xAAA9A9, 0xFFFFFF,
0xE9E9E9, 0x807F7F, 0xEBEBEB, 0x8C93A5, 0x6284D5, 0x5177D6, 0x4E75D9, 0x4D76DA, 0x4D75D9, 0x4D75D9, 0x4D75D9, 0x4B74D8, 0x4A73D8, 0x4B73D8, 0x3F68D3, 0x3860C9, 0x395EBF, 0x325AC5, 0x4068D2, 0x436AD0, 0x4067CE, 0x3E64CB, 0x3C62C8, 0x395FC6, 0x375EC4, 0x365BC0, 0x365BBB, 0x3E5DAC, 0x667089, 0xEBEBEB, 0x807F7F, 0xE9E9E9,
0xC7C6C6, 0xA2A2A2, 0xD6D6D7, 0x7387BC, 0x5276CF, 0x4A73D5, 0x4972D6, 0x4972D7, 0x4972D7, 0x4972D6, 0x4871D6, 0x4870D5, 0x486FD5, 0x456BD3, 0x4B6FD5, 0x4D72D6, 0x4C71D6, 0x4E72D5, 0x4267CD, 0x3057BF, 0x2E54BC, 0x2950B8, 0x274EB5, 0x264BB4, 0x264DB3, 0x274DB5, 0x2A4FB4, 0x3254AD, 0x435995, 0xD2D2D3, 0xA3A3A3, 0xC7C6C6,
0xA9A8A8, 0xC0C0C0, 0xA6A8AD, 0x5C7AC3, 0x4B72CD, 0x476FD2, 0x466FD2, 0x466FD3, 0x466DD3, 0x466DD3, 0x466DD2, 0x456CD2, 0x436BD3, 0x436BD2, 0xA3B3DD, 0xF5F5F0, 0xEBEAE7, 0xC3CCE6, 0x2C4383, 0xB32A2, 0x1A41A9, 0x1A40A8, 0x1A40A9, 0x1B41A9, 0x1A41A8, 0x1B40A8, 0x1C41A9, 0x2245A5, 0x314D99, 0x9598A0, 0xC1C1C1, 0xA9A8A8,
0x8F8E8E, 0xDADADA, 0x878D9A, 0x5172C3, 0x456CCD, 0x436BCF, 0x426BD0, 0x416BD0, 0x426AD0, 0x426AD0, 0x426AD0, 0x426AD1, 0x3A61CB, 0x3056BE, 0xCFCECE, 0xD0CDCA, 0xC1C1C1, 0xE5E4E3, 0x334984, 0xB31A3, 0x1C42AD, 0x1C41AB, 0x1C41AB, 0x1B41AC, 0x1B41AB, 0x1C41AB, 0x1C41AB, 0x1F43A8, 0x2B499C, 0x6A7184, 0xDADADA, 0x8F8E8E,
0x7C7B7B, 0xEDEDED, 0x737C95, 0x4C6FC3, 0x4169CB, 0x3F68CD, 0x3F67CD, 0x3F67CD, 0x3F67CD, 0x4068CF, 0x3E64CD, 0x2F56BE, 0x1C42AD, 0x2046AF, 0xCACCCC, 0xC5C4C0, 0xB9B9B9, 0xE3E2E1, 0x324784, 0xB31A4, 0x1C42AD, 0x1B40AC, 0x1B40AC, 0x1B40AC, 0x1B40AC, 0x1B40AB, 0x1B40AB, 0x1E41A9, 0x29479F, 0x4C5979, 0xEDEDED, 0x7C7B7B,
0x6F6E6E, 0xFBFBFB, 0x697597, 0x476AC1, 0x3E65C7, 0x3C64C9, 0x3C63CA, 0x3D63CA, 0x3D64CB, 0x355CC5, 0x2349B3, 0x1B41AB, 0x1A40AB, 0x2449B1, 0xCACAC9, 0xBCB9B7, 0xB1B1B1, 0xE1E0DE, 0x324784, 0xB30A5, 0x1B41AE, 0x1B3FAD, 0x1B3FAD, 0x1B3FAD, 0x1B3FAD, 0x1B3FAC, 0x1B3FAC, 0x1D41AA, 0x2645A1, 0x414F7B, 0xFBFBFB, 0x6F6E6E,
0x6F6E6E, 0xFBFBFB, 0x667395, 0x4467BF, 0x3A62C5, 0x3960C7, 0x3961C7, 0x3A61C8, 0x2E56BE, 0x1E45AE, 0x1C42AC, 0x1E43AE, 0x1B41AD, 0x2448B3, 0xC8C8C9, 0xB5B3AF, 0xADADAC, 0xE0DFDE, 0x324784, 0xB31A6, 0x1B40AF, 0x1B3FAE, 0x1B3FAE, 0x1B3FAE, 0x1B3FAE, 0x1B3FAE, 0x1B3FAD, 0x1D40AB, 0x2646A2, 0x404F7B, 0xFBFBFB, 0x6F6E6E,
0x7C7B7B, 0xEDEDED, 0x6B758E, 0x4264B9, 0x385FC2, 0x365EC5, 0x375FC6, 0x2C52BC, 0x1E45AE, 0x1E43AE, 0x1E43AE, 0x1D43AE, 0x1A3FAE, 0x2549B5, 0xC6C7C9, 0xAFAEA9, 0xABABAB, 0xE1E0DE, 0x324784, 0xC30A7, 0x1C40B1, 0x1C3FB1, 0x1C3FB0, 0x1C3FB0, 0x1C3FB0, 0x1B3FAF, 0x1B3FAE, 0x1E41AC, 0x2946A1, 0x4A5678, 0xEDEDED, 0x7C7B7B,
0x8F8E8E, 0xDADADA, 0x7D838F, 0x3E60B3, 0x375DBE, 0x365BC1, 0x2B52BA, 0x1E45AE, 0x1E45AF, 0x1E43AF, 0x1E43AF, 0x1D42AF, 0x1A3FAE, 0x2549B5, 0xC6C7C7, 0xAFAEA9, 0xAEAEAE, 0xE1E1DE, 0x324785, 0xC30A9, 0x1C40B5, 0x1C3FB4, 0x1D3FB4, 0x1D3FB4, 0x1C3FB3, 0x1C3FB3, 0x1D3FB0, 0x2041AD, 0x2C48A0, 0x656C80, 0xDADADA, 0x8F8E8E,
0xA9A8A8, 0xC0C0C0, 0x9EA0A6, 0x425EAA, 0x365BBA, 0x2D53B9, 0x1F46AF, 0x1F46AF, 0x1E43AF, 0x1E43AF, 0x1E42AF, 0x1D42B0, 0x1A3FAF, 0x2449B6, 0xC6C7C9, 0xB4B3AF, 0xB5B5B6, 0xE4E4E1, 0x334786, 0xD30AD, 0x1D41B8, 0x1E3FB7, 0x1D40B7, 0x1D3FB7, 0x1D3FB7, 0x1D3FB6, 0x1E3FB3, 0x2243AE, 0x294398, 0x94979F, 0xC1C1C1, 0xA9A8A8,
0xC7C6C6, 0xA2A2A2, 0xD3D3D4, 0x4D629B, 0x3558B3, 0x224AB0, 0x1F46B0, 0x1F45B0, 0x1E45B0, 0x1E43B0, 0x1D42B0, 0x1D42B1, 0x1A3FB1, 0x2447B7, 0xC8C8C9, 0xBDBCB7, 0xBFBFC0, 0xE8E6E5, 0x334786, 0xD30AF, 0x1E41BC, 0x1F40BA, 0x1E40BA, 0x1E40BA, 0x1E40B9, 0x1E40B8, 0x1F40B6, 0x2845AD, 0x32468B, 0xD2D2D3, 0xA3A3A3, 0xC7C6C6,
0xE9E9E9, 0x807F7F, 0xEBEBEB, 0x6D7489, 0x3251A6, 0x2448AC, 0x2046AF, 0x1F45B0, 0x1E43B0, 0x1E42B1, 0x1E42B1, 0x1D42B1, 0x1B3FB3, 0x2447B9, 0xD0D0CF, 0xC7C6C2, 0xCACBCB, 0xEBEBE9, 0x344887, 0xE30B1, 0x1F41BF, 0x1F40BE, 0x1F40BE, 0x1F40BD, 0x1F40BD, 0x1F40BB, 0x2443B6, 0x2E49A8, 0x5B6380, 0xEBEBEB, 0x818080, 0xE9E9E9,
0xFFFFFF, 0xAAA9A9, 0xBFBFBF, 0xB5B6B8, 0x375092, 0x294BA7, 0x2146AE, 0x2045B0, 0x1E43B1, 0x1E42B1, 0x1E42B1, 0x1D41B3, 0x1B3FB4, 0x2347B9, 0xD5D7D8, 0xD6D5D0, 0xDFDEDF, 0xF2F1EF, 0x344988, 0xE2FB4, 0x2142C1, 0x2041C1, 0x2041C0, 0x2041C0, 0x2140BF, 0x2241BD, 0x2A47B4, 0x304493, 0xB4B5B9, 0xC0C0C0, 0xAAA9A9, 0xFFFFFF,
0xFFFFFF, 0xD9D9D9, 0x8F8F8F, 0xEDEDED, 0x6E7484, 0x2F4B9E, 0x2648AB, 0x2046B0, 0x1E42B1, 0x1E42B3, 0x1E42B4, 0x1E41B5, 0x1B3FB6, 0x2346B9, 0xDFDFE3, 0xEBE9E7, 0xF3F3F4, 0xF3F3F2, 0x364988, 0xE2FB5, 0x2342C4, 0x2141C4, 0x2141C4, 0x2141C2, 0x2342C0, 0x2745BA, 0x344CAA, 0x697088, 0xEDEDED, 0x8F8F8F, 0xD9D9D9, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xB0B0B0, 0xB9B8B8, 0xD8D8D9, 0x4C597E, 0x2E4BA1, 0x2548AD, 0x1F43B2, 0x1F42B3, 0x1E42B5, 0x1E41B7, 0x1C3FB8, 0x2143B9, 0xEBEBED, 0xFDFDFA, 0xFCFCFD, 0xF3F3F2, 0x374B8A, 0xE30B7, 0x2443C6, 0x2342C6, 0x2442C5, 0x2542C3, 0x2845BE, 0x334BB0, 0x475484, 0xDBDBDB, 0xBAB9B9, 0xB0B0B0, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0x959595, 0xD3D3D3, 0xBEBEC0, 0x445584, 0x2D4AA2, 0x2546AE, 0x2043B3, 0x2042B5, 0x1F42B8, 0x1D3FBA, 0x1F40B9, 0xB9C0D3, 0xF5F5F6, 0xF5F5F5, 0xC7CCDD, 0x304386, 0x1231B9, 0x2443C8, 0x2442C6, 0x2543C5, 0x2A46BF, 0x344CB3, 0x414F89, 0xC1C2C5, 0xD4D4D4, 0x959595, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x919090, 0xE1E1E1, 0xBFBFC1, 0x4B587F, 0x2E49A0, 0x2848AB, 0x2344B3, 0x2143B7, 0x2142BC, 0x1F40BE, 0x354689, 0x475282, 0x455184, 0x424E83, 0x2942B3, 0x2240C7, 0x2644C7, 0x2945C3, 0x2E48BC, 0x354CB0, 0x4A5587, 0xC3C3C6, 0xE1E1E1, 0x919090, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD1D1D1, 0x919090, 0xD3D3D3, 0xD8D8D9, 0x6C7183, 0x324993, 0x2B47A7, 0x2947B2, 0x2645B8, 0x2444BD, 0x1B3BBC, 0x1635B5, 0x1735B5, 0x1837B8, 0x2442C3, 0x2B48C3, 0x2D48BD, 0x324AB4, 0x33479C, 0x6D728B, 0xDBDCDC, 0xD3D3D3, 0x919090, 0xD1D1D1, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x959595, 0xB9B8B8, 0xEDEDED, 0xB1B2B5, 0x5E6680, 0x374B92, 0x2E46A3, 0x2D47AE, 0x2C47B4, 0x2C47B9, 0x2D47BB, 0x2E48B8, 0x3049B5, 0x2E46AB, 0x364996, 0x5F6685, 0xB6B8BC, 0xEDEDED, 0xB9B8B8, 0x959595, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0xB0B0B0, 0x8F8F8F, 0xBFBFBF, 0xEBEBEB, 0xD1D1D2, 0x93969F, 0x666C82, 0x4E587F, 0x434F83, 0x434F83, 0x4E5880, 0x686E86, 0x9698A1, 0xD3D4D5, 0xEBEBEB, 0xBFBFBF, 0x8F8F8F, 0xB0B0B0, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD9D9D9, 0xAAA9A9, 0x807F7F, 0xA2A2A2, 0xC0C0C0, 0xDADADA, 0xEDEDED, 0xFBFBFB, 0xFBFBFB, 0xEDEDED, 0xDADADA, 0xC0C0C0, 0xA2A2A2, 0x807F7F, 0xAAA9A9, 0xD9D9D9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xE9E9E9, 0xC7C6C6, 0xA9A8A8, 0x8F8E8E, 0x7C7B7B, 0x6F6E6E, 0x6F6E6E, 0x7C7B7B, 0x8F8E8E, 0xA9A8A8, 0xC7C6C6, 0xE9E9E9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
};
const unsigned pic_warning[] = {
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFDFDFD, 0xD6D7D7, 0xD8D7D8, 0xECECEC, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xE6E6E5, 0xB5B5B9, 0xBBBAC3, 0xC8C8C9, 0xFEFEFE, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xF3F3F3, 0xAFB0B3, 0xBFBFB7, 0xC2C2AC, 0xB2B2B8, 0xDADADA, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xC9C9C8, 0xADAEBF, 0xB8B26D, 0xC7B81E, 0xBBBBB8, 0xB3B4BB, 0xF7F7F8, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xE9E9E8, 0xAEAEB5, 0xAEAEAC, 0xD6C611, 0xE4DB06, 0xBCAC4D, 0xB5B8CB, 0xCBCBCB, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFDFDFD, 0xC0C0C0, 0xB4B4C2, 0xB6AA53, 0xFFFF00, 0xFFFF00, 0xD1C00E, 0xBDB8A0, 0xB3B4BE, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xDBDBDB, 0xB2B2BD, 0xB6B6A6, 0xDDCC07, 0xFFFF00, 0xFFFF00, 0xFFFD00, 0xBBA63E, 0xC3C4D6, 0xC0C0C2, 0xFEFEFE, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xF8F8F7, 0xB2B2B5, 0xC3C3D4, 0xBCAC4A, 0xFFFF00, 0xFFF700, 0xFFF700, 0xFFFD00, 0xD2BC0B, 0xCAC39C, 0xB8B9C7, 0xE4E3E4, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xCFCFCF, 0xB9B9C7, 0xC1BF97, 0xDBC907, 0x989533, 0x747144, 0x757442, 0x7F7D45, 0xDCCE0D, 0xC4AC31, 0xC6C8D3, 0xBEBEC1, 0xFCFCFC, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xEEEEEE, 0xB6B6BB, 0xCDCECE, 0xC6B63D, 0xFAF400, 0x6D6D65, 0x65657E, 0x646578, 0x5E5E74, 0xC4B71F, 0xE4CA0D, 0xC5B679, 0xC5C8D5, 0xD4D4D5, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFEFEFE, 0xC6C6C6, 0xD5D6E2, 0xC7C48C, 0xE0D306, 0xF9F303, 0x76755B, 0x676771, 0x65656A, 0x5D5E62, 0xC6B720, 0xFFEE08, 0xC0A32B, 0xE7E6E8, 0xBBBCC2, 0xF3F3F4, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xE4E4E4, 0xBDBEC7, 0xC8C9C5, 0xD7C21D, 0xFFFD01, 0xFCF405, 0x747151, 0x5A5B66, 0x56575B, 0x4D4E4F, 0xC9B71D, 0xFFEA15, 0xE6C60A, 0xC2AB64, 0xE8EAF5, 0xC9C9C9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFCFCFC, 0xB7B7B9, 0xE8E9F2, 0xC3B766, 0xF3E406, 0xFFF512, 0xF8EC0A, 0x706E45, 0x4A4B56, 0x45464B, 0x404041, 0xC9B418, 0xFFE313, 0xF9D708, 0xC3A21B, 0xDAD2BE, 0xC5C8CE, 0xECECEC, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD5D5D5, 0xC2C3CE, 0xC9C9B1, 0xDDC617, 0xFFF00F, 0xFFF019, 0xF8EB0A, 0x6C673A, 0x373844, 0x37383C, 0x3E3D3A, 0xCBB415, 0xFFDD0D, 0xF7D30B, 0xE4B903, 0xBFA449, 0xEDEEF6, 0xC3C3C5, 0xFDFDFD, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xF3F3F3, 0xB6B7BB, 0xE8E9EF, 0xBFAF4F, 0xFFF00D, 0xFFEA1A, 0xFFEC1B, 0xF8E80D, 0x655E2D, 0x292A38, 0x34353B, 0x46453D, 0xD2B711, 0xFFD906, 0xF5CC05, 0xF7CB00, 0xCEA306, 0xC8B68C, 0xCBCDD8, 0xDFDFDF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xC0C0C2, 0xD4D5E4, 0xC7C39D, 0xDFC414, 0xFFEB18, 0xFDE41B, 0xFFE418, 0xF5D711, 0x534A15, 0x80916, 0x1E1F24, 0x3D3B31, 0xCFAD05, 0xFBCB00, 0xF0C300, 0xF0C100, 0xF0B900, 0xB69123, 0xE8EAEE, 0xBDBEC1, 0xF9F9F9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xECECEC, 0xB6B7BD, 0xD8D8D7, 0xC3AD43, 0xFFE506, 0xF8DA0A, 0xF4D302, 0xF7D300, 0xEFC900, 0x453900, 0x0, 0x6070F, 0x3A3829, 0xCDA601, 0xF5BF00, 0xEDB800, 0xEDB400, 0xF0B400, 0xCE9706, 0xC2AB77, 0xCBD0DD, 0xD7D6D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFCFCFC, 0xB8B8BA, 0xD8D9E5, 0xBAAB65, 0xECC902, 0xF4CD00, 0xF0CA00, 0xEEC600, 0xF3C800, 0xF2C600, 0x4D3D00, 0x0, 0x171922, 0x534F3D, 0xD3A901, 0xF4BA00, 0xEDB200, 0xEDB100, 0xECB000, 0xEDAE00, 0xB88B16, 0xCBC5BB, 0xBABCC0, 0xF3F3F3, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xDEDEDE, 0xB4B5BF, 0xB8B8AC, 0xD1AE0D, 0xF6CD00, 0xEFC900, 0xEFC600, 0xEEC400, 0xF2C500, 0xF6C900, 0x5D4A00, 0x4, 0x202435, 0x5A5544, 0xD4A801, 0xF4B800, 0xEDB000, 0xECAF00, 0xEBAC00, 0xECAC00, 0xD99903, 0xB5964E, 0xC6CBDA, 0xC7C7C7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xF8F8F8, 0xB2B3B5, 0xC4C5D1, 0xB9A550, 0xEAC102, 0xEFC800, 0xEEC500, 0xEEC400, 0xEEC200, 0xEEC100, 0xF0C000, 0xD1A100, 0xB38800, 0xBB9100, 0xCA9B00, 0xE5AB00, 0xEDB100, 0xEBAE00, 0xEAAC00, 0xEAA900, 0xE8A700, 0xEDA800, 0xC28B06, 0xB9AB8D, 0xB7BBC3, 0xE9E9E9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xC7C7C8, 0xB9BCCB, 0xB5B090, 0xD5AE06, 0xF0C800, 0xEEC300, 0xEEC200, 0xEEC100, 0xEDBD00, 0xEDBB00, 0xF2BB00, 0xCD9E00, 0x907000, 0x806506, 0xB68A00, 0xF4B400, 0xEBAB00, 0xEAA900, 0xEAA800, 0xE7A600, 0xE7A400, 0xE7A300, 0xDC9803, 0xB18C36, 0xC2C5D3, 0xBFBFC0, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xF1F1F1, 0xAFB0B6, 0xB7B7B8, 0xBBA543, 0xEBBF02, 0xEEC400, 0xEEC100, 0xEEBF00, 0xEEBD00, 0xEDBA00, 0xEFBA00, 0xF4BD00, 0x765A00, 0x5, 0x161B33, 0x645A38, 0xDBA200, 0xEEAC00, 0xEAA800, 0xE8A700, 0xE7A400, 0xE7A400, 0xE7A400, 0xEBA600, 0xC58B06, 0xB19E75, 0xB6BBC5, 0xDEDEDE, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xBCBCBD, 0xB4B7C4, 0xB3AB77, 0xD8B006, 0xF3C805, 0xF0C506, 0xF0C305, 0xF0C102, 0xEFC001, 0xF0BC00, 0xF4BD00, 0xF5C000, 0x554200, 0xA, 0x343944, 0x5F5D57, 0xD19C06, 0xF3B300, 0xEBAE04, 0xEBAC05, 0xEAAB06, 0xEAAB06, 0xEBAB05, 0xECAC06, 0xE1A203, 0xB38823, 0xBCBBBF, 0xB5B7BB, 0xF8F8F8, 0xFFFFFF,
0xFFFFFF, 0xE8E8E7, 0xAEAEB3, 0xB1AFA0, 0xC3AB45, 0xFED923, 0xF8D329, 0xF8D028, 0xF8CE27, 0xF8CD26, 0xF7CC24, 0xF8CB23, 0xF8CA22, 0xFFCE20, 0xC9A21E, 0x4C4324, 0x55544A, 0x9D863E, 0xECB821, 0xF7C228, 0xF3BD29, 0xF2BD2A, 0xF3BF2A, 0xF3BF29, 0xF3BF29, 0xF4BF29, 0xF9C227, 0xD19F19, 0xB09964, 0xB2B4BF, 0xD1D1D2, 0xFFFFFF,
0xFFFFFF, 0xBABABB, 0xB7B8C0, 0xB6AA73, 0xCCA420, 0xCBA326, 0xCBA126, 0xCB9F26, 0xCB9E24, 0xCB9E24, 0xCB9E24, 0xCB9E23, 0xCA9E22, 0xCA9E22, 0xCE9E22, 0xC49822, 0xBB8F1F, 0xC59820, 0xC99B23, 0xC89B26, 0xC89A26, 0xC89A26, 0xC89B26, 0xC99B26, 0xC99B26, 0xC99B26, 0xCA9B26, 0xCC9E22, 0xBC9637, 0xBAB4B0, 0xB1B3B7, 0xEFEFF0,
0xFFFFFF, 0xB2B3B4, 0xC9CACC, 0xD2CFC9, 0xD3CFCA, 0xD3CFCB, 0xD4CFCD, 0xD5D1CE, 0xD6D2CF, 0xDDDAD6, 0xE3DFDD, 0xEAE7E6, 0xEEEBEA, 0xEFEDEA, 0xEFEDEB, 0xF0EDEB, 0xF0EEEB, 0xEFEDEB, 0xEFEDEB, 0xEDEAE7, 0xE7E5E3, 0xE7E4E3, 0xDFDAD8, 0xD8D4D1, 0xD6D2CF, 0xD5D1CE, 0xD4CFCD, 0xD3CECB, 0xD4CFCD, 0xD0CECF, 0xBDBDC0, 0xC9C9C9,
0xFFFFFF, 0xBBBBBB, 0x9F9FA0, 0x979799, 0x97979B, 0x97979B, 0x97989B, 0x98999C, 0x999B9C, 0x9B9C9E, 0x9C9CA1, 0x9C9DA1, 0x9DA1A2, 0xA1A1A3, 0xA1A1A3, 0xA1A2A4, 0xA2A2A4, 0xA1A2A4, 0xA1A1A3, 0xA1A1A3, 0x9EA1A2, 0x9D9EA1, 0x9D9DA0, 0x9C9D9E, 0x9A9B9D, 0x999A9D, 0x98999C, 0x97989B, 0x98989B, 0x989899, 0xA7A7A7, 0xE0E0E0,
0xFFFFFF, 0xFFFFFF, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
};
const unsigned pic_error[] = {
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xE9E9E9, 0xC7C6C6, 0xA9A8A8, 0x8F8E8E, 0x7C7B7B, 0x6F6E6E, 0x6F6E6E, 0x7C7B7B, 0x8F8E8E, 0xA9A8A8, 0xC7C6C6, 0xE9E9E9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD9D9D9, 0xAAA9A9, 0x807F7F, 0xA2A2A2, 0xC0C0C0, 0xDADADA, 0xEEEDED, 0xFBFBFB, 0xFBFBFB, 0xEEEDED, 0xDADADA, 0xC0C0C0, 0xA2A2A2, 0x807F7F, 0xAAA9A9, 0xD9D9D9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0xB0B0B0, 0x8F8F8F, 0xBFBFBF, 0xECEBEB, 0xEBD9D8, 0xE4BDBD, 0xDCA7A8, 0xD79596, 0xD48688, 0xCE7D7F, 0xD28B8C, 0xD9A2A1, 0xE1BEC0, 0xEAD9D9, 0xECEAEA, 0xBFBFBF, 0x8F8F8F, 0xB0B0B0, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x959595, 0xB9B8B8, 0xEFECEC, 0xE5C2C3, 0xE1AEAD, 0xE89D9E, 0xE06F6F, 0xE15C5C, 0xE25254, 0xE15150, 0xDF4F4F, 0xDB4F4F, 0xD65051, 0xCF5151, 0xC85F5F, 0xD3A1A1, 0xE0C8C7, 0xE7E4E4, 0xB9B8B8, 0x959595, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD1D1D1, 0x919090, 0xD3D3D3, 0xECD0D0, 0xDFA9AA, 0xECA2A2, 0xE36565, 0xE65151, 0xE44F4F, 0xE44D4F, 0xE04D4D, 0xDF4D4D, 0xDC4D4D, 0xDB494C, 0xD84A4A, 0xD64947, 0xD44747, 0xCB4949, 0xC34B4B, 0xD08E8E, 0xE8CCCD, 0xD3D3D3, 0x919090, 0xD1D1D1, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x919090, 0xE1E1E1, 0xE2B5B5, 0xE4A6A7, 0xE57778, 0xE55151, 0xE44F4F, 0xE24E4E, 0xE04D4D, 0xDE4C4C, 0xDC4B4B, 0xDB4949, 0xD74848, 0xD54747, 0xD34545, 0xD14545, 0xCF4343, 0xCC4242, 0xCB3F3F, 0xC24343, 0xB64546, 0xDCADAD, 0xE1E1E1, 0x919090, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0x959595, 0xD3D3D3, 0xE2B5B5, 0xE49E9E, 0xE26667, 0xE6504E, 0xE04646, 0xDA3D3D, 0xDC4444, 0xDC4B4B, 0xDB4848, 0xD94748, 0xD54646, 0xD34344, 0xD14343, 0xCF4242, 0xCD4341, 0xC83A3A, 0xC52F31, 0xC33535, 0xC33C3C, 0xBE3D3D, 0xB53F40, 0xDCACAC, 0xD3D3D3, 0x959595, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xB0B0B0, 0xB9B8B8, 0xECD0D0, 0xDB8F8F, 0xE36868, 0xE24E4E, 0xDB403E, 0xE96565, 0xF7B2B2, 0xE46565, 0xD23B39, 0xD74646, 0xD44343, 0xD14343, 0xCF4242, 0xCB4040, 0xCA3F3F, 0xC43333, 0xCB4E4E, 0xE29E9E, 0xCF5B5C, 0xBA2A29, 0xBC3636, 0xB83839, 0xB13E3F, 0xE9CBCB, 0xB9B8B8, 0xB0B0B0, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xD9D9D9, 0x8F8F8F, 0xEFECEC, 0xD69696, 0xE37B7B, 0xE04B4D, 0xDB4141, 0xE65F5F, 0xFFE7E7, 0xFFFFFF, 0xFFE9E9, 0xDC5A5A, 0xCA3333, 0xCF4242, 0xCB4040, 0xC93D3D, 0xC83E3D, 0xC23030, 0xC94848, 0xDDC0C0, 0xDEEEEC, 0xE0D0D0, 0xC75455, 0xB32828, 0xB43232, 0xB13434, 0xB75354, 0xEFECEC, 0x8F8F8F, 0xD9D9D9, 0xFFFFFF,
0xFFFFFF, 0xAAA9A9, 0xBEBEBE, 0xE6CAC9, 0xDB797A, 0xDF4C4C, 0xDB4141, 0xE05757, 0xFFEAEA, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFE7E8, 0xD75B5B, 0xC62E2E, 0xC93E3E, 0xC53A3A, 0xC12E2C, 0xC8494A, 0xDDC2C2, 0xDAE3E3, 0xD4D5D5, 0xD3DADA, 0xD9CBCA, 0xBB4747, 0xAD2525, 0xAC2B2C, 0xAE3233, 0xD8A4A5, 0xBFBFBF, 0xAAA9A9, 0xFFFFFF,
0xE9E9E9, 0x807F7F, 0xEBE9E9, 0xDAA7A7, 0xDB6060, 0xDB4745, 0xD63C3C, 0xDE5758, 0xFFF2F2, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xF8E8E8, 0xD45B5B, 0xBD2828, 0xBD2B2A, 0xC54949, 0xDBC3C3, 0xDAE4E4, 0xD5D5D5, 0xD0CECE, 0xE5E8E8, 0xF4F4F4, 0xAF4949, 0xA62121, 0xA62A2A, 0xA92B2C, 0xB85755, 0xECEAEA, 0x807F7F, 0xE9E9E9,
0xC7C6C6, 0xA2A2A2, 0xEAD9DA, 0xCF6B6B, 0xD74444, 0xD64341, 0xD34242, 0xCD3434, 0xDB6464, 0xFFEFEF, 0xFFFFFF, 0xFCFCFC, 0xF6F6F6, 0xF4FCFC, 0xF0E1E2, 0xCC5050, 0xC14040, 0xDBC3C3, 0xD8E1E1, 0xD5D4D4, 0xCFCFCF, 0xE5E8E8, 0xF4F2F2, 0xA24040, 0x990C0C, 0xA20F0F, 0xA00F0F, 0x9D0F0F, 0xA92F30, 0xE8D1D1, 0xA3A3A3, 0xC7C6C6,
0xA9A8A8, 0xC0C0C0, 0xE1BABD, 0xCF5556, 0xD44141, 0xD23F3F, 0xCE3F3F, 0xCC3D3D, 0xC32A2C, 0xD35E5E, 0xF6EBEB, 0xFAFFFF, 0xF1F1F1, 0xEEEDED, 0xE9F0F0, 0xE6D2D2, 0xD6BDBD, 0xD3DADA, 0xCFCFCF, 0xCAC9C9, 0xE2E5E5, 0xF3F1F1, 0xA03A3A, 0x980C0C, 0xA30B0B, 0x9F0B0B, 0x9E0B0B, 0x9E0B0B, 0xA41C1C, 0xD39C9C, 0xC1C1C1, 0xA9A8A8,
0x8F8E8E, 0xDADADA, 0xD59B9C, 0xCD4949, 0xD03D3E, 0xCE3D3C, 0xCA3C3C, 0xC83A3A, 0xC7393B, 0xBD2828, 0xCC5C5C, 0xEDE5E5, 0xEDF4F4, 0xE6E5E5, 0xDEDEDE, 0xD9DCDC, 0xD3D9D9, 0xCDCDCD, 0xC8C8C8, 0xE1E5E5, 0xF3F1F1, 0xA03F3F, 0x990C0C, 0xA40A0A, 0xA10B0B, 0xA00B0B, 0xA00B0B, 0x9F0B0B, 0xA21313, 0xC06B6B, 0xDADADA, 0x8F8E8E,
0x7C7B7B, 0xEEEDED, 0xCB807F, 0xCC4140, 0xCA3C3C, 0xC83A3A, 0xC83A38, 0xC43838, 0xC23636, 0xC03939, 0xB72321, 0xC24A4A, 0xDECBCB, 0xDCE0E0, 0xD6D6D6, 0xD3D2D2, 0xCECDCD, 0xC9C9C9, 0xE1E2E2, 0xF2F1F1, 0xA34242, 0x990C0C, 0xA40A0A, 0xA40A0A, 0xA40A0A, 0xA30B0B, 0xA30B0B, 0xA10B0B, 0xA10E0E, 0xB04344, 0xEEEDED, 0x7C7B7B,
0x6F6E6E, 0xFBFBFB, 0xBE5959, 0xCA3B3B, 0xC83A3A, 0xC43737, 0xC23535, 0xC03636, 0xBE3636, 0xB82323, 0xB10909, 0xA70A0A, 0xBE4949, 0xD4D6D6, 0xD1D3D3, 0xCDCDCD, 0xC8C8C8, 0xC3C4C4, 0xEDEDED, 0xB35F5F, 0x980C0C, 0xA70A0A, 0xA60A0A, 0xA60A0A, 0xA60A0A, 0xA40A0A, 0xA60A0A, 0xA40A0A, 0xA40B0B, 0xA62D2D, 0xFBFBFB, 0x6F6E6E,
0x6F6E6E, 0xF9F9F9, 0xC16666, 0xC43838, 0xC23535, 0xC03434, 0xBE3535, 0xBC3030, 0xB41313, 0xAD0909, 0xA80A0A, 0xB31E1E, 0xD0AAAA, 0xCDD3D3, 0xCCCCCC, 0xC8C8C8, 0xC3C3C3, 0xC1C2C2, 0xBFC4C4, 0xCBB2B2, 0xB42B2B, 0xA40A0A, 0xA80A0A, 0xA80A0A, 0xA90A0A, 0xA90A0A, 0xA90A0A, 0xA90A0A, 0xA90B0B, 0xA63131, 0xFAFAFA, 0x6F6E6E,
0x7C7B7B, 0xEBEAEB, 0xC77C7D, 0xBF3838, 0xBE3434, 0xBE3635, 0xB82A2A, 0xB00909, 0xAC0909, 0xA80A0A, 0xB11C1C, 0xD0B2B2, 0xCCD7D7, 0xCBCBCB, 0xC8C7C7, 0xC3C8C8, 0xC3C6C6, 0xC1BFBF, 0xBDBDBD, 0xBCC5C5, 0xCEB8B8, 0xB52929, 0xA80A0A, 0xAC0909, 0xAD0909, 0xAF0909, 0xAF0909, 0xAF0909, 0xB00C0C, 0xAF4747, 0xEDECEC, 0x7C7B7B,
0x8F8E8E, 0xD7D8D9, 0xD19999, 0xBB3838, 0xBC3636, 0xB72C2C, 0xAD0909, 0xA90A0A, 0xA40A0A, 0xAF1C1C, 0xCFB1B1, 0xCBD6D6, 0xCBCCCC, 0xC7C7C7, 0xE1E4E4, 0xEEECEC, 0xB7ACAC, 0xBCC2C2, 0xBFBEBE, 0xC0C0C0, 0xC6CFCF, 0xD5C1C1, 0xB82727, 0xAC0909, 0xB20909, 0xB20909, 0xB40909, 0xB40808, 0xB50E0E, 0xBF6E6E, 0xD9D9D9, 0x8F8E8E,
0xA9A8A8, 0xBEBEBE, 0xDCBBBA, 0xB7393A, 0xB82F2F, 0xAD0909, 0xA90A0A, 0xA60A0A, 0xAC1515, 0xCFADAD, 0xCBD6D6, 0xCACBCB, 0xC6C6C6, 0xE1E4E4, 0xEFEEEE, 0xA13838, 0xA22222, 0xB8ABAC, 0xC0C8C8, 0xC8C7C7, 0xCDCDCD, 0xD9E1E1, 0xE1CAC8, 0xBC2424, 0xB40808, 0xB90808, 0xBA0808, 0xBB0808, 0xAB0E0F, 0xD5A2A1, 0xC0C0C0, 0xA9A8A8,
0xC7C6C6, 0xA0A1A0, 0xE4D7D6, 0xB33A3A, 0xAD1212, 0xA80A0A, 0xA40A0A, 0xAA1313, 0xCFABAB, 0xCBD6D6, 0xCACACA, 0xC6C6C6, 0xE0E4E4, 0xEFEEEE, 0xA03F3F, 0x990C0C, 0xA60A0A, 0xAB2828, 0xBFB2B2, 0xCED8D8, 0xD8D6D6, 0xE0E0E0, 0xEDF5F6, 0xEDD1D1, 0xC01C1E, 0xBE0707, 0xBF0707, 0xC00707, 0xAA2021, 0xE9D5D3, 0xA3A3A2, 0xC7C6C6,
0xE9E9E9, 0x807F7F, 0xE5E3E3, 0xB24646, 0xA81414, 0xA40A0A, 0xA00B0B, 0xA92121, 0xCABDBD, 0xC8D0D0, 0xC5C5C5, 0xE1E3E3, 0xEFEDED, 0x9E3E3E, 0x980C0C, 0xA60A0A, 0xA80A0A, 0xA90A0A, 0xB02B2B, 0xCDC0C0, 0xE2EAEA, 0xEBEBEB, 0xF8FEFE, 0xEEEDED, 0xBD2828, 0xC40707, 0xC70908, 0xC40F0F, 0xCB8887, 0xECEBEB, 0x818080, 0xE9E9E9,
0xFFFFFF, 0xAAA9A9, 0xBFBFBF, 0xD59B9B, 0xA61C1C, 0xA10C0C, 0x9F0B0B, 0x9A0B0B, 0xA73535, 0xBEB5B5, 0xDFE6E6, 0xEFEDED, 0x9C3C3C, 0x970C0C, 0xA40A0A, 0xA60A0A, 0xA90A0A, 0xAD0909, 0xB00909, 0xB52626, 0xDECECE, 0xFBFFFF, 0xF1EEEE, 0xBA4848, 0xBC0808, 0xCD0A0A, 0xCE0B0B, 0xAB1111, 0xE0C0BE, 0xBFC0BF, 0xAAA9A9, 0xFFFFFF,
0xFFFFFF, 0xD9D9D9, 0x8F8F8F, 0xEFECEC, 0xB14545, 0xA41616, 0x9B0B0B, 0x990C0C, 0x960C0C, 0xA23333, 0xD0B9B9, 0x9B3A39, 0x950C0C, 0xA10B0B, 0xA40A0A, 0xA70A0A, 0xAB0A0A, 0xB00909, 0xB40808, 0xB70808, 0xC22F2F, 0xE2AEAE, 0xBF4B4B, 0xBE0707, 0xD10B0B, 0xD30C0C, 0xCC1314, 0xB14848, 0xEFECEC, 0x8F8F8F, 0xD9D9D9, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xB0B0B0, 0xB9B8B8, 0xE8CACA, 0xA32425, 0x9F1313, 0x970C0C, 0x950C0C, 0x950C0C, 0x910C0C, 0x950C0C, 0x9E0B0B, 0xA00B0B, 0xA40A0A, 0xA80A0A, 0xAD0909, 0xB20909, 0xB80808, 0xBC0808, 0xC00707, 0xBC0808, 0xC50707, 0xD30C0C, 0xD70D0D, 0xD11212, 0xA72020, 0xEBCDCD, 0xBAB9B9, 0xB0B0B0, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0x959595, 0xD3D3D3, 0xD9A8A8, 0xA42020, 0x9B1313, 0x920C0C, 0x950C0C, 0x970C0C, 0x990C0C, 0x9E0B0B, 0xA00B0B, 0xA40A0A, 0xA90A0A, 0xB00909, 0xB40808, 0xBB0808, 0xC00707, 0xC60A0A, 0xCC0909, 0xD30C0C, 0xD80D0D, 0xD31313, 0xA81A1A, 0xDEADAE, 0xD4D4D4, 0x959595, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x919090, 0xE1E1E1, 0xDAA8A8, 0xA02323, 0x9C1515, 0x920D0D, 0x950C0C, 0x990C0C, 0x9E0B0B, 0xA00B0B, 0xA60A0A, 0xAC0909, 0xB20909, 0xB80808, 0xBC0808, 0xC30808, 0xC90C0C, 0xD00C0C, 0xD60D0D, 0xCF1313, 0xA92222, 0xDEAFAF, 0xE1E1E1, 0x919090, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD1D1D1, 0x919090, 0xD3D3D3, 0xE8CACA, 0xB04344, 0x991717, 0x9C1111, 0x980C0C, 0x9B0B0B, 0xA00B0B, 0xA60A0A, 0xAC0909, 0xB20909, 0xBA0808, 0xBF0707, 0xC8090B, 0xCE0D0D, 0xCC1111, 0xAF1010, 0xB2494A, 0xEBCFCF, 0xD3D3D3, 0x919090, 0xD1D1D1, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x959595, 0xB9B8B8, 0xEFECEC, 0xDFC0C0, 0xC47779, 0xA02122, 0x9B1212, 0xA41010, 0xA80C0C, 0xAC0A0A, 0xB40A0A, 0xB90A0A, 0xBE0D0D, 0xB10F0F, 0xA61111, 0xB85656, 0xDCADAE, 0xEFECEC, 0xB9B8B8, 0x959595, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0xB0B0B0, 0x8F8F8F, 0xBDBDBD, 0xEBE9E9, 0xE9D9D9, 0xDDB5B5, 0xCD8B8B, 0xB75A59, 0xA83937, 0xA42C2B, 0xB1494A, 0xC17171, 0xD7A2A1, 0xE8D3D3, 0xEBEAEA, 0xBFBEBE, 0x8F8F8F, 0xB0B0B0, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD9D9D9, 0xAAA9A9, 0x807F7F, 0xA2A2A2, 0xC0C0C0, 0xDADADA, 0xEEEDED, 0xFBFBFB, 0xFBFBFB, 0xEEEDED, 0xDADADA, 0xC0C0C0, 0xA2A2A2, 0x807F7F, 0xAAA9A9, 0xD9D9D9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xE9E9E9, 0xC7C6C6, 0xA9A8A8, 0x8F8E8E, 0x7C7B7B, 0x6F6E6E, 0x6F6E6E, 0x7C7B7B, 0x8F8E8E, 0xA9A8A8, 0xC7C6C6, 0xE9E9E9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
};
const unsigned pic_question[] = {
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xE9E9E9, 0xC7C6C6, 0xA9A8A8, 0x8F8E8E, 0x7C7B7B, 0x6F6E6E, 0x6F6E6E, 0x7C7B7B, 0x8F8E8E, 0xA9A8A8, 0xC7C6C6, 0xE9E9E9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD9D9D9, 0xAAA9A9, 0x7F7E7E, 0xA1A1A1, 0xC0C0C0, 0xDADADA, 0xEDEDED, 0xFBFBFB, 0xFBFBFB, 0xEDEDED, 0xDADADA, 0xC0C0C0, 0xA1A1A1, 0x7F7E7E, 0xAAA9A9, 0xD9D9D9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0xB0B0B0, 0x8F8E8E, 0xBFBFBF, 0xEBEBEB, 0xDADADA, 0xBFC0C3, 0xAFB4C4, 0x9AA7CA, 0x7D8EC0, 0x7889BE, 0x8898C5, 0xA1AAC5, 0xB4B6C0, 0xDAD9DA, 0xEBEBEB, 0xBFBFBF, 0x8F8E8E, 0xB0B0B0, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x959595, 0xB8B7B7, 0xEDEDED, 0xCACACA, 0xBEC2CF, 0x9BADDF, 0x698CE8, 0x4C75E3, 0x406BE0, 0x416DE0, 0x3F6BDD, 0x3B67D8, 0x3864D4, 0x3E68D1, 0x5375CC, 0x8A98BF, 0xC4C5CA, 0xEDEDED, 0xB8B7B7, 0x959595, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD1D1D1, 0x908F8F, 0xD3D3D3, 0xDEDEDE, 0xC3C6CE, 0xA1B5E9, 0x6B8FED, 0x4C77E7, 0x446FE0, 0x446EDD, 0x456EDB, 0x426DD9, 0x416BD6, 0x4069D4, 0x3D67D1, 0x3C65CE, 0x3761CB, 0x305AC6, 0x3B60C3, 0x8694B8, 0xDDDDDD, 0xD3D3D3, 0x908F8F, 0xD1D1D1, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x908F8F, 0xE1E1E1, 0xCECECE, 0xBFC8DF, 0x819EEF, 0x537CE8, 0x416DE0, 0x446EDE, 0x456EDB, 0x416AD9, 0x3D67D6, 0x3864D3, 0x3761CF, 0x3763CD, 0x3A63CB, 0x3C64CA, 0x3B63C7, 0x3860C4, 0x335DC1, 0x2852BB, 0x5570B3, 0xC7C8CB, 0xE1E1E1, 0x908F8F, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0x959595, 0xD3D3D3, 0xCECECE, 0xBAC7E9, 0x7092ED, 0x4671E2, 0x426DDE, 0x466FDD, 0x3F69D8, 0x3865D6, 0x4870D8, 0x5F82DB, 0x7290DF, 0x7290DD, 0x5E7FD6, 0x446ACB, 0x3059C2, 0x335CC1, 0x365EC1, 0x345CBC, 0x345BBA, 0x2951B5, 0x3E5EAE, 0xC5C6CB, 0xD3D3D3, 0x959595, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xB0B0B0, 0xB8B7B7, 0xDEDEDE, 0xB7C0DA, 0x6E91EC, 0x426DDF, 0x456EDD, 0x456EDB, 0x3F6AD8, 0x567CDD, 0xAEC1F2, 0xEBF1FF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFAFCFF, 0xE7EAF8, 0xA3B5E3, 0x4468C2, 0x2C55B9, 0x335AB8, 0x3157B5, 0x3056B4, 0x244CAE, 0x405DA4, 0xDBDBDC, 0xB8B7B7, 0xB0B0B0, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xD9D9D9, 0x8F8E8E, 0xEDEDED, 0xAEB1BA, 0x7A9AED, 0x456FDF, 0x446DDB, 0x456ED9, 0x426BD7, 0x3763D1, 0xB1C3F1, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFEFD, 0xFFFFFC, 0xD4DAED, 0x4466BA, 0x2B52B2, 0x2E55B0, 0x2C53AF, 0x2B51AD, 0x1F47A5, 0x6576A1, 0xEDEDED, 0x8F8E8E, 0xD9D9D9, 0xFFFFFF,
0xFFFFFF, 0xAAA9A9, 0xBFBFBF, 0xC3C3C3, 0x92A7E1, 0x537AE2, 0x406AD9, 0x446DD8, 0x426BD6, 0x3F68D3, 0x3661CE, 0xB6C5EE, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFCFCFE, 0xF8F8FA, 0xFFFFFD, 0xAAB8D9, 0x264CAC, 0x2C52AE, 0x2C51AC, 0x2B50A8, 0x2A4FA6, 0x1E429C, 0xB1B5BF, 0xBFBFBF, 0xAAA9A9, 0xFFFFFF,
0xE9E9E9, 0x7F7E7E, 0xEBEBEB, 0x9DA3B4, 0x6B8DE8, 0x3E69D7, 0x416AD7, 0x4069D4, 0x3F68D0, 0x3D67CE, 0x345ECA, 0xB7C4EA, 0xFFFFFA, 0xC2C9DA, 0x8B9BC5, 0x778DC2, 0x99AAD1, 0xF2F3F8, 0xFEFDFF, 0xFAFAFD, 0xFAFAFC, 0xE8EAF2, 0x3859AA, 0x2A50AB, 0x2C51A8, 0x2C50A6, 0x2A4FA4, 0x244AA0, 0x506698, 0xEBEBEB, 0x7F7E7E, 0xE9E9E9,
0xC7C6C6, 0xA1A1A1, 0xD6D6D6, 0x8498CE, 0x4E75DD, 0x3D67D4, 0x3F68D3, 0x3E66CF, 0x3D66CC, 0x3C64CA, 0x365FC6, 0x7990CF, 0x7085B8, 0x2D52AE, 0x2750B4, 0x2650B4, 0x1F48AD, 0x8499CE, 0xFDFCFA, 0xF8F8FA, 0xF9F8FC, 0xF5F6F7, 0x4865A8, 0x284FA6, 0x2C51A5, 0x2C50A3, 0x2B4FA2, 0x2B4EA1, 0x244797, 0xCBCDD2, 0xA2A2A2, 0xC7C6C6,
0xA9A8A8, 0xC0C0C0, 0xA8AAB0, 0x5E82DA, 0x3E68D4, 0x3D67CF, 0x3E66CD, 0x3D65CB, 0x3B63C9, 0x3A61C5, 0x385FC3, 0x3057BE, 0x2B54B9, 0x335CBC, 0x345BB9, 0x345AB7, 0x274FB0, 0x5B78BF, 0xE9E9EB, 0xEDECEF, 0xF2F1F4, 0xEBEBF1, 0x31509B, 0x19419D, 0x1D429C, 0x1E429B, 0x1E4299, 0x204499, 0x173D96, 0x7F8AA3, 0xC1C1C1, 0xA9A8A8,
0x8F8E8E, 0xDADADA, 0x8E94A5, 0x476ED5, 0x3B64CD, 0x3D66CC, 0x3C64C9, 0x3B61C6, 0x3860C4, 0x365EC2, 0x365DBF, 0x355CBB, 0x345BBA, 0x335AB7, 0x2E54B4, 0x244CAD, 0x133EA5, 0x7587B8, 0xD3D0D1, 0xD8D8DE, 0xEFEEEF, 0xBBC2D5, 0x173B91, 0x193F9A, 0x1C4199, 0x1D4199, 0x1D4198, 0x1D4197, 0x1C4096, 0x44598B, 0xDADADA, 0x8F8E8E,
0x7C7B7B, 0xEDEDED, 0x7683A3, 0x3E67D0, 0x3B63CA, 0x3B63C7, 0x3860C4, 0x375FC2, 0x365DC0, 0x355CBE, 0x355CBA, 0x3359B7, 0x2B52B2, 0x2149AC, 0x1640A5, 0xC37A1, 0x4E68AB, 0xB5B4BA, 0xC0BFC3, 0xD1D0D6, 0xEDECEC, 0x5C72A4, 0x123893, 0x1E4299, 0x1E4299, 0x1E4298, 0x1F4298, 0x204297, 0x214498, 0x2C478A, 0xEDEDED, 0x7C7B7B,
0x6F6E6E, 0xFBFBFB, 0x63749F, 0x3B64CC, 0x375FC4, 0x365EC3, 0x355DC0, 0x345CBE, 0x345BBB, 0x3359B7, 0x2A52B2, 0x2048AB, 0x1740A6, 0x143DA2, 0x143DA1, 0x5E74AC, 0xB1B1B7, 0xB2B1B6, 0xBABABF, 0xD6D4D6, 0x8592B5, 0x183C90, 0x20459C, 0x22469A, 0x22459A, 0x224599, 0x234699, 0x22459A, 0x23469A, 0x2B4990, 0xFBFBFB, 0x6F6E6E,
0x6F6E6E, 0xFBFBFB, 0x617098, 0x3660C7, 0x355DBF, 0x345CBE, 0x335BBB, 0x345AB8, 0x2E54B4, 0x1F47AB, 0x1640A6, 0x143EA3, 0x153EA1, 0xE389D, 0x5F75AD, 0xC0BCBC, 0xB4B4B8, 0xB6B6BB, 0xC1C1C4, 0x6577A2, 0x1C3E92, 0x274A9E, 0x2A4B9E, 0x2A4C9E, 0x2A4C9E, 0x2A4C9E, 0x2A4BA0, 0x294BA0, 0x294A9E, 0x2F4B94, 0xFBFBFB, 0x6F6E6E,
0x7C7B7B, 0xEDEDED, 0x6B7694, 0x335BC0, 0x335ABB, 0x3259B8, 0x3257B6, 0x2951B0, 0x1944A7, 0x153FA4, 0x153EA2, 0x143DA0, 0x133B9C, 0x1F45A0, 0xB1B6C4, 0xC4C3C6, 0xBFBFC4, 0xBEBEC4, 0x546798, 0x1D4096, 0x2C4FA2, 0x3051A2, 0x3151A2, 0x3252A3, 0x3252A4, 0x3252A5, 0x3152A5, 0x3151A5, 0x3050A5, 0x354F93, 0xEDEDED, 0x7C7B7B,
0x8F8E8E, 0xDADADA, 0x828895, 0x2C55B7, 0x3056B7, 0x3056B5, 0x2850AE, 0x1741A5, 0x143EA2, 0x143DA0, 0x133C9D, 0x133C9B, 0xE3698, 0x3F5DA6, 0xCECED3, 0xCCCCD1, 0xD5D3D5, 0x7A87A8, 0x1E4194, 0x3253A5, 0x3454A4, 0x3655A7, 0x3756A8, 0x3756AA, 0x3856AB, 0x3856AB, 0x3756AB, 0x3555AB, 0x3554AC, 0x445993, 0xDADADA, 0x8F8E8E,
0xA9A8A8, 0xC0C0C0, 0xA0A2A6, 0x3759AE, 0x2C54B2, 0x284FAD, 0x1740A3, 0x143EA1, 0x143D9E, 0x123B9B, 0x123B99, 0x133B99, 0xE3696, 0x4C67A8, 0xD1CED0, 0xD3D0D1, 0xD7D4D4, 0x5A6DA0, 0x2B4EA3, 0x3756A7, 0x3A59AB, 0x3B5AAD, 0x3C5AAE, 0x3D5BB0, 0x3D5BB0, 0x3C5AB0, 0x3B59B0, 0x3A57B0, 0x3554B0, 0x7380A2, 0xC1C1C1, 0xA9A8A8,
0xC7C6C6, 0xA1A1A1, 0xD4D4D4, 0x4A629B, 0x284FAD, 0x1840A3, 0x133C9E, 0x133C9D, 0x113A9A, 0x113A98, 0x123897, 0x143C96, 0x183E97, 0x2D4F9D, 0x5E71A1, 0x6173A1, 0x6577A3, 0x3D579D, 0x3756AB, 0x3C5AAE, 0x3D5BB1, 0x3F5CB2, 0x3F5CB5, 0x3F5CB6, 0x3F5BB6, 0x3E5BB6, 0x3D5AB6, 0x3C59B6, 0x3350AC, 0xBEC2CD, 0xA2A2A2, 0xC7C6C6,
0xE9E9E9, 0x7F7E7E, 0xEBEBEB, 0x737B8E, 0x163FA3, 0x123B9D, 0x123B9B, 0x113898, 0xF3896, 0xF3794, 0x123894, 0x173D96, 0x1F4498, 0x1F4499, 0x21469B, 0x3252A2, 0x3151A5, 0x3252AB, 0x3D5BB0, 0x3F5CB4, 0x3F5CB7, 0x3F5CB9, 0x3F5CBA, 0x3F5CBB, 0x3F5BBB, 0x3E5BBB, 0x3D5ABB, 0x3B59BB, 0x475B9E, 0xE9E9EA, 0x807F7F, 0xE9E9E9,
0xFFFFFF, 0xAAA9A9, 0xBFBFBF, 0xB8B8B9, 0x28468D, 0xF3799, 0x113897, 0xF3694, 0xE3692, 0xF3691, 0x133892, 0x1B4096, 0x1E4298, 0x415EA3, 0x98A1B9, 0xB4B5BE, 0xB2B6C5, 0x6F83BF, 0x3A57B4, 0x3F5CB8, 0x3F5CBB, 0x3F5CBE, 0x3F5BC0, 0x3E5BC0, 0x3E5BC1, 0x3E5AC1, 0x3D5AC0, 0x3350BC, 0x9FA5B9, 0xC0C0C0, 0xAAA9A9, 0xFFFFFF,
0xFFFFFF, 0xD9D9D9, 0x8F8E8E, 0xEDEDED, 0x6E7586, 0x93291, 0xE3693, 0xD3591, 0xD3590, 0xF3690, 0x153B92, 0x1D4194, 0x24489A, 0x97A0B9, 0xC2BFBF, 0xB7B6BA, 0xBFBCBF, 0xC7C9D1, 0x4C66B8, 0x3C59BE, 0x3F5AC0, 0x3E5AC2, 0x3D59C4, 0x3D57C5, 0x3B56C5, 0x3B56C4, 0x3855C5, 0x4F61A0, 0xECECEC, 0x8F8E8E, 0xD9D9D9, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xB0B0B0, 0xB8B7B7, 0xD9D9D9, 0x43557D, 0x5308E, 0xC348F, 0xD348E, 0x12378F, 0x193D91, 0x204496, 0x2C4E9D, 0xAFB5C5, 0xC6C4C7, 0xBEBEC3, 0xC2C2C6, 0xD4D3D6, 0x5368B6, 0x3A56C2, 0x3D59C4, 0x3B56C6, 0x3854C9, 0x3754C9, 0x3753C9, 0x3753CA, 0x364EAD, 0xCFD1D7, 0xB9B8B8, 0xB0B0B0, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0x959595, 0xD3D3D3, 0xBFC0C0, 0x384E7F, 0x7308B, 0xD348C, 0x13388E, 0x1D4093, 0x244799, 0x284A9D, 0x7788B8, 0xD4D3D4, 0xD8D6D6, 0xDDDAD9, 0xA4ABC3, 0x3852B4, 0x3B56C6, 0x3854C9, 0x3652CA, 0x3551CC, 0x3350CC, 0x334FCD, 0x344CB7, 0xB2B6C3, 0xD4D4D4, 0x959595, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x908F8F, 0xE1E1E1, 0xBFC0C1, 0x3B4E7A, 0xC338A, 0x153A8F, 0x1F4294, 0x284A9B, 0x3050A1, 0x3353A6, 0x6077B2, 0x8592BA, 0x7282B6, 0x3C54AF, 0x3855C4, 0x3854C9, 0x3551CB, 0x324FCD, 0x304BCE, 0x2E4AD1, 0x364DB0, 0xADB2C2, 0xE1E1E1, 0x908F8F, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD1D1D1, 0x908F8F, 0xD3D3D3, 0xD9D9D9, 0x5D6881, 0x234186, 0x1E4196, 0x2A4B9C, 0x3353A3, 0x3857AB, 0x3655AE, 0x3351B0, 0x3553B8, 0x3C59C3, 0x3B56C6, 0x3652CA, 0x324ECE, 0x2D4AD1, 0x2B45C9, 0x4F5FA2, 0xD0D2D8, 0xD3D3D3, 0x908F8F, 0xD1D1D1, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x959595, 0xB8B7B7, 0xEDEDED, 0xADAFB4, 0x546181, 0x364F8E, 0x3453A2, 0x3859AD, 0x3E5BB2, 0x405CBA, 0x405CC0, 0x3E59C4, 0x3A55CA, 0x3450CE, 0x344BBD, 0x4758A0, 0xA2A7BA, 0xEDEDED, 0xB8B7B7, 0x959595, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0xB0B0B0, 0x8F8E8E, 0xBFBFBF, 0xEBEBEB, 0xCECFD1, 0x888E9D, 0x5E6988, 0x4C5C89, 0x43558F, 0x435594, 0x475894, 0x596696, 0x7E86A4, 0xC6C9D1, 0xEBEBEB, 0xBFBFBF, 0x8F8E8E, 0xB0B0B0, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD9D9D9, 0xAAA9A9, 0x7F7E7E, 0xA1A1A1, 0xC0C0C0, 0xDADADA, 0xEDEDED, 0xFBFBFB, 0xFBFBFB, 0xEDEDED, 0xDADADA, 0xC0C0C0, 0xA1A1A1, 0x7F7E7E, 0xAAA9A9, 0xD9D9D9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xE9E9E9, 0xC7C6C6, 0xA9A8A8, 0x8F8E8E, 0x7C7B7B, 0x6F6E6E, 0x6F6E6E, 0x7C7B7B, 0x8F8E8E, 0xA9A8A8, 0xC7C6C6, 0xE9E9E9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
};
const unsigned * rawpx;
switch(ico)
{
case msgbox::icon_information:
rawpx = pic_information;
break;
case msgbox::icon_warning:
rawpx = pic_warning;
break;
case msgbox::icon_error:
rawpx = pic_error;
break;
case msgbox::icon_question:
rawpx = pic_question;
break;
default:
rawpx = nullptr;
}
if(rawpx)
{
nana::paint::pixel_buffer pxbuf(32, 32);
pxbuf.put(reinterpret_cast<const unsigned char*>(rawpx), 32, 32, 32, 4*32, true);
ico_.make(32, 32);
pxbuf.paste(ico_.handle(), 0, 0);
}
}
void _m_click(const arg_mouse& arg)
{
if(arg.window_handle == yes_)
pick_ = (no_.empty() ? msgbox::pick_ok : msgbox::pick_yes);
else if(arg.window_handle == no_)
pick_ = msgbox::pick_no;
else if(arg.window_handle == cancel_)
pick_ = msgbox::pick_cancel;
this->close();
}
private:
window owner_;
place place_;
nana::paint::graphics ico_;
nana::label text_;
nana::button yes_, no_, cancel_;
msgbox::pick_t pick_;
};
#endif
//class msgbox
msgbox::msgbox()
: wd_(nullptr), button_(ok), icon_(icon_none)
{}
msgbox::msgbox(const msgbox& rhs)
: wd_(rhs.wd_), title_(rhs.title_), button_(rhs.button_), icon_(rhs.icon_)
{
sstream_<<rhs.sstream_.str();
}
msgbox& msgbox::operator=(const msgbox& rhs)
{
if(this != &rhs)
{
wd_ = rhs.wd_;
title_ = rhs.title_;
button_ = rhs.button_;
icon_ = rhs.icon_;
sstream_ << rhs.sstream_.str();
}
return *this;
}
msgbox::msgbox(const nana::string& title)
: wd_(nullptr), title_(title), button_(ok), icon_(icon_none)
{}
msgbox::msgbox(window wd, const nana::string& title)
: wd_(wd), title_(title), button_(ok), icon_(icon_none)
{}
msgbox::msgbox(window wd, const nana::string& title, button_t b)
: wd_(wd), title_(title), button_(b), icon_(icon_none)
{}
msgbox& msgbox::icon(icon_t ic)
{
icon_ = ic;
return *this;
}
void msgbox::clear()
{
sstream_.str("");
sstream_.clear();
}
msgbox & msgbox::operator<<(const nana::string& str)
{
#if defined(NANA_UNICODE)
sstream_<<static_cast<std::string>(nana::charset(str));
#else
sstream_<<str;
#endif
return *this;
}
msgbox & msgbox::operator<<(const nana::char_t* str)
{
#if defined(NANA_UNICODE)
sstream_<<static_cast<std::string>(nana::charset(str));;
#else
sstream_<<str;
#endif
return *this;
}
msgbox & msgbox::operator<<(const nana::charset& cs)
{
std::string str = cs;
sstream_ << str;
return *this;
}
msgbox & msgbox::operator<<(std::ostream& (*manipulator)(std::ostream&))
{
sstream_<<manipulator;
return *this;
}
msgbox::pick_t msgbox::show() const
{
#if defined(NANA_WINDOWS)
int type = 0;
switch(button_)
{
case msgbox::ok:
type = MB_OK;
break;
case msgbox::yes_no:
type = MB_YESNO;
break;
case msgbox::yes_no_cancel:
type = MB_YESNOCANCEL;
break;
}
switch(icon_)
{
case msgbox::icon_error:
type |= MB_ICONERROR;
break;
case msgbox::icon_question:
type |= MB_ICONQUESTION;
break;
case msgbox::icon_information:
type |= MB_ICONINFORMATION;
break;
case msgbox::icon_warning:
type |= MB_ICONWARNING;
break;
default: break;
}
#if defined(NANA_UNICODE)
int bt = ::MessageBoxW(reinterpret_cast<HWND>(API::root(wd_)), static_cast<std::wstring>(nana::charset(sstream_.str())).c_str(), title_.c_str(), type);
#else
int bt = ::MessageBoxA(reinterpret_cast<HWND>(API::root(wd_), sstream_.str().c_str(), title_.c_str(), type);
#endif
switch(bt)
{
case IDOK:
return pick_ok;
case IDYES:
return pick_yes;
case IDNO:
return pick_no;
case IDCANCEL:
return pick_cancel;
}
return pick_yes;
#elif defined(NANA_X11)
msgbox_window box(wd_, title_, button_, icon_);
box.prompt(nana::charset(sstream_.str()));
return box.pick();
#endif
return pick_yes;
}
//end class msgbox
}

360
source/gui/notifier.cpp Normal file
View File

@@ -0,0 +1,360 @@
/*
* Implementation of Notifier
* 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/notifier.cpp
*/
#include <nana/deploy.hpp>
#include <nana/gui/programming_interface.hpp>
#include <nana/gui/notifier.hpp>
#include <nana/gui/timer.hpp>
#include <unordered_map>
#include <unordered_set>
#include <mutex>
#if defined(NANA_WINDOWS)
#include <nana/detail/win32/platform_spec.hpp>
#elif defined(NANA_LINUX)
#include PLATFORM_SPEC_HPP
#include <nana/system/platform.hpp>
#include <iostream>
#endif
namespace nana
{
typedef std::lock_guard<std::recursive_mutex> lock_guard;
struct notifier::implement
{
nana::timer ani_timer;
native_window_type native_handle;
window handle;
event_handle evt_destroy;
unsigned short id;
detail::notifier_events events;
bool icon_added = false;
std::size_t play_index;
#if defined(NANA_WINDOWS)
HICON icon_handle = nullptr;
std::vector<HICON> icons;
void set_icon(HICON icon)
{
if (icon_handle)
{
NOTIFYICONDATA icon_data;
memset(&icon_data, 0, sizeof icon_data);
icon_data.cbSize = sizeof icon_data;
icon_data.hWnd = reinterpret_cast<HWND>(native_handle);
icon_data.uID = id;
icon_data.uFlags = NIF_MESSAGE | NIF_ICON;
icon_data.uCallbackMessage = nana::detail::messages::tray;
icon_data.hIcon = icon;
::Shell_NotifyIcon(icon_added ? NIM_MODIFY : NIM_ADD, &icon_data);
icon_added = true;
}
}
#endif
};
arg_notifier::operator nana::arg_mouse() const
{
arg_mouse arg;
arg.evt_code = evt_code;
arg.ctrl = false;
arg.shift = false;
arg.left_button = left_button;
arg.mid_button = mid_button;
arg.right_button = right_button;
arg.pos = pos;
arg.window_handle = (notifier_ptr ? notifier_ptr->handle() : nullptr);
return arg;
}
class notifications
{
struct notifier_data
{
::nana::notifier * notifier_ptr;
detail::notifier_events* evt_ptr;
};
struct window_notifiers
{
std::unordered_map<unsigned short, notifier_data> idtable;
};
public:
static notifications& instance()
{
static notifications obj;
return obj;
}
unsigned short register_wd(::nana::notifier* ntf_ptr, native_window_type native_handle, detail::notifier_events* evt_ptr)
{
lock_guard lock(mutex_);
auto i = wd_table_.find(native_handle);
if (i == wd_table_.end())
{
auto & data = wd_table_[native_handle].idtable[0];
data.notifier_ptr = ntf_ptr;
data.evt_ptr = evt_ptr;
return 0;
}
auto & idtable = i->second.idtable;
auto id = static_cast<unsigned short>(idtable.size());
const auto orig_id = id;
while (idtable.count(id) != 0)
{
if (orig_id == ++id)
throw std::runtime_error("Full");
}
auto & data = idtable[id];
data.notifier_ptr = ntf_ptr;
data.evt_ptr = evt_ptr;
return id;
}
void cancel(native_window_type wd, unsigned short id)
{
lock_guard lock(mutex_);
auto i_wd = wd_table_.find(wd);
if (i_wd == wd_table_.end())
return;
auto & idtable = i_wd->second.idtable;
auto i_id = idtable.find(id);
if (i_id == idtable.end())
return;
idtable.erase(i_id);
if (idtable.empty())
wd_table_.erase(i_wd);
}
void emit(native_window_type wd, unsigned short id, const arg_notifier& arg_basic)
{
lock_guard lock(mutex_);
auto i_wd = wd_table_.find(wd);
if (i_wd == wd_table_.end())
return;
auto & idtable = i_wd->second.idtable;
auto i_id = idtable.find(id);
if (i_id == idtable.end())
return;
auto arg = arg_basic;
arg.notifier_ptr = i_id->second.notifier_ptr;
auto evt_ptr = i_id->second.evt_ptr;
switch (arg.evt_code)
{
case event_code::mouse_down:
evt_ptr->mouse_down.emit(arg);
break;
case event_code::mouse_up:
evt_ptr->mouse_up.emit(arg);
break;
case event_code::mouse_leave:
evt_ptr->mouse_leave.emit(arg);
break;
case event_code::mouse_move:
evt_ptr->mouse_move.emit(arg);
break;
case event_code::dbl_click:
evt_ptr->dbl_click.emit(arg);
break;
default:
break;
}
}
private:
mutable std::recursive_mutex mutex_;
std::unordered_map<native_window_type, window_notifiers> wd_table_;
};
#if defined(NANA_WINDOWS)
void notifications_window_proc(HWND wd, WPARAM wparam, LPARAM lparam)
{
arg_notifier arg;
switch (lparam)
{
case WM_LBUTTONDBLCLK:
case WM_MBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
arg.evt_code = event_code::dbl_click;
arg.left_button = (lparam == WM_LBUTTONDBLCLK);
arg.mid_button = (lparam == WM_MBUTTONDBLCLK);
arg.right_button = (lparam == WM_RBUTTONDBLCLK);
break;
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
arg.evt_code = event_code::mouse_down;
arg.left_button = (lparam == WM_LBUTTONDOWN);
arg.mid_button = (lparam == WM_MBUTTONDOWN);
arg.right_button = (lparam == WM_RBUTTONDOWN);
break;
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
arg.evt_code = event_code::mouse_up;
arg.left_button = (lparam == WM_LBUTTONUP);
arg.mid_button = (lparam == WM_MBUTTONUP);
arg.right_button = (lparam == WM_RBUTTONUP);
break;
case WM_MOUSEMOVE:
case WM_MOUSELEAVE:
arg.evt_code = (WM_MOUSEMOVE == lparam ? event_code::mouse_move : event_code::mouse_leave);
arg.left_button = false;
arg.mid_button = false;
arg.right_button = false;
break;
default:
return;
}
::POINT pos;
::GetCursorPos(&pos);
arg.pos.x = pos.x;
arg.pos.y = pos.y;
notifications::instance().emit(reinterpret_cast<native_window_type>(wd), static_cast<unsigned short>(wparam), arg);
}
#endif
typedef ::nana::detail::bedrock bedrock;
//class notifier
notifier::notifier(window wd)
: impl_(new implement)
{
impl_->ani_timer.elapse([this]
{
#if defined(NANA_WINDOWS)
if (impl_->play_index >= impl_->icons.size())
impl_->play_index = 0;
auto ico = impl_->icons[impl_->play_index++];
impl_->set_icon(ico);
#endif
});
auto & brock = bedrock::instance();
impl_->handle = wd;
impl_->native_handle = brock.root(reinterpret_cast<bedrock::core_window_t*>(wd));
impl_->evt_destroy = API::events(wd).destroy([this]
{
close();
});
impl_->id = notifications::instance().register_wd(this, impl_->native_handle, &impl_->events);
}
notifier::~notifier()
{
close();
delete impl_;
}
void notifier::close()
{
if (nullptr == impl_->native_handle)
return;
#if defined(NANA_WINDOWS)
NOTIFYICONDATA icon_data;
memset(&icon_data, 0, sizeof icon_data);
icon_data.cbSize = sizeof icon_data;
icon_data.hWnd = reinterpret_cast<HWND>(impl_->native_handle);
icon_data.uID = impl_->id;
::Shell_NotifyIcon(NIM_DELETE, &icon_data);
if (impl_->icon_handle)
::DestroyIcon(impl_->icon_handle);
for (auto handle : impl_->icons)
::DestroyIcon(handle);
#endif
API::umake_event(impl_->evt_destroy);
notifications::instance().cancel(impl_->native_handle, impl_->id);
impl_->native_handle = nullptr;
}
void notifier::text(const nana::string& str)
{
#if defined(NANA_WINDOWS)
NOTIFYICONDATA icon_data;
memset(&icon_data, 0, sizeof icon_data);
icon_data.cbSize = sizeof icon_data;
icon_data.hWnd = reinterpret_cast<HWND>(impl_->native_handle);
icon_data.uID = impl_->id;
icon_data.uFlags = NIF_MESSAGE | NIF_TIP;
icon_data.uCallbackMessage = nana::detail::messages::tray;
strcpy(icon_data.szTip, str.data());
::Shell_NotifyIcon(impl_->icon_added ? NIM_MODIFY : NIM_ADD, &icon_data);
impl_->icon_added = true;
#endif
}
void notifier::icon(const nana::string& icon_file)
{
#if defined(NANA_WINDOWS)
auto pre_icon = impl_->icon_handle;
auto ico = (HICON)::LoadImage(0, icon_file.data(), IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
if (ico)
{
impl_->icon_handle = ico;
impl_->ani_timer.stop();
impl_->play_index = 0;
impl_->set_icon(impl_->icon_handle);
::DestroyIcon(pre_icon);
}
#endif
}
void notifier::insert_icon(const nana::string& icon_file)
{
#if defined(NANA_WINDOWS)
auto icon = (HICON)::LoadImage(0, icon_file.data(), IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
impl_->icons.push_back(icon);
#endif
}
void notifier::period(unsigned ms)
{
#if defined(NANA_WINDOWS)
if (ms && impl_->icons.size())
{
ms /= static_cast<unsigned>(impl_->icons.size());
impl_->ani_timer.interval(ms < 16 ? 16 : ms);
impl_->ani_timer.start();
}
else
impl_->ani_timer.stop();
#endif
}
detail::notifier_events& notifier::events()
{
return impl_->events;
}
window notifier::handle() const
{
return impl_->handle;
}
//end notifier
}

2219
source/gui/place.cpp Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,62 @@
/*
* State Cursor
* 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/state_cursor.cpp
*/
#include <nana/gui/state_cursor.hpp>
#include <nana/gui/detail/bedrock.hpp>
#include <nana/gui/detail/basic_window.hpp>
namespace nana
{
state_cursor::state_cursor(window handle, cursor cur)
: handle_(handle)
{
auto & brock = detail::bedrock::instance();
auto wd = reinterpret_cast<detail::basic_window*>(handle);
if (brock.wd_manager.available(wd))
brock.define_state_cursor(wd, cur, nullptr);
else
handle_ = nullptr;
}
state_cursor::state_cursor(state_cursor&& rhs)
: handle_(rhs.handle_)
{
rhs.handle_ = nullptr;
}
state_cursor& state_cursor::operator = (state_cursor&& rhs)
{
if (this != &rhs)
{
if (handle_)
{
auto & brock = detail::bedrock::instance();
auto wd = reinterpret_cast<detail::basic_window*>(handle_);
if (brock.wd_manager.available(wd))
brock.undefine_state_cursor(wd, nullptr);
}
handle_ = rhs.handle_;
rhs.handle_ = nullptr;
}
return *this;
}
state_cursor::~state_cursor()
{
if (handle_)
{
auto & brock = detail::bedrock::instance();
auto wd = reinterpret_cast<detail::basic_window*>(handle_);
if (brock.wd_manager.available(wd))
brock.undefine_state_cursor(wd, nullptr);
}
}
}

238
source/gui/timer.cpp Normal file
View File

@@ -0,0 +1,238 @@
/*
* A Timer 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/timer.hpp
* @description:
* A timer can repeatedly call a piece of code. The duration between
* calls is specified in milliseconds. Timer is defferent from other graphics
* controls, it has no graphics interface.
*/
#include <nana/deploy.hpp>
#include <nana/gui/timer.hpp>
#include <map>
#include <memory>
#if defined(NANA_MINGW) && defined(STD_THREAD_NOT_SUPPORTED)
#include <nana/std_mutex.hpp>
#else
#include <mutex>
#endif
#if defined(NANA_WINDOWS)
#include <windows.h>
#elif defined(NANA_LINUX)
#include PLATFORM_SPEC_HPP
#include <nana/system/platform.hpp>
#endif
namespace nana
{
class timer_core;
#if defined(NANA_WINDOWS)
typedef UINT_PTR timer_identifier;
#else
typedef timer_core* timer_identifier;
#endif
class timer_driver
{
typedef std::lock_guard<std::recursive_mutex> lock_guard;
friend class timer_core;
timer_driver()
{}
public:
static timer_driver& instance()
{
static timer_driver obj;
return obj;
}
template<typename Factory>
timer_core* create(unsigned ms, Factory && factory)
{
#if defined(NANA_WINDOWS)
auto tmid = ::SetTimer(nullptr, 0, ms, &timer_driver::_m_timer_proc);
#endif
try
{
#if defined(NANA_WINDOWS)
auto p = factory(tmid);
#else
auto p = factory();
auto tmid = p;
::nana::detail::platform_spec::instance().set_timer(reinterpret_cast<std::size_t>(tmid), ms, &timer_driver::_m_timer_proc);
#endif
lock_guard lock(mutex_);
timer_table_[tmid].reset(p);
return p;
}
catch (...)
{
}
return nullptr;
}
void destroy(timer_identifier tid)
{
lock_guard lock(mutex_);
auto i = timer_table_.find(tid);
if (i != timer_table_.end())
{
#if defined(NANA_WINDOWS)
::KillTimer(nullptr, tid);
#else
::nana::detail::platform_spec::instance().kill_timer(reinterpret_cast<std::size_t>(tid));
#endif
timer_table_.erase(i);
}
}
private:
#if defined(NANA_WINDOWS)
static void __stdcall _m_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime);
#else
static void _m_timer_proc(std::size_t id);
#endif
private:
std::recursive_mutex mutex_;
std::map<timer_identifier, std::unique_ptr<timer_core>> timer_table_;
};
class timer_core
{
public:
#if defined(NANA_WINDOWS)
timer_core(timer_identifier tmid, const nana::basic_event<arg_elapse>& evt_elapse)
: timer_(tmid), evt_elapse_(evt_elapse)
{}
#else
timer_core(const nana::basic_event<arg_elapse>& evt_elapse)
: timer_(this), evt_elapse_(evt_elapse)
{}
#endif
timer_identifier id() const
{
return timer_;
}
void interval(unsigned ms)
{
#if defined(NANA_WINDOWS)
::SetTimer(nullptr, timer_, ms, &timer_driver::_m_timer_proc);
#else
::nana::detail::platform_spec::instance().set_timer(reinterpret_cast<std::size_t>(timer_), ms, &timer_driver::_m_timer_proc);
#endif
}
void emit(const arg_elapse& arg)
{
evt_elapse_.emit(arg);
}
private:
const timer_identifier timer_;
const nana::basic_event<arg_elapse> & evt_elapse_;
}; //end class timer_core
#if defined(NANA_WINDOWS)
void __stdcall timer_driver::_m_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
#else
void timer_driver::_m_timer_proc(std::size_t id)
#endif
{
auto & driver = instance();
lock_guard lock(driver.mutex_);
#if defined(NANA_WINDOWS)
auto i = driver.timer_table_.find(id);
#else
auto i = driver.timer_table_.find(reinterpret_cast<timer_identifier>(id));
#endif
if (i == driver.timer_table_.end())
return;
arg_elapse arg;
arg.id = id;
i->second->emit(arg);
}
struct timer::implement
{
unsigned interval = 1000; //Defaultly 1 second.
timer_core * tm_core = nullptr;
};
//class timer
timer::timer()
: impl_(new implement)
{
}
timer::~timer()
{
if (impl_->tm_core)
timer_driver::instance().destroy(impl_->tm_core->id());
delete impl_;
}
void timer::reset()
{
stop();
elapse_.clear();
}
void timer::start()
{
if (impl_->tm_core)
return;
#if defined(NANA_WINDOWS)
impl_->tm_core = timer_driver::instance().create(impl_->interval, [this](timer_identifier id)
{
return new timer_core(id, elapse_);
});
#else
impl_->tm_core = timer_driver::instance().create(impl_->interval, [this]
{
return new timer_core(elapse_);
});
#endif
}
bool timer::started() const
{
return (nullptr != impl_->tm_core);
}
void timer::stop()
{
if (nullptr == impl_->tm_core)
return;
auto tmid = impl_->tm_core->id();
impl_->tm_core = nullptr;
timer_driver::instance().destroy(tmid);
}
void timer::interval(unsigned ms)
{
if (ms != impl_->interval)
{
impl_->interval = ms;
if (impl_->tm_core)
impl_->tm_core->interval(ms);
}
}
unsigned timer::interval() const
{
return impl_->interval;
}
//end class timer
}//end namespace nana

355
source/gui/tooltip.cpp Normal file
View File

@@ -0,0 +1,355 @@
/*
* A Tooltip 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/tooltip.cpp
*/
#include <nana/gui/tooltip.hpp>
#include <nana/gui/widgets/label.hpp>
#include <nana/gui/timer.hpp>
#include <memory>
namespace nana
{
namespace drawerbase
{
namespace tooltip
{
class drawer
: public drawer_trigger
{
private:
void refresh(graph_reference graph)
{
graph.rectangle(0x0, false);
graph.rectangle(1, 1, graph.width() - 2, graph.height() - 2, 0xF0F0F0, true);
}
};
nana::point pos_by_screen(nana::point pos, const nana::size& sz, bool overlap_allowed)
{
auto scr_area = API::screen_area_from_point(pos);
if (pos.x + sz.width > scr_area.x + scr_area.width)
pos.x = static_cast<int>(scr_area.x + scr_area.width - sz.width);
if (pos.x < scr_area.x)
pos.x = scr_area.x;
if (pos.y + sz.height >= scr_area.y + scr_area.height)
pos.y = static_cast<int>(scr_area.y + scr_area.height - sz.height);
else if (!overlap_allowed)
pos.y += 20; //Add some pixels to avoid overlapping between cursor and tip window.
if (pos.y < scr_area.y)
pos.y = scr_area.y;
return pos;
}
class tip_form
: public widget_object<category::root_tag, drawer>,
public tooltip_interface
{
typedef widget_object<category::root_tag, drawer> base_type;
public:
tip_form()
: base_type(nana::rectangle(), appear::bald<appear::floating>()),
duration_(0)
{
API::take_active(this->handle(), false, nullptr);
label_.create(*this);
label_.format(true);
label_.transparent(true);
}
private:
//tooltip_interface implementation
bool tooltip_empty() const override
{
return this->empty();
}
void tooltip_text(const nana::string& text) override
{
label_.caption(text);
auto text_s = label_.measure(API::screen_size().width * 2 / 3);
this->size(nana::size{ text_s.width + 10, text_s.height + 10 });
label_.move(rectangle{ 5, 5, text_s.width, text_s.height });
timer_.reset();
if (duration_)
{
timer_.interval(static_cast<unsigned>(duration_));
timer_.elapse(std::bind(&tip_form::_m_tick_duration, this));
}
else
{
timer_.interval(500);
timer_.elapse(std::bind(&tip_form::_m_tick, this));
}
timer_.start();
}
virtual nana::size tooltip_size() const override
{
return this->size();
}
virtual void tooltip_move(const nana::point& scr_pos, bool ignore_pos) override
{
ignore_pos_ = ignore_pos;
pos_ = scr_pos;
if (duration_)
{
this->move(scr_pos.x, scr_pos.y);
this->show();
}
}
virtual void duration(std::size_t d) override
{
duration_ = d;
timer_.reset();
}
private:
void _m_tick()
{
nana::point pos;
if (ignore_pos_)
{
pos = API::cursor_position();
//The cursor must be stay here for half second.
if (pos != pos_)
{
pos_ = pos;
return;
}
pos = pos_by_screen(pos, size(), false);
}
else
pos = pos_;
timer_.stop();
move(pos.x, pos.y);
show();
}
void _m_tick_duration()
{
timer_.reset();
this->close();
}
private:
timer timer_;
nana::label label_;
nana::point pos_;
bool ignore_pos_;
std::size_t duration_;
};//end class tip_form
class controller
{
typedef std::pair<window, nana::string> pair_t;
typedef std::function<void(tooltip_interface*)> deleter_type;
class tip_form_factory
: public nana::tooltip::factory_if_type
{
tooltip_interface * create() override
{
return new tip_form;
}
void destroy(tooltip_interface* p) override
{
delete p;
}
};
public:
static std::shared_ptr<nana::tooltip::factory_if_type>& factory()
{
static std::shared_ptr<nana::tooltip::factory_if_type> fp;
if (nullptr == fp)
fp = std::make_shared<tip_form_factory>();
return fp;
}
//external synchronization.
static controller* instance(bool destroy = false)
{
static controller* ptr;
if(destroy)
{
delete ptr;
ptr = nullptr;
}
else if(nullptr == ptr)
{
ptr = new controller;
}
return ptr;
}
void set(window wd, const nana::string& str)
{
if (str.empty())
_m_untip(wd);
else
_m_get(wd).second = str;
}
void show(const nana::string& text)
{
if (nullptr == window_ || window_->tooltip_empty())
{
auto fp = factory();
window_ = std::unique_ptr<tooltip_interface, deleter_type>(fp->create(), [fp](tooltip_interface* ti)
{
fp->destroy(ti);
});
}
window_->duration(0);
window_->tooltip_text(text);
window_->tooltip_move(API::cursor_position(), true);
}
void show_duration(window wd, point pos, const nana::string& text, std::size_t duration)
{
if (nullptr == window_ || window_->tooltip_empty())
{
auto fp = factory();
window_ = std::unique_ptr<tooltip_interface, deleter_type>(fp->create(), [fp](tooltip_interface* ti)
{
fp->destroy(ti);
});
}
window_->duration(duration);
window_->tooltip_text(text);
pos = pos_by_screen(pos, window_->tooltip_size(), true);
window_->tooltip_move(pos, false);
}
void close()
{
window_.reset();
//Destroy the tooltip controller when there are not tooltips.
if (cont_.empty())
instance(true);
}
private:
void _m_enter(const arg_mouse& arg)
{
pair_t & pr = _m_get(arg.window_handle);
if(pr.second.size())
{
this->show(pr.second);
}
}
void _m_leave(const arg_mouse&)
{
close();
}
void _m_destroy(const arg_destroy& arg)
{
_m_untip(arg.window_handle);
}
void _m_untip(window wd)
{
for (auto i = cont_.begin(); i != cont_.end(); ++i)
{
if (i->first == wd)
{
cont_.erase(i);
if (cont_.empty())
{
window_.reset();
instance(true);
}
return;
}
}
}
private:
pair_t& _m_get(window wd)
{
for (auto & pr : cont_)
{
if (pr.first == wd)
return pr;
}
auto & events = API::events(wd);
events.mouse_enter.connect([this](const arg_mouse& arg){
_m_enter(arg);
});
auto leave_fn = std::bind(&controller::_m_leave, this, std::placeholders::_1);
events.mouse_leave.connect(leave_fn);
events.mouse_down.connect(leave_fn);
events.destroy.connect([this](const arg_destroy& arg){
_m_destroy(arg);
});
cont_.emplace_back(wd, nana::string());
return cont_.back();
}
private:
std::unique_ptr<tooltip_interface, deleter_type> window_;
std::vector<pair_t> cont_;
};
}//namespace tooltip
}//namespace drawerbase
//class tooltip
typedef drawerbase::tooltip::controller ctrl;
void tooltip::set(window wd, const nana::string& text)
{
if(false == API::empty_window(wd))
{
internal_scope_guard lock;
ctrl::instance()->set(wd, text);
}
}
void tooltip::show(window wd, point pos, const nana::string& text, std::size_t duration)
{
internal_scope_guard lock;
API::calc_screen_point(wd, pos);
ctrl::instance()->show_duration(wd, pos, text, duration);
}
void tooltip::close()
{
internal_scope_guard lock;
ctrl::instance()->close();
}
void tooltip::_m_hold_factory(factory_interface* p)
{
ctrl::factory().reset(p);
}
//end class tooltip
}//namespace nana

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

22
source/gui/wvl.cpp Normal file
View File

@@ -0,0 +1,22 @@
/*
* Nana GUI Library Definition
* 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/wvl.cpp
* @description:
* the file contains the files required for running of Nana.GUI
*/
#include <nana/gui/wvl.hpp>
namespace nana
{
void exec()
{
detail::bedrock::instance().pump_event(nullptr, false);
}
}//end namespace nana