From 1b29f1987b8891852a606afbb03e5e08b16c8c3e Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sun, 2 Dec 2012 11:44:11 +0200 Subject: [PATCH] Move all child widget handling into Container This solves some problems like the slider of a list not receiving pointer enter/leave events. There are no obvious downsides either. Widgets can always override event handlers if they want to prevent something from happening. The event handlers are currently just combinations of those of the Panel and Container classes. They'll be smoothed out shortly. --- source/container.cpp | 185 +++++++++++++++++++++++++++++++++++----- source/container.h | 18 ++++ source/panel.cpp | 196 +------------------------------------------ source/panel.h | 35 -------- 4 files changed, 184 insertions(+), 250 deletions(-) diff --git a/source/container.cpp b/source/container.cpp index bec2066..fade54e 100644 --- a/source/container.cpp +++ b/source/container.cpp @@ -12,7 +12,10 @@ hierarchy_error::hierarchy_error(const string &w): Container::Container(): click_focus(0), - click_button(0) + click_button(0), + pointer_focus(0), + pointer_grabbed(false), + input_focus(0) { } Container::~Container() @@ -78,29 +81,100 @@ Widget *Container::get_descendant_at(int x, int y) return wdg; } +void Container::raise(Widget &wdg) +{ + for(list::iterator i=children.begin(); i!=children.end(); ++i) + if((*i)->widget==&wdg) + { + children.splice(children.end(), children, i); + return; + } + + throw hierarchy_error("widget not in container"); +} + +void Container::set_pointer_focus(Widget *wdg) +{ + if(wdg!=pointer_focus) + { + if(pointer_focus) + pointer_focus->pointer_leave(); + + pointer_focus = wdg; + + if(pointer_focus) + pointer_focus->pointer_enter(); + } +} + +void Container::set_input_focus(Widget *wdg) +{ + if(wdg!=input_focus) + { + if(input_focus) + input_focus->focus_out(); + + input_focus = wdg; + + if(input_focus) + { + raise(*wdg); + input_focus->focus_in(); + } + } +} + +Widget *Container::get_final_input_focus() const +{ + if(Container *container = dynamic_cast(input_focus)) + if(Widget *focus = container->get_final_input_focus()) + return focus; + + return input_focus; +} + void Container::button_press(int x, int y, unsigned btn) { - if(click_focus) + if(pointer_grabbed) { - const Geometry &cgeom = click_focus->get_geometry(); - click_focus->button_press(x-cgeom.x, y-cgeom.y, btn); + const Geometry &cgeom = pointer_focus->get_geometry(); + pointer_focus->button_press(x-cgeom.x, y-cgeom.y, btn); } else { if(Widget *wdg = get_child_at(x, y)) { - click_focus = wdg; - click_button = btn; + set_pointer_focus(wdg); + if(wdg->is_focusable()) + set_input_focus(wdg); + } + if(click_focus) + { + const Geometry &cgeom = click_focus->get_geometry(); + click_focus->button_press(x-cgeom.x, y-cgeom.y, btn); + } + else + { + if(Widget *wdg = get_child_at(x, y)) + { + click_focus = wdg; + click_button = btn; - const Geometry &cgeom = wdg->get_geometry(); - wdg->button_press(x-cgeom.x, y-cgeom.y, btn); + const Geometry &cgeom = wdg->get_geometry(); + wdg->button_press(x-cgeom.x, y-cgeom.y, btn); + } } } } void Container::button_release(int x, int y, unsigned btn) { - if(click_focus) + if(pointer_grabbed) + { + const Geometry &cgeom = pointer_focus->get_geometry(); + pointer_focus->button_release(x-cgeom.x, y-cgeom.y, btn); + } + else if(click_focus) { Widget *wdg = click_focus; @@ -122,18 +196,27 @@ void Container::button_release(int x, int y, unsigned btn) void Container::pointer_motion(int x, int y) { - if(click_focus) + if(pointer_grabbed) { - const Geometry &cgeom = click_focus->get_geometry(); - click_focus->pointer_motion(x-cgeom.x, y-cgeom.y); + const Geometry &cgeom = pointer_focus->get_geometry(); + pointer_focus->pointer_motion(x-cgeom.x, y-cgeom.y); } else { - Widget *wdg = get_child_at(x, y); - if(wdg) + set_pointer_focus(get_child_at(x, y)); + if(click_focus) { - const Geometry &cgeom = wdg->get_geometry(); - wdg->pointer_motion(x-cgeom.x, y-cgeom.y); + const Geometry &cgeom = click_focus->get_geometry(); + click_focus->pointer_motion(x-cgeom.x, y-cgeom.y); + } + else + { + Widget *wdg = get_child_at(x, y); + if(wdg) + { + const Geometry &cgeom = wdg->get_geometry(); + wdg->pointer_motion(x-cgeom.x, y-cgeom.y); + } } } } @@ -142,6 +225,31 @@ void Container::pointer_leave() { Widget::pointer_leave(); click_focus = 0; + set_pointer_focus(0); +} + +void Container::key_press(unsigned key, unsigned mod) +{ + if(input_focus) + input_focus->key_press(key, mod); +} + +void Container::key_release(unsigned key, unsigned mod) +{ + if(input_focus) + input_focus->key_release(key, mod); +} + +void Container::character(wchar_t ch) +{ + if(input_focus) + input_focus->character(ch); +} + +void Container::focus_out() +{ + set_input_focus(0); + Widget::focus_out(); } void Container::on_reparent() @@ -160,18 +268,55 @@ Container::Child::Child(Container &c, Widget *w): widget(w) { widget->signal_visibility_changed.connect(sigc::mem_fun(this, &Child::visibility_changed)); + widget->signal_request_focus.connect(sigc::mem_fun(this, &Child::request_focus)); + widget->signal_grab_pointer.connect(sigc::mem_fun(this, &Child::grab_pointer)); + widget->signal_ungrab_pointer.connect(sigc::mem_fun(this, &Child::ungrab_pointer)); } Container::Child::~Child() { - if(widget==container.click_focus) - container.click_focus = 0; + visibility_changed(false); } void Container::Child::visibility_changed(bool v) { - if(!v && widget==container.click_focus) - container.click_focus = 0; + if(!v) + { + if(widget==container.click_focus) + container.click_focus = 0; + if(widget==container.pointer_focus) + container.set_pointer_focus(0); + if(widget==container.input_focus) + container.set_input_focus(0); + } +} + +void Container::Child::request_focus() +{ + container.set_input_focus(widget); + if(container.parent && container.visible) + container.set_focus(); +} + +void Container::Child::grab_pointer() +{ + if(!container.pointer_grabbed) + { + container.set_pointer_focus(widget); + container.pointer_grabbed = true; + container.signal_grab_pointer.emit(); + } +} + +void Container::Child::ungrab_pointer() +{ + if(container.pointer_grabbed && container.pointer_focus==widget) + { + // XXX Should set to the widget under pointer + container.set_pointer_focus(0); + container.pointer_grabbed = false; + container.signal_ungrab_pointer.emit(); + } } } // namespace GLtk diff --git a/source/container.h b/source/container.h index d1120cd..bca1c59 100644 --- a/source/container.h +++ b/source/container.h @@ -29,11 +29,17 @@ protected: virtual ~Child(); void visibility_changed(bool); + void request_focus(); + void grab_pointer(); + void ungrab_pointer(); }; std::list children; Widget *click_focus; unsigned click_button; + Widget *pointer_focus; + bool pointer_grabbed; + Widget *input_focus; Container(); public: @@ -47,11 +53,23 @@ public: std::list get_children() const; Widget *get_child_at(int, int); Widget *get_descendant_at(int, int); + void raise(Widget &); + +protected: + void set_pointer_focus(Widget *); + void set_input_focus(Widget *); +public: + Widget *get_input_focus() const { return input_focus; } + Widget *get_final_input_focus() const; virtual void button_press(int, int, unsigned); virtual void button_release(int, int, unsigned); virtual void pointer_motion(int, int); virtual void pointer_leave(); + virtual void key_press(unsigned, unsigned); + virtual void key_release(unsigned, unsigned); + virtual void character(wchar_t); + virtual void focus_out(); protected: virtual void on_reparent(); virtual void on_child_added(Widget &) { } diff --git a/source/panel.cpp b/source/panel.cpp index 11d90e4..c7b1574 100644 --- a/source/panel.cpp +++ b/source/panel.cpp @@ -20,10 +20,7 @@ namespace Msp { namespace GLtk { Panel::Panel(): - layout(0), - pointer_focus(0), - pointer_grabbed(false), - input_focus(0) + layout(0) { } Panel::~Panel() @@ -45,34 +42,6 @@ void Panel::autosize() layout->autosize(); } -Panel::Child *Panel::create_child(Widget *wdg) -{ - return new Child(*this, wdg); -} - -void Panel::raise(Widget &wdg) -{ - for(list::iterator i=children.begin(); i!=children.end(); ++i) - if((*i)->widget==&wdg) - { - children.splice(children.end(), children, i); - return; - } - - throw hierarchy_error("widget not in panel"); -} - -Widget *Panel::get_final_input_focus() const -{ - if(Panel *panel = dynamic_cast(input_focus)) - { - Widget *focus = panel->get_final_input_focus(); - if(focus) - return focus; - } - return input_focus; -} - void Panel::render_special(const Part &part, GL::Renderer &renderer) const { if(part.get_name()=="children") @@ -83,80 +52,6 @@ void Panel::render_special(const Part &part, GL::Renderer &renderer) const } } -void Panel::button_press(int x, int y, unsigned btn) -{ - if(pointer_grabbed) - { - const Geometry &cgeom = pointer_focus->get_geometry(); - pointer_focus->button_press(x-cgeom.x, y-cgeom.y, btn); - } - else - { - if(Widget *wdg = get_child_at(x, y)) - { - set_pointer_focus(wdg); - if(wdg->is_focusable()) - set_input_focus(wdg); - } - Container::button_press(x, y, btn); - } -} - -void Panel::button_release(int x, int y, unsigned btn) -{ - if(pointer_grabbed) - { - const Geometry &cgeom = pointer_focus->get_geometry(); - pointer_focus->button_release(x-cgeom.x, y-cgeom.y, btn); - } - else - Container::button_release(x, y, btn); -} - -void Panel::pointer_motion(int x, int y) -{ - if(pointer_grabbed) - { - const Geometry &cgeom = pointer_focus->get_geometry(); - pointer_focus->pointer_motion(x-cgeom.x, y-cgeom.y); - } - else - { - set_pointer_focus(get_child_at(x, y)); - Container::pointer_motion(x, y); - } -} - -void Panel::pointer_leave() -{ - Container::pointer_leave(); - set_pointer_focus(0); -} - -void Panel::key_press(unsigned key, unsigned mod) -{ - if(input_focus) - input_focus->key_press(key, mod); -} - -void Panel::key_release(unsigned key, unsigned mod) -{ - if(input_focus) - input_focus->key_release(key, mod); -} - -void Panel::character(wchar_t ch) -{ - if(input_focus) - input_focus->character(ch); -} - -void Panel::focus_out() -{ - set_input_focus(0); - Widget::focus_out(); -} - void Panel::on_geometry_change() { if(layout) @@ -181,37 +76,6 @@ void Panel::on_child_removed(Widget &wdg) } } -void Panel::set_pointer_focus(Widget *wdg) -{ - if(wdg!=pointer_focus) - { - if(pointer_focus) - pointer_focus->pointer_leave(); - - pointer_focus = wdg; - - if(pointer_focus) - pointer_focus->pointer_enter(); - } -} - -void Panel::set_input_focus(Widget *wdg) -{ - if(wdg!=input_focus) - { - if(input_focus) - input_focus->focus_out(); - - input_focus = wdg; - - if(input_focus) - { - raise(*wdg); - input_focus->focus_in(); - } - } -} - Panel::Loader::Loader(Panel &p, map &m): Widget::Loader(p), @@ -248,63 +112,5 @@ void Panel::Loader::panel(const string &n) wdg_map[n] = p.release(); } - -Panel::Child::Child(Panel &p, Widget *w): - Container::Child(p, w) -{ - widget->signal_visibility_changed.connect(sigc::mem_fun(this, &Child::visibility_changed)); - widget->signal_request_focus.connect(sigc::mem_fun(this, &Child::request_focus)); - widget->signal_grab_pointer.connect(sigc::mem_fun(this, &Child::grab_pointer)); - widget->signal_ungrab_pointer.connect(sigc::mem_fun(this, &Child::ungrab_pointer)); -} - -Panel::Child::~Child() -{ - visibility_changed(false); -} - -void Panel::Child::visibility_changed(bool v) -{ - if(!v) - { - Panel &panel = static_cast(container); - if(widget==panel.pointer_focus) - panel.set_pointer_focus(0); - if(widget==panel.input_focus) - panel.set_input_focus(0); - } -} - -void Panel::Child::request_focus() -{ - Panel &panel = static_cast(container); - panel.set_input_focus(widget); - if(panel.parent && panel.visible) - panel.set_focus(); -} - -void Panel::Child::grab_pointer() -{ - Panel &panel = static_cast(container); - if(!panel.pointer_grabbed) - { - panel.set_pointer_focus(widget); - panel.pointer_grabbed = true; - panel.signal_grab_pointer.emit(); - } -} - -void Panel::Child::ungrab_pointer() -{ - Panel &panel = static_cast(container); - if(panel.pointer_grabbed && panel.pointer_focus==widget) - { - // XXX Should set to the widget under pointer - panel.set_pointer_focus(0); - panel.pointer_grabbed = false; - panel.signal_ungrab_pointer.emit(); - } -} - } // namespace GLtk } // namespace Msp diff --git a/source/panel.h b/source/panel.h index 170364d..c50725b 100644 --- a/source/panel.h +++ b/source/panel.h @@ -34,21 +34,7 @@ public: }; protected: - struct Child: public Container::Child - { - Child(Panel &, Widget *); - virtual ~Child(); - - void visibility_changed(bool); - void request_focus(); - void grab_pointer(); - void ungrab_pointer(); - }; - Layout *layout; - Widget *pointer_focus; - bool pointer_grabbed; - Widget *input_focus; Panel(const Panel &); Panel &operator=(const Panel &); @@ -61,33 +47,12 @@ public: void set_layout(Layout *); virtual void autosize(); -protected: - virtual Child *create_child(Widget *); - -public: - void raise(Widget &); - Widget *get_input_focus() const { return input_focus; } - Widget *get_final_input_focus() const; - protected: virtual void render_special(const Part &, GL::Renderer &) const; -public: - virtual void button_press(int, int, unsigned); - virtual void button_release(int, int, unsigned); - virtual void pointer_motion(int, int); - virtual void pointer_leave(); - virtual void key_press(unsigned, unsigned); - virtual void key_release(unsigned, unsigned); - virtual void character(wchar_t); - virtual void focus_out(); -protected: virtual void on_geometry_change(); virtual void on_child_added(Widget &); virtual void on_child_removed(Widget &); - - void set_pointer_focus(Widget *); - void set_input_focus(Widget *); }; } // namespace GLtk -- 2.43.0