1 /*
2  * XP-Replay, playback an XPilot session.  Copyright (C) 1994-98 by
3  *
4  *      Bj�rn Stabell        <bjoern@xpilot.org>
5  *      Ken Ronny Schouten   <ken@xpilot.org>
6  *      Bert Gijsbers        <bert@xpilot.org>
7  *      Steven Singer        (S.Singer@ph.surrey.ac.uk)
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERC_HANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23 
24 #include "xp-replay.h"
25 
26 #include "tools/grey.xbm"
27 
28 struct button {
29     struct button	*next;
30     Display		*display;
31     Window		window;
32     unsigned long	fg;
33     unsigned int	width;
34     unsigned int	height;
35     union button_image	image;
36     unsigned int	imagewidth;
37     unsigned int	imageheight;
38     int			flags;
39     int			group;
40     void		(*callback)(void *);
41     void		*data;
42 };
43 
44 static unsigned long	background = 0,
45 			topshadow = 0,
46 			bottomshadow = 0,
47 			black = 0;
48 static Button		buttonhead = NULL, buttontail = NULL;
49 static XFontStruct	*buttonFont = NULL;
50 
SetGlobalButtonAttributes(unsigned long bg,unsigned long ts,unsigned long bs,unsigned long bl)51 void SetGlobalButtonAttributes(unsigned long bg,
52 			       unsigned long ts,
53 			       unsigned long bs,
54 			       unsigned long bl)
55 {
56     Button b;
57     int flag = 0;
58 
59     if (background != bg) {
60 	for (b = buttonhead; b != NULL; b = b->next)
61 	    XSetWindowBackground(b->display, b->window, bg);
62 	background = bg;
63 	flag = 1;
64     }
65     background = bg;
66     if (topshadow != ts || bottomshadow != bs || black != bl)
67 	flag = 1;
68     topshadow = ts;
69     bottomshadow = bs;
70     black = bl;
71     if (flag)
72 	for (b = buttonhead; b != NULL; b = b->next)
73 	    RedrawButton(b);
74 }
75 
SetButtonFont(Display * display)76 static void SetButtonFont(Display *display)
77 {
78     if ((buttonFont =
79 	 XLoadQueryFont(display,
80 			"-*-helvetica-bold-r-*--14-*-*-*-*-*-*-*")) == NULL)
81 	buttonFont = XQueryFont(display, XGContextFromGC(DefaultGC(display,
82 	    DefaultScreen(display))));
83 }
84 
CreateButton(Display * display,Window parent,int x,int y,unsigned int width,unsigned int height,union button_image image,unsigned iw,unsigned ih,unsigned long foreground,void (* callback)(void *),void * data,int flags,int group)85 Button CreateButton(Display *display, Window parent,
86 		    int x, int y,
87 		    unsigned int width, unsigned int height,
88 		    union button_image image,
89 		    unsigned iw, unsigned ih,
90 		    unsigned long foreground,
91 		    void (*callback)(void *),
92 		    void *data, int flags, int group)
93 {
94     Window window;
95     Button b;
96 
97     b = (Button) MyMalloc(sizeof(struct button), MEM_UI);
98 
99     if ((width == 0 || height == 0) && (flags & BUTTON_TEXT)) {
100 	if (buttonFont == NULL)
101 	    SetButtonFont(display);
102 	if (width == 0)
103 	    width = XTextWidth(buttonFont, image.string,
104 			       (int)strlen(image.string)) + 10;
105 	if (height == 0)
106 	    height = buttonFont->ascent + buttonFont->descent + 10;
107     }
108 
109     window = XCreateSimpleWindow(display, parent,
110 				 x, y,
111 				 width, height,
112 				 0,
113 				 background, background);
114 
115     b->display = display;
116     b->window = window;
117     b->fg = foreground;
118     b->width = width;
119     b->height = height;
120     b->image = image;
121     b->imagewidth = iw;
122     b->imageheight = ih;
123     b->flags = flags;
124     b->group = group;
125     b->callback = callback;
126     b->data = data;
127     b->next = NULL;
128 
129     if (buttontail == NULL)
130 	buttonhead = buttontail = b;
131     else {
132 	buttontail->next = b;
133 	buttontail = b;
134     }
135 
136     XSelectInput(display, window,
137 		 ExposureMask | ButtonPressMask | ButtonReleaseMask);
138 
139     XMapWindow(display, window);
140 
141     return(b);
142 }
143 
ReleaseButtons(Button b)144 static void ReleaseButtons(Button b)
145 {
146     Button c;
147 
148     if (b->group != 0) {
149 	for (c = buttonhead; c != NULL; c = c->next)
150 	    if (c->group == b->group && c != b
151 		&& (c->flags & BUTTON_PRESSED)) {
152 		c->flags &= ~BUTTON_PRESSED;
153 		RedrawButton(c);
154 	    }
155     }
156 }
157 
PressButton(Button b)158 static void PressButton(Button b)
159 {
160     /* Buttons which stay in have no affect if pressed when in */
161 
162     if ((b->flags & BUTTON_PRESSED && !(b->flags & BUTTON_RELEASE)) ||
163 	b->flags & BUTTON_DISABLED)
164 	return;
165 
166     ReleaseButtons(b);
167 
168     b->flags |= BUTTON_PRESSED;
169 
170     RedrawButton(b);
171 
172     if (!(b->flags & BUTTON_RELEASE) && b->callback != NULL)
173 	b->callback(b->data);
174 }
175 
ReleaseButton(Button b,Bool inwindow)176 static void ReleaseButton(Button b, Bool inwindow)
177 {
178 
179     if (!(b->flags & BUTTON_PRESSED) || !(b->flags & BUTTON_RELEASE) ||
180 	b->flags & BUTTON_DISABLED)
181 	return;
182 
183     b->flags &= ~BUTTON_PRESSED;
184 
185     RedrawButton(b);
186 
187     if (inwindow && b->callback != NULL)
188 	b->callback(b->data);
189 }
190 
CheckButtonEvent(XEvent * event)191 int CheckButtonEvent(XEvent *event)
192 {
193     Button b;
194 
195     for (b = buttonhead; b != NULL; b = b->next)
196 	if (event->xany.window == b->window)
197 	    break;
198 
199     if (b == NULL)
200 	return(0);
201 
202     switch(event->type) {
203     case Expose:
204 	if (event->xexpose.count != 0)
205 	    return(1);
206 	RedrawButton(b);
207 	return(1);
208     case ButtonPress:
209 	if (event->xbutton.button == 1)
210 	    PressButton(b);
211 	return(1);
212     case ButtonRelease:
213 	if (event->xbutton.button == 1)
214 	    ReleaseButton(b, (event->xbutton.x >= 0 &&
215 			      event->xbutton.y >= 0 &&
216 			      event->xbutton.x < (int)b->width &&
217 			      event->xbutton.y < (int)b->height)
218 			  ? True : False);
219 	return(1);
220     default:
221 	break;
222     }
223 
224     return(0);
225 }
226 
RedrawButton(Button b)227 void RedrawButton(Button b)
228 {
229     static GC gc = 0;
230     static Pixmap grey = 0;
231     int bh = b->height, bw = b->width;
232 
233     if (gc == 0) {
234 	gc = XCreateGC(b->display, b->window, 0, NULL);
235 	if (buttonFont == NULL)
236 	    SetButtonFont(b->display);
237 	XSetFont(b->display, gc, buttonFont->fid);
238     }
239 
240     if (grey == 0) {
241 	grey = XCreateBitmapFromData(b->display, b->window, (char *) grey_bits,
242 				     grey_width, grey_height);
243 	XSetStipple(b->display, gc, grey);
244     }
245 
246     XSetBackground(b->display, gc, background);
247 
248     XClearWindow(b->display, b->window);
249 
250     XSetForeground(b->display, gc, b->fg);
251 
252     if (b->flags & BUTTON_TEXT)
253  	XDrawString(b->display, b->window, gc, 5, 5 + buttonFont->ascent,
254 		    b->image.string, (int)strlen(b->image.string));
255     else if (b->image.icon != None) {
256 	int x, y;
257 	unsigned w, h;
258 
259 	w = (b->imagewidth);
260 	if (w > b->width)
261 	    w = b->width;
262 	h = (b->imageheight);
263 	if (h > b->height)
264 	    h = b->height;
265 	x = (b->width - w) >> 1;
266 	y = (b->height - h) >> 1;
267 	XCopyPlane(b->display, b->image.icon, b->window, gc,
268 		   (int)((b->imagewidth-w) >> 1),
269 		   (int)((b->imageheight-h) >> 1),
270 		   w, h, x, y, 1);
271     }
272 
273     if (b->flags & BUTTON_DISABLED) {
274 	XSetForeground(b->display, gc, background);
275 	    XSetFillStyle(b->display, gc, FillStippled);
276 	XFillRectangle(b->display, b->window, gc, 0, 0, b->width, b->height);
277 	XSetFillStyle(b->display, gc, FillSolid);
278     }
279 
280     if (b->flags & BUTTON_PRESSED) {
281 	XSetForeground(b->display, gc, black);
282 	XDrawRectangle(b->display, b->window, gc,
283 		       0, 0, b->width-1, b->height-1);
284 	XDrawRectangle(b->display, b->window, gc,
285 		       1, 1, b->width-3, b->height-3);
286     } else {
287 	XSetForeground(b->display, gc, bottomshadow);
288 	XDrawLine(b->display, b->window, gc, 0, bh-1, bw-1, bh-1);
289 	XDrawLine(b->display, b->window, gc, bw-1, bh-1, bw-1, 0);
290 	XSetForeground(b->display, gc, topshadow);
291 	XDrawLine(b->display, b->window, gc, 0, 0, bw-1, 0);
292 	XDrawLine(b->display, b->window, gc, 0, 0, 0, bh-1);
293 	XSetForeground(b->display, gc, bottomshadow);
294 	XDrawLine(b->display, b->window, gc, 1, bh-2, bw-2, bh-2);
295 	XDrawLine(b->display, b->window, gc, bw-2, bh-2, bw-2, 1);
296 	XSetForeground(b->display, gc, topshadow);
297 	XDrawLine(b->display, b->window, gc, 1, 1, bw-2, 1);
298 	XDrawLine(b->display, b->window, gc, 1, 1, 1, bh-2);
299     }
300 
301     XSetForeground(b->display, gc, bottomshadow);
302     XDrawLine(b->display, b->window, gc, 2, bh-3, bw-3, bh-3);
303     XDrawLine(b->display, b->window, gc, bw-3, bh-3, bw-3, 2);
304     XSetForeground(b->display, gc, topshadow);
305     XDrawLine(b->display, b->window, gc, 2, 2, bw-3, 2);
306     XDrawLine(b->display, b->window, gc, 2, 2, 2, bh-3);
307 
308 }
309 
DisableButton(Button b)310 void DisableButton(Button b)
311 {
312     if (b->flags & BUTTON_DISABLED)
313 	return;
314 
315     b->flags |= BUTTON_DISABLED;
316 
317     RedrawButton(b);
318 }
319 
EnableButton(Button b)320 void EnableButton(Button b)
321 {
322     if (!(b->flags & BUTTON_DISABLED))
323 	return;
324 
325     b->flags &= ~BUTTON_DISABLED;
326 
327     RedrawButton(b);
328 }
329 
ReleaseableButton(Button b)330 void ReleaseableButton(Button b)
331 {
332     int i;
333 
334     i = (b->flags & BUTTON_PRESSED);
335 
336     b->flags &= ~BUTTON_PRESSED;
337     b->flags |= BUTTON_RELEASE;
338 
339     if (i)
340 	RedrawButton(b);
341 }
342 
NonreleaseableButton(Button b)343 void NonreleaseableButton(Button b)
344 {
345     b->flags &= ~BUTTON_RELEASE;
346 }
347 
ChangeButtonGroup(Button b,int group)348 void ChangeButtonGroup(Button b, int group)
349 {
350     if (group == b->group)
351 	return;
352 
353     b->group = group;
354 
355     if (b->flags & BUTTON_PRESSED)
356 	ReleaseButtons(b);
357 }
358 
MoveButton(Button b,int x,int y)359 void MoveButton(Button b, int x, int y)
360 {
361     XWindowChanges values;
362 
363     values.x = x;
364     values.y = y;
365 
366     XConfigureWindow(b->display, b->window, CWX | CWY, &values);
367 }
368 
GetButtonSize(Button b,unsigned * width,unsigned * height)369 void GetButtonSize(Button b, unsigned *width, unsigned *height)
370 {
371     *width = b->width;
372     *height = b->height;
373 }
374