Add arrow/button images
[fim-ctu.git] / menu.c
blob19f7ae41854b26655d0f425f18baf21dd27292ee
1 #include "ctu.h"
3 #include <windows.h>
4 #include <stdio.h>
6 #include "res.h"
7 #include "inject.h"
8 #include "menu.h"
10 #define DLGITEM(x) { #x, CTU_DLGITEM_ ## x }
12 static struct dlg_item dlg_action[] = {
13 DLGITEM(None),
14 DLGITEM(Recover),
15 DLGITEM(Control),
16 DLGITEM(Record),
17 DLGITEM(Replay),
18 { NULL },
21 static struct dlg_item dlg_health[] = {
22 DLGITEM(Normal),
23 DLGITEM(Refill),
24 { NULL },
27 static struct dlg_item dlg_meter[] = {
28 DLGITEM(Normal),
29 DLGITEM(0_Bars),
30 DLGITEM(1_Bar),
31 DLGITEM(2_Bars),
32 DLGITEM(3_Bars),
33 { NULL },
36 static struct dlg_item dlg_magic[] = {
37 DLGITEM(Normal),
38 DLGITEM(Refill),
39 DLGITEM(Deplete),
40 { NULL },
43 static struct dlg_item dlg_info[] = {
44 DLGITEM(Off),
45 DLGITEM(On),
46 { NULL },
49 #undef DLGITEM
51 struct ctu_dlg dlg[] = {
52 { "Action:", &dlg_action[0], 1, },
53 { "Health:", &dlg_health[0], 1, },
54 { "Meter:", &dlg_meter[0], 0, },
55 { "Magic:", &dlg_magic[0], 0, },
56 { "Info:", &dlg_info[0], 1, },
58 int n_dlg = sizeof(dlg) / sizeof(dlg[0]);
60 static int dlg_cur = 0;
62 static HWND hwndMenu;
64 static int fm2k_win_set;
65 static HWND fm2k_win;
67 static BOOL CALLBACK
68 find_fm2k_win(HWND hwnd, LPARAM lParam)
70 int code;
71 static char buf[16];
73 code = GetClassName(hwnd, buf, sizeof(buf));
74 if (code == 0) {
75 ctud("GetClassName failed with %d\n", (int)GetLastError());
76 return 1;
79 if (!strcasecmp(buf, "KGT2KGAME")) {
80 if (fm2k_win_set) {
81 ctud("Found multiple FM2K windows? old: 0x%lx new: 0x%lx\n",
82 (unsigned long)fm2k_win, (unsigned long)hwnd);
83 return 1;
85 fm2k_win_set = 1;
86 fm2k_win = hwnd;
89 return 1;
92 static int
93 get_fm2k_win(void)
95 if (!fm2k_win_set) {
96 if (!EnumThreadWindows(proc_thread_id, &find_fm2k_win, 0)) {
97 ctud("EnumThreadWindows failed with %d\n", (int)GetLastError());
101 if (!fm2k_win_set) {
102 return 0;
105 return 1;
108 static void
109 handle_title(void)
111 if (get_fm2k_win()) {
112 if (!SetWindowText(fm2k_win, "FightingIsMagic (Collective Training Unit)")) {
113 ctud("SetWindowText failed with %d\n", (int)GetLastError());
119 get_menu_coords(RECT *rc_win, RECT *rc_client)
121 WINDOWINFO winfo;
123 if (!get_fm2k_win()) {
124 return 0;
127 ZeroMemory(&winfo, sizeof(winfo));
128 winfo.cbSize = sizeof(winfo);
130 if (!GetWindowInfo(fm2k_win, &winfo)) {
131 ctud("GetWindowInfo failed with %d\n", (int)GetLastError());
132 return 0;
135 if (rc_win) {
136 *rc_win = winfo.rcWindow;
138 if (rc_client) {
139 *rc_client = winfo.rcClient;
142 return 1;
145 static void
146 setctrl(HWND dlgHwnd, int id, const char *str)
148 char buf[64];
149 char *cur;
150 HWND hwnd;
152 strcpy(buf, str);
153 for (cur = buf; *cur; cur++) {
154 if (*cur == '_') {
155 *cur = ' ';
159 hwnd = GetDlgItem(dlgHwnd, id);
160 if (!hwnd) {
161 ctud("Error %d from GetDlgItem\n", (int)GetLastError());
162 return;
165 if (!SetWindowText(hwnd, buf)) {
166 ctud("Error %d from SetWindowText\n", (int)GetLastError());
170 static void
171 setlabel(HWND dlgHwnd, int index, const char *str)
173 setctrl(dlgHwnd, CTU_CTRL_LBL + index, str);
176 static void
177 setval(HWND dlgHwnd, int index, const char *str)
179 setctrl(dlgHwnd, CTU_CTRL_CENT + index, str);
182 static void
183 setactive(HWND dlgHwnd, int index)
185 if (index != dlg_cur) {
186 setctrl(dlgHwnd, CTU_CTRL_LEFT + dlg_cur, "");
187 setctrl(dlgHwnd, CTU_CTRL_RIGHT + dlg_cur, "");
189 setctrl(dlgHwnd, CTU_CTRL_LEFT + index, "<");
190 setctrl(dlgHwnd, CTU_CTRL_RIGHT + index, ">");
193 static BOOL CALLBACK
194 menu_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
196 switch (message) {
197 case WM_INITDIALOG: {
198 RECT rc;
199 int i;
201 for (i = 0; i < n_dlg; i++) {
202 struct ctu_dlg *cur = &dlg[i];
204 setlabel(hwnd, i, cur->label);
205 setval(hwnd, i, cur->val_arr[cur->cur].name);
207 if (i == dlg_cur) {
208 setactive(hwnd, i);
212 if (get_menu_coords(NULL, &rc)) {
213 int center, width;
215 center = (rc.left + rc.right) / 2;
216 width = 300;
218 rc.left = center - width/2;
219 /* actually the width */
220 rc.right = width;
221 /* actually the height */
222 rc.bottom = 200;
223 rc.top = rc.top + 100;
225 ctud("Setting window pos\n");
226 if (!SetWindowPos(hwnd,
227 HWND_TOPMOST,
228 rc.left, rc.top,
229 rc.right,
230 rc.bottom,
231 SWP_SHOWWINDOW | SWP_NOACTIVATE)) {
232 ctud("SetWindowPos error %d\n", (int)GetLastError());
235 break;
239 return FALSE;
242 static void
243 handle_pauseinput(int val)
245 int delta_h = 0, delta_v = 0;
247 /*ctud("pause menu got input 0x%x\n", (unsigned)val);*/
249 if ((val & CTRL_BACK)) {
250 delta_h--;
252 if ((val & CTRL_FWD)) {
253 delta_h++;
255 if ((val & CTRL_DOWN)) {
256 delta_v++;
258 if ((val & CTRL_UP)) {
259 delta_v--;
262 if (delta_v) {
263 int newcur = dlg_cur;
264 newcur += delta_v;
265 if (newcur < 0) {
266 newcur = n_dlg - 1;
268 if (newcur >= n_dlg) {
269 newcur = newcur % n_dlg;
271 setactive(hwndMenu, newcur);
272 dlg_cur = newcur;
275 if (delta_h) {
276 struct ctu_dlg *curdlg = &dlg[dlg_cur];
277 int cur = curdlg->cur;
279 cur += delta_h;
281 if (cur < 0) {
282 for (cur = 0; curdlg->val_arr[cur].name; cur++)
284 cur--;
287 if (!curdlg->val_arr[cur].name) {
288 cur = 0;
291 setval(hwndMenu, dlg_cur, curdlg->val_arr[cur].name);
292 curdlg->cur = cur;
297 menu_loop(void)
299 static HANDLE hwndInfo;
300 MSG msg;
301 DWORD code;
303 while ((code = GetMessage(&msg, NULL, 0, 0)) != 0) {
304 if (code == -1) {
305 ctud("GetMessage got error: %d\n", (int)GetLastError());
306 return 1;
308 switch (msg.message) {
309 case CTU_MENUOFF:
310 if (IsWindow(hwndMenu)) {
311 DestroyWindow(hwndMenu);
312 hwndMenu = NULL;
313 } else {
314 ctud("menu not on?\n");
316 break;
317 case CTU_MENUON:
318 ctud("got MENUON message\n");
319 if (IsWindow(hwndMenu)) {
320 ctud("menu already on?\n");
321 } else {
322 hwndMenu = CreateDialog(hinst,
323 MAKEINTRESOURCE(CTU_MENUDLG),
324 NULL,
325 menu_dlg_proc);
327 ShowWindow(hwndMenu, SW_SHOWNOACTIVATE);
329 break;
331 case CTU_MENUINPUT:
332 handle_pauseinput((int)msg.wParam);
333 break;
335 case CTU_SETTITLE:
336 handle_title();
337 break;
339 case CTU_INFOOFF:
340 if (IsWindow(hwndInfo)) {
341 DestroyWindow(hwndInfo);
342 hwndInfo = NULL;
343 } else {
344 ctud("info dlg not on?\n");
346 break;
348 case CTU_INFOON:
349 if (IsWindow(hwndInfo)) {
350 ctud("info dlg already on?\n");
351 } else {
352 hwndInfo = CreateDialog(hinst, MAKEINTRESOURCE(CTU_INFODLG), NULL,
353 info_dlg_proc);
354 ShowWindow(hwndInfo, SW_SHOWNOACTIVATE);
356 break;
358 case CTU_INFOUPDATE:
359 info_update(hwndInfo);
360 break;
362 case CTU_INPUT:
363 if (IsWindow(hwndInfo)) {
364 info_input(hwndInfo, (int)msg.lParam);
366 break;
368 case CTU_THREADUPDATE:
369 if (!AttachThreadInput(mainthread, proc_thread_id, TRUE)) {
370 ctud("AttachThreadInput error %d\n", (int)GetLastError());
372 break;
374 case WM_QUIT:
375 return 0;
377 default:
378 if (IsWindow(hwndMenu) && IsDialogMessage(hwndMenu, &msg)) {
379 /* noop; IsDialogMessage dispatches the message for us */
380 } else {
381 TranslateMessage(&msg);
382 DispatchMessage(&msg);
387 return 0;