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)
{
};
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)
{
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;
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);
{
Window child, next;
+ bits.holdChildMonitoring = true;
for(child = firstChild; child; child = next)
{
next = child ? child.next : null;
{
child.Destroy(0);
child.parent = null;
- // delete child;
}
}
+ bits.holdChildMonitoring = true;
}
public void MakeControlVisible(Window control)
}
}
}
+
+ 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;
+ }
}
public class SelectorBar : Stacker
{
- // We need this because Stacker incref's only when created
- Array<SelectorButton> buttonsHolder { };
direction = horizontal;
background = activeBorder;
//tabCycle = true;
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)
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;
}
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;
}
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;
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;
}
}
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;
SelectorBar selector = (SelectorBar)parent;
text = newName;
if(selector)
- {
- selector.OnResize(selector.clientSize.w, selector.clientSize.h);
selector.MakeControlVisible(this);
- }
}
delete oldName;