From 0c3195ffb89c0af09998533c6d10c71212902676 Mon Sep 17 00:00:00 2001 From: Cary Sandvig Date: Tue, 31 Oct 2000 21:02:44 +0000 Subject: [PATCH] super early draft of Panda2d --- panda/src/gui/Sources.pp | 31 ++++++ panda/src/gui/config_gui.cxx | 14 +++ panda/src/gui/config_gui.h | 10 ++ panda/src/gui/guiButton.I | 155 ++++++++++++++++++++++++++ panda/src/gui/guiButton.cxx | 198 +++++++++++++++++++++++++++++++++ panda/src/gui/guiButton.h | 63 +++++++++++ panda/src/gui/guiLabel.I | 14 ++- panda/src/gui/guiLabel.cxx | 47 ++++++++ panda/src/gui/guiLabel.h | 27 +++++ panda/src/gui/guiManager.I | 7 +- panda/src/gui/guiManager.cxx | 96 +++++++++++++++- panda/src/gui/guiManager.h | 33 +++++- panda/src/gui/guiRegion.I | 17 ++- panda/src/gui/guiRegion.cxx | 3 + panda/src/gui/guiRegion.h | 20 +++- panda/src/gui/guiRollover.I | 30 ++++- panda/src/gui/guiRollover.cxx | 64 +++++++++++ panda/src/gui/guiRollover.h | 29 ++++- panda/src/testbed/Sources.pp | 9 ++ panda/src/testbed/gui_demo.cxx | 20 ++++ 20 files changed, 868 insertions(+), 19 deletions(-) diff --git a/panda/src/gui/Sources.pp b/panda/src/gui/Sources.pp index e69de29bb2..0341c12327 100644 --- a/panda/src/gui/Sources.pp +++ b/panda/src/gui/Sources.pp @@ -0,0 +1,31 @@ +#define OTHER_LIBS dtool + +#begin lib_target + #define TARGET gui + + #define LOCAL_LIBS \ + putil display tform device pandabase dgraph sgattrib light gobj text + + #define SOURCES \ + config_gui.h config_gui.cxx \ + guiManager.h guiManager.I guiManager.cxx \ + guiRegion.h guiRegion.I guiRegion.cxx \ + guiLabel.h guiLabel.I guiLabel.cxx \ + guiRollover.h guiRollover.I guiRollover.cxx \ + guiButton.h guiButton.I guiButton.cxx + + #define INSTALL_HEADERS \ + guiManager.h guiManager.I \ + guiRegion.h guiRegion.I \ + guiLabel.h guiLabel.I \ + guiRollover.h guiRollover.I \ + guiButton.h guiButton.I + + #define IGATESCAN \ + guiManager.h guiManager.I \ + guiRegion.h guiRegion.I \ + guiLabel.h guiLabel.I \ + guiRollover.h guiRollover.I \ + guiButton.h guiButton.I + +#end lib_target diff --git a/panda/src/gui/config_gui.cxx b/panda/src/gui/config_gui.cxx index e69de29bb2..a1fa659b2b 100644 --- a/panda/src/gui/config_gui.cxx +++ b/panda/src/gui/config_gui.cxx @@ -0,0 +1,14 @@ +// Filename: config_gui.cxx +// Created by: cary (26Oct00) +// +//////////////////////////////////////////////////////////////////// + +#include "config_gui.h" + +#include + +Configure(config_gui); +NotifyCategoryDef(gui, ""); + +ConfigureFn(config_gui) { +} diff --git a/panda/src/gui/config_gui.h b/panda/src/gui/config_gui.h index 8b5e8957b8..b3084a9994 100644 --- a/panda/src/gui/config_gui.h +++ b/panda/src/gui/config_gui.h @@ -2,3 +2,13 @@ // Created by: cary (26Oct00) // //////////////////////////////////////////////////////////////////// + +#ifndef __CONFIG_GUI_H__ +#define __CONFIG_GUI_H__ + +#include +#include + +NotifyCategoryDecl(gui, EXPCL_PANDA, EXPTP_PANDA); + +#endif /* __CONFIG_GUI_H__ */ diff --git a/panda/src/gui/guiButton.I b/panda/src/gui/guiButton.I index 8182bd118e..a4ffc0a0e8 100644 --- a/panda/src/gui/guiButton.I +++ b/panda/src/gui/guiButton.I @@ -2,3 +2,158 @@ // Created by: cary (30Oct00) // //////////////////////////////////////////////////////////////////// + +INLINE GuiButton::GuiButton(void) { +} + +INLINE void GuiButton::enter(void) { + switch (_state) { + case UP: + switch_state(UP_ROLLOVER); + break; + case DOWN: + switch_state(DOWN_ROLLOVER); + break; + case INACTIVE: + switch_state(INACTIVE_ROLLOVER); + break; + default: + break; + } +} + +INLINE void GuiButton::exit(void) { + switch (_state) { + case UP_ROLLOVER: + switch_state(UP); + break; + case DOWN_ROLLOVER: + switch_state(DOWN); + break; + case INACTIVE_ROLLOVER: + switch_state(INACTIVE); + break; + default: + break; + } +} + +INLINE void GuiButton::up(void) { + switch (_state) { + case DOWN: + switch_state(UP); + break; + case DOWN_ROLLOVER: + switch_state(UP_ROLLOVER); + break; + default: + gui_cat->warning() << "got up from invalid state (" << _state << ")" + << endl; + } +} + +INLINE void GuiButton::down(void) { + switch (_state) { + case UP: + switch_state(DOWN); + break; + case UP_ROLLOVER: + switch_state(DOWN_ROLLOVER); + break; + default: + gui_cat->warning() << "got down from invalid state (" << _state << ")" + << endl; + } +} + +INLINE void GuiButton::inactive(void) { + switch (_state) { + case UP: + case DOWN: + switch_state(INACTIVE); + break; + case UP_ROLLOVER: + case DOWN_ROLLOVER: + switch_state(INACTIVE_ROLLOVER); + break; + default: + gui_cat->warning() << "got inactive from invalid state (" << _state << ")" + << endl; + } +} + +INLINE void GuiButton::click(void) { + switch (_state) { + case UP: + case UP_ROLLOVER: + down(); + break; + case DOWN: + case DOWN_ROLLOVER: + up(); + break; + case INACTIVE: + break; + default: + gui_cat->warning() << "got click from invalid state (" << _state << ")" + << endl; + } +} + +INLINE bool GuiButton::is_up(void) const { + if ((_state == UP) || (_state == UP_ROLLOVER)) + return true; + return false; +} + +INLINE bool GuiButton::is_over(void) const { + if ((_state == UP_ROLLOVER) || (_state == DOWN_ROLLOVER)) + return true; + return false; +} + +INLINE bool GuiButton::is_active(void) const { + if ((_state == INACTIVE) || (_state == NONE)) + return false; + return true; +} + +INLINE void GuiButton::set_up_event(const string& s) { + _up_event = s; +} + +INLINE void GuiButton::set_up_rollover_event(const string& s) { + _up_rollover_event = s; +} + +INLINE void GuiButton::set_down_event(const string& s) { + _down_event = s; +} + +INLINE void GuiButton::set_down_rollover_event(const string& s) { + _down_rollover_event = s; +} + +INLINE void GuiButton::set_inactive_event(const string& s) { + _inactive_event = s; +} + +INLINE const string& GuiButton::get_up_event(void) const { + return _up_event; +} + +INLINE const string& GuiButton::get_up_rollover_event(void) const { + return _up_rollover_event; +} + +INLINE const string& GuiButton::get_down_event(void) const { + return _down_event; +} + +INLINE const string& GuiButton::get_down_rollover_event(void) const { + return _down_rollover_event; +} + +INLINE const string& GuiButton::get_inactive_event(void) const { + return _inactive_event; +} diff --git a/panda/src/gui/guiButton.cxx b/panda/src/gui/guiButton.cxx index e551a13c9c..455dc96914 100644 --- a/panda/src/gui/guiButton.cxx +++ b/panda/src/gui/guiButton.cxx @@ -2,3 +2,201 @@ // Created by: cary (30Oct00) // //////////////////////////////////////////////////////////////////// + +#include "guiButton.h" +#include "config_gui.h" + +#include + +#include + +typedef map ButtonMap; +static ButtonMap buttons; + +inline void GetExtents(GuiLabel* v, GuiLabel* w, GuiLabel* x, GuiLabel* y, + GuiLabel* z, float& l, float& r, float& b, float& t) { + float l1, l2, r1, r2, b1, b2, t1, t2; + v->get_extents(l1, r1, b1, t1); + w->get_extents(l2, r2, b2, t2); + l1 = (l1get_extents(l2, r2, b2, t2); + l1 = (l1get_extents(l2, r2, b2, t2); + l1 = (l1get_extents(l2, r2, b2, t2); + l = (l1get_name()]; + val->enter(); +} + +static void exit_button(CPT_Event e) { + GuiButton* val = buttons[e->get_name()]; + val->exit(); +} + +static void click_button(CPT_Event e) { + GuiButton* val = buttons[e->get_name()]; + val->click(); +} + +void GuiButton::switch_state(GuiButton::States nstate) { + // cleanup old state + switch (_state) { + case NONE: + break; + case UP: + _mgr->remove_label(_up); + break; + case UP_ROLLOVER: + _mgr->remove_label(_up_rollover); + break; + case DOWN: + _mgr->remove_label(_down); + break; + case DOWN_ROLLOVER: + _mgr->remove_label(_down_rollover); + break; + case INACTIVE: + if (_inactive != (GuiLabel*)0L) + _mgr->remove_label(_inactive); + break; + case INACTIVE_ROLLOVER: + if (_inactive != (GuiLabel*)0L) + _mgr->remove_label(_inactive); + break; + default: + gui_cat->warning() << "switching away from invalid state (" << _state + << ")" << endl; + } + _state = nstate; + // deal with new state + switch (_state) { + case NONE: + _rgn->trap_clicks(false); + break; + case UP: + _mgr->add_label(_up); + if (!_up_event.empty()) + throw_event(_up_event); + _rgn->trap_clicks(true); + break; + case UP_ROLLOVER: + if (_up_rollover != (GuiLabel*)0L) { + _mgr->add_label(_up_rollover); + if (!_up_rollover_event.empty()) + throw_event(_up_rollover_event); + } else { + _mgr->add_label(_up); + if (!_up_event.empty()) + throw_event(_up_event); + _state = UP; + } + _rgn->trap_clicks(true); + break; + case DOWN: + _mgr->add_label(_down); + if (!_down_event.empty()) + throw_event(_down_event); + _rgn->trap_clicks(true); + break; + case DOWN_ROLLOVER: + if (_down_rollover != (GuiLabel*)0L) { + _mgr->add_label(_down_rollover); + if (!_down_rollover_event.empty()) + throw_event(_down_rollover_event); + } else { + _mgr->add_label(_down); + if (!_down_event.empty()) + throw_event(_down_event); + _state = DOWN; + } + _rgn->trap_clicks(true); + break; + case INACTIVE: + if (_inactive != (GuiLabel*)0L) { + _mgr->add_label(_inactive); + if (!_inactive_event.empty()) + throw_event(_inactive_event); + } + _rgn->trap_clicks(false); + break; + case INACTIVE_ROLLOVER: + if (_inactive != (GuiLabel*)0L) { + _mgr->add_label(_inactive); + if (!_inactive_event.empty()) + throw_event(_inactive_event); + } + _rgn->trap_clicks(false); + break; + default: + gui_cat->warning() << "switched to invalid state (" << _state << ")" + << endl; + } +} + +GuiButton::GuiButton(const string& name, GuiLabel* up, GuiLabel* up_roll, + GuiLabel* down, GuiLabel* down_roll, GuiLabel* inactive) + : Namable(name), _up(up), _up_rollover(up_roll), _down(down), + _down_rollover(down_roll), _inactive(inactive), _state(GuiButton::NONE), + _added_hooks(false), _mgr((GuiManager*)0L), _up_event(name + "-up"), + _up_rollover_event(name + "-up-rollover"), _down_event(name +"-down"), + _down_rollover_event(name + "-down-rollover"), + _inactive_event(name + "-inactive") { + float left, right, bottom, top; + + GetExtents(up, down, up_roll, down_roll, inactive, left, right, bottom, top); + _rgn = new GuiRegion("button-" + name, left, right, bottom, top, true); + buttons["gui-in-button-" + name] = this; + buttons["gui-out-button-" + name] = this; + buttons["gui-button-" + name + "-mouse1"] = this; + buttons["gui-button-" + name + "-mouse2"] = this; + buttons["gui-button-" + name + "-mouse3"] = this; +} + +GuiButton::~GuiButton(void) { +} + +void GuiButton::manage(GuiManager* mgr, EventHandler& eh) { + if (!_added_hooks) { + eh.add_hook("gui-in-button-" + get_name(), enter_button); + eh.add_hook("gui-out-button-" + get_name(), exit_button); + eh.add_hook("gui-button-" + get_name() + "-mouse1", click_button); + eh.add_hook("gui-button-" + get_name() + "-mouse2", click_button); + eh.add_hook("gui-button-" + get_name() + "-mouse3", click_button); + _added_hooks = true; + } + if (_mgr == (GuiManager*)0L) { + mgr->add_region(_rgn); + _mgr = mgr; + switch_state(UP); + } else + gui_cat->warning() << "tried to manage button (0x" << (void*)this + << ") that is already managed" << endl; +} + +void GuiButton::unmanage(void) { + _mgr->remove_region(_rgn); + switch_state(NONE); + _mgr = (GuiManager*)0L; +} diff --git a/panda/src/gui/guiButton.h b/panda/src/gui/guiButton.h index 8f2149dbf0..fee0d51856 100644 --- a/panda/src/gui/guiButton.h +++ b/panda/src/gui/guiButton.h @@ -2,3 +2,66 @@ // Created by: cary (30Oct00) // //////////////////////////////////////////////////////////////////// + +#ifndef __GUIBUTTON_H__ +#define __GUIBUTTON_H__ + +#include "guiRegion.h" +#include "guiLabel.h" +#include "guiManager.h" + +#include + +class GuiButton : public Namable { +private: + GuiLabel* _up; + GuiLabel* _up_rollover; + GuiLabel* _down; + GuiLabel* _down_rollover; + GuiLabel* _inactive; + string _up_event, _up_rollover_event, _down_event, _down_rollover_event; + string _inactive_event; + GuiRegion* _rgn; + + enum States { NONE, UP, UP_ROLLOVER, DOWN, DOWN_ROLLOVER, INACTIVE, + INACTIVE_ROLLOVER }; + States _state; + bool _added_hooks; + GuiManager* _mgr; + + INLINE GuiButton(void); + void switch_state(States); +public: + GuiButton(const string&, GuiLabel*, GuiLabel*, GuiLabel*, GuiLabel*, + GuiLabel*); + ~GuiButton(void); + + void manage(GuiManager*, EventHandler&); + void unmanage(void); + INLINE void enter(void); + INLINE void exit(void); + INLINE void up(void); + INLINE void down(void); + INLINE void inactive(void); + INLINE void click(void); + + INLINE bool is_up(void) const; + INLINE bool is_over(void) const; + INLINE bool is_active(void) const; + + INLINE void set_up_event(const string&); + INLINE void set_up_rollover_event(const string&); + INLINE void set_down_event(const string&); + INLINE void set_down_rollover_event(const string&); + INLINE void set_inactive_event(const string&); + + INLINE const string& get_up_event(void) const; + INLINE const string& get_up_rollover_event(void) const; + INLINE const string& get_down_event(void) const; + INLINE const string& get_down_rollover_event(void) const; + INLINE const string& get_inactive_event(void) const; +}; + +#include "guiButton.I" + +#endif /* __GUIBUTTON_H__ */ diff --git a/panda/src/gui/guiLabel.I b/panda/src/gui/guiLabel.I index 4174a22e51..7e72514069 100644 --- a/panda/src/gui/guiLabel.I +++ b/panda/src/gui/guiLabel.I @@ -3,5 +3,17 @@ // //////////////////////////////////////////////////////////////////// -INLINE GuiLabel::GuiLabel(void) { +INLINE GuiLabel::GuiLabel(void) : _type(GuiLabel::NONE) { +} + +INLINE Node* GuiLabel::get_geometry(void) const { + return _geom; +} + +INLINE void GuiLabel::set_arc(RenderRelation* r) { + _arc = r; +} + +INLINE RenderRelation* GuiLabel::get_arc(void) const { + return _arc; } diff --git a/panda/src/gui/guiLabel.cxx b/panda/src/gui/guiLabel.cxx index 8ba7a7a0b7..77daefbfde 100644 --- a/panda/src/gui/guiLabel.cxx +++ b/panda/src/gui/guiLabel.cxx @@ -4,3 +4,50 @@ //////////////////////////////////////////////////////////////////// #include "guiLabel.h" + +GuiLabel::~GuiLabel(void) { +} + +GuiLabel* GuiLabel::make_simple_texture_label(void) { + return new GuiLabel(); +} + +#include + +GuiLabel* GuiLabel::make_simple_text_label(const string& text, Node* font) { + GuiLabel* ret = new GuiLabel(); + ret->_type = SIMPLE_TEXT; + TextNode* n = new TextNode("GUI label"); + ret->_geom = n; + LMatrix4f mat = LMatrix4f::scale_mat(0.1); + n->set_transform(mat); + n->set_font(font); + // n->set_card_color(1., 1., 1., 0.); + n->set_align(TM_ALIGN_CENTER); + n->set_text_color(1., 1., 1., 1.); + n->set_text(text); + return ret; +} + +void GuiLabel::get_extents(float& l, float& r, float& b, float& t) { + switch (_type) { + case SIMPLE_TEXT: + { + TextNode* n = DCAST(TextNode, _geom); + LVector3f ul = n->get_upper_left_3d() - LPoint3f::origin(); + LVector3f lr = n->get_lower_right_3d() - LPoint3f::origin(); + LVector3f up = LVector3f::up(); + LVector3f right = LVector3f::right(); + l = ul.dot(right); + r = lr.dot(right); + b = lr.dot(up); + t = ul.dot(up); + } + break; + default: + gui_cat->warning() + << "trying to get extents from something I don't know how to" << endl; + l = b = 0.; + r = t = 1.; + } +} diff --git a/panda/src/gui/guiLabel.h b/panda/src/gui/guiLabel.h index 31ff8ab3ba..b51dde148a 100644 --- a/panda/src/gui/guiLabel.h +++ b/panda/src/gui/guiLabel.h @@ -6,12 +6,39 @@ #ifndef __GUILABEL_H__ #define __GUILABEL_H__ +#include "config_gui.h" + +#include +#include +#include +#include + // label-ish behavior for GUI objects (labels, buttons, rollovers) +class GuiManager; + class GuiLabel { private: + enum LabelType { NONE, SIMPLE_TEXTURE, SIMPLE_TEXT }; + LabelType _type; + PT_Node _geom; + RenderRelation* _arc; + + INLINE Node* get_geometry(void) const; + INLINE void set_arc(RenderRelation*); + INLINE RenderRelation* get_arc(void) const; + + friend GuiManager; public: INLINE GuiLabel(void); + virtual ~GuiLabel(void); + + static GuiLabel* make_simple_texture_label(void); + static GuiLabel* make_simple_text_label(const string&, Node*); + + void get_extents(float&, float&, float&, float&); }; +#include "guiLabel.I" + #endif /* __GUILABEL_H__ */ diff --git a/panda/src/gui/guiManager.I b/panda/src/gui/guiManager.I index a9538a5f9e..014009a94f 100644 --- a/panda/src/gui/guiManager.I +++ b/panda/src/gui/guiManager.I @@ -3,9 +3,6 @@ // //////////////////////////////////////////////////////////////////// -INLINE GuiManager* GuiManager::get_ptr(void) { - if (_singleton == (GuiManager*)0L) { - _singleton = new GuiManager; - } - return _singleton; +INLINE GuiManager::GuiManager(MouseWatcher* w, Node* n) : _root(n), + _watcher(w) { } diff --git a/panda/src/gui/guiManager.cxx b/panda/src/gui/guiManager.cxx index dba947f281..3ae23f2ba6 100644 --- a/panda/src/gui/guiManager.cxx +++ b/panda/src/gui/guiManager.cxx @@ -4,6 +4,7 @@ //////////////////////////////////////////////////////////////////// #include "guiManager.h" +#include "config_gui.h" #include #include @@ -19,14 +20,22 @@ GuiManager::GuiMap* GuiManager::_map = (GuiManager::GuiMap*)0L; GuiManager* GuiManager::get_ptr(GraphicsWindow* w, MouseAndKeyboard* mak) { GuiManager* ret; - if (_map == (GuiMap*)0L) + if (_map == (GuiMap*)0L) { + if (gui_cat->is_debug()) + gui_cat->debug() << "allocating a manager map" << endl; _map = new GuiMap; + } GuiMap::const_iterator gi; gi = _map->find(w); - if (gi != _map->end()) + if (gi != _map->end()) { ret = (*gi).second; - else { + if (gui_cat->is_debug()) + gui_cat->debug() << "a manager for this window already exists (0x" + << (void*)ret << ")" << endl; + } else { // going to allocate a new GuiManager for this window + if (gui_cat->is_debug()) + gui_cat->debug() << "allocating a new manager for this window" << endl; // first see if there is a mouseWatcher already under the MouseAndKeyboard bool has_watcher = false; TypeHandle dgt = DataRelation::get_class_type(); @@ -40,6 +49,8 @@ GuiManager* GuiManager::get_ptr(GraphicsWindow* w, MouseAndKeyboard* mak) { if (!has_watcher) { // there isn't already a mousewatcher in the data graph, so we'll make // one and re-parent everything to it. + if (gui_cat->is_debug()) + gui_cat->debug() << "no MouseWatcher found, making one" << endl; watcher = new MouseWatcher("GUI watcher"); DataRelation* tmp = new DataRelation(mak, watcher); for (int j=0; jget_num_children(dgt); ++j) { @@ -48,7 +59,30 @@ GuiManager* GuiManager::get_ptr(GraphicsWindow* w, MouseAndKeyboard* mak) { // it's not the node we just created, so reparent it to ours rel->change_parent(watcher); } - } + } else if (gui_cat->is_debug()) + gui_cat->debug() << "found a MouseWatcher, don't have to make one" + << endl; + // now setup event triggers for the watcher + if (has_watcher) + gui_cat->warning() << "overwriting existing button down pattern '" + << watcher->get_button_down_pattern() + << "' with 'gui-%r-%b'" << endl; + watcher->set_button_down_pattern("gui-%r-%b"); + if (has_watcher) + gui_cat->warning() << "overwriting existing button up pattern '" + << watcher->get_button_up_pattern() + << "' with 'gui-%r-%b-up'" << endl; + watcher->set_button_up_pattern("gui-%r-%b"); + if (has_watcher) + gui_cat->warning() << "overwriting existing enter pattern '" + << watcher->get_enter_pattern() + << "' with 'gui-in-%r'" << endl; + watcher->set_enter_pattern("gui-in-%r"); + if (has_watcher) + gui_cat->warning() << "overwriting existing exit pattern '" + << watcher->get_leave_pattern() + << "' with 'gui-out-%r'" << endl; + watcher->set_leave_pattern("gui-out-%r"); // next, create a 2d layer for the GUI stuff to live in. Node* root2d_top = new NamedNode("GUI_top"); Node* root2d = new NamedNode("GUI"); @@ -71,9 +105,63 @@ GuiManager* GuiManager::get_ptr(GraphicsWindow* w, MouseAndKeyboard* mak) { DisplayRegion *dr = layer->make_display_region(); nassertv(dr != (DisplayRegion*)0L); dr->set_camera(cam); + if (gui_cat->is_debug()) + gui_cat->debug() << "2D layer created" << endl; // now make the manager for this window ret = new GuiManager(watcher, root2d); + if (gui_cat->is_debug()) + gui_cat->debug() << "new manager allocated (0x" << (void*)ret << ")" + << endl; (*_map)[w] = ret; } return ret; } + +void GuiManager::add_region(GuiRegion* region) { + RegionSet::const_iterator ri; + ri = _regions.find(region); + if (ri == _regions.end()) { + _watcher->add_region(region->get_region()); + _regions.insert(region); + } else + gui_cat->warning() << "tried adding region ('" << *region + << "') more then once" << endl; +} + +void GuiManager::add_label(GuiLabel* label) { + LabelSet::const_iterator li; + li = _labels.find(label); + if (li == _labels.end()) { + // add it to the scenegraph + label->set_arc(new RenderRelation(_root, label->get_geometry())); + _labels.insert(label); + } else + gui_cat->warning() << "tried adding label (0x" << (void*)label + << ") more then once" << endl; +} + +void GuiManager::remove_region(GuiRegion* region) { + RegionSet::const_iterator ri; + ri = _regions.find(region); + if (ri == _regions.end()) + gui_cat->warning() << "tried removing region ('" << *region + << "') that isn't there" << endl; + else { + _watcher->remove_region(region->get_region()); + _regions.erase(ri); + } +} + +void GuiManager::remove_label(GuiLabel* label) { + LabelSet::const_iterator li; + li = _labels.find(label); + if (li == _labels.end()) + gui_cat->warning() << "label (0x" << (void*)label + << ") is not there to be removed" << endl; + else { + // remove it to the scenegraph + remove_arc(label->get_arc()); + label->set_arc((RenderRelation*)0L); + _labels.erase(li); + } +} diff --git a/panda/src/gui/guiManager.h b/panda/src/gui/guiManager.h index 2a66141852..f32a4f5d6f 100644 --- a/panda/src/gui/guiManager.h +++ b/panda/src/gui/guiManager.h @@ -6,11 +6,40 @@ #ifndef __GUIMANAGER_H__ #define __GUIMANAGER_H__ +#include +#include +#include +#include +#include +#include + +#include "guiRegion.h" +#include "guiLabel.h" +#include "config_gui.h" + class GuiManager { private: - static GuiManager* _singleton; + typedef map GuiMap; + static GuiMap* _map; + typedef set RegionSet; + RegionSet _regions; + typedef set LabelSet; + LabelSet _labels; + + Node* _root; + MouseWatcher* _watcher; + + INLINE GuiManager(MouseWatcher*, Node*); public: - INLINE static GuiManager* get_ptr(void); + static GuiManager* get_ptr(GraphicsWindow*, MouseAndKeyboard*); + + void add_region(GuiRegion*); + void add_label(GuiLabel*); + + void remove_region(GuiRegion*); + void remove_label(GuiLabel*); }; +#include "guiManager.I" + #endif /* __GUIMANAGER_H__ */ diff --git a/panda/src/gui/guiRegion.I b/panda/src/gui/guiRegion.I index 77871c7e2c..6b1d593dc5 100644 --- a/panda/src/gui/guiRegion.I +++ b/panda/src/gui/guiRegion.I @@ -3,8 +3,21 @@ // //////////////////////////////////////////////////////////////////// -INLINE GiuRegion::GuiRegion(void) { +INLINE GuiRegion::GuiRegion(void) { } -INLINE GiuRegion::GuiRegion(float, float, float, float) { +INLINE GuiRegion::GuiRegion(const string& name, float l, float r, float b, + float t, bool buttons) : Namable(name), _left(l), + _right(r), _bottom(b), + _top(t) { + _region = new MouseWatcherRegion(name, l, r, b, t); + _region->set_suppress_below(buttons); +} + +INLINE MouseWatcherRegion* GuiRegion::get_region(void) const { + return _region; +} + +INLINE void GuiRegion::trap_clicks(bool t) { + _region->set_suppress_below(t); } diff --git a/panda/src/gui/guiRegion.cxx b/panda/src/gui/guiRegion.cxx index 1874a778f0..62738a877e 100644 --- a/panda/src/gui/guiRegion.cxx +++ b/panda/src/gui/guiRegion.cxx @@ -4,3 +4,6 @@ //////////////////////////////////////////////////////////////////// #include "guiRegion.h" + +GuiRegion::~GuiRegion(void) { +} diff --git a/panda/src/gui/guiRegion.h b/panda/src/gui/guiRegion.h index 31b7fc5043..751375c20e 100644 --- a/panda/src/gui/guiRegion.h +++ b/panda/src/gui/guiRegion.h @@ -6,13 +6,29 @@ #ifndef __GUIREGION_H__ #define __GUIREGION_H__ +#include +#include +#include + // container for active regions of a GUI -class GuiRegion { +class GuiManager; + +class GuiRegion : public Namable { private: float _left, _right, _bottom, _top; + PT(MouseWatcherRegion) _region; + + INLINE GuiRegion(void); + + INLINE MouseWatcherRegion* get_region(void) const; + + friend GuiManager; public: - INLINE GuiRegion(float, float, float, float); + INLINE GuiRegion(const string&, float, float, float, float, bool); + ~GuiRegion(void); + + INLINE void trap_clicks(bool); }; #include "guiRegion.I" diff --git a/panda/src/gui/guiRollover.I b/panda/src/gui/guiRollover.I index 7b2ae60ba6..d4b9885e8e 100644 --- a/panda/src/gui/guiRollover.I +++ b/panda/src/gui/guiRollover.I @@ -3,5 +3,33 @@ // //////////////////////////////////////////////////////////////////// -INLINE GuiRollover::GuiRollover(float, float, float, float) { +INLINE GuiRollover::GuiRollover(void) { +} + +INLINE void GuiRollover::enter(void) { + if (_state) { + if (gui_cat->is_debug()) + gui_cat->debug() << "entered '" << *this + << "' more then once without exit" << endl; + } else if (_mgr != (GuiManager*)0L) { + _mgr->remove_label(_off); + _mgr->add_label(_on); + _state = true; + } +} + +INLINE void GuiRollover::exit(void) { + if (!_state) { + if (gui_cat->is_debug()) + gui_cat->debug() << "exited '" << *this + << "' more then once without enter" << endl; + } else if (_mgr != (GuiManager*)0L) { + _mgr->remove_label(_on); + _mgr->add_label(_off); + _state = false; + } +} + +INLINE bool GuiRollover::is_over(void) const { + return _state; } diff --git a/panda/src/gui/guiRollover.cxx b/panda/src/gui/guiRollover.cxx index 78adafc1ae..385804dae4 100644 --- a/panda/src/gui/guiRollover.cxx +++ b/panda/src/gui/guiRollover.cxx @@ -4,3 +4,67 @@ //////////////////////////////////////////////////////////////////// #include "guiRollover.h" +#include "config_gui.h" + +#include + +typedef map RolloverMap; +static RolloverMap rollovers; + +inline void GetExtents(GuiLabel* x, GuiLabel* y, float& l, float& r, float& b, + float& t) { + float l1, l2, r1, r2, b1, b2, t1, t2; + x->get_extents(l1, r1, b1, t1); + y->get_extents(l2, r2, b2, t2); + l = (l1get_name()]; + val->enter(); +} + +static void exit_rollover(CPT_Event e) { + GuiRollover* val = rollovers[e->get_name()]; + val->exit(); +} + +GuiRollover::GuiRollover(const string& name, GuiLabel* off, GuiLabel* on) + : Namable(name), _off(off), _on(on), _state(false), _added_hooks(false) { + float left, right, bottom, top; + + GetExtents(off, on, left, right, bottom, top); + _rgn = new GuiRegion("rollover-" + name, left, right, bottom, top, false); + rollovers["gui-in-rollover-" + name] = this; + rollovers["gui-out-rollover-" + name] = this; + _mgr = (GuiManager*)0L; +} + +GuiRollover::~GuiRollover(void) { +} + +void GuiRollover::manage(GuiManager* mgr, EventHandler& eh) { + if (!_added_hooks) { + eh.add_hook("gui-in-rollover-" + get_name(), enter_rollover); + eh.add_hook("gui-out-rollover-" + get_name(), exit_rollover); + _added_hooks = true; + } + if (_mgr == (GuiManager*)0L) { + mgr->add_region(_rgn); + _state = false; + mgr->add_label(_off); + _mgr = mgr; + } else + gui_cat->warning() << "tried to manage rollover (0x" << (void*)this + << ") that is already managed" << endl; +} + +void GuiRollover::unmanage(void) { + _mgr->remove_region(_rgn); + _mgr->remove_label(_off); + _mgr->remove_label(_on); + _mgr = (GuiManager*)0L; +} diff --git a/panda/src/gui/guiRollover.h b/panda/src/gui/guiRollover.h index 996bdad607..5fa61a924b 100644 --- a/panda/src/gui/guiRollover.h +++ b/panda/src/gui/guiRollover.h @@ -6,10 +6,35 @@ #ifndef __GUIROLLOVER_H__ #define __GUIROLLOVER_H__ -class GuiRollover : public GuiBaseButton { +#include "guiRegion.h" +#include "guiLabel.h" +#include "guiManager.h" + +#include + +class GuiRollover : public Namable { private: + GuiLabel* _off; + GuiLabel* _on; + GuiRegion* _rgn; + + bool _state; + bool _added_hooks; + GuiManager* _mgr; + + INLINE GuiRollover(void); public: - INLINE GuiRollover(float, float, float, float); + GuiRollover(const string&, GuiLabel*, GuiLabel*); + ~GuiRollover(void); + + void manage(GuiManager*, EventHandler&); + void unmanage(void); + INLINE void enter(void); + INLINE void exit(void); + + INLINE bool is_over(void) const; }; +#include "guiRollover.I" + #endif /* __GUIROLLOVER_H__ */ diff --git a/panda/src/testbed/Sources.pp b/panda/src/testbed/Sources.pp index 84c26089c2..292e601e30 100644 --- a/panda/src/testbed/Sources.pp +++ b/panda/src/testbed/Sources.pp @@ -131,3 +131,12 @@ #end test_bin_target +#begin test_bin_target + #define TARGET gui_demo + + #define SOURCES \ + gui_demo.cxx + + #define LOCAL_LIBS $[LOCAL_LIBS] gui + +#end test_bin_target diff --git a/panda/src/testbed/gui_demo.cxx b/panda/src/testbed/gui_demo.cxx index f9c10b4932..08be10adef 100644 --- a/panda/src/testbed/gui_demo.cxx +++ b/panda/src/testbed/gui_demo.cxx @@ -40,8 +40,11 @@ #include #include #include +#include #include +#include +#include //From framework extern PT(GeomNode) geomnode; @@ -49,6 +52,23 @@ extern RenderRelation* first_arc; static void setup_gui(void) { GuiManager* mgr = GuiManager::get_ptr(main_win, mak); + PT_Node font = ModelPool::load_model("ttf-comic"); + // test 1 + // mgr->add_region(new GuiRegion("test1", 0., 0.25, 0., 0.25)); + // mgr->add_label(GuiLabel::make_simple_text_label("test2", font)); + // test 2 + // GuiLabel* l1 = GuiLabel::make_simple_text_label("off", font); + // GuiLabel* l2 = GuiLabel::make_simple_text_label("on", font); + // GuiRollover* r1 = new GuiRollover("test2", l1, l2); + // r1->manage(mgr, event_handler); + // test 3 + GuiLabel* l1 = GuiLabel::make_simple_text_label("up", font); + GuiLabel* l2 = GuiLabel::make_simple_text_label("upr", font); + GuiLabel* l3 = GuiLabel::make_simple_text_label("down", font); + GuiLabel* l4 = GuiLabel::make_simple_text_label("downr", font); + GuiLabel* l5 = GuiLabel::make_simple_text_label("none", font); + GuiButton* b1 = new GuiButton("test3", l1, l2, l3, l4, l5); + b1->manage(mgr, event_handler); } static void event_2(CPT_Event) {