7 #include <X11/keysym.h>
12 #define CURSOR_BLINK_ON_DELAY 600
13 #define CURSOR_BLINK_OFF_DELAY 300
17 char *WMTextDidChangeNotification
= "WMTextDidChangeNotification";
18 char *WMTextDidBeginEditingNotification
= "WMTextDidBeginEditingNotification";
19 char *WMTextDidEndEditingNotification
= "WMTextDidEndEditingNotification";
22 typedef struct W_TextField
{
27 struct W_TextField
*nextField
; /* next textfield in the chain */
28 struct W_TextField
*prevField
;
32 int textLen
; /* size of text */
33 int bufferSize
; /* memory allocated for text */
35 int viewPosition
; /* position of text being shown */
37 int cursorPosition
; /* position of the insertion cursor */
40 short offsetWidth
; /* offset of text from border */
43 WMRange prevselection
;
47 WMTextFieldDelegate
*delegate
;
50 WMHandlerID timerID
; /* for cursor blinking */
53 WMAlignment alignment
:2;
55 unsigned int bordered
:1;
57 unsigned int beveled
:1;
59 unsigned int enabled
:1;
61 unsigned int focused
:1;
63 unsigned int cursorOn
:1;
65 unsigned int secure
:1; /* password entry style */
67 unsigned int pointerGrabbed
:1;
70 unsigned int notIllegalMovement
:1;
75 #define NOTIFY(T,C,N,A) { WMNotification *notif = WMCreateNotification(N,T,A);\
76 if ((T)->delegate && (T)->delegate->C)\
77 (*(T)->delegate->C)((T)->delegate,notif);\
78 WMPostNotification(notif);\
79 WMReleaseNotification(notif);}
82 #define MIN_TEXT_BUFFER 2
83 #define TEXT_BUFFER_INCR 8
86 #define WM_EMACSKEYMASK ControlMask
88 #define WM_EMACSKEY_LEFT XK_b
89 #define WM_EMACSKEY_RIGHT XK_f
90 #define WM_EMACSKEY_HOME XK_a
91 #define WM_EMACSKEY_END XK_e
92 #define WM_EMACSKEY_BS XK_h
93 #define WM_EMACSKEY_DEL XK_d
97 #define DEFAULT_WIDTH 60
98 #define DEFAULT_HEIGHT 20
99 #define DEFAULT_BORDERED True
100 #define DEFAULT_ALIGNMENT WALeft
104 static void destroyTextField(TextField
*tPtr
);
105 static void paintTextField(TextField
*tPtr
);
107 static void handleEvents(XEvent
*event
, void *data
);
108 static void handleTextFieldActionEvents(XEvent
*event
, void *data
);
109 static void resizeTextField();
111 struct W_ViewProcedureTable _TextFieldViewProcedures
= {
118 #define TEXT_WIDTH(tPtr, start) (WMWidthOfString((tPtr)->font, \
119 &((tPtr)->text[(start)]), (tPtr)->textLen - (start) + 1))
121 #define TEXT_WIDTH2(tPtr, start, end) (WMWidthOfString((tPtr)->font, \
122 &((tPtr)->text[(start)]), (end) - (start) + 1))
126 memmv(char *dest
, char *src
, int size
)
131 for (i
=size
-1; i
>=0; i
--) {
134 } else if (dest
< src
) {
135 for (i
=0; i
<size
; i
++) {
143 incrToFit(TextField
*tPtr
)
145 int vp
= tPtr
->viewPosition
;
147 while (TEXT_WIDTH(tPtr
, tPtr
->viewPosition
) > tPtr
->usableWidth
) {
148 tPtr
->viewPosition
++;
150 return vp
!=tPtr
->viewPosition
;
155 incrToFit2(TextField
*tPtr
)
157 int vp
= tPtr
->viewPosition
;
158 while (TEXT_WIDTH2(tPtr
, tPtr
->viewPosition
, tPtr
->cursorPosition
)
159 >= tPtr
->usableWidth
)
160 tPtr
->viewPosition
++;
163 return vp
!=tPtr
->viewPosition
;
168 decrToFit(TextField
*tPtr
)
170 while (TEXT_WIDTH(tPtr
, tPtr
->viewPosition
-1) < tPtr
->usableWidth
171 && tPtr
->viewPosition
>0)
172 tPtr
->viewPosition
--;
180 WMCreateTextField(WMWidget
*parent
)
184 tPtr
= wmalloc(sizeof(TextField
));
185 memset(tPtr
, 0, sizeof(TextField
));
187 tPtr
->widgetClass
= WC_TextField
;
189 tPtr
->view
= W_CreateView(W_VIEW(parent
));
194 tPtr
->view
->self
= tPtr
;
196 tPtr
->view
->attribFlags
|= CWCursor
;
197 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->textCursor
;
199 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->view
->screen
->white
);
201 tPtr
->text
= wmalloc(MIN_TEXT_BUFFER
);
204 tPtr
->bufferSize
= MIN_TEXT_BUFFER
;
206 tPtr
->flags
.enabled
= 1;
208 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
209 |FocusChangeMask
, handleEvents
, tPtr
);
211 W_ResizeView(tPtr
->view
, DEFAULT_WIDTH
, DEFAULT_HEIGHT
);
213 tPtr
->font
= WMRetainFont(tPtr
->view
->screen
->normalFont
);
215 tPtr
->flags
.bordered
= DEFAULT_BORDERED
;
216 tPtr
->flags
.beveled
= True
;
217 tPtr
->flags
.alignment
= DEFAULT_ALIGNMENT
;
219 WMAX((tPtr
->view
->size
.height
- WMFontHeight(tPtr
->font
))/2, 1);
221 WMCreateEventHandler(tPtr
->view
, EnterWindowMask
|LeaveWindowMask
222 |ButtonReleaseMask
|ButtonPressMask
|KeyPressMask
|Button1MotionMask
,
223 handleTextFieldActionEvents
, tPtr
);
225 tPtr
->flags
.cursorOn
= 1;
232 WMSetTextFieldDelegate(WMTextField
*tPtr
, WMTextFieldDelegate
*delegate
)
234 tPtr
->delegate
= delegate
;
239 WMInsertTextFieldText(WMTextField
*tPtr
, char *text
, int position
)
243 CHECK_CLASS(tPtr
, WC_TextField
);
250 /* check if buffer will hold the text */
251 if (len
+ tPtr
->textLen
>= tPtr
->bufferSize
) {
252 tPtr
->bufferSize
= tPtr
->textLen
+ len
+ TEXT_BUFFER_INCR
;
253 tPtr
->text
= realloc(tPtr
->text
, tPtr
->bufferSize
);
256 if (position
< 0 || position
>= tPtr
->textLen
) {
257 /* append the text at the end */
258 strcat(tPtr
->text
, text
);
262 tPtr
->textLen
+= len
;
263 tPtr
->cursorPosition
+= len
;
265 /* insert text at position */
266 memmv(&(tPtr
->text
[position
+len
]), &(tPtr
->text
[position
]),
267 tPtr
->textLen
-position
+1);
269 memcpy(&(tPtr
->text
[position
]), text
, len
);
271 tPtr
->textLen
+= len
;
272 if (position
>= tPtr
->cursorPosition
) {
273 tPtr
->cursorPosition
+= len
;
280 paintTextField(tPtr
);
285 WMDeleteTextFieldRange(WMTextField
*tPtr
, WMRange range
)
287 CHECK_CLASS(tPtr
, WC_TextField
);
289 if (range
.position
>= tPtr
->textLen
)
292 if (range
.count
< 1) {
293 if (range
.position
< 0)
295 tPtr
->text
[range
.position
] = 0;
296 tPtr
->textLen
= range
.position
;
298 tPtr
->cursorPosition
= 0;
299 tPtr
->viewPosition
= 0;
301 if (range
.position
+ range
.count
> tPtr
->textLen
)
302 range
.count
= tPtr
->textLen
- range
.position
;
303 memmv(&(tPtr
->text
[range
.position
]), &(tPtr
->text
[range
.position
+range
.count
]),
304 tPtr
->textLen
- (range
.position
+range
.count
) + 1);
305 tPtr
->textLen
-= range
.count
;
307 if (tPtr
->cursorPosition
> range
.position
)
308 tPtr
->cursorPosition
-= range
.count
;
313 paintTextField(tPtr
);
319 WMGetTextFieldText(WMTextField
*tPtr
)
321 CHECK_CLASS(tPtr
, WC_TextField
);
323 return wstrdup(tPtr
->text
);
328 WMSetTextFieldText(WMTextField
*tPtr
, char *text
)
330 if ((text
&& strcmp(tPtr
->text
, text
) == 0) ||
331 (!text
&& tPtr
->textLen
== 0))
338 tPtr
->textLen
= strlen(text
);
340 if (tPtr
->textLen
>= tPtr
->bufferSize
) {
341 tPtr
->bufferSize
= tPtr
->textLen
+ TEXT_BUFFER_INCR
;
342 tPtr
->text
= realloc(tPtr
->text
, tPtr
->bufferSize
);
344 strcpy(tPtr
->text
, text
);
347 if (tPtr->textLen < tPtr->cursorPosition)
348 tPtr->cursorPosition = tPtr->textLen;
350 tPtr
->cursorPosition
= tPtr
->textLen
;
351 tPtr
->viewPosition
= 0;
352 tPtr
->selection
.count
= 0;
354 if (tPtr
->view
->flags
.realized
)
355 paintTextField(tPtr
);
360 WMSetTextFieldFont(WMTextField
*tPtr
, WMFont
*font
)
362 /* TODO: update font change after field is mapped */
363 WMReleaseFont(tPtr
->font
);
364 tPtr
->font
= WMRetainFont(font
);
369 WMSetTextFieldAlignment(WMTextField
*tPtr
, WMAlignment alignment
)
371 tPtr
->flags
.alignment
= alignment
;
372 if (alignment
!=WALeft
) {
373 wwarning("only left alignment is supported in textfields");
377 if (tPtr
->view
->flags
.realized
) {
378 paintTextField(tPtr
);
384 WMSetTextFieldBordered(WMTextField
*tPtr
, Bool bordered
)
386 tPtr
->flags
.bordered
= bordered
;
388 if (tPtr
->view
->flags
.realized
) {
389 paintTextField(tPtr
);
395 WMSetTextFieldBeveled(WMTextField
*tPtr
, Bool flag
)
397 tPtr
->flags
.beveled
= flag
;
399 if (tPtr
->view
->flags
.realized
) {
400 paintTextField(tPtr
);
407 WMSetTextFieldSecure(WMTextField
*tPtr
, Bool flag
)
409 tPtr
->flags
.secure
= flag
;
411 if (tPtr
->view
->flags
.realized
) {
412 paintTextField(tPtr
);
418 WMGetTextFieldEditable(WMTextField
*tPtr
)
420 return tPtr
->flags
.enabled
;
425 WMSetTextFieldEditable(WMTextField
*tPtr
, Bool flag
)
427 tPtr
->flags
.enabled
= flag
;
429 if (tPtr
->view
->flags
.realized
) {
430 paintTextField(tPtr
);
436 WMSelectTextFieldRange(WMTextField
*tPtr
, WMRange range
)
438 if (tPtr
->flags
.enabled
) {
439 if (range
.position
< 0) {
440 range
.count
+= range
.position
;
441 range
.count
= (range
.count
< 0) ? 0 : range
.count
;
443 } else if (range
.position
> tPtr
->textLen
) {
444 range
.position
= tPtr
->textLen
;
448 if (range
.position
+ range
.count
> tPtr
->textLen
)
449 range
.count
= tPtr
->textLen
- range
.position
;
451 tPtr
->prevselection
= tPtr
->selection
; /* check if this is needed */
453 tPtr
->selection
= range
;
455 if (tPtr
->view
->flags
.realized
) {
456 paintTextField(tPtr
);
463 WMSetTextFieldCursorPosition(WMTextField
*tPtr
, unsigned int position
)
465 if (tPtr
->flags
.enabled
) {
466 if (position
> tPtr
->textLen
)
467 position
= tPtr
->textLen
;
469 tPtr
->cursorPosition
= position
;
470 if (tPtr
->view
->flags
.realized
) {
471 paintTextField(tPtr
);
478 WMSetTextFieldNextTextField(WMTextField
*tPtr
, WMTextField
*next
)
480 CHECK_CLASS(tPtr
, WC_TextField
);
482 if (tPtr
->view
->nextFocusChain
)
483 tPtr
->view
->nextFocusChain
->prevFocusChain
= NULL
;
484 tPtr
->view
->nextFocusChain
= NULL
;
488 CHECK_CLASS(next
, WC_TextField
);
490 if (tPtr
->view
->nextFocusChain
)
491 tPtr
->view
->nextFocusChain
->prevFocusChain
= NULL
;
492 if (next
->view
->prevFocusChain
)
493 next
->view
->prevFocusChain
->nextFocusChain
= NULL
;
495 tPtr
->view
->nextFocusChain
= next
->view
;
496 next
->view
->prevFocusChain
= tPtr
->view
;
501 WMSetTextFieldPrevTextField(WMTextField
*tPtr
, WMTextField
*prev
)
503 CHECK_CLASS(tPtr
, WC_TextField
);
505 if (tPtr
->view
->prevFocusChain
)
506 tPtr
->view
->prevFocusChain
->nextFocusChain
= NULL
;
507 tPtr
->view
->prevFocusChain
= NULL
;
511 CHECK_CLASS(prev
, WC_TextField
);
513 if (tPtr
->view
->prevFocusChain
)
514 tPtr
->view
->prevFocusChain
->nextFocusChain
= NULL
;
515 if (prev
->view
->nextFocusChain
)
516 prev
->view
->nextFocusChain
->prevFocusChain
= NULL
;
518 tPtr
->view
->prevFocusChain
= prev
->view
;
519 prev
->view
->nextFocusChain
= tPtr
->view
;
524 resizeTextField(WMTextField
*tPtr
, unsigned int width
, unsigned int height
)
526 W_ResizeView(tPtr
->view
, width
, height
);
529 WMAX((tPtr
->view
->size
.height
- WMFontHeight(tPtr
->font
))/2, 1);
531 tPtr
->usableWidth
= tPtr
->view
->size
.width
- 2*tPtr
->offsetWidth
+ 2;
536 makeHiddenString(int length
)
538 char *data
= wmalloc(length
+1);
540 memset(data
, '*', length
);
547 paintCursor(TextField
*tPtr
)
550 WMScreen
*screen
= tPtr
->view
->screen
;
554 if (tPtr
->flags
.secure
)
555 text
= makeHiddenString(strlen(tPtr
->text
));
559 cx
= WMWidthOfString(tPtr
->font
, &(text
[tPtr
->viewPosition
]),
560 tPtr
->cursorPosition
-tPtr
->viewPosition
);
562 switch (tPtr
->flags
.alignment
) {
564 textWidth
= WMWidthOfString(tPtr
->font
, text
, tPtr
->textLen
);
565 if (textWidth
< tPtr
->usableWidth
)
566 cx
+= tPtr
->offsetWidth
+ tPtr
->usableWidth
- textWidth
+ 1;
568 cx
+= tPtr
->offsetWidth
+ 1;
571 cx
+= tPtr
->offsetWidth
+ 1;
576 textWidth
= WMWidthOfString(tPtr
->font
, text
, tPtr
->textLen
);
577 if (textWidth
< tPtr
->usableWidth
)
578 cx
+= tPtr
->offsetWidth
+ (tPtr
->usableWidth
-textWidth
)/2;
580 cx
+= tPtr
->offsetWidth
;
584 XDrawRectangle(screen->display, tPtr->view->window, screen->xorGC,
585 cx, tPtr->offsetWidth, 1,
586 tPtr->view->size.height - 2*tPtr->offsetWidth - 1);
587 printf("%d %d\n",cx,tPtr->cursorPosition);
589 XDrawLine(screen
->display
, tPtr
->view
->window
, screen
->xorGC
,
590 cx
, tPtr
->offsetWidth
, cx
,
591 tPtr
->view
->size
.height
- tPtr
->offsetWidth
- 1);
593 if (tPtr
->flags
.secure
)
600 drawRelief(WMView
*view
, Bool beveled
)
602 WMScreen
*scr
= view
->screen
;
603 Display
*dpy
= scr
->display
;
607 int width
= view
->size
.width
;
608 int height
= view
->size
.height
;
610 dgc
= WMColorGC(scr
->darkGray
);
613 XDrawRectangle(dpy
, view
->window
, dgc
, 0, 0, width
-1, height
-1);
617 wgc
= WMColorGC(scr
->white
);
618 lgc
= WMColorGC(scr
->gray
);
621 XDrawLine(dpy
, view
->window
, dgc
, 0, 0, width
-1, 0);
622 XDrawLine(dpy
, view
->window
, dgc
, 0, 1, width
-2, 1);
624 XDrawLine(dpy
, view
->window
, dgc
, 0, 0, 0, height
-2);
625 XDrawLine(dpy
, view
->window
, dgc
, 1, 0, 1, height
-3);
628 XDrawLine(dpy
, view
->window
, wgc
, 0, height
-1, width
-1, height
-1);
629 XDrawLine(dpy
, view
->window
, lgc
, 1, height
-2, width
-2, height
-2);
631 XDrawLine(dpy
, view
->window
, wgc
, width
-1, 0, width
-1, height
-1);
632 XDrawLine(dpy
, view
->window
, lgc
, width
-2, 1, width
-2, height
-3);
637 paintTextField(TextField
*tPtr
)
639 W_Screen
*screen
= tPtr
->view
->screen
;
640 W_View
*view
= tPtr
->view
;
650 if (!view
->flags
.realized
|| !view
->flags
.mapped
)
653 if (!tPtr
->flags
.bordered
) {
659 if (tPtr
->flags
.secure
) {
660 text
= makeHiddenString(strlen(tPtr
->text
));
665 totalWidth
= tPtr
->view
->size
.width
- 2*bd
;
667 drawbuffer
= XCreatePixmap(screen
->display
, view
->window
,
668 view
->size
.width
, view
->size
.height
, screen
->depth
);
669 XFillRectangle(screen
->display
, drawbuffer
, WMColorGC(screen
->white
),
670 0,0, view
->size
.width
,view
->size
.height
);
671 /* this is quite dirty */
672 viewbuffer
.screen
= view
->screen
;
673 viewbuffer
.size
= view
->size
;
674 viewbuffer
.window
= drawbuffer
;
677 if (tPtr
->textLen
> 0) {
678 tw
= WMWidthOfString(tPtr
->font
, &(text
[tPtr
->viewPosition
]),
679 tPtr
->textLen
- tPtr
->viewPosition
);
681 th
= WMFontHeight(tPtr
->font
);
683 ty
= tPtr
->offsetWidth
;
684 switch (tPtr
->flags
.alignment
) {
686 tx
= tPtr
->offsetWidth
+ 1;
687 if (tw
< tPtr
->usableWidth
)
688 XFillRectangle(screen
->display
, drawbuffer
,
689 WMColorGC(screen
->white
),
690 bd
+tw
,bd
, totalWidth
-tw
,view
->size
.height
-2*bd
);
694 tx
= tPtr
->offsetWidth
+ (tPtr
->usableWidth
- tw
) / 2;
695 if (tw
< tPtr
->usableWidth
)
696 XClearArea(screen
->display
, view
->window
, bd
, bd
,
697 totalWidth
, view
->size
.height
-2*bd
, False
);
702 tx
= tPtr
->offsetWidth
+ tPtr
->usableWidth
- tw
- 1;
703 if (tw
< tPtr
->usableWidth
)
704 XClearArea(screen
->display
, view
->window
, bd
, bd
,
705 totalWidth
-tw
, view
->size
.height
-2*bd
, False
);
709 if (!tPtr
->flags
.enabled
)
710 WMSetColorInGC(screen
->darkGray
, screen
->textFieldGC
);
712 WMDrawImageString(screen
, drawbuffer
, screen
->textFieldGC
,
714 &(text
[tPtr
->viewPosition
]),
715 tPtr
->textLen
- tPtr
->viewPosition
);
717 if (tPtr
->selection
.count
) {
720 count
= tPtr
->selection
.count
< 0
721 ? tPtr
->selection
.position
+ tPtr
->selection
.count
722 : tPtr
->selection
.position
;
723 count2
= abs(tPtr
->selection
.count
);
724 if (count
< tPtr
->viewPosition
) {
725 count2
= abs(count2
- abs(tPtr
->viewPosition
- count
));
726 count
= tPtr
->viewPosition
;
730 rx
= tPtr
->offsetWidth
+ 1 + WMWidthOfString(tPtr
->font
,text
,count
)
731 - WMWidthOfString(tPtr
->font
,text
,tPtr
->viewPosition
);
733 XSetBackground(screen
->display
, screen
->textFieldGC
,
734 screen
->gray
->color
.pixel
);
736 WMDrawImageString(screen
, drawbuffer
, screen
->textFieldGC
,
737 tPtr
->font
, rx
, ty
, &(text
[count
]),
740 XSetBackground(screen
->display
, screen
->textFieldGC
,
741 screen
->white
->color
.pixel
);
744 if (!tPtr
->flags
.enabled
)
745 WMSetColorInGC(screen
->black
, screen
->textFieldGC
);
747 XFillRectangle(screen
->display
, drawbuffer
,
748 WMColorGC(screen
->white
),
749 bd
,bd
, totalWidth
,view
->size
.height
-2*bd
);
753 if (tPtr
->flags
.bordered
) {
754 drawRelief(&viewbuffer
, tPtr
->flags
.beveled
);
757 if (tPtr
->flags
.secure
)
759 XCopyArea(screen
->display
, drawbuffer
, view
->window
,
760 screen
->copyGC
, 0,0, view
->size
.width
,
761 view
->size
.height
,0,0);
762 XFreePixmap(screen
->display
, drawbuffer
);
765 if (tPtr
->flags
.focused
&& tPtr
->flags
.enabled
&& tPtr
->flags
.cursorOn
) {
773 blinkCursor(void *data
)
775 TextField
*tPtr
= (TextField
*)data
;
777 if (tPtr
->flags
.cursorOn
) {
778 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY
, blinkCursor
,
781 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
, blinkCursor
,
785 tPtr
->flags
.cursorOn
= !tPtr
->flags
.cursorOn
;
791 handleEvents(XEvent
*event
, void *data
)
793 TextField
*tPtr
= (TextField
*)data
;
795 CHECK_CLASS(data
, WC_TextField
);
798 switch (event
->type
) {
800 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))!=tPtr
->view
)
802 tPtr
->flags
.focused
= 1;
804 if (!tPtr
->timerID
) {
805 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
,
809 paintTextField(tPtr
);
811 NOTIFY(tPtr
, didBeginEditing
, WMTextDidBeginEditingNotification
, NULL
);
813 tPtr
->flags
.notIllegalMovement
= 0;
817 tPtr
->flags
.focused
= 0;
820 WMDeleteTimerHandler(tPtr
->timerID
);
821 tPtr
->timerID
= NULL
;
824 paintTextField(tPtr
);
825 if (!tPtr
->flags
.notIllegalMovement
) {
826 NOTIFY(tPtr
, didEndEditing
, WMTextDidEndEditingNotification
,
827 (void*)WMIllegalTextMovement
);
832 if (event
->xexpose
.count
!=0)
834 paintTextField(tPtr
);
838 destroyTextField(tPtr
);
845 handleTextFieldKeyPress(TextField
*tPtr
, XEvent
*event
)
849 int count
, refresh
= 0;
850 int control_pressed
= 0;
852 if (((XKeyEvent
*) event
)->state
& WM_EMACSKEYMASK
) {
856 count
= XLookupString(&event
->xkey
, buffer
, 63, &ksym
, NULL
);
857 buffer
[count
] = '\0';
859 if (!(event
->xkey
.state
& ShiftMask
)) {
860 if (tPtr
->selection
.count
)
862 tPtr
->prevselection
= tPtr
->selection
;
863 tPtr
->selection
.position
= tPtr
->cursorPosition
;
864 tPtr
->selection
.count
= 0;
867 /* Be careful in any case in this switch statement, never to call
868 * to more than a function that can generate text change notifications.
869 * Only one text change notification should be sent in any case.
870 * Else hazardous things can happen.
871 * Maybe we need a better solution than the function wrapper to inform
872 * functions that change text in text fields, if they need to send a
873 * change notification or not. -Dan
877 case XK_ISO_Left_Tab
:
878 if (event
->xkey
.state
& ShiftMask
) {
879 if (tPtr
->view
->prevFocusChain
) {
880 W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr
->view
),
881 tPtr
->view
->prevFocusChain
);
882 tPtr
->flags
.notIllegalMovement
= 1;
884 NOTIFY(tPtr
, didEndEditing
, WMTextDidEndEditingNotification
,
885 (void*)WMBacktabTextMovement
);
887 if (tPtr
->view
->nextFocusChain
) {
888 W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr
->view
),
889 tPtr
->view
->nextFocusChain
);
890 tPtr
->flags
.notIllegalMovement
= 1;
892 NOTIFY(tPtr
, didEndEditing
, WMTextDidEndEditingNotification
,
893 (void*)WMTabTextMovement
);
898 NOTIFY(tPtr
, didEndEditing
, WMTextDidEndEditingNotification
,
899 (void*)WMReturnTextMovement
);
902 case WM_EMACSKEY_LEFT
:
903 if (!control_pressed
) {
908 if (tPtr
->cursorPosition
> 0) {
910 if (event
->xkey
.state
& ControlMask
) {
912 for (i
= tPtr
->cursorPosition
- 1; i
>= 0; i
--)
913 if (tPtr
->text
[i
] == ' ' || i
== 0) {
914 tPtr
->cursorPosition
= i
;
918 tPtr
->cursorPosition
--;
920 if (tPtr
->cursorPosition
< tPtr
->viewPosition
) {
921 tPtr
->viewPosition
= tPtr
->cursorPosition
;
929 case WM_EMACSKEY_RIGHT
:
930 if (!control_pressed
) {
935 if (tPtr
->cursorPosition
< tPtr
->textLen
) {
937 if (event
->xkey
.state
& ControlMask
) {
939 for (i
= tPtr
->cursorPosition
+ 1; i
<= tPtr
->textLen
; i
++)
940 if (tPtr
->text
[i
] == ' ' || i
== tPtr
->textLen
) {
941 tPtr
->cursorPosition
= i
;
945 tPtr
->cursorPosition
++;
947 while (WMWidthOfString(tPtr
->font
,
948 &(tPtr
->text
[tPtr
->viewPosition
]),
949 tPtr
->cursorPosition
-tPtr
->viewPosition
)
950 > tPtr
->usableWidth
) {
951 tPtr
->viewPosition
++;
959 case WM_EMACSKEY_HOME
:
960 if (!control_pressed
) {
965 if (tPtr
->cursorPosition
> 0) {
967 tPtr
->cursorPosition
= 0;
968 if (tPtr
->viewPosition
> 0) {
969 tPtr
->viewPosition
= 0;
977 case WM_EMACSKEY_END
:
978 if (!control_pressed
) {
983 if (tPtr
->cursorPosition
< tPtr
->textLen
) {
985 tPtr
->cursorPosition
= tPtr
->textLen
;
986 tPtr
->viewPosition
= 0;
987 while (WMWidthOfString(tPtr
->font
,
988 &(tPtr
->text
[tPtr
->viewPosition
]),
989 tPtr
->textLen
-tPtr
->viewPosition
)
990 > tPtr
->usableWidth
) {
991 tPtr
->viewPosition
++;
1000 if (!control_pressed
) {
1004 if (tPtr
->cursorPosition
> 0) {
1007 if (tPtr
->prevselection
.count
) {
1008 range
.position
= tPtr
->prevselection
.count
< 0
1009 ? tPtr
->prevselection
.position
+ tPtr
->prevselection
.count
1010 : tPtr
->prevselection
.position
;
1012 range
.count
= abs(tPtr
->prevselection
.count
);
1014 range
.position
= tPtr
->cursorPosition
- 1;
1017 WMDeleteTextFieldRange(tPtr
, range
);
1018 NOTIFY(tPtr
, didChange
, WMTextDidChangeNotification
,
1019 (void*)WMDeleteTextEvent
);
1023 case WM_EMACSKEY_DEL
:
1024 if (!control_pressed
) {
1029 if (tPtr
->cursorPosition
< tPtr
->textLen
|| tPtr
->prevselection
.count
) {
1032 if (tPtr
->prevselection
.count
) {
1033 range
.position
= tPtr
->prevselection
.count
< 0
1034 ? tPtr
->prevselection
.position
+ tPtr
->prevselection
.count
1035 : tPtr
->prevselection
.position
;
1037 range
.count
= abs(tPtr
->prevselection
.count
);
1039 range
.position
= tPtr
->cursorPosition
;
1042 WMDeleteTextFieldRange(tPtr
, range
);
1043 NOTIFY(tPtr
, didChange
, WMTextDidChangeNotification
,
1044 (void*)WMDeleteTextEvent
);
1050 if (count
> 0 && !iscntrl(buffer
[0])) {
1053 if (tPtr
->prevselection
.count
) {
1054 range
.position
= tPtr
->prevselection
.count
< 0
1055 ? tPtr
->prevselection
.position
+ tPtr
->prevselection
.count
1056 : tPtr
->prevselection
.position
;
1058 range
.count
= abs(tPtr
->prevselection
.count
);
1060 range
.position
= tPtr
->cursorPosition
;
1063 if (tPtr
->prevselection
.count
)
1064 WMDeleteTextFieldRange(tPtr
, range
);
1065 WMInsertTextFieldText(tPtr
, buffer
, tPtr
->cursorPosition
);
1066 NOTIFY(tPtr
, didChange
, WMTextDidChangeNotification
,
1067 (void*)WMInsertTextEvent
);
1073 if (event
->xkey
.state
& ShiftMask
) {
1074 if (tPtr
->selection
.count
== 0)
1075 tPtr
->selection
.position
= tPtr
->cursorPosition
;
1076 tPtr
->selection
.count
= tPtr
->cursorPosition
- tPtr
->selection
.position
;
1079 tPtr
->prevselection
.count
= 0;
1081 paintTextField(tPtr
);
1087 pointToCursorPosition(TextField
*tPtr
, int x
)
1092 if (tPtr
->flags
.bordered
)
1095 a
= tPtr
->viewPosition
;
1096 b
= tPtr
->viewPosition
+ tPtr
->textLen
;
1097 if (WMWidthOfString(tPtr
->font
, &(tPtr
->text
[tPtr
->viewPosition
]),
1098 tPtr
->textLen
- tPtr
->viewPosition
) < x
)
1099 return tPtr
->textLen
;
1101 while (a
< b
&& b
-a
>1) {
1103 tw
= WMWidthOfString(tPtr
->font
, &(tPtr
->text
[tPtr
->viewPosition
]),
1104 mid
- tPtr
->viewPosition
);
1117 handleTextFieldActionEvents(XEvent
*event
, void *data
)
1119 TextField
*tPtr
= (TextField
*)data
;
1122 CHECK_CLASS(data
, WC_TextField
);
1124 switch (event
->type
) {
1126 if (tPtr
->flags
.enabled
&& tPtr
->flags
.focused
) {
1127 handleTextFieldKeyPress(tPtr
, event
);
1128 XGrabPointer(WMScreenDisplay(W_VIEW(tPtr
)->screen
),
1129 W_VIEW(tPtr
)->window
, False
,
1130 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
1131 GrabModeAsync
, GrabModeAsync
, None
,
1132 W_VIEW(tPtr
)->screen
->invisibleCursor
,
1134 tPtr
->flags
.pointerGrabbed
= 1;
1140 if (tPtr
->flags
.pointerGrabbed
) {
1141 tPtr
->flags
.pointerGrabbed
= 0;
1142 XUngrabPointer(WMScreenDisplay(W_VIEW(tPtr
)->screen
), CurrentTime
);
1145 if (tPtr
->flags
.enabled
&& (event
->xmotion
.state
& Button1Mask
)) {
1147 if (tPtr
->viewPosition
< tPtr
->textLen
&& event
->xmotion
.x
>
1148 tPtr
->usableWidth
) {
1149 if (WMWidthOfString(tPtr
->font
,
1150 &(tPtr
->text
[tPtr
->viewPosition
]),
1151 tPtr
->cursorPosition
-tPtr
->viewPosition
)
1152 > tPtr
->usableWidth
) {
1153 tPtr
->viewPosition
++;
1155 } else if (tPtr
->viewPosition
> 0 && event
->xmotion
.x
< 0) {
1157 tPtr
->viewPosition
--;
1160 if (!tPtr
->selection
.count
) {
1161 tPtr
->selection
.position
= tPtr
->cursorPosition
;
1164 tPtr
->cursorPosition
=
1165 pointToCursorPosition(tPtr
, event
->xmotion
.x
);
1167 tPtr
->selection
.count
= tPtr
->cursorPosition
- tPtr
->selection
.position
;
1170 printf("notify %d %d\n",event->xmotion.x,tPtr->usableWidth);
1174 paintTextField(tPtr
);
1179 XSetSelectionOwner(tPtr
->view
->screen
->display
,
1180 XA_PRIMARY
, None
, CurrentTime
);
1181 count
= tPtr
->selection
.count
< 0
1182 ? tPtr
->selection
.position
+ tPtr
->selection
.count
1183 : tPtr
->selection
.position
;
1184 XStoreBuffer(tPtr
->view
->screen
->display
,
1185 &tPtr
->text
[count
] , abs(tPtr
->selection
.count
), 0);
1190 if (tPtr
->flags
.pointerGrabbed
) {
1191 tPtr
->flags
.pointerGrabbed
= 0;
1192 XUngrabPointer(WMScreenDisplay(W_VIEW(tPtr
)->screen
), CurrentTime
);
1197 switch (tPtr
->flags
.alignment
) {
1200 textWidth
= WMWidthOfString(tPtr
->font
, tPtr
->text
, tPtr
->textLen
);
1201 if (tPtr
->flags
.enabled
&& !tPtr
->flags
.focused
) {
1202 WMSetFocusToWidget(tPtr
);
1203 } else if (tPtr
->flags
.focused
) {
1204 tPtr
->selection
.count
= 0;
1206 if(textWidth
< tPtr
->usableWidth
){
1207 tPtr
->cursorPosition
= pointToCursorPosition(tPtr
,
1208 event
->xbutton
.x
- tPtr
->usableWidth
1211 else tPtr
->cursorPosition
= pointToCursorPosition(tPtr
,
1214 tPtr->cursorPosition = pointToCursorPosition(tPtr,
1216 tPtr->cursorPosition += tPtr->usableWidth - textWidth;
1219 tPtr->cursorPosition = pointToCursorPosition(tPtr,
1222 paintTextField(tPtr
);
1226 if (tPtr
->flags
.enabled
&& !tPtr
->flags
.focused
) {
1227 WMSetFocusToWidget(tPtr
);
1228 tPtr
->cursorPosition
= pointToCursorPosition(tPtr
,
1230 paintTextField(tPtr
);
1231 } else if (tPtr
->flags
.focused
) {
1232 tPtr
->cursorPosition
= pointToCursorPosition(tPtr
,
1234 tPtr
->selection
.count
= 0;
1235 paintTextField(tPtr
);
1237 if (event
->xbutton
.button
== Button2
&& tPtr
->flags
.enabled
) {
1240 text
= W_GetTextSelection(tPtr
->view
->screen
,
1241 tPtr
->view
->screen
->clipboardAtom
);
1243 text
= W_GetTextSelection(tPtr
->view
->screen
,
1247 WMInsertTextFieldText(tPtr
, text
, tPtr
->cursorPosition
);
1249 NOTIFY(tPtr
, didChange
, WMTextDidChangeNotification
,
1250 (void*)WMInsertTextEvent
);
1258 if (tPtr
->flags
.pointerGrabbed
) {
1259 tPtr
->flags
.pointerGrabbed
= 0;
1260 XUngrabPointer(WMScreenDisplay(W_VIEW(tPtr
)->screen
), CurrentTime
);
1270 destroyTextField(TextField
*tPtr
)
1274 WMDeleteTimerHandler(tPtr
->timerID
);
1277 WMReleaseFont(tPtr
->font
);