-#ifndef ITEM_MODALCONTROLLER_H
-#define ITEM_MODALCONTROLLER_H
-#include "container.qc"
-CLASS(ModalController, Container)
- METHOD(ModalController, resizeNotify, void(entity, vector, vector, vector, vector));
- METHOD(ModalController, draw, void(entity));
- METHOD(ModalController, showChild, void(entity, entity, vector, vector, float));
- METHOD(ModalController, hideChild, void(entity, entity, float));
- METHOD(ModalController, hideAll, void(entity, float));
- METHOD(ModalController, addItem, void(entity, entity, vector, vector, float));
- METHOD(ModalController, addTab, void(entity, entity, entity));
+#include "modalcontroller.qh"
- METHOD(ModalController, initializeDialog, void(entity, entity));
+#include "button.qh"
- METHOD(ModalController, switchState, void(entity, entity, float, float));
- ATTRIB(ModalController, origin, vector, '0 0 0')
- ATTRIB(ModalController, size, vector, '0 0 0')
- ATTRIB(ModalController, previousButton, entity, NULL)
- ATTRIB(ModalController, fadedAlpha, float, 0.3)
-ENDCLASS(ModalController)
+ .vector ModalController_initialSize;
+ .vector ModalController_initialOrigin;
+ .vector ModalController_initialFontScale;
+ .float ModalController_initialAlpha;
+ .vector ModalController_buttonSize;
+ .vector ModalController_buttonOrigin;
+ .float ModalController_state;
+ .float ModalController_factor;
+ .entity ModalController_controllingButton;
-.entity tabSelectingButton;
-.vector origin;
-.vector size;
-void TabButton_Click(entity button, entity tab); // assumes a button has set the above fields to its own absolute origin, its size, and the tab to activate
-void DialogOpenButton_Click(entity button, entity tab); // assumes a button has set the above fields to its own absolute origin, its size, and the tab to activate
-void DialogOpenButton_Click_withCoords(entity button, entity tab, vector theOrigin, vector theSize);
-void DialogCloseButton_Click(entity button, entity tab); // assumes a button has set the above fields to the tab to close
-#endif
-
-#ifdef IMPLEMENTATION
-
-// modal dialog controller
-// handles a stack of dialog elements
-// each element can have one of the following states:
-// 0: hidden (fading out)
-// 1: visible (zooming in)
-// 2: greyed out (inactive)
-// While an animation is running, no item has focus. When an animation is done,
-// the topmost item gets focus.
-// The items are assumed to be added in overlapping order, that is, the lowest
-// window must get added first.
-//
-// Possible uses:
-// - to control a modal dialog:
-// - show modal dialog: me.showChild(me, childItem, buttonAbsOrigin, buttonAbsSize, 0) // childItem also gets focus
-// - dismiss modal dialog: me.hideChild(me, childItem, 0) // childItem fades out and relinquishes focus
-// - show first screen in m_show: me.hideAll(me, 1); me.showChild(me, me.firstChild, '0 0 0', '0 0 0', 1);
-// - to show a temporary dialog instead of the menu (teamselect): me.hideAll(me, 1); me.showChild(me, teamSelectDialog, '0 0 0', '0 0 0', 1);
-// - as a tabbed dialog control:
-// - to initialize: me.hideAll(me, 1); me.showChild(me, me.firstChild, '0 0 0', '0 0 0', 1);
-// - to show a tab: me.hideChild(me, currentTab, 0); me.showChild(me, newTab, buttonAbsOrigin, buttonAbsSize, 0);
-
-.vector ModalController_initialSize;
-.vector ModalController_initialOrigin;
-.vector ModalController_initialFontScale;
-.float ModalController_initialAlpha;
-.vector ModalController_buttonSize;
-.vector ModalController_buttonOrigin;
-.float ModalController_state;
-.float ModalController_factor;
-.entity ModalController_controllingButton;
-
-void ModalController_initializeDialog(entity me, entity root)
-{
- me.hideAll(me, 1);
- me.showChild(me, root, '0 0 0', '0 0 0', 1); // someone else animates for us
-}
-
-void TabButton_Click(entity button, entity tab)
-{
- if(tab.ModalController_state == 1)
- return;
- tab.parent.hideAll(tab.parent, 0);
- button.forcePressed = 1;
- tab.ModalController_controllingButton = button;
- tab.parent.showChild(tab.parent, tab, button.origin, button.size, 0);
-}
-
-void DialogOpenButton_Click(entity button, entity tab)
-{
- DialogOpenButton_Click_withCoords(button, tab, button.origin, button.size);
-}
+ void ModalController_initializeDialog(entity me, entity root)
+ {
+ me.hideAll(me, 1);
+ me.showChild(me, root, '0 0 0', '0 0 0', 1); // someone else animates for us
+ }
-void DialogOpenButton_Click_withCoords(entity button, entity tab, vector theOrigin, vector theSize)
-{
- if(tab.ModalController_state)
- return;
- if(button)
+ void TabButton_Click(entity button, entity tab)
+ {
+ if (tab.ModalController_state == 1) return;
+ tab.parent.hideAll(tab.parent, 0);
button.forcePressed = 1;
- if(tab.parent.focusedChild)
- tab.parent.focusedChild.saveFocus(tab.parent.focusedChild);
- tab.ModalController_controllingButton = button;
- tab.parent.showChild(tab.parent, tab, theOrigin, theSize, 0);
-}
+ tab.ModalController_controllingButton = button;
+ tab.parent.showChild(tab.parent, tab, button.origin, button.size, 0);
+ }
-void DialogCloseButton_Click(entity button, entity tab)
-{
- tab.parent.hideChild(tab.parent, tab, 0);
-}
+ void DialogOpenButton_Click(entity button, entity tab)
+ {
+ DialogOpenButton_Click_withCoords(button, tab, button.origin, button.size);
+ }
-void ModalController_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
- me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, ModalController_initialOrigin, ModalController_initialSize, ModalController_initialFontScale);
-}
+ void DialogOpenButton_Click_withCoords(entity button, entity tab, vector theOrigin, vector theSize)
+ {
+ if (tab.ModalController_state) return;
+ if (button) button.forcePressed = 1;
+ if (tab.parent.focusedChild) tab.parent.focusedChild.saveFocus(tab.parent.focusedChild);
+ tab.ModalController_controllingButton = button;
+ tab.parent.showChild(tab.parent, tab, theOrigin, theSize, 0);
+ }
-void ModalController_switchState(entity me, entity other, float state, float skipAnimation)
-{
- float previousState;
- previousState = other.ModalController_state;
- if(state == previousState && !skipAnimation)
- return;
- other.ModalController_state = state;
- switch(state)
+ void DialogCloseButton_Click(entity button, entity tab)
{
- case 0:
- other.ModalController_factor = 1 - other.Container_alpha / other.ModalController_initialAlpha;
- // fading out
- break;
- case 1:
- other.ModalController_factor = other.Container_alpha / other.ModalController_initialAlpha;
- if(previousState == 0 && !skipAnimation)
- {
- other.Container_origin = other.ModalController_buttonOrigin;
- other.Container_size = other.ModalController_buttonSize;
- }
- // zooming in
- break;
- case 2:
- other.ModalController_factor = bound(0, (1 - other.Container_alpha / other.ModalController_initialAlpha) / me.fadedAlpha, 1);
- // fading out halfway
- break;
+ tab.parent.hideChild(tab.parent, tab, 0);
}
- if(skipAnimation)
- other.ModalController_factor = 1;
-}
-void ModalController_draw(entity me)
-{
- entity e;
- entity front;
- float animating;
- float f; // animation factor
- float df; // animation step size
- float prevFactor, targetFactor;
- vector targetOrigin, targetSize; float targetAlpha;
- vector fs;
- animating = 0;
+ void ModalController_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+ {
+ me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, ModalController_initialOrigin, ModalController_initialSize, ModalController_initialFontScale);
+ }
- front = world;
- for(e = me.firstChild; e; e = e.nextSibling)
- if(e.ModalController_state)
+ void ModalController_switchState(entity me, entity other, float state, float skipAnimation)
+ {
+ float previousState;
+ previousState = other.ModalController_state;
+ if (state == previousState && !skipAnimation) return;
+ other.ModalController_state = state;
+ switch (state)
{
- if(front)
- me.switchState(me, front, 2, 0);
- front = e;
+ case 0:
+ other.ModalController_factor = 1 - other.Container_alpha / other.ModalController_initialAlpha;
+ // fading out
+ break;
+ case 1:
+ other.ModalController_factor = other.Container_alpha / other.ModalController_initialAlpha;
+ if (previousState == 0 && !skipAnimation)
+ {
+ other.Container_origin = other.ModalController_buttonOrigin;
+ other.Container_size = other.ModalController_buttonSize;
+ }
+ // zooming in
+ break;
+ case 2:
+ other.ModalController_factor = bound(0, (1 - other.Container_alpha / other.ModalController_initialAlpha) / me.fadedAlpha, 1);
+ // fading out halfway
+ break;
}
- if(front)
- me.switchState(me, front, 1, 0);
-
- df = frametime * 3; // animation speed
+ if (skipAnimation) other.ModalController_factor = 1;
+ }
- for(e = me.firstChild; e; e = e.nextSibling)
+ void ModalController_draw(entity me)
{
- if(e.ModalController_state == 2)
- {
- // fading out partially
- targetOrigin = e.Container_origin; // stay as is
- targetSize = e.Container_size; // stay as is
- targetAlpha = me.fadedAlpha * e.ModalController_initialAlpha;
- }
- else if(e.ModalController_state == 1)
- {
- // zooming in
- targetOrigin = e.ModalController_initialOrigin;
- targetSize = e.ModalController_initialSize;
- targetAlpha = e.ModalController_initialAlpha;
- }
- else
- {
- // fading out
- targetOrigin = e.Container_origin; // stay as is
- targetSize = e.Container_size; // stay as is
- targetAlpha = 0;
- }
+ entity e;
+ entity front;
+ float animating;
+ float f; // animation factor
+ float df; // animation step size
+ float prevFactor, targetFactor;
+ vector targetOrigin, targetSize;
+ float targetAlpha;
+ vector fs;
+ animating = 0;
+
+ front = NULL;
+ for (e = me.firstChild; e; e = e.nextSibling)
+ if (e.ModalController_state)
+ {
+ if (front) me.switchState(me, front, 2, 0);
+ front = e;
+ }
+ if (front) me.switchState(me, front, 1, 0);
- f = (e.ModalController_factor = min(1, e.ModalController_factor + df));
- if(f == 1)
- {
- prevFactor = 0;
- targetFactor = 1;
- e.Container_origin = targetOrigin;
- e.Container_size = targetSize;
- me.setAlphaOf(me, e, targetAlpha);
- }
- else
+ df = frametime * 3; // animation speed
+
+ for (e = me.firstChild; e; e = e.nextSibling)
{
- prevFactor = (1 - f) / (1 - f + df);
- if(!e.ModalController_state) // optimize code and avoid precision errors
- me.setAlphaOf(me, e, e.Container_alpha * prevFactor);
+ if (e.ModalController_state == 2)
+ {
+ // fading out partially
+ targetOrigin = e.Container_origin; // stay as is
+ targetSize = e.Container_size; // stay as is
+ targetAlpha = me.fadedAlpha * e.ModalController_initialAlpha;
+ }
+ else if (e.ModalController_state == 1)
+ {
+ // zooming in
+ targetOrigin = e.ModalController_initialOrigin;
+ targetSize = e.ModalController_initialSize;
+ targetAlpha = e.ModalController_initialAlpha;
+ }
else
{
- animating = 1;
- targetFactor = df / (1 - f + df);
+ // fading out
+ targetOrigin = e.Container_origin; // stay as is
+ targetSize = e.Container_size; // stay as is
+ targetAlpha = 0;
+ }
- if(e.ModalController_state == 1)
+ f = (e.ModalController_factor = min(1, e.ModalController_factor + df));
+ if (f == 1)
+ {
+ prevFactor = 0;
+ targetFactor = 1;
+ e.Container_origin = targetOrigin;
+ e.Container_size = targetSize;
+ me.setAlphaOf(me, e, targetAlpha);
+ }
+ else
+ {
+ prevFactor = (1 - f) / (1 - f + df);
+ if (!e.ModalController_state) // optimize code and avoid precision errors
{
- e.Container_origin = e.Container_origin * prevFactor + targetOrigin * targetFactor;
- e.Container_size = e.Container_size * prevFactor + targetSize * targetFactor;
+ me.setAlphaOf(me, e, e.Container_alpha * prevFactor);
}
- me.setAlphaOf(me, e, e.Container_alpha * prevFactor + targetAlpha * targetFactor);
+ else
+ {
+ animating = 1;
+ targetFactor = df / (1 - f + df);
+
+ if (e.ModalController_state == 1)
+ {
+ e.Container_origin = e.Container_origin * prevFactor + targetOrigin * targetFactor;
+ e.Container_size = e.Container_size * prevFactor + targetSize * targetFactor;
+ }
+ me.setAlphaOf(me, e, e.Container_alpha * prevFactor + targetAlpha * targetFactor);
+ }
+ }
+ // assume: o == to * f_prev + X * (1 - f_prev)
+ // make: o' = to * f + X * (1 - f)
+ // -->
+ // X == (o - to * f_prev) / (1 - f_prev)
+ // o' = to * f + (o - to * f_prev) / (1 - f_prev) * (1 - f)
+ // --> (maxima)
+ // o' = (to * (f - f_prev) + o * (1 - f)) / (1 - f_prev)
+
+ if (e.ModalController_state == 1)
+ {
+ fs = globalToBoxSize(e.Container_size, e.ModalController_initialSize);
+ e.Container_fontscale_x = fs.x * e.ModalController_initialFontScale.x;
+ e.Container_fontscale_y = fs.y * e.ModalController_initialFontScale.y;
}
}
- // assume: o == to * f_prev + X * (1 - f_prev)
- // make: o' = to * f + X * (1 - f)
- // -->
- // X == (o - to * f_prev) / (1 - f_prev)
- // o' = to * f + (o - to * f_prev) / (1 - f_prev) * (1 - f)
- // --> (maxima)
- // o' = (to * (f - f_prev) + o * (1 - f)) / (1 - f_prev)
- if(e.ModalController_state == 1)
+ if (animating || !me.focused) me.setFocus(me, NULL);
+ else me.setFocus(me, front);
+ SUPER(ModalController).draw(me);
+ }
+
+ void ModalController_addTab(entity me, entity other, entity tabButton)
+ {
+ me.addItem(me, other, '0 0 0', '1 1 1', 1);
+ tabButton.onClick = TabButton_Click;
+ tabButton.onClickEntity = other;
+ other.tabSelectingButton = tabButton;
+ if (other == me.firstChild)
{
- fs = globalToBoxSize(e.Container_size, e.ModalController_initialSize);
- e.Container_fontscale_x = fs.x * e.ModalController_initialFontScale.x;
- e.Container_fontscale_y = fs.y * e.ModalController_initialFontScale.y;
+ tabButton.forcePressed = 1;
+ other.ModalController_controllingButton = tabButton;
+ me.showChild(me, other, '0 0 0', '0 0 0', 1);
}
}
- if(animating || !me.focused)
- me.setFocus(me, NULL);
- else
- me.setFocus(me, front);
- SUPER(ModalController).draw(me);
-}
-
-void ModalController_addTab(entity me, entity other, entity tabButton)
-{
- me.addItem(me, other, '0 0 0', '1 1 1', 1);
- tabButton.onClick = TabButton_Click;
- tabButton.onClickEntity = other;
- other.tabSelectingButton = tabButton;
- if(other == me.firstChild)
+ void ModalController_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
{
- tabButton.forcePressed = 1;
- other.ModalController_controllingButton = tabButton;
- me.showChild(me, other, '0 0 0', '0 0 0', 1);
+ SUPER(ModalController).addItem(me, other, theOrigin, theSize, (other == me.firstChild) ? theAlpha : 0);
+ other.ModalController_initialFontScale = other.Container_fontscale;
+ other.ModalController_initialSize = other.Container_size;
+ other.ModalController_initialOrigin = other.Container_origin;
+ other.ModalController_initialAlpha = theAlpha; // hope Container never modifies this
+ if (other.ModalController_initialFontScale == '0 0 0') other.ModalController_initialFontScale = '1 1 0';
}
-}
-void ModalController_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
-{
- SUPER(ModalController).addItem(me, other, theOrigin, theSize, (other == me.firstChild) ? theAlpha : 0);
- other.ModalController_initialFontScale = other.Container_fontscale;
- other.ModalController_initialSize = other.Container_size;
- other.ModalController_initialOrigin = other.Container_origin;
- other.ModalController_initialAlpha = theAlpha; // hope Container never modifies this
- if(other.ModalController_initialFontScale == '0 0 0')
- other.ModalController_initialFontScale = '1 1 0';
-}
-
-void ModalController_showChild(entity me, entity other, vector theOrigin, vector theSize, float skipAnimation)
-{
- if(other.ModalController_state == 0 || skipAnimation)
+ void ModalController_showChild(entity me, entity other, vector theOrigin, vector theSize, float skipAnimation)
{
- me.setFocus(me, NULL);
- if(!skipAnimation)
+ if (other.ModalController_state == 0 || skipAnimation)
{
- other.ModalController_buttonOrigin = globalToBox(theOrigin, me.origin, me.size);
- other.ModalController_buttonSize = globalToBoxSize(theSize, me.size);
- }
- me.switchState(me, other, 1, skipAnimation);
- } // zoom in from button (factor increases)
-}
+ me.setFocus(me, NULL);
+ if (!skipAnimation)
+ {
+ other.ModalController_buttonOrigin = globalToBox(theOrigin, me.origin, me.size);
+ other.ModalController_buttonSize = globalToBoxSize(theSize, me.size);
+ }
+ me.switchState(me, other, 1, skipAnimation);
+ } // zoom in from button (factor increases)
+ }
-void ModalController_hideAll(entity me, float skipAnimation)
-{
- entity e;
- for(e = me.firstChild; e; e = e.nextSibling)
- me.hideChild(me, e, skipAnimation);
-}
+ void ModalController_hideAll(entity me, float skipAnimation)
+ {
+ entity e;
+ for (e = me.firstChild; e; e = e.nextSibling)
+ me.hideChild(me, e, skipAnimation);
+ }
-void ModalController_hideChild(entity me, entity other, float skipAnimation)
-{
- if(other.ModalController_state || skipAnimation)
+ void ModalController_hideChild(entity me, entity other, float skipAnimation)
{
- me.setFocus(me, NULL);
- me.switchState(me, other, 0, skipAnimation);
- if(other.ModalController_controllingButton)
+ if (other.ModalController_state || skipAnimation)
{
- other.ModalController_controllingButton.forcePressed = 0;
- other.ModalController_controllingButton = NULL;
- }
- } // just alpha fade out (factor increases and decreases alpha)
-}
-#endif
+ me.setFocus(me, NULL);
+ me.switchState(me, other, 0, skipAnimation);
+ if (other.ModalController_controllingButton)
+ {
+ other.ModalController_controllingButton.forcePressed = 0;
+ other.ModalController_controllingButton = NULL;
+ }
+ } // just alpha fade out (factor increases and decreases alpha)
+ }