384 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			384 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#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_);
 | 
						|
						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.right() > 0 && rect.bottom() > 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.right()) ||
 | 
						|
					(pos.y + static_cast<int>(size.height) <= rect.y) || (pos.y >= rect.bottom())
 | 
						|
					)
 | 
						|
				{//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 + static_cast<int>(size.width) > rect.right())
 | 
						|
					{
 | 
						|
						size.width -= pos.x + size.width - rect.right();
 | 
						|
					}
 | 
						|
 | 
						|
					if(pos.y < rect.y)
 | 
						|
					{
 | 
						|
						size.width -= (rect.y - pos.y);
 | 
						|
						pos.y = rect.y;
 | 
						|
					}
 | 
						|
					else if(pos.y + static_cast<int>(size.height) > rect.bottom())
 | 
						|
						size.height -= pos.y + size.height - rect.bottom();
 | 
						|
 | 
						|
					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);
 | 
						|
						real_visible_state_ = false;
 | 
						|
						if(visible_)
 | 
						|
							_m_visible(true);
 | 
						|
 | 
						|
						paint_size_ = size;
 | 
						|
					}
 | 
						|
				
 | 
						|
					native_interface::caret_pos(wd_->root, wd_->pos_root + pos);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		//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(nullptr, 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;
 | 
						|
			}
 | 
						|
 | 
						|
			bool basic_window::is_draw_through() const
 | 
						|
			{
 | 
						|
				if (::nana::category::flags::root == this->other.category)
 | 
						|
					return static_cast<bool>(other.attribute.root->draw_through);
 | 
						|
				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 += parent->pos_root;
 | 
						|
			}
 | 
						|
 | 
						|
			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.captured = 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;
 | 
						|
				flags.make_bground_declared = false;
 | 
						|
				flags.ignore_menubar_focus = false;
 | 
						|
 | 
						|
				visible = false;
 | 
						|
 | 
						|
				effect.edge_nimbus = effects::edge_nimbus::none;
 | 
						|
				effect.bground = nullptr;
 | 
						|
				effect.bground_fade_rate = 0;
 | 
						|
 | 
						|
				together.caret = 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.events_ptr)
 | 
						|
					return false;
 | 
						|
				together.events_ptr = p;
 | 
						|
				return true;
 | 
						|
			}
 | 
						|
 | 
						|
			general_events * basic_window::get_events() const
 | 
						|
			{
 | 
						|
				return together.events_ptr.get();
 | 
						|
			}
 | 
						|
		//end struct basic_window
 | 
						|
	}//end namespace detail
 | 
						|
}//end namespace nana
 |