1 // Text box handling for dialogs
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	BORDER_WIDTH			3
20 #define	SHADOW_COLOR_UL			0x314F5E	// shadow colors (upper left)
21 #define	SHADOW_COLOR_LR			0x91AFBE	// (lower right)
22 
23 typedef struct textBox
24 {
25 	EDITOR_WINDOW
26 		*parentWindow;					// the window that contains this text box
27 	textBoxResizeFunction
28 		*resizeFunction;				// function which is used to resize for this window
29 	EDITOR_RECT
30 		rect;							// position and size within parent window
31 	EDITOR_COLOR
32 		focusBackgroundColor,			// color to use when drawing background when we have the focus
33 		focusForegroundColor,			// color to use when drawing foreground when we have the focus
34 		nofocusBackgroundColor,			// color to use when drawing background when we do not have focus
35 		nofocusForegroundColor;			// color to use when drawing foreground when we do not have focus
36 	EDITOR_VIEW
37 		*view;							// the view that this text box item made
38 } TEXT_BOX;
39 
InvalidateTextBox(TEXT_BOX * textBox)40 static void InvalidateTextBox(TEXT_BOX *textBox)
41 // invalidate the text box within its parent window
42 {
43 	InvalidateWindowRect(textBox->parentWindow,&textBox->rect);
44 }
45 
GetTextBoxControlRects(TEXT_BOX * textBox,EDITOR_RECT * borderRect,EDITOR_RECT * textContentRect)46 static void GetTextBoxControlRects(TEXT_BOX *textBox,EDITOR_RECT *borderRect,EDITOR_RECT *textContentRect)
47 // return the rectangles that enclose the various pieces of textBox
48 // if the text box starts getting too small, certain rects may be returned with 0 width or
49 // height
50 {
51 	EDITOR_RECT
52 		insetRect;
53 
54 	insetRect=*borderRect=textBox->rect;					// border rect is the whole thing
55 
56 	insetRect.x+=BORDER_WIDTH;								// inset from the border to the content area of the text box
57 	insetRect.y+=BORDER_WIDTH;
58 	if(insetRect.w>2*BORDER_WIDTH)
59 	{
60 		insetRect.w-=2*BORDER_WIDTH;
61 	}
62 	else
63 	{
64 		insetRect.w=0;
65 	}
66 	if(insetRect.h>2*BORDER_WIDTH)
67 	{
68 		insetRect.h-=2*BORDER_WIDTH;
69 	}
70 	else
71 	{
72 		insetRect.h=0;
73 	}
74 	*textContentRect=insetRect;
75 }
76 
SetTextBoxRectangle(TEXT_BOX * textBox)77 static void SetTextBoxRectangle(TEXT_BOX *textBox)
78 // Work out the rectangle given the current window
79 {
80 	EDITOR_RECT
81 		borderRect,
82 		textContentRect;
83 
84 	if(textBox->resizeFunction)			// see if non-null resize function specified
85 	{
86 		textBox->resizeFunction(textBox->parentWindow,&textBox->rect);	// get new rectangle
87 		GetTextBoxControlRects(textBox,&borderRect,&textContentRect);
88 		SetViewBounds(textBox->view,&textContentRect);		// move the view over
89 		InvalidateTextBox(textBox);							// invalidate it
90 	}
91 }
92 
PointInTextBox(TEXT_BOX * textBox,INT32 x,INT32 y)93 static bool PointInTextBox(TEXT_BOX *textBox,INT32 x,INT32 y)
94 // return true if parent window relative x/y are in textBox
95 // false if not
96 {
97 	return(PointInRECT(x,y,&textBox->rect));
98 }
99 
DrawTextBox(TEXT_BOX * textBox,Pixmap imageBuffer,Region updateRegion,bool hasFocus)100 static void DrawTextBox(TEXT_BOX *textBox,Pixmap imageBuffer,Region updateRegion,bool hasFocus)
101 // redraw textBox in its parent window, obey the invalid area of the parent's window
102 {
103 	XRectangle
104 		regionBox;
105 	Region
106 		invalidRegion;
107 	EDITOR_RECT
108 		borderRect,
109 		textContentRect;
110 
111 	GetTextBoxControlRects(textBox,&borderRect,&textContentRect);
112 
113 	invalidRegion=XCreateRegion();
114 
115 	regionBox.x=borderRect.x;
116 	regionBox.y=borderRect.y;
117 	regionBox.width=borderRect.w;
118 	regionBox.height=borderRect.h;
119 	XUnionRectWithRegion(&regionBox,invalidRegion,invalidRegion);					// create a region which is the rectangle of the text box
120 	XIntersectRegion(invalidRegion,updateRegion,invalidRegion);						// intersect with what is invalid in this window
121 
122 	if(!XEmptyRegion(invalidRegion))												// see if it has an invalid area
123 	{
124 		XSetRegion(xDisplay,xGraphicsContext,invalidRegion);						// set clipping to what's invalid
125 		if(!hasFocus)
126 		{
127 			OutlineShadowRectangle(imageBuffer,&borderRect,SHADOW_COLOR_UL,SHADOW_COLOR_LR,BORDER_WIDTH);	// drop in border
128 		}
129 		else
130 		{
131 			OutlineShadowRectangle(imageBuffer,&borderRect,BLACK,GRAY_1,BORDER_WIDTH);	// drop in border
132 		}
133 		XSetClipMask(xDisplay,xGraphicsContext,None);								// get rid of clip mask
134 	}
135 	XDestroyRegion(invalidRegion);													// get rid of invalid region
136 	DrawView(textBox->view,imageBuffer,updateRegion);
137 }
138 
TrackTextBox(TEXT_BOX * textBox,XEvent * event)139 static bool TrackTextBox(TEXT_BOX *textBox,XEvent *event)
140 // a button was pressed, see if it was in textBox, if so, track it, and return true
141 // if it was not within the text box, return false
142 {
143 	return(TrackView(textBox->view,event));	// only thing tracking in the text box is the view
144 }
145 
HandleTextBoxKeyEvent(TEXT_BOX * textBox,XEvent * event)146 static void HandleTextBoxKeyEvent(TEXT_BOX *textBox,XEvent *event)
147 // A keyboard event is arriving for the text box, handle it here
148 {
149 	HandleViewKeyEvent(textBox->view,event);
150 }
151 
ActivateTextBox(TEXT_BOX * textBox)152 static void ActivateTextBox(TEXT_BOX *textBox)
153 // when the text box gets focus, call this to make it active
154 {
155 	SetEditorViewStyleForegroundColor(textBox->view,0,textBox->focusForegroundColor);
156 	SetEditorViewStyleBackgroundColor(textBox->view,0,textBox->focusBackgroundColor);
157 	EditorActivateView(textBox->view);
158 	ResetEditorViewCursorBlink(textBox->view);
159 	InvalidateTextBox(textBox);						// invalidate where it is now
160 }
161 
DeactivateTextBox(TEXT_BOX * textBox)162 static void DeactivateTextBox(TEXT_BOX *textBox)
163 // when the text box loses focus, call this to make it inactive
164 {
165 	SetEditorViewStyleForegroundColor(textBox->view,0,textBox->nofocusForegroundColor);
166 	SetEditorViewStyleBackgroundColor(textBox->view,0,textBox->nofocusBackgroundColor);
167 	EditorDeactivateView(textBox->view);
168 	InvalidateTextBox(textBox);						// invalidate where it is now
169 }
170 
HandleTextBoxPeriodicProc(TEXT_BOX * textBox)171 static void HandleTextBoxPeriodicProc(TEXT_BOX *textBox)
172 // call this to handle periodic things a text box must do
173 {
174 	ViewCursorTask(textBox->view);
175 }
176 
CreateTextBox(EDITOR_WINDOW * window,TEXT_BOX_DESCRIPTOR * description)177 static TEXT_BOX *CreateTextBox(EDITOR_WINDOW *window,TEXT_BOX_DESCRIPTOR *description)
178 // create a text box in window, invalidate the area of window
179 // where the text box is to be placed
180 // return a pointer to it if successful
181 // SetError, return NULL if not
182 {
183 	TEXT_BOX
184 		*textBox;
185 	EDITOR_VIEW_DESCRIPTOR
186 		viewDescriptor;
187 
188 	if((textBox=(TEXT_BOX *)MNewPtr(sizeof(TEXT_BOX))))			// create text box data structure
189 	{
190 		textBox->parentWindow=window;
191 
192 		textBox->resizeFunction=description->resizeFunction;
193 
194 		textBox->focusBackgroundColor=description->focusBackgroundColor;	// copy over the colors
195 		textBox->focusForegroundColor=description->focusForegroundColor;
196 		textBox->nofocusBackgroundColor=description->nofocusBackgroundColor;
197 		textBox->nofocusForegroundColor=description->nofocusForegroundColor;
198 
199 		viewDescriptor.buffer=description->buffer;				// the buffer on which to view
200 
201 		viewDescriptor.rect.x=0;								// initally make empty view
202 		viewDescriptor.rect.y=0;
203 		viewDescriptor.rect.w=0;
204 		viewDescriptor.rect.h=0;
205 		viewDescriptor.topLine=description->topLine;
206 		viewDescriptor.leftPixel=description->leftPixel;
207 		viewDescriptor.tabSize=description->tabSize;
208 		viewDescriptor.backgroundColor=textBox->nofocusBackgroundColor;
209 		viewDescriptor.foregroundColor=textBox->nofocusForegroundColor;
210 		viewDescriptor.fontName=description->fontName;			// initial font to use
211 		viewDescriptor.active=false;							// tells if the view is created active or not
212 		viewDescriptor.viewTextChangedVector=NULL;
213 		viewDescriptor.viewSelectionChangedVector=NULL;
214 		viewDescriptor.viewPositionChangedVector=NULL;
215 
216 		if((textBox->view=CreateEditorView(textBox->parentWindow,&viewDescriptor)))
217 		{
218 			SetTextBoxRectangle(textBox);
219 			return(textBox);
220 		}
221 		MDisposePtr(textBox);
222 	}
223 	return(NULL);
224 }
225 
DisposeTextBox(TEXT_BOX * textBox)226 static void DisposeTextBox(TEXT_BOX *textBox)
227 // unlink textBox from its parent window, and delete it
228 // invalidate the area of the window where the text box was
229 {
230 	InvalidateTextBox(textBox);					// invalidate where it is now
231 	DisposeEditorView(textBox->view);
232 	MDisposePtr(textBox);
233 }
234 
235 // dialog interface routines
236 
DrawTextBoxItem(DIALOG_ITEM * item,Pixmap imageBuffer,Region updateRegion)237 static void DrawTextBoxItem(DIALOG_ITEM *item,Pixmap imageBuffer,Region updateRegion)
238 // draw the view pointed to by item
239 {
240 	DrawTextBox((TEXT_BOX *)item->itemStruct,imageBuffer,updateRegion,(item==item->dialog->focusItem));	// draw the text box
241 }
242 
ResizeTextBoxItem(DIALOG_ITEM * item)243 static void ResizeTextBoxItem(DIALOG_ITEM *item)
244 // When the dialog window size changes, call this to update the item itself
245 // This will invalidate the old and new item areas
246 {
247 	TEXT_BOX
248 		*textBox;
249 
250 	textBox=(TEXT_BOX *)item->itemStruct;
251 	InvalidateTextBox(textBox);					// invalidate where we're at currently
252 	SetTextBoxRectangle(textBox);
253 }
254 
TrackTextBoxItem(DIALOG_ITEM * item,XEvent * event)255 static bool TrackTextBoxItem(DIALOG_ITEM *item,XEvent *event)
256 // attempt to track the text box pointed to by item
257 {
258 	if(PointInTextBox((TEXT_BOX *)item->itemStruct,event->xbutton.x,event->xbutton.y))
259 	{
260 		DialogTakeFocus(item);
261 		return(TrackTextBox((TEXT_BOX *)item->itemStruct,event));
262 	}
263 	return(false);
264 }
265 
DisposeTextBoxItem(DIALOG_ITEM * item)266 static void DisposeTextBoxItem(DIALOG_ITEM *item)
267 // dispose of the local text box structure pointed to by item
268 {
269 	DisposeTextBox((TEXT_BOX *)item->itemStruct);
270 }
271 
TextBoxItemFocusChange(DIALOG_ITEM * item)272 static void TextBoxItemFocusChange(DIALOG_ITEM *item)
273 // the focus is changing into, or out of this view item, deal with it
274 {
275 	if(item==item->dialog->focusItem)
276 	{
277 		ActivateTextBox((TEXT_BOX *)item->itemStruct);
278 	}
279 	else
280 	{
281 		DeactivateTextBox((TEXT_BOX *)item->itemStruct);
282 	}
283 }
284 
TextBoxItemFocusKey(DIALOG_ITEM * item,XEvent * event)285 static void TextBoxItemFocusKey(DIALOG_ITEM *item,XEvent *event)
286 // give the key to the text box
287 {
288 	HandleTextBoxKeyEvent((TEXT_BOX *)item->itemStruct,event);
289 }
290 
TextBoxItemPeriodicProc(DIALOG_ITEM * item)291 static void TextBoxItemPeriodicProc(DIALOG_ITEM *item)
292 // this is used to flash the cursor of the view
293 {
294 	HandleTextBoxPeriodicProc((TEXT_BOX *)item->itemStruct);
295 }
296 
CreateTextBoxItem(DIALOG_ITEM * item,void * descriptor)297 bool CreateTextBoxItem(DIALOG_ITEM *item,void *descriptor)
298 // create the textBox, and fill in item
299 // if there is a problem, SetError, return false
300 {
301 	if((item->itemStruct=(void *)CreateTextBox(item->dialog->parentWindow,(TEXT_BOX_DESCRIPTOR *)descriptor)))
302 	{
303 		item->disposeProc=DisposeTextBoxItem;
304 		item->drawProc=DrawTextBoxItem;
305 		item->resizeProc=ResizeTextBoxItem;
306 		item->trackProc=TrackTextBoxItem;
307 		item->earlyKeyProc=NULL;
308 		item->wantFocus=true;
309 		item->focusChangeProc=TextBoxItemFocusChange;
310 		item->focusKeyProc=TextBoxItemFocusKey;
311 		item->focusPeriodicProc=TextBoxItemPeriodicProc;		// set up cursor flash task
312 		return(true);
313 	}
314 	return(false);
315 }
316