ecere/gui/controls/Stacker: Freeing space for scrollers when not needed
[sdk] / ecere / src / gui / controls / Stacker.ec
index 449e030..fa89484 100644 (file)
@@ -10,92 +10,7 @@ public import "ecere"
 #endif
 #endif
 
-public class RepButton : Button
-{
-public:
-   bool pressing;
-   isRemote = true;
-   inactive = true;
-   
-   property Seconds delay { set { timer2.delay = value; } }
-   property Seconds delay0 { set { timer.delay = value; } }
-   
-   bool OnKeyHit(Key key, unichar ch)
-   {
-      return true;
-   }
-
-   bool OnKeyDown(Key key, unichar ch)
-   {
-      if(key == hotKey)
-      {
-         NotifyPushed(master, this, 0,0, key.modifiers);
-         return false;
-      }
-      return true;
-   }
-
-   bool OnKeyUp(Key key, unichar ch)
-   {
-      if(key == hotKey)
-      {
-         NotifyReleased(master, this, 0,0, key.modifiers);
-         return false;
-      }
-      return true;
-   }
-
-   bool NotifyPushed(RepButton button, int x, int y, Modifiers mods)
-   {
-      button.pressing = true;
-      button.NotifyClicked(this, button, x, y, mods);
-      button.timer.Start();
-      return true;
-   }
-
-   bool NotifyMouseLeave(RepButton button, Modifiers mods)
-   {
-      button.timer.Stop();
-      button.timer2.Stop();
-      return true;
-   }
-
-   bool NotifyReleased(RepButton button, int x, int y, Modifiers mods)
-   {
-      button.pressing = false;
-      button.NotifyMouseLeave(this, button, mods);
-      return false;
-   }
-
-   bool NotifyMouseOver(RepButton button, int x, int y, Modifiers mods)
-   {
-      if(button.pressing)
-         button.timer2.Start();
-      return true;
-   }
-
-   Timer timer
-   {
-      this, delay = 0.1;
-
-      bool DelayExpired()
-      {
-         timer.Stop();
-         timer2.Start();
-         timer2.DelayExpired(this);
-         return true;
-      }
-   };
-   Timer timer2
-   {
-      this, delay = 0.1;
-      bool DelayExpired()
-      {
-         NotifyClicked(master, this, 0, 0, 0);
-         return true;
-      }
-   };
-}
+// class RepButton WAS ALREADY DEFINED IN date.ec! The version here broke CalendarControl behavior.
 
 static define stackerScrolling = 16;
 
@@ -201,7 +116,7 @@ private:
 
    RepButton left
    {
-      nonClient = true, parent = this, visible = false, bevelOver = true, keyRepeat = true, opacity = 0;
+      nonClient = true, parent = this, visible = false, bevelOver = true, keyRepeat = true, opacity = 0; delay0 = 0.1;
 
       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
       {
@@ -222,7 +137,7 @@ private:
    };
    RepButton right
    {
-      nonClient = true, parent = this, visible = false, bevelOver = true, keyRepeat = true, opacity = 0;
+      nonClient = true, parent = this, visible = false, bevelOver = true, keyRepeat = true, opacity = 0; delay0 = 0.1;
 
       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
       {
@@ -247,7 +162,7 @@ private:
    void GetDecorationsSize(MinMaxValue * w, MinMaxValue * h)
    {
       Window::GetDecorationsSize(w, h);
-      if(bits.scrollable && bits.endButtons)
+      if(bits.scrollable && bits.endButtons && left.visible)
       {
          if(direction == vertical) *h += left.size.h + right.size.h + 8; else *w += left.size.w + right.size.w + 8;
       }
@@ -256,7 +171,7 @@ private:
    void SetWindowArea(int * x, int * y, MinMaxValue * w, MinMaxValue * h, MinMaxValue * cw, MinMaxValue * ch)
    {
       Window::SetWindowArea(x, y, w, h, cw, ch);
-      if(bits.scrollable && bits.endButtons)
+      if(bits.scrollable && bits.endButtons && left.visible)
       {
          if(direction == vertical) *y += left.size.h + 4; else *x += left.size.w + 4;
       }
@@ -267,8 +182,15 @@ private:
       controls.Free();
    }
 
+   bool OnCreate()
+   {
+      bits.holdChildMonitoring = true;
+      return true;
+   }
+
    bool OnPostCreate()
    {
+      bits.holdChildMonitoring = false;
       OnResize(clientSize.w, clientSize.h);
 
       if(direction == vertical)
@@ -296,21 +218,47 @@ private:
 
    void OnChildAddedOrRemoved(Window child, bool removed)
    {
-      if(!bits.holdChildMonitoring)
-         UpdateControls();
+      if(!child.nonClient)
+      {
+         if(removed)
+         {
+            if((child.destroyed && !destroyed) || child.parent != this)
+            {
+               Iterator<Window> it { controls };
+               if(it.Find(child))
+               {
+                  it.Remove();
+                  delete child;
+               }
+            }
+         }
+         else
+         {
+            if((child.created || (!created && child.autoCreate)) && !child.destroyed && child.parent == this)
+            {
+               if(!controls.Find(child))
+               {
+                  controls.Add(child);
+                  incref child;
+               }
+            }
+         }
+         if(!bits.holdChildMonitoring)
+            DoResize(size.w, size.h);
+      }
    }
    void OnChildVisibilityToggled(Window child, bool visible)
    {
       DoResize(size.w, size.h); // todo: improve with DoPartialResize(size.w, size.h, client);
-      size = size;   // TRIGGER SCROLLING UPDATE (Currently required since we aren't using Window scrollbars)
+      // size = size;   // TRIGGER SCROLLING UPDATE (Currently required since we aren't using Window scrollbars)
    }
    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);
-      size = size;   // TRIGGER SCROLLING UPDATE (Currently required since we aren't using Window scrollbars)
+      // size = size;   // TRIGGER SCROLLING UPDATE (Currently required since we aren't using Window scrollbars)
    }
 
-   void UpdateControls()
+   /*void UpdateControls()
    {
       Window child;
       Array<Window> newControls { };
@@ -346,16 +294,24 @@ private:
       delete controls;
       controls = newControls;
       newControls = null;
-   }
+   }*/
 
    void OnResize(int width, int height)
    {
-      if(!inAutoSize)
+      if(!bits.holdChildMonitoring && !inAutoSize)
          DoResize(width, height);
    }
 
    void DoResize(int width, int height)
    {
+      if(left.visible)
+      {
+         // Take into consideration the space we would gain back by getting rid of the scrolling buttons
+         if(direction == horizontal)
+            width += 2 * (left.size.w + 4);
+         else
+            height += 2 * (left.size.h + 4);
+      }
       // 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
@@ -364,23 +320,21 @@ private:
 
       if(created)
       {
-         int y, c;
+         int y = margin, 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)
+         for(c = r ? controls.count-1 : 0; c<controls.count && c>-1; c += inc)
          {
             Anchor anchor;
-            child = controls[c];
+            Window child = controls[c];
             if(flip && child == flip) break;
             if(child.nonClient || !child.visible) continue;
             anchor = child.anchor;
             if(direction == vertical)
             {
-               if(bits.reverse)
+               if(r)
                {
                   if(!anchor.bottom.type || anchor.bottom.distance != y)
                      child.anchor.bottom = y;
@@ -394,7 +348,7 @@ private:
             }
             else
             {
-               if(bits.reverse)
+               if(r)
                {
                   if(!anchor.right.type || anchor.right.distance != y)
                      child.anchor.right = y;
@@ -406,7 +360,14 @@ private:
                }
                y += child.size.w + gap;
             }
-            Flip(flipper, child, controls, margin, &bits, &inc, &c, &y, &flip);
+            // If this child is the flipper, we flip
+            if(flipper && !flip && child == flipper)
+            {
+               flip = child;
+               if(r) { r = false; inc = 1; c = -1; }
+               else  { r = true;  inc =-1; c = controls.count; }
+               y = margin;
+            }
          }
 
          if(flip)
@@ -415,13 +376,13 @@ private:
             {
                if(direction == vertical)
                {
-                  if(bits.reverse) flip.anchor.bottom = y;
-                  else             flip.anchor.top = y;
+                  if(r) flip.anchor.bottom = y;
+                  else  flip.anchor.top = y;
                }
                else
                {
-                  if(bits.reverse) flip.anchor.right = y;
-                  else             flip.anchor.left = y;
+                  if(r) flip.anchor.right = y;
+                  else  flip.anchor.left = y;
                }
             }
          }
@@ -434,7 +395,6 @@ private:
             else
                //this.clientSize.w = y - gap + margin;
                this.size.w = y - gap + margin + (this.size.w - this.clientSize.w);
-            //Update(null);
             inAutoSize = false;
          }
 
@@ -478,19 +438,36 @@ private:
 
    public void DestroyChildren()
    {
-      Window child, next;
-
-      bits.holdChildMonitoring = true;
-      for(child = firstChild; child; child = next)
+      // This safe loop with 'left' will jam if the Stacker is destroyed
+      if(!destroyed && created)
       {
-         next = child ? child.next : null;
-         if(!child.nonClient)
+         bool left = true;
+         while(left)
          {
-            child.Destroy(0);
-            child.parent = null;
+            left = false;
+            for(w : controls)
+            {
+               if(!w.destroyed && w.created)
+               {
+                  w.Destroy(0);
+                  left = true;
+                  break;
+               }
+            }
+         }
+      }
+      else
+      {
+         // If the stacker is already destroyed, just clear everything
+         Iterator<Window> it { controls };
+         while(it.pointer = null, it.Next())
+         {
+            Window w = it.data;
+            it.Remove();
+            w.Destroy(0);
+            delete w;
          }
       }
-      bits.holdChildMonitoring = false;
    }
 
    public void MakeControlVisible(Window control)
@@ -570,15 +547,3 @@ private:
       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;
-   }
-}