]> git.draconx.ca Git - rrace.git/blob - src/motif_ui.c
Initial commit
[rrace.git] / src / motif_ui.c
1 /*
2  * X11 GUI for slide puzzle game
3  * Copyright © 2022 Nick Bowler
4  *
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.
9  *
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.
14  *
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/>.
17  */
18
19 #include <config.h>
20 #include <inttypes.h>
21 #include <assert.h>
22 #include <Xm/XmAll.h>
23
24 #include "motif.h"
25 #include "motifgui.h"
26
27 #define SPLIT_NUMERATOR    75
28 #define SPLIT_DENOMINATOR 100
29
30 #define MIN(a, b) ((a) < (b) ? (a) : (b))
31
32 static void game_configure(Widget w);
33
34 static const struct ui_widget {
35         uint_least16_t name;
36         uint_least16_t subtree;
37         WidgetClass *class;
38         void (*configure)(Widget w);
39 } mainwin[] = { MAINWIN_INITIALIZER };
40
41 static void
42 ResizeGameArea(Widget form, XEvent *e, String *args, Cardinal *num_args)
43 {
44         Widget game = XtNameToWidget(form, &tree_strtab[gameArea]);
45         Widget goal = XtNameToWidget(form, &tree_strtab[goalArea]);
46         Dimension w, h, gamesz, gameborder, goalsz, goalborder;
47         int x, y, gap;
48
49         XtVaGetValues(form, XmNwidth, &w, XmNheight, &h, (char *)NULL);
50         XtVaGetValues(game, XmNshadowThickness, &gameborder, (char *)NULL);
51         XtVaGetValues(goal, XmNshadowThickness, &goalborder,
52                             XmNleftOffset, &gap,
53                             (char *)NULL);
54
55         gamesz = MIN(h, w * SPLIT_NUMERATOR / SPLIT_DENOMINATOR);
56         gamesz = 5*( (gamesz - 2*gameborder)/5 ) + 2*gameborder;
57
58         goalsz = MIN(gamesz*3/5, w - gamesz - gap);
59         goalsz = 3*( (goalsz - 2*goalborder)/3 ) + 2*goalborder;
60
61         x = (w - gamesz - goalsz - gap) / 2;
62         if (x < 2) x = 0;
63
64         y = (h - gamesz) / 2;
65         if (y < 3) y = 0;
66
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);
70 }
71
72 static void game_configure(Widget form)
73 {
74         Widget gamearea = XtNameToWidget(form, &tree_strtab[gameArea]);
75         Widget goalarea = XtNameToWidget(form, &tree_strtab[goalArea]);
76         XtActionsRec resize_rec;
77
78         assert(gamearea && goalarea);
79         XtVaSetValues(form, XmNfractionBase, SPLIT_DENOMINATOR, (char *)NULL);
80
81         XtVaSetValues(gamearea, //XmNrightAttachment, XmATTACH_POSITION,
82                                 //XmNrightPosition, SPLIT_NUMERATOR,
83                                 XmNleftAttachment, XmATTACH_FORM,
84                                 XmNtopAttachment, XmATTACH_FORM,
85                                 (char *)NULL);
86
87         XtVaSetValues(goalarea, XmNleftAttachment, XmATTACH_WIDGET,
88                                 XmNleftWidget, gamearea,
89                                 XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
90                                 XmNtopWidget, gamearea,
91                                 (char *)NULL);
92
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"
99         ));
100 }
101
102 static void
103 construct_widgets(const struct ui_widget *root, Widget parent, unsigned i)
104 {
105         const struct ui_widget *item;
106
107         for (item = &root[i]; item->name; item++) {
108                 Widget w;
109
110                 w = XtCreateWidget(&tree_strtab[item->name], *item->class,
111                                    parent, NULL, 0);
112                 if (item->subtree) {
113                         construct_widgets(root, w, item->subtree);
114                 }
115
116                 if (item->configure) {
117                         item->configure(w);
118                 }
119
120                 XtManageChild(w);
121         }
122 }
123
124 static void game_resize(Widget w, void *data, void *cb_data)
125 {
126         Dimension width, height;
127
128         XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, (char *)NULL);
129
130         printf("game %ux%u\n", width, height);
131 }
132
133 static void goal_resize(Widget w, void *data, void *cb_data)
134 {
135         Dimension width, height;
136
137         XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, (char *)NULL);
138
139         printf("goal %ux%u\n", width, height);
140 }
141
142 void ui_initialize(Widget shell)
143 {
144         Widget game, goal;
145
146         construct_widgets(mainwin, shell, 0);
147
148         game = XtNameToWidget(shell, "*gameCanvas");
149         goal = XtNameToWidget(shell, "*goalCanvas");
150
151         XtAddCallback(game, XmNresizeCallback, game_resize, NULL);
152         XtAddCallback(goal, XmNresizeCallback, goal_resize, NULL);
153 }