2 * WINGs WMText: multi-line/font/color/graphic text widget
4 * Copyright (c) 1999-2000 Nwanua Elumeze
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <X11/keysym.h>
24 #include <X11/Xatom.h>
31 * - use currentTextBlock and neighbours for fast paint and layout
32 * - replace copious uses of Refreshtext with appropriate layOut()...
33 * - code replaceSelection
34 * (deleteSelection is same cept replaceSelection(tPtr, NULL); )
35 * - WMFindInTextStream should also highlight found text...
40 /* a Section is a section of a TextBlock that describes what parts
41 of a TextBlock has been laid out on which "line"...
42 o this greatly aids redraw, scroll and selection.
43 o this is created during layoutLine, but may be later modified.
44 o there may be many Sections per TextBlock, hence the array */
46 int x
, y
; /* where to draw it from */
47 int w
, h
; /* it's width and height (to aid selection) */
49 unsigned short begin
, end
; /* what part of the text block */
53 /* a TextBlock is a doubly-linked list of TextBlocks containing:
54 o text for the block, color and font
55 o or a pointer to the widget and the (text) description for its graphic
58 typedef struct _TextBlock
{
59 struct _TextBlock
*next
; /* next text block in linked list */
60 struct _TextBlock
*prior
; /* prior text block in linked list */
62 char *text
; /* pointer to 8- or 16-bit text */
63 /* or to the object's description */
65 WMFont
*font
; /* the font */
66 WMWidget
*widget
; /* the embedded widget */
67 } d
; /* description */
69 WMColor
*color
; /* the color */
70 Section
*sections
; /* the region for layouts (a growable array) */
71 /* an _array_! of size _nsections_ */
74 unsigned short used
; /* number of chars in this block */
75 unsigned short allocated
; /* size of allocation (in chars) */
77 unsigned int first
:1; /* first TextBlock in paragraph */
78 unsigned int blank
:1; /* ie. blank paragraph */
79 unsigned int kanji
:1; /* is of 16-bit characters or not */
80 unsigned int graphic
:1; /* embedded object or text: text=0 */
81 unsigned int underlined
:1; /* underlined or not */
82 unsigned int nsections
:8; /* over how many "lines" a TexBlock wraps */
83 int script
:8; /* script in points: negative for subscript */
84 unsigned int marginN
:10; /* which of the margins in WMText to use */
85 unsigned int RESERVED
:1;
89 /* somehow visible.h beats the hell outta visible.size.height :-) */
98 typedef struct W_Text
{
99 W_Class widgetClass
; /* the class number of this widget */
100 W_View
*view
; /* the view referring to this instance */
102 WMRuler
*ruler
; /* the ruler subwiget to manipulate paragraphs */
104 WMScroller
*vS
; /* the vertical scroller */
105 int vpos
; /* the current vertical position */
106 int prevVpos
; /* the previous vertical position */
108 WMScroller
*hS
; /* the horizontal scroller */
109 int hpos
; /* the current horizontal position */
110 int prevHpos
; /* the previous horizontal position */
111 /* in short: tPtr->hS?nowrap:wrap */
113 WMFont
*dFont
; /* the default font */
114 WMColor
*dColor
; /* the default color */
115 WMPixmap
*dBulletPix
; /* the default pixmap for bullets */
117 GC bgGC
; /* the background GC to draw with */
118 GC fgGC
; /* the foreground GC to draw with */
119 Pixmap db
; /* the buffer on which to draw */
121 WMRulerMargins
*margins
;/* a (growable) array of margins to be used */
122 /* by the various TextBlocks */
124 myRect visible
; /* the actual rectangle that can be drawn into */
125 myRect cursor
; /* the position and (height) of cursor */
126 myRect sel
; /* the selection rectangle */
127 int docWidth
; /* the width of the entire document */
128 int docHeight
; /* the height of the entire document */
131 TextBlock
*firstTextBlock
;
132 TextBlock
*lastTextBlock
;
133 TextBlock
*currentTextBlock
;
136 WMBag
*gfxItems
; /* a nice bag containing graphic items */
139 WMHandlerID timerID
; /* for nice twinky-winky */
141 WMPoint clicked
; /* where in the _document_ was clicked */
142 unsigned short tpos
; /* the character position in the currentTextBlock */
143 unsigned short RESERVED
;/* space taker upper... */
150 unsigned int monoFont
:1; /* whether to ignore formats */
151 unsigned int focused
:1; /* whether this instance has input focus */
152 unsigned int editable
:1; /* "silly user, you can't edit me" */
153 unsigned int ownsSelection
:1; /* "I ownz the current selection!" */
154 unsigned int pointerGrabbed
:1;/* "heh, gib me pointer" */
155 unsigned int buttonHeld
:1; /* the user is holding down the button */
156 unsigned int waitingForSelection
:1; /* dum dee dumm... */
157 unsigned int extendSelection
:1; /* shift-drag to select more regions */
159 unsigned int rulerShown
:1; /* whether the ruler is shown or not */
160 unsigned int frozen
:1; /* whether screen updates are to be made */
161 unsigned int cursorShown
:1; /* whether to show the cursor */
162 unsigned int clickPos
:1; /* clicked before=0 or after=1 a graphic: */
163 /* within counts as after too */
165 unsigned int ignoreNewLine
:1;/* turn it into a ' ' when typed */
166 unsigned int laidOut
:1; /* have the TextBlocks all been laid out */
167 unsigned int prepend
:1; /* prepend=1, append=0 (for parsers) */
168 WMAlignment alignment
:2; /* the alignment for text */
169 WMReliefType relief
:3; /* the relief to display with */
170 unsigned int RESERVED
:4;
171 unsigned int nmargins
:10; /* the number of margin arrays */
175 static char *default_bullet
[] = {
177 " c None s None", ". c black",
178 "X c white", "o c #808080",
188 paintText(Text
*tPtr
)
190 TextBlock
*tb
= tPtr
->firstTextBlock
;
194 int len
, y
, c
, s
, done
=False
;
196 WMScreen
*scr
= tPtr
->view
->screen
;
197 Display
*dpy
= tPtr
->view
->screen
->display
;
198 Window win
= tPtr
->view
->window
;
201 if (!tPtr
->view
->flags
.realized
|| !tPtr
->db
|| tPtr
->flags
.frozen
)
204 XFillRectangle(dpy
, tPtr
->db
, tPtr
->bgGC
,
205 0, 0, WMWidgetWidth(tPtr
), WMWidgetWidth(tPtr
));
206 //tPtr->visible.w, tPtr->visible.h);
208 tb
= tPtr
->firstTextBlock
;
213 if (tPtr
->flags
.ownsSelection
) {
214 greyGC
= WMColorGC(WMGrayColor(scr
));
215 //XFillRectangle(dpy, tPtr->db, greyGC,
216 // tPtr->sel.x, tPtr->sel.y-tPtr->vpos, tPtr->sel.w, tPtr->sel.h);
217 // XDrawRectangle(dpy, tPtr->db, tPtr->fgGC,
218 // tPtr->sel.x, tPtr->sel.y-tPtr->vpos, tPtr->sel.w, tPtr->sel.h);
222 while (!done
&& tb
) {
229 for(s
=0; s
<tb
->nsections
&& !done
; s
++) {
232 if (tb
->sections
[s
]._y
> tPtr
->vpos
+ tPtr
->visible
.h
) {
237 if ( tb
->sections
[s
].y
+ tb
->sections
[s
].h
< tPtr
->vpos
)
240 if (tPtr
->flags
.monoFont
) {
245 gc
= WMColorGC(tb
->color
);
248 if (tPtr
->flags
.ownsSelection
) {
250 if (prev_y
!= tb
->sections
[s
]._y
251 && (tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
252 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
253 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)) {
254 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
256 tPtr
->visible
.y
+ tb
->sections
[s
]._y
- tPtr
->vpos
,
257 tPtr
->visible
.w
, tb
->sections
[s
].h
);
259 } else if ( prev_y
!= tb
->sections
[s
]._y
260 && (tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
261 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
262 >= tPtr
->visible
.y
+ tPtr
->sel
.y
)
263 && (tPtr
->sel
.x
>= tb
->sections
[s
].x
)
264 && (tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
265 >= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
)) {
266 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
268 tPtr
->visible
.y
+ tb
->sections
[s
]._y
- tPtr
->vpos
,
269 tPtr
->visible
.w
- tPtr
->sel
.x
, tb
->sections
[s
].h
);
271 } else if (prev_y
!= tb
->sections
[s
]._y
272 && (tb
->sections
[s
]._y
<= tPtr
->sel
.y
+ tPtr
->sel
.h
)
273 && (tb
->sections
[s
]._y
>= tPtr
->sel
.y
)) {
274 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
276 tPtr
->visible
.y
+ tb
->sections
[s
]._y
- tPtr
->vpos
,
277 tPtr
->sel
.x
+ tPtr
->sel
.w
-tPtr
->visible
.x
,
280 } else if ( prev_y
!= tb
->sections
[s
]._y
281 && (tb
->sections
[s
]._y
<= tPtr
->sel
.y
)
282 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
283 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
284 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
286 tPtr
->visible
.y
+ tb
->sections
[s
]._y
- tPtr
->vpos
,
287 tPtr
->sel
.w
,tb
->sections
[s
].h
);
292 prev_y
= tb
->sections
[s
]._y
;
294 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
295 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
296 y
= tb
->sections
[s
].y
- tPtr
->vpos
;
297 WMDrawString(scr
, tPtr
->db
, gc
, font
,
298 tb
->sections
[s
].x
, y
, text
, len
);
300 if (tb
->underlined
) {
301 XDrawLine(dpy
, tPtr
->db
, gc
,
302 tb
->sections
[s
].x
, y
+ font
->y
+ 1,
303 tb
->sections
[s
].x
+ tb
->sections
[s
].w
, y
+ font
->y
+ 1);
308 tb
= (!done
? tb
->next
: NULL
);
312 c
= WMGetBagItemCount(tPtr
->gfxItems
);
313 if (c
> 0 && !tPtr
->flags
.monoFont
) {
317 tb
= (TextBlock
*) WMGetFromBag(tPtr
->gfxItems
, j
);
319 if (tb
->sections
[0]._y
+ tb
->sections
[0].h
<= tPtr
->vpos
320 || tb
->sections
[0]._y
>= tPtr
->vpos
+ tPtr
->visible
.h
) {
322 if ((W_VIEW(wdt
))->flags
.mapped
) {
326 if (!(W_VIEW(wdt
))->flags
.mapped
) {
328 //WMLowerWidget(wdt);
331 if (tPtr
->flags
.ownsSelection
&& 0
332 //&& (tb->sections[s]._y >= tPtr->sel.y)
333 //&& (tb->sections[s]._y + tb->sections[s].h
334 ){ // <= tPtr->sel.y + tPtr->sel.h)) {
335 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
336 tb
->sections
[0].x
, tb
->sections
[0].y
- tPtr
->vpos
,
337 tb
->sections
[0].w
, tb
->sections
[0].h
);
340 WMMoveWidget(wdt
, 3 + tb
->sections
[0].x
+ tPtr
->visible
.x
,
341 tb
->sections
[0].y
- tPtr
->vpos
);
343 if (tb
->underlined
) {
344 XDrawLine(dpy
, tPtr
->db
, WMColorGC(tb
->color
),
346 tb
->sections
[0].y
+ WMWidgetHeight(wdt
) + 1,
347 tb
->sections
[0].x
+ tb
->sections
[0].w
,
348 tb
->sections
[0].y
+ WMWidgetHeight(wdt
) + 1);
354 if (tPtr
->flags
.editable
&& tPtr
->flags
.cursorShown
355 && tPtr
->cursor
.x
!= -23 && tPtr
->flags
.focused
) {
356 int y
= tPtr
->cursor
.y
- tPtr
->vpos
;
357 XDrawLine(dpy
, tPtr
->db
, tPtr
->fgGC
,
359 tPtr
->cursor
.x
, y
+ tPtr
->cursor
.h
);
361 //printf("%d %d %d\n", tPtr->cursor.x, tPtr->cursor.y, tPtr->cursor.h);
364 XCopyArea(dpy
, tPtr
->db
, win
, tPtr
->bgGC
,
366 tPtr
->visible
.w
, tPtr
->visible
.h
,
367 tPtr
->visible
.x
, tPtr
->visible
.y
);
369 W_DrawRelief(scr
, win
, 0, 0,
370 tPtr
->view
->size
.width
, tPtr
->view
->size
.height
,
373 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)
376 tPtr
->view
->size
.width
-4, 42);
383 #define CURSOR_BLINK_ON_DELAY 600
384 #define CURSOR_BLINK_OFF_DELAY 400
387 blinkCursor(void *data
)
389 Text
*tPtr
= (Text
*)data
;
391 if (tPtr
->flags
.cursorShown
) {
392 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY
,
395 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
,
399 tPtr
->flags
.cursorShown
= !tPtr
->flags
.cursorShown
;
404 getFirstNonGraphicBlockFor(TextBlock
*tb
, short dir
)
411 tb
= (dir
? tb
->next
: tb
->prior
);
419 cursorToTextPosition(Text
*tPtr
, int x
, int y
)
421 TextBlock
*tb
= NULL
;
422 int done
=False
, s
, pos
, len
, _w
, _y
, dir
=1; /* 1 == "down" */
425 y
+= (tPtr
->vpos
- tPtr
->visible
.y
);
429 x
-= (tPtr
->visible
.x
- 2);
433 /* clicked is relative to document, not window... */
437 if (! (tb
= tPtr
->currentTextBlock
)) {
438 if (! (tb
= tPtr
->firstTextBlock
)) {
440 tPtr
->cursor
.h
= tPtr
->dFont
->height
;
447 /* first, which direction? Most likely, newly clicked
448 position will be close to previous */
449 dir
= !(y
< tb
->sections
[0].y
);
451 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
452 tb
= getFirstNonGraphicBlockFor(tb
, 1);
454 tPtr
->currentTextBlock
=
455 (dir
? tPtr
->lastTextBlock
: tPtr
->firstTextBlock
);
461 s
= (dir
? 0 : tb
->nsections
-1);
462 if ( y
>= tb
->sections
[s
]._y
463 && y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) {
468 /* get the first section of the TextBlock that lies about
469 the vertical click point */
471 while (!done
&& tb
) {
473 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
479 s
= (dir
? 0 : tb
->nsections
-1);
480 while (!done
&& (dir
? (s
<tb
->nsections
) : (s
>=0) )) {
482 if ( y
>= tb
->sections
[s
]._y
483 && y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) {
491 if ( (dir
? tb
->next
: tb
->prior
)) {
492 tb
= (dir
? tb
->next
: tb
->prior
);
495 break; //goto _doneH;
501 if (s
<0 || s
>=tb
->nsections
) {
502 s
= (dir
? tb
->nsections
-1 : 0);
506 /* we have the line, which TextBlock on that line is it? */
508 if (tPtr
->flags
.monoFont
&& tb
->graphic
)
509 tb
= getFirstNonGraphicBlockFor(tb
, dir
);
511 if ((dir
? tb
->sections
[s
].x
>= x
: tb
->sections
[s
].x
< x
))
513 _y
= tb
->sections
[s
]._y
;
518 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
519 tb
= (dir
? tb
->next
: tb
->prior
);
525 _w
= WMWidgetWidth(tb
->d
.widget
);
527 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
528 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
529 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
530 if (tb
->sections
[s
].x
+ _w
>= x
)
535 if (tb
->sections
[s
].x
<= x
)
540 if ((dir
? tb
->next
: tb
->prior
)) {
541 TextBlock
*nxt
= (dir
? tb
->next
: tb
->prior
);
542 if (tPtr
->flags
.monoFont
&& nxt
->graphic
) {
543 nxt
= getFirstNonGraphicBlockFor(nxt
, dir
);
549 if (_y
!= nxt
->sections
[s
]._y
) {
550 /* this must be the last/first on this line. stop */
551 pos
= (dir
? tb
->used
: 0);
557 if ( (dir
? tb
->next
: tb
->prior
)) {
558 tb
= (dir
? tb
->next
: tb
->prior
);
565 s
= (dir
? 0 : tb
->nsections
-1);
568 /* we have said TextBlock, now where within it? */
569 if (tb
&& !tb
->graphic
) {
570 WMFont
*f
= tb
->d
.font
;
571 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
572 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
574 _w
= x
- tb
->sections
[s
].x
;
577 while (pos
<len
&& WMWidthOfString(f
, text
, pos
+1) < _w
)
580 tPtr
->cursor
.x
= tb
->sections
[s
].x
+
581 (pos
? WMWidthOfString(f
, text
, pos
) : 0);
582 pos
+= tb
->sections
[s
].begin
;
583 tPtr
->tpos
= (pos
<tb
->used
)? pos
: tb
->used
;
586 tPtr
->currentTextBlock
= tb
;
587 tPtr
->cursor
.h
= tb
->sections
[s
].h
;
588 tPtr
->cursor
.y
= tb
->sections
[s
]._y
;
592 printf("will hang :-)\n");
597 updateScrollers(Text
*tPtr
)
600 if (tPtr
->flags
.frozen
)
604 if (tPtr
->docHeight
< tPtr
->visible
.h
) {
605 WMSetScrollerParameters(tPtr
->vS
, 0, 1);
608 float vmax
= (float)(tPtr
->docHeight
);
609 WMSetScrollerParameters(tPtr
->vS
,
610 ((float)tPtr
->vpos
)/(vmax
- (float)tPtr
->visible
.h
),
611 (float)tPtr
->visible
.h
/vmax
);
613 } else tPtr
->vpos
= 0;
620 scrollersCallBack(WMWidget
*w
, void *self
)
622 Text
*tPtr
= (Text
*)self
;
627 if (!tPtr
->view
->flags
.realized
|| tPtr
->flags
.frozen
)
633 vmax
= (float)(tPtr
->docHeight
);
634 height
= tPtr
->visible
.h
;
636 which
= WMGetScrollerHitPart(tPtr
->vS
);
638 case WSDecrementLine
:
639 if (tPtr
->vpos
> 0) {
640 if (tPtr
->vpos
>16) tPtr
->vpos
-=16;
644 case WSIncrementLine
: {
645 int limit
= tPtr
->docHeight
- height
;
646 if (tPtr
->vpos
< limit
) {
647 if (tPtr
->vpos
<limit
-16) tPtr
->vpos
+=16;
648 else tPtr
->vpos
=limit
;
651 case WSDecrementPage
:
652 tPtr
->vpos
-= height
;
658 printf("dimple needs to jump to mouse location ;-/\n");
660 case WSIncrementPage
:
661 tPtr
->vpos
+= height
;
662 if (tPtr
->vpos
> (tPtr
->docHeight
- height
))
663 tPtr
->vpos
= tPtr
->docHeight
- height
;
666 printf("dimple needs to jump to mouse location ;-/\n");
671 tPtr
->vpos
= WMGetScrollerValue(tPtr
->vS
)
672 * (float)(tPtr
->docHeight
- height
);
678 printf("WSNoPart, WSKnobSlot\n");
680 float vmax
= (float)(tPtr
->docHeight
);
681 ((float)tPtr
->vpos
)/(vmax
- (float)tPtr
->visible
.h
),
682 (float)tPtr
->visible
.h
/vmax
;
683 dimple
=where mouse is
.
687 scroll
= (tPtr
->vpos
!= tPtr
->prevVpos
);
688 tPtr
->prevVpos
= tPtr
->vpos
;
697 if (tPtr->rulerShown)
698 XClearArea(tPtr->view->screen->display, tPtr->view->window, 22, 47,
699 tPtr->view->size.width-24, tPtr->view->size.height-49, True);
701 XClearArea(tPtr->view->screen->display, tPtr->view->window, 22, 2,
702 tPtr->view->size.width-24, tPtr->view->size.height-4, True);
705 if (which
== WSDecrementLine
|| which
== WSIncrementLine
)
706 updateScrollers(tPtr
);
715 unsigned short begin
, end
; /* what part of the text block */
721 layOutLine(Text
*tPtr
, myLineItems
*items
, int nitems
, int x
, int y
,
724 int i
, j
=0, lw
= 0, line_height
=0, max_d
=0, len
, n
;
729 TextBlock
*tbsame
=NULL
;
731 for(i
=0; i
<nitems
; i
++) {
735 if (!tPtr
->flags
.monoFont
) {
736 WMWidget
*wdt
= tb
->d
.widget
;
737 line_height
= WMAX(line_height
, WMWidgetHeight(wdt
));
738 if (tPtr
->flags
.alignment
!= WALeft
)
739 lw
+= WMWidgetWidth(wdt
);
744 font
= (tPtr
->flags
.monoFont
)?tPtr
->dFont
: tb
->d
.font
;
745 max_d
= WMAX(max_d
, font
->height
-font
->y
);
746 line_height
= WMAX(line_height
, font
->height
);
747 text
= &(tb
->text
[items
[i
].begin
]);
748 len
= items
[i
].end
- items
[i
].begin
;
749 if (tPtr
->flags
.alignment
!= WALeft
)
750 lw
+= WMWidthOfString(font
, text
, len
);
754 if (tPtr
->flags
.alignment
== WARight
) {
756 } else if (tPtr
->flags
.alignment
== WACenter
) {
757 j
= (int) ((float)(pwidth
- lw
))/2.0;
762 for(i
=0; i
<nitems
; i
++) {
765 if (tbsame
== tb
) { /*extend it, since it's on same line */
766 tb
->sections
[tb
->nsections
-1].end
= items
[i
].end
;
769 tb
->sections
= wrealloc(tb
->sections
,
770 (++tb
->nsections
)*sizeof(Section
));
772 tb
->sections
[n
]._y
= y
;
773 tb
->sections
[n
].x
= x
+j
;
774 tb
->sections
[n
].h
= line_height
;
775 tb
->sections
[n
].begin
= items
[i
].begin
;
776 tb
->sections
[n
].end
= items
[i
].end
;
779 if (!tPtr
->flags
.monoFont
) {
780 WMWidget
*wdt
= tb
->d
.widget
;
781 tb
->sections
[n
].y
= 1 + max_d
+
782 y
+ line_height
- WMWidgetHeight(wdt
);
783 tb
->sections
[n
].w
= WMWidgetWidth(wdt
);
784 x
+= tb
->sections
[n
].w
;
787 font
= (tPtr
->flags
.monoFont
)? tPtr
->dFont
: tb
->d
.font
;
788 len
= items
[i
].end
- items
[i
].begin
;
789 text
= &(tb
->text
[items
[i
].begin
]);
791 tb
->sections
[n
].y
= y
+line_height
-font
->y
;
793 WMWidthOfString(font
,
794 &(tb
->text
[tb
->sections
[n
].begin
]),
795 tb
->sections
[n
].end
- tb
->sections
[n
].begin
);
797 x
+= WMWidthOfString(font
, text
, len
);
803 return line_height
+(gfx
?10:0);
809 output(char *ptr
, int len
)
814 //printf(" s is [%s] (%d)\n", s, strlen(s));
819 /* tb->text doesn't necessarily end in '\0' hmph! (strchr) */
821 mystrchr(char *s
, char needle
, unsigned short len
)
825 if (!haystack
|| len
< 1)
828 while ( (int) (haystack
- s
) < len
) {
829 if (*haystack
== needle
)
836 #define MAX_TB_PER_LINE 64
839 layOutDocument(Text
*tPtr
)
842 myLineItems items
[MAX_TB_PER_LINE
];
844 Bool lhc
= !tPtr
->flags
.laidOut
; /* line height changed? */
847 int nitems
=0, x
=0, y
=0, lw
= 0, width
=0;
848 int pwidth
= tPtr
->visible
.w
- tPtr
->visible
.x
;
850 char *start
=NULL
, *mark
=NULL
;
853 if (tPtr
->flags
.frozen
)
856 if (!(tb
= tPtr
->firstTextBlock
))
859 if (0&&tPtr
->flags
.laidOut
) {
860 tb
= tPtr
->currentTextBlock
;
861 if (tb
->sections
&& tb
->nsections
>0)
862 prev_y
= tb
->sections
[tb
->nsections
-1]._y
;
864 printf("1 prev_y %d \n", prev_y
);
866 /* search backwards for textblocks on same line */
868 if (!tb
->sections
|| tb
->nsections
<1) {
869 tb
= tPtr
->firstTextBlock
;
872 if (tb
->sections
[tb
->nsections
-1]._y
!= prev_y
) {
876 // prev_y = tb->sections[tb->nsections-1]._y;
879 y
= 0;//tb->sections[tb->nsections-1]._y;
880 printf("2 prev_y %d \n\n", tb
->sections
[tb
->nsections
-1]._y
);
886 if (tb
->sections
&& tb
->nsections
>0) {
893 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
, pwidth
);
894 x
= 0;//tPtr->visible.x+2;
900 if (!tPtr
->flags
.monoFont
) {
901 width
= WMWidgetWidth(tb
->d
.widget
);
902 if (width
> pwidth
)printf("rescale graphix to fit?\n");
905 || nitems
>= MAX_TB_PER_LINE
) {
906 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
, pwidth
);
908 x
= 0;//tPtr->visible.x+2;
912 items
[nitems
].tb
= tb
;
913 items
[nitems
].begin
= 0;
914 items
[nitems
].end
= 0;
918 } else if ((start
= tb
->text
)) {
920 font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
923 mark
= mystrchr(start
, ' ', tb
->used
);
925 end
+= (int)(mark
-start
)+1;
928 end
+= strlen(start
);
937 width
= WMWidthOfString(font
,
938 &tb
->text
[begin
], end
-begin
);
940 if (width
> pwidth
) { /* break this tb up */
941 char *t
= &tb
->text
[begin
];
942 int l
=end
-begin
, i
=0;
944 width
= WMWidthOfString(font
, t
, ++i
);
945 } while (width
< pwidth
&& i
< l
);
947 if (start
) // and since (nil)-4 = 0xfffffffd
954 if ((lw
>= pwidth
- x
)
955 || nitems
>= MAX_TB_PER_LINE
) {
956 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
, pwidth
);
958 x
= 0; //tPtr->visible.x+2;
962 items
[nitems
].tb
= tb
;
963 items
[nitems
].begin
= begin
;
964 items
[nitems
].end
= end
;
975 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
, pwidth
);
977 tPtr
->docHeight
= y
+10;
978 updateScrollers(tPtr
);
980 tPtr
->flags
.laidOut
= True
;
986 textDidResize(W_ViewDelegate
*self
, WMView
*view
)
988 Text
*tPtr
= (Text
*)view
->self
;
989 unsigned short w
= WMWidgetWidth(tPtr
);
990 unsigned short h
= WMWidgetHeight(tPtr
);
991 unsigned short rh
= 0, vw
= 0;
993 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
) {
994 WMMoveWidget(tPtr
->ruler
, 2, 2);
995 WMResizeWidget(tPtr
->ruler
, w
- 4, 40);
1000 WMMoveWidget(tPtr
->vS
, 1, rh
+ 2);
1001 WMResizeWidget(tPtr
->vS
, 20, h
- rh
- 3);
1003 WMSetRulerOffset(tPtr
->ruler
,22);
1004 } else WMSetRulerOffset(tPtr
->ruler
, 2);
1008 WMMoveWidget(tPtr
->hS
, vw
, h
- 21);
1009 WMResizeWidget(tPtr
->hS
, w
- vw
- 1, 20);
1011 WMMoveWidget(tPtr
->hS
, vw
+1, h
- 21);
1012 WMResizeWidget(tPtr
->hS
, w
- vw
- 2, 20);
1016 tPtr
->visible
.x
= (tPtr
->vS
)?22:2;
1017 tPtr
->visible
.y
= (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)?43:3;
1018 tPtr
->visible
.w
= tPtr
->view
->size
.width
- tPtr
->visible
.x
- 12;
1019 tPtr
->visible
.h
= tPtr
->view
->size
.height
- tPtr
->visible
.y
;
1020 tPtr
->visible
.h
-= (tPtr
->hS
)?20:0;
1022 tPtr
->margins
[0].left
= tPtr
->margins
[0].right
= tPtr
->visible
.x
;
1023 tPtr
->margins
[0].body
= tPtr
->visible
.x
;
1024 tPtr
->margins
[0].right
= tPtr
->visible
.w
;
1027 if (tPtr
->view
->flags
.realized
) {
1030 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
1031 tPtr
->db
= (Pixmap
) NULL
;
1034 if (tPtr
->visible
.w
< 10) tPtr
->visible
.w
= 10;
1035 if (tPtr
->visible
.h
< 10) tPtr
->visible
.h
= 10;
1037 //if (size change or !db
1039 tPtr
->db
= XCreatePixmap(tPtr
->view
->screen
->display
,
1040 tPtr
->view
->window
, tPtr
->visible
.w
,
1041 tPtr
->visible
.h
, tPtr
->view
->screen
->depth
);
1045 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1048 W_ViewDelegate _TextViewDelegate
=
1056 /* nice, divisble-by-16 blocks */
1057 static inline unsigned short
1058 reqBlockSize(unsigned short requested
)
1060 return requested
+ 16 - (requested
%16);
1065 clearText(Text
*tPtr
)
1067 if (!tPtr
->firstTextBlock
)
1070 while (tPtr
->currentTextBlock
)
1071 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1073 tPtr
->firstTextBlock
= NULL
;
1074 tPtr
->currentTextBlock
= NULL
;
1075 tPtr
->lastTextBlock
= NULL
;
1079 deleteTextInteractively(Text
*tPtr
, KeySym ksym
)
1081 TextBlock
*tb
= tPtr
->currentTextBlock
;
1086 if (ksym
== XK_BackSpace
) {
1087 if ( (tb
->used
> 0) && (tPtr
->tpos
> 0)
1088 && (tPtr
->tpos
<= tb
->used
) && !tb
->graphic
) {
1090 memmove(&(tb
->text
[tPtr
->tpos
]),
1091 &(tb
->text
[tPtr
->tpos
+ 1]), tb
->used
- tPtr
->tpos
);
1095 if (tPtr
->tpos
< 1) {
1096 TextBlock
*prior
= tb
->prior
;
1098 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1099 if (prior
|| !tPtr
->currentTextBlock
) {
1100 tPtr
->currentTextBlock
= prior
;
1101 if(tPtr
->currentTextBlock
)
1102 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
1103 } else tPtr
->tpos
= 0;
1111 } else if (!back
&& tb
->next
) {
1112 TextBlock
*next
= tb
->next
;
1113 tPtr
->currentTextBlock
= next
;
1125 insertTextInteractively(Text
*tPtr
, char *text
, int len
)
1128 char *newline
= NULL
;
1130 if (!tPtr
->flags
.editable
|| len
< 1 || !text
)
1133 if(tPtr
->flags
.ignoreNewLine
&& *text
== '\n' && len
== 1)
1136 if (tPtr
->flags
.ignoreNewLine
) {
1138 for(i
=0; i
<len
; i
++) {
1139 if (text
[i
] == '\n')
1144 tb
= tPtr
->currentTextBlock
;
1145 if (!tb
|| tb
->graphic
) {
1147 WMAppendTextStream(tPtr
, text
);
1148 if (tPtr
->currentTextBlock
) {
1149 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
1154 if ((newline
= strchr(text
, '\n'))) {
1155 int nlen
= (int)(newline
-text
);
1156 int s
= tb
->used
- tPtr
->tpos
;
1159 if (!tb
->blank
&& (1||nlen
>0 )) {
1161 memcpy(save
, &tb
->text
[tPtr
->tpos
], s
);
1162 tb
->used
-= (tb
->used
- tPtr
->tpos
);
1165 insertTextInteractively(tPtr
, text
, nlen
);
1167 WMAppendTextStream(tPtr
, newline
);
1169 insertTextInteractively(tPtr
, save
, s
);
1172 WMAppendTextStream(tPtr
, text
);
1174 printf("split me\n");
1180 if (tb
->used
+ len
>= tb
->allocated
) {
1181 tb
->allocated
= reqBlockSize(tb
->used
+len
);
1182 tb
->text
= wrealloc(tb
->text
, tb
->allocated
);
1186 memcpy(tb
->text
, text
, len
);
1191 memmove(&(tb
->text
[tPtr
->tpos
+len
]), &tb
->text
[tPtr
->tpos
],
1192 tb
->used
-tPtr
->tpos
+1);
1193 memmove(&tb
->text
[tPtr
->tpos
], text
, len
);
1203 selectRegion(Text
*tPtr
, int x
, int y
)
1207 y
+= (tPtr
->flags
.rulerShown
? 40: 0);
1209 if (y
>10) y
-= 10; /* the original offset */
1211 x
-= tPtr
->visible
.x
-2;
1214 tPtr
->sel
.x
= WMAX(0, WMIN(tPtr
->clicked
.x
, x
));
1215 tPtr
->sel
.w
= abs(tPtr
->clicked
.x
- x
);
1216 tPtr
->sel
.y
= WMAX(0, WMIN(tPtr
->clicked
.y
, y
));
1217 tPtr
->sel
.h
= abs(tPtr
->clicked
.y
- y
);
1219 tPtr
->flags
.ownsSelection
= True
;
1225 pasteText(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
1226 void *cdata
, WMData
*data
)
1228 Text
*tPtr
= (Text
*)view
->self
;
1231 tPtr
->flags
.waitingForSelection
= False
;
1234 str
= (char*)WMDataBytes(data
);
1236 (tPtr
->parser
) (tPtr
, (void *) str
);
1238 insertTextInteractively(tPtr
, str
, strlen(str
));
1240 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1243 str
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
1247 (tPtr
->parser
) (tPtr
, (void *) str
);
1249 insertTextInteractively(tPtr
, str
, n
);
1251 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1258 releaseSelection(Text
*tPtr
)
1260 tPtr
->flags
.ownsSelection
= False
;
1265 requestHandler(WMView
*view
, Atom selection
, Atom target
,
1266 void *cdata
, Atom
*type
)
1268 Text
*tPtr
= view
->self
;
1269 Display
*dpy
= tPtr
->view
->screen
->display
;
1270 Atom TEXT
= XInternAtom(dpy
, "TEXT", False
);
1271 Atom COMPOUND_TEXT
= XInternAtom(dpy
, "COMPOUND_TEXT", False
);
1274 if (target
== XA_STRING
|| target
== TEXT
|| target
== COMPOUND_TEXT
) {
1275 char *text
= WMGetTextSelected(tPtr
);
1276 WMData
*data
= WMCreateDataWithBytes(text
, strlen(text
));
1280 Atom PIXMAP
= XInternAtom(dpy
, "PIXMAP", False
);
1281 WMData
*data
= WMCreateDataWithBytes("bleh", 4);
1282 if(target
== PIXMAP
) {
1283 printf("whoa! pixmap WMGetTextSelectedObjects\n");
1293 lostHandler(WMView
*view
, Atom selection
, void *cdata
)
1295 releaseSelection((WMText
*)view
->self
);
1298 static WMSelectionProcs selectionHandler
= {
1299 requestHandler
, lostHandler
, NULL
1303 ownershipObserver(void *observerData
, WMNotification
*notification
)
1305 WMText
*to
= (WMText
*)observerData
;
1306 WMText
*tw
= (WMText
*)WMGetNotificationClientData(notification
);
1308 lostHandler(to
->view
, XA_PRIMARY
, NULL
);
1313 handleTextKeyPress(Text
*tPtr
, XEvent
*event
)
1317 int control_pressed
= False
;
1320 if (((XKeyEvent
*) event
)->state
& ControlMask
)
1321 control_pressed
= True
;
1322 buffer
[XLookupString(&event
->xkey
, buffer
, 1, &ksym
, NULL
)] = 0;
1329 printf("arrows %ld\n", ksym
);
1335 deleteTextInteractively(tPtr
, ksym
);
1336 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1341 control_pressed
= True
;
1347 if (buffer
[0] != 0 && !control_pressed
) {
1348 insertTextInteractively(tPtr
, buffer
, 1);
1349 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1351 } else if (control_pressed
&& ksym
==XK_r
) {
1352 Bool i
= !tPtr
->flags
.rulerShown
;
1353 WMShowTextRuler(tPtr
, i
);
1354 tPtr
->flags
.rulerShown
= i
;
1356 else if (control_pressed
&& buffer
[0] == '\a')
1357 XBell(tPtr
->view
->screen
->display
, 0);
1360 if (!control_pressed
&& tPtr
->flags
.ownsSelection
)
1361 releaseSelection(tPtr
);
1365 handleWidgetPress(XEvent
*event
, void *data
)
1367 TextBlock
*tb
= (TextBlock
*)data
;
1373 /* this little bit of nastiness here saves a boatload of trouble */
1374 w
= (WMWidget
*)(((W_VIEW(tb
->d
.widget
))->parent
)->self
);
1375 if (W_CLASS(w
) != WC_Text
)
1378 tPtr
->currentTextBlock
= getFirstNonGraphicBlockFor(tb
, 1);
1379 if (!tPtr
->currentTextBlock
)
1380 tPtr
->currentTextBlock
= tb
;
1382 output(tPtr
->currentTextBlock
->text
, tPtr
->currentTextBlock
->used
);
1383 //if (!tPtr->flags.focused) {
1384 // WMSetFocusToWidget(tPtr);
1385 // tPtr->flags.focused = True;
1391 handleActionEvents(XEvent
*event
, void *data
)
1393 Text
*tPtr
= (Text
*)data
;
1394 Display
*dpy
= event
->xany
.display
;
1398 switch (event
->type
) {
1400 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
1401 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
1402 tPtr
->flags
.extendSelection
= True
;
1405 if (!tPtr
->flags
.editable
|| tPtr
->flags
.buttonHeld
) {
1410 if (tPtr
->flags
.waitingForSelection
)
1412 if (tPtr
->flags
.focused
) {
1413 XGrabPointer(dpy
, W_VIEW(tPtr
)->window
, False
,
1414 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
1415 GrabModeAsync
, GrabModeAsync
, None
,
1416 tPtr
->view
->screen
->invisibleCursor
, CurrentTime
);
1417 tPtr
->flags
.pointerGrabbed
= True
;
1418 handleTextKeyPress(tPtr
, event
);
1423 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
1424 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
1425 tPtr
->flags
.extendSelection
= False
;
1427 //end modify flag so selection can be extended
1433 if (tPtr
->flags
.pointerGrabbed
) {
1434 tPtr
->flags
.pointerGrabbed
= False
;
1435 XUngrabPointer(dpy
, CurrentTime
);
1437 if ((event
->xmotion
.state
& Button1Mask
)) {
1438 if (!tPtr
->flags
.ownsSelection
) {
1439 WMCreateSelectionHandler(tPtr
->view
, XA_PRIMARY
,
1440 event
->xbutton
.time
, &selectionHandler
, NULL
);
1441 tPtr
->flags
.ownsSelection
= True
;
1443 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
1449 tPtr
->flags
.buttonHeld
= True
;
1450 if (tPtr
->flags
.extendSelection
) {
1451 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
1454 if (event
->xbutton
.button
== Button1
) {
1456 if (!tPtr
->flags
.focused
) {
1457 WMSetFocusToWidget(tPtr
);
1458 tPtr
->flags
.focused
= True
;
1461 if (tPtr
->flags
.ownsSelection
)
1462 releaseSelection(tPtr
);
1463 cursorToTextPosition(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
1465 if (tPtr
->flags
.pointerGrabbed
) {
1466 tPtr
->flags
.pointerGrabbed
= False
;
1467 XUngrabPointer(dpy
, CurrentTime
);
1472 if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelDown
)
1473 WMScrollText(tPtr
, -16);
1474 else if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelUp
)
1475 WMScrollText(tPtr
, 16);
1479 tPtr
->flags
.buttonHeld
= False
;
1480 if (tPtr
->flags
.pointerGrabbed
) {
1481 tPtr
->flags
.pointerGrabbed
= False
;
1482 XUngrabPointer(dpy
, CurrentTime
);
1485 if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelDown
1486 || event
->xbutton
.button
== WINGsConfiguration
.mouseWheelUp
)
1489 if (event
->xbutton
.button
== Button2
&& tPtr
->flags
.editable
) {
1492 if (!WMRequestSelection(tPtr
->view
, XA_PRIMARY
, XA_STRING
,
1493 event
->xbutton
.time
, pasteText
, NULL
)) {
1494 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
1498 (tPtr
->parser
) (tPtr
, (void *) text
);
1500 insertTextInteractively(tPtr
, text
, n
-1);
1502 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1504 } else tPtr
->flags
.waitingForSelection
= True
;
1515 handleEvents(XEvent
*event
, void *data
)
1517 Text
*tPtr
= (Text
*)data
;
1519 switch(event
->type
) {
1522 tPtr
->db
= XCreatePixmap(tPtr
->view
->screen
->display
,
1523 tPtr
->view
->window
, tPtr
->visible
.w
,
1524 tPtr
->visible
.h
, tPtr
->view
->screen
->depth
);
1527 if (!((W_VIEW(tPtr
->hS
))->flags
.mapped
)) {
1528 WMRealizeWidget(tPtr
->hS
);
1529 WMMapWidget(tPtr
->hS
);
1533 if (!((W_VIEW(tPtr
->vS
))->flags
.mapped
)) {
1534 WMRealizeWidget(tPtr
->vS
);
1535 WMMapWidget(tPtr
->vS
);
1538 if (!event
->xexpose
.count
&& tPtr
->view
->flags
.realized
)
1543 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))
1546 tPtr
->flags
.focused
= True
;
1548 if (tPtr
->flags
.editable
&& !tPtr
->timerID
) {
1549 tPtr
->timerID
= WMAddTimerHandler(12+0*CURSOR_BLINK_ON_DELAY
,
1557 tPtr
->flags
.focused
= False
;
1560 if (tPtr
->timerID
) {
1561 WMDeleteTimerHandler(tPtr
->timerID
);
1562 tPtr
->timerID
= NULL
;
1569 //for(...)WMRemoveTextParagraph(tPtr, para);
1579 insertPlainText(WMText
*tPtr
, char *text
)
1591 mark
= strchr(start
, '\n');
1593 tb
= WMCreateTextBlockWithText(start
, tPtr
->dFont
,
1594 tPtr
->dColor
, True
, (int)(mark
-start
));
1597 if (start
&& strlen(start
)) {
1598 tb
= WMCreateTextBlockWithText(start
, tPtr
->dFont
,
1599 tPtr
->dColor
, False
, strlen(start
));
1604 if (tPtr
->flags
.prepend
)
1605 WMPrependTextBlock(tPtr
, tb
);
1607 WMAppendTextBlock(tPtr
, tb
);
1615 rulerMoveCallBack(WMWidget
*w
, void *self
)
1617 Text
*tPtr
= (Text
*)self
;
1620 if (W_CLASS(tPtr
) != WC_Text
)
1628 rulerReleaseCallBack(WMWidget
*w
, void *self
)
1630 Text
*tPtr
= (Text
*)self
;
1633 if (W_CLASS(tPtr
) != WC_Text
)
1636 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1643 draggingEntered(WMView
*self
, WMDraggingInfo
*info
)
1645 printf("draggingEntered\n");
1646 return WDOperationCopy
;
1651 draggingUpdated(WMView
*self
, WMDraggingInfo
*info
)
1653 printf("draggingUpdated\n");
1654 return WDOperationCopy
;
1659 draggingExited(WMView
*self
, WMDraggingInfo
*info
)
1661 printf("draggingExited\n");
1665 prepareForDragOperation(WMView
*self
, WMDraggingInfo
*info
)
1667 printf("draggingExited\n");
1668 return;//"bll"; //"application/X-color";
1673 performDragOperation(WMView
*self
, WMDraggingInfo
*info
) //, WMData *data)
1675 char *colorName
= "Blue";// (char*)WMDataBytes(data);
1677 WMText
*tPtr
= (WMText
*)self
->self
;
1682 if (tPtr
->flags
.monoFont
)
1685 color
= WMCreateNamedColor(W_VIEW_SCREEN(self
), colorName
, True
);
1686 printf("color [%s] %p\n", colorName
, color
);
1688 WMSetTextSelectionColor(tPtr
, color
);
1689 WMReleaseColor(color
);
1696 concludeDragOperation(WMView
*self
, WMDraggingInfo
*info
)
1698 printf("concludeDragOperation\n");
1702 static WMDragDestinationProcs _DragDestinationProcs
= {
1706 prepareForDragOperation
,
1707 performDragOperation
,
1708 concludeDragOperation
1714 WMCreateText(WMWidget
*parent
)
1716 Text
*tPtr
= wmalloc(sizeof(Text
));
1718 printf("could not create text widget\n");
1723 printf("sizeof:\n");
1724 printf(" TextBlock %d\n", sizeof(TextBlock
));
1725 printf(" Section %d\n", sizeof(Section
));
1726 printf(" char * %d\n", sizeof(char *));
1727 printf(" void * %d\n", sizeof(void *));
1728 printf(" short %d\n", sizeof(short));
1729 printf(" Text %d\n", sizeof(Text
));
1732 memset(tPtr
, 0, sizeof(Text
));
1733 tPtr
->widgetClass
= WC_Text
;
1734 tPtr
->view
= W_CreateView(W_VIEW(parent
));
1736 perror("could not create text's view\n");
1740 tPtr
->view
->self
= tPtr
;
1741 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->textCursor
;
1742 tPtr
->view
->attribFlags
|= CWOverrideRedirect
| CWCursor
;
1743 W_ResizeView(tPtr
->view
, 250, 200);
1744 tPtr
->bgGC
= WMColorGC(tPtr
->view
->screen
->white
);
1745 tPtr
->fgGC
= WMColorGC(tPtr
->view
->screen
->black
);
1746 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->view
->screen
->white
);
1753 //tPtr->dFont = WMCreateFont(tPtr->view->screen,
1754 // "-*-fixed-medium-r-normal--26-*-*-*-*-*-*-*");
1755 //"-sony-fixed-medium-r-normal--24-230-75-75-c-120-jisx0201.1976-0");
1756 // "-*-times-bold-r-*-*-12-*-*-*-*-*-*-*,"
1757 // "-*-fixed-medium-r-normal-*-12-*");
1759 tPtr
->dFont
= WMRetainFont(tPtr
->view
->screen
->normalFont
);
1761 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
1763 tPtr
->view
->delegate
= &_TextViewDelegate
;
1766 tPtr
->timerID
= NULL
;
1769 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
1770 |EnterWindowMask
|LeaveWindowMask
|FocusChangeMask
,
1771 handleEvents
, tPtr
);
1773 WMCreateEventHandler(tPtr
->view
, ButtonReleaseMask
|ButtonPressMask
1774 |KeyReleaseMask
|KeyPressMask
|Button1MotionMask
,
1775 handleActionEvents
, tPtr
);
1777 WMAddNotificationObserver(ownershipObserver
, tPtr
, "_lostOwnership", tPtr
);
1780 WMSetViewDragDestinationProcs(tPtr
->view
, &_DragDestinationProcs
);
1782 char *types
[2] = {"application/X-color", NULL
};
1783 WMRegisterViewForDraggedTypes(tPtr
->view
, types
);
1790 tPtr
->firstTextBlock
= NULL
;
1791 tPtr
->lastTextBlock
= NULL
;
1792 tPtr
->currentTextBlock
= NULL
;
1795 tPtr
->gfxItems
= WMCreateArrayBag(4);
1797 tPtr
->parser
= NULL
;
1798 tPtr
->writer
= NULL
;
1800 tPtr
->sel
.x
= tPtr
->sel
.y
= 2;
1801 tPtr
->sel
.w
= tPtr
->sel
.h
= 0;
1803 tPtr
->clicked
.x
= tPtr
->clicked
.y
= 2;
1805 tPtr
->visible
.x
= tPtr
->visible
.y
= 2;
1806 tPtr
->visible
.h
= tPtr
->view
->size
.height
;
1807 tPtr
->visible
.w
= tPtr
->view
->size
.width
- 12;
1809 tPtr
->cursor
.x
= -23;
1812 tPtr
->docHeight
= 0;
1813 tPtr
->dBulletPix
= WMCreatePixmapFromXPMData(tPtr
->view
->screen
,
1815 tPtr
->db
= (Pixmap
) NULL
;
1817 tPtr
->margins
= wmalloc(sizeof(WMRulerMargins
));
1818 tPtr
->margins
[0].left
= tPtr
->margins
[0].right
= tPtr
->visible
.x
;
1819 tPtr
->margins
[0].body
= tPtr
->visible
.x
;
1820 tPtr
->margins
[0].right
= tPtr
->visible
.w
;
1822 tPtr
->flags
.nmargins
= 1;
1823 tPtr
->flags
.rulerShown
= False
;
1824 tPtr
->flags
.monoFont
= False
;
1825 tPtr
->flags
.focused
= False
;
1826 tPtr
->flags
.editable
= True
;
1827 tPtr
->flags
.ownsSelection
= False
;
1828 tPtr
->flags
.pointerGrabbed
= False
;
1829 tPtr
->flags
.buttonHeld
= False
;
1830 tPtr
->flags
.waitingForSelection
= False
;
1831 tPtr
->flags
.extendSelection
= False
;
1832 tPtr
->flags
.rulerShown
= False
;
1833 tPtr
->flags
.frozen
= False
;
1834 tPtr
->flags
.cursorShown
= True
;
1835 tPtr
->flags
.clickPos
= 1;
1836 tPtr
->flags
.ignoreNewLine
= False
;
1837 tPtr
->flags
.laidOut
= False
;
1838 tPtr
->flags
.prepend
= False
;
1839 tPtr
->flags
.relief
= WRFlat
;
1840 tPtr
->flags
.alignment
= WALeft
;
1847 WMPrependTextStream(WMText
*tPtr
, char *text
)
1852 tPtr
->flags
.prepend
= True
;
1853 if (text
&& tPtr
->parser
)
1854 (tPtr
->parser
) (tPtr
, (void *) text
);
1856 insertPlainText(tPtr
, text
);
1861 WMAppendTextStream(WMText
*tPtr
, char *text
)
1866 tPtr
->flags
.prepend
= False
;
1867 if (text
&& tPtr
->parser
)
1868 (tPtr
->parser
) (tPtr
, (void *) text
);
1870 insertPlainText(tPtr
, text
);
1876 WMGetTextStream(WMText
*tPtr
)
1878 TextBlock
*tb
= NULL
;
1880 unsigned long length
= 0, where
= 0;
1885 if (!(tb
= tPtr
->firstTextBlock
))
1889 (tPtr
->writer
) (tPtr
, (void *) text
);
1893 /* first, how large a buffer would we want? */
1895 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
))
1902 text
= wmalloc(length
+1); /* +1 for the end of string, let's be nice */
1903 tb
= tPtr
->firstTextBlock
;
1906 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
))
1907 text
[where
++] = '\n';
1908 memcpy(&text
[where
], tb
->text
, tb
->used
);
1922 WMGetTextStreamObjects(WMText
*tPtr
)
1932 WMGetTextSelected(WMText
*tPtr
)
1940 //tb = tPtr->firstTextBlock;
1941 tb
= tPtr
->currentTextBlock
;
1945 text
= wmalloc(tb
->used
+1);
1946 memcpy(text
, tb
->text
, tb
->used
);
1952 WMGetTextSelectedObjects(WMText
*tPtr
)
1961 WMCreateTextBlockWithObject(WMWidget
*w
, char *description
, WMColor
*color
,
1962 unsigned short first
, unsigned short reserved
)
1965 unsigned short length
;
1967 if (!w
|| !description
|| !color
)
1970 tb
= wmalloc(sizeof(TextBlock
));
1974 length
= strlen(description
);
1975 tb
->text
= (char *)wmalloc(length
);
1976 memset(tb
->text
, 0, length
);
1977 memcpy(tb
->text
, description
, length
);
1981 tb
->color
= WMRetainColor(color
);
1987 tb
->underlined
= False
;
1989 tb
->sections
= NULL
;
1998 WMCreateTextBlockWithText(char *text
, WMFont
*font
, WMColor
*color
,
1999 unsigned short first
, unsigned short length
)
2003 if (!font
|| !color
)
2006 tb
= wmalloc(sizeof(TextBlock
));
2010 tb
->allocated
= reqBlockSize(length
);
2011 tb
->text
= (char *)wmalloc(tb
->allocated
);
2012 memset(tb
->text
, 0, tb
->allocated
);
2014 if (length
< 1|| !text
) { // || *text == '\n') {
2019 memcpy(tb
->text
, text
, length
);
2024 tb
->d
.font
= WMRetainFont(font
);
2025 tb
->color
= WMRetainColor(color
);
2029 tb
->graphic
= False
;
2030 tb
->underlined
= False
;
2032 tb
->sections
= NULL
;
2040 WMSetTextBlockProperties(void *vtb
, unsigned int first
,
2041 unsigned int kanji
, unsigned int underlined
, int script
,
2042 unsigned int marginN
)
2044 TextBlock
*tb
= (TextBlock
*) vtb
;
2050 tb
->underlined
= underlined
;
2051 tb
->script
= script
;
2052 tb
->marginN
= marginN
;
2056 WMGetTextBlockProperties(void *vtb
, unsigned int *first
,
2057 unsigned int *kanji
, unsigned int *underlined
, int *script
,
2058 unsigned int *marginN
)
2060 TextBlock
*tb
= (TextBlock
*) vtb
;
2064 if (first
) *first
= tb
->first
;
2065 if (kanji
) *kanji
= tb
->kanji
;
2066 if (underlined
) *underlined
= tb
->underlined
;
2067 if (script
) *script
= tb
->script
;
2068 if (marginN
) *marginN
= tb
->marginN
;
2074 WMPrependTextBlock(WMText
*tPtr
, void *vtb
)
2076 TextBlock
*tb
= (TextBlock
*)vtb
;
2083 WMWidget
*w
= tb
->d
.widget
;
2084 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
2085 handleWidgetPress
, tb
);
2086 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
2087 (W_VIEW(w
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
2088 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2090 WMPutInBag(tPtr
->gfxItems
, (void *)tb
);
2092 } else tPtr
->tpos
= tb
->used
;
2094 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
2095 tb
->next
= tb
->prior
= NULL
;
2096 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
2097 = tPtr
->currentTextBlock
= tb
;
2101 tb
->next
= tPtr
->currentTextBlock
;
2102 tb
->prior
= tPtr
->currentTextBlock
->prior
;
2103 if (tPtr
->currentTextBlock
->prior
)
2104 tPtr
->currentTextBlock
->prior
->next
= tb
;
2106 tPtr
->currentTextBlock
->prior
= tb
;
2108 tPtr
->firstTextBlock
= tb
;
2110 tPtr
->currentTextBlock
= tb
;
2115 WMAppendTextBlock(WMText
*tPtr
, void *vtb
)
2117 TextBlock
*tb
= (TextBlock
*)vtb
;
2123 WMWidget
*w
= tb
->d
.widget
;
2125 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
2126 handleWidgetPress
, tb
);
2127 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
2128 (W_VIEW(w
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
2129 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2131 WMPutInBag(tPtr
->gfxItems
, (void *)tb
);
2133 } else tPtr
->tpos
= tb
->used
;
2135 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
2136 tb
->next
= tb
->prior
= NULL
;
2137 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
2138 = tPtr
->currentTextBlock
= tb
;
2142 tb
->next
= tPtr
->currentTextBlock
->next
;
2143 tb
->prior
= tPtr
->currentTextBlock
;
2144 if (tPtr
->currentTextBlock
->next
)
2145 tPtr
->currentTextBlock
->next
->prior
= tb
;
2147 tPtr
->currentTextBlock
->next
= tb
;
2150 tPtr
->lastTextBlock
= tb
;
2152 tPtr
->currentTextBlock
= tb
;
2156 WMRemoveTextBlock(WMText
*tPtr
)
2158 TextBlock
*tb
= NULL
;
2160 if (!tPtr
|| !tPtr
->firstTextBlock
|| !tPtr
->lastTextBlock
2161 || !tPtr
->currentTextBlock
) {
2162 printf("cannot remove non existent TextBlock!\b");
2166 tb
= tPtr
->currentTextBlock
;
2168 WMDeleteEventHandler(W_VIEW(tb
->d
.widget
), ButtonPressMask
,
2169 handleWidgetPress
, tb
);
2170 WMRemoveFromBag(tPtr
->gfxItems
, (void *)tb
);
2171 WMUnmapWidget(tb
->d
.widget
);
2174 if (tPtr
->currentTextBlock
== tPtr
->firstTextBlock
) {
2175 if (tPtr
->currentTextBlock
->next
)
2176 tPtr
->currentTextBlock
->next
->prior
= NULL
;
2178 tPtr
->firstTextBlock
= tPtr
->currentTextBlock
->next
;
2179 tPtr
->currentTextBlock
= tPtr
->firstTextBlock
;
2181 } else if (tPtr
->currentTextBlock
== tPtr
->lastTextBlock
) {
2182 tPtr
->currentTextBlock
->prior
->next
= NULL
;
2183 tPtr
->lastTextBlock
= tPtr
->currentTextBlock
->prior
;
2184 tPtr
->currentTextBlock
= tPtr
->lastTextBlock
;
2186 tPtr
->currentTextBlock
->prior
->next
= tPtr
->currentTextBlock
->next
;
2187 tPtr
->currentTextBlock
->next
->prior
= tPtr
->currentTextBlock
->prior
;
2188 tPtr
->currentTextBlock
= tPtr
->currentTextBlock
->next
;
2195 WMDestroyTextBlock(WMText
*tPtr
, void *vtb
)
2197 TextBlock
*tb
= (TextBlock
*)vtb
;
2202 /* naturally, there's a danger to destroying
2203 widgets whose action brings us here:
2204 ie. press a button to destroy it... need to
2205 find a safer way. till then... this stays commented out */
2206 //WMDestroyWidget(tb->d.widget);
2207 //wfree(tb->d.widget);
2208 tb
->d
.widget
= NULL
;
2210 WMReleaseFont(tb
->d
.font
);
2213 WMReleaseColor(tb
->color
);
2214 if (tb
->sections
&& tb
->nsections
> 0)
2215 wfree(tb
->sections
);
2223 WMRefreshText(WMText
*tPtr
, int vpos
, int hpos
)
2227 if (!tPtr
|| vpos
<0 || hpos
<0)
2230 if (tPtr
->flags
.frozen
)
2234 tPtr
->flags
.laidOut
= False
;
2235 layOutDocument(tPtr
);
2236 updateScrollers(tPtr
);
2243 WMSetTextForegroundColor(WMText
*tPtr
, WMColor
*color
)
2249 tPtr
->fgGC
= WMColorGC(color
);
2251 tPtr
->fgGC
= WMColorGC(WMBlackColor(tPtr
->view
->screen
));
2253 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2257 WMSetTextBackgroundColor(WMText
*tPtr
, WMColor
*color
)
2263 tPtr
->bgGC
= WMColorGC(color
);
2264 W_SetViewBackgroundColor(tPtr
->view
, color
);
2266 tPtr
->bgGC
= WMColorGC(WMWhiteColor(tPtr
->view
->screen
));
2267 W_SetViewBackgroundColor(tPtr
->view
,
2268 WMWhiteColor(tPtr
->view
->screen
));
2271 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2275 WMSetTextRelief(WMText
*tPtr
, WMReliefType relief
)
2279 tPtr
->flags
.relief
= relief
;
2284 WMSetTextHasHorizontalScroller(WMText
*tPtr
, Bool shouldhave
)
2289 if (shouldhave
&& !tPtr
->hS
) {
2290 tPtr
->hS
= WMCreateScroller(tPtr
);
2291 (W_VIEW(tPtr
->hS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
2292 (W_VIEW(tPtr
->hS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2293 WMSetScrollerArrowsPosition(tPtr
->hS
, WSAMaxEnd
);
2294 WMSetScrollerAction(tPtr
->hS
, scrollersCallBack
, tPtr
);
2295 } else if (!shouldhave
&& tPtr
->hS
) {
2296 WMUnmapWidget(tPtr
->hS
);
2297 WMDestroyWidget(tPtr
->hS
);
2303 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2308 WMSetTextHasRuler(WMText
*tPtr
, Bool shouldhave
)
2313 if(shouldhave
&& !tPtr
->ruler
) {
2314 tPtr
->ruler
= WMCreateRuler(tPtr
);
2315 (W_VIEW(tPtr
->ruler
))->attribs
.cursor
=
2316 tPtr
->view
->screen
->defaultCursor
;
2317 (W_VIEW(tPtr
->ruler
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2318 WMRealizeWidget(tPtr
->ruler
);
2319 WMSetRulerReleaseAction(tPtr
->ruler
, rulerReleaseCallBack
, tPtr
);
2320 WMSetRulerMoveAction(tPtr
->ruler
, rulerMoveCallBack
, tPtr
);
2321 } else if(!shouldhave
&& tPtr
->ruler
) {
2322 WMShowTextRuler(tPtr
, False
);
2323 WMDestroyWidget(tPtr
->ruler
);
2326 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2330 WMShowTextRuler(WMText
*tPtr
, Bool show
)
2337 if(tPtr
->flags
.monoFont
)
2340 tPtr
->flags
.rulerShown
= show
;
2342 WMMapWidget(tPtr
->ruler
);
2344 WMUnmapWidget(tPtr
->ruler
);
2347 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2352 WMSetTextHasVerticalScroller(WMText
*tPtr
, Bool shouldhave
)
2357 if (shouldhave
&& !tPtr
->vS
) {
2358 tPtr
->vS
= WMCreateScroller(tPtr
);
2359 (W_VIEW(tPtr
->vS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
2360 (W_VIEW(tPtr
->vS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2361 WMSetScrollerArrowsPosition(tPtr
->vS
, WSAMaxEnd
);
2362 WMSetScrollerAction(tPtr
->vS
, scrollersCallBack
, tPtr
);
2363 } else if (!shouldhave
&& tPtr
->vS
) {
2364 WMUnmapWidget(tPtr
->vS
);
2365 WMDestroyWidget(tPtr
->vS
);
2371 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2377 WMScrollText(WMText
*tPtr
, int amount
)
2382 if (amount
== 0 || !tPtr
->view
->flags
.realized
)
2386 if (tPtr
->vpos
> 0) {
2387 if (tPtr
->vpos
> amount
) tPtr
->vpos
+= amount
;
2391 int limit
= tPtr
->docHeight
- tPtr
->visible
.h
;
2392 if (tPtr
->vpos
< limit
) {
2393 if (tPtr
->vpos
< limit
-amount
) tPtr
->vpos
+= amount
;
2394 else tPtr
->vpos
= limit
;
2398 if (scroll
&& tPtr
->vpos
!= tPtr
->prevVpos
) {
2399 updateScrollers(tPtr
);
2402 tPtr
->prevVpos
= tPtr
->vpos
;
2407 WMPageText(WMText
*tPtr
, Bool direction
)
2409 if (!tPtr
) return False
;
2410 if (!tPtr
->view
->flags
.realized
) return False
;
2412 return WMScrollText(tPtr
, direction
?tPtr
->visible
.h
:-tPtr
->visible
.h
);
2416 WMSetTextEditable(WMText
*tPtr
, Bool editable
)
2420 tPtr
->flags
.editable
= editable
;
2424 WMGetTextEditable(WMText
*tPtr
)
2428 return tPtr
->flags
.editable
;
2432 WMSetTextIgnoresNewline(WMText
*tPtr
, Bool ignore
)
2436 tPtr
->flags
.ignoreNewLine
= ignore
;
2440 WMGetTextIgnoresNewline(WMText
*tPtr
)
2444 return tPtr
->flags
.ignoreNewLine
;
2448 WMSetTextUsesMonoFont(WMText
*tPtr
, Bool mono
)
2452 if (mono
&& tPtr
->flags
.rulerShown
)
2453 ;//WMShowTextRuler(tPtr, False);
2455 tPtr
->flags
.monoFont
= mono
;
2456 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2460 WMGetTextUsesMonoFont(WMText
*tPtr
)
2464 return tPtr
->flags
.monoFont
;
2469 WMSetTextDefaultFont(WMText
*tPtr
, WMFont
*font
)
2477 tPtr
->dFont
= WMRetainFont(tPtr
->view
->screen
->normalFont
);
2481 WMGetTextDefaultFont(WMText
*tPtr
)
2490 WMSetTextAlignment(WMText
*tPtr
, WMAlignment alignment
)
2494 tPtr
->flags
.alignment
= alignment
;
2495 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2499 WMSetTextParser(WMText
*tPtr
, WMAction
*parser
)
2503 tPtr
->parser
= parser
;
2507 WMSetTextWriter(WMText
*tPtr
, WMAction
*writer
)
2511 tPtr
->writer
= writer
;
2515 WMGetTextInsertType(WMText
*tPtr
)
2519 return tPtr
->flags
.prepend
;
2524 WMSetTextSelectionColor(WMText
*tPtr
, WMColor
*color
)
2527 if (!tPtr
|| !color
)
2530 tb
= tPtr
->firstTextBlock
;
2531 if (!tb
|| !tPtr
->flags
.ownsSelection
)
2536 WMReleaseColor(tb
->color
);
2537 tb
->color
= WMRetainColor(color
);
2540 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2544 WMSetTextSelectionFont(WMText
*tPtr
, WMFont
*font
)
2550 tb
= tPtr
->firstTextBlock
;
2551 if (!tb
|| !tPtr
->flags
.ownsSelection
)
2556 tb
->d
.font
= WMRetainFont(font
);
2559 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2563 WMFreezeText(WMText
*tPtr
)
2568 tPtr
->flags
.frozen
= True
;
2572 WMThawText(WMText
*tPtr
)
2577 tPtr
->flags
.frozen
= False
;
2582 WMFindInTextStream(WMText
*tPtr
, char *needle
)
2584 char *haystack
= NULL
;
2587 if (!tPtr
|| !needle
)
2590 if ( !(haystack
= WMGetTextStream(tPtr
)))
2593 result
= (Bool
) strstr(haystack
, needle
);