#ifdef INTERFACE CLASS(Container) EXTENDS(Item) METHOD(Container, draw, void(entity)) METHOD(Container, keyUp, float(entity, float, float, float)) METHOD(Container, keyDown, float(entity, float, float, float)) METHOD(Container, mouseMove, float(entity, vector)) METHOD(Container, mousePress, float(entity, vector)) METHOD(Container, mouseDrag, float(entity, vector)) METHOD(Container, mouseRelease, float(entity, vector)) METHOD(Container, focusLeave, void(entity)) METHOD(Container, resizeNotify, void(entity, vector, vector, vector, vector)) METHOD(Container, resizeNotifyLie, void(entity, vector, vector, vector, vector, .vector, .vector)) METHOD(Container, addItem, void(entity, entity, vector, vector, float)) METHOD(Container, addItemCentered, void(entity, entity, vector, float)) METHOD(Container, moveItemAfter, void(entity, entity, entity)) METHOD(Container, removeItem, void(entity, entity)) METHOD(Container, setFocus, void(entity, entity)) METHOD(Container, setAlphaOf, void(entity, entity, float)) METHOD(Container, itemFromPoint, entity(entity, vector)) METHOD(Container, showNotify, void(entity)) METHOD(Container, hideNotify, void(entity)) METHOD(Container, preferredFocusedGrandChild, entity(entity)) ATTRIB(Container, focusable, float, 0) ATTRIB(Container, firstChild, entity, NULL) ATTRIB(Container, lastChild, entity, NULL) ATTRIB(Container, focusedChild, entity, NULL) ATTRIB(Container, shown, float, 0) ENDCLASS(Container) .entity nextSibling; .entity prevSibling; .float resized; .vector Container_origin; .vector Container_size; .vector Container_fontscale; .float Container_alpha; #endif #ifdef IMPLEMENTATION void Container_showNotify(entity me) { entity e; if(me.shown) return; me.shown = 1; for(e = me.firstChild; e; e = e.nextSibling) if(e.Container_alpha > 0) e.showNotify(e); } void Container_hideNotify(entity me) { entity e; if not(me.shown) return; me.shown = 0; for(e = me.firstChild; e; e = e.nextSibling) if(e.Container_alpha > 0) e.hideNotify(e); } void Container_setAlphaOf(entity me, entity other, float theAlpha) { if(theAlpha <= 0) { if(other.Container_alpha > 0) other.hideNotify(other); } else // value > 0 { if(other.Container_alpha <= 0) other.showNotify(other); } other.Container_alpha = theAlpha; } void Container_resizeNotifyLie(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize, .vector originField, .vector sizeField) { entity e; vector o, s; float d; for(e = me.firstChild; e; e = e.nextSibling) { o = e.originField; s = e.sizeField; e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize)); } do { d = 0; for(e = me.firstChild; e; e = e.nextSibling) if(e.resized) { e.resized = 0; d = 1; o = e.originField; s = e.sizeField; e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize)); } } while(d); SUPER(Container).resizeNotify(me, relOrigin, relSize, absOrigin, absSize); } void Container_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize) { me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, Container_origin, Container_size); } entity Container_itemFromPoint(entity me, vector pos) { entity e; vector o, s; for(e = me.lastChild; e; e = e.prevSibling) { o = e.Container_origin; s = e.Container_size; if(pos_x < o_x) continue; if(pos_y < o_y) continue; if(pos_x >= o_x + s_x) continue; if(pos_y >= o_y + s_y) continue; return e; } return NULL; } void Container_draw(entity me) { vector oldshift; vector oldscale; float oldalpha; vector oldfontscale; entity e; oldshift = draw_shift; oldscale = draw_scale; oldalpha = draw_alpha; oldfontscale = draw_fontscale; me.focusable = 0; for(e = me.firstChild; e; e = e.nextSibling) { if(e.focusable) me.focusable += 1; if(e.Container_alpha < 0.003) // can't change color values anyway continue; draw_shift = boxToGlobal(e.Container_origin, oldshift, oldscale); draw_scale = boxToGlobalSize(e.Container_size, oldscale); if(e.Container_fontscale != '0 0 0') draw_fontscale = boxToGlobalSize(e.Container_fontscale, oldfontscale); draw_alpha *= e.Container_alpha; e.draw(e); draw_shift = oldshift; draw_scale = oldscale; draw_fontscale = oldfontscale; draw_alpha = oldalpha; } }; void Container_focusLeave(entity me) { me.setFocus(me, NULL); } float Container_keyUp(entity me, float scan, float ascii, float shift) { entity f; f = me.focusedChild; if(f) return f.keyUp(f, scan, ascii, shift); return 0; } float Container_keyDown(entity me, float scan, float ascii, float shift) { entity f; f = me.focusedChild; if(f) return f.keyDown(f, scan, ascii, shift); return 0; } float Container_mouseMove(entity me, vector pos) { entity f; f = me.focusedChild; if(f) return f.mouseMove(f, globalToBox(pos, f.Container_origin, f.Container_size)); return 0; } float Container_mousePress(entity me, vector pos) { entity f; f = me.focusedChild; if(f) return f.mousePress(f, globalToBox(pos, f.Container_origin, f.Container_size)); return 0; } float Container_mouseDrag(entity me, vector pos) { entity f; f = me.focusedChild; if(f) return f.mouseDrag(f, globalToBox(pos, f.Container_origin, f.Container_size)); return 0; } float Container_mouseRelease(entity me, vector pos) { entity f; f = me.focusedChild; if(f) return f.mouseRelease(f, globalToBox(pos, f.Container_origin, f.Container_size)); return 0; } void Container_addItemCentered(entity me, entity other, vector theSize, float theAlpha) { me.addItem(me, other, '0.5 0.5 0' - 0.5 * theSize, theSize, theAlpha); } void Container_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha) { if(other.parent) error("Can't add already added item!"); if(other.focusable) me.focusable += 1; if(theSize_x > 1) { theOrigin_x -= 0.5 * (theSize_x - 1); theSize_x = 1; } if(theSize_y > 1) { theOrigin_y -= 0.5 * (theSize_y - 1); theSize_y = 1; } theOrigin_x = bound(0, theOrigin_x, 1 - theSize_x); theOrigin_y = bound(0, theOrigin_y, 1 - theSize_y); other.parent = me; other.Container_origin = theOrigin; other.Container_size = theSize; me.setAlphaOf(me, other, theAlpha); entity f, l; f = me.firstChild; l = me.lastChild; if(l) l.nextSibling = other; else me.firstChild = other; other.prevSibling = l; other.nextSibling = NULL; me.lastChild = other; draw_NeedResizeNotify = 1; } void Container_removeItem(entity me, entity other) { if(other.parent != me) error("Can't remove from wrong container!"); if(other.focusable) me.focusable -= 1; other.parent = NULL; entity n, p, f, l; f = me.firstChild; l = me.lastChild; n = other.nextSibling; p = other.prevSibling; if(p) p.nextSibling = n; else me.firstChild = n; if(n) n.prevSibling = p; else me.lastChild = p; } void Container_setFocus(entity me, entity other) { if(other) if not(me.focused) error("Trying to set focus in a non-focused control!"); if(me.focusedChild == other) return; //print(etos(me), ": focus changes from ", etos(me.focusedChild), " to ", etos(other), "\n"); if(me.focusedChild) { me.focusedChild.focused = 0; me.focusedChild.focusLeave(me.focusedChild); } if(other) { other.focused = 1; other.focusEnter(other); } me.focusedChild = other; } void Container_moveItemAfter(entity me, entity other, entity dest) { // first: remove other from the chain entity n, p, f, l; if(other.parent != me) error("Can't move in wrong container!"); f = me.firstChild; l = me.lastChild; n = other.nextSibling; p = other.prevSibling; if(p) p.nextSibling = n; else me.firstChild = n; if(n) n.prevSibling = p; else me.lastChild = p; // now other got removed. Insert it behind dest now. other.prevSibling = dest; if(dest) other.nextSibling = dest.nextSibling; else other.nextSibling = me.firstChild; if(dest) dest.nextSibling = other; else me.firstChild = other; if(other.nextSibling) other.nextSibling.prevSibling = other; else me.lastChild = other; } entity Container_preferredFocusedGrandChild(entity me) { entity e, e2; entity best; best = NULL; for(e = me.firstChild; e; e = e.nextSibling) { if(e.instanceOfContainer) { e2 = e.preferredFocusedGrandChild(e); if(e2) if(!best || best.preferredFocusPriority < e2.preferredFocusPriority) best = e2; } if(e) if(!best || best.preferredFocusPriority < e.preferredFocusPriority) best = e; } return best; } #endif