ecere/gui/Stacker: New Stacker implementation, adaptation of SelectorBar
authorRejean Loyer <rejean.loyer@gmail.com>
Sun, 12 Feb 2012 09:15:14 +0000 (16:15 +0700)
committerJerome St-Louis <jerome@ecere.com>
Sun, 12 Feb 2012 09:19:37 +0000 (16:19 +0700)
ecere/src/gui/controls/Stacker.ec
extras/gui/controls/SelectorBar.ec
ide/src/ProjectSettings.ec

index ef18651..0ea441a 100644 (file)
@@ -99,41 +99,56 @@ public:
 
 static define stackerScrolling = 16;
 
+class StackerBits
+{
+   bool reverse:1, scrollable:1, flipSpring:1, autoSize:1;
+
+   // internals
+   bool holdChildMonitoring:1;
+}
+
 public class Stacker : Window
 {
 public:
 
    property ScrollDirection direction { set { direction = value; } get { return direction; } };
    property int gap { set { gap = value; } get { return gap; } };
-   property bool reverse { set { reverse = value; } get { return reverse; } };
+   property bool reverse { set { bits.reverse = value; } get { return bits.reverse; } };
 
    property bool scrollable
    {
       set
       {
-         if(value != scrollable)
+         if(value != bits.scrollable)
          {
-            scrollable = value;
+            bits.scrollable = value;
             // how to recall these?
             //GetDecorationsSize(...);
             //SetWindowArea(...);
             OnResize(clientSize.w, clientSize.h);
          }
       }
-      get { return scrollable; }
+      get { return bits.scrollable; }
    }
 
    property Array<Window> controls { get { return controls; } };
 
+   property Window flipper { set { flipper = value; } get { return flipper; } };
+   property bool flipSpring { set { bits.flipSpring = value; } get { return bits.flipSpring; } };
+   property bool autoSize { set { bits.autoSize = value; } get { return bits.autoSize; } };
+   property int margin { set { margin = value; } get { return margin; } };
+
 private:
+   StackerBits bits;
    ScrollDirection direction;
    int gap;
-   bool scrollable;
+   int margin;
    Array<Window> controls { };
-   bool reverse;
+   Window flipper;
+
    RepButton left
    {
-      this, visible = false, bevelOver = true, nonClient = true, keyRepeat = true, opacity = 0;
+      nonClient = true, parent = this, visible = false, bevelOver = true, keyRepeat = true, opacity = 0;
 
       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
       {
@@ -154,7 +169,7 @@ private:
    };
    RepButton right
    {
-      this, visible = false, bevelOver = true, nonClient = true, keyRepeat = true, opacity = 0;
+      nonClient = true, parent = this, visible = false, bevelOver = true, keyRepeat = true, opacity = 0;
 
       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
       {
@@ -223,83 +238,122 @@ private:
    gap = 5;
    direction = vertical;
 
-   void OnResize(int width, int height)
+   void OnChildAddedOrRemoved(Window child, bool removed)
    {
-      if(created)
-      {
-         int y = 0;
-         Array<Window> oldControls = controls;
-         Array<Window> orderedControls;
-         Window child;
-
-         controls = { };     
+      if(!bits.holdChildMonitoring)
+         UpdateControls();
+   }
+   void OnChildVisibilityToggled(Window child, bool visible)
+   {
+      DoResize(size.w, size.h); // todo: improve with DoPartialResize(size.w, size.h, client);
+   }
+   void OnChildResized(Window child, int x, int y, int w, int h)
+   {
+      DoResize(size.w, size.h); // todo: improve with DoPartialResize(size.w, size.h, client);
+   }
 
-         for(c : oldControls)
+   void UpdateControls()
+   {
+      Window child;
+      Array<Window> newControls { };
+      for(c : controls)
+      {
+         for(child = firstChild; child; child = child.next)
          {
-            for(child = firstChild; child; child = child.next)
+            if(child.nonClient) continue;
+            if(c == child)
             {
-               if(child.nonClient || !child.visible /*|| !child.created*/) continue;
-               if(c == child)
-               {
-                  controls.Add(child);
-                  incref child;
-                  break;
-               }
+               newControls.Add(child);
+               break;
             }
          }
-         for(child = firstChild; child; child = child.next)
+         if(!child)
          {
-            if(child.nonClient || !child.visible /*|| !child.created*/) continue;
-            if(!controls.Find(child))
-            {
-               controls.Add(child);
-               incref child;
-            }
+            child = c;
+            delete child;
          }
-
-         oldControls.Free();
-         delete oldControls;
-
-         if(reverse)
+      }
+      for(child = firstChild; child; child = child.next)
+      {
+         if(child.nonClient) continue;
+         if(!newControls.Find(child))
          {
-            int c;
-            orderedControls = { };
-            for(c = controls.count-1; c >= 0; c--)
-            {
-               child = controls[c];
-               orderedControls.Add(child);
-               incref child;
-            }
+            newControls.Add(child);
+            incref child;
          }
-         else
-            orderedControls = controls;
-         
-         for(child : orderedControls)
+      }
+      delete controls;
+      controls = newControls;
+      newControls = null;
+   }
+
+   void OnResize(int width, int height)
+   {
+      DoResize(width, height);
+   }
+
+   void DoResize(int width, int height)
+   {
+      // TOIMPROVE: this needs to maintain an order and allow for dynamically adding
+      //            children. inserting in the order should also be possible.
+      // TOIMPROVE: in Window.ec... it should be possible to change the order of children
+      //            at runtime. it should also be possible to choose where dynamically
+      //            created children are inserted.
+
+      if(created)
+      {
+         int y, c;
+         bool r = bits.reverse;
+         int inc = bits.reverse ? -1 : 1;
+         Window child;
+         Window flip = null;
+
+         y = margin;
+         for(c = bits.reverse ? controls.count-1 : 0; c<controls.count && c>-1; c += inc)
          {
+            child = controls[c];
+            if(flip && child == flip) break;
+            if(child.nonClient || !child.visible) continue;
             if(direction == vertical)
             {
-               if(reverse)
-                  child.anchor.bottom = y;
-               else
-                  child.anchor.top = y;
+               if(bits.reverse) child.anchor.bottom = y;
+               else             child.anchor.top = y;
                y += child.size.h + gap;
             }
             else
             {
-               if(reverse)
-                  child.anchor.right = y;
-               else
-                  child.anchor.left = y;
+               if(bits.reverse) child.anchor.right = y;
+               else             child.anchor.left = y;
                y += child.size.w + gap;
             }
+            Flip(flipper, child, controls, margin, &bits, &inc, &c, &y, &flip);
          }
-         if(reverse)
+
+         if(flip)
          {
-            orderedControls.Free();
-            delete orderedControls;
+            if(bits.flipSpring)
+            {
+               if(direction == vertical)
+               {
+                  if(bits.reverse) flip.anchor.bottom = y;
+                  else             flip.anchor.top = y;
+               }
+               else
+               {
+                  if(bits.reverse) flip.anchor.right = y;
+                  else             flip.anchor.left = y;
+               }
+            }
+         }
+         else if(bits.autoSize)
+         {
+            if(direction == vertical)
+               this.clientSize.h = y - gap + margin;
+            else
+               this.clientSize.w = y - gap + margin;
          }
 
-         if(scrollable && y > ((direction == horizontal) ? width : height))
+         if(bits.scrollable && y > ((direction == horizontal) ? width : height))
          {
             scrollArea = (direction == horizontal) ? { y, 0 } : { 0, y };
             left.visible = true;
@@ -312,12 +366,12 @@ private:
             scrollArea = { 0, 0 };
          }
 
-         // FOR WHEN SCROLLING OCCURED
-         for(child : controls)
-            child.anchor = child.anchor;
-
-         if(scrollable)
+         if(bits.scrollable)
          {
+            // FOR WHEN SCROLLING OCCURED
+            for(child : controls)
+               child.anchor = child.anchor;
+
             if(direction == horizontal)
             {
                left.disabled = (scroll.x == 0);
@@ -338,6 +392,7 @@ private:
    {
       Window child, next;
 
+      bits.holdChildMonitoring = true;
       for(child = firstChild; child; child = next)
       {
          next = child ? child.next : null;
@@ -345,9 +400,9 @@ private:
          {
             child.Destroy(0);
             child.parent = null;
-            // delete child;
          }
       }
+      bits.holdChildMonitoring = true;
    }
 
    public void MakeControlVisible(Window control)
@@ -393,4 +448,49 @@ private:
          }
       }
    }
+
+   public Window GetNextStackedItem(Window current, bool previous, Class filter)
+   {
+      Window result = null;
+      Window next = null;
+      Window child;
+      bool direction = !(reverse^previous);
+      int c;
+      for(c = (!direction) ? controls.count-1 : 0; c<controls.count && c>-1; c += (!direction) ? -1 : 1)
+      {
+         child = controls[c];
+         if(child.nonClient || !child.created || !child.visible) continue;
+         if(filter && !eClass_IsDerived(child._class, filter)) continue;
+         next = child;
+         break;
+      }
+      if(current)
+      {
+         for(c = direction ? controls.count-1 : 0; c<controls.count && c>-1; c += direction ? -1 : 1)
+         {
+            child = controls[c];
+            if(child.nonClient || !child.created || !child.visible) continue;
+            if(!eClass_IsDerived(child._class, filter)) continue;
+            if(child == current)
+               break;
+            next = child;
+         }
+         result = next;
+      }
+      else
+         result = next;
+      return result;
+   }
+}
+
+static void Flip(Window flipper, Window child, Array<Window> controls, int margin, StackerBits * bits, int * inc, int * c, int * y, Window * flip)
+{
+   if(flipper && !*flip && child == flipper)
+   {
+      *flip = child;
+      (*bits).reverse = !(*bits).reverse;
+      *inc = (*bits).reverse ? -1 : 1;
+      *c = (*bits).reverse ? controls.count : -1;
+      *y = margin;
+   }
 }
index 71e1664..5a7539c 100644 (file)
@@ -26,8 +26,6 @@ static void DrawStipple(Surface surface, Size clientSize)
 
 public class SelectorBar : Stacker
 {
-   // We need this because Stacker incref's only when created
-   Array<SelectorButton> buttonsHolder { };
    direction = horizontal;
    background = activeBorder;
    //tabCycle = true;
@@ -53,12 +51,10 @@ public:
       Iterator<Window> it { controls };
       while(it.Next())
       {
-         SelectorButton button = (SelectorButton)it.data;
+         Window button = it.data;
          button.visible = false;
          button.Destroy(0);
       }
-      buttonsHolder.Free();
-      OnResize(clientSize.w, clientSize.h);
    }
 
    void Select(SelectorButton button)
@@ -71,24 +67,17 @@ public:
 
    void AddButton(SelectorButton button)
    {
-      incref button;
-      buttonsHolder.Add(button);
       if(created)
-      {
          button.Create();
-         // Find a more elegant manner to force updating of positions?
-         OnResize(clientSize.w, clientSize.h);
-      }
    }
 
    void RemoveButton(SelectorButton button)
    {
       Iterator<Window> it { controls };
-      buttonsHolder.TakeOut(button);
       while(it.Next())
       {
          if(button == (SelectorButton)it.data)
-         {                     
+         {
             if(it.Next() || (it.Prev() && it.Prev()))
             {
                SelectorButton newSelection = (SelectorButton)it.data;
@@ -100,37 +89,21 @@ public:
       }
       button.visible = false;
       button.Destroy(0);
-      delete button;
-      OnResize(clientSize.w, clientSize.h);
    }
 
    SelectorButton FindButtonByID(int id)
    {
       SelectorButton button = null;
-      
       Iterator<Window> it { controls };
       while(it.Next())
       {
-         SelectorButton b = (SelectorButton)it.data;
-         if(eClass_IsDerived(b._class, class(SelectorButton)) && b.id == id)
-         {                     
-            button = b;
-            break;
-         }
-      }
-      
-      // This alternate technique works outside but give very weird results when used inside. :S
-      /*
-      SelectorButton b;
-      for(b = (SelectorButton)firstChild; b; b = (SelectorButton)b.next)
-      {
+         Window b = it.data;
          if(eClass_IsDerived(b._class, class(SelectorButton)) && b.id == id)
          {
-            button = b;
+            button = (SelectorButton)b;
             break;
          }
       }
-      */
       return button;
    }
 
@@ -148,11 +121,15 @@ public:
          Iterator<Window> it { controls };
          while(it.Next())
          {
-            SelectorButton b = (SelectorButton)it.data;
-            if(eClass_IsDerived(b._class, class(SelectorButton)) && b.checked)
-            {                     
-               button = b;
-               break;
+            Window w = it.data;
+            if(eClass_IsDerived(w._class, class(SelectorButton)))
+            {
+               SelectorButton b = (SelectorButton)w;
+               if(b.checked)
+               {
+                  button = (SelectorButton)b;
+                  break;
+               }
             }
          }
          return button;
@@ -189,6 +166,7 @@ public:
          SelectorBar selector = (SelectorBar)parent;
          for(b = (SelectorButton)parent.firstChild; b; b = (SelectorButton)b.next)
          {
+            if(b.nonClient) continue;
             if(eClass_IsDerived(b._class, class(SelectorButton)) && b != this)
             {
                b.font = null;
@@ -196,17 +174,13 @@ public:
             }
          }
          font = { font.faceName, font.size, bold = true }; 
+         // this should not be required: the font change should resize the control and Stacker should adapt automatically
+         // why does it not?
          selector.OnResize(selector.clientSize.w, selector.clientSize.h);
          selector.MakeControlVisible(this);
       }
    };
 
-   watch(text)
-   {
-      if(parent && eClass_IsDerived(parent._class, class(SelectorBar)))
-         parent.OnResize(parent.clientSize.w, parent.clientSize.h);
-   };
-
    bool OnLeftButtonDown(int x, int y, Modifiers mods)
    {
       bool result;
@@ -274,10 +248,7 @@ class EditableSelectorButton : SelectorButton
                   SelectorBar selector = (SelectorBar)parent;
                   text = newName;
                   if(selector)
-                  {
-                     selector.OnResize(selector.clientSize.w, selector.clientSize.h);
                      selector.MakeControlVisible(this);
-                  }
                }
                
                delete oldName;
index 9ac14c2..d0de689 100644 (file)
@@ -1293,7 +1293,6 @@ class BuildTab : Tab
                   {                     
                      button.visible = false;
                      button.Destroy(0);
-                     delete button;
 
                      if(it.Prev())
                      {