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