1 // Dialog push button handler
2 // Copyright (C) 2000 Core Technologies.
3
4 // This file is part of e93.
5 //
6 // e93 is free software; you can redistribute it and/or modify
7 // it under the terms of the e93 LICENSE AGREEMENT.
8 //
9 // e93 is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // e93 LICENSE AGREEMENT for more details.
13 //
14 // You should have received a copy of the e93 LICENSE AGREEMENT
15 // along with e93; see the file "LICENSE.TXT".
16
17 #include "includes.h"
18
19 #define SHADOW_COLOR_UL 0x91AFBE // shadow colors (upper left)
20 #define SHADOW_COLOR_LR 0x314F5E // (lower right)
21
22 #define MAX_BUTTON_NAME 256 // maximum length of button name (including terminator)
23
24 typedef struct button
25 {
26 EDITOR_WINDOW
27 *parentWindow; // the window that contains this button
28 buttonResizeFunction
29 *resizeFunction; // function which is used to resize for this window
30 EDITOR_RECT
31 rect;
32 EDITOR_FONT
33 *font; // info about currently selected font
34 char
35 buttonName[MAX_BUTTON_NAME];
36 bool
37 highlight; // used during tracking to remember if highlighted
38 bool
39 hasKey; // true if this button has a key code associated with it
40 KeySym
41 keySym; // equivalent key code for this button
42 bool
43 *pressedState; // boolean set to true if button pressed
44 void
45 (*pressedProc)(void *parameters); // routine called when the button has been pressed
46 void
47 *pressedProcParameters; // data passed to pressedProc routine
48 } BUTTON;
49
50
PointInButton(BUTTON * button,INT32 x,INT32 y)51 static bool PointInButton(BUTTON *button,INT32 x,INT32 y)
52 // return true if parent window relative x/y are in button
53 // false if not
54 {
55 return(PointInRECT(x,y,&button->rect));
56 }
57
InvalidateButton(BUTTON * button)58 static void InvalidateButton(BUTTON *button)
59 // invalidate the button within its parent window
60 {
61 InvalidateWindowRect(button->parentWindow,&button->rect);
62 }
63
SetButtonRectangle(BUTTON * button)64 static void SetButtonRectangle(BUTTON *button)
65 // Work out the rectangle given the current window
66 {
67 if(button->resizeFunction) // see if non-null resize function specified
68 {
69 button->resizeFunction(button->parentWindow,&button->rect); // get new rectangle
70 InvalidateButton(button); // invalidate it
71 }
72 }
73
DrawButton(BUTTON * button,Pixmap imageBuffer,Region updateRegion)74 static void DrawButton(BUTTON *button,Pixmap imageBuffer,Region updateRegion)
75 // redraw button in its parent window, obey the invalid area of the parent's window
76 {
77 int
78 stringLength,
79 stringWidth;
80 int
81 stringX,
82 stringY;
83 EDITOR_COLOR
84 background,
85 upLeftHighlight,
86 downRightHighlight;
87
88 XSetRegion(xDisplay,xGraphicsContext,updateRegion); // set clipping to what's invalid
89
90 if(button->rect.w&&button->rect.h)
91 {
92 if(button->highlight)
93 {
94 background=GRAY_2;
95 upLeftHighlight=SHADOW_COLOR_LR;
96 downRightHighlight=SHADOW_COLOR_UL;
97 }
98 else
99 {
100 background=GRAY_3;
101 upLeftHighlight=SHADOW_COLOR_UL;
102 downRightHighlight=SHADOW_COLOR_LR;
103 }
104 XSetFillStyle(xDisplay,xGraphicsContext,FillSolid);
105 XSetForeground(xDisplay,xGraphicsContext,EditorColorToXPixel(background));
106 XFillRectangle(xDisplay,imageBuffer,xGraphicsContext,button->rect.x,button->rect.y,button->rect.w,button->rect.h);
107
108 OutlineShadowRectangle(imageBuffer,&button->rect,upLeftHighlight,downRightHighlight,2);
109
110 stringLength=strlen(&(button->buttonName[0]));
111 stringWidth=XTextWidth(button->font->xFont,&(button->buttonName[0]),stringLength);
112 stringX=button->rect.x+(button->rect.w/2)-(stringWidth/2);
113 stringY=button->rect.y+(button->rect.h/2)-(button->font->ascent+button->font->descent)/2+button->font->ascent;
114
115 if(button->highlight)
116 {
117 stringX--;
118 stringY--;
119 }
120
121 XSetForeground(xDisplay,xGraphicsContext,EditorColorToXPixel(BLACK));
122 XSetFont(xDisplay,xGraphicsContext,button->font->xFont->fid); // point to the current font for this button
123 XDrawString(xDisplay,imageBuffer,xGraphicsContext,stringX,stringY,&(button->buttonName[0]),stringLength);
124 }
125 XSetClipMask(xDisplay,xGraphicsContext,None); // get rid of clip mask
126 }
127
PressButton(BUTTON * button)128 static void PressButton(BUTTON *button)
129 // call this and button will behave as if it has been pressed
130 {
131 button->highlight=true;
132 InvalidateButton(button);
133 UpdateEditorWindows();
134 if(button->pressedState)
135 {
136 (*button->pressedState)=true;
137 }
138 if(button->pressedProc)
139 {
140 button->pressedProc(button->pressedProcParameters);
141 }
142 button->highlight=false;
143 InvalidateButton(button);
144 }
145
TrackButton(BUTTON * button,XEvent * event)146 static bool TrackButton(BUTTON *button,XEvent *event)
147 // see if the point given by event falls over button,
148 // if so, track it, and return true
149 // if not, return false
150 {
151 bool
152 onButton,
153 wasOnButton;
154 Window
155 root,
156 child;
157 int
158 rootX,
159 rootY,
160 windowX,
161 windowY;
162 unsigned int
163 state;
164
165 if((event->xbutton.button==Button1)&&PointInButton(button,event->xbutton.x,event->xbutton.y))
166 {
167 button->highlight=true;
168 InvalidateButton(button);
169 UpdateEditorWindows(); // redraw anything that is needed
170 wasOnButton=onButton=true;
171 while(StillDown(Button1,1))
172 {
173 if(XQueryPointer(xDisplay,((WINDOW_LIST_ELEMENT *)button->parentWindow->userData)->xWindow,&root,&child,&rootX,&rootY,&windowX,&windowY,&state))
174 {
175 onButton=PointInButton(button,windowX,windowY);
176 }
177 if(wasOnButton!=onButton)
178 {
179 button->highlight=onButton;
180 InvalidateButton(button);
181 UpdateEditorWindows(); // redraw anything that is needed
182 wasOnButton=onButton;
183 }
184 }
185 if(onButton)
186 {
187 PressButton(button);
188 }
189 button->highlight=false;
190 InvalidateButton(button);
191 return(true);
192 }
193 return(false);
194 }
195
ButtonKeyOverride(BUTTON * button,XEvent * event)196 static bool ButtonKeyOverride(BUTTON *button,XEvent *event)
197 // this is called for buttons that may wish to grab keys before they go
198 // into the default focus of a dialog
199 // true is returned if the button wanted the key
200 {
201 KeySym
202 keySym;
203 XKeyEvent
204 localKeyEvent; // make a local copy so we can strip annoying bits
205
206 if(button->hasKey)
207 {
208 localKeyEvent=*(XKeyEvent *)event; // copy the event
209 localKeyEvent.state&=(~(Mod1Mask|LockMask)); // remove these from consideration
210 ComposeXLookupString(&localKeyEvent,NULL,0,&keySym);
211 if(keySym==button->keySym)
212 {
213 PressButton(button);
214 return(true);
215 }
216 }
217 return(false);
218 }
219
CreateButton(EDITOR_WINDOW * window,BUTTON_DESCRIPTOR * descriptor)220 static BUTTON *CreateButton(EDITOR_WINDOW *window,BUTTON_DESCRIPTOR *descriptor)
221 // create a button in window, invalidate the area of window
222 // where the button is to be placed
223 // return a pointer to it if successful
224 // SetError, and return NULL if not
225 {
226 BUTTON
227 *button;
228
229 if((button=(BUTTON *)MNewPtr(sizeof(BUTTON)))) // create button data structure
230 {
231 button->parentWindow=window;
232 button->resizeFunction=descriptor->resizeFunction;
233 strncpy(&(button->buttonName[0]),descriptor->buttonName,MAX_BUTTON_NAME);
234 button->buttonName[MAX_BUTTON_NAME-1]='\0'; // terminate the string as needed
235 button->highlight=false; // not highlighted
236 button->hasKey=descriptor->hasKey; // true if this button has a key code associated with it
237 button->keySym=descriptor->keySym; // equivalent key code for this button
238 button->pressedState=descriptor->pressedState; // points to a bool (or to NULL) that is set to true if this button has been pressed
239 button->pressedProc=descriptor->pressedProc; // copy the procedure to be called when the button is pressed
240 button->pressedProcParameters=descriptor->pressedProcParameters; // copy parameters for pressed Proc
241 if((button->font=LoadEditorFont(descriptor->fontName)))
242 {
243 SetButtonRectangle(button);
244 return(button);
245 }
246 MDisposePtr(button);
247 }
248 return(NULL);
249 }
250
DisposeButton(BUTTON * button)251 static void DisposeButton(BUTTON *button)
252 // unlink button from its parent window, and delete it
253 // invalidate the area of the window where button was
254 {
255 InvalidateButton(button); // invalidate where it is now
256 FreeEditorFont(button->font);
257 MDisposePtr(button);
258 }
259
260 // dialog interface routines
261
DrawButtonItem(DIALOG_ITEM * item,Pixmap imageBuffer,Region updateRegion)262 static void DrawButtonItem(DIALOG_ITEM *item,Pixmap imageBuffer,Region updateRegion)
263 // draw the button pointed to by item
264 {
265 DrawButton((BUTTON *)item->itemStruct,imageBuffer,updateRegion);
266 }
267
ResizeButtonItem(DIALOG_ITEM * item)268 static void ResizeButtonItem(DIALOG_ITEM *item)
269 // When the dialog window size changes, call this to update the item itself
270 // This will invalidate the old and new item areas
271 {
272 BUTTON
273 *button;
274
275 button=(BUTTON *)item->itemStruct;
276 InvalidateButton(button); // invalidate where we're at currently
277 SetButtonRectangle(button);
278 }
279
PressButtonItem(DIALOG_ITEM * item)280 void PressButtonItem(DIALOG_ITEM *item)
281 // Do whatever would be done if the user pressed item
282 {
283 PressButton((BUTTON *)item->itemStruct);
284 }
285
TrackButtonItem(DIALOG_ITEM * item,XEvent * event)286 static bool TrackButtonItem(DIALOG_ITEM *item,XEvent *event)
287 // track the button pointed to by item
288 {
289 return(TrackButton((BUTTON *)item->itemStruct,event));
290 }
291
EarlyKeyButtonItem(DIALOG_ITEM * item,XEvent * event)292 static bool EarlyKeyButtonItem(DIALOG_ITEM *item,XEvent *event)
293 // see if this button wants the key given by event, if so, return true
294 {
295 return(ButtonKeyOverride((BUTTON *)item->itemStruct,event));
296 }
297
DisposeButtonItem(DIALOG_ITEM * item)298 static void DisposeButtonItem(DIALOG_ITEM *item)
299 // dispose of the local button structure pointed to by item
300 {
301 DisposeButton((BUTTON *)item->itemStruct);
302 }
303
CreateButtonItem(DIALOG_ITEM * item,void * descriptor)304 bool CreateButtonItem(DIALOG_ITEM *item,void *descriptor)
305 // create the button, and fill in item
306 // if there is a problem, SetError, return false
307 {
308 if((item->itemStruct=(void *)CreateButton(item->dialog->parentWindow,(BUTTON_DESCRIPTOR *)descriptor)))
309 {
310 item->disposeProc=DisposeButtonItem;
311 item->drawProc=DrawButtonItem;
312 item->resizeProc=ResizeButtonItem;
313 item->trackProc=TrackButtonItem;
314 item->earlyKeyProc=EarlyKeyButtonItem;
315 item->wantFocus=false;
316 item->focusChangeProc=NULL;
317 item->focusKeyProc=NULL;
318 item->focusPeriodicProc=NULL;
319 return(true);
320 }
321 return(false);
322 }
323