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 * - assess danger of destroying widgets whose actions link to other pages
32 * - confirm with Alfredo et. all about field markers 0xFA and 0xCE
33 * - add paragraph support (full) and '\n' code in getStream..
34 * - use currentTextBlock and neighbours for fast paint and layout
35 * - replace copious uses of Refreshtext with appropriate layOut()...
36 * - WMFindInTextStream should also highlight found text...
37 * - add full support for Horizontal Scroll
42 /* a Section is a section of a TextBlock that describes what parts
43 of a TextBlock has been laid out on which "line"...
44 o this greatly aids redraw, scroll and selection.
45 o this is created during layoutLine, but may be later modified.
46 o there may be many Sections per TextBlock, hence the array */
48 unsigned int x
, y
; /* where to draw it from */
49 unsigned short w
, h
; /* its width and height */
50 unsigned int _y
; /* the "line" it and other textblocks are on */
51 unsigned short begin
; /* where the layout begins */
52 unsigned short end
; /* where it ends */
53 unsigned short last
; /* last section on a line? */
54 unsigned short RESERVED
:15;
58 /* a TextBlock is a doubly-linked list of TextBlocks containing:
59 o text for the block, color and font
60 o or a pointer to the pixmap
61 o OR a pointer to the widget and the (text) description for its graphic
64 typedef struct _TextBlock
{
65 struct _TextBlock
*next
; /* next text block in linked list */
66 struct _TextBlock
*prior
; /* prior text block in linked list */
68 char *text
; /* pointer to text (could be kanji) */
69 /* or to the object's description */
71 WMFont
*font
; /* the font */
72 WMWidget
*widget
; /* the embedded widget */
73 WMPixmap
*pixmap
; /* the pixmap */
74 } d
; /* description */
76 unsigned short used
; /* number of chars in this block */
77 unsigned short allocated
; /* size of allocation (in chars) */
78 WMColor
*color
; /* the color */
79 WMRulerMargins margins
; /* first & body indentations, tabstops, etc... */
81 Section
*sections
; /* the region for layouts (a growable array) */
82 /* an _array_! of size _nsections_ */
84 unsigned short s_begin
; /* where the selection begins */
85 unsigned short s_end
; /* where it ends */
87 unsigned int first
:1; /* first TextBlock in paragraph */
88 unsigned int blank
:1; /* ie. blank paragraph */
89 unsigned int kanji
:1; /* is of 16-bit characters or not */
90 unsigned int graphic
:1; /* graphic or text: text=0 */
91 unsigned int object
:1; /* embedded object or pixmap */
92 unsigned int underlined
:1; /* underlined or not */
93 unsigned int selected
:1; /* selected or not */
94 unsigned int nsections
:8; /* over how many "lines" a TextBlock wraps */
95 int script
:8; /* script in points: negative for subscript */
96 unsigned int RESERVED
:9;
100 /* somehow visible.h beats the hell outta visible.size.height :-) */
109 typedef struct W_Text
{
110 W_Class widgetClass
; /* the class number of this widget */
111 W_View
*view
; /* the view referring to this instance */
113 WMRuler
*ruler
; /* the ruler widget to manipulate paragraphs */
115 WMScroller
*vS
; /* the vertical scroller */
116 unsigned int vpos
; /* the current vertical position */
117 unsigned int prevVpos
; /* the previous vertical position */
119 WMScroller
*hS
; /* the horizontal scroller */
120 unsigned int hpos
; /* the current horizontal position */
121 unsigned int prevHpos
; /* the previous horizontal position */
123 WMFont
*dFont
; /* the default font */
124 WMColor
*dColor
; /* the default color */
125 WMPixmap
*dBulletPix
; /* the default pixmap for bullets */
126 WMRulerMargins dmargins
; /* default margins */
128 GC bgGC
; /* the background GC to draw with */
129 GC fgGC
; /* the foreground GC to draw with */
130 Pixmap db
; /* the buffer on which to draw */
132 myRect visible
; /* the actual rectangle that can be drawn into */
133 myRect cursor
; /* the position and (height) of cursor */
134 myRect sel
; /* the selection rectangle */
135 unsigned int docWidth
; /* the width of the entire document */
136 unsigned int docHeight
; /* the height of the entire document */
138 TextBlock
*firstTextBlock
;
139 TextBlock
*lastTextBlock
;
140 TextBlock
*currentTextBlock
;
143 WMBag
*gfxItems
; /* a nice bag containing graphic items */
146 WMHandlerID timerID
; /* for nice twinky-winky */
148 WMPoint clicked
; /* where in the _document_ was clicked */
149 unsigned short tpos
; /* the position in the currentTextBlock */
150 unsigned short RESERVED
; /* space taker upper... */
156 unsigned int monoFont
:1; /* whether to ignore formats */
157 unsigned int focused
:1; /* whether this instance has input focus */
158 unsigned int editable
:1; /* "silly user, you can't edit me" */
159 unsigned int ownsSelection
:1; /* "I ownz the current selection!" */
160 unsigned int pointerGrabbed
:1;/* "heh, gib me pointer" */
161 unsigned int buttonHeld
:1; /* the user is holding down the button */
162 unsigned int waitingForSelection
:1; /* dum dee dumm... */
163 unsigned int extendSelection
:1; /* shift-drag to select more regions */
165 unsigned int rulerShown
:1; /* whether the ruler is shown or not */
166 unsigned int frozen
:1; /* whether screen updates are to be made */
167 unsigned int cursorShown
:1; /* whether to show the cursor */
168 unsigned int clickPos
:1; /* clicked before=0 or after=1 a graphic: */
169 /* (within counts as after too) */
171 unsigned int ignoreNewLine
:1;/* turn it into a ' ' in streams > 1 */
172 unsigned int laidOut
:1; /* have the TextBlocks all been laid out */
173 unsigned int prepend
:1; /* prepend=1, append=0 (for parsers) */
174 WMAlignment alignment
:2; /* the alignment for text */
175 WMReliefType relief
:3; /* the relief to display with */
176 unsigned int RESERVED
:12;
181 static char *default_bullet
[] = {
183 " c None s None", ". c black",
184 "X c white", "o c #808080",
194 sectionWasSelected(Text
*tPtr
, TextBlock
*tb
, XRectangle
*rect
, int s
)
196 unsigned short i
, w
, lw
, selected
= False
;
202 /* if selection rectangle completely encloses the section */
203 if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
204 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
205 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
207 sel
.w
= tPtr
->visible
.w
;
210 /* or if it starts on a line and then goes further down */
211 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
212 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
213 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
214 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
215 >= tPtr
->visible
.y
+ tPtr
->sel
.y
) ) {
217 sel
.w
= tPtr
->visible
.w
;
220 /* or if it begins before a line, but ends on it */
221 } else if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
222 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
223 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
224 && (tb
->sections
[s
]._y
225 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
228 sel
.w
= tPtr
->sel
.x
+ tPtr
->sel
.w
;
231 /* or if the selection rectangle lies entirely within a line */
232 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
233 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
234 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
244 /* if not within (modified) selection rectangle */
245 if ( tb
->sections
[s
].x
> sel
.x
+ sel
.w
246 || tb
->sections
[s
].x
+ tb
->sections
[s
].w
< sel
.x
)
251 if ( tb
->sections
[s
].x
+ tb
->sections
[s
].w
<= sel
.x
+ sel
.w
252 && tb
->sections
[s
].x
>= sel
.x
) {
253 rect
->width
= tb
->sections
[s
].w
;
254 rect
->x
= tb
->sections
[s
].x
;
260 i
= tb
->sections
[s
].begin
;
263 //if ( tb->sections[s].x >= sel.x)
266 while (++i
<= tb
->sections
[s
].end
) {
268 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
271 if (lw
+ tb
->sections
[s
].x
>= sel
.x
272 || i
== tb
->sections
[s
].end
) {
275 tb
->s_begin
= (tb
->selected
? WMIN(tb
->s_begin
, i
) : i
);
280 if (i
> tb
->sections
[s
].end
) {
281 printf("WasSelected: (i > tb->sections[s].end) \n");
287 rect
->x
= tb
->sections
[s
].x
+ lw
;
289 while(++i
<= tb
->sections
[s
].end
) {
291 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
294 if (lw
+ rect
->x
>= sel
.x
+ sel
.w
295 || i
== tb
->sections
[s
].end
) {
297 if (i
!= tb
->sections
[s
].end
) {
302 tb
->s_end
= (tb
->selected
? WMAX(tb
->s_end
, i
) : i
);
311 rect
->y
= tb
->sections
[s
]._y
- tPtr
->vpos
;
312 rect
->height
= tb
->sections
[s
].h
;
319 removeSelection(Text
*tPtr
)
321 TextBlock
*tb
= NULL
;
323 if (!(tb
= tPtr
->firstTextBlock
))
329 if ( (tb
->s_end
- tb
->s_begin
== tb
->used
) || tb
->graphic
) {
330 tPtr
->currentTextBlock
= tb
;
331 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
332 tb
= tPtr
->currentTextBlock
;
337 } else if (tb
->s_end
<= tb
->used
) {
338 memmove(&(tb
->text
[tb
->s_begin
]),
339 &(tb
->text
[tb
->s_end
]), tb
->used
- tb
->s_end
);
340 tb
->used
-= (tb
->s_end
- tb
->s_begin
);
341 tb
->selected
= False
;
342 tPtr
->tpos
= tb
->s_begin
;
353 paintText(Text
*tPtr
)
355 TextBlock
*tb
= tPtr
->firstTextBlock
;
359 int len
, y
, c
, s
, done
=False
;
361 WMScreen
*scr
= tPtr
->view
->screen
;
362 Display
*dpy
= tPtr
->view
->screen
->display
;
363 Window win
= tPtr
->view
->window
;
365 if (!tPtr
->view
->flags
.realized
|| !tPtr
->db
|| tPtr
->flags
.frozen
)
368 XFillRectangle(dpy
, tPtr
->db
, tPtr
->bgGC
,
369 0, 0, WMWidgetWidth(tPtr
), WMWidgetWidth(tPtr
));
370 //tPtr->visible.w, tPtr->visible.h);
372 tb
= tPtr
->firstTextBlock
;
377 if (tPtr
->flags
.ownsSelection
)
378 greyGC
= WMColorGC(WMGrayColor(scr
));
382 while (!done
&& tb
) {
389 tb
->selected
= False
;
391 for(s
=0; s
<tb
->nsections
&& !done
; s
++) {
393 if (tb
->sections
[s
]._y
> tPtr
->vpos
+ tPtr
->visible
.h
) {
398 if ( tb
->sections
[s
].y
+ tb
->sections
[s
].h
< tPtr
->vpos
)
401 if (tPtr
->flags
.monoFont
) {
406 gc
= WMColorGC(tb
->color
);
409 if (tPtr
->flags
.ownsSelection
) {
412 if ( sectionWasSelected(tPtr
, tb
, &rect
, s
)) {
414 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
415 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
419 prev_y
= tb
->sections
[s
]._y
;
421 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
422 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
423 y
= tb
->sections
[s
].y
- tPtr
->vpos
;
424 WMDrawString(scr
, tPtr
->db
, gc
, font
,
425 tb
->sections
[s
].x
, y
, text
, len
);
427 if (tb
->underlined
) {
428 XDrawLine(dpy
, tPtr
->db
, gc
,
429 tb
->sections
[s
].x
, y
+ font
->y
+ 1,
430 tb
->sections
[s
].x
+ tb
->sections
[s
].w
, y
+ font
->y
+ 1);
435 tb
= (!done
? tb
->next
: NULL
);
439 c
= WMGetBagItemCount(tPtr
->gfxItems
);
440 if (c
> 0 && !tPtr
->flags
.monoFont
) {
444 tb
= (TextBlock
*) WMGetFromBag(tPtr
->gfxItems
, j
);
445 if (tb
->sections
[0]._y
+ tb
->sections
[0].h
<= tPtr
->vpos
446 || tb
->sections
[0]._y
>= tPtr
->vpos
+ tPtr
->visible
.h
) {
449 if ((W_VIEW(tb
->d
.widget
))->flags
.mapped
) {
450 WMUnmapWidget(tb
->d
.widget
);
455 if (!(W_VIEW(tb
->d
.widget
))->flags
.mapped
) {
456 if (!(W_VIEW(tb
->d
.widget
))->flags
.realized
)
457 WMRealizeWidget(tb
->d
.widget
);
458 WMMapWidget(tb
->d
.widget
);
459 WMLowerWidget(tb
->d
.widget
);
463 if (tPtr
->flags
.ownsSelection
) {
466 if ( sectionWasSelected(tPtr
, tb
, &rect
, s
)) {
468 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
469 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
474 WMMoveWidget(tb
->d
.widget
,
475 3 + tb
->sections
[0].x
+ tPtr
->visible
.x
,
476 tb
->sections
[0].y
+ tPtr
->visible
.y
- tPtr
->vpos
);
477 h
= WMWidgetHeight(tb
->d
.widget
) + 1;
479 WMDrawPixmap(tb
->d
.pixmap
, tPtr
->db
,
480 tb
->sections
[0].x
, tb
->sections
[0].y
- tPtr
->vpos
);
481 h
= tb
->d
.pixmap
->height
+ 1;
484 if (tb
->underlined
) {
485 XDrawLine(dpy
, tPtr
->db
, WMColorGC(tb
->color
),
487 tb
->sections
[0].y
+ h
,
488 tb
->sections
[0].x
+ tb
->sections
[0].w
,
489 tb
->sections
[0].y
+ h
);
494 if (tPtr
->flags
.editable
&& tPtr
->flags
.cursorShown
495 && tPtr
->cursor
.x
!= -23 && tPtr
->flags
.focused
) {
496 int y
= tPtr
->cursor
.y
- tPtr
->vpos
;
497 XDrawLine(dpy
, tPtr
->db
, tPtr
->fgGC
,
499 tPtr
->cursor
.x
, y
+ tPtr
->cursor
.h
);
502 XCopyArea(dpy
, tPtr
->db
, win
, tPtr
->bgGC
,
504 tPtr
->visible
.w
, tPtr
->visible
.h
,
505 tPtr
->visible
.x
, tPtr
->visible
.y
);
507 W_DrawRelief(scr
, win
, 0, 0,
508 tPtr
->view
->size
.width
, tPtr
->view
->size
.height
,
511 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)
514 tPtr
->view
->size
.width
-4, 42);
521 #define CURSOR_BLINK_ON_DELAY 600
522 #define CURSOR_BLINK_OFF_DELAY 400
525 blinkCursor(void *data
)
527 Text
*tPtr
= (Text
*)data
;
529 if (tPtr
->flags
.cursorShown
) {
530 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY
,
533 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
,
537 tPtr
->flags
.cursorShown
= !tPtr
->flags
.cursorShown
;
542 getFirstNonGraphicBlockFor(TextBlock
*tb
, short dir
)
549 tb
= (dir
? tb
->next
: tb
->prior
);
557 cursorToTextPosition(Text
*tPtr
, int x
, int y
)
559 TextBlock
*tb
= NULL
;
560 int done
=False
, s
, pos
, len
, _w
, _y
, dir
=1; /* 1 == "down" */
563 y
+= (tPtr
->vpos
- tPtr
->visible
.y
);
567 x
-= (tPtr
->visible
.x
- 2);
571 /* clicked is relative to document, not window... */
575 if (! (tb
= tPtr
->currentTextBlock
)) {
576 if (! (tb
= tPtr
->firstTextBlock
)) {
578 tPtr
->cursor
.h
= tPtr
->dFont
->height
;
585 /* first, which direction? Most likely, newly clicked
586 position will be close to previous */
587 dir
= !(y
<= tb
->sections
[0].y
);
588 if ( ( y
<= tb
->sections
[0]._y
+ tb
->sections
[0].h
)
589 && (y
>= tb
->sections
[0]._y
) ) {
590 /* if it's on the same line */
591 if(x
< tb
->sections
[0].x
)
593 if(x
>= tb
->sections
[0].x
)
597 tb
= tPtr
->firstTextBlock
;
600 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
601 tb
= getFirstNonGraphicBlockFor(tb
, 1);
603 tPtr
->currentTextBlock
=
604 (dir
? tPtr
->lastTextBlock
: tPtr
->firstTextBlock
);
610 s
= (dir
? 0 : tb
->nsections
-1);
611 if ( y
>= tb
->sections
[s
]._y
612 && y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) {
616 /* get the first section of the TextBlock that lies about
617 the vertical click point */
619 while (!done
&& tb
) {
621 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
627 s
= (dir
? 0 : tb
->nsections
-1);
628 while (!done
&& (dir
? (s
<tb
->nsections
) : (s
>=0) )) {
630 if ( (dir
? (y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) :
631 ( y
>= tb
->sections
[s
]._y
) ) ) {
639 if ( (dir
? tb
->next
: tb
->prior
)) {
640 tb
= (dir
? tb
->next
: tb
->prior
);
643 break; //goto _doneH;
649 if (s
<0 || s
>=tb
->nsections
) {
650 s
= (dir
? tb
->nsections
-1 : 0);
654 /* we have the line, which TextBlock on that line is it? */
656 if (tPtr
->flags
.monoFont
&& tb
->graphic
)
657 tb
= getFirstNonGraphicBlockFor(tb
, dir
);
659 if ((dir
? tb
->sections
[s
].x
>= x
: tb
->sections
[s
].x
< x
))
667 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
668 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
669 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
671 printf("here %d %d \n", tb
->sections
[s
].x
+ _w
, x
);
672 if ((dir
? tb
->sections
[s
].x
+ _w
< x
: tb
->sections
[s
].x
+ _w
>= x
)) {
673 pos
= tb
->sections
[s
].end
;
674 tPtr
->cursor
.x
= tb
->sections
[s
].x
+ _w
;
678 _y
= tb
->sections
[s
]._y
;
683 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
684 tb
= (dir
? tb
->next
: tb
->prior
);
691 _w
= WMWidgetWidth(tb
->d
.widget
);
693 _w
= tb
->d
.pixmap
->width
;
695 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
696 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
697 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
698 if (tb
->sections
[s
].x
+ _w
>= x
)
703 if (tb
->sections
[s
].x
<= x
)
707 if ((dir
? tb
->next
: tb
->prior
)) {
708 TextBlock
*nxt
= (dir
? tb
->next
: tb
->prior
);
709 if (tPtr
->flags
.monoFont
&& nxt
->graphic
) {
710 nxt
= getFirstNonGraphicBlockFor(nxt
, dir
);
713 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
718 if (_y
!= nxt
->sections
[0]._y
) {
719 /* this must be the last/first on this line. stop */
720 pos
= (dir
? tb
->sections
[s
].end
: 0);
721 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
725 tPtr
->cursor
.x
+= WMWidgetWidth(tb
->d
.widget
);
727 tPtr
->cursor
.x
+= tb
->d
.pixmap
->width
;
728 } else if (pos
> tb
->sections
[s
].begin
) {
730 WMWidthOfString(tb
->d
.font
,
731 &(tb
->text
[tb
->sections
[s
].begin
]),
732 pos
- tb
->sections
[s
].begin
);
739 if ( (dir
? tb
->next
: tb
->prior
)) {
740 tb
= (dir
? tb
->next
: tb
->prior
);
747 s
= (dir
? 0 : tb
->nsections
-1);
750 /* we have said TextBlock, now where within it? */
751 if (tb
&& !tb
->graphic
) {
752 WMFont
*f
= tb
->d
.font
;
753 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
754 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
756 _w
= x
- tb
->sections
[s
].x
;
759 while (pos
<len
&& WMWidthOfString(f
, text
, pos
+1) < _w
)
762 tPtr
->cursor
.x
= tb
->sections
[s
].x
+
763 (pos
? WMWidthOfString(f
, text
, pos
) : 0);
765 pos
+= tb
->sections
[s
].begin
;
767 tPtr
->tpos
= (pos
<tb
->used
)? pos
: tb
->used
;
770 tPtr
->currentTextBlock
= tb
;
771 tPtr
->cursor
.h
= tb
->sections
[s
].h
;
772 tPtr
->cursor
.y
= tb
->sections
[s
]._y
;
775 printf("will hang :-)\n");
780 updateScrollers(Text
*tPtr
)
783 if (tPtr
->flags
.frozen
)
787 if (tPtr
->docHeight
< tPtr
->visible
.h
) {
788 WMSetScrollerParameters(tPtr
->vS
, 0, 1);
791 float vmax
= (float)(tPtr
->docHeight
);
792 WMSetScrollerParameters(tPtr
->vS
,
793 ((float)tPtr
->vpos
)/(vmax
- (float)tPtr
->visible
.h
),
794 (float)tPtr
->visible
.h
/vmax
);
796 } else tPtr
->vpos
= 0;
803 scrollersCallBack(WMWidget
*w
, void *self
)
805 Text
*tPtr
= (Text
*)self
;
810 if (!tPtr
->view
->flags
.realized
|| tPtr
->flags
.frozen
)
816 vmax
= (float)(tPtr
->docHeight
);
817 height
= tPtr
->visible
.h
;
819 which
= WMGetScrollerHitPart(tPtr
->vS
);
821 case WSDecrementLine
:
822 if (tPtr
->vpos
> 0) {
823 if (tPtr
->vpos
>16) tPtr
->vpos
-=16;
827 case WSIncrementLine
: {
828 int limit
= tPtr
->docHeight
- height
;
829 if (tPtr
->vpos
< limit
) {
830 if (tPtr
->vpos
<limit
-16) tPtr
->vpos
+=16;
831 else tPtr
->vpos
=limit
;
834 case WSDecrementPage
:
835 tPtr
->vpos
-= height
;
841 printf("dimple needs to jump to mouse location ;-/\n");
843 case WSIncrementPage
:
844 tPtr
->vpos
+= height
;
845 if (tPtr
->vpos
> (tPtr
->docHeight
- height
))
846 tPtr
->vpos
= tPtr
->docHeight
- height
;
849 printf("dimple needs to jump to mouse location ;-/\n");
854 tPtr
->vpos
= WMGetScrollerValue(tPtr
->vS
)
855 * (float)(tPtr
->docHeight
- height
);
861 printf("WSNoPart, WSKnobSlot\n");
863 float vmax
= (float)(tPtr
->docHeight
);
864 ((float)tPtr
->vpos
)/(vmax
- (float)tPtr
->visible
.h
),
865 (float)tPtr
->visible
.h
/vmax
;
866 dimple
=where mouse is
.
870 scroll
= (tPtr
->vpos
!= tPtr
->prevVpos
);
871 tPtr
->prevVpos
= tPtr
->vpos
;
880 if (tPtr->rulerShown)
881 XClearArea(tPtr->view->screen->display, tPtr->view->window, 22, 47,
882 tPtr->view->size.width-24, tPtr->view->size.height-49, True);
884 XClearArea(tPtr->view->screen->display, tPtr->view->window, 22, 2,
885 tPtr->view->size.width-24, tPtr->view->size.height-4, True);
888 if (dimple
|| which
== WSDecrementLine
|| which
== WSIncrementLine
)
889 updateScrollers(tPtr
);
898 unsigned short begin
, end
; /* what part of the text block */
903 layOutLine(Text
*tPtr
, myLineItems
*items
, int nitems
,
904 int x
, int y
, int pwidth
)
906 int i
, j
=0, lw
= 0, line_height
=0, max_d
=0, len
, n
;
910 TextBlock
*tbsame
=NULL
;
912 for(i
=0; i
<nitems
; i
++) {
916 if (!tPtr
->flags
.monoFont
) {
918 WMWidget
*wdt
= tb
->d
.widget
;
919 line_height
= WMAX(line_height
, WMWidgetHeight(wdt
));
920 if (tPtr
->flags
.alignment
!= WALeft
)
921 lw
+= WMWidgetWidth(wdt
);
923 line_height
= WMAX(line_height
, tb
->d
.pixmap
->height
+ max_d
);
924 if (tPtr
->flags
.alignment
!= WALeft
)
925 lw
+= tb
->d
.pixmap
->width
;
930 font
= (tPtr
->flags
.monoFont
)?tPtr
->dFont
: tb
->d
.font
;
931 max_d
= WMAX(max_d
, abs(font
->height
-font
->y
));
932 line_height
= WMAX(line_height
, font
->height
+ max_d
);
933 text
= &(tb
->text
[items
[i
].begin
]);
934 len
= items
[i
].end
- items
[i
].begin
;
935 if (tPtr
->flags
.alignment
!= WALeft
)
936 lw
+= WMWidthOfString(font
, text
, len
);
940 if (tPtr
->flags
.alignment
== WARight
) {
942 } else if (tPtr
->flags
.alignment
== WACenter
) {
943 j
= (int) ((float)(pwidth
- lw
))/2.0;
946 for(i
=0; i
<nitems
; i
++) {
949 if (tbsame
== tb
) { /*extend it, since it's on same line */
950 tb
->sections
[tb
->nsections
-1].end
= items
[i
].end
;
953 tb
->sections
= wrealloc(tb
->sections
,
954 (++tb
->nsections
)*sizeof(Section
));
956 tb
->sections
[n
]._y
= y
+ max_d
;
957 tb
->sections
[n
].x
= x
+j
;
958 tb
->sections
[n
].h
= line_height
;
959 tb
->sections
[n
].begin
= items
[i
].begin
;
960 tb
->sections
[n
].end
= items
[i
].end
;
963 tb
->sections
[n
].last
= (i
+1==nitems
);
966 if (!tPtr
->flags
.monoFont
) {
968 WMWidget
*wdt
= tb
->d
.widget
;
969 tb
->sections
[n
].y
= max_d
+ y
+ line_height
- WMWidgetHeight(wdt
);
970 tb
->sections
[n
].w
= WMWidgetWidth(wdt
);
972 tb
->sections
[n
].y
= y
+ max_d
;// + line_height - tb->d.pixmap->height;
973 tb
->sections
[n
].w
= tb
->d
.pixmap
->width
;
975 x
+= tb
->sections
[n
].w
;
978 font
= (tPtr
->flags
.monoFont
)? tPtr
->dFont
: tb
->d
.font
;
979 len
= items
[i
].end
- items
[i
].begin
;
980 text
= &(tb
->text
[items
[i
].begin
]);
982 tb
->sections
[n
].y
= y
+line_height
-font
->y
;
984 WMWidthOfString(font
,
985 &(tb
->text
[tb
->sections
[n
].begin
]),
986 tb
->sections
[n
].end
- tb
->sections
[n
].begin
);
988 x
+= WMWidthOfString(font
, text
, len
);
1000 output(char *ptr
, int len
)
1003 memcpy(s
, ptr
, len
);
1005 //printf(" s is [%s] (%d)\n", s, strlen(s));
1006 printf("[%s]\n", s
);
1010 /* tb->text doesn't necessarily end in '\0' hmph! (strchr) */
1011 static inline char *
1012 mystrchr(char *s
, char needle
, unsigned short len
)
1016 if (!haystack
|| len
< 1)
1019 while ( (int) (haystack
- s
) < len
) {
1020 if (*haystack
== needle
)
1027 #define MAX_TB_PER_LINE 64
1030 layOutDocument(Text
*tPtr
)
1033 myLineItems items
[MAX_TB_PER_LINE
];
1035 Bool lhc
= !tPtr
->flags
.laidOut
; /* line height changed? */
1038 int nitems
=0, x
=0, y
=0, lw
= 0, width
=0;
1039 int pwidth
= tPtr
->visible
.w
- tPtr
->visible
.x
;
1041 char *start
=NULL
, *mark
=NULL
;
1044 if (tPtr
->flags
.frozen
)
1047 if (!(tb
= tPtr
->firstTextBlock
))
1050 if (0&&tPtr
->flags
.laidOut
) {
1051 tb
= tPtr
->currentTextBlock
;
1052 if (tb
->sections
&& tb
->nsections
>0)
1053 prev_y
= tb
->sections
[tb
->nsections
-1]._y
;
1055 printf("1 prev_y %d \n", prev_y
);
1057 /* search backwards for textblocks on same line */
1059 if (!tb
->sections
|| tb
->nsections
<1) {
1060 tb
= tPtr
->firstTextBlock
;
1063 if (tb
->sections
[tb
->nsections
-1]._y
!= prev_y
) {
1067 // prev_y = tb->sections[tb->nsections-1]._y;
1070 y
= 0;//tb->sections[tb->nsections-1]._y;
1071 printf("2 prev_y %d \n\n", tb
->sections
[tb
->nsections
-1]._y
);
1077 if (tb
->sections
&& tb
->nsections
>0) {
1078 wfree(tb
->sections
);
1079 tb
->sections
= NULL
;
1084 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
, pwidth
);
1085 x
= 0;//tPtr->visible.x+2;
1091 if (!tPtr
->flags
.monoFont
) {
1093 width
= WMWidgetWidth(tb
->d
.widget
);
1095 width
= tb
->d
.pixmap
->width
;
1097 if (width
> pwidth
)printf("rescale graphix to fit?\n");
1099 if (lw
>= pwidth
- x
1100 || nitems
>= MAX_TB_PER_LINE
) {
1101 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
, pwidth
);
1103 x
= 0;//tPtr->visible.x+2;
1107 items
[nitems
].tb
= tb
;
1108 items
[nitems
].begin
= 0;
1109 items
[nitems
].end
= 0;
1113 } else if ((start
= tb
->text
)) {
1115 font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
1118 mark
= mystrchr(start
, ' ', tb
->used
);
1120 end
+= (int)(mark
-start
)+1;
1123 end
+= strlen(start
);
1130 if (end
-begin
> 0) {
1132 width
= WMWidthOfString(font
,
1133 &tb
->text
[begin
], end
-begin
);
1135 if (width
> pwidth
) { /* break this tb up */
1136 char *t
= &tb
->text
[begin
];
1137 int l
=end
-begin
, i
=0;
1139 width
= WMWidthOfString(font
, t
, ++i
);
1140 } while (width
< pwidth
&& i
< l
);
1142 if (start
) // and since (nil)-4 = 0xfffffffd
1149 if ((lw
>= pwidth
- x
)
1150 || nitems
>= MAX_TB_PER_LINE
) {
1151 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
, pwidth
);
1153 x
= 0; //tPtr->visible.x+2;
1157 items
[nitems
].tb
= tb
;
1158 items
[nitems
].begin
= begin
;
1159 items
[nitems
].end
= end
;
1170 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
, pwidth
);
1172 tPtr
->docHeight
= y
+10;
1173 updateScrollers(tPtr
);
1175 tPtr
->flags
.laidOut
= True
;
1181 textDidResize(W_ViewDelegate
*self
, WMView
*view
)
1183 Text
*tPtr
= (Text
*)view
->self
;
1184 unsigned short w
= WMWidgetWidth(tPtr
);
1185 unsigned short h
= WMWidgetHeight(tPtr
);
1186 unsigned short rh
= 0, vw
= 0;
1188 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
) {
1189 WMMoveWidget(tPtr
->ruler
, 2, 2);
1190 WMResizeWidget(tPtr
->ruler
, w
- 4, 40);
1195 WMMoveWidget(tPtr
->vS
, 1, rh
+ 2);
1196 WMResizeWidget(tPtr
->vS
, 20, h
- rh
- 3);
1198 WMSetRulerOffset(tPtr
->ruler
,22);
1199 } else WMSetRulerOffset(tPtr
->ruler
, 2);
1203 WMMoveWidget(tPtr
->hS
, vw
, h
- 21);
1204 WMResizeWidget(tPtr
->hS
, w
- vw
- 1, 20);
1206 WMMoveWidget(tPtr
->hS
, vw
+1, h
- 21);
1207 WMResizeWidget(tPtr
->hS
, w
- vw
- 2, 20);
1211 tPtr
->visible
.x
= (tPtr
->vS
)?22:2;
1212 tPtr
->visible
.y
= (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)?43:3;
1213 tPtr
->visible
.w
= tPtr
->view
->size
.width
- tPtr
->visible
.x
- 12;
1214 tPtr
->visible
.h
= tPtr
->view
->size
.height
- tPtr
->visible
.y
;
1215 tPtr
->visible
.h
-= (tPtr
->hS
)?20:0;
1217 tPtr
->dmargins
= WMGetRulerMargins(tPtr
->ruler
);
1219 if (tPtr
->view
->flags
.realized
) {
1222 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
1223 tPtr
->db
= (Pixmap
) NULL
;
1226 if (tPtr
->visible
.w
< 40)
1227 tPtr
->visible
.w
= 40;
1228 if (tPtr
->visible
.h
< 20)
1229 tPtr
->visible
.h
= 20;
1231 //if (size change or !db
1233 tPtr
->db
= XCreatePixmap(tPtr
->view
->screen
->display
,
1234 tPtr
->view
->window
, tPtr
->visible
.w
,
1235 tPtr
->visible
.h
, tPtr
->view
->screen
->depth
);
1239 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1242 W_ViewDelegate _TextViewDelegate
=
1250 /* nice, divisble-by-16 blocks */
1251 static inline unsigned short
1252 reqBlockSize(unsigned short requested
)
1254 return requested
+ 16 - (requested
%16);
1259 clearText(Text
*tPtr
)
1261 if (!tPtr
->firstTextBlock
)
1264 while (tPtr
->currentTextBlock
)
1265 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1267 tPtr
->firstTextBlock
= NULL
;
1268 tPtr
->currentTextBlock
= NULL
;
1269 tPtr
->lastTextBlock
= NULL
;
1273 deleteTextInteractively(Text
*tPtr
, KeySym ksym
)
1275 TextBlock
*tb
= tPtr
->currentTextBlock
;
1276 Bool back
= (Bool
) (ksym
== XK_BackSpace
);
1279 if (!tPtr
->flags
.editable
|| tPtr
->flags
.buttonHeld
) {
1280 XBell(tPtr
->view
->screen
->display
, 0);
1287 if (tPtr
->flags
.ownsSelection
) {
1288 removeSelection(tPtr
);
1292 if (back
&& tPtr
->tpos
< 1) {
1295 tPtr
->tpos
= tb
->used
;
1296 tPtr
->currentTextBlock
= tb
;
1301 if ( (tb
->used
> 0) && ((back
?tPtr
->tpos
> 0:1))
1302 && (tPtr
->tpos
<= tb
->used
) && !tb
->graphic
) {
1305 memmove(&(tb
->text
[tPtr
->tpos
]),
1306 &(tb
->text
[tPtr
->tpos
+ 1]), tb
->used
- tPtr
->tpos
);
1311 if ( (back
? (tPtr
->tpos
< 1 && !done
) : ( tPtr
->tpos
>= tb
->used
))
1314 TextBlock
*sibling
= (back
? tb
->prior
: tb
->next
);
1316 if(tb
->used
== 0 || tb
->graphic
)
1317 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1320 tPtr
->currentTextBlock
= sibling
;
1321 tPtr
->tpos
= (back
? sibling
->used
: 0);
1328 insertTextInteractively(Text
*tPtr
, char *text
, int len
)
1331 char *newline
= NULL
;
1333 if (!tPtr
->flags
.editable
|| tPtr
->flags
.buttonHeld
) {
1334 XBell(tPtr
->view
->screen
->display
, 0);
1339 WMColor
*color
= WMCreateNamedColor(W_VIEW_SCREEN(tPtr
->view
),
1341 WMSetTextSelectionColor(tPtr
, color
);
1345 if (len
< 1 || !text
)
1348 if (tPtr
->flags
.ownsSelection
)
1349 removeSelection(tPtr
);
1351 if(tPtr
->flags
.ignoreNewLine
&& *text
== '\n' && len
== 1)
1354 if (tPtr
->flags
.ignoreNewLine
) {
1356 for(i
=0; i
<len
; i
++) {
1357 if (text
[i
] == '\n')
1362 tb
= tPtr
->currentTextBlock
;
1363 if (!tb
|| tb
->graphic
) {
1365 WMAppendTextStream(tPtr
, text
);
1366 if (tPtr
->currentTextBlock
) {
1367 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
1372 if ((newline
= strchr(text
, '\n'))) {
1373 int nlen
= (int)(newline
-text
);
1374 int s
= tb
->used
- tPtr
->tpos
;
1377 if (!tb
->blank
&& nlen
>0) {
1379 memcpy(save
, &tb
->text
[tPtr
->tpos
], s
);
1380 tb
->used
-= (tb
->used
- tPtr
->tpos
);
1383 insertTextInteractively(tPtr
, text
, nlen
);
1385 WMAppendTextStream(tPtr
, newline
);
1387 insertTextInteractively(tPtr
, save
, s
);
1390 if (tPtr
->tpos
>0 && tPtr
->tpos
< tb
->used
1391 && !tb
->graphic
&& tb
->text
) {
1393 void *ntb
= WMCreateTextBlockWithText(&tb
->text
[tPtr
->tpos
],
1394 tb
->d
.font
, tb
->color
, True
, tb
->used
- tPtr
->tpos
);
1395 tb
->used
= tPtr
->tpos
;
1396 WMAppendTextBlock(tPtr
, ntb
);
1398 } else if (tPtr
->tpos
== tb
->used
|| tPtr
->tpos
== 0) {
1399 void *ntb
= WMCreateTextBlockWithText(NULL
,
1400 tb
->d
.font
, tb
->color
, True
, 0);
1403 WMAppendTextBlock(tPtr
, ntb
);
1405 WMPrependTextBlock(tPtr
, ntb
);
1412 if (tb
->used
+ len
>= tb
->allocated
) {
1413 tb
->allocated
= reqBlockSize(tb
->used
+len
);
1414 tb
->text
= wrealloc(tb
->text
, tb
->allocated
);
1418 memcpy(tb
->text
, text
, len
);
1423 memmove(&(tb
->text
[tPtr
->tpos
+len
]), &tb
->text
[tPtr
->tpos
],
1424 tb
->used
-tPtr
->tpos
+1);
1425 memmove(&tb
->text
[tPtr
->tpos
], text
, len
);
1435 selectRegion(Text
*tPtr
, int x
, int y
)
1442 y
+= (tPtr
->flags
.rulerShown
? 40: 0);
1445 y
-= 10; /* the original offset */
1447 x
-= tPtr
->visible
.x
-2;
1451 tPtr
->sel
.x
= WMAX(0, WMIN(tPtr
->clicked
.x
, x
));
1452 tPtr
->sel
.w
= abs(tPtr
->clicked
.x
- x
);
1453 tPtr
->sel
.y
= WMAX(0, WMIN(tPtr
->clicked
.y
, y
));
1454 tPtr
->sel
.h
= abs(tPtr
->clicked
.y
- y
);
1456 tPtr
->flags
.ownsSelection
= True
;
1462 pasteText(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
1463 void *cdata
, WMData
*data
)
1465 Text
*tPtr
= (Text
*)view
->self
;
1468 tPtr
->flags
.waitingForSelection
= False
;
1471 str
= (char*)WMDataBytes(data
);
1472 if (0&&tPtr
->parser
) {
1473 /* parser is not yet well behaved to do this properly..*/
1474 (tPtr
->parser
) (tPtr
, (void *) str
);
1476 insertTextInteractively(tPtr
, str
, strlen(str
));
1478 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1481 str
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
1484 if (0&&tPtr
->parser
) {
1485 /* parser is not yet well behaved to do this properly..*/
1486 (tPtr
->parser
) (tPtr
, (void *) str
);
1488 insertTextInteractively(tPtr
, str
, n
);
1490 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1498 releaseSelection(Text
*tPtr
)
1500 TextBlock
*tb
= tPtr
->firstTextBlock
;
1503 tb
->selected
= False
;
1506 tPtr
->flags
.ownsSelection
= False
;
1507 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
,
1514 requestHandler(WMView
*view
, Atom selection
, Atom target
,
1515 void *cdata
, Atom
*type
)
1517 Text
*tPtr
= view
->self
;
1518 Display
*dpy
= tPtr
->view
->screen
->display
;
1519 Atom TEXT
= XInternAtom(dpy
, "TEXT", False
);
1520 Atom COMPOUND_TEXT
= XInternAtom(dpy
, "COMPOUND_TEXT", False
);
1523 if (target
== XA_STRING
|| target
== TEXT
|| target
== COMPOUND_TEXT
) {
1524 char *text
= WMGetTextSelected(tPtr
);
1525 WMData
*data
= WMCreateDataWithBytes(text
, strlen(text
));
1529 Atom PIXMAP
= XInternAtom(dpy
, "PIXMAP", False
);
1530 WMData
*data
= WMCreateDataWithBytes("bleh", 4);
1531 if(target
== PIXMAP
) {
1532 printf("whoa! pixmap\n");
1542 lostHandler(WMView
*view
, Atom selection
, void *cdata
)
1544 releaseSelection((WMText
*)view
->self
);
1547 static WMSelectionProcs selectionHandler
= {
1548 requestHandler
, lostHandler
, NULL
1552 ownershipObserver(void *observerData
, WMNotification
*notification
)
1554 WMText
*to
= (WMText
*)observerData
;
1555 WMText
*tw
= (WMText
*)WMGetNotificationClientData(notification
);
1557 lostHandler(to
->view
, XA_PRIMARY
, NULL
);
1562 handleTextKeyPress(Text
*tPtr
, XEvent
*event
)
1566 int control_pressed
= False
;
1569 if (((XKeyEvent
*) event
)->state
& ControlMask
)
1570 control_pressed
= True
;
1571 buffer
[XLookupString(&event
->xkey
, buffer
, 1, &ksym
, NULL
)] = 0;
1577 TextBlock
*tb
= tPtr
->currentTextBlock
;
1578 int x
= tPtr
->cursor
.x
+ tPtr
->visible
.x
;
1579 int y
= tPtr
->visible
.y
+ tPtr
->cursor
.y
+ tPtr
->cursor
.h
;
1587 w
= WMWidgetWidth(tb
->d
.widget
);
1589 w
= tb
->d
.pixmap
->width
;
1593 w
= WMWidthOfString(tb
->d
.font
, &tb
->text
[pos
], 1);
1596 cursorToTextPosition(tPtr
, w
+ tPtr
->cursor
.x
+ tPtr
->visible
.x
,
1597 3 + tPtr
->visible
.y
+ tPtr
->cursor
.y
1598 + tPtr
->cursor
.h
- tPtr
->vpos
);
1599 if(x
== tPtr
->cursor
.x
+ tPtr
->visible
.x
) {
1600 printf("same %d %d\n", x
, tPtr
->cursor
.x
+ tPtr
->visible
.x
);
1601 cursorToTextPosition(tPtr
, tPtr
->visible
.x
,
1602 3 + tPtr
->visible
.y
+ tPtr
->cursor
.y
+ tPtr
->cursor
.h
);
1610 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
1611 tPtr
->clicked
.y
+ tPtr
->cursor
.h
- tPtr
->vpos
);
1616 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
1617 tPtr
->visible
.y
+ tPtr
->cursor
.y
- tPtr
->vpos
- 3);
1624 deleteTextInteractively(tPtr
, ksym
);
1625 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1630 control_pressed
= True
;
1636 if (buffer
[0] != 0 && !control_pressed
) {
1637 insertTextInteractively(tPtr
, buffer
, 1);
1638 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1640 } else if (control_pressed
&& ksym
==XK_r
) {
1641 Bool i
= !tPtr
->flags
.rulerShown
;
1642 WMShowTextRuler(tPtr
, i
);
1643 tPtr
->flags
.rulerShown
= i
;
1645 else if (control_pressed
&& buffer
[0] == '\a')
1646 XBell(tPtr
->view
->screen
->display
, 0);
1649 if (!control_pressed
&& tPtr
->flags
.ownsSelection
)
1650 releaseSelection(tPtr
);
1654 handleWidgetPress(XEvent
*event
, void *data
)
1656 TextBlock
*tb
= (TextBlock
*)data
;
1662 /* this little bit of nastiness here saves a boatload of trouble */
1663 w
= (WMWidget
*)(((W_VIEW(tb
->d
.widget
))->parent
)->self
);
1664 if (W_CLASS(w
) != WC_Text
)
1667 tPtr
->currentTextBlock
= getFirstNonGraphicBlockFor(tb
, 1);
1668 if (!tPtr
->currentTextBlock
)
1669 tPtr
->currentTextBlock
= tb
;
1671 output(tPtr
->currentTextBlock
->text
, tPtr
->currentTextBlock
->used
);
1672 //if (!tPtr->flags.focused) {
1673 // WMSetFocusToWidget(tPtr);
1674 // tPtr->flags.focused = True;
1680 handleActionEvents(XEvent
*event
, void *data
)
1682 Text
*tPtr
= (Text
*)data
;
1683 Display
*dpy
= event
->xany
.display
;
1687 switch (event
->type
) {
1689 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
1690 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
1691 tPtr
->flags
.extendSelection
= True
;
1695 if (tPtr
->flags
.waitingForSelection
)
1697 if (tPtr
->flags
.focused
) {
1698 XGrabPointer(dpy
, W_VIEW(tPtr
)->window
, False
,
1699 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
1700 GrabModeAsync
, GrabModeAsync
, None
,
1701 tPtr
->view
->screen
->invisibleCursor
, CurrentTime
);
1702 tPtr
->flags
.pointerGrabbed
= True
;
1703 handleTextKeyPress(tPtr
, event
);
1708 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
1709 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
1710 tPtr
->flags
.extendSelection
= False
;
1712 //end modify flag so selection can be extended
1718 if (tPtr
->flags
.pointerGrabbed
) {
1719 tPtr
->flags
.pointerGrabbed
= False
;
1720 XUngrabPointer(dpy
, CurrentTime
);
1723 if (tPtr
->flags
.ownsSelection
) {
1725 if(1//if (event->xmotion.x >= tPtr->sel.x
1726 //&& event->xmotion.x <= tPtr->sel.x + tPtr->sel.w
1727 )// && event->xmotion.y >= tPtr->sel.y
1728 // && event->xmotion.y <= tPtr->sel.y + tPtr->sel.w)
1732 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->textCursor
;
1735 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
1738 if ((event
->xmotion
.state
& Button1Mask
)) {
1739 if (!tPtr
->flags
.ownsSelection
) {
1740 WMCreateSelectionHandler(tPtr
->view
, XA_PRIMARY
,
1741 event
->xbutton
.time
, &selectionHandler
, NULL
);
1742 tPtr
->flags
.ownsSelection
= True
;
1744 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
1750 tPtr
->flags
.buttonHeld
= True
;
1751 if (tPtr
->flags
.extendSelection
) {
1752 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
1755 if (event
->xbutton
.button
== Button1
) {
1757 if (!tPtr
->flags
.focused
) {
1758 WMSetFocusToWidget(tPtr
);
1759 tPtr
->flags
.focused
= True
;
1762 if (tPtr
->flags
.ownsSelection
)
1763 releaseSelection(tPtr
);
1764 cursorToTextPosition(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
1766 if (tPtr
->flags
.pointerGrabbed
) {
1767 tPtr
->flags
.pointerGrabbed
= False
;
1768 XUngrabPointer(dpy
, CurrentTime
);
1773 if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelDown
)
1774 WMScrollText(tPtr
, -16);
1775 else if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelUp
)
1776 WMScrollText(tPtr
, 16);
1780 tPtr
->flags
.buttonHeld
= False
;
1781 if (tPtr
->flags
.pointerGrabbed
) {
1782 tPtr
->flags
.pointerGrabbed
= False
;
1783 XUngrabPointer(dpy
, CurrentTime
);
1786 if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelDown
1787 || event
->xbutton
.button
== WINGsConfiguration
.mouseWheelUp
)
1790 if (event
->xbutton
.button
== Button2
) {
1794 if (!tPtr
->flags
.editable
) {
1799 if (!WMRequestSelection(tPtr
->view
, XA_PRIMARY
, XA_STRING
,
1800 event
->xbutton
.time
, pasteText
, NULL
)) {
1801 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
1804 if (0&&tPtr
->parser
) {
1805 /* parser is not yet well behaved to do this properly..*/
1806 (tPtr
->parser
) (tPtr
, (void *) text
);
1808 insertTextInteractively(tPtr
, text
, n
-1);
1810 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1812 } else tPtr
->flags
.waitingForSelection
= True
;
1823 handleEvents(XEvent
*event
, void *data
)
1825 Text
*tPtr
= (Text
*)data
;
1827 switch(event
->type
) {
1831 if (!(W_VIEW(tPtr
->hS
))->flags
.realized
)
1832 WMRealizeWidget(tPtr
->hS
);
1833 if (!((W_VIEW(tPtr
->hS
))->flags
.mapped
))
1834 WMMapWidget(tPtr
->hS
);
1838 if (!(W_VIEW(tPtr
->vS
))->flags
.realized
)
1839 WMRealizeWidget(tPtr
->vS
);
1840 if (!((W_VIEW(tPtr
->vS
))->flags
.mapped
))
1841 WMMapWidget(tPtr
->vS
);
1845 if (!(W_VIEW(tPtr
->ruler
))->flags
.realized
)
1846 WMRealizeWidget(tPtr
->ruler
);
1848 if (!((W_VIEW(tPtr
->ruler
))->flags
.mapped
)
1849 && tPtr
->flags
.rulerShown
)
1850 WMMapWidget(tPtr
->ruler
);
1853 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
1855 if (!event
->xexpose
.count
&& tPtr
->view
->flags
.realized
)
1860 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))
1863 tPtr
->flags
.focused
= True
;
1865 if (tPtr
->flags
.editable
&& !tPtr
->timerID
) {
1866 tPtr
->timerID
= WMAddTimerHandler(12+0*CURSOR_BLINK_ON_DELAY
,
1874 tPtr
->flags
.focused
= False
;
1877 if (tPtr
->timerID
) {
1878 WMDeleteTimerHandler(tPtr
->timerID
);
1879 tPtr
->timerID
= NULL
;
1887 WMDestroyWidget(tPtr
->hS
);
1889 WMDestroyWidget(tPtr
->vS
);
1891 WMDestroyWidget(tPtr
->ruler
);
1893 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
1895 WMFreeBag(tPtr
->gfxItems
);
1898 WMDeleteTimerHandler(tPtr
->timerID
);
1900 WMReleaseFont(tPtr
->dFont
);
1901 WMReleaseColor(tPtr
->dColor
);
1902 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
, CurrentTime
);
1903 WMRemoveNotificationObserver(tPtr
);
1914 insertPlainText(WMText
*tPtr
, char *text
)
1926 mark
= strchr(start
, '\n');
1928 tb
= WMCreateTextBlockWithText(start
, tPtr
->dFont
,
1929 tPtr
->dColor
, True
, (int)(mark
-start
));
1932 if (start
&& strlen(start
)) {
1933 tb
= WMCreateTextBlockWithText(start
, tPtr
->dFont
,
1934 tPtr
->dColor
, False
, strlen(start
));
1939 if (tPtr
->flags
.prepend
)
1940 WMPrependTextBlock(tPtr
, tb
);
1942 WMAppendTextBlock(tPtr
, tb
);
1950 rulerMoveCallBack(WMWidget
*w
, void *self
)
1952 Text
*tPtr
= (Text
*)self
;
1955 if (W_CLASS(tPtr
) != WC_Text
)
1963 rulerReleaseCallBack(WMWidget
*w
, void *self
)
1965 Text
*tPtr
= (Text
*)self
;
1968 if (W_CLASS(tPtr
) != WC_Text
)
1971 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1978 draggingEntered(WMView
*self
, WMDraggingInfo
*info
)
1980 printf("draggingEntered\n");
1981 return WDOperationCopy
;
1986 draggingUpdated(WMView
*self
, WMDraggingInfo
*info
)
1988 printf("draggingUpdated\n");
1989 return WDOperationCopy
;
1994 draggingExited(WMView
*self
, WMDraggingInfo
*info
)
1996 printf("draggingExited\n");
2000 prepareForDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2002 printf("draggingExited\n");
2003 return;//"bll"; //"application/X-color";
2008 performDragOperation(WMView
*self
, WMDraggingInfo
*info
) //, WMData *data)
2010 char *colorName
= "Blue";// (char*)WMDataBytes(data);
2012 WMText
*tPtr
= (WMText
*)self
->self
;
2017 if (tPtr
->flags
.monoFont
)
2020 color
= WMCreateNamedColor(W_VIEW_SCREEN(self
), colorName
, True
);
2021 printf("color [%s] %p\n", colorName
, color
);
2023 WMSetTextSelectionColor(tPtr
, color
);
2024 WMReleaseColor(color
);
2031 concludeDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2033 printf("concludeDragOperation\n");
2037 static WMDragDestinationProcs _DragDestinationProcs
= {
2041 prepareForDragOperation
,
2042 performDragOperation
,
2043 concludeDragOperation
2048 releaseBagData(void *data
)
2056 getStream(WMText
*tPtr
, int sel
)
2058 TextBlock
*tb
= NULL
;
2060 unsigned long length
= 0, where
= 0;
2065 if (!(tb
= tPtr
->firstTextBlock
))
2068 /* this might be tricky to get right... not yet implemented */
2070 (tPtr
->writer
) (tPtr
, (void *) text
);
2075 /* first, how large a buffer would we want? */
2078 if (!tb
->graphic
|| (tb
->graphic
&& !tPtr
->flags
.monoFont
)) {
2080 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
))
2083 if (!sel
|| (tb
->graphic
&& tb
->selected
)) {
2086 length
+= 1; /* field markers 0xFA and 0xCE */
2087 } else if (sel
&& tb
->selected
) {
2088 length
+= (tb
->s_end
- tb
->s_begin
);
2095 text
= wmalloc(length
+1); /* +1 for the end of string, let's be nice */
2096 tb
= tPtr
->firstTextBlock
;
2099 if (!tb
->graphic
|| (tb
->graphic
&& !tPtr
->flags
.monoFont
)) {
2101 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
))
2102 text
[where
++] = '\n';
2104 if (!sel
|| (tb
->graphic
&& tb
->selected
)) {
2106 text
[where
++] = 0xFA;
2107 memcpy(&text
[where
], tb
->text
, tb
->used
);
2110 text
[where
++] = 0xCE;
2112 } else if (sel
&& tb
->selected
) {
2113 memcpy(&text
[where
], &tb
->text
[tb
->s_begin
],
2114 tb
->s_end
- tb
->s_begin
);
2115 where
+= tb
->s_end
- tb
->s_begin
;
2129 getStreamIntoBag(WMText
*tPtr
, int sel
)
2131 char *stream
, *start
= NULL
, *fa
= NULL
, *ce
= NULL
, *desc
= NULL
;
2137 stream
= getStream(tPtr
, sel
);
2141 bag
= WMCreateArrayBagWithDestructor(4, releaseBagData
);
2146 fa
= strchr(start
, 0xFA);
2148 desc
= wmalloc((int)(fa
- start
));
2149 memcpy(desc
, start
, (int)(fa
- start
));
2150 WMPutInBag(bag
, (void *) desc
);
2152 ce
= strchr(fa
, 0xCE);
2154 desc
= wmalloc(3 + (int)(ce
- fa
));
2157 memcpy(&desc
[2], fa
+1, ((int)(ce
- fa
))-1);
2158 desc
[2 + (int)(ce
-fa
)] = 0;
2159 WMPutInBag(bag
, (void *) desc
);
2166 if (start
&& strlen(start
)) {
2167 desc
= wmalloc(strlen(start
));
2168 memcpy(desc
, start
, strlen(start
));
2169 WMPutInBag(bag
, (void *) desc
);
2181 WMCreateText(WMWidget
*parent
)
2183 Text
*tPtr
= wmalloc(sizeof(Text
));
2185 printf("could not create text widget\n");
2190 printf("sizeof:\n");
2191 printf(" TextBlock %d\n", sizeof(TextBlock
));
2192 printf(" Section %d\n", sizeof(Section
));
2193 printf(" char * %d\n", sizeof(char *));
2194 printf(" void * %d\n", sizeof(void *));
2195 printf(" short %d\n", sizeof(short));
2196 printf(" Text %d\n", sizeof(Text
));
2199 memset(tPtr
, 0, sizeof(Text
));
2200 tPtr
->widgetClass
= WC_Text
;
2201 tPtr
->view
= W_CreateView(W_VIEW(parent
));
2203 perror("could not create text's view\n");
2207 tPtr
->view
->self
= tPtr
;
2208 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->textCursor
;
2209 tPtr
->view
->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2210 W_ResizeView(tPtr
->view
, 250, 200);
2211 tPtr
->bgGC
= WMColorGC(tPtr
->view
->screen
->white
);
2212 tPtr
->fgGC
= WMColorGC(tPtr
->view
->screen
->black
);
2213 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->view
->screen
->white
);
2220 //tPtr->dFont = WMCreateFont(tPtr->view->screen,
2221 // "-*-fixed-medium-r-normal--26-*-*-*-*-*-*-*");
2222 //"-sony-fixed-medium-r-normal--24-230-75-75-c-120-jisx0201.1976-0");
2223 // "-*-times-bold-r-*-*-12-*-*-*-*-*-*-*,"
2224 // "-*-fixed-medium-r-normal-*-12-*");
2226 tPtr
->dFont
= WMRetainFont(tPtr
->view
->screen
->normalFont
);
2228 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
2230 tPtr
->view
->delegate
= &_TextViewDelegate
;
2233 tPtr
->timerID
= NULL
;
2236 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
2237 |EnterWindowMask
|LeaveWindowMask
|FocusChangeMask
,
2238 handleEvents
, tPtr
);
2240 WMCreateEventHandler(tPtr
->view
, ButtonReleaseMask
|ButtonPressMask
2241 |KeyReleaseMask
|KeyPressMask
|Button1MotionMask
,
2242 handleActionEvents
, tPtr
);
2244 WMAddNotificationObserver(ownershipObserver
, tPtr
, "_lostOwnership", tPtr
);
2247 WMSetViewDragDestinationProcs(tPtr
->view
, &_DragDestinationProcs
);
2249 char *types
[2] = {"application/X-color", NULL
};
2250 WMRegisterViewForDraggedTypes(tPtr
->view
, types
);
2257 tPtr
->firstTextBlock
= NULL
;
2258 tPtr
->lastTextBlock
= NULL
;
2259 tPtr
->currentTextBlock
= NULL
;
2262 tPtr
->gfxItems
= WMCreateArrayBag(4);
2264 tPtr
->parser
= NULL
;
2265 tPtr
->writer
= NULL
;
2267 tPtr
->sel
.x
= tPtr
->sel
.y
= 2;
2268 tPtr
->sel
.w
= tPtr
->sel
.h
= 0;
2270 tPtr
->clicked
.x
= tPtr
->clicked
.y
= 2;
2272 tPtr
->visible
.x
= tPtr
->visible
.y
= 2;
2273 tPtr
->visible
.h
= tPtr
->view
->size
.height
;
2274 tPtr
->visible
.w
= tPtr
->view
->size
.width
- 12;
2276 tPtr
->cursor
.x
= -23;
2279 tPtr
->docHeight
= 0;
2280 tPtr
->dBulletPix
= WMCreatePixmapFromXPMData(tPtr
->view
->screen
,
2282 tPtr
->db
= (Pixmap
) NULL
;
2284 tPtr
->dmargins
= WMGetRulerMargins(tPtr
->ruler
);
2286 tPtr
->flags
.rulerShown
= False
;
2287 tPtr
->flags
.monoFont
= False
;
2288 tPtr
->flags
.focused
= False
;
2289 tPtr
->flags
.editable
= True
;
2290 tPtr
->flags
.ownsSelection
= False
;
2291 tPtr
->flags
.pointerGrabbed
= False
;
2292 tPtr
->flags
.buttonHeld
= False
;
2293 tPtr
->flags
.waitingForSelection
= False
;
2294 tPtr
->flags
.extendSelection
= False
;
2295 tPtr
->flags
.frozen
= False
;
2296 tPtr
->flags
.cursorShown
= True
;
2297 tPtr
->flags
.clickPos
= 1;
2298 tPtr
->flags
.ignoreNewLine
= False
;
2299 tPtr
->flags
.laidOut
= False
;
2300 tPtr
->flags
.prepend
= False
;
2301 tPtr
->flags
.relief
= WRFlat
;
2302 tPtr
->flags
.alignment
= WALeft
;
2308 WMPrependTextStream(WMText
*tPtr
, char *text
)
2313 tPtr
->flags
.prepend
= True
;
2314 if (text
&& tPtr
->parser
)
2315 (tPtr
->parser
) (tPtr
, (void *) text
);
2317 insertPlainText(tPtr
, text
);
2322 WMAppendTextStream(WMText
*tPtr
, char *text
)
2327 tPtr
->flags
.prepend
= False
;
2328 if (text
&& tPtr
->parser
)
2329 (tPtr
->parser
) (tPtr
, (void *) text
);
2331 insertPlainText(tPtr
, text
);
2337 WMGetTextStream(WMText
*tPtr
)
2339 return getStream(tPtr
, 0);
2343 WMGetTextSelected(WMText
*tPtr
)
2345 return getStream(tPtr
, 1);
2349 WMGetTextStreamIntoBag(WMText
*tPtr
)
2351 return getStreamIntoBag(tPtr
, 0);
2355 WMGetTextSelectedIntoBag(WMText
*tPtr
)
2357 return getStreamIntoBag(tPtr
, 1);
2362 WMCreateTextBlockWithObject(WMWidget
*w
, char *description
, WMColor
*color
,
2363 unsigned short first
, unsigned short reserved
)
2366 unsigned short length
;
2368 if (!w
|| !description
|| !color
)
2371 tb
= wmalloc(sizeof(TextBlock
));
2375 length
= strlen(description
);
2376 tb
->text
= (char *)wmalloc(length
);
2377 memset(tb
->text
, 0, length
);
2378 memcpy(tb
->text
, description
, length
);
2382 tb
->color
= WMRetainColor(color
);
2383 //&tb->margins = NULL;
2389 tb
->underlined
= False
;
2390 tb
->selected
= False
;
2392 tb
->sections
= NULL
;
2402 WMCreateTextBlockWithPixmap(WMPixmap
*p
, char *description
, WMColor
*color
,
2403 unsigned short first
, unsigned short reserved
)
2406 unsigned short length
;
2408 if (!p
|| !description
|| !color
)
2411 tb
= wmalloc(sizeof(TextBlock
));
2415 length
= strlen(description
);
2416 tb
->text
= (char *)wmalloc(length
);
2417 memset(tb
->text
, 0, length
);
2418 memcpy(tb
->text
, description
, length
);
2422 tb
->color
= WMRetainColor(color
);
2423 //&tb->margins = NULL;
2429 tb
->underlined
= False
;
2430 tb
->selected
= False
;
2432 tb
->sections
= NULL
;
2441 WMCreateTextBlockWithText(char *text
, WMFont
*font
, WMColor
*color
,
2442 unsigned short first
, unsigned short length
)
2446 if (!font
|| !color
)
2449 tb
= wmalloc(sizeof(TextBlock
));
2453 tb
->allocated
= reqBlockSize(length
);
2454 tb
->text
= (char *)wmalloc(tb
->allocated
);
2455 memset(tb
->text
, 0, tb
->allocated
);
2457 if (length
< 1|| !text
) { // || *text == '\n') {
2462 memcpy(tb
->text
, text
, length
);
2467 tb
->d
.font
= WMRetainFont(font
);
2468 tb
->color
= WMRetainColor(color
);
2471 tb
->graphic
= False
;
2472 tb
->underlined
= False
;
2473 tb
->selected
= False
;
2475 tb
->sections
= NULL
;
2483 WMSetTextBlockProperties(void *vtb
, unsigned int first
,
2484 unsigned int kanji
, unsigned int underlined
, int script
,
2485 WMRulerMargins margins
)
2487 TextBlock
*tb
= (TextBlock
*) vtb
;
2493 tb
->underlined
= underlined
;
2494 tb
->script
= script
;
2495 tb
->margins
.left
= margins
.left
;
2496 tb
->margins
.first
= margins
.first
;
2497 tb
->margins
.body
= margins
.body
;
2498 tb
->margins
.right
= margins
.right
;
2499 //for: tb->margins.tabs = margins.tabs;
2503 WMGetTextBlockProperties(void *vtb
, unsigned int *first
,
2504 unsigned int *kanji
, unsigned int *underlined
, int *script
,
2505 WMRulerMargins
*margins
)
2507 TextBlock
*tb
= (TextBlock
*) vtb
;
2511 if (first
) *first
= tb
->first
;
2512 if (kanji
) *kanji
= tb
->kanji
;
2513 if (underlined
) *underlined
= tb
->underlined
;
2514 if (script
) *script
= tb
->script
;
2517 (*margins
).left
= tb
->margins
.left
;
2518 (*margins
).first
= tb
->margins
.first
;
2519 (*margins
).body
= tb
->margins
.body
;
2520 (*margins
).right
= tb
->margins
.right
;
2521 //for: (*margins).tabs = tb->margins.tabs;
2528 WMPrependTextBlock(WMText
*tPtr
, void *vtb
)
2530 TextBlock
*tb
= (TextBlock
*)vtb
;
2537 WMWidget
*w
= tb
->d
.widget
;
2538 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
2539 handleWidgetPress
, tb
);
2540 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
2541 (W_VIEW(w
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
2542 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2545 WMPutInBag(tPtr
->gfxItems
, (void *)tb
);
2547 } else tPtr
->tpos
= tb
->used
;
2549 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
2550 tb
->next
= tb
->prior
= NULL
;
2551 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
2552 = tPtr
->currentTextBlock
= tb
;
2556 tb
->next
= tPtr
->currentTextBlock
;
2557 tb
->prior
= tPtr
->currentTextBlock
->prior
;
2558 if (tPtr
->currentTextBlock
->prior
)
2559 tPtr
->currentTextBlock
->prior
->next
= tb
;
2561 tPtr
->currentTextBlock
->prior
= tb
;
2563 tPtr
->firstTextBlock
= tb
;
2565 tPtr
->currentTextBlock
= tb
;
2570 WMAppendTextBlock(WMText
*tPtr
, void *vtb
)
2572 TextBlock
*tb
= (TextBlock
*)vtb
;
2579 WMWidget
*w
= tb
->d
.widget
;
2580 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
2581 handleWidgetPress
, tb
);
2582 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
2583 (W_VIEW(w
))->attribs
.cursor
=
2584 tPtr
->view
->screen
->defaultCursor
;
2585 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2588 WMPutInBag(tPtr
->gfxItems
, (void *)tb
);
2590 } else tPtr
->tpos
= tb
->used
;
2592 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
2593 tb
->next
= tb
->prior
= NULL
;
2594 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
2595 = tPtr
->currentTextBlock
= tb
;
2599 tb
->next
= tPtr
->currentTextBlock
->next
;
2600 tb
->prior
= tPtr
->currentTextBlock
;
2601 if (tPtr
->currentTextBlock
->next
)
2602 tPtr
->currentTextBlock
->next
->prior
= tb
;
2604 tPtr
->currentTextBlock
->next
= tb
;
2607 tPtr
->lastTextBlock
= tb
;
2609 tPtr
->currentTextBlock
= tb
;
2613 WMRemoveTextBlock(WMText
*tPtr
)
2615 TextBlock
*tb
= NULL
;
2617 if (!tPtr
|| !tPtr
->firstTextBlock
|| !tPtr
->lastTextBlock
2618 || !tPtr
->currentTextBlock
) {
2619 printf("cannot remove non existent TextBlock!\b");
2623 tb
= tPtr
->currentTextBlock
;
2625 WMRemoveFromBag(tPtr
->gfxItems
, (void *)tb
);
2628 WMDeleteEventHandler(W_VIEW(tb
->d
.widget
), ButtonPressMask
,
2629 handleWidgetPress
, tb
);
2630 WMUnmapWidget(tb
->d
.widget
);
2634 if (tPtr
->currentTextBlock
== tPtr
->firstTextBlock
) {
2635 if (tPtr
->currentTextBlock
->next
)
2636 tPtr
->currentTextBlock
->next
->prior
= NULL
;
2638 tPtr
->firstTextBlock
= tPtr
->currentTextBlock
->next
;
2639 tPtr
->currentTextBlock
= tPtr
->firstTextBlock
;
2641 } else if (tPtr
->currentTextBlock
== tPtr
->lastTextBlock
) {
2642 tPtr
->currentTextBlock
->prior
->next
= NULL
;
2643 tPtr
->lastTextBlock
= tPtr
->currentTextBlock
->prior
;
2644 tPtr
->currentTextBlock
= tPtr
->lastTextBlock
;
2646 tPtr
->currentTextBlock
->prior
->next
= tPtr
->currentTextBlock
->next
;
2647 tPtr
->currentTextBlock
->next
->prior
= tPtr
->currentTextBlock
->prior
;
2648 tPtr
->currentTextBlock
= tPtr
->currentTextBlock
->next
;
2655 WMDestroyTextBlock(WMText
*tPtr
, void *vtb
)
2657 TextBlock
*tb
= (TextBlock
*)vtb
;
2663 /* naturally, there's a danger to destroying
2664 widgets whose action brings us here:
2665 ie. press a button to destroy it... need to
2666 find a safer way. till then... this stays commented out */
2667 //WMDestroyWidget(tb->d.widget);
2668 //wfree(tb->d.widget);
2669 tb
->d
.widget
= NULL
;
2671 WMReleasePixmap(tb
->d
.pixmap
);
2672 tb
->d
.pixmap
= NULL
;
2675 WMReleaseFont(tb
->d
.font
);
2678 WMReleaseColor(tb
->color
);
2679 if (tb
->sections
&& tb
->nsections
> 0)
2680 wfree(tb
->sections
);
2688 WMRefreshText(WMText
*tPtr
, int vpos
, int hpos
)
2690 if (!tPtr
|| vpos
<0 || hpos
<0)
2693 if (tPtr
->flags
.frozen
)
2696 if(tPtr
->flags
.monoFont
) {
2697 int j
, c
= WMGetBagItemCount(tPtr
->gfxItems
);
2700 /* make sure to unmap widgets no matter where they are */
2701 for(j
=0; j
<c
; j
++) {
2702 if ((tb
= (TextBlock
*) WMGetFromBag(tPtr
->gfxItems
, j
))) {
2703 if (tb
->object
&& ((W_VIEW(tb
->d
.widget
))->flags
.mapped
))
2704 WMUnmapWidget(tb
->d
.widget
);
2710 if (tPtr
->vpos
!= vpos
) {
2711 if (vpos
< 0 || tPtr
->docHeight
< tPtr
->visible
.h
) {
2713 } else if(tPtr
->docHeight
- vpos
> tPtr
->visible
.h
- tPtr
->visible
.y
) {
2716 tPtr
->vpos
= tPtr
->docHeight
- tPtr
->visible
.h
;
2720 tPtr
->flags
.laidOut
= False
;
2721 layOutDocument(tPtr
);
2722 updateScrollers(tPtr
);
2728 WMSetTextForegroundColor(WMText
*tPtr
, WMColor
*color
)
2734 tPtr
->fgGC
= WMColorGC(color
);
2736 tPtr
->fgGC
= WMColorGC(WMBlackColor(tPtr
->view
->screen
));
2738 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2742 WMSetTextBackgroundColor(WMText
*tPtr
, WMColor
*color
)
2748 tPtr
->bgGC
= WMColorGC(color
);
2749 W_SetViewBackgroundColor(tPtr
->view
, color
);
2751 tPtr
->bgGC
= WMColorGC(WMWhiteColor(tPtr
->view
->screen
));
2752 W_SetViewBackgroundColor(tPtr
->view
,
2753 WMWhiteColor(tPtr
->view
->screen
));
2756 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2760 WMSetTextRelief(WMText
*tPtr
, WMReliefType relief
)
2764 tPtr
->flags
.relief
= relief
;
2769 WMSetTextHasHorizontalScroller(WMText
*tPtr
, Bool shouldhave
)
2774 if (shouldhave
&& !tPtr
->hS
) {
2775 tPtr
->hS
= WMCreateScroller(tPtr
);
2776 (W_VIEW(tPtr
->hS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
2777 (W_VIEW(tPtr
->hS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2778 WMSetScrollerArrowsPosition(tPtr
->hS
, WSAMaxEnd
);
2779 WMSetScrollerAction(tPtr
->hS
, scrollersCallBack
, tPtr
);
2780 } else if (!shouldhave
&& tPtr
->hS
) {
2781 WMUnmapWidget(tPtr
->hS
);
2782 WMDestroyWidget(tPtr
->hS
);
2788 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2793 WMSetTextHasRuler(WMText
*tPtr
, Bool shouldhave
)
2798 if(shouldhave
&& !tPtr
->ruler
) {
2799 tPtr
->ruler
= WMCreateRuler(tPtr
);
2800 (W_VIEW(tPtr
->ruler
))->attribs
.cursor
=
2801 tPtr
->view
->screen
->defaultCursor
;
2802 (W_VIEW(tPtr
->ruler
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2803 WMSetRulerReleaseAction(tPtr
->ruler
, rulerReleaseCallBack
, tPtr
);
2804 WMSetRulerMoveAction(tPtr
->ruler
, rulerMoveCallBack
, tPtr
);
2805 } else if(!shouldhave
&& tPtr
->ruler
) {
2806 WMShowTextRuler(tPtr
, False
);
2807 WMDestroyWidget(tPtr
->ruler
);
2810 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2814 WMShowTextRuler(WMText
*tPtr
, Bool show
)
2821 if(tPtr
->flags
.monoFont
)
2824 tPtr
->flags
.rulerShown
= show
;
2826 WMMapWidget(tPtr
->ruler
);
2828 WMUnmapWidget(tPtr
->ruler
);
2831 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2835 WMGetTextRulerShown(WMText
*tPtr
)
2843 return tPtr
->flags
.rulerShown
;
2848 WMSetTextHasVerticalScroller(WMText
*tPtr
, Bool shouldhave
)
2853 if (shouldhave
&& !tPtr
->vS
) {
2854 tPtr
->vS
= WMCreateScroller(tPtr
);
2855 (W_VIEW(tPtr
->vS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
2856 (W_VIEW(tPtr
->vS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2857 WMSetScrollerArrowsPosition(tPtr
->vS
, WSAMaxEnd
);
2858 WMSetScrollerAction(tPtr
->vS
, scrollersCallBack
, tPtr
);
2859 } else if (!shouldhave
&& tPtr
->vS
) {
2860 WMUnmapWidget(tPtr
->vS
);
2861 WMDestroyWidget(tPtr
->vS
);
2867 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2873 WMScrollText(WMText
*tPtr
, int amount
)
2878 if (amount
== 0 || !tPtr
->view
->flags
.realized
)
2882 if (tPtr
->vpos
> 0) {
2883 if (tPtr
->vpos
> amount
) tPtr
->vpos
+= amount
;
2887 int limit
= tPtr
->docHeight
- tPtr
->visible
.h
;
2888 if (tPtr
->vpos
< limit
) {
2889 if (tPtr
->vpos
< limit
-amount
) tPtr
->vpos
+= amount
;
2890 else tPtr
->vpos
= limit
;
2894 if (scroll
&& tPtr
->vpos
!= tPtr
->prevVpos
) {
2895 updateScrollers(tPtr
);
2898 tPtr
->prevVpos
= tPtr
->vpos
;
2903 WMPageText(WMText
*tPtr
, Bool direction
)
2905 if (!tPtr
) return False
;
2906 if (!tPtr
->view
->flags
.realized
) return False
;
2908 return WMScrollText(tPtr
, direction
?tPtr
->visible
.h
:-tPtr
->visible
.h
);
2912 WMSetTextEditable(WMText
*tPtr
, Bool editable
)
2916 tPtr
->flags
.editable
= editable
;
2920 WMGetTextEditable(WMText
*tPtr
)
2924 return tPtr
->flags
.editable
;
2928 WMSetTextIgnoresNewline(WMText
*tPtr
, Bool ignore
)
2932 tPtr
->flags
.ignoreNewLine
= ignore
;
2936 WMGetTextIgnoresNewline(WMText
*tPtr
)
2940 return tPtr
->flags
.ignoreNewLine
;
2944 WMSetTextUsesMonoFont(WMText
*tPtr
, Bool mono
)
2948 if (mono
&& tPtr
->flags
.rulerShown
)
2949 WMShowTextRuler(tPtr
, False
);
2951 tPtr
->flags
.monoFont
= mono
;
2952 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2956 WMGetTextUsesMonoFont(WMText
*tPtr
)
2960 return tPtr
->flags
.monoFont
;
2965 WMSetTextDefaultFont(WMText
*tPtr
, WMFont
*font
)
2970 WMReleaseFont(tPtr
->dFont
);
2974 tPtr
->dFont
= WMRetainFont(tPtr
->view
->screen
->normalFont
);
2978 WMGetTextDefaultFont(WMText
*tPtr
)
2987 WMSetTextAlignment(WMText
*tPtr
, WMAlignment alignment
)
2991 tPtr
->flags
.alignment
= alignment
;
2992 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2996 WMSetTextParser(WMText
*tPtr
, WMAction
*parser
)
3000 tPtr
->parser
= parser
;
3004 WMSetTextWriter(WMText
*tPtr
, WMAction
*writer
)
3008 tPtr
->writer
= writer
;
3012 WMGetTextInsertType(WMText
*tPtr
)
3016 return tPtr
->flags
.prepend
;
3021 WMSetTextSelectionColor(WMText
*tPtr
, WMColor
*color
)
3024 if (!tPtr
|| !color
)
3027 tb
= tPtr
->firstTextBlock
;
3028 if (!tb
|| !tPtr
->flags
.ownsSelection
)
3034 if ( (tb
->s_end
- tb
->s_begin
== tb
->used
) || tb
->graphic
) {
3036 WMReleaseColor(tb
->color
);
3037 tb
->color
= WMRetainColor(color
);
3039 } else if (tb
->s_end
<= tb
->used
) {
3041 TextBlock
*otb
= tb
;
3043 TextBlock
*ntb
= (TextBlock
*) WMCreateTextBlockWithText(
3044 &(tb
->text
[tb
->s_begin
]),
3045 tb
->d
.font
, color
, False
, (tb
->s_end
- tb
->s_begin
));
3048 ntb
->selected
= True
;
3050 ntb
->s_end
= ntb
->used
;
3051 WMAppendTextBlock(tPtr
, ntb
);
3056 if (tb
->used
> tb
->s_end
) {
3057 ntb
= (TextBlock
*) WMCreateTextBlockWithText(
3058 &(tb
->text
[tb
->s_end
]),
3059 tb
->d
.font
, tb
->color
, False
, tb
->used
- tb
->s_end
);
3061 ntb
->selected
= True
;
3063 ntb
->s_end
= ntb
->used
;
3064 WMAppendTextBlock(tPtr
, ntb
);
3072 else if (count
== 2)
3073 tb
= otb
->next
->next
;
3075 tb
->used
= tb
->s_end
= tb
->s_begin
;
3082 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
3086 WMSetTextSelectionFont(WMText
*tPtr
, WMFont
*font
)
3092 tb
= tPtr
->firstTextBlock
;
3093 if (!tb
|| !tPtr
->flags
.ownsSelection
)
3098 tb
->d
.font
= WMRetainFont(font
);
3101 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
3105 WMFreezeText(WMText
*tPtr
)
3110 tPtr
->flags
.frozen
= True
;
3114 WMThawText(WMText
*tPtr
)
3119 tPtr
->flags
.frozen
= False
;
3124 WMFindInTextStream(WMText
*tPtr
, char *needle
)
3126 char *haystack
= NULL
;
3129 if (!tPtr
|| !needle
)
3132 if ( !(haystack
= "WMGetTextStream(tPtr)"))
3135 result
= (Bool
) strstr(haystack
, needle
);