1 #include <stdio.h>
2 #include <stdlib.h>
3 
4 #include "x11.h"
5 #include "x11-motif.h"
6 
7 #include <Xm/Xm.h>
8 #include <Xm/Label.h>
9 #include <Xm/RowColumn.h>
10 #include <Xm/DrawingA.h>
11 #include <Xm/PushB.h>
12 #include <Xm/CascadeB.h>
13 #include <Xm/MessageB.h>
14 #include <Xm/SelectioB.h>
15 #include <Xm/Text.h>
16 
17 #include "util.h"
18 
19 #include "Game.h"
20 #include "UI.h"
21 
22 static Widget base, menubar, field;
23 static Widget dialogs[DIALOG_MAX + 1];
24 static Widget pausebutton;
25 
26 static void
x11_motif_popup_dialog(int index)27 x11_motif_popup_dialog(int index) {
28 	x11_popup(dialogs[index]);
29 }
30 
31 static void
popup(Widget w,XtPointer client_data,XtPointer call_data)32 popup(Widget w, XtPointer client_data, XtPointer call_data) {
33 	UNUSED(w);
34 	UNUSED(call_data);
35 	x11_motif_popup_dialog((int)client_data);
36 }
37 
38 static Widget
new_menu_item(Widget pulldown,int dialog)39 new_menu_item(Widget pulldown, int dialog) {
40 	Widget menu_item = XtCreateManagedWidget(UI_menu_string(dialog),
41 						 xmPushButtonWidgetClass,
42 						 pulldown, NULL, 0);
43 	XtAddCallback(menu_item, XmNactivateCallback, popup, (void *) dialog);
44 	return menu_item;
45 }
46 
47 static Widget
CreateMenuBar(const char * name,Widget parent)48 CreateMenuBar(const char *name, Widget parent) {
49 	Widget menubar, pulldown;
50 	Widget game_menu, info_menu;
51 
52 	menubar = XmCreateMenuBar(parent, (char *)name, NULL, 0);
53 	XtManageChild(menubar);
54 
55 	pulldown = XmCreatePulldownMenu(menubar, "menu", NULL, 0);
56 	game_menu = XtVaCreateManagedWidget("Game",
57 					    xmCascadeButtonWidgetClass,
58 					    menubar, XmNsubMenuId,
59 					    pulldown, NULL);
60 
61 	new_menu_item(pulldown, DIALOG_NEWGAME);
62 	pausebutton = new_menu_item(pulldown, DIALOG_PAUSEGAME);
63 	new_menu_item(pulldown, DIALOG_WARPLEVEL);
64 	new_menu_item(pulldown, DIALOG_HIGHSCORE);
65 	new_menu_item(pulldown, DIALOG_QUITGAME);
66 
67 	pulldown = XmCreatePulldownMenu(menubar, "menu", NULL, 0);
68 	info_menu = XtVaCreateManagedWidget("Info",
69 					    xmCascadeButtonWidgetClass,
70 					    menubar, XmNsubMenuId,
71 					    pulldown, NULL);
72 
73 	new_menu_item(pulldown, DIALOG_STORY);
74 	new_menu_item(pulldown, DIALOG_RULES);
75 	new_menu_item(pulldown, DIALOG_ABOUT);
76 
77 	return menubar;
78 }
79 
80 static Widget
CreateRowCol(const char * name,Widget parent)81 CreateRowCol(const char *name, Widget parent) {
82 	return XtVaCreateManagedWidget(name, xmRowColumnWidgetClass, parent,
83 		XmNorientation, XmVERTICAL, NULL);
84 }
85 
86 static void
CreatePixmapBox(int index,Widget parent,Pixmap logo,Pixmap pixmap)87 CreatePixmapBox(int index, Widget parent, Pixmap logo, Pixmap pixmap) {
88 	Arg wargs[2];
89 	XmString mstr;
90 	Widget dialog, base;
91 	const char *text = UI_dialog_string(index);
92 
93 	mstr = XmStringCreateLtoR("", XmSTRING_DEFAULT_CHARSET);
94 	XtSetArg(wargs[0], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL);
95 	XtSetArg(wargs[1], XmNmessageString, mstr);
96 	dialog = XmCreateMessageDialog(parent, (char *)UI_menu_string(index),
97 				       wargs, 2);
98 
99 	base = CreateRowCol("", dialog);
100 
101 	XtVaCreateManagedWidget("", xmLabelWidgetClass, base, XmNlabelType,
102 				XmPIXMAP, XmNlabelPixmap, logo, NULL);
103 
104 	if (pixmap)
105 		XtVaCreateManagedWidget("", xmLabelWidgetClass, base,
106 					XmNlabelType, XmPIXMAP,
107 					XmNlabelPixmap, pixmap, NULL);
108 
109 	if (text) {
110 		mstr = XmStringCreateLtoR((char *)text,
111 					  XmSTRING_DEFAULT_CHARSET);
112 		XtVaCreateManagedWidget(text, xmLabelWidgetClass, base,
113 			XmNlabelString, mstr, NULL);
114 		XmStringFree(mstr);
115 	}
116 
117 	XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
118 	XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
119 	dialogs[index] = dialog;
120 }
121 
122 static void
CreateEnterText(int index,Widget parent,XtCallbackProc callback)123 CreateEnterText(int index, Widget parent, XtCallbackProc callback) {
124 	Widget dialog;
125 	Arg wargs[2];
126 	XmString mstr = XmStringCreateLtoR((char *) UI_dialog_string(index),
127 					   XmSTRING_DEFAULT_CHARSET);
128 	XtSetArg(wargs[0], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL);
129 	XtSetArg(wargs[1], XmNselectionLabelString, mstr);
130 	dialog = XmCreatePromptDialog(parent, (char *) UI_menu_string(index),
131 				      wargs, 2);
132 	XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
133 	XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_APPLY_BUTTON));
134 	XtAddCallback(dialog, XmNokCallback, callback,
135 		      XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT));
136 	dialogs[index] = dialog;
137 }
138 
139 static void
CreateDialog(int index,Widget parent,int hascancel,Pixmap icon,const char * buttonlabel,XtCallbackProc callback)140 CreateDialog(int index, Widget parent, int hascancel, Pixmap icon,
141 	     const char *buttonlabel, XtCallbackProc callback)
142 {
143 	Widget dialog;
144 	Arg wargs[2];
145 	XmString mstr = XmStringCreateLtoR((char *) UI_dialog_string(index),
146 					   XmSTRING_DEFAULT_CHARSET);
147 	XtSetArg(wargs[0], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL);
148 	XtSetArg(wargs[1], XmNmessageString, mstr);
149 	dialog = XmCreateMessageDialog(parent, (char *) UI_menu_string(index),
150 				       wargs, 2);
151 	if (icon != (Pixmap) NULL)
152 		XtVaSetValues(dialog, XmNsymbolPixmap, icon, NULL);
153 	XmStringFree(mstr);
154 	if (!hascancel)
155 		XtUnmanageChild(XmMessageBoxGetChild(dialog,
156 						     XmDIALOG_CANCEL_BUTTON));
157 	XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
158 	if (buttonlabel != NULL) {
159 		mstr = XmStringCreateLtoR((char *) buttonlabel,
160 					  XmSTRING_DEFAULT_CHARSET);
161 		XtVaSetValues(XmMessageBoxGetChild(dialog, XmDIALOG_OK_BUTTON),
162 			      XmNlabelString, mstr, NULL);
163 		XmStringFree(mstr);
164 	}
165 	if (callback != NULL)
166 		XtAddCallback(dialog, XmNokCallback, callback, NULL);
167 	dialogs[index] = dialog;
168 }
169 
170 static Widget
CreateDrawingArea(const char * name,Widget parent,int width,int height)171 CreateDrawingArea(const char *name, Widget parent, int width, int height) {
172 	return XtVaCreateManagedWidget(name, xmDrawingAreaWidgetClass, parent,
173 				       XtNwidth, width, XtNheight, height,
174 				       XmNresizePolicy, FALSE, NULL);
175 }
176 
177 static void
x11_motif_update_dialog(int index,const char * str)178 x11_motif_update_dialog(int index, const char *str) {
179 	XmString mstr = XmStringCreateLtoR((char *) str,
180 					   XmSTRING_DEFAULT_CHARSET);
181 	XtVaSetValues(
182 		XmMessageBoxGetChild(dialogs[index], XmDIALOG_MESSAGE_LABEL),
183 		XmNlabelString, mstr, NULL);
184 	XmStringFree(mstr);
185 }
186 
187 static void
x11_motif_make_main_window(int size)188 x11_motif_make_main_window(int size) {
189 	x11_setup_resources();
190 	base = CreateRowCol("base", x11_toplevel());
191 	menubar = CreateMenuBar("menubar", base);
192 	field = CreateDrawingArea("field", base, size, size);
193 	x11_setup();
194 	x11_set_drawingarea(field, size);
195 	x11_add_event_handlers(field);
196 }
197 
198 static void
new_game(Widget w,XtPointer client_data,XtPointer call_data)199 new_game(Widget w, XtPointer client_data, XtPointer call_data) {
200 	UNUSED(w);
201 	UNUSED(client_data);
202 	UNUSED(call_data);
203 	Game_start(1);
204 }
205 
206 static void
quit_game(Widget w,XtPointer client_data,XtPointer call_data)207 quit_game(Widget w, XtPointer client_data, XtPointer call_data) {
208 	UNUSED(w);
209 	UNUSED(client_data);
210 	UNUSED(call_data);
211 	Game_quit();
212 }
213 
214 static void
warp_apply(Widget w,XtPointer client_data,XtPointer call_data)215 warp_apply(Widget w, XtPointer client_data, XtPointer call_data) {
216 	char *str;
217 	char *endp;
218 	int newlevel;
219 	Widget text = (Widget) client_data;
220 
221 	UNUSED(w);
222 	UNUSED(call_data);
223 
224 	str = XmTextGetString(text);
225 	newlevel = strtol(str, &endp, 10);
226 	if (*endp != '\0')
227 		return;
228 	XtFree(str);
229 	Game_warp_to_level(newlevel);
230 }
231 
232 static void
enter_name(Widget w,XtPointer client_data,XtPointer call_data)233 enter_name(Widget w, XtPointer client_data, XtPointer call_data) {
234 	char *str;
235 	Widget text = (Widget) client_data;
236 
237 	UNUSED(w);
238 	UNUSED(call_data);
239 
240 	str = XmTextGetString(text);
241 	Game_add_high_score(str);
242 	XtFree(str);
243 }
244 
245 static void
x11_motif_create_dialogs(Picture * logo,Picture * icon,Picture * about)246 x11_motif_create_dialogs(Picture *logo, Picture *icon, Picture *about) {
247 	CreateDialog(DIALOG_NEWGAME, base, 1, (Pixmap)NULL, NULL, new_game);
248 	CreateDialog(DIALOG_PAUSEGAME, base, 0, icon->pix, "Continue", NULL);
249 	CreateEnterText(DIALOG_WARPLEVEL, base, warp_apply);
250 	CreateDialog(DIALOG_HIGHSCORE, base, 0, (Pixmap)NULL, NULL, NULL);
251 	CreateDialog(DIALOG_QUITGAME, base, 1, (Pixmap)NULL, NULL, quit_game);
252 
253 	CreatePixmapBox(DIALOG_STORY, base, logo->pix, (Pixmap)NULL);
254 	CreatePixmapBox(DIALOG_RULES, base, logo->pix, (Pixmap)NULL);
255 	CreatePixmapBox(DIALOG_ABOUT, base, logo->pix, about->pix);
256 
257 	CreateDialog(DIALOG_SCORE, base, 0, (Pixmap)NULL, NULL, NULL);
258 	CreateDialog(DIALOG_ENDGAME, base, 0, (Pixmap)NULL, "Nuts!", NULL);
259 	CreateEnterText(DIALOG_ENTERNAME, base, enter_name);
260 }
261 
262 static void
x11_motif_set_pausebutton(int active)263 x11_motif_set_pausebutton(int active) {
264 	if (pausebutton != NULL)
265 		XtSetSensitive(pausebutton, active);
266 }
267 
268 static struct UI_methods x11_motif_methods = {
269 	x11_set_cursor,
270 	x11_load_cursor,
271 	x11_load_picture,
272 	x11_set_icon,
273 	x11_picture_width,
274 	x11_picture_height,
275 	x11_graphics_init,
276 	x11_clear_window,
277 	x11_refresh_window,
278 	x11_draw_image,
279 	x11_draw_line,
280 	x11_draw_string,
281 	x11_start_timer,
282 	x11_stop_timer,
283 	x11_timer_active,
284 	x11_motif_popup_dialog,
285 	x11_main_loop,
286 	x11_initialize,
287 	x11_motif_make_main_window,
288 	x11_motif_create_dialogs,
289 	x11_motif_set_pausebutton,
290 	x11_motif_update_dialog,
291 };
292 
293 void
x11_motif_setmethods(UI_methods ** methodsp)294 x11_motif_setmethods(UI_methods **methodsp) {
295 	*methodsp = &x11_motif_methods;
296 }
297