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(®ionBox,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