first init of 0.9
This commit is contained in:
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
Reference in New Issue
Block a user