7 #include <X11/keysym.h>
12 #define CURSOR_BLINK_ON_DELAY 600
13 #define CURSOR_BLINK_OFF_DELAY 300
16 char *WMTextDidChangeNotification
= "WMTextDidChangeNotification";
17 char *WMTextDidBeginEditingNotification
= "WMTextDidBeginEditingNotification";
18 char *WMTextDidEndEditingNotification
= "WMTextDidEndEditingNotification";
21 typedef struct W_TextField
{
26 struct W_TextField
*nextField
; /* next textfield in the chain */
27 struct W_TextField
*prevField
;
31 int textLen
; /* size of text */
32 int bufferSize
; /* memory allocated for text */
34 int viewPosition
; /* position of text being shown */
36 int cursorPosition
; /* position of the insertion cursor */
39 short offsetWidth
; /* offset of text from border */
42 WMRange prevselection
;
47 WMHandlerID timerID
; /* for cursor blinking */
50 WMAlignment alignment
:2;
52 unsigned int bordered
:1;
54 unsigned int beveled
:1;
56 unsigned int enabled
:1;
58 unsigned int focused
:1;
60 unsigned int cursorOn
:1;
62 unsigned int secure
:1; /* password entry style */
65 unsigned int notIllegalMovement
:1;
70 #define MIN_TEXT_BUFFER 2
71 #define TEXT_BUFFER_INCR 8
74 #define WM_EMACSKEYMASK ControlMask
76 #define WM_EMACSKEY_LEFT XK_b
77 #define WM_EMACSKEY_RIGHT XK_f
78 #define WM_EMACSKEY_HOME XK_a
79 #define WM_EMACSKEY_END XK_e
80 #define WM_EMACSKEY_BS XK_h
81 #define WM_EMACSKEY_DEL XK_d
85 #define DEFAULT_WIDTH 60
86 #define DEFAULT_HEIGHT 20
87 #define DEFAULT_BORDERED True
88 #define DEFAULT_ALIGNMENT WALeft
92 static void destroyTextField(TextField
*tPtr
);
93 static void paintTextField(TextField
*tPtr
);
95 static void handleEvents(XEvent
*event
, void *data
);
96 static void handleTextFieldActionEvents(XEvent
*event
, void *data
);
97 static void resizeTextField();
99 struct W_ViewProcedureTable _TextFieldViewProcedures
= {
106 #define TEXT_WIDTH(tPtr, start) (WMWidthOfString((tPtr)->font, \
107 &((tPtr)->text[(start)]), (tPtr)->textLen - (start) + 1))
109 #define TEXT_WIDTH2(tPtr, start, end) (WMWidthOfString((tPtr)->font, \
110 &((tPtr)->text[(start)]), (end) - (start) + 1))
114 memmv(char *dest
, char *src
, int size
)
119 for (i
=size
-1; i
>=0; i
--) {
122 } else if (dest
< src
) {
123 for (i
=0; i
<size
; i
++) {
131 incrToFit(TextField
*tPtr
)
133 int vp
= tPtr
->viewPosition
;
135 while (TEXT_WIDTH(tPtr
, tPtr
->viewPosition
) > tPtr
->usableWidth
) {
136 tPtr
->viewPosition
++;
138 return vp
!=tPtr
->viewPosition
;
143 incrToFit2(TextField
*tPtr
)
145 int vp
= tPtr
->viewPosition
;
146 while (TEXT_WIDTH2(tPtr
, tPtr
->viewPosition
, tPtr
->cursorPosition
)
147 >= tPtr
->usableWidth
)
148 tPtr
->viewPosition
++;
151 return vp
!=tPtr
->viewPosition
;
156 decrToFit(TextField
*tPtr
)
158 while (TEXT_WIDTH(tPtr
, tPtr
->viewPosition
-1) < tPtr
->usableWidth
159 && tPtr
->viewPosition
>0)
160 tPtr
->viewPosition
--;
168 WMCreateTextField(WMWidget
*parent
)
172 tPtr
= wmalloc(sizeof(TextField
));
173 memset(tPtr
, 0, sizeof(TextField
));
175 tPtr
->widgetClass
= WC_TextField
;
177 tPtr
->view
= W_CreateView(W_VIEW(parent
));
182 tPtr
->view
->self
= tPtr
;
184 tPtr
->view
->attribFlags
|= CWCursor
;
185 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->textCursor
;
187 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->view
->screen
->white
);
189 tPtr
->text
= wmalloc(MIN_TEXT_BUFFER
);
192 tPtr
->bufferSize
= MIN_TEXT_BUFFER
;
194 tPtr
->flags
.enabled
= 1;
196 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
197 |FocusChangeMask
, handleEvents
, tPtr
);
199 W_ResizeView(tPtr
->view
, DEFAULT_WIDTH
, DEFAULT_HEIGHT
);
201 tPtr
->font
= WMRetainFont(tPtr
->view
->screen
->normalFont
);
203 tPtr
->flags
.bordered
= DEFAULT_BORDERED
;
204 tPtr
->flags
.beveled
= True
;
205 tPtr
->flags
.alignment
= DEFAULT_ALIGNMENT
;
207 WMAX((tPtr
->view
->size
.height
- WMFontHeight(tPtr
->font
))/2, 1);
209 WMCreateEventHandler(tPtr
->view
, EnterWindowMask
|LeaveWindowMask
210 |ButtonReleaseMask
|ButtonPressMask
|KeyPressMask
|Button1MotionMask
,
211 handleTextFieldActionEvents
, tPtr
);
213 tPtr
->flags
.cursorOn
= 1;
220 WMInsertTextFieldText(WMTextField
*tPtr
, char *text
, int position
)
224 CHECK_CLASS(tPtr
, WC_TextField
);
231 /* check if buffer will hold the text */
232 if (len
+ tPtr
->textLen
>= tPtr
->bufferSize
) {
233 tPtr
->bufferSize
= tPtr
->textLen
+ len
+ TEXT_BUFFER_INCR
;
234 tPtr
->text
= realloc(tPtr
->text
, tPtr
->bufferSize
);
237 if (position
< 0 || position
>= tPtr
->textLen
) {
238 /* append the text at the end */
239 strcat(tPtr
->text
, text
);
243 tPtr
->textLen
+= len
;
244 tPtr
->cursorPosition
+= len
;
246 /* insert text at position */
247 memmv(&(tPtr
->text
[position
+len
]), &(tPtr
->text
[position
]),
248 tPtr
->textLen
-position
+1);
250 memcpy(&(tPtr
->text
[position
]), text
, len
);
252 tPtr
->textLen
+= len
;
253 if (position
>= tPtr
->cursorPosition
) {
254 tPtr
->cursorPosition
+= len
;
261 paintTextField(tPtr
);
263 WMPostNotificationName(WMTextDidChangeNotification
, tPtr
,
264 (void*)WMInsertTextEvent
);
269 deleteTextFieldRange(WMTextField
*tPtr
, WMRange range
)
271 CHECK_CLASS(tPtr
, WC_TextField
);
273 if (range
.position
>= tPtr
->textLen
)
276 if (range
.count
< 1) {
277 if (range
.position
< 0)
279 tPtr
->text
[range
.position
] = 0;
280 tPtr
->textLen
= range
.position
;
282 tPtr
->cursorPosition
= 0;
283 tPtr
->viewPosition
= 0;
285 if (range
.position
+ range
.count
> tPtr
->textLen
)
286 range
.count
= tPtr
->textLen
- range
.position
;
287 memmv(&(tPtr
->text
[range
.position
]), &(tPtr
->text
[range
.position
+range
.count
]),
288 tPtr
->textLen
- (range
.position
+range
.count
) + 1);
289 tPtr
->textLen
-= range
.count
;
291 if (tPtr
->cursorPosition
> range
.position
)
292 tPtr
->cursorPosition
-= range
.count
;
297 paintTextField(tPtr
);
302 WMDeleteTextFieldRange(WMTextField
*tPtr
, WMRange range
)
304 deleteTextFieldRange(tPtr
, range
);
305 WMPostNotificationName(WMTextDidChangeNotification
, tPtr
,
306 (void*)WMDeleteTextEvent
);
312 WMGetTextFieldText(WMTextField
*tPtr
)
314 CHECK_CLASS(tPtr
, WC_TextField
);
316 return wstrdup(tPtr
->text
);
321 WMSetTextFieldText(WMTextField
*tPtr
, char *text
)
323 if ((text
&& strcmp(tPtr
->text
, text
) == 0) ||
324 (!text
&& tPtr
->textLen
== 0))
331 tPtr
->textLen
= strlen(text
);
333 if (tPtr
->textLen
>= tPtr
->bufferSize
) {
334 tPtr
->bufferSize
= tPtr
->textLen
+ TEXT_BUFFER_INCR
;
335 tPtr
->text
= realloc(tPtr
->text
, tPtr
->bufferSize
);
337 strcpy(tPtr
->text
, text
);
340 if (tPtr->textLen < tPtr->cursorPosition)
341 tPtr->cursorPosition = tPtr->textLen;
343 tPtr
->cursorPosition
= tPtr
->textLen
;
344 tPtr
->viewPosition
= 0;
345 tPtr
->selection
.count
= 0;
347 if (tPtr
->view
->flags
.realized
)
348 paintTextField(tPtr
);
350 WMPostNotificationName(WMTextDidChangeNotification
, tPtr
,
351 (void*)WMSetTextEvent
);
356 WMSetTextFieldFont(WMTextField
*tPtr
, WMFont
*font
)
358 /* TODO: update font change after field is mapped */
359 WMReleaseFont(tPtr
->font
);
360 tPtr
->font
= WMRetainFont(font
);
364 WMSetTextFieldAlignment(WMTextField
*tPtr
, WMAlignment alignment
)
366 tPtr
->flags
.alignment
= alignment
;
367 if (alignment
!=WALeft
) {
368 wwarning("only left alignment is supported in textfields");
372 if (tPtr
->view
->flags
.realized
) {
373 paintTextField(tPtr
);
379 WMSetTextFieldBordered(WMTextField
*tPtr
, Bool bordered
)
381 tPtr
->flags
.bordered
= bordered
;
383 if (tPtr
->view
->flags
.realized
) {
384 paintTextField(tPtr
);
390 WMSetTextFieldBeveled(WMTextField
*tPtr
, Bool flag
)
392 tPtr
->flags
.beveled
= flag
;
394 if (tPtr
->view
->flags
.realized
) {
395 paintTextField(tPtr
);
402 WMSetTextFieldSecure(WMTextField
*tPtr
, Bool flag
)
404 tPtr
->flags
.secure
= flag
;
406 if (tPtr
->view
->flags
.realized
) {
407 paintTextField(tPtr
);
413 WMGetTextFieldEditable(WMTextField
*tPtr
)
415 return tPtr
->flags
.enabled
;
420 WMSetTextFieldEditable(WMTextField
*tPtr
, Bool flag
)
422 tPtr
->flags
.enabled
= flag
;
424 if (tPtr
->view
->flags
.realized
) {
425 paintTextField(tPtr
);
431 WMSelectTextFieldRange(WMTextField
*tPtr
, WMRange range
)
433 if (tPtr
->flags
.enabled
) {
434 if (range
.position
< 0) {
435 range
.count
+= range
.position
;
436 range
.count
= (range
.count
< 0) ? 0 : range
.count
;
438 } else if (range
.position
> tPtr
->textLen
) {
439 range
.position
= tPtr
->textLen
;
443 if (range
.position
+ range
.count
> tPtr
->textLen
)
444 range
.count
= tPtr
->textLen
- range
.position
;
446 tPtr
->prevselection
= tPtr
->selection
; /* check if this is needed */
448 tPtr
->selection
= range
;
450 if (tPtr
->view
->flags
.realized
) {
451 paintTextField(tPtr
);
458 WMSetTextFieldCursorPosition(WMTextField
*tPtr
, unsigned int position
)
460 if (tPtr
->flags
.enabled
) {
461 if (position
> tPtr
->textLen
)
462 position
= tPtr
->textLen
;
464 tPtr
->cursorPosition
= position
;
465 if (tPtr
->view
->flags
.realized
) {
466 paintTextField(tPtr
);
473 WMSetTextFieldNextTextField(WMTextField
*tPtr
, WMTextField
*next
)
475 CHECK_CLASS(tPtr
, WC_TextField
);
477 if (tPtr
->view
->nextFocusChain
)
478 tPtr
->view
->nextFocusChain
->prevFocusChain
= NULL
;
479 tPtr
->view
->nextFocusChain
= NULL
;
483 CHECK_CLASS(next
, WC_TextField
);
485 if (tPtr
->view
->nextFocusChain
)
486 tPtr
->view
->nextFocusChain
->prevFocusChain
= NULL
;
487 if (next
->view
->prevFocusChain
)
488 next
->view
->prevFocusChain
->nextFocusChain
= NULL
;
490 tPtr
->view
->nextFocusChain
= next
->view
;
491 next
->view
->prevFocusChain
= tPtr
->view
;
496 WMSetTextFieldPrevTextField(WMTextField
*tPtr
, WMTextField
*prev
)
498 CHECK_CLASS(tPtr
, WC_TextField
);
500 if (tPtr
->view
->prevFocusChain
)
501 tPtr
->view
->prevFocusChain
->nextFocusChain
= NULL
;
502 tPtr
->view
->prevFocusChain
= NULL
;
506 CHECK_CLASS(prev
, WC_TextField
);
508 if (tPtr
->view
->prevFocusChain
)
509 tPtr
->view
->prevFocusChain
->nextFocusChain
= NULL
;
510 if (prev
->view
->nextFocusChain
)
511 prev
->view
->nextFocusChain
->prevFocusChain
= NULL
;
513 tPtr
->view
->prevFocusChain
= prev
->view
;
514 prev
->view
->nextFocusChain
= tPtr
->view
;
519 resizeTextField(WMTextField
*tPtr
, unsigned int width
, unsigned int height
)
521 W_ResizeView(tPtr
->view
, width
, height
);
524 WMAX((tPtr
->view
->size
.height
- WMFontHeight(tPtr
->font
))/2, 1);
526 tPtr
->usableWidth
= tPtr
->view
->size
.width
- 2*tPtr
->offsetWidth
+ 2;
531 makeHiddenString(int length
)
533 char *data
= wmalloc(length
+1);
535 memset(data
, '*', length
);
542 paintCursor(TextField
*tPtr
)
545 WMScreen
*screen
= tPtr
->view
->screen
;
549 if (tPtr
->flags
.secure
)
550 text
= makeHiddenString(strlen(tPtr
->text
));
554 cx
= WMWidthOfString(tPtr
->font
, &(text
[tPtr
->viewPosition
]),
555 tPtr
->cursorPosition
-tPtr
->viewPosition
);
557 switch (tPtr
->flags
.alignment
) {
559 textWidth
= WMWidthOfString(tPtr
->font
, text
, tPtr
->textLen
);
560 if (textWidth
< tPtr
->usableWidth
)
561 cx
+= tPtr
->offsetWidth
+ tPtr
->usableWidth
- textWidth
+ 1;
563 cx
+= tPtr
->offsetWidth
+ 1;
566 cx
+= tPtr
->offsetWidth
+ 1;
571 textWidth
= WMWidthOfString(tPtr
->font
, text
, tPtr
->textLen
);
572 if (textWidth
< tPtr
->usableWidth
)
573 cx
+= tPtr
->offsetWidth
+ (tPtr
->usableWidth
-textWidth
)/2;
575 cx
+= tPtr
->offsetWidth
;
579 XDrawRectangle(screen->display, tPtr->view->window, screen->xorGC,
580 cx, tPtr->offsetWidth, 1,
581 tPtr->view->size.height - 2*tPtr->offsetWidth - 1);
582 printf("%d %d\n",cx,tPtr->cursorPosition);
584 XDrawLine(screen
->display
, tPtr
->view
->window
, screen
->xorGC
,
585 cx
, tPtr
->offsetWidth
, cx
,
586 tPtr
->view
->size
.height
- tPtr
->offsetWidth
- 1);
588 if (tPtr
->flags
.secure
)
595 drawRelief(WMView
*view
, Bool beveled
)
597 WMScreen
*scr
= view
->screen
;
598 Display
*dpy
= scr
->display
;
602 int width
= view
->size
.width
;
603 int height
= view
->size
.height
;
605 dgc
= WMColorGC(scr
->darkGray
);
608 XDrawRectangle(dpy
, view
->window
, dgc
, 0, 0, width
-1, height
-1);
612 wgc
= WMColorGC(scr
->white
);
613 lgc
= WMColorGC(scr
->gray
);
616 XDrawLine(dpy
, view
->window
, dgc
, 0, 0, width
-1, 0);
617 XDrawLine(dpy
, view
->window
, dgc
, 0, 1, width
-2, 1);
619 XDrawLine(dpy
, view
->window
, dgc
, 0, 0, 0, height
-2);
620 XDrawLine(dpy
, view
->window
, dgc
, 1, 0, 1, height
-3);
623 XDrawLine(dpy
, view
->window
, wgc
, 0, height
-1, width
-1, height
-1);
624 XDrawLine(dpy
, view
->window
, lgc
, 1, height
-2, width
-2, height
-2);
626 XDrawLine(dpy
, view
->window
, wgc
, width
-1, 0, width
-1, height
-1);
627 XDrawLine(dpy
, view
->window
, lgc
, width
-2, 1, width
-2, height
-3);
632 paintTextField(TextField
*tPtr
)
634 W_Screen
*screen
= tPtr
->view
->screen
;
635 W_View
*view
= tPtr
->view
;
645 if (!view
->flags
.realized
|| !view
->flags
.mapped
)
648 if (!tPtr
->flags
.bordered
) {
654 if (tPtr
->flags
.secure
) {
655 text
= makeHiddenString(strlen(tPtr
->text
));
660 totalWidth
= tPtr
->view
->size
.width
- 2*bd
;
662 drawbuffer
= XCreatePixmap(screen
->display
, view
->window
,
663 view
->size
.width
, view
->size
.height
, screen
->depth
);
664 XFillRectangle(screen
->display
, drawbuffer
, WMColorGC(screen
->white
),
665 0,0, view
->size
.width
,view
->size
.height
);
666 /* this is quite dirty */
667 viewbuffer
.screen
= view
->screen
;
668 viewbuffer
.size
= view
->size
;
669 viewbuffer
.window
= drawbuffer
;
672 if (tPtr
->textLen
> 0) {
673 tw
= WMWidthOfString(tPtr
->font
, &(text
[tPtr
->viewPosition
]),
674 tPtr
->textLen
- tPtr
->viewPosition
);
676 th
= WMFontHeight(tPtr
->font
);
678 ty
= tPtr
->offsetWidth
;
679 switch (tPtr
->flags
.alignment
) {
681 tx
= tPtr
->offsetWidth
+ 1;
682 if (tw
< tPtr
->usableWidth
)
683 XFillRectangle(screen
->display
, drawbuffer
,
684 WMColorGC(screen
->white
),
685 bd
+tw
,bd
, totalWidth
-tw
,view
->size
.height
-2*bd
);
689 tx
= tPtr
->offsetWidth
+ (tPtr
->usableWidth
- tw
) / 2;
690 if (tw
< tPtr
->usableWidth
)
691 XClearArea(screen
->display
, view
->window
, bd
, bd
,
692 totalWidth
, view
->size
.height
-2*bd
, False
);
697 tx
= tPtr
->offsetWidth
+ tPtr
->usableWidth
- tw
- 1;
698 if (tw
< tPtr
->usableWidth
)
699 XClearArea(screen
->display
, view
->window
, bd
, bd
,
700 totalWidth
-tw
, view
->size
.height
-2*bd
, False
);
704 if (!tPtr
->flags
.enabled
)
705 WMSetColorInGC(screen
->darkGray
, screen
->textFieldGC
);
707 WMDrawImageString(screen
, drawbuffer
, screen
->textFieldGC
,
709 &(text
[tPtr
->viewPosition
]),
710 tPtr
->textLen
- tPtr
->viewPosition
);
712 if (tPtr
->selection
.count
) {
715 count
= tPtr
->selection
.count
< 0
716 ? tPtr
->selection
.position
+ tPtr
->selection
.count
717 : tPtr
->selection
.position
;
718 count2
= abs(tPtr
->selection
.count
);
719 if (count
< tPtr
->viewPosition
) {
720 count2
= abs(count2
- abs(tPtr
->viewPosition
- count
));
721 count
= tPtr
->viewPosition
;
725 rx
= tPtr
->offsetWidth
+ 1 + WMWidthOfString(tPtr
->font
,text
,count
)
726 - WMWidthOfString(tPtr
->font
,text
,tPtr
->viewPosition
);
728 XSetBackground(screen
->display
, screen
->textFieldGC
,
729 screen
->gray
->color
.pixel
);
731 WMDrawImageString(screen
, drawbuffer
, screen
->textFieldGC
,
732 tPtr
->font
, rx
, ty
, &(text
[count
]),
733 abs(tPtr
->selection
.count
));
735 XSetBackground(screen
->display
, screen
->textFieldGC
,
736 screen
->white
->color
.pixel
);
739 if (!tPtr
->flags
.enabled
)
740 WMSetColorInGC(screen
->black
, screen
->textFieldGC
);
742 XFillRectangle(screen
->display
, drawbuffer
,
743 WMColorGC(screen
->white
),
744 bd
,bd
, totalWidth
,view
->size
.height
-2*bd
);
748 if (tPtr
->flags
.bordered
) {
749 drawRelief(&viewbuffer
, tPtr
->flags
.beveled
);
752 if (tPtr
->flags
.secure
)
754 XCopyArea(screen
->display
, drawbuffer
, view
->window
,
755 screen
->copyGC
, 0,0, view
->size
.width
,
756 view
->size
.height
,0,0);
757 XFreePixmap(screen
->display
, drawbuffer
);
760 if (tPtr
->flags
.focused
&& tPtr
->flags
.enabled
&& tPtr
->flags
.cursorOn
) {
768 blinkCursor(void *data
)
770 TextField
*tPtr
= (TextField
*)data
;
772 if (tPtr
->flags
.cursorOn
) {
773 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY
, blinkCursor
,
776 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
, blinkCursor
,
780 tPtr
->flags
.cursorOn
= !tPtr
->flags
.cursorOn
;
786 handleEvents(XEvent
*event
, void *data
)
788 TextField
*tPtr
= (TextField
*)data
;
790 CHECK_CLASS(data
, WC_TextField
);
793 switch (event
->type
) {
795 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))!=tPtr
->view
)
797 tPtr
->flags
.focused
= 1;
799 if (!tPtr
->timerID
) {
800 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
,
804 paintTextField(tPtr
);
806 WMPostNotificationName(WMTextDidBeginEditingNotification
, tPtr
, NULL
);
808 tPtr
->flags
.notIllegalMovement
= 0;
812 tPtr
->flags
.focused
= 0;
815 WMDeleteTimerHandler(tPtr
->timerID
);
816 tPtr
->timerID
= NULL
;
819 paintTextField(tPtr
);
820 if (!tPtr
->flags
.notIllegalMovement
) {
821 WMPostNotificationName(WMTextDidEndEditingNotification
, tPtr
,
822 (void*)WMIllegalTextMovement
);
827 if (event
->xexpose
.count
!=0)
829 paintTextField(tPtr
);
833 destroyTextField(tPtr
);
840 handleTextFieldKeyPress(TextField
*tPtr
, XEvent
*event
)
844 int count
, refresh
= 0;
845 int control_pressed
= 0;
847 if (((XKeyEvent
*) event
)->state
& WM_EMACSKEYMASK
) {
851 count
= XLookupString(&event
->xkey
, buffer
, 63, &ksym
, NULL
);
852 buffer
[count
] = '\0';
854 if (!(event
->xkey
.state
& ShiftMask
)) {
855 if (tPtr
->selection
.count
)
857 tPtr
->prevselection
= tPtr
->selection
;
858 tPtr
->selection
.position
= tPtr
->cursorPosition
;
859 tPtr
->selection
.count
= 0;
862 /* Be careful in any case in this switch statement, never to call
863 * to more than a function that can generate text change notifications.
864 * Only one text change notification should be sent in any case.
865 * Else hazardous things can happen.
866 * Maybe we need a better solution than the function wrapper to inform
867 * functions that change text in text fields, if they need to send a
868 * change notification or not. -Dan
872 if (event
->xkey
.state
& ShiftMask
) {
873 if (tPtr
->view
->prevFocusChain
) {
874 W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr
->view
),
875 tPtr
->view
->prevFocusChain
);
876 tPtr
->flags
.notIllegalMovement
= 1;
878 WMPostNotificationName(WMTextDidEndEditingNotification
, tPtr
,
879 (void*)WMBacktabTextMovement
);
881 if (tPtr
->view
->nextFocusChain
) {
882 W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr
->view
),
883 tPtr
->view
->nextFocusChain
);
884 tPtr
->flags
.notIllegalMovement
= 1;
886 WMPostNotificationName(WMTextDidEndEditingNotification
,
887 tPtr
, (void*)WMTabTextMovement
);
892 WMPostNotificationName(WMTextDidEndEditingNotification
, tPtr
,
893 (void*)WMReturnTextMovement
);
896 case WM_EMACSKEY_LEFT
:
897 if (!control_pressed
) {
902 if (tPtr
->cursorPosition
> 0) {
904 if (event
->xkey
.state
& ControlMask
) {
906 for (i
= tPtr
->cursorPosition
- 1; i
>= 0; i
--)
907 if (tPtr
->text
[i
] == ' ' || i
== 0) {
908 tPtr
->cursorPosition
= i
;
912 tPtr
->cursorPosition
--;
914 if (tPtr
->cursorPosition
< tPtr
->viewPosition
) {
915 tPtr
->viewPosition
= tPtr
->cursorPosition
;
923 case WM_EMACSKEY_RIGHT
:
924 if (!control_pressed
) {
929 if (tPtr
->cursorPosition
< tPtr
->textLen
) {
931 if (event
->xkey
.state
& ControlMask
) {
933 for (i
= tPtr
->cursorPosition
+ 1; i
<= tPtr
->textLen
; i
++)
934 if (tPtr
->text
[i
] == ' ' || i
== tPtr
->textLen
) {
935 tPtr
->cursorPosition
= i
;
939 tPtr
->cursorPosition
++;
941 while (WMWidthOfString(tPtr
->font
,
942 &(tPtr
->text
[tPtr
->viewPosition
]),
943 tPtr
->cursorPosition
-tPtr
->viewPosition
)
944 > tPtr
->usableWidth
) {
945 tPtr
->viewPosition
++;
953 case WM_EMACSKEY_HOME
:
954 if (!control_pressed
) {
959 if (tPtr
->cursorPosition
> 0) {
961 tPtr
->cursorPosition
= 0;
962 if (tPtr
->viewPosition
> 0) {
963 tPtr
->viewPosition
= 0;
971 case WM_EMACSKEY_END
:
972 if (!control_pressed
) {
977 if (tPtr
->cursorPosition
< tPtr
->textLen
) {
979 tPtr
->cursorPosition
= tPtr
->textLen
;
980 tPtr
->viewPosition
= 0;
981 while (WMWidthOfString(tPtr
->font
,
982 &(tPtr
->text
[tPtr
->viewPosition
]),
983 tPtr
->textLen
-tPtr
->viewPosition
)
984 > tPtr
->usableWidth
) {
985 tPtr
->viewPosition
++;
994 if (!control_pressed
) {
998 if (tPtr
->cursorPosition
> 0) {
1001 if (tPtr
->prevselection
.count
) {
1002 range
.position
= tPtr
->prevselection
.count
< 0
1003 ? tPtr
->prevselection
.position
+ tPtr
->prevselection
.count
1004 : tPtr
->prevselection
.position
;
1006 range
.count
= abs(tPtr
->prevselection
.count
);
1008 range
.position
= tPtr
->cursorPosition
- 1;
1011 WMDeleteTextFieldRange(tPtr
, range
);
1015 case WM_EMACSKEY_DEL
:
1016 if (!control_pressed
) {
1021 if (tPtr
->cursorPosition
< tPtr
->textLen
|| tPtr
->prevselection
.count
) {
1024 if (tPtr
->prevselection
.count
) {
1025 range
.position
= tPtr
->prevselection
.count
< 0
1026 ? tPtr
->prevselection
.position
+ tPtr
->prevselection
.count
1027 : tPtr
->prevselection
.position
;
1029 range
.count
= abs(tPtr
->prevselection
.count
);
1031 range
.position
= tPtr
->cursorPosition
;
1034 WMDeleteTextFieldRange(tPtr
, range
);
1040 if (count
> 0 && !iscntrl(buffer
[0])) {
1043 if (tPtr
->prevselection
.count
) {
1044 range
.position
= tPtr
->prevselection
.count
< 0
1045 ? tPtr
->prevselection
.position
+ tPtr
->prevselection
.count
1046 : tPtr
->prevselection
.position
;
1048 range
.count
= abs(tPtr
->prevselection
.count
);
1050 range
.position
= tPtr
->cursorPosition
;
1053 if (tPtr
->prevselection
.count
)
1054 deleteTextFieldRange(tPtr
, range
);
1055 WMInsertTextFieldText(tPtr
, buffer
, tPtr
->cursorPosition
);
1061 if (event
->xkey
.state
& ShiftMask
) {
1062 if (tPtr
->selection
.count
== 0)
1063 tPtr
->selection
.position
= tPtr
->cursorPosition
;
1064 tPtr
->selection
.count
= tPtr
->cursorPosition
- tPtr
->selection
.position
;
1067 tPtr
->prevselection
.count
= 0;
1069 paintTextField(tPtr
);
1075 pointToCursorPosition(TextField
*tPtr
, int x
)
1080 if (tPtr
->flags
.bordered
)
1083 a
= tPtr
->viewPosition
;
1084 b
= tPtr
->viewPosition
+ tPtr
->textLen
;
1085 if (WMWidthOfString(tPtr
->font
, &(tPtr
->text
[tPtr
->viewPosition
]),
1086 tPtr
->textLen
-tPtr
->viewPosition
) < x
)
1087 return tPtr
->textLen
;
1089 while (a
< b
&& b
-a
>1) {
1091 tw
= WMWidthOfString(tPtr
->font
, &(tPtr
->text
[tPtr
->viewPosition
]),
1092 mid
- tPtr
->viewPosition
);
1105 handleTextFieldActionEvents(XEvent
*event
, void *data
)
1107 TextField
*tPtr
= (TextField
*)data
;
1110 CHECK_CLASS(data
, WC_TextField
);
1112 switch (event
->type
) {
1114 if (tPtr
->flags
.enabled
&& tPtr
->flags
.focused
)
1115 handleTextFieldKeyPress(tPtr
, event
);
1120 if (tPtr
->flags
.enabled
&& (event
->xmotion
.state
& Button1Mask
)) {
1123 if (tPtr
->viewPosition
< tPtr
->textLen
&& event
->xmotion
.x
>
1124 tPtr
->usableWidth
) {
1125 if (WMWidthOfString(tPtr
->font
,
1126 &(tPtr
->text
[tPtr
->viewPosition
]),
1127 tPtr
->cursorPosition
-tPtr
->viewPosition
)
1128 > tPtr
->usableWidth
) {
1129 tPtr
->viewPosition
++;
1132 else if (tPtr
->viewPosition
> 0 && event
->xmotion
.x
< 0) {
1134 tPtr
->viewPosition
--;
1137 if (!tPtr
->selection
.count
) {
1138 tPtr
->selection
.position
= tPtr
->cursorPosition
;
1141 tPtr
->cursorPosition
= pointToCursorPosition(tPtr
, event
->xmotion
.x
);
1143 tPtr
->selection
.count
= tPtr
->cursorPosition
- tPtr
->selection
.position
;
1146 printf("notify %d %d\n",event->xmotion.x,tPtr->usableWidth);
1150 paintTextField(tPtr
);
1155 XSetSelectionOwner(tPtr
->view
->screen
->display
,
1156 XA_PRIMARY
, None
, CurrentTime
);
1157 count
= tPtr
->selection
.count
< 0
1158 ? tPtr
->selection
.position
+ tPtr
->selection
.count
1159 : tPtr
->selection
.position
;
1160 XStoreBuffer(tPtr
->view
->screen
->display
,
1161 &tPtr
->text
[count
] , abs(tPtr
->selection
.count
), 0);
1167 switch (tPtr
->flags
.alignment
) {
1170 textWidth
= WMWidthOfString(tPtr
->font
, tPtr
->text
, tPtr
->textLen
);
1171 if (tPtr
->flags
.enabled
&& !tPtr
->flags
.focused
) {
1172 WMSetFocusToWidget(tPtr
);
1173 } else if (tPtr
->flags
.focused
) {
1174 tPtr
->selection
.count
= 0;
1176 if(textWidth
< tPtr
->usableWidth
){
1177 tPtr
->cursorPosition
= pointToCursorPosition(tPtr
,
1178 event
->xbutton
.x
- tPtr
->usableWidth
1181 else tPtr
->cursorPosition
= pointToCursorPosition(tPtr
,
1184 tPtr->cursorPosition = pointToCursorPosition(tPtr,
1186 tPtr->cursorPosition += tPtr->usableWidth - textWidth;
1189 tPtr->cursorPosition = pointToCursorPosition(tPtr,
1192 paintTextField(tPtr
);
1196 if (tPtr
->flags
.enabled
&& !tPtr
->flags
.focused
) {
1197 WMSetFocusToWidget(tPtr
);
1198 tPtr
->cursorPosition
= pointToCursorPosition(tPtr
,
1200 paintTextField(tPtr
);
1201 } else if (tPtr
->flags
.focused
) {
1202 tPtr
->cursorPosition
= pointToCursorPosition(tPtr
,
1204 tPtr
->selection
.count
= 0;
1205 paintTextField(tPtr
);
1207 if (event
->xbutton
.button
== Button2
&& tPtr
->flags
.enabled
) {
1210 text
= W_GetTextSelection(tPtr
->view
->screen
,
1211 tPtr
->view
->screen
->clipboardAtom
);
1213 text
= W_GetTextSelection(tPtr
->view
->screen
, XA_CUT_BUFFER0
);
1216 WMInsertTextFieldText(tPtr
, text
, tPtr
->cursorPosition
);
1218 WMPostNotificationName(WMTextDidChangeNotification
, tPtr
, NULL
);
1233 destroyTextField(TextField
*tPtr
)
1237 WMDeleteTimerHandler(tPtr
->timerID
);
1240 WMReleaseFont(tPtr
->font
);