1 /**
2 List
3 Shows a simple list menu.
4 */
5
6 local Name = "List Menu";
7
8 local entries;
9 local on_mouse_over_callback, on_mouse_out_callback;
10 local on_close_callback;
11 local permanent;
12
13 local menu_id;
14
Construction()15 func Construction()
16 {
17 entries = [];
18 this.Style = GUI_VerticalLayout;
19 this.Target = this;
20 this.ID = 0xffffff;
21
22 this.OnClose = GuiAction_Call(this, "OnCloseCallback");
23
24 SetPosition(0, 0);
25 }
26
OnCloseCallback()27 func OnCloseCallback()
28 {
29 menu_id = 0;
30 Close();
31 }
32
Close()33 func Close()
34 {
35 var self = this;
36 if (on_close_callback && on_close_callback[0])
37 on_close_callback[0]->Call(on_close_callback[1], on_close_callback[2]);
38 if (self && menu_id)
39 GuiClose(menu_id);
40 if (self)
41 RemoveObject();
42 }
43
SetPermanent(bool perm)44 func SetPermanent(bool perm) { permanent = perm ?? true; }
SetFitChildren()45 func SetFitChildren() { this.Style = this.Style | GUI_FitChildren; this.Bottom = "0em";}
46
SetCloseCallback(proplist target,callback,parameter)47 func SetCloseCallback(proplist target, callback, parameter)
48 {
49 on_close_callback = [target, callback, parameter];
50 }
51
SetMouseOverCallback(proplist target,callback)52 func SetMouseOverCallback(proplist target, callback)
53 {
54 on_mouse_over_callback = [target, callback];
55 }
56
SetMouseOutCallback(proplist target,callback)57 func SetMouseOutCallback(proplist target, callback)
58 {
59 on_mouse_out_callback = [target, callback];
60 }
61
62 // can be overloaded for custom menu styles
MakeEntryProplist(symbol,text)63 func MakeEntryProplist(symbol, text)
64 {
65 var custom_entry = {Bottom = "+2em", sym = {Right = "+2em", Bottom = "+2em"}, desc = {Left = "+2em"}};
66 custom_entry.sym.Symbol = symbol;
67 custom_entry.desc.Text = text;
68 custom_entry.desc.Style = GUI_TextVCenter;
69 custom_entry.Style = GUI_FitChildren;
70 custom_entry.BackgroundColor = {Std = 0, OnHover = 0x50ff0000};
71 return custom_entry;
72 }
73
74 // custom_menu_id should be passed if the menu was manually opened and not via Open()
AddItem(symbol,string text,user_ID,proplist target,command,parameter,custom_entry,custom_menu_id,bool onlyUpdate)75 func AddItem(symbol, string text, user_ID, proplist target, command, parameter, custom_entry, custom_menu_id, bool onlyUpdate)
76 {
77 onlyUpdate = onlyUpdate ?? false;
78 custom_menu_id = custom_menu_id ?? menu_id;
79
80 var on_hover = GuiAction_SetTag("OnHover", 0, nil);
81 if (on_mouse_over_callback)
82 on_hover = [on_hover, GuiAction_Call(this, "DoCallback", on_mouse_over_callback)];
83 var on_hover_stop = GuiAction_SetTag("Std", 0, nil);
84 if (on_mouse_out_callback)
85 on_hover_stop = [on_hover_stop, GuiAction_Call(this, "DoCallback", on_mouse_out_callback)];
86
87 // in case of a new entry, append to array
88 var ID = GetLength(entries) + 1;
89 // otherwise, replace the old entry
90 if (onlyUpdate)
91 {
92 for (var i = 0; i < GetLength(entries); ++i)
93 {
94 if (!entries[i]) continue;
95 if (entries[i][3] != user_ID) continue;
96 ID = i + 1;
97 break;
98 }
99 }
100
101 if (!custom_entry)
102 custom_entry = MakeEntryProplist(symbol, text);
103
104 // Always add some properties later. This is done so that real custom entries do not need to care about target etc.
105 custom_entry.ID = ID; // A fixed ID is obligatory for now. Might be possible to omit that, but would need to check if updating etc works.
106 custom_entry.Target = this; // Same as above.
107
108 // These properties can in theory be set/customized by the user without breaking functionality. But they are (probably) required anway.
109 custom_entry.Priority = custom_entry.Priority ?? ID;
110 custom_entry.OnClick = custom_entry.OnClick ?? GuiAction_Call(this, "OnClick");
111 custom_entry.OnMouseIn = custom_entry.OnMouseIn ?? on_hover;
112 custom_entry.OnMouseOut = custom_entry.OnMouseOut ?? on_hover_stop;
113
114 // Save entry to list and prepare call information.
115 entries[ID - 1] = [target, command, parameter, user_ID];
116 this[Format("_menuChild%d", ID)] = custom_entry;
117
118 // need to add to existing menu?
119 if (custom_menu_id)
120 {
121 if (onlyUpdate)
122 {
123 // need to close the old entry first
124 // this is done so a full refresh is guaranteed
125 GuiClose(custom_menu_id, ID, this);
126 }
127
128 var temp = {_child = custom_entry};
129 GuiUpdate(temp, custom_menu_id, this.ID, this);
130 }
131
132 return custom_entry;
133 }
134
135 // updates an existing entry with the given user_ID
UpdateItem(symbol,string text,user_ID,proplist target,command,parameter,custom_entry,custom_menu_id)136 func UpdateItem(symbol, string text, user_ID, proplist target, command, parameter, custom_entry, custom_menu_id)
137 {
138 return AddItem(symbol, text, user_ID, target, command, parameter, custom_entry, custom_menu_id, true);
139 }
140
141 // can be used when the menu has already been opened
142 // needs to be passed the menu ID if the menu was not opened using Open()
RemoveItem(user_ID,int custom_menu_id)143 func RemoveItem(user_ID, int custom_menu_id)
144 {
145 custom_menu_id = custom_menu_id ?? menu_id;
146 for (var i = 0; i < GetLength(entries); ++i)
147 {
148 var ID = i+1;
149 if (!entries[i]) continue;
150 if (entries[i][3] != user_ID) continue;
151 GuiClose(custom_menu_id, ID, this);
152 entries[i] = nil;
153 return true;
154 }
155 return false;
156 }
157
DoCall(int ID,command,proplist target,bool noclose,int player)158 func DoCall(int ID, command, proplist target, bool noclose, int player)
159 {
160 var self = this; // safety
161 var entry = entries[ID - 1];
162 target = target ?? entry[0];
163 // target removed? safety first!
164 if (target)
165 {
166 if (target->Call(command ?? entry[1], entry[2], entry[3], player) == -1) return;
167 }
168 if (self)
169 if (!noclose && !permanent)
170 Close();
171 }
172
OnClick(data,int player,int ID,int subwindowID,object target)173 func OnClick(data, int player, int ID, int subwindowID, object target)
174 {
175 DoCall(subwindowID, nil, nil, nil, player);
176 }
177
DoCallback(data,int player,int ID,int subwindowID,object target)178 func DoCallback(data, int player, int ID, int subwindowID, object target)
179 {
180 DoCall(subwindowID, data[1], data[0], true, player);
181 }
182
Open()183 func Open()
184 {
185 this.ID = nil; // no subwindow ID when opened as real menu
186 menu_id = GuiOpen(this);
187 return menu_id;
188 }