#Include "TextLib" as TextLib declare CMlControl[][Text] _mQ_selectorCache; declare CMlControl[][Text] _mQ_byTagName; declare CMlControl[][CMlControl] _mQ_children; declare Boolean _mQ_childrenRead; declare Boolean mQ_debug; Text mQ_Typeof(CMlControl c) { switchtype(c) { case CMlCamera: { return "CMlCamera"; } case CMlEntry: { return "CMlEntry"; } case CMlFrame: { return "CMlFrame"; } case CMlGauge: { return "CMlGauge"; } case CMlGraph: { return "CMlGraph"; } case CMlLabel: { return "CMlLabel"; } case CMlMediaPlayer: { return "CMlMediaPlayer"; } case CMlMinimap: { return "CMlMinimap"; } case CMlQuad: { return "CMlQuad"; } default: { return "unknown"; } } return "unknown"; } Void _mQ_readChildren() { if(_mQ_childrenRead != True) { _mQ_byTagName["CMlCamera"] = CMlControl[]; _mQ_byTagName["CMlEntry"] = CMlControl[]; _mQ_byTagName["CMlFrame"] = CMlControl[]; _mQ_byTagName["CMlGauge"] = CMlControl[]; _mQ_byTagName["CMlGraph"] = CMlControl[]; _mQ_byTagName["CMlLabel"] = CMlControl[]; _mQ_byTagName["CMlMediaPlayer"] = CMlControl[]; _mQ_byTagName["CMlMinimap"] = CMlControl[]; _mQ_byTagName["CMlQuad"] = CMlControl[]; _mQ_byTagName["unknown"] = CMlControl[]; declare CMlFrame[] _frame_stack; _frame_stack.add(Page.MainFrame); while(_frame_stack.count > 0) { declare _currindex = _frame_stack.count - 1; declare _frame = _frame_stack[_currindex]; _mQ_children[_frame] = CMlControl[]; _frame_stack.removekey(_currindex); foreach(_control in _frame.Controls) { _mQ_children[_frame].add(_control); _mQ_byTagName[mQ_Typeof(_control)].add(_control); switchtype(_control as __control) { case CMlFrame: { _frame_stack.add( __control); } } } } } _mQ_childrenRead = True; } Text _mQ_join(Text glue, Text[] strings) { declare Text result = ""; for (i, 0, strings.count-2) { result ^= strings[i] ^ glue; } result ^= strings[strings.count-1]; return result; } Text _mQ_getTagClass(Text input) { declare Text[Text] tbl = ["camera" => "CMlCamera", "entry" => "CMlEntry", "frame" => "CMlFrame", "gauge" => "CMlGauge", "graph" => "CMlGraph", "label" => "CMlLabel", "mediaplayer" => "CMlMediaPlayer", "minimap" => "CMlMinimap", "quad" => "CMlQuad"]; if (tbl.existskey(input)) return tbl[input]; if (tbl.exists(input)) return input; return ""; } Text[][Text] _mQ_normalizeSelector(Text selector) { declare Text[][Text] result; declare Text[] ids; declare Text[] classes; declare Text[] tags; declare Text[] selectors = TextLib::Split(",", selector); declare Text[] trimmed; foreach (sel in selectors) { declare Text t = TextLib::Trim(sel); switch (TextLib::SubString(t, 0, 1)) { case "#":{ ids.add(TextLib::SubString(t, 1, TextLib::Length(t))); trimmed.add(t); } case ".":{ classes.add(TextLib::SubString(t, 1, TextLib::Length(t))); trimmed.add(t); } default:{ tags.add(t); trimmed.add(t); } } } result["id"] = ids.sort(); result["class"] = classes.sort(); result["tag"] = tags.sort(); result["string"] = [_mQ_join(",", trimmed.sort())]; return result; } CMlFrame mQ_Parent(CMlControl control) { _mQ_readChildren(); foreach (_parent => _children in _mQ_children) { if (_children.exists(control)) return (_parent as CMlFrame); } return Page.MainFrame; } Boolean mQ_IsChildOf(CMlControl control, CMlFrame parent, Boolean recursive) { _mQ_readChildren(); if (parent == Page.MainFrame) return True; if (!recursive) return _mQ_children[parent].exists(control); declare CMlFrame _parent = mQ_Parent(control); while (_parent != Page.MainFrame) { if (_parent == parent) return True; _parent = mQ_Parent(_parent); } return False; } Boolean mQ_IsChildOf(CMlControl control, CMlFrame parent) { return mQ_IsChildOf(control, parent, True); } CMlControl[] mQ(Text selector, CMlFrame root) { _mQ_readChildren(); declare CMlControl[] elements; declare Text[][Text] nselector = _mQ_normalizeSelector(selector); if (_mQ_selectorCache.existskey(nselector["string"][0])) { return _mQ_selectorCache[nselector["string"][0]]; } else { foreach (id in nselector["id"]) { elements.add(root.GetFirstChild(id)); } foreach (class in nselector["class"]) { Page.GetClassChildren(class, root, True); foreach (c in Page.GetClassChildren_Result) { declare tmp = c; elements.add(tmp); } } foreach (tag in nselector["tag"]) { foreach (e in _mQ_byTagName[_mQ_getTagClass(tag)]) { if (mQ_IsChildOf(e, root)) elements.add(e); } } _mQ_selectorCache[nselector["string"][0]] = elements; } if (mQ_debug) { log("mQ elements " ^ nselector["string"][0]); log(elements); } return elements; } CMlControl[] mQ(Text selector) { return mQ(selector, Page.MainFrame); } CMlControl[] mQAdd(CMlControl control, CMlControl[] elements) { declare CMlControl[] result = elements; result.add(control); return result; } CMlControl[] mQAdd(CMlControl[] controls, CMlControl[] elements) { declare CMlControl[] result = elements; foreach (control in controls) { if (!result.exists(control)) result.add(control); } if (mQ_debug) { log("mQAdd:"); log(elements); log(controls); log(result); } return result; } CMlControl[] mQAdd(Text selector, CMlFrame root, CMlControl[] elements) { return mQAdd(mQ(selector, root), elements); } CMlControl[] mQAdd(Text selector, CMlControl[] elements) { return mQAdd(selector, Page.MainFrame, elements); } CMlControl[] mQNot(Text selector, CMlFrame root, CMlControl[] elements) { declare CMlControl[] result; declare CMlControl[] additional = mQ(selector, root); foreach (c in elements) { if (!additional.exists(c)) { result.add(c); } } if (mQ_debug) { log("mQNot elements"); log(elements); log("mQNot result"); log(result); } return result; } CMlControl[] mQNot(Text selector, CMlControl[] elements) { return mQNot(selector, Page.MainFrame, elements); } CMlControl[] mQFilter(Text selector, CMlControl[] elements) { declare CMlControl[] result; if (elements.count == 0) return result; switch(selector) { case ":first": { result.add(elements[0]); } case ":last": { result.add(elements[elements.count - 1]); } case ":odd": { declare Integer i = 0; foreach(e in elements) { if (i % 2 == 1) result.add(e); i += 1; } } case ":even": { declare Integer i = 0; foreach(e in elements) { if (i % 2 == 0) result.add(e); i += 1; } } case "[visible]": { foreach(e in elements) { if (e.Visible) result.add(e); } } case "[hidden]": { foreach(e in elements) { if (!e.Visible) result.add(e); } } default :{ if (TextLib::SubString(selector, 3, 1) == "(" && TextLib::SubString(selector, TextLib::Length(selector)-1, 1) == ")") { declare Text param = TextLib::SubString(selector, 4, TextLib::Length(selector)-5); declare Integer i = TextLib::ToInteger(param) % elements.count; switch (TextLib::SubString(selector, 0, 3)) { case ":eq": { result.add(elements[i]); } case ":lt": { for (j,0,i-1) result.add(elements[j]); } case ":gt": { for (j,i+1,elements.count-1) result.add(elements[j]); } } } } } return result; } CMlControl[] mQ_SetText(Text t, CMlControl[] elements) { foreach(e in elements) { if (mQ_Typeof(e) == "CMlLabel" && e != Null) (e as CMlLabel).SetText(t); } return elements; } CMlControl[] mQ_Hide(Text t, CMlControl[] elements) { foreach(e in elements) e.Hide(); return elements; } CMlControl[] mQ_Show(Text t, CMlControl[] elements) { foreach(e in elements) e.Show(); return elements; } Void Unload(Text t, CMlControl[] elements) { foreach(e in elements) e.Unload(); } CMlControl[] mQ_PosnX(Real x, CMlControl[] elements) { foreach(e in elements) e.RelativePosition.X = x; return elements; } CMlControl[] mQ_PosnY(Real x, CMlControl[] elements) { foreach(e in elements) e.RelativePosition.Y = x; return elements; } CMlControl[] mQ_PosnZ(Real x, CMlControl[] elements) { foreach(e in elements) e.RelativePosition.Z = x; return elements; } CMlControl[] mQ_RelativePosition(Vec3 x, CMlControl[] elements) { foreach(e in elements) e.RelativePosition = x; return elements; } CMlControl[] mQ_Scale(Real x, CMlControl[] elements) { foreach(e in elements) e.RelativeScale = x; return elements; } CMlControl[] mQ_Size(Vec2 x, CMlControl[] elements) { foreach(e in elements) e.Size = x; return elements; } CMlControl mQ(Integer i, CMlControl[] elements) { if (elements.count == 0) return Null; declare Integer j = i % elements.count; if (elements.count >= j) return elements[j]; return Null; } CMlControl mQ(CMlControl[] elements) { return mQ(0, elements); } Boolean mQ_IsOver(CMlControl control) { declare Vec2 topleft = <0., 0.>; declare Real width = control.AbsoluteScale * control.Size[0]; declare Real height = control.AbsoluteScale * control.Size[1]; declare Real x = control.AbsolutePosition[0]; declare Real y = control.AbsolutePosition[1]; switch (control.HorizontalAlign) { case CMlControl::AlignHorizontal::HCenter: { topleft[0] = x - width / 2; } case CMlControl::AlignHorizontal::Right: { topleft[0] = x - width; } default: { topleft[0] = x; } } switch (control.VerticalAlign) { case CMlControl::AlignVertical::VCenter : { topleft[1] = y + height / 2; } case CMlControl::AlignVertical::Bottom: { topleft[1] = y + height; } default: { topleft[1] = y; } } declare Boolean inX = (MouseX >= topleft[0] && MouseX <= topleft[0] + width); declare Boolean inY = (MouseY <= topleft[1] && MouseY >= topleft[1] - height); return inX && inY; } Boolean mQ_IsOver(CMlControl[] controls) { declare Boolean overall = False; foreach (control in controls) { overall = overall || mQ_IsOver(control); } return overall; }