Author: spitzak
Date: 2008-11-10 13:10:13 -0800 (Mon, 10 Nov 2008)
New Revision: 6514
Log:
New shortcut assignments using WidgetAssociation data, written
by Andreas Rover.
This makes shortcut assignments much simpler and proves that the
WidgetAssociations are useable for storing data. A function to
find and to remove a specific association had to be added.


Modified:
   trunk/fltk/Widget.h
   trunk/fltk/WidgetAssociation.h
   trunk/fltk/events.h
   trunk/src/ShortcutAssignment.cxx
   trunk/src/Widget.cxx
   trunk/src/WidgetAssociation.cxx
   trunk/test/menu.cxx

Modified: trunk/fltk/Widget.h
===================================================================
--- trunk/fltk/Widget.h 2008-11-10 21:05:22 UTC (rev 6513)
+++ trunk/fltk/Widget.h 2008-11-10 21:10:13 UTC (rev 6514)
@@ -102,10 +102,10 @@
   void tooltip(const char *t)  { tooltip_ = t; }
 
   unsigned shortcut() const    ;
-  bool shortcut(unsigned key)  ;
+  void shortcut(unsigned key)  ;
   bool add_shortcut(unsigned key);
   bool remove_shortcut(unsigned key);
-  bool  remove_shortcuts()     ;
+  void  remove_shortcuts()     ;
   unsigned label_shortcut() const;
   bool test_label_shortcut() const;
   bool test_shortcut() const   ;
@@ -259,6 +259,8 @@
   void  set(const AssociationType&, void* data);
   void* get(const AssociationType&) const;
   void* foreach(const AssociationType&, AssociationFunctor&) const;
+  bool  remove(const AssociationType&, void* data);
+  bool  find(const AssociationType&, void* data) const;
 
 #ifdef FLTK_1_WIDGET  // back-compatability section:
 

Modified: trunk/fltk/WidgetAssociation.h
===================================================================
--- trunk/fltk/WidgetAssociation.h      2008-11-10 21:05:22 UTC (rev 6513)
+++ trunk/fltk/WidgetAssociation.h      2008-11-10 21:10:13 UTC (rev 6514)
@@ -39,8 +39,8 @@
 
 /*! \brief Base class for the association type.
  *
- * FLTK allows you to attach any kind user data to a widget. This data is 
automatically freed when the
- * widget to which it is attached is destroyed. Internally an association 
table is used to connetc the
+ * FLTK allows you to attach any kind of user data to a widget. This data is 
automatically freed when the
+ * widget to which it is attached is destroyed. Internally an association 
table is used to connect the
  * widget pointer with the data pointer that is why all the functions 
concerned with this feature contain
  * "association" in their name. The advantage of this is that no space is 
taken on widgets that do not
  * contain the data (or that have the "default value"), and that the 
destructor code is not linked in
@@ -62,7 +62,7 @@
 class FL_API AssociationType {
 
  public:
-  /*! \brief This function is called with associated data is freed
+  /*! \brief This function is called when associated data is freed
    * This function must be proveded when creating a data specific subclass. 
The function
    * must do whatever is necessary to free associated data. Most of the time 
it will be a cast
    * to the right datatype and a delete
@@ -70,8 +70,8 @@
   virtual void destroy(void* data) const = 0;
 
   /*! \brief Finds all data of this association type for a widget
-   * This function is just calls fltk::foreach(this, wg, fkt). If \a widget
-   * is NULL this all data for any widget.
+   * This function just calls fltk::foreach(this, wg, fkt). If \a wg
+   * is NULL this function will find all data for any widget.
    */
   void* foreach(const Widget* wg, AssociationFunctor& fkt) { return 
fltk::foreach(this, wg, fkt); }
 };

Modified: trunk/fltk/events.h
===================================================================
--- trunk/fltk/events.h 2008-11-10 21:05:22 UTC (rev 6513)
+++ trunk/fltk/events.h 2008-11-10 21:10:13 UTC (rev 6514)
@@ -275,16 +275,17 @@
 inline void compose_reset()            {compose_state = 0;}
 
 // shortcuts:
-/*! Structure created by Widget::add_shortcut() and returned by 
list_shortcuts(). */
-struct ShortcutAssignment {Widget* widget; unsigned key;};
-FL_API const ShortcutAssignment* list_shortcuts(unsigned key, unsigned& count);
-FL_API const ShortcutAssignment* list_shortcuts(const Widget*,unsigned& count);
-FL_API const ShortcutAssignment* list_shortcuts(unsigned& count);
-FL_API const ShortcutAssignment* list_matching_shortcuts(unsigned& count);
 FL_API bool try_shortcut();
 FL_API const char* key_name(unsigned key);
 FL_API unsigned key(const char* name);
 
+class FL_API ShortcutFunctor {
+ public:
+  virtual bool handle(const Widget*, unsigned key) = 0;
+};
+FL_API unsigned foreachShortcut(const Widget*, ShortcutFunctor&);
+inline unsigned foreachShortcut(ShortcutFunctor& f) { return 
foreachShortcut(0,f); }
+
 // get current information, not info from last event:
 FL_API bool get_key_state(unsigned);
 FL_API void get_mouse(int &,int &);

Modified: trunk/src/ShortcutAssignment.cxx
===================================================================
--- trunk/src/ShortcutAssignment.cxx    2008-11-10 21:05:22 UTC (rev 6513)
+++ trunk/src/ShortcutAssignment.cxx    2008-11-10 21:10:13 UTC (rev 6514)
@@ -22,77 +22,27 @@
 //
 
 
-// Shortcuts are stored entirely using hidden data structures, and are
-// looked up by searching for pointers in tables. This keeps the size
-// of widgets with no shortcut small, and allows us freedom to change
-// the implementation. The current implementation just does binary
-// search for shortcuts and uses insertion sort to put things into the
-// tables, but a hash table is probably better and it should be
-// changed to this someday.
+// Shortcuts are stored in the association table
 
-// Two parallel arrays are maintained with exactly the same data.
-// One is sorted by widget, the other by key. If the structure gets
-// any more complex we may want to sort arrays of pointers instead.
-
 #include <config.h>
 #include <fltk/events.h>
 #include <fltk/Widget.h>
+#include <fltk/WidgetAssociation.h>
 #include <fltk/string.h>
 #include <ctype.h>
 
 using namespace fltk;
 
-static ShortcutAssignment* keylist = 0;
-static ShortcutAssignment* widgetlist = 0;
-static unsigned num_shortcuts = 0;
-static unsigned array_size = 0;
+class shortcutAssociationType : public AssociationType {
 
-// Returns entry, or pointer where to insert it:
-static ShortcutAssignment* findkey(unsigned key) {
-  unsigned a = 0;
-  unsigned b = num_shortcuts;
-  while (a < b) {
-    unsigned c = (a+b)/2;
-    ShortcutAssignment* p = keylist+c;
-    int n = (p->key&0xffff)-(key&0xffff);
-    if (n < 0) a = c+1;
-    else if (n > 0) b = c;
-    else {
-      n = p->key - key;
-      if (n < 0) a = c+1;
-      else if (n > 0) b = c;
-      else {
-       // found it, but search backwards for first one
-       while (p > keylist && (p-1)->key == key) --p;
-       return p;
-      }
-    }
-  }
-  return keylist+a;
-}
+  // we use the data pointer as unsigned int, so
+  // we don't need to free anything
+  void destroy(void *data) const {}
+};
 
-// Search the sorted-by-widget list
-static ShortcutAssignment* findwidget(const Widget* widget) {
-  unsigned a = 0;
-  unsigned b = num_shortcuts;
-  while (a < b) {
-    int c = (a+b)/2;
-    ShortcutAssignment* p = widgetlist+c;
-    if (p->widget < widget) a = c+1;
-    else if (p->widget > widget) b = c;
-    else {
-      // found it, but search backwards for first one
-      while (p > widgetlist && (p-1)->widget == widget) --p;
-      return p;
-    }
-  }
-  return widgetlist+a;
-}
+// this is our association to the shortcuts associated with widgets
+static shortcutAssociationType shortcutAssociation;
 
-static unsigned last_list = 0;
-static const ShortcutAssignment* last_list_pointer = 0;
-static unsigned last_list_length = 0;
-
 /*!
 
   Add a new shortcut assignment. Returns true if successful.  If \a key
@@ -102,8 +52,7 @@
   There can be any number of shortcut assignments, fltk stores them in
   internal tables shared by all widgets. A widget can have any number
   of shortcuts (though most have zero or one), and a given shortcut
-  value can be assigned to more than one widget. You can examine
-  the assignments with fltk::list_shortcuts().
+  value can be assigned to more than one widget.
 
   If you only want one shortcut use shortcut() to assign it.
 
@@ -115,8 +64,7 @@
   - just <code>'a'</code>
   - <code>fltk::SHIFT+'#'</code>
   - <code>fltk::SHIFT+fltk::UpKey</code>
-  See fltk::list_matching_shortcuts() for the exact rules for how
-  a KEY event is matched to a shortcut assignment. Case is ignored
+  Case is ignored
   (the lower-case version of any letter is actually put in the table).
 
   When FLTK gets a keystroke, it sends it to the fltk::focus()
@@ -131,249 +79,56 @@
   they are interested in).  */
 bool Widget::add_shortcut(unsigned key) {
   if (!key) return false;
-  if (!(key&0xff00u)) key = key&0xffff0000u|tolower(key&0xffu);
-  // return false if any duplicates, then point after last one:
-  ShortcutAssignment* p = findwidget(this);
-  while (p < widgetlist+num_shortcuts && p->widget == this) {
-    if (p->key == key) return false;
-    p++;
-  }
-  if (num_shortcuts >= array_size) {
-    array_size = array_size ? 2*array_size : 64;
-    ShortcutAssignment* newlist = new ShortcutAssignment[array_size];
-    memcpy(newlist, keylist, num_shortcuts*sizeof(*keylist));
-    delete[] keylist;
-    keylist = newlist;
-    newlist = new ShortcutAssignment[array_size];
-    memcpy(newlist, widgetlist, num_shortcuts*sizeof(*widgetlist));
-    p = p-widgetlist+newlist;
-    delete[] widgetlist;
-    widgetlist = newlist;
-  }
-  // insert the new assignment:
-  memmove(p+1, p, (widgetlist+num_shortcuts-p)*sizeof(*widgetlist));
-  p->widget = this;
-  p->key = key;
-  // also insert it into keylist, after all other matching keys:
-  p = findkey(key);
-  while (p < keylist+num_shortcuts && p->key==key) p++;
-  memmove(p+1, p, (keylist+num_shortcuts-p)*sizeof(*keylist));
-  p->widget = this;
-  p->key = key;
-  ++num_shortcuts;
-  last_list = 0;
+  key = key&0xffff0000u|tolower(key&0xffu);
+  if (find(shortcutAssociation, (void*)key)) return false;
+  add(shortcutAssociation, (void*)key);
   return true;
 }
 
-/*! Delete a shortcut after widget entry is found */
-static void remove_keylist(ShortcutAssignment* p) {
-  // Find the matching one in shortcut list (this will crash if missing):
-  ShortcutAssignment* q = findkey(p->key);
-  for (;;) {
-    //assert(q < keylist+num_shortcuts);
-    if (q->widget == p->widget) break;
-    ++q;
-  }
-  memmove(q, q+1, (keylist+num_shortcuts-q-1)*sizeof(*keylist));
-  last_list = 0;
-}
 
-/*! Delete a shortcut assignment. Returns true if it actually existed. */
+/*!
+  Delete a shortcut assignment. Returns true if it actually existed.
+*/
 bool Widget::remove_shortcut(unsigned key) {
-  if (!key) return false;
-  if (!(key&0xff00u)) key = key&0xffff0000u|tolower(key&0xffu);
-  ShortcutAssignment* p = findwidget(this);
-  for (;;) {
-    if (p >= widgetlist+num_shortcuts) return false;
-    if (p->widget != this) return false;
-    if (p->key == key) {
-      ::remove_keylist(p);
-      // now delete the widgetlist entry:
-      memmove(p, p+1, (widgetlist+num_shortcuts-p-1)*sizeof(*widgetlist));
-      --num_shortcuts;
-      return true;
-    }
-    ++p;
-  }
+  return remove(shortcutAssociation, (void*)key);
 }
 
-/*! Remove all shortcuts for the widget.  Returns true if there were
-    any. This is automatically done by the Widget destructor.
-*/
-bool Widget::remove_shortcuts() {
-  ShortcutAssignment* p = findwidget(this);
-  unsigned n = 0;
-  while (p+n < widgetlist+num_shortcuts && p[n].widget == this) {
-    remove_keylist(p+n);
-    n++;
-  }
-  if (!n) return false;
-  memmove(p, p+n, (widgetlist+num_shortcuts-p-n)*sizeof(*widgetlist));
-  num_shortcuts -= n;
-  return true;
-}
 
-/*! Returns an array of shortcut assignments for this widget.
-    The number of matching ones is put in \a count. Do not
-    assumme any particular order for the returned array. Also
-    there may be entries with key==0, ignore them.
-
-    The returned array is temporary storage and can be overwritten
-    by the next call to alter or query shortcuts!
+/*!
+  Remove all shortcuts for the widget.
+  This is automatically done by the Widget destructor.
 */
-const ShortcutAssignment*
-fltk::list_shortcuts(const Widget* widget, unsigned& count) {
-  ShortcutAssignment* p = findwidget(widget);
-  unsigned n = 0;
-  for (; p+n < widgetlist+num_shortcuts && p[n].widget==widget; n++);
-  count = n;
-  return p;
+void Widget::remove_shortcuts() {
+  set(shortcutAssociation, 0);
 }
 
-/*! Returns one of the add_shortcut() assignments for this widget,
-    or returns zero if there are none. If you want to look at more
-    than onle you must use fltk::list_shortcuts(this).
-*/
-unsigned Widget::shortcut() const {
-  ShortcutAssignment* p = findwidget(this);
-  if (p < widgetlist+num_shortcuts && p->widget==this) return p->key;
-  return 0;
-}
 
-/*! Returns an array of shortcut assignments that match the given
-    value for \a key. The number of matching ones is put in \a count.
-    If there are no matches \a count is set to zero. Do not assumme
-    any particular order for the returned array. Also there may be
-    entries with widget==0, ignore them.
-
-    The returned array is temporary storage and can be overwritten
-    by the next call to alter or query shortcuts!  */
-const ShortcutAssignment*
-fltk::list_shortcuts(unsigned key, unsigned& count) {
-  if (!(key&0xff00u)) key = key&0xffff0000u|tolower(key&0xffu);
-  ShortcutAssignment* p = findkey(key);
-  unsigned n = 0;
-  for (; p+n < keylist+num_shortcuts && p[n].key==key; n++);
-  count = n;
-  return p;
-}
-
 /*!
-  Returns an array of shortcut assignments that match the current
-  event, which should be a KEY, SHORTCUT, or KEYUP event.  The number
-  of matching ones is put in \a count.  If there are no matches null
-  is returned and \a count is set to zero.
-
-  The returned array is temporary storage and can be overwritten
-  by the next call to alter or query shortcuts! Also there may be
-  entries with widget==0, ignore them.
-
-  This is very similar to list_shortcuts(event_key()|event_state())
-  except if no \e exact match is found, it will try to locate a
-  "close" matching key assignment and return that:
-
-  - Shift flags \e other than META, ALT, SHIFT, and CTRL do not have to
-    be "off". For instance a shortcut with SCROLL_LOCK requires the
-    SCROLL_LOCK to be on, but one without it does not require it to
-    be off. If there are several matches the numerically-highest
-    one is chosen.
-  - If no shortcut matches fltk::event_key(), then the first letter
-    of fltk::event_text() is converted to upper-case and tried instead,
-    and SHIFT can be held down even if the shortcut does not indicate
-    it. This means that a shortcut that is a capital 'A' will match
-    the 'a' key, and '3' will match both the main and keypad 3, and
-    a shortcut of '#' or SHIFT+'#' will work.
+  Returns one of the add_shortcut() assignments for this widget,
+  or returns zero if there are none. If you want to look at more
+  than onle you must use fltk::list_shortcuts(this).
 */
-const ShortcutAssignment*
-fltk::list_matching_shortcuts(unsigned& count) {
-  // This will get called a LOT for the same event, so cache the return value:
-  if ((event_key()|event_state())==last_list) {
-    count = last_list_length;
-    return last_list_pointer;
-  }
-  ShortcutAssignment* ret = 0;
-  count = 0;
-  // Check against the actual keysym, return highest one (most likely the
-  // one with the most shift keys down):
-  ShortcutAssignment* p = findkey(event_key());
-  for (; p < keylist+num_shortcuts ;) {
-    unsigned mismatch = p->key ^ (event_key()|event_state());
-    if (mismatch & 0xffff) break; // we are in the next key
-    // find out how many identical shortcut assignments there are:
-    unsigned n = 1;
-    for (; p+n < keylist+num_shortcuts && p[n].key==p->key; n++);
-    // we must match all shifts in the shortcut, plus the 4 main shifts:
-    if (!(mismatch & (p->key|META|ALT|CTRL|SHIFT))) {
-      ret = p;
-      count = n;
-    }
-    // skip to next different shortcut:
-    p += n;
-  }
-  // If nothing matched, try using the ASCII letters. Again find the highest
-  // one, but we don't require shift to be up:
-  if (!ret && event_text() && event_text()[0]) {
-    unsigned c = tolower(event_text()[0]);
-    p = findkey(c);
-    for (; p < keylist+num_shortcuts ;) {
-      unsigned mismatch = p->key ^ (c|event_state());
-      if (mismatch & 0xffff) break; // we are in the next key
-      // find out how many identical shortcut assignments there are:
-      unsigned n = 1;
-      for (; p+n < keylist+num_shortcuts && p[n].key==p->key; n++);
-      // we must match all shifts in the shortcut, plus the 3 main shifts:
-      if (!(mismatch & (p->key|META|ALT|CTRL))) {
-       ret = p;
-       count = n;
-      }
-      // skip to next different shortcut:
-      p += n;
-    }
-  }
-#if 0
-  if (ret) {
-    printf("For key %x found %d matches starting at index %d in:\n",
-          event_key()|event_state(), count, ret-keylist);
-    for (unsigned n = 0; n < num_shortcuts; n++)
-      printf(" %s %x\n", keylist[n].widget->label(), keylist[n].key);
-  }
-#endif
-  last_list = event_key()|event_state();
-  last_list_length = count;
-  last_list_pointer = ret;
-  return ret;
+unsigned Widget::shortcut() const {
+  return (unsigned int)get(shortcutAssociation);
 }
 
-/*! Returns an array of every shortcut assignment. They are sorted by
-    the key, and then by shift flags.
 
-    The returned array is temporary storage and will be overwritten
-    by the next call to alter or query shortcuts! Also there may be
-    entries with widget==0, ignore them.
-*/
-const ShortcutAssignment* fltk::list_shortcuts(unsigned& count) {
-  count = num_shortcuts;
-  return keylist;
-}
-
 /*!
   Same as remove_shortcuts(), add_shortcut(key)
   except it may be implemented in a more efficient way.
   The result is exactly one shortcut (or none if \a key is zero).
-  Return value is intended to indicate if the shortcut changed, but
-  that is nyi.
 */
-bool Widget::shortcut(unsigned key) {
-  remove_shortcuts();
-  return add_shortcut(key);
+void Widget::shortcut(unsigned key) {
+  set(shortcutAssociation, (void*)key);
 }
 
+
 /*!
   Returns a value that can be passed to add_shortcut() so that this
-  widget has a real shortcut assignment to match any &x in it's label().
-  The returned value is ALT|c where c is the character after
-  the first '&' in the label, or zero if there isn't any '&' sign
-  or if flag(RAW_LABEL) is on.
+  widget has a real shortcut assignment to match any &x in it's
+  label().  The returned value is ALT|c where c is the character after
+  the first '&' in the label (except '&&' is ignored), or zero if
+  there isn't any '&' sign or if flag(RAW_LABEL) is on.
 */
 unsigned Widget::label_shortcut() const {
   if (flag(RAW_LABEL)) return 0;
@@ -387,18 +142,20 @@
   return 0;
 }
 
-/*! Test to see if the current KEY or SHORTCUT event matches a shortcut
-    specified with &x in the label.
 
-    This will match if the character in the label() after a '&'
-    matches event_text()[0]. Case is ignored. The caller may want
-    to check if ACCELERATOR or some other shift key is held down
-    before calling this so that plain keys do not do anything, and
-    should certainly make sure no other widgets want the shortcut.
+/*!
+  Test to see if the current KEY or SHORTCUT event matches a shortcut
+  specified with &x in the label.
 
-    This is ignored if flag(RAW_LABEL) is on (which stops the &x from
-    printing as an underscore. The sequence "&&" is ignored as well
-    because that is used to print a plain '&' in the label.
+  This will match if the character in the label() after a '&'
+  matches event_text()[0]. Case is ignored. The caller may want
+  to check if ACCELERATOR or some other shift key is held down
+  before calling this so that plain keys do not do anything, and
+  should certainly make sure no other widgets want the shortcut.
+
+  This is ignored if flag(RAW_LABEL) is on (which stops the &x from
+  printing as an underscore. The sequence "&&" is ignored as well
+  because that is used to print a plain '&' in the label.
 */
 bool Widget::test_label_shortcut() const {
   if (flag(RAW_LABEL)) return false;
@@ -421,37 +178,116 @@
   return false;
 }
 
-/*! Same as test_shortcut(true) */
-bool Widget::test_shortcut() const {
-  return test_shortcut(true);
-}
 
-/*! Returns true if the current event matches one of the assignements
-    made with add_shortcut(), or if test_label is true and
-    test_label_shortcut() returns true. Normally a widget calls this
-    in response to a SHORTCUT event to see if the shortcut key is
-    assigned to it.
+// this class is a functor class used in the test_shortcut functions below
+// the handle function is called for each associated key of this widget and
+// it checks, if that key fist the current key event
+// if that is the case, the function returns true, making the foreach loop
+// stop and return something != 0, this is a sign for the function that
+// a key has been associated to the current widget that fits the current
+// key event...
+class keyCompareFunctor : public AssociationFunctor {
 
-    This is done by doing list_matching_shortcuts() and seeing if this
-    widget is in the returned list. If the list is empty and test_label
-    is true, it will return test_label_shortcut().
+  public:
 
-    If the current event matches a \e different widget "better" than
-    this one, then false is returned. For instance if this widget has
-    'x' as a shortcut, this will return true if the user types
-    'X'. But if another widget has 'X' then this will return
-    false. See fltk::list_matching_shortcuts() for the rules about
-    what ones are "better".
+    unsigned int count;
+
+    keyCompareFunctor(void) : count(0) {}
+
+    bool handle(const AssociationType&, const Widget*, void* data) {
+
+      count++;
+
+      unsigned int key = (unsigned int)data;
+
+      unsigned mismatch = key ^ (event_key() | event_state());
+
+      if (!(mismatch & 0xffff) &&
+          !(mismatch & (key|META|ALT|CTRL|SHIFT)))
+        return true;
+
+      mismatch = key ^ (tolower(event_text()[0]) | event_state());
+
+      if (!(mismatch & 0xffff) &&
+          !(mismatch & (key|META|ALT|CTRL|SHIFT)))
+        return true;
+
+      return false;
+    }
+};
+
+
+/*! Same as test_shortcut(true) */
+bool Widget::test_shortcut() const { return test_shortcut(true); }
+
+
+/*!
+  Returns true if the current event matches one of the assignements
+  made with add_shortcut(), or if test_label is true and
+  test_label_shortcut() returns true. Normally a widget calls this
+  in response to a SHORTCUT event to see if the shortcut key is
+  assigned to it.
 */
 bool Widget::test_shortcut(bool test_label) const {
-  unsigned count;
-  const ShortcutAssignment* list = list_matching_shortcuts(count);
-  if (!count) return test_label && test_label_shortcut();
-  for (unsigned i = 0; i < count; i++)
-    if (list[i].widget == this) return true;
+
+  keyCompareFunctor fkt;
+
+  // if there is a suitable assignment, return true
+  if (foreach(shortcutAssociation, fkt)) return true;
+
+  // if not, check how many keys had been assigned, if none,
+  // check for label shortcut
+  if (test_label && fkt.count == 0)
+    return test_label_shortcut();
+
   return false;
 }
 
+////////////////////////////////////////////////////////////////
+
+class GlueFunctor : public AssociationFunctor {
+public:
+  ShortcutFunctor& f;
+  GlueFunctor(ShortcutFunctor& g) : f(g) {}
+  bool handle(const AssociationType&, const Widget* widget, void* data) {
+    return f.handle(widget, (unsigned int)data);
+  }
+};
+
+/*!
+  Call the handle() method from the passed ShortcutFunctor object
+  for every Widget::shortcut() assignment known. If any return true
+  then this immediately returns that shortcut value, else this
+  returns zero after calling it for the last one. This is most
+  useful for making a display of shortcuts for the user, or implementing
+  a shortcut editor.
+
+\code
+class ListShortcuts : public ShortcutFunctor {
+public:
+  bool handle(const Widget* widget, unsigned key) {
+    printf("Widget=%s shortcut=%s\n",
+           widget->label() ? widget->label() : "NULL",
+           key_name(key));
+    return false;
+  }
+};
+f() {
+  ListShortcuts listShortcuts;
+  fltk::foreachShortcut(listShortcuts);
+}
+\endcode
+
+  If \a widget is not null, only do assignments for that widget,
+  this is much faster than searching the entire list. This is useful
+  for drawing the shortcuts on a widget (though most fltk widgets only
+  draw the first one).
+*/
+unsigned fltk::foreachShortcut(const Widget* widget, ShortcutFunctor& f) {
+  GlueFunctor g(f);
+  return (unsigned int)(foreach(&shortcutAssociation, widget, g));
+}
+
 // End of $Id$
 
 

Modified: trunk/src/Widget.cxx
===================================================================
--- trunk/src/Widget.cxx        2008-11-10 21:05:22 UTC (rev 6513)
+++ trunk/src/Widget.cxx        2008-11-10 21:10:13 UTC (rev 6514)
@@ -90,7 +90,6 @@
 */
 Widget::~Widget() {
   remove_timeout();
-  remove_shortcuts();
   if (parent_) parent_->remove(this);
   throw_focus();
   delete_associations_for(this);

Modified: trunk/src/WidgetAssociation.cxx
===================================================================
--- trunk/src/WidgetAssociation.cxx     2008-11-10 21:05:22 UTC (rev 6513)
+++ trunk/src/WidgetAssociation.cxx     2008-11-10 21:10:13 UTC (rev 6514)
@@ -177,6 +177,72 @@
 }
 
 /*!
+ * tries to remove one association from a widget, if it exists it is removed
+ * and the function returns true, if such an association doesn't exist false 
is returned
+ * and nothing is changed
+ */
+bool Widget::remove(const AssociationType& at, void* data) {
+
+  if (associationTableSize == 0) return false;
+
+  const size_t hash = (size_t)this % associationTableSize;
+
+  PrimaryAssociation* node = associationTable[hash];
+
+  while (node && node->wg != this) node = node->next;
+
+  if (!node) return false;
+
+  Association* ass = node->associations;
+  Association* prev = 0;
+
+  while (ass && ass->at != &at && ass->data != data) {
+    prev = ass;
+    ass = ass->next;
+  }
+
+  if (!ass) return false;
+
+  if (prev)
+    prev->next = ass->next;
+  else
+    node->associations = ass->next;
+
+  ass->at->destroy(ass->data);
+  delete ass;
+
+  return true;
+}
+
+/*!
+ * tries to find an association of this type with the given data
+ * if found the function returns true, else false
+ */
+bool Widget::find(const AssociationType& at, void* data) const {
+
+  if (associationTableSize == 0) return false;
+
+  const size_t hash = (size_t)this % associationTableSize;
+
+  PrimaryAssociation* node = associationTable[hash];
+
+  while (node && node->wg != this) node = node->next;
+
+  if (!node) return false;
+
+  Association* ass = node->associations;
+  Association* prev = 0;
+
+  while (ass && ass->at != &at && ass->data != data) {
+    prev = ass;
+    ass = ass->next;
+  }
+
+  return ass != 0;
+}
+
+
+/*!
   Call the functor for each piece of data of the give AssociationType.
   This is a wrapper for ::foreach(&at, this, fkt).
  */

Modified: trunk/test/menu.cxx
===================================================================
--- trunk/test/menu.cxx 2008-11-10 21:05:22 UTC (rev 6513)
+++ trunk/test/menu.cxx 2008-11-10 21:10:13 UTC (rev 6514)
@@ -81,6 +81,14 @@
 
 void quit_cb(Widget*, void*) {exit(0);}
 
+class ListShortcuts : public ShortcutFunctor {
+public:
+  bool handle(const Widget* widget, unsigned key) {
+    printf("Widget=%s shortcut=%s\n", widget->label() ? widget->label() : 
"NULL", key_name(key));
+    return false;
+  }
+} listShortcuts;
+
 int main(int argc, char **argv) {
   Window window(WIDTH,400);
   window.begin();
@@ -186,5 +194,7 @@
   window.end();
   window.show(argc, argv);
 
+  foreachShortcut(listShortcuts);
+
   return run();
 }

_______________________________________________
fltk-commit mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk-commit

Reply via email to