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
{
25 struct W_TextField
*nextField
; /* next textfield in the chain */
26 struct W_TextField
*prevField
;
29 int textLen
; /* size of text */
30 int bufferSize
; /* memory allocated for text */
32 int viewPosition
; /* position of text being shown */
34 int cursorPosition
; /* position of the insertion cursor */
37 short offsetWidth
; /* offset of text from border */
40 WMRange prevselection
;
43 WMHandlerID timerID
; /* for cursor blinking */
46 WMAlignment alignment
:2;
48 unsigned int bordered
:1;
50 unsigned int enabled
:1;
52 unsigned int focused
:1;
54 unsigned int cursorOn
:1;
56 unsigned int secure
:1; /* password entry style */
59 unsigned int notIllegalMovement
:1;
64 #define MIN_TEXT_BUFFER 2
65 #define TEXT_BUFFER_INCR 8
68 #define WM_EMACSKEYMASK ControlMask
70 #define WM_EMACSKEY_LEFT XK_b
71 #define WM_EMACSKEY_RIGHT XK_f
72 #define WM_EMACSKEY_HOME XK_a
73 #define WM_EMACSKEY_END XK_e
74 #define WM_EMACSKEY_BS XK_h
75 #define WM_EMACSKEY_DEL XK_d
79 #define DEFAULT_WIDTH 60
80 #define DEFAULT_HEIGHT 20
81 #define DEFAULT_BORDERED True
82 #define DEFAULT_ALIGNMENT WALeft
86 static void destroyTextField(TextField
*tPtr
);
87 static void paintTextField(TextField
*tPtr
);
89 static void handleEvents(XEvent
*event
, void *data
);
90 static void handleTextFieldActionEvents(XEvent
*event
, void *data
);
91 static void resizeTextField();
93 struct W_ViewProcedureTable _TextFieldViewProcedures
= {
100 #define TEXT_WIDTH(tPtr, start) (WMWidthOfString((tPtr)->view->screen->normalFont, \
101 &((tPtr)->text[(start)]), (tPtr)->textLen - (start) + 1))
103 #define TEXT_WIDTH2(tPtr, start, end) (WMWidthOfString((tPtr)->view->screen->normalFont, \
104 &((tPtr)->text[(start)]), (end) - (start) + 1))
108 memmv(char *dest
, char *src
, int size
)
113 for (i
=size
-1; i
>=0; i
--) {
116 } else if (dest
< src
) {
117 for (i
=0; i
<size
; i
++) {
125 incrToFit(TextField
*tPtr
)
127 int vp
= tPtr
->viewPosition
;
129 while (TEXT_WIDTH(tPtr
, tPtr
->viewPosition
) > tPtr
->usableWidth
) {
130 tPtr
->viewPosition
++;
132 return vp
!=tPtr
->viewPosition
;
137 incrToFit2(TextField
*tPtr
)
139 int vp
= tPtr
->viewPosition
;
140 while (TEXT_WIDTH2(tPtr
, tPtr
->viewPosition
, tPtr
->cursorPosition
)
141 >= tPtr
->usableWidth
)
142 tPtr
->viewPosition
++;
145 return vp
!=tPtr
->viewPosition
;
150 decrToFit(TextField
*tPtr
)
152 while (TEXT_WIDTH(tPtr
, tPtr
->viewPosition
-1) < tPtr
->usableWidth
153 && tPtr
->viewPosition
>0)
154 tPtr
->viewPosition
--;
162 WMCreateTextField(WMWidget
*parent
)
167 tPtr
= wmalloc(sizeof(TextField
));
168 memset(tPtr
, 0, sizeof(TextField
));
170 tPtr
->widgetClass
= WC_TextField
;
172 tPtr
->view
= W_CreateView(W_VIEW(parent
));
177 tPtr
->view
->self
= tPtr
;
179 tPtr
->view
->attribFlags
|= CWCursor
;
180 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->textCursor
;
182 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->view
->screen
->white
);
184 tPtr
->text
= wmalloc(MIN_TEXT_BUFFER
);
187 tPtr
->bufferSize
= MIN_TEXT_BUFFER
;
189 tPtr
->flags
.enabled
= 1;
191 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
192 |FocusChangeMask
, handleEvents
, tPtr
);
194 W_ResizeView(tPtr
->view
, DEFAULT_WIDTH
, DEFAULT_HEIGHT
);
195 WMSetTextFieldBordered(tPtr
, DEFAULT_BORDERED
);
196 tPtr
->flags
.alignment
= DEFAULT_ALIGNMENT
;
197 tPtr
->offsetWidth
= (tPtr
->view
->size
.height
198 - WMFontHeight(tPtr
->view
->screen
->normalFont
))/2;
200 WMCreateEventHandler(tPtr
->view
, EnterWindowMask
|LeaveWindowMask
201 |ButtonPressMask
|KeyPressMask
|Button1MotionMask
,
202 handleTextFieldActionEvents
, tPtr
);
204 tPtr
->flags
.cursorOn
= 1;
211 WMInsertTextFieldText(WMTextField
*tPtr
, char *text
, int position
)
215 CHECK_CLASS(tPtr
, WC_TextField
);
222 /* check if buffer will hold the text */
223 if (len
+ tPtr
->textLen
>= tPtr
->bufferSize
) {
224 tPtr
->bufferSize
= tPtr
->textLen
+ len
+ TEXT_BUFFER_INCR
;
225 tPtr
->text
= realloc(tPtr
->text
, tPtr
->bufferSize
);
228 if (position
< 0 || position
>= tPtr
->textLen
) {
229 /* append the text at the end */
230 strcat(tPtr
->text
, text
);
234 tPtr
->textLen
+= len
;
235 tPtr
->cursorPosition
+= len
;
237 /* insert text at position */
238 memmv(&(tPtr
->text
[position
+len
]), &(tPtr
->text
[position
]),
239 tPtr
->textLen
-position
+1);
241 memcpy(&(tPtr
->text
[position
]), text
, len
);
243 tPtr
->textLen
+= len
;
244 if (position
>= tPtr
->cursorPosition
) {
245 tPtr
->cursorPosition
+= len
;
252 paintTextField(tPtr
);
254 WMPostNotificationName(WMTextDidChangeNotification
, tPtr
,
255 (void*)WMInsertTextEvent
);
260 deleteTextFieldRange(WMTextField
*tPtr
, WMRange range
)
262 CHECK_CLASS(tPtr
, WC_TextField
);
264 if (range
.position
>= tPtr
->textLen
)
267 if (range
.count
< 1) {
268 if (range
.position
< 0)
270 tPtr
->text
[range
.position
] = 0;
271 tPtr
->textLen
= range
.position
;
273 tPtr
->cursorPosition
= 0;
274 tPtr
->viewPosition
= 0;
276 if (range
.position
+ range
.count
> tPtr
->textLen
)
277 range
.count
= tPtr
->textLen
- range
.position
;
278 memmv(&(tPtr
->text
[range
.position
]), &(tPtr
->text
[range
.position
+range
.count
]),
279 tPtr
->textLen
- (range
.position
+range
.count
) + 1);
280 tPtr
->textLen
-= range
.count
;
282 if (tPtr
->cursorPosition
> range
.position
)
283 tPtr
->cursorPosition
-= range
.count
;
288 paintTextField(tPtr
);
293 WMDeleteTextFieldRange(WMTextField
*tPtr
, WMRange range
)
295 deleteTextFieldRange(tPtr
, range
);
296 WMPostNotificationName(WMTextDidChangeNotification
, tPtr
,
297 (void*)WMDeleteTextEvent
);
303 WMGetTextFieldText(WMTextField
*tPtr
)
305 CHECK_CLASS(tPtr
, WC_TextField
);
307 return wstrdup(tPtr
->text
);
312 WMSetTextFieldText(WMTextField
*tPtr
, char *text
)
314 /* We do not set text if it's the same. This will also help
315 * to avoid some infinite loops if this function is called from
316 * a function called by a notification observer. -Dan
318 if ((text
&& strcmp(tPtr
->text
, text
) == 0) ||
319 (!text
&& tPtr
->textLen
== 0))
326 tPtr
->textLen
= strlen(text
);
328 if (tPtr
->textLen
>= tPtr
->bufferSize
) {
329 tPtr
->bufferSize
= tPtr
->textLen
+ TEXT_BUFFER_INCR
;
330 tPtr
->text
= realloc(tPtr
->text
, tPtr
->bufferSize
);
332 strcpy(tPtr
->text
, text
);
335 if (tPtr->textLen < tPtr->cursorPosition)
336 tPtr->cursorPosition = tPtr->textLen;
338 tPtr
->cursorPosition
= tPtr
->textLen
;
339 tPtr
->viewPosition
= 0;
340 tPtr
->selection
.count
= 0;
342 if (tPtr
->view
->flags
.realized
)
343 paintTextField(tPtr
);
345 WMPostNotificationName(WMTextDidChangeNotification
, tPtr
,
346 (void*)WMSetTextEvent
);
351 WMSetTextFieldAlignment(WMTextField
*tPtr
, WMAlignment alignment
)
353 tPtr
->flags
.alignment
= alignment
;
354 if (alignment
!=WALeft
) {
355 wwarning("only left alignment is supported in textfields");
359 if (tPtr
->view
->flags
.realized
) {
360 paintTextField(tPtr
);
366 WMSetTextFieldBordered(WMTextField
*tPtr
, Bool bordered
)
368 tPtr
->flags
.bordered
= bordered
;
370 if (tPtr
->view
->flags
.realized
) {
371 paintTextField(tPtr
);
378 WMSetTextFieldSecure(WMTextField
*tPtr
, Bool flag
)
380 tPtr
->flags
.secure
= flag
;
382 if (tPtr
->view
->flags
.realized
) {
383 paintTextField(tPtr
);
389 WMSetTextFieldEnabled(WMTextField
*tPtr
, Bool flag
)
391 tPtr
->flags
.enabled
= flag
;
393 if (tPtr
->view
->flags
.realized
) {
394 paintTextField(tPtr
);
400 WMSelectTextFieldRange(WMTextField
*tPtr
, WMRange range
)
402 if (tPtr
->flags
.enabled
) {
403 if (range
.position
< 0) {
404 range
.count
+= range
.position
;
405 range
.count
= (range
.count
< 0) ? 0 : range
.count
;
407 } else if (range
.position
> tPtr
->textLen
) {
408 range
.position
= tPtr
->textLen
;
412 if (range
.position
+ range
.count
> tPtr
->textLen
)
413 range
.count
= tPtr
->textLen
- range
.position
;
415 tPtr
->prevselection
= tPtr
->selection
; /* check if this is needed */
417 tPtr
->selection
= range
;
419 if (tPtr
->view
->flags
.realized
) {
420 paintTextField(tPtr
);
427 WMSetTextFieldCursorPosition(WMTextField
*tPtr
, unsigned int position
)
429 if (tPtr
->flags
.enabled
) {
430 if (position
> tPtr
->textLen
)
431 position
= tPtr
->textLen
;
433 tPtr
->cursorPosition
= position
;
434 if (tPtr
->view
->flags
.realized
) {
435 paintTextField(tPtr
);
442 resizeTextField(WMTextField
*tPtr
, unsigned int width
, unsigned int height
)
444 W_ResizeView(tPtr
->view
, width
, height
);
446 tPtr
->offsetWidth
= (tPtr
->view
->size
.height
447 - WMFontHeight(tPtr
->view
->screen
->normalFont
))/2;
449 tPtr
->usableWidth
= tPtr
->view
->size
.width
- 2*tPtr
->offsetWidth
;
454 paintCursor(TextField
*tPtr
)
457 WMScreen
*screen
= tPtr
->view
->screen
;
460 cx
= WMWidthOfString(screen
->normalFont
,
461 &(tPtr
->text
[tPtr
->viewPosition
]),
462 tPtr
->cursorPosition
-tPtr
->viewPosition
);
464 switch (tPtr
->flags
.alignment
) {
466 textWidth
= WMWidthOfString(screen
->normalFont
, tPtr
->text
,
468 if (textWidth
< tPtr
->usableWidth
)
469 cx
+= tPtr
->offsetWidth
+ tPtr
->usableWidth
- textWidth
;
471 cx
+= tPtr
->offsetWidth
;
474 cx
+= tPtr
->offsetWidth
;
479 textWidth
= WMWidthOfString(screen
->normalFont
, tPtr
->text
,
481 if (textWidth
< tPtr
->usableWidth
)
482 cx
+= tPtr
->offsetWidth
+ (tPtr
->usableWidth
-textWidth
)/2;
484 cx
+= tPtr
->offsetWidth
;
488 XDrawRectangle(screen->display, tPtr->view->window, screen->xorGC,
489 cx, tPtr->offsetWidth, 1,
490 tPtr->view->size.height - 2*tPtr->offsetWidth - 1);
492 XDrawLine(screen
->display
, tPtr
->view
->window
, screen
->xorGC
,
493 cx
, tPtr
->offsetWidth
, cx
,
494 tPtr
->view
->size
.height
- tPtr
->offsetWidth
- 1);
500 drawRelief(WMView
*view
)
502 WMScreen
*scr
= view
->screen
;
503 Display
*dpy
= scr
->display
;
507 int width
= view
->size
.width
;
508 int height
= view
->size
.height
;
510 wgc
= W_GC(scr
->white
);
511 dgc
= W_GC(scr
->darkGray
);
512 lgc
= W_GC(scr
->gray
);
515 XDrawLine(dpy
, view
->window
, dgc
, 0, 0, width
-1, 0);
516 XDrawLine(dpy
, view
->window
, dgc
, 0, 1, width
-2, 1);
518 XDrawLine(dpy
, view
->window
, dgc
, 0, 0, 0, height
-2);
519 XDrawLine(dpy
, view
->window
, dgc
, 1, 0, 1, height
-3);
522 XDrawLine(dpy
, view
->window
, wgc
, 0, height
-1, width
-1, height
-1);
523 XDrawLine(dpy
, view
->window
, lgc
, 1, height
-2, width
-2, height
-2);
525 XDrawLine(dpy
, view
->window
, wgc
, width
-1, 0, width
-1, height
-1);
526 XDrawLine(dpy
, view
->window
, lgc
, width
-2, 1, width
-2, height
-3);
531 paintTextField(TextField
*tPtr
)
533 W_Screen
*screen
= tPtr
->view
->screen
;
534 W_View
*view
= tPtr
->view
;
541 if (!view
->flags
.realized
|| !view
->flags
.mapped
)
544 if (!tPtr
->flags
.bordered
) {
550 totalWidth
= tPtr
->view
->size
.width
- 2*bd
;
552 if (tPtr
->textLen
> 0) {
553 tw
= WMWidthOfString(screen
->normalFont
,
554 &(tPtr
->text
[tPtr
->viewPosition
]),
555 tPtr
->textLen
- tPtr
->viewPosition
);
557 th
= WMFontHeight(screen
->normalFont
);
559 ty
= tPtr
->offsetWidth
;
560 switch (tPtr
->flags
.alignment
) {
562 tx
= tPtr
->offsetWidth
;
563 if (tw
< tPtr
->usableWidth
)
564 XClearArea(screen
->display
, view
->window
, bd
+tw
, bd
,
565 totalWidth
-tw
, view
->size
.height
-2*bd
,
570 tx
= tPtr
->offsetWidth
+ (tPtr
->usableWidth
- tw
) / 2;
571 if (tw
< tPtr
->usableWidth
)
572 XClearArea(screen
->display
, view
->window
, bd
, bd
,
573 totalWidth
, view
->size
.height
-2*bd
, False
);
578 tx
= tPtr
->offsetWidth
+ tPtr
->usableWidth
- tw
;
579 if (tw
< tPtr
->usableWidth
)
580 XClearArea(screen
->display
, view
->window
, bd
, bd
,
581 totalWidth
-tw
, view
->size
.height
-2*bd
, False
);
585 if (!tPtr
->flags
.secure
) {
586 if (!tPtr
->flags
.enabled
)
587 WMSetColorInGC(screen
->darkGray
, screen
->textFieldGC
);
589 WMDrawImageString(screen
, view
->window
, screen
->textFieldGC
,
590 screen
->normalFont
, tx
, ty
,
591 &(tPtr
->text
[tPtr
->viewPosition
]),
592 tPtr
->textLen
- tPtr
->viewPosition
);
594 if (tPtr
->selection
.count
) {
597 count
= tPtr
->selection
.count
< 0
598 ? tPtr
->selection
.position
+ tPtr
->selection
.count
599 : tPtr
->selection
.position
;
601 rx
= tx
+ WMWidthOfString(screen
->normalFont
,
602 &(tPtr
->text
[tPtr
->viewPosition
]),
605 XSetBackground(screen
->display
, screen
->textFieldGC
,
606 screen
->gray
->color
.pixel
);
608 WMDrawImageString(screen
, view
->window
, screen
->textFieldGC
,
609 screen
->normalFont
, rx
, ty
,
610 &(tPtr
->text
[count
]),
611 abs(tPtr
->selection
.count
));
613 XSetBackground(screen
->display
, screen
->textFieldGC
,
614 screen
->white
->color
.pixel
);
617 if (!tPtr
->flags
.enabled
)
618 WMSetColorInGC(screen
->black
, screen
->textFieldGC
);
621 XClearArea(screen
->display
, view
->window
, bd
, bd
, totalWidth
,
622 view
->size
.height
- 2*bd
, False
);
626 if (tPtr
->flags
.focused
&& tPtr
->flags
.enabled
&& tPtr
->flags
.cursorOn
627 && !tPtr
->flags
.secure
) {
632 if (tPtr
->flags
.bordered
) {
640 blinkCursor(void *data
)
642 TextField
*tPtr
= (TextField
*)data
;
644 if (tPtr
->flags
.cursorOn
) {
645 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY
, blinkCursor
,
648 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
, blinkCursor
,
652 tPtr
->flags
.cursorOn
= !tPtr
->flags
.cursorOn
;
658 handleEvents(XEvent
*event
, void *data
)
660 TextField
*tPtr
= (TextField
*)data
;
662 CHECK_CLASS(data
, WC_TextField
);
665 switch (event
->type
) {
667 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))!=tPtr
->view
)
669 tPtr
->flags
.focused
= 1;
671 if (!tPtr
->timerID
) {
672 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
,
676 paintTextField(tPtr
);
678 WMPostNotificationName(WMTextDidBeginEditingNotification
, tPtr
, NULL
);
680 tPtr
->flags
.notIllegalMovement
= 0;
684 tPtr
->flags
.focused
= 0;
687 WMDeleteTimerHandler(tPtr
->timerID
);
688 tPtr
->timerID
= NULL
;
691 paintTextField(tPtr
);
692 if (!tPtr
->flags
.notIllegalMovement
) {
693 WMPostNotificationName(WMTextDidEndEditingNotification
, tPtr
,
694 (void*)WMIllegalTextMovement
);
699 if (event
->xexpose
.count
!=0)
701 paintTextField(tPtr
);
705 destroyTextField(tPtr
);
712 handleTextFieldKeyPress(TextField
*tPtr
, XEvent
*event
)
716 int count
, refresh
= 0;
717 int control_pressed
= 0;
718 WMScreen
*scr
= tPtr
->view
->screen
;
720 if (((XKeyEvent
*) event
)->state
& WM_EMACSKEYMASK
) {
724 count
= XLookupString(&event
->xkey
, buffer
, 63, &ksym
, NULL
);
725 buffer
[count
] = '\0';
727 if (!(event
->xkey
.state
& ShiftMask
)) {
728 if (tPtr
->selection
.count
)
730 tPtr
->prevselection
= tPtr
->selection
;
731 tPtr
->selection
.position
= tPtr
->cursorPosition
;
732 tPtr
->selection
.count
= 0;
735 /* Be careful in any case in this switch statement, never to call
736 * to more than 2 functions at the same time, that can generate text
737 * change notifications. Only one text change notification should be sent
738 * in any case. Else hazardous things can happen.
739 * Maybe we need a better solution than the function wrapper to inform
740 * functions that change text in text fields, if they need to send a
741 * change notification or not. -Dan
745 if (event
->xkey
.state
& ShiftMask
) {
746 if (tPtr
->view
->prevFocusChain
) {
747 W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr
->view
),
748 tPtr
->view
->prevFocusChain
);
749 tPtr
->flags
.notIllegalMovement
= 1;
751 WMPostNotificationName(WMTextDidEndEditingNotification
, tPtr
,
752 (void*)WMBacktabTextMovement
);
754 if (tPtr
->view
->nextFocusChain
) {
755 W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr
->view
),
756 tPtr
->view
->nextFocusChain
);
757 tPtr
->flags
.notIllegalMovement
= 1;
759 WMPostNotificationName(WMTextDidEndEditingNotification
,
760 tPtr
, (void*)WMTabTextMovement
);
765 WMPostNotificationName(WMTextDidEndEditingNotification
, tPtr
,
766 (void*)WMReturnTextMovement
);
769 case WM_EMACSKEY_LEFT
:
770 if (!control_pressed
) {
775 if (tPtr
->cursorPosition
> 0) {
777 if (event
->xkey
.state
& ControlMask
) {
779 for (i
= tPtr
->cursorPosition
- 1; i
>= 0; i
--)
780 if (tPtr
->text
[i
] == ' ' || i
== 0) {
781 tPtr
->cursorPosition
= i
;
785 tPtr
->cursorPosition
--;
787 if (tPtr
->cursorPosition
< tPtr
->viewPosition
) {
788 tPtr
->viewPosition
= tPtr
->cursorPosition
;
796 case WM_EMACSKEY_RIGHT
:
797 if (!control_pressed
) {
802 if (tPtr
->cursorPosition
< tPtr
->textLen
) {
804 if (event
->xkey
.state
& ControlMask
) {
806 for (i
= tPtr
->cursorPosition
+ 1; i
<= tPtr
->textLen
; i
++)
807 if (tPtr
->text
[i
] == ' ' || i
== tPtr
->textLen
) {
808 tPtr
->cursorPosition
= i
;
812 tPtr
->cursorPosition
++;
814 while (WMWidthOfString(scr
->normalFont
,
815 &(tPtr
->text
[tPtr
->viewPosition
]),
816 tPtr
->cursorPosition
-tPtr
->viewPosition
)
817 > tPtr
->usableWidth
) {
818 tPtr
->viewPosition
++;
826 case WM_EMACSKEY_HOME
:
827 if (!control_pressed
) {
832 if (tPtr
->cursorPosition
> 0) {
834 tPtr
->cursorPosition
= 0;
835 if (tPtr
->viewPosition
> 0) {
836 tPtr
->viewPosition
= 0;
844 case WM_EMACSKEY_END
:
845 if (!control_pressed
) {
850 if (tPtr
->cursorPosition
< tPtr
->textLen
) {
852 tPtr
->cursorPosition
= tPtr
->textLen
;
853 tPtr
->viewPosition
= 0;
854 while (WMWidthOfString(scr
->normalFont
,
855 &(tPtr
->text
[tPtr
->viewPosition
]),
856 tPtr
->textLen
-tPtr
->viewPosition
)
857 > tPtr
->usableWidth
) {
858 tPtr
->viewPosition
++;
867 if (!control_pressed
) {
871 if (tPtr
->cursorPosition
> 0) {
873 if (tPtr
->prevselection
.count
) {
874 range
.position
= tPtr
->prevselection
.count
< 0
875 ? tPtr
->prevselection
.position
+ tPtr
->prevselection
.count
876 : tPtr
->prevselection
.position
;
878 range
.count
= abs(tPtr
->prevselection
.count
);
880 range
.position
= tPtr
->cursorPosition
- 1;
883 WMDeleteTextFieldRange(tPtr
, range
);
887 case WM_EMACSKEY_DEL
:
888 if (!control_pressed
) {
893 if (tPtr
->cursorPosition
< tPtr
->textLen
|| tPtr
->prevselection
.count
) {
895 if (tPtr
->prevselection
.count
) {
896 range
.position
= tPtr
->prevselection
.count
< 0
897 ? tPtr
->prevselection
.position
+ tPtr
->prevselection
.count
898 : tPtr
->prevselection
.position
;
900 range
.count
= abs(tPtr
->prevselection
.count
);
902 range
.position
= tPtr
->cursorPosition
;
905 WMDeleteTextFieldRange(tPtr
, range
);
911 if (count
> 0 && !iscntrl(buffer
[0])) {
913 if (tPtr
->prevselection
.count
) {
914 range
.position
= tPtr
->prevselection
.count
< 0
915 ? tPtr
->prevselection
.position
+ tPtr
->prevselection
.count
916 : tPtr
->prevselection
.position
;
918 range
.count
= abs(tPtr
->prevselection
.count
);
920 range
.position
= tPtr
->cursorPosition
;
923 if (tPtr
->prevselection
.count
)
924 deleteTextFieldRange(tPtr
, range
);
925 WMInsertTextFieldText(tPtr
, buffer
, tPtr
->cursorPosition
);
931 if (event
->xkey
.state
& ShiftMask
) {
932 if (tPtr
->selection
.count
== 0)
933 tPtr
->selection
.position
= tPtr
->cursorPosition
;
934 tPtr
->selection
.count
= tPtr
->cursorPosition
- tPtr
->selection
.position
;
937 tPtr
->prevselection
.count
= 0;
939 paintTextField(tPtr
);
945 pointToCursorPosition(TextField
*tPtr
, int x
)
947 WMFont
*font
= tPtr
->view
->screen
->normalFont
;
951 if (tPtr
->flags
.bordered
)
954 a
= tPtr
->viewPosition
;
955 b
= tPtr
->viewPosition
+ tPtr
->textLen
;
956 if (WMWidthOfString(font
, &(tPtr
->text
[tPtr
->viewPosition
]),
957 tPtr
->textLen
-tPtr
->viewPosition
) < x
)
958 return tPtr
->textLen
;
960 while (a
< b
&& b
-a
>1) {
962 tw
= WMWidthOfString(font
, &(tPtr
->text
[tPtr
->viewPosition
]),
963 mid
- tPtr
->viewPosition
);
976 handleTextFieldActionEvents(XEvent
*event
, void *data
)
978 TextField
*tPtr
= (TextField
*)data
;
980 CHECK_CLASS(data
, WC_TextField
);
982 switch (event
->type
) {
984 if (tPtr
->flags
.enabled
)
985 handleTextFieldKeyPress(tPtr
, event
);
989 if (tPtr
->flags
.enabled
&& (event
->xmotion
.state
& Button1Mask
)) {
991 if (!tPtr
->selection
.count
) {
992 tPtr
->selection
.position
= tPtr
->cursorPosition
;
995 tPtr
->cursorPosition
= pointToCursorPosition(tPtr
,
998 tPtr
->selection
.count
= tPtr
->cursorPosition
999 - tPtr
->selection
.position
;
1001 paintTextField(tPtr
);
1006 if (tPtr
->flags
.enabled
&& !tPtr
->flags
.focused
) {
1007 WMSetFocusToWidget(tPtr
);
1008 tPtr
->cursorPosition
= pointToCursorPosition(tPtr
,
1010 paintTextField(tPtr
);
1011 } else if (tPtr
->flags
.focused
) {
1012 tPtr
->cursorPosition
= pointToCursorPosition(tPtr
,
1014 tPtr
->selection
.count
= 0;
1015 paintTextField(tPtr
);
1017 if (event
->xbutton
.button
== Button2
&& tPtr
->flags
.enabled
) {
1020 text
= W_GetTextSelection(tPtr
->view
->screen
,
1021 tPtr
->view
->screen
->clipboardAtom
);
1023 text
= W_GetTextSelection(tPtr
->view
->screen
, XA_CUT_BUFFER0
);
1026 WMInsertTextFieldText(tPtr
, text
, tPtr
->cursorPosition
);
1028 WMPostNotificationName(WMTextDidChangeNotification
, tPtr
,
1042 destroyTextField(TextField
*tPtr
)
1046 WMDeleteTimerHandler(tPtr
->timerID
);