From 95210598ff214bbc8d05657aeffc4ce7801f211a Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 29 Dec 2007 08:44:09 +0000 Subject: [PATCH] Add Dropdown widget Allow widgets to grab the pointer Support raising widgets Fix Button and Toggle logic a bit Bugfixes --- source/button.cpp | 10 +++- source/dropdown.cpp | 120 ++++++++++++++++++++++++++++++++++++++++++++ source/dropdown.h | 51 +++++++++++++++++++ source/list.cpp | 5 ++ source/list.h | 2 + source/panel.cpp | 28 +++++++++++ source/panel.h | 5 ++ source/toggle.cpp | 26 ++++++++-- source/toggle.h | 5 ++ 9 files changed, 247 insertions(+), 5 deletions(-) create mode 100644 source/dropdown.cpp create mode 100644 source/dropdown.h diff --git a/source/button.cpp b/source/button.cpp index bc6fd27..3661c01 100644 --- a/source/button.cpp +++ b/source/button.cpp @@ -12,7 +12,8 @@ namespace Msp { namespace GLtk { Button::Button(const Resources &r, const std::string &t): - Widget(r) + Widget(r), + pressed(false) { set_text(t); update_style(); @@ -26,12 +27,15 @@ void Button::set_text(const std::string &t) void Button::button_press(int, int, unsigned btn) { if(btn==1) + { + pressed=true; state=ACTIVE; + } } void Button::button_release(int x, int y, unsigned btn) { - if(btn==1) + if(pressed && btn==1) { if(geom.is_inside_relative(x, y)) { @@ -40,6 +44,8 @@ void Button::button_release(int x, int y, unsigned btn) } else state=NORMAL; + + pressed=false; } } diff --git a/source/dropdown.cpp b/source/dropdown.cpp new file mode 100644 index 0000000..bc44f27 --- /dev/null +++ b/source/dropdown.cpp @@ -0,0 +1,120 @@ +/* $Id$ + +This file is part of libmspgltk +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include "dropdown.h" +#include "list.h" +#include "panel.h" +#include "part.h" + +using namespace std; + +namespace Msp { +namespace GLtk { + +Dropdown::Dropdown(const Resources &r): + Widget(r), + list(new List(res)), + list_active(false) +{ + list->signal_item_selected.connect(sigc::mem_fun(this, &Dropdown::list_item_selected)); + + update_style(); +} + +Dropdown::~Dropdown() +{ + delete list; +} + +void Dropdown::append(const string &item) +{ + list->append(item); +} + +void Dropdown::button_press(int x, int y, unsigned btn) +{ + if(list->get_geometry().is_inside(x, y)) + { + const Geometry &lgeom=list->get_geometry(); + list->button_press(x-lgeom.x, y-lgeom.y, btn); + list_active=true; + } + else if(state==ACTIVE) + { + state=HOVER; + parent->ungrab_pointer(*this); + } + else if(btn==1) + { + state=ACTIVE; + + if(parent) + { + parent->raise(*this); + parent->grab_pointer(*this); + } + } +} + +void Dropdown::button_release(int x, int y, unsigned btn) +{ + if(list_active) + { + const Geometry &lgeom=list->get_geometry(); + list->button_release(x-lgeom.x, y-lgeom.y, btn); + list_active=false; + } +} + +void Dropdown::pointer_motion(int x, int y) +{ + if(list_active) + { + const Geometry &lgeom=list->get_geometry(); + list->pointer_motion(x-lgeom.x, y-lgeom.y); + } +} + +void Dropdown::pointer_enter() +{ + if(state==NORMAL) + state=HOVER; +} + +void Dropdown::pointer_leave() +{ + if(state==HOVER) + state=NORMAL; +} + +void Dropdown::render_special(const Part &part) const +{ + if(part.get_name()=="text") + render_text(part, text); + else if(part.get_name()=="list" && state==ACTIVE) + list->render(); +} + +void Dropdown::on_geometry_change() +{ + list->set_geometry(Geometry(0, -100, geom.w, 100)); +} + +void Dropdown::list_item_selected(unsigned index, const std::string &item) +{ + text=item; + + list_active=false; + state=NORMAL; + if(parent) + parent->ungrab_pointer(*this); + + signal_item_selected.emit(index, item); +} + +} // namespace GLtk +} // namespace Msp diff --git a/source/dropdown.h b/source/dropdown.h new file mode 100644 index 0000000..825b800 --- /dev/null +++ b/source/dropdown.h @@ -0,0 +1,51 @@ +/* $Id$ + +This file is part of libmspgltk +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GLTK_DROPDOWN_H_ +#define MSP_GLTK_DROPDOWN_H_ + +#include +#include "widget.h" + +namespace Msp { +namespace GLtk { + +class List; + +class Dropdown: public Widget +{ +private: + List *list; + std::string text; + bool list_active; + +public: + sigc::signal signal_item_selected; + + Dropdown(const Resources &); + ~Dropdown(); + + void append(const std::string &); + + virtual void button_press(int, int, unsigned); + virtual void button_release(int, int, unsigned); + virtual void pointer_motion(int, int); + virtual void pointer_enter(); + virtual void pointer_leave(); +private: + virtual const char *get_class() const { return "dropdown"; } + virtual void render_special(const Part &) const; + + virtual void on_geometry_change(); + + void list_item_selected(unsigned, const std::string &); +}; + +} // namespace GLtk +} // namespace Msp + +#endif diff --git a/source/list.cpp b/source/list.cpp index 73f427b..4f8b27c 100644 --- a/source/list.cpp +++ b/source/list.cpp @@ -33,6 +33,11 @@ List::List(const Resources &r): update_style(); } +List::~List() +{ + delete slider; +} + void List::append(const string &v) { items.push_back(v); diff --git a/source/list.h b/source/list.h index edcec33..77d7e9f 100644 --- a/source/list.h +++ b/source/list.h @@ -46,6 +46,8 @@ public: sigc::signal signal_item_selected; List(const Resources &); + ~List(); + void append(const std::string &); void insert(unsigned, const std::string &); void remove(unsigned); diff --git a/source/panel.cpp b/source/panel.cpp index 22ccb1b..f17439a 100644 --- a/source/panel.cpp +++ b/source/panel.cpp @@ -7,6 +7,7 @@ Distributed under the LGPL #include #include "button.h" +#include "dropdown.h" #include "entry.h" #include "hslider.h" #include "indicator.h" @@ -53,6 +54,16 @@ void Panel::remove(Widget &wdg) } } +void Panel::raise(Widget &wdg) +{ + ChildSeq::iterator i=find(children.begin(), children.end(), &wdg); + if(i!=children.end()) + { + children.erase(i); + children.push_back(&wdg); + } +} + void Panel::button_press(int x, int y, unsigned btn) { if(pointer_grab>0) @@ -140,6 +151,22 @@ void Panel::child_hidden(Widget &wdg) set_pointer_focus(0, 0); } +void Panel::grab_pointer(Widget &wdg) +{ + if(pointer_grab==0 || pointer_focus==&wdg) + set_pointer_focus(&wdg, 255); + else + throw InvalidState("Pointer is already grabbed"); +} + +void Panel::ungrab_pointer(Widget &wdg) +{ + if(pointer_focus==&wdg) + set_pointer_focus(0, 0); + else if(pointer_grab>0) + throw Exception("Someone is trying to steal the pointer!"); +} + void Panel::render_special(const Part &part) const { if(part.get_name()=="children") @@ -199,6 +226,7 @@ Panel::Loader::Loader(Panel &p, map &m): wdg_map(m) { add("button", &Loader::child