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 }