2 * X11 GUI for slide puzzle game
3 * Copyright © 2022 Nick Bowler
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
27 #define SPLIT_NUMERATOR 75
28 #define SPLIT_DENOMINATOR 100
30 #define MIN(a, b) ((a) < (b) ? (a) : (b))
32 static void game_configure(Widget w);
34 static const struct ui_widget {
36 uint_least16_t subtree;
38 void (*configure)(Widget w);
39 } mainwin[] = { MAINWIN_INITIALIZER };
42 ResizeGameArea(Widget form, XEvent *e, String *args, Cardinal *num_args)
44 Widget game = XtNameToWidget(form, &tree_strtab[gameArea]);
45 Widget goal = XtNameToWidget(form, &tree_strtab[goalArea]);
46 Dimension w, h, gamesz, gameborder, goalsz, goalborder;
49 XtVaGetValues(form, XmNwidth, &w, XmNheight, &h, (char *)NULL);
50 XtVaGetValues(game, XmNshadowThickness, &gameborder, (char *)NULL);
51 XtVaGetValues(goal, XmNshadowThickness, &goalborder,
55 gamesz = MIN(h, w * SPLIT_NUMERATOR / SPLIT_DENOMINATOR);
56 gamesz = 5*( (gamesz - 2*gameborder)/5 ) + 2*gameborder;
58 goalsz = MIN(gamesz*3/5, w - gamesz - gap);
59 goalsz = 3*( (goalsz - 2*goalborder)/3 ) + 2*goalborder;
61 x = (w - gamesz - goalsz - gap) / 2;
67 XtVaSetValues(game, XmNleftOffset, x, XmNtopOffset, y, (char *)NULL);
68 XtVaSetValues(game, XmNwidth, gamesz, XmNheight, gamesz, (char *)NULL);
69 XtVaSetValues(goal, XmNwidth, goalsz, XmNheight, goalsz, (char *)NULL);
72 static void game_configure(Widget form)
74 Widget gamearea = XtNameToWidget(form, &tree_strtab[gameArea]);
75 Widget goalarea = XtNameToWidget(form, &tree_strtab[goalArea]);
76 XtActionsRec resize_rec;
78 assert(gamearea && goalarea);
79 XtVaSetValues(form, XmNfractionBase, SPLIT_DENOMINATOR, (char *)NULL);
81 XtVaSetValues(gamearea, //XmNrightAttachment, XmATTACH_POSITION,
82 //XmNrightPosition, SPLIT_NUMERATOR,
83 XmNleftAttachment, XmATTACH_FORM,
84 XmNtopAttachment, XmATTACH_FORM,
87 XtVaSetValues(goalarea, XmNleftAttachment, XmATTACH_WIDGET,
88 XmNleftWidget, gamearea,
89 XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
90 XmNtopWidget, gamearea,
93 resize_rec.string = "ResizeGameArea";
94 resize_rec.proc = ResizeGameArea;
95 XtAppAddActions(XtWidgetToApplicationContext(form), &resize_rec, 1);
96 XtOverrideTranslations(form, XtParseTranslationTable(
97 "<Configure>: ResizeGameArea()\n"
98 "<Map>: ResizeGameArea()\n"
103 construct_widgets(const struct ui_widget *root, Widget parent, unsigned i)
105 const struct ui_widget *item;
107 for (item = &root[i]; item->name; item++) {
110 w = XtCreateWidget(&tree_strtab[item->name], *item->class,
113 construct_widgets(root, w, item->subtree);
116 if (item->configure) {
124 static void game_resize(Widget w, void *data, void *cb_data)
127 x11_redraw_game(data);
130 static void goal_resize(Widget w, void *data, void *cb_data)
133 x11_redraw_goal(data);
136 static void game_input(Widget w, void *data, void *cb_data)
138 XmDrawingAreaCallbackStruct *cbs = cb_data;
139 XButtonEvent *click = &cbs->event->xbutton;
140 struct app_state *state = data;
141 Dimension width, height;
142 unsigned x = -1, y = -1;
144 switch (cbs->event->type) {
146 XtVaGetValues(w, XmNwidth, &width,
149 x = click->x / (width/5);
150 y = click->y / (width/5);
156 if (game_do_move(&state->board, x, y) == 0) {
157 x11_redraw_game(state);
161 void ui_initialize(struct app_state *state, Widget shell)
163 construct_widgets(mainwin, shell, 0);
165 state->game = XtNameToWidget(shell, "*gameCanvas");
166 state->goal = XtNameToWidget(shell, "*goalCanvas");
168 XtAddCallback(state->game, XmNresizeCallback, game_resize, state);
169 XtAddCallback(state->game, XmNexposeCallback, game_resize, state);
170 XtAddCallback(state->game, XmNinputCallback, game_input, state);
172 XtAddCallback(state->goal, XmNresizeCallback, goal_resize, state);
173 XtAddCallback(state->goal, XmNexposeCallback, goal_resize, state);