Cary Sandvig 25 years ago
parent
commit
44271cccd3
4 changed files with 239 additions and 5 deletions
  1. 8 0
      panda/src/gui/guiItem.I
  2. 2 0
      panda/src/gui/guiItem.h
  3. 206 4
      panda/src/gui/guiListBox.cxx
  4. 23 1
      panda/src/gui/guiListBox.h

+ 8 - 0
panda/src/gui/guiItem.I

@@ -51,6 +51,14 @@ INLINE LVector4f GuiItem::get_frame(void) const {
   return LVector4f(_left, _right, _bottom, _top);
 }
 
+INLINE float GuiItem::get_width(void) const {
+  return _right - _left;
+}
+
+INLINE float GuiItem::get_height(void) const {
+  return _top - _bottom;
+}
+
 INLINE GuiItem::Priority GuiItem::get_priority(void) const {
   return _pri;
 }

+ 2 - 0
panda/src/gui/guiItem.h

@@ -45,6 +45,8 @@ PUBLISHED:
   INLINE float get_bottom(void) const;
   INLINE float get_top(void) const;
   INLINE LVector4f get_frame(void) const;
+  INLINE float get_width(void) const;
+  INLINE float get_height(void) const;
   INLINE Priority get_priority(void) const;
 
   INLINE void recompute(void);

+ 206 - 4
panda/src/gui/guiListBox.cxx

@@ -9,37 +9,239 @@ TypeHandle GuiListBox::_type_handle;
 
 void GuiListBox::recompute_frame(void) {
   GuiItem::recompute_frame();
+  LVector3f p = _pos;
+  for (ItemVector::iterator i=_visible.begin(); i!=_visible.end();
+       p+=(*i)->get_height(), ++i)
+    (*i)->set_pos(p);
+  // NEED TO COMPUTE FRAME AT SAME TIME!
 }
 
-GuiListBox::GuiListBox(const string& name) : GuiItem(name) {
+void GuiListBox::visible_patching(void) {
+  // check for 2 cases on both top and bottom of the visible list.  First,
+  // if there is an item off that edge, but no arrow active; then put an arrow
+  // up (needing to move a second item off the edge).  Second, if there is an
+  // arrow up, but there is only a single item off the edge; replace the arrow
+  // with the item.
+
+  // top first
+  if (_arrow_top) {
+    if (_top_stack.size() == 1) {
+      // replace the up arrow with the single item in the top stack
+      _arrow_top = false;
+      _visible[0]->unmanage();
+      _visible[0] = *(_top_stack.begin());
+      _visible[0]->manage(_mgr, *_eh);
+      _top_stack.pop_back();
+    }
+  } else {
+    if (_top_stack.size() > 0) {
+      // move the top of the visible list to the top stack and put the up
+      // arrow in it's place
+      _arrow_top = true;
+      _visible[0]->unmanage();
+      _top_stack.push_back(_visible[0]);
+      _visible[0] = _up_arrow;
+      _up_arrow->manage(_mgr, *_eh);
+    }
+  }
+
+  // now bottom
+  if (_arrow_bottom) {
+    if (_bottom_stack.size() == 1) {
+      // replace the down arrow with the single item in the bottom stack
+      _arrow_bottom = false;
+      int last = _n_visible-1;
+      _visible[last]->unmanage();
+      _visible[last] = *(_bottom_stack.begin());
+      if (_mgr != (GuiManager*)0L)
+	_visible[last]->manage(_mgr, *_eh);
+      _bottom_stack.pop_back();
+    }
+  } else {
+    if (_bottom_stack.size() > 0) {
+      // move the bottom of the visible list to the bottom stack and put the
+      // down arrow in it's place
+      _arrow_bottom = true;
+      int last = _n_visible-1;
+      _visible[last]->unmanage();
+      _bottom_stack.push_back(_visible[last]);
+      _visible[last] = _down_arrow;
+      if (_mgr != (GuiManager*)0L)
+	_down_arrow->manage(_mgr, *_eh);
+    }
+  }
+}
+
+GuiListBox::GuiListBox(const string& name, int N, GuiItem* up, GuiItem* down)
+  : GuiItem(name), _arrow_top(false), _arrow_bottom(false), _up_arrow(up),
+    _down_arrow(down), _n_visible(N) {
+  if (N < 4) {
+    gui_cat->warning() << "ListBoxes should have at least 4 visible slots"
+		       << endl;
+    _n_visible = 4;
+  }
 }
 
 GuiListBox::~GuiListBox(void) {
   this->unmanage();
 }
 
+void GuiListBox::scroll_up(void) {
+  if (_bottom_stack.size() == 0)
+    return;   // nothing to scroll
+  // compute what the first and list item in the visible list are
+  int first = 0;
+  int last = _n_visible-1;
+  if (_arrow_top)
+    ++first;
+  if (_arrow_bottom)
+    --last;
+  // first push one off the top onto the top stack
+  _top_stack.push_back(_visible[first]);
+  _visible[first]->unmanage();
+  // then move everything up one
+  for (int i=first; i!=last; ++i)
+    _visible[i] = _visible[i+1];
+  // then add one from the bottom stack to the bottom
+  _visible[last] = *(_bottom_stack.rbegin());
+  if (_mgr != (GuiManager*)0L)
+    _visible[last]->manage(_mgr, *_eh);
+  // and pop it off the bottom stack
+  _bottom_stack.pop_back();
+  // now patch-up any dangling items
+  visible_patching();
+  // finally recompute all the possitions
+  this->recompute_frame();
+}
+
+void GuiListBox::scroll_down(void) {
+  if (_top_stack.size() == 0)
+    return;  // nothing to scroll
+  // compute what the first and last item in the visible list are
+  int first = 0;
+  int last = _n_visible - 1;
+  if (_arrow_top)
+    ++first;
+  if (_arrow_bottom)
+    --last;
+  // first push one off the bottom onto the bottom stack
+  _bottom_stack.push_back(_visible[last]);
+  _visible[last]->unmanage();
+  // then move everything down one
+  for (int i=last; i!=first; --i)
+    _visible[i] = _visible[i-1];
+  // then add one from the top stack to the top
+  _visible[first] = *(_top_stack.rbegin());
+  if (_mgr != (GuiManager*)0L)
+    _visible[first]->manage(_mgr, *_eh);
+  // and pop it off the top stack
+  _top_stack.pop_back();
+  // now patch-up any dangling item
+  visible_patching();
+  // finally recompute all the possitions
+  this->recompute_frame();
+}
+
+void GuiListBox::add_item(GuiItem* item) {
+  if (_bottom_stack.size() > 0)
+    _bottom_stack.push_front(item);
+  else {
+    if (_visible.size() < _n_visible) {
+      _visible.push_back(item);
+      if (_mgr != (GuiManager*)0L)
+	item->manage(_mgr, *_eh);
+    } else
+      _bottom_stack.push_back(item);
+  }
+}
+
+int GuiListBox::freeze(void) {
+  int result = 0;
+
+  for (ItemVector::iterator i=_visible.begin(); i!=_visible.end(); ++i) {
+    int count = (*i)->freeze();
+    result = max(result, count);
+  }
+  return result;
+}
+
+int GuiListBox::thaw(void) {
+  int result = 0;
+
+  for (ItemVector::iterator i=_visible.begin(); i!=_visible.end(); ++i) {
+    int count = (*i)->thaw();
+    result = max(result, count);
+  }
+  return result;
+}
+
 void GuiListBox::manage(GuiManager* mgr, EventHandler& eh) {
-  if (_mgr == (GuiManager*)0L)
+  if (_mgr == (GuiManager*)0L) {
+    for (ItemVector::iterator i=_visible.begin(); i!=_visible.end(); ++i)
+      (*i)->manage(mgr, eh);
+    _eh = &eh;
     GuiItem::manage(mgr, eh);
-  else
+  } else
     gui_cat->warning() << "tried to manage listbox (0x" << (void*)this
 		       << ") that is already managed" << endl;
 }
 
 void GuiListBox::unmanage(void) {
+  for (ItemVector::iterator i=_visible.begin(); i!=_visible.end(); ++i)
+    (*i)->unmanage();
   GuiItem::unmanage();
 }
 
 void GuiListBox::set_scale(float f) {
+  ItemVector::iterator i;
+  for (i=_top_stack.begin(); i!=_top_stack.end(); ++i)
+    (*i)->set_scale(f);
+  for (i=_visible.begin(); i!=_visible.end(); ++i)
+    (*i)->set_scale(f);
+  for (ItemDeque::iterator j=_bottom_stack.begin(); j!=_bottom_stack.end();
+       ++j)
+    (*j)->set_scale(f);
   GuiItem::set_scale(f);
 }
 
 void GuiListBox::set_pos(const LVector3f& p) {
+  ItemVector::iterator i;
+  for (i=_top_stack.begin(); i!=_top_stack.end(); ++i)
+    (*i)->set_pos(p);
+  for (i=_visible.begin(); i!=_visible.end(); ++i)
+    (*i)->set_pos(p);
+  for (ItemDeque::iterator j=_bottom_stack.begin(); j!=_bottom_stack.end();
+       ++j)
+    (*j)->set_pos(p);
   GuiItem::set_pos(p);
 }
 
 void GuiListBox::output(ostream& os) const {
   GuiItem::output(os);
   os << "  Listbox data:" << endl;
-  os << "    none" << endl;
+  os << "    There is ";
+  if (!_arrow_top)
+    os << "no ";
+  os << "top arrow (0x" << (void*)_up_arrow << ")" << endl;
+  os << "    There is ";
+  if (!_arrow_bottom)
+    os << "no ";
+  os << "bottom arrow (0x" << (void*)_down_arrow << ")" << endl;
+  os << "    Top stack (" << _top_stack.size() << "):" << endl;
+  ItemVector::const_iterator i;
+  for (i=_top_stack.begin(); i!=_top_stack.end(); ++i)
+    os << "      0x" << (void*)(*i) << endl;
+  os << "    Visible (" << _visible.size() << "):" << endl;
+  for (i=_visible.begin(); i!=_visible.end(); ++i)
+    os << "      0x" << (void*)(*i) << endl;
+  os << "    Bottom stack (" << _bottom_stack.size() << "):" << endl;
+  ItemDeque::const_iterator j;
+  for (j=_bottom_stack.begin(); j!=_bottom_stack.end(); ++j)
+    os << "      0x" << (void*)(*j) << endl;
+  for (i=_top_stack.begin(); i!=_top_stack.end(); ++i)
+    os << *(*i);
+  for (i=_visible.begin(); i!=_visible.end(); ++i)
+    os << *(*i);
+  for (j=_bottom_stack.begin(); j!=_bottom_stack.end(); ++j)
+    os << *(*j);
 }

+ 23 - 1
panda/src/gui/guiListBox.h

@@ -9,15 +9,37 @@
 #include "guiItem.h"
 
 #include <vector>
+#include <deque>
 
 class EXPCL_PANDA GuiListBox : public GuiItem {
 private:
+  typedef vector< PT(GuiItem) > ItemVector;
+  typedef deque< PT(GuiItem) > ItemDeque;
+
+  ItemVector _top_stack;
+  ItemDeque _bottom_stack;
+  ItemVector _visible;
+  bool _arrow_top;
+  bool _arrow_bottom;
+  PT(GuiItem) _up_arrow;
+  PT(GuiItem) _down_arrow;
+  unsigned int _n_visible;
+  EventHandler* _eh;
+
   INLINE GuiListBox(void);
   virtual void recompute_frame(void);
+  void visible_patching(void);
 PUBLISHED:
-  GuiListBox(const string&);
+  GuiListBox(const string&, int, GuiItem*, GuiItem*);
   ~GuiListBox(void);
 
+  void scroll_up(void);
+  void scroll_down(void);
+  void add_item(GuiItem*);
+
+  virtual int freeze(void);
+  virtual int thaw(void);
+
   virtual void manage(GuiManager*, EventHandler&);
   virtual void unmanage(void);