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