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>
32 use currentTextBlock
and neighbours
for fast paint
and layout
34 WMGetTextStreamAll
... WMGetTextStream
WMGetTextSelection(if (selected
) )
44 /* a Section is a section of a TextBlock that describes what parts
45 of a TextBlock has been laid out on which "line"...
46 o this greatly aids redraw, scroll and selection.
47 o this is created during layoutLine, but may be later modified.
48 o there may be many Sections per TextBlock, hence the array */
50 int x
, y
; /* where to draw it from */
51 int w
, h
; /* it's width and height (to aid selection) */
53 unsigned short begin
, end
; /* what part of the text block */
57 /* a TextBlock is a doubly-linked list of TextBlocks containing:
58 o text for the block, color and font
59 o or a pointer to the widget and the (text) description for its graphic
62 typedef struct _TextBlock
{
63 struct _TextBlock
*next
; /* next text block in linked list */
64 struct _TextBlock
*prior
; /* prior text block in linked list */
66 char *text
; /* pointer to 8- or 16-bit text */
67 /* or to the object's description */
69 WMFont
*font
; /* the font */
70 WMWidget
*widget
; /* the embedded widget */
71 } d
; /* description */
73 WMColor
*color
; /* the color */
74 Section
*sections
; /* the region for layouts (a growable array) */
75 /* an _array_! of size _nsections_ */
78 unsigned short used
; /* number of chars in this block */
79 unsigned short allocated
; /* size of allocation (in chars) */
81 unsigned int first
:1; /* first TextBlock in paragraph */
82 unsigned int blank
:1; /* ie. blank paragraph */
83 unsigned int kanji
:1; /* is of 16-bit characters or not */
84 unsigned int graphic
:1; /* embedded object or text: text=0 */
85 unsigned int underlined
:1; /* underlined or not */
86 unsigned int nsections
:8; /* over how many "lines" a TexBlock wraps */
87 int script
:8; /* script in points: negative for subscript */
88 unsigned int marginN
:10; /* which of the margins in WMText to use */
89 unsigned int RESERVED
:1;
93 /* somehow visible.h beats the hell outta visible.size.height :-) */
102 typedef struct W_Text
{
103 W_Class widgetClass
; /* the class number of this widget */
104 W_View
*view
; /* the view referring to this instance */
106 WMRuler
*ruler
; /* the ruler subwiget to manipulate paragraphs */
108 WMScroller
*vS
; /* the vertical scroller */
109 int vpos
; /* the current vertical position */
110 int prevVpos
; /* the previous vertical position */
112 WMScroller
*hS
; /* the horizontal scroller */
113 int hpos
; /* the current horizontal position */
114 int prevHpos
; /* the previous horizontal position */
115 /* in short: tPtr->hS?nowrap:wrap */
117 WMFont
*dFont
; /* the default font */
118 WMColor
*dColor
; /* the default color */
119 WMPixmap
*dBulletPix
; /* the default pixmap for bullets */
121 GC bgGC
; /* the background GC to draw with */
122 GC fgGC
; /* the foreground GC to draw with */
123 Pixmap db
; /* the buffer on which to draw */
125 WMRulerMargins
*margins
;/* a (growable) array of margins to be used */
126 /* by the various TextBlocks */
128 myRect visible
; /* the actual rectangle that can be drawn into */
129 myRect cursor
; /* the position and (height) of cursor */
130 myRect sel
; /* the selection rectangle */
131 int docWidth
; /* the width of the entire document */
132 int docHeight
; /* the height of the entire document */
135 TextBlock
*firstTextBlock
;
136 TextBlock
*lastTextBlock
;
137 TextBlock
*currentTextBlock
;
140 WMBag
*gfxItems
; /* a nice bag containing graphic items */
142 WMHandlerID timerID
; /* for nice twinky-winky */
143 WMPoint clicked
; /* where in the _document_ was clicked */
144 unsigned short tpos
; /* the character position in the currentTextBlock */
145 unsigned short RESERVED
;/* space taker upper... */
152 unsigned int monoFont
:1; /* whether to ignore formats */
153 unsigned int focused
:1; /* whether this instance has input focus */
154 unsigned int editable
:1; /* "silly user, you can't edit me" */
155 unsigned int ownsSelection
:1; /* "I ownz the current selection!" */
156 unsigned int pointerGrabbed
:1;/* "heh, gib me pointer" */
157 unsigned int buttonHeld
:1; /* the user is holding down the button */
158 unsigned int waitingForSelection
:1; /* dum dee dumm... */
159 unsigned int extendSelection
:1; /* shift-drag to select more regions */
161 unsigned int rulerShown
:1; /* whether the ruler is shown or not */
162 unsigned int frozen
:1; /* whether screen updates are to be made */
163 unsigned int cursorShown
:1; /* whether to show the cursor */
164 unsigned int clickPos
:1; /* clicked before=0 or after=1 a graphic: */
165 /* within counts as after too */
167 unsigned int ignoreNewLine
:1;/* "bleh XK_Return" ignore it when typed */
168 unsigned int laidOut
:1; /* have the TextBlocks all been laid out */
169 unsigned int prepend
:1; /* prepend=1, append=0 (for parsers) */
170 WMAlignment alignment
:2; /* the alignment for text */
171 WMReliefType relief
:3; /* the relief to display with */
172 unsigned int RESERVED
:4;
173 unsigned int nmargins
:10; /* the number of margin arrays */
177 static char *default_bullet
[] = {
179 " c None s None", ". c black",
180 "X c white", "o c #808080",
190 paintText(Text
*tPtr
)
192 TextBlock
*tb
= tPtr
->firstTextBlock
;
196 int len
, y
, c
, s
, done
=False
;
198 WMScreen
*scr
= tPtr
->view
->screen
;
199 Display
*dpy
= tPtr
->view
->screen
->display
;
200 Window win
= tPtr
->view
->window
;
203 if (!tPtr
->view
->flags
.realized
|| !tPtr
->db
)
206 XFillRectangle(dpy
, tPtr
->db
, tPtr
->bgGC
,
207 0, 0, tPtr
->visible
.w
, tPtr
->visible
.h
);
210 tb
= tPtr
->firstTextBlock
;
215 if (tPtr
->flags
.ownsSelection
) {
216 greyGC
= WMColorGC(WMGrayColor(scr
));
217 //XFillRectangle(dpy, tPtr->db, greyGC,
218 // tPtr->sel.x, tPtr->sel.y-tPtr->vpos, tPtr->sel.w, tPtr->sel.h);
219 // XDrawRectangle(dpy, tPtr->db, tPtr->fgGC,
220 // tPtr->sel.x, tPtr->sel.y-tPtr->vpos, tPtr->sel.w, tPtr->sel.h);
231 for(s
=0; s
<tb
->nsections
&& !done
; s
++) {
234 if (tb
->sections
[s
]._y
> tPtr
->vpos
+ tPtr
->visible
.h
) {
239 if ( tb
->sections
[s
].y
+ tb
->sections
[s
].h
< tPtr
->vpos
)
242 if (tPtr
->flags
.monoFont
) {
247 gc
= WMColorGC(tb
->color
);
250 if (tPtr
->flags
.ownsSelection
) {
252 if (prev_y
!= tb
->sections
[s
]._y
253 && (tb
->sections
[s
]._y
>= tPtr
->sel
.y
)
254 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
255 <= tPtr
->sel
.y
+ tPtr
->sel
.h
)) {
256 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
258 tPtr
->visible
.y
+ tb
->sections
[s
]._y
- tPtr
->vpos
,
259 tPtr
->visible
.w
, tb
->sections
[s
].h
);
261 } else if ( prev_y
!= tb
->sections
[s
]._y
262 && (tb
->sections
[s
]._y
<= tPtr
->sel
.y
)
263 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
265 && (tPtr
->sel
.x
>= tb
->sections
[s
].x
)
266 && (tPtr
->sel
.y
+ tPtr
->sel
.h
267 >= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
)) {
268 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
270 tPtr
->visible
.y
+ tb
->sections
[s
]._y
- tPtr
->vpos
,
271 tPtr
->visible
.w
- tPtr
->sel
.x
, tb
->sections
[s
].h
);
273 } else if (prev_y
!= tb
->sections
[s
]._y
274 && (tb
->sections
[s
]._y
<= tPtr
->sel
.y
+ tPtr
->sel
.h
)
275 && (tb
->sections
[s
]._y
>= tPtr
->sel
.y
)) {
276 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
278 tPtr
->visible
.y
+ tb
->sections
[s
]._y
- tPtr
->vpos
,
279 tPtr
->sel
.x
+ tPtr
->sel
.w
-tPtr
->visible
.x
,
282 } else if ( prev_y
!= tb
->sections
[s
]._y
283 && (tb
->sections
[s
]._y
<= tPtr
->sel
.y
)
284 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
285 >= tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
286 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
288 tPtr
->visible
.y
+ tb
->sections
[s
]._y
- tPtr
->vpos
,
289 tPtr
->sel
.w
,tb
->sections
[s
].h
);
294 prev_y
= tb
->sections
[s
]._y
;
296 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
297 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
298 y
= tb
->sections
[s
].y
- tPtr
->vpos
;
299 WMDrawString(scr
, tPtr
->db
, gc
, font
,
300 tb
->sections
[s
].x
, y
, text
, len
);
302 if (tb
->underlined
) {
303 XDrawLine(dpy
, tPtr
->db
, gc
,
304 tb
->sections
[s
].x
, y
+ font
->y
+ 1,
305 tb
->sections
[s
].x
+ tb
->sections
[s
].w
, y
+ font
->y
+ 1);
310 tb
= (!done
? tb
->next
: NULL
);
314 c
= WMGetBagItemCount(tPtr
->gfxItems
);
315 if (c
> 0 && !tPtr
->flags
.monoFont
) {
319 tb
= (TextBlock
*) WMGetFromBag(tPtr
->gfxItems
, j
);
321 if (tb
->sections
[0]._y
+ tb
->sections
[0].h
<= tPtr
->vpos
322 || tb
->sections
[0]._y
>= tPtr
->vpos
+ tPtr
->visible
.h
) {
324 if ((W_VIEW(wdt
))->flags
.mapped
) {
328 if (!(W_VIEW(wdt
))->flags
.mapped
) {
330 //WMLowerWidget(wdt);
333 if (tPtr
->flags
.ownsSelection
&& 0
334 //&& (tb->sections[s]._y >= tPtr->sel.y)
335 //&& (tb->sections[s]._y + tb->sections[s].h
336 ){ // <= tPtr->sel.y + tPtr->sel.h)) {
337 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
338 tb
->sections
[0].x
, tb
->sections
[0].y
- tPtr
->vpos
,
339 tb
->sections
[0].w
, tb
->sections
[0].h
);
342 WMMoveWidget(wdt
, 3 + tb
->sections
[0].x
+ tPtr
->visible
.x
,
343 tb
->sections
[0].y
- tPtr
->vpos
);
345 if (tb
->underlined
) {
346 XDrawLine(dpy
, tPtr
->db
, WMColorGC(tb
->color
),
348 tb
->sections
[0].y
+ WMWidgetHeight(wdt
) + 1,
349 tb
->sections
[0].x
+ tb
->sections
[0].w
,
350 tb
->sections
[0].y
+ WMWidgetHeight(wdt
) + 1);
354 if (tPtr
->flags
.cursorShown
&& tPtr
->cursor
.x
!= -23
355 && 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
);
360 //printf("%d %d %d\n", tPtr->cursor.x, tPtr->cursor.y, tPtr->cursor.h);
365 XCopyArea(dpy
, tPtr
->db
, win
, tPtr
->bgGC
,
367 tPtr
->visible
.w
, tPtr
->visible
.h
,
368 tPtr
->visible
.x
, tPtr
->visible
.y
);
370 W_DrawRelief(scr
, win
, 0, 0,
371 tPtr
->view
->size
.width
, tPtr
->view
->size
.height
,
374 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)
377 tPtr
->view
->size
.width
-4, 42);
380 XFillRectangle(tPtr->view->screen->display, tPtr->view->window,
382 2, tPtr->view->size.height-3,
383 tPtr->view->size.width-4, 3);
388 #define CURSOR_BLINK_ON_DELAY 600
389 #define CURSOR_BLINK_OFF_DELAY 400
392 blinkCursor(void *data
)
394 Text
*tPtr
= (Text
*)data
;
396 if (tPtr
->flags
.cursorShown
) {
397 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY
,
400 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
,
404 tPtr
->flags
.cursorShown
= !tPtr
->flags
.cursorShown
;
408 getFirstNonGraphicBlockFor(TextBlock
*tb
, short dir
)
415 tb
= (dir
? tb
->next
: tb
->prior
);
423 cursorToTextPosition(Text
*tPtr
, int x
, int y
)
425 TextBlock
*tb
= NULL
;
426 int done
=False
, s
, pos
, len
, _w
, _y
, dir
=1; /* 1 == "down" */
429 y
+= (tPtr
->vpos
- tPtr
->visible
.y
);
433 x
-= (tPtr
->visible
.x
- 2);
437 /* clicked is relative to document, not window... */
441 if (! (tb
= tPtr
->currentTextBlock
)) {
442 if (! (tb
= tPtr
->firstTextBlock
)) {
448 /* first, which direction? Most likely, newly clicked
449 position will be close to previous */
450 dir
= !(y
< tb
->sections
[0].y
);
452 tb
= tPtr
->lastTextBlock
;
453 printf("%s\n", dir
?"down":"up");
455 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
456 tb
= getFirstNonGraphicBlockFor(tb
, 1);
458 tPtr
->currentTextBlock
=
459 (dir
? tPtr
->lastTextBlock
: tPtr
->firstTextBlock
);
465 s
= (dir
? 0 : tb
->nsections
-1);
466 if ( y
>= tb
->sections
[s
]._y
467 && y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) {
472 /* get the first section of the TextBlock that lies about
473 the vertical click point */
477 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
482 s
= (dir
? 0 : tb
->nsections
-1);
483 while(!done
&& (dir
? (s
<tb
->nsections
) : (s
>=0) )) {
485 if ( y
>= tb
->sections
[s
]._y
486 && y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) {
494 if ( (dir
? tb
->next
: tb
->prior
)) {
495 tb
= (dir
? tb
->next
: tb
->prior
);
498 break; //goto _doneH;
504 if (s
<0 || s
>=tb
->nsections
) {
505 s
= (dir
? tb
->nsections
-1 : 0);
509 /* we have the line, which TextBlock on that line is it? */
511 if (tPtr
->flags
.monoFont
&& tb
->graphic
)
512 tb
= getFirstNonGraphicBlockFor(tb
, dir
);
514 if ((dir
? tb
->sections
[s
].x
>= x
: tb
->sections
[s
].x
< x
))
516 _y
= tb
->sections
[s
]._y
;
521 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
522 tb
= (dir
? tb
->next
: tb
->prior
);
528 _w
= WMWidgetWidth(tb
->d
.widget
);
530 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
531 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
532 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
533 if (tb
->sections
[s
].x
+ _w
>= x
)
538 if (tb
->sections
[s
].x
<= x
)
543 if ((dir
? tb
->next
: tb
->prior
)) {
544 TextBlock
*nxt
= (dir
? tb
->next
: tb
->prior
);
545 if (tPtr
->flags
.monoFont
&& nxt
->graphic
) {
546 nxt
= getFirstNonGraphicBlockFor(nxt
, dir
);
552 if (_y
!= nxt
->sections
[s
]._y
) {
553 /* this must be the last/first on this line. stop */
554 pos
= (dir
? tb
->used
: 0);
560 tb
= (dir
? tb
->next
: tb
->prior
);
562 s
= (dir
? 0 : tb
->nsections
-1);
565 /* we have said TextBlock, now where within it? */
566 if (tb
&& !tb
->graphic
) {
567 WMFont
*f
= tb
->d
.font
;
568 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
569 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
571 _w
= x
- tb
->sections
[s
].x
;
574 while(pos
<len
&& WMWidthOfString(f
, text
, pos
+1) < _w
)
577 tPtr
->cursor
.x
= tb
->sections
[s
].x
+
578 (pos
? WMWidthOfString(f
, text
, pos
) : 0);
579 pos
+= tb
->sections
[s
].begin
;
581 tPtr
->tpos
= (pos
<tb
->used
)? pos
: tb
->used
;
584 tPtr
->currentTextBlock
= tb
;
585 tPtr
->flags
.cursorShown
;
586 tPtr
->cursor
.h
= tb
->sections
[s
].h
;
587 tPtr
->cursor
.y
= tb
->sections
[s
]._y
;
592 printf("will hang :-)\n");
597 updateScrollers(Text
*tPtr
)
601 if (tPtr
->docHeight
< tPtr
->visible
.h
) {
602 WMSetScrollerParameters(tPtr
->vS
, 0, 1);
605 float vmax
= (float)(tPtr
->docHeight
);
606 WMSetScrollerParameters(tPtr
->vS
,
607 ((float)tPtr
->vpos
)/(vmax
- (float)tPtr
->visible
.h
),
608 (float)tPtr
->visible
.h
/vmax
);
610 } else tPtr
->vpos
= 0;
617 scrollersCallBack(WMWidget
*w
, void *self
)
619 Text
*tPtr
= (Text
*)self
;
624 if (!tPtr
->view
->flags
.realized
) return;
629 vmax
= (float)(tPtr
->docHeight
);
630 height
= tPtr
->visible
.h
;
632 which
= WMGetScrollerHitPart(tPtr
->vS
);
634 case WSDecrementLine
:
635 if (tPtr
->vpos
> 0) {
636 if (tPtr
->vpos
>16) tPtr
->vpos
-=16;
640 case WSIncrementLine
: {
641 int limit
= tPtr
->docHeight
- height
;
642 if (tPtr
->vpos
< limit
) {
643 if (tPtr
->vpos
<limit
-16) tPtr
->vpos
+=16;
644 else tPtr
->vpos
=limit
;
647 case WSDecrementPage
:
648 tPtr
->vpos
-= height
;
654 printf("dimple needs to jump to mouse location ;-/\n");
656 case WSIncrementPage
:
657 tPtr
->vpos
+= height
;
658 if (tPtr
->vpos
> (tPtr
->docHeight
- height
))
659 tPtr
->vpos
= tPtr
->docHeight
- height
;
662 printf("dimple needs to jump to mouse location ;-/\n");
667 tPtr
->vpos
= WMGetScrollerValue(tPtr
->vS
)
668 * (float)(tPtr
->docHeight
- height
);
674 printf("WSNoPart, WSKnobSlot\n");
676 float vmax
= (float)(tPtr
->docHeight
);
677 ((float)tPtr
->vpos
)/(vmax
- (float)tPtr
->visible
.h
),
678 (float)tPtr
->visible
.h
/vmax
;
679 dimple
=where mouse is
.
683 scroll
= (tPtr
->vpos
!= tPtr
->prevVpos
);
684 tPtr
->prevVpos
= tPtr
->vpos
;
693 if (tPtr->rulerShown)
694 XClearArea(tPtr->view->screen->display, tPtr->view->window, 22, 47,
695 tPtr->view->size.width-24, tPtr->view->size.height-49, True);
697 XClearArea(tPtr->view->screen->display, tPtr->view->window, 22, 2,
698 tPtr->view->size.width-24, tPtr->view->size.height-4, True);
701 if (which
== WSDecrementLine
|| which
== WSIncrementLine
)
702 updateScrollers(tPtr
);
711 unsigned short begin
, end
; /* what part of the text block */
717 layOutLine(Text
*tPtr
, myLineItems
*items
, int nitems
, int x
, int y
,
718 int pwidth
, WMAlignment align
)
720 int i
, j
=0, lw
= 0, line_height
=0, max_d
=0, len
, n
;
725 TextBlock
*tbsame
=NULL
;
727 for(i
=0; i
<nitems
; i
++) {
731 if (!tPtr
->flags
.monoFont
) {
732 WMWidget
*wdt
= tb
->d
.widget
;
733 line_height
= WMAX(line_height
, WMWidgetHeight(wdt
));
735 lw
+= WMWidgetWidth(wdt
);
740 font
= (tPtr
->flags
.monoFont
)?tPtr
->dFont
: tb
->d
.font
;
741 max_d
= WMAX(max_d
, font
->height
-font
->y
);
742 line_height
= WMAX(line_height
, font
->height
);
743 text
= &(tb
->text
[items
[i
].begin
]);
744 len
= items
[i
].end
- items
[i
].begin
;
746 lw
+= WMWidthOfString(font
, text
, len
);
750 if (align
== WARight
) {
752 } else if (align
== WACenter
) {
753 j
= (int) ((float)(pwidth
- lw
))/2.0;
758 for(i
=0; i
<nitems
; i
++) {
761 if (tbsame
== tb
) { /*extend it, since it's on same line */
762 tb
->sections
[tb
->nsections
-1].end
= items
[i
].end
;
765 tb
->sections
= wrealloc(tb
->sections
,
766 (++tb
->nsections
)*sizeof(Section
));
768 tb
->sections
[n
]._y
= y
;
769 tb
->sections
[n
].x
= x
+j
;
770 tb
->sections
[n
].h
= line_height
;
771 tb
->sections
[n
].begin
= items
[i
].begin
;
772 tb
->sections
[n
].end
= items
[i
].end
;
775 if (!tPtr
->flags
.monoFont
) {
776 WMWidget
*wdt
= tb
->d
.widget
;
777 tb
->sections
[n
].y
= 1 + max_d
+
778 y
+ line_height
- WMWidgetHeight(wdt
);
779 tb
->sections
[n
].w
= WMWidgetWidth(wdt
);
780 x
+= tb
->sections
[n
].w
;
783 font
= (tPtr
->flags
.monoFont
)? tPtr
->dFont
: tb
->d
.font
;
784 len
= items
[i
].end
- items
[i
].begin
;
785 text
= &(tb
->text
[items
[i
].begin
]);
787 tb
->sections
[n
].y
= y
+line_height
-font
->y
;
789 WMWidthOfString(font
,
790 &(tb
->text
[tb
->sections
[n
].begin
]),
791 tb
->sections
[n
].end
- tb
->sections
[n
].begin
);
793 x
+= WMWidthOfString(font
, text
, len
);
799 return line_height
+(gfx
?10:0);
805 output(char *ptr
, int len
)
810 //printf(" s is [%s] (%d)\n", s, strlen(s));
816 #define MAX_TB_PER_LINE 64
819 layOutDocument(Text
*tPtr
)
822 myLineItems items
[MAX_TB_PER_LINE
];
823 WMAlignment align
= WALeft
;
825 Bool lhc
= !tPtr
->flags
.laidOut
; /* line height changed? */
828 int nitems
=0, x
=0, y
=0, lw
= 0, width
=0;
829 int pwidth
= tPtr
->visible
.w
- tPtr
->visible
.x
;
831 char *start
=NULL
, *mark
=NULL
;
834 if (!(tb
= tPtr
->firstTextBlock
))
837 if (0&&tPtr
->flags
.laidOut
) {
838 tb
= tPtr
->currentTextBlock
;
839 if (tb
->sections
&& tb
->nsections
>0)
840 prev_y
= tb
->sections
[tb
->nsections
-1]._y
;
842 printf("1 prev_y %d \n", prev_y
);
844 /* search backwards for textblocks on same line */
846 if (!tb
->sections
|| tb
->nsections
<1) {
847 tb
= tPtr
->firstTextBlock
;
850 if (tb
->sections
[tb
->nsections
-1]._y
!= prev_y
) {
854 // prev_y = tb->sections[tb->nsections-1]._y;
857 y
= 0;//tb->sections[tb->nsections-1]._y;
858 printf("2 prev_y %d \n\n", tb
->sections
[tb
->nsections
-1]._y
);
864 if (tb
->sections
&& tb
->nsections
>0) {
871 output(tb
->text
, tb
->used
);
872 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
, pwidth
, align
);
873 x
= 0;//tPtr->visible.x+2;
879 if (!tPtr
->flags
.monoFont
) {
880 width
= WMWidgetWidth(tb
->d
.widget
);
881 if (width
> pwidth
)printf("rescale graphix to fit?\n");
884 || nitems
>= MAX_TB_PER_LINE
) {
885 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
,
888 x
= 0;//tPtr->visible.x+2;
892 items
[nitems
].tb
= tb
;
893 items
[nitems
].begin
= 0;
894 items
[nitems
].end
= 0;
898 } else if ((start
= tb
->text
)) {
900 font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
903 mark
= strchr(start
, ' ');
905 end
+= (int)(mark
-start
)+1;
908 end
+= strlen(start
);
917 width
= WMWidthOfString(font
,
918 &tb
->text
[begin
], end
-begin
);
920 if (width
> pwidth
) { /* break this tb up */
921 char *t
= &tb
->text
[begin
];
922 int l
=end
-begin
, i
=0;
924 width
= WMWidthOfString(font
, t
, ++i
);
925 } while (width
< pwidth
&& i
< l
);
927 if (start
) // and since (nil)-4 = 0xfffffffd
935 if ((lw
>= pwidth
- x
)
936 || nitems
>= MAX_TB_PER_LINE
) {
937 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
,
940 x
= 0; //tPtr->visible.x+2;
944 items
[nitems
].tb
= tb
;
945 items
[nitems
].begin
= begin
;
946 items
[nitems
].end
= end
;
957 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
, pwidth
, align
);
959 tPtr
->docHeight
= y
+10;
960 updateScrollers(tPtr
);
962 tPtr
->flags
.laidOut
= True
;
968 textDidResize(W_ViewDelegate
*self
, WMView
*view
)
970 Text
*tPtr
= (Text
*)view
->self
;
971 unsigned short w
= WMWidgetWidth(tPtr
);
972 unsigned short h
= WMWidgetHeight(tPtr
);
973 unsigned short rh
= 0, vw
= 0;
975 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
) {
976 WMMoveWidget(tPtr
->ruler
, 20, 2);
977 WMResizeWidget(tPtr
->ruler
, w
- 22, 40);
982 WMMoveWidget(tPtr
->vS
, 1, rh
+ 2);
983 WMResizeWidget(tPtr
->vS
, 20, h
- rh
- 3);
985 WMSetRulerOffset(tPtr
->ruler
, 22);
986 } else WMSetRulerOffset(tPtr
->ruler
, 2);
990 WMMoveWidget(tPtr
->hS
, vw
, h
- 21);
991 WMResizeWidget(tPtr
->hS
, w
- vw
- 1, 20);
993 WMMoveWidget(tPtr
->hS
, vw
+1, h
- 21);
994 WMResizeWidget(tPtr
->hS
, w
- vw
- 2, 20);
998 tPtr
->visible
.x
= (tPtr
->vS
)?22:0;
999 tPtr
->visible
.y
= (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)?43:3;
1000 tPtr
->visible
.w
= tPtr
->view
->size
.width
- tPtr
->visible
.x
- 12;
1001 tPtr
->visible
.h
= tPtr
->view
->size
.height
- tPtr
->visible
.y
;
1002 tPtr
->visible
.h
-= (tPtr
->hS
)?20:0;
1004 tPtr
->margins
[0].left
= tPtr
->margins
[0].right
= tPtr
->visible
.x
;
1005 tPtr
->margins
[0].body
= tPtr
->visible
.x
;
1006 tPtr
->margins
[0].right
= tPtr
->visible
.w
;
1008 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1011 //if (tPtr->view->flags.realized)
1012 //XFreePixmap(tPtr->view->screen->display, tPtr->db);
1015 if (tPtr
->visible
.w
< 10) tPtr
->visible
.w
= 10;
1016 if (tPtr
->visible
.h
< 10) tPtr
->visible
.h
= 10;
1018 //if (size change or !db
1019 tPtr
->db
= XCreatePixmap(tPtr
->view
->screen
->display
,
1020 tPtr
->view
->window
, tPtr
->visible
.w
,
1021 tPtr
->visible
.h
, tPtr
->view
->screen
->depth
);
1026 W_ViewDelegate _TextViewDelegate
=
1034 /* nice, divisble-by-16 blocks */
1035 static inline unsigned short
1036 reqBlockSize(unsigned short requested
)
1038 return requested
+ 16 - (requested
%16);
1042 clearText(Text
*tPtr
)
1045 if (!tPtr
->firstTextBlock
)
1048 while(tPtr
->currentTextBlock
)
1049 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1051 printf("yadda clearText\n");
1053 printf("remove the document\n");
1054 tPtr
->firstTextBlock
= NULL
;
1055 tPtr
->currentTextBlock
= NULL
;
1056 tPtr
->lastTextBlock
= NULL
;
1058 WMRefreshText(tPtr
, 0, 0);
1062 deleteTextInteractively(Text
*tPtr
, KeySym ksym
)
1064 printf("deleting %ld\n", ksym
);
1069 insertTextInteractively(Text
*tPtr
, char *text
, int len
)
1072 char *newline
= NULL
;
1074 if (!tPtr
->flags
.editable
|| len
< 1 || !text
)
1077 if (tPtr
->flags
.ignoreNewLine
) {
1079 for(i
=0; i
<len
; i
++) {
1080 if (text
[i
] == '\n')
1086 WMSetTextSelectionColor(tPtr
, WMCreateNamedColor(tPtr
->view
->screen
,
1089 tb
= tPtr
->currentTextBlock
;
1090 if (!tb
|| tb
->graphic
) {
1091 WMAppendTextStream(tPtr
, text
);
1092 if (tPtr
->currentTextBlock
) {
1093 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
1098 if ((newline
= strchr(text
, '\n'))) {
1099 int nlen
= (int)(newline
-text
);
1100 int s
= tb
->used
- tPtr
->tpos
;
1103 if (!tb
->blank
&& nlen
>0 ) {
1105 memcpy(save
, &tb
->text
[tPtr
->tpos
], s
);
1106 tb
->used
-= (tb
->used
- tPtr
->tpos
);
1109 insertTextInteractively(tPtr
, text
, nlen
);
1111 WMAppendTextStream(tPtr
, newline
);
1113 insertTextInteractively(tPtr
, save
, s
);
1114 } else WMAppendTextStream(tPtr
, text
);
1117 if (tb
->used
+ len
>= tb
->allocated
) {
1118 tb
->allocated
= reqBlockSize(tb
->used
+len
);
1119 tb
->text
= wrealloc(tb
->text
, tb
->allocated
);
1123 memcpy(tb
->text
, text
, len
);
1128 memmove(&(tb
->text
[tPtr
->tpos
+len
]), &tb
->text
[tPtr
->tpos
],
1129 tb
->used
-tPtr
->tpos
+1);
1130 memmove(&tb
->text
[tPtr
->tpos
], text
, len
);
1140 selectRegion(Text
*tPtr
, int x
, int y
)
1145 if (y
>10) y
-= 10; /* the original offset */
1147 x
-= tPtr
->visible
.x
-2;
1150 tPtr
->sel
.x
= WMAX(0, WMIN(tPtr
->clicked
.x
, x
));
1151 tPtr
->sel
.w
= abs(tPtr
->clicked
.x
- x
);
1152 tPtr
->sel
.y
= WMAX(0, WMIN(tPtr
->clicked
.y
, y
));
1153 tPtr
->sel
.h
= abs(tPtr
->clicked
.y
- y
);
1155 tPtr
->flags
.ownsSelection
= True
;
1161 pasteText(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
1162 void *cdata
, WMData
*data
)
1164 Text
*tPtr
= (Text
*)view
->self
;
1167 tPtr
->flags
.waitingForSelection
= False
;
1170 str
= (char*)WMDataBytes(data
);
1172 (tPtr
->parser
) (tPtr
, (void *) str
);
1174 insertTextInteractively(tPtr
, str
, strlen(str
));
1176 WMRefreshText(tPtr
, 0, 0);
1179 str
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
1183 (tPtr
->parser
) (tPtr
, (void *) str
);
1185 insertTextInteractively(tPtr
, str
, n
);
1187 WMRefreshText(tPtr
, 0, 0);
1194 releaseSelection(Text
*tPtr
)
1196 tPtr
->flags
.ownsSelection
= False
;
1201 requestHandler(WMView
*view
, Atom selection
, Atom target
,
1202 void *cdata
, Atom
*type
)
1204 Text
*tPtr
= view
->self
;
1206 Display
*dpy
= tPtr
->view
->screen
->display
;
1207 Atom TEXT
= XInternAtom(dpy
, "TEXT", False
);
1208 Atom COMPOUND_TEXT
= XInternAtom(dpy
, "COMPOUND_TEXT", False
);
1211 if (target
== XA_STRING
|| target
== TEXT
|| target
== COMPOUND_TEXT
)
1212 return WMGetTextSelected(tPtr
);
1214 WMData
*data
= WMCreateDataWithBytes("bleh", 4);
1223 lostHandler(WMView
*view
, Atom selection
, void *cdata
)
1225 releaseSelection((WMText
*)view
->self
);
1228 static WMSelectionProcs selectionHandler
= {
1229 requestHandler
, lostHandler
, NULL
1233 _notification(void *observerData
, WMNotification
*notification
)
1235 WMText
*to
= (WMText
*)observerData
;
1236 WMText
*tw
= (WMText
*)WMGetNotificationClientData(notification
);
1238 lostHandler(to
->view
, XA_PRIMARY
, NULL
);
1242 handleTextKeyPress(Text
*tPtr
, XEvent
*event
)
1246 int control_pressed
= False
;
1249 if (((XKeyEvent
*) event
)->state
& ControlMask
)
1250 control_pressed
= True
;
1251 buffer
[XLookupString(&event
->xkey
, buffer
, 1, &ksym
, NULL
)] = '\0';
1258 printf("arrows %ld\n", ksym
);
1264 deleteTextInteractively(tPtr
, ksym
);
1271 if (buffer
[0] != '\0' && !control_pressed
) {
1272 insertTextInteractively(tPtr
, buffer
, 1);
1273 WMRefreshText(tPtr
, 0, 0);
1275 } else if (control_pressed
&& ksym
==XK_r
) {
1276 // Bool i = !tPtr->rulerShown; WMShowTextRuler(tPtr, i);
1277 // tPtr->rulerShown = i;
1278 printf("toggle ruler\n");
1280 else if (control_pressed
&& buffer
[0] == '\a')
1281 XBell(tPtr
->view
->screen
->display
, 0);
1284 if (tPtr
->flags
.ownsSelection
)
1285 releaseSelection(tPtr
);
1289 handleWidgetPress(XEvent
*event
, void *data
)
1291 TextBlock
*tb
= (TextBlock
*)data
;
1297 /* this little bit of nastiness here saves a boatload of trouble */
1298 w
= (WMWidget
*)(((W_VIEW(tb
->d
.widget
))->parent
)->self
);
1299 if (W_CLASS(w
) != WC_Text
)
1302 printf("%p clicked on tb %p wif: (%c)%c", tPtr
, tb
,
1303 tPtr
->firstTextBlock
->text
[0], tPtr
->firstTextBlock
->text
[1]);
1304 tPtr
->currentTextBlock
= getFirstNonGraphicBlockFor(tb
, 1);
1305 if (!tPtr
->currentTextBlock
)
1306 tPtr
->currentTextBlock
= tb
;
1308 output(tPtr
->currentTextBlock
->text
, tPtr
->currentTextBlock
->used
);
1309 //if (!tPtr->flags.focused) {
1310 // WMSetFocusToWidget(tPtr);
1311 // tPtr->flags.focused = True;
1317 handleActionEvents(XEvent
*event
, void *data
)
1319 Text
*tPtr
= (Text
*)data
;
1320 Display
*dpy
= event
->xany
.display
;
1324 if (tPtr
->flags
.waitingForSelection
)
1327 switch (event
->type
) {
1329 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
1330 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
1331 WMSetTextSelectionFont(tPtr
, WMBoldSystemFontOfSize(
1332 tPtr
->view
->screen
, 18));
1333 tPtr
->flags
.extendSelection
= True
;
1336 if (!tPtr
->flags
.editable
|| tPtr
->flags
.buttonHeld
) {
1341 if (tPtr
->flags
.waitingForSelection
)
1343 if (tPtr
->flags
.focused
) {
1344 XGrabPointer(dpy
, W_VIEW(tPtr
)->window
, False
,
1345 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
1346 GrabModeAsync
, GrabModeAsync
, None
,
1347 tPtr
->view
->screen
->invisibleCursor
, CurrentTime
);
1348 tPtr
->flags
.pointerGrabbed
= True
;
1349 handleTextKeyPress(tPtr
, event
);
1354 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
1355 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
1356 tPtr
->flags
.extendSelection
= False
;
1358 //end modify flag so selection can be extended
1364 if (tPtr
->flags
.pointerGrabbed
) {
1365 tPtr
->flags
.pointerGrabbed
= False
;
1366 XUngrabPointer(dpy
, CurrentTime
);
1368 if ((event
->xmotion
.state
& Button1Mask
)) {
1369 if (!tPtr
->flags
.ownsSelection
) {
1370 WMCreateSelectionHandler(tPtr
->view
, XA_PRIMARY
,
1371 event
->xbutton
.time
, &selectionHandler
, NULL
);
1372 tPtr
->flags
.ownsSelection
= True
;
1374 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
1380 tPtr
->flags
.buttonHeld
= True
;
1381 if (tPtr
->flags
.extendSelection
) {
1382 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
1385 if (event
->xbutton
.button
== Button1
) {
1387 if (!tPtr
->flags
.focused
) {
1388 WMSetFocusToWidget(tPtr
);
1389 tPtr
->flags
.focused
= True
;
1392 if (tPtr
->flags
.ownsSelection
)
1393 releaseSelection(tPtr
);
1394 cursorToTextPosition(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
1395 if (tPtr
->flags
.pointerGrabbed
) {
1396 tPtr
->flags
.pointerGrabbed
= False
;
1397 XUngrabPointer(dpy
, CurrentTime
);
1402 if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelDown
)
1403 WMScrollText(tPtr
, -16);
1404 else if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelUp
)
1405 WMScrollText(tPtr
, 16);
1409 tPtr
->flags
.buttonHeld
= False
;
1410 if (tPtr
->flags
.pointerGrabbed
) {
1411 tPtr
->flags
.pointerGrabbed
= False
;
1412 XUngrabPointer(dpy
, CurrentTime
);
1415 if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelDown
1416 || event
->xbutton
.button
== WINGsConfiguration
.mouseWheelUp
)
1419 if (event
->xbutton
.button
== Button2
&& tPtr
->flags
.editable
) {
1422 if (!WMRequestSelection(tPtr
->view
, XA_PRIMARY
, XA_STRING
,
1423 event
->xbutton
.time
, pasteText
, NULL
)) {
1424 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
1428 (tPtr
->parser
) (tPtr
, (void *) text
);
1430 insertTextInteractively(tPtr
, text
, n
-1);
1432 WMRefreshText(tPtr
, 0, 0);
1434 } else tPtr
->flags
.waitingForSelection
= True
;
1445 handleEvents(XEvent
*event
, void *data
)
1447 Text
*tPtr
= (Text
*)data
;
1449 switch(event
->type
) {
1451 if (!event
->xexpose
.count
&& tPtr
->view
->flags
.realized
)
1456 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))
1459 tPtr
->flags
.focused
= True
;
1460 if (!tPtr
->timerID
) {
1461 tPtr
->timerID
= WMAddTimerHandler(12+0*CURSOR_BLINK_ON_DELAY
,
1468 tPtr
->flags
.focused
= False
;
1470 if (tPtr
->timerID
) {
1471 WMDeleteTimerHandler(tPtr
->timerID
);
1472 tPtr
->timerID
= NULL
;
1478 //for(...)WMRemoveTextParagraph(tPtr, para);
1488 insertPlainText(WMText
*tPtr
, char *text
)
1502 mark
= strchr(start
, '\n');
1504 tb
= WMCreateTextBlockWithText(start
, tPtr
->dFont
,
1505 tPtr
->dColor
, True
, (int)(mark
-start
));
1508 if (start
&& strlen(start
)) {
1509 tb
= WMCreateTextBlockWithText(start
, tPtr
->dFont
,
1510 tPtr
->dColor
, False
, strlen(start
));
1515 if (tPtr
->flags
.prepend
)
1516 WMPrependTextBlock(tPtr
, tb
);
1518 WMAppendTextBlock(tPtr
, tb
);
1530 WMCreateText(WMWidget
*parent
)
1532 Text
*tPtr
= wmalloc(sizeof(Text
));
1534 printf("could not create text widget\n");
1539 printf("sizeof:\n");
1540 printf(" TextBlock %d\n", sizeof(TextBlock
));
1541 printf(" Section %d\n", sizeof(Section
));
1542 printf(" char * %d\n", sizeof(char *));
1543 printf(" void * %d\n", sizeof(void *));
1544 printf(" short %d\n", sizeof(short));
1545 printf(" Text %d\n", sizeof(Text
));
1548 memset(tPtr
, 0, sizeof(Text
));
1549 tPtr
->widgetClass
= WC_Text
;
1550 tPtr
->view
= W_CreateView(W_VIEW(parent
));
1552 perror("could not create text's view\n");
1556 tPtr
->view
->self
= tPtr
;
1557 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->textCursor
;
1558 tPtr
->view
->attribFlags
|= CWOverrideRedirect
| CWCursor
;
1559 W_ResizeView(tPtr
->view
, 250, 200);
1560 tPtr
->bgGC
= WMColorGC(tPtr
->view
->screen
->white
);
1561 tPtr
->fgGC
= WMColorGC(tPtr
->view
->screen
->black
);
1562 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->view
->screen
->white
);
1569 //tPtr->dFont = WMCreateFont(tPtr->view->screen,
1570 // "-*-fixed-medium-r-normal--26-*-*-*-*-*-*-*");
1571 //"-sony-fixed-medium-r-normal--24-230-75-75-c-120-jisx0201.1976-0");
1572 // "-*-times-bold-r-*-*-12-*-*-*-*-*-*-*,"
1573 // "-*-fixed-medium-r-normal-*-12-*");
1575 tPtr
->dFont
= WMRetainFont(tPtr
->view
->screen
->normalFont
);
1577 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
1579 tPtr
->view
->delegate
= &_TextViewDelegate
;
1581 tPtr
->timerID
= NULL
;
1583 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
1584 |EnterWindowMask
|LeaveWindowMask
|FocusChangeMask
,
1585 handleEvents
, tPtr
);
1587 WMCreateEventHandler(tPtr
->view
, ButtonReleaseMask
|ButtonPressMask
1588 |KeyReleaseMask
|KeyPressMask
|Button1MotionMask
,
1589 handleActionEvents
, tPtr
);
1591 WMAddNotificationObserver(_notification
, tPtr
, "_lostOwnership", tPtr
);
1594 tPtr
->firstTextBlock
= NULL
;
1595 tPtr
->lastTextBlock
= NULL
;
1596 tPtr
->currentTextBlock
= NULL
;
1599 tPtr
->gfxItems
= WMCreateArrayBag(4);
1601 tPtr
->parser
= NULL
;
1602 tPtr
->writer
= NULL
;
1604 tPtr
->sel
.x
= tPtr
->sel
.y
= 2;
1605 tPtr
->sel
.w
= tPtr
->sel
.h
= 0;
1607 tPtr
->clicked
.x
= tPtr
->clicked
.y
= 2;
1609 tPtr
->visible
.x
= tPtr
->visible
.y
= 2;
1610 tPtr
->visible
.h
= tPtr
->view
->size
.height
;
1611 tPtr
->visible
.w
= tPtr
->view
->size
.width
- 12;
1613 tPtr
->cursor
.x
= -23;
1616 tPtr
->docHeight
= 0;
1617 tPtr
->dBulletPix
= WMCreatePixmapFromXPMData(tPtr
->view
->screen
,
1619 tPtr
->db
= (Pixmap
) NULL
;
1621 tPtr
->margins
= wmalloc(sizeof(WMRulerMargins
));
1622 tPtr
->margins
[0].left
= tPtr
->margins
[0].right
= tPtr
->visible
.x
;
1623 tPtr
->margins
[0].body
= tPtr
->visible
.x
;
1624 tPtr
->margins
[0].right
= tPtr
->visible
.w
;
1626 tPtr
->flags
.nmargins
= 1;
1627 tPtr
->flags
.rulerShown
= False
;
1628 tPtr
->flags
.monoFont
= False
;
1629 tPtr
->flags
.focused
= False
;
1630 tPtr
->flags
.editable
= True
;
1631 tPtr
->flags
.ownsSelection
= False
;
1632 tPtr
->flags
.pointerGrabbed
= False
;
1633 tPtr
->flags
.buttonHeld
= False
;
1634 tPtr
->flags
.waitingForSelection
= False
;
1635 tPtr
->flags
.extendSelection
= False
;
1636 tPtr
->flags
.rulerShown
= False
;
1637 tPtr
->flags
.frozen
= False
;
1638 tPtr
->flags
.cursorShown
= True
;
1639 tPtr
->flags
.clickPos
= 1;
1640 tPtr
->flags
.ignoreNewLine
= False
;
1641 tPtr
->flags
.laidOut
= False
;
1642 tPtr
->flags
.prepend
= False
;
1643 tPtr
->flags
.relief
= WRFlat
;
1644 tPtr
->flags
.alignment
= WALeft
;
1651 WMPrependTextStream(WMText
*tPtr
, char *text
)
1655 //check for "{\rtf0" in the text...
1658 tPtr
->flags
.prepend
= True
;
1659 if (text
&& tPtr
->parser
)
1660 (tPtr
->parser
) (tPtr
, (void *) text
);
1662 insertPlainText(tPtr
, text
);
1667 WMAppendTextStream(WMText
*tPtr
, char *text
)
1671 //check for "{\rtf0" in the text...
1674 tPtr
->flags
.prepend
= False
;
1675 if (text
&& tPtr
->parser
)
1676 (tPtr
->parser
) (tPtr
, (void *) text
);
1678 insertPlainText(tPtr
, text
);
1683 WMGetTextSelected(WMText
*tPtr
)
1685 WMData
*data
= NULL
;
1691 //tb = tPtr->firstTextBlock;
1692 tb
= tPtr
->currentTextBlock
;
1696 data
= WMCreateDataWithBytes(tb
->text
, tb
->used
);
1698 WMSetDataFormat(data
, 8);
1703 WMCreateTextBlockWithObject(WMWidget
*w
, char *description
, WMColor
*color
,
1704 unsigned short first
, unsigned short reserved
)
1707 unsigned short length
;
1709 if (!w
|| !description
|| !color
)
1712 tb
= wmalloc(sizeof(TextBlock
));
1716 length
= strlen(description
);
1717 tb
->text
= (char *)wmalloc(length
);
1718 memset(tb
->text
, 0, length
);
1719 memcpy(tb
->text
, description
, length
);
1723 tb
->color
= WMRetainColor(color
);
1729 tb
->underlined
= False
;
1731 tb
->sections
= NULL
;
1740 WMCreateTextBlockWithText(char *text
, WMFont
*font
, WMColor
*color
,
1741 unsigned short first
, unsigned short length
)
1745 if (!font
|| !color
)
1748 tb
= wmalloc(sizeof(TextBlock
));
1752 tb
->allocated
= reqBlockSize(length
);
1753 tb
->text
= (char *)wmalloc(tb
->allocated
);
1754 memset(tb
->text
, 0, tb
->allocated
);
1756 if (length
< 1|| !text
) { // || *text == '\n') {
1761 memcpy(tb
->text
, text
, length
);
1766 tb
->d
.font
= WMRetainFont(font
);
1767 tb
->color
= WMRetainColor(color
);
1771 tb
->graphic
= False
;
1772 tb
->underlined
= False
;
1774 tb
->sections
= NULL
;
1782 WMSetTextBlockProperties(void *vtb
, unsigned int first
,
1783 unsigned int kanji
, unsigned int underlined
, int script
,
1784 unsigned int marginN
)
1786 TextBlock
*tb
= (TextBlock
*) vtb
;
1792 tb
->underlined
= underlined
;
1793 tb
->script
= script
;
1794 tb
->marginN
= marginN
;
1798 WMGetTextBlockProperties(void *vtb
, unsigned int *first
,
1799 unsigned int *kanji
, unsigned int *underlined
, int *script
,
1800 unsigned int *marginN
)
1802 TextBlock
*tb
= (TextBlock
*) vtb
;
1806 if (first
) *first
= tb
->first
;
1807 if (kanji
) *kanji
= tb
->kanji
;
1808 if (underlined
) *underlined
= tb
->underlined
;
1809 if (script
) *script
= tb
->script
;
1810 if (marginN
) *marginN
= tb
->marginN
;
1816 WMPrependTextBlock(WMText
*tPtr
, void *vtb
)
1818 TextBlock
*tb
= (TextBlock
*)vtb
;
1825 WMWidget
*w
= tb
->d
.widget
;
1826 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
1827 handleWidgetPress
, tb
);
1828 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
1829 (W_VIEW(w
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
1830 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
1832 WMPutInBag(tPtr
->gfxItems
, (void *)tb
);
1835 } else tPtr
->tpos
= tb
->used
;
1837 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
1838 tb
->next
= tb
->prior
= NULL
;
1839 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
1840 = tPtr
->currentTextBlock
= tb
;
1844 tb
->next
= tPtr
->currentTextBlock
;
1845 tb
->prior
= tPtr
->currentTextBlock
->prior
;
1846 if (tPtr
->currentTextBlock
->prior
)
1847 tPtr
->currentTextBlock
->prior
->next
= tb
;
1849 tPtr
->currentTextBlock
->prior
= tb
;
1851 tPtr
->firstTextBlock
= tb
;
1853 tPtr
->currentTextBlock
= tb
;
1858 WMAppendTextBlock(WMText
*tPtr
, void *vtb
)
1860 TextBlock
*tb
= (TextBlock
*)vtb
;
1866 WMWidget
*w
= tb
->d
.widget
;
1868 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
1869 handleWidgetPress
, tb
);
1870 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
1871 (W_VIEW(w
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
1872 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
1874 WMPutInBag(tPtr
->gfxItems
, (void *)tb
);
1877 } else tPtr
->tpos
= tb
->used
;
1879 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
1880 tb
->next
= tb
->prior
= NULL
;
1881 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
1882 = tPtr
->currentTextBlock
= tb
;
1886 tb
->next
= tPtr
->currentTextBlock
->next
;
1887 tb
->prior
= tPtr
->currentTextBlock
;
1888 if (tPtr
->currentTextBlock
->next
)
1889 tPtr
->currentTextBlock
->next
->prior
= tb
;
1891 tPtr
->currentTextBlock
->next
= tb
;
1894 tPtr
->lastTextBlock
= tb
;
1896 tPtr
->currentTextBlock
= tb
;
1900 WMRemoveTextBlock(WMText
*tPtr
)
1902 TextBlock
*tb
= NULL
;
1904 if (!tPtr
|| !tPtr
->firstTextBlock
|| !tPtr
->lastTextBlock
1905 || !tPtr
->currentTextBlock
) {
1906 printf("cannot remove non existent TextBlock!\b");
1910 tb
= tPtr
->currentTextBlock
;
1912 WMDeleteEventHandler(W_VIEW(tb
->d
.widget
), ButtonPressMask
,
1913 handleWidgetPress
, tb
);
1914 WMRemoveFromBag(tPtr
->gfxItems
, (void *)tb
);
1915 WMUnmapWidget(tb
->d
.widget
);
1918 if (tPtr
->currentTextBlock
== tPtr
->firstTextBlock
) {
1919 if (tPtr
->currentTextBlock
->next
)
1920 tPtr
->currentTextBlock
->next
->prior
= NULL
;
1922 tPtr
->firstTextBlock
= tPtr
->currentTextBlock
->next
;
1923 tPtr
->currentTextBlock
= tPtr
->firstTextBlock
;
1925 } else if (tPtr
->currentTextBlock
== tPtr
->lastTextBlock
) {
1926 tPtr
->currentTextBlock
->prior
->next
= NULL
;
1927 tPtr
->lastTextBlock
= tPtr
->currentTextBlock
->prior
;
1928 tPtr
->currentTextBlock
= tPtr
->lastTextBlock
;
1930 tPtr
->currentTextBlock
->prior
->next
= tPtr
->currentTextBlock
->next
;
1931 tPtr
->currentTextBlock
->next
->prior
= tPtr
->currentTextBlock
->prior
;
1932 tPtr
->currentTextBlock
= tPtr
->currentTextBlock
->next
;
1939 WMDestroyTextBlock(WMText
*tPtr
, void *vtb
)
1941 TextBlock
*tb
= (TextBlock
*)vtb
;
1946 /* naturally, there's a danger to destroying
1947 widgets whose action brings us here:
1948 ie. press a button to destroy it... need to
1949 find a safer way. till then... this stays commented out */
1950 //WMDestroyWidget(tb->d.widget);
1951 //wfree(tb->d.widget);
1952 tb
->d
.widget
= NULL
;
1954 WMReleaseFont(tb
->d
.font
);
1957 WMReleaseColor(tb
->color
);
1958 if (tb
->sections
&& tb
->nsections
> 0)
1959 wfree(tb
->sections
);
1966 WMRefreshText(WMText
*tPtr
, int vpos
, int hpos
)
1970 if (!tPtr
|| vpos
<0 || hpos
<0)
1973 tPtr
->flags
.laidOut
= False
;
1974 layOutDocument(tPtr
);
1975 updateScrollers(tPtr
);
1982 WMSetTextForegroundColor(WMText
*tPtr
, WMColor
*color
)
1988 tPtr
->fgGC
= WMColorGC(color
);
1990 tPtr
->fgGC
= WMColorGC(WMBlackColor(tPtr
->view
->screen
));
1992 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1996 WMSetTextBackgroundColor(WMText
*tPtr
, WMColor
*color
)
2002 tPtr
->bgGC
= WMColorGC(color
);
2003 W_SetViewBackgroundColor(tPtr
->view
, color
);
2005 tPtr
->bgGC
= WMColorGC(WMWhiteColor(tPtr
->view
->screen
));
2006 W_SetViewBackgroundColor(tPtr
->view
,
2007 WMWhiteColor(tPtr
->view
->screen
));
2010 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2014 WMSetTextRelief(WMText
*tPtr
, WMReliefType relief
)
2018 tPtr
->flags
.relief
= relief
;
2023 WMSetTextHasHorizontalScroller(WMText
*tPtr
, Bool shouldhave
)
2028 if (shouldhave
&& !tPtr
->hS
) {
2029 tPtr
->hS
= WMCreateScroller(tPtr
);
2030 (W_VIEW(tPtr
->hS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
2031 (W_VIEW(tPtr
->hS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2032 WMSetScrollerArrowsPosition(tPtr
->hS
, WSAMaxEnd
);
2033 WMSetScrollerAction(tPtr
->hS
, scrollersCallBack
, tPtr
);
2034 WMRealizeWidget(tPtr
->hS
);
2035 WMMapWidget(tPtr
->hS
);
2036 } else if (!shouldhave
&& tPtr
->hS
) {
2037 WMUnmapWidget(tPtr
->hS
);
2038 WMDestroyWidget(tPtr
->hS
);
2044 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2049 WMSetTextHasVerticalScroller(WMText
*tPtr
, Bool shouldhave
)
2054 if (shouldhave
&& !tPtr
->vS
) {
2055 tPtr
->vS
= WMCreateScroller(tPtr
);
2056 (W_VIEW(tPtr
->vS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
2057 (W_VIEW(tPtr
->vS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2058 WMSetScrollerArrowsPosition(tPtr
->vS
, WSAMaxEnd
);
2059 WMSetScrollerAction(tPtr
->vS
, scrollersCallBack
, tPtr
);
2060 WMRealizeWidget(tPtr
->vS
);
2061 WMMapWidget(tPtr
->vS
);
2062 } else if (!shouldhave
&& tPtr
->vS
) {
2063 WMUnmapWidget(tPtr
->vS
);
2064 WMDestroyWidget(tPtr
->vS
);
2070 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2076 WMScrollText(WMText
*tPtr
, int amount
)
2081 if (amount
== 0 || !tPtr
->view
->flags
.realized
)
2085 if (tPtr
->vpos
> 0) {
2086 if (tPtr
->vpos
> amount
) tPtr
->vpos
+= amount
;
2090 int limit
= tPtr
->docHeight
- tPtr
->visible
.h
;
2091 if (tPtr
->vpos
< limit
) {
2092 if (tPtr
->vpos
< limit
-amount
) tPtr
->vpos
+= amount
;
2093 else tPtr
->vpos
= limit
;
2097 if (scroll
&& tPtr
->vpos
!= tPtr
->prevVpos
) {
2098 updateScrollers(tPtr
);
2101 tPtr
->prevVpos
= tPtr
->vpos
;
2106 WMPageText(WMText
*tPtr
, Bool direction
)
2108 if (!tPtr
) return False
;
2109 if (!tPtr
->view
->flags
.realized
) return False
;
2111 return WMScrollText(tPtr
, direction
?tPtr
->visible
.h
:-tPtr
->visible
.h
);
2116 WMSetTextUseMonoFont(WMText
*tPtr
, Bool mono
)
2120 if (mono
&& tPtr
->flags
.rulerShown
)
2121 ;//WMShowTextRuler(tPtr, False);
2123 tPtr
->flags
.monoFont
= mono
;
2124 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2128 WMGetTextUsesMonoFont(WMText
*tPtr
)
2132 return tPtr
->flags
.monoFont
;
2136 WMSetTextDefaultFont(WMText
*tPtr
, WMFont
*font
)
2144 tPtr
->dFont
= WMRetainFont(tPtr
->view
->screen
->normalFont
);
2148 WMGetTextDefaultFont(WMText
*tPtr
)
2157 WMSetTextParser(WMText
*tPtr
, WMAction
*parser
)
2161 tPtr
->parser
= parser
;
2166 WMSetTextWriter(WMText
*tPtr
, WMAction
*writer
)
2170 tPtr
->writer
= writer
;
2174 WMGetTextInsertType(WMText
*tPtr
)
2178 return tPtr
->flags
.prepend
;
2183 WMSetTextSelectionColor(WMText
*tPtr
, WMColor
*color
)
2186 if (!tPtr
|| !color
)
2189 tb
= tPtr
->firstTextBlock
;
2190 if (!tb
|| !tPtr
->flags
.ownsSelection
)
2194 tb
->color
= WMRetainColor(color
);
2197 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2201 WMSetTextSelectionFont(WMText
*tPtr
, WMFont
*font
)
2207 tb
= tPtr
->firstTextBlock
;
2208 if (!tb
|| !tPtr
->flags
.ownsSelection
)
2213 tb
->d
.font
= WMRetainFont(font
);
2216 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);