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.
22 #include <X11/keysym.h>
23 #include <X11/Xatom.h>
29 * - assess danger of destroying widgets whose actions link to other pages
30 * - change cursor shape around pixmaps
31 * - redo blink code to reduce paint event... use pixmap buffer...
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
41 /* a Section is a section of a TextBlock that describes what parts
42 of a TextBlock has been laid out on which "line"...
43 o this greatly aids redraw, scroll and selection.
44 o this is created during layoutLine, but may be later modified.
45 o there may be many Sections per TextBlock, hence the array */
47 unsigned int x
, y
; /* where to draw it from */
48 unsigned short w
, h
; /* its width and height */
49 unsigned short begin
; /* where the layout begins */
50 unsigned short end
; /* where it ends */
51 unsigned short last
:1; /* is it the last section on a "line"? */
52 unsigned int _y
:31; /* the "line" it and other textblocks are on */
56 /* a TextBlock is a doubly-linked list of TextBlocks containing:
57 o text for the block, color and font
58 o or a pointer to the pixmap
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 text (could be kanji) */
67 /* or to the object's description */
69 WMFont
*font
; /* the font */
70 WMWidget
*widget
; /* the embedded widget */
71 WMPixmap
*pixmap
; /* the pixmap */
72 } d
; /* description */
74 unsigned short used
; /* number of chars in this block */
75 unsigned short allocated
; /* size of allocation (in chars) */
76 WMColor
*color
; /* the color */
77 // WMRulerMargins margins; /* first & body indentations, tabstops, etc... */
79 Section
*sections
; /* the region for layouts (a growable array) */
80 /* an _array_! of size _nsections_ */
82 unsigned short s_begin
; /* where the selection begins */
83 unsigned short s_end
; /* where it ends */
85 unsigned int first
:1; /* first TextBlock in paragraph */
86 unsigned int blank
:1; /* ie. blank paragraph */
87 unsigned int kanji
:1; /* is of 16-bit characters or not */
88 unsigned int graphic
:1; /* graphic or text: text=0 */
89 unsigned int object
:1; /* embedded object or pixmap */
90 unsigned int underlined
:1; /* underlined or not */
91 unsigned int selected
:1; /* selected or not */
92 unsigned int nsections
:8; /* over how many "lines" a TextBlock wraps */
93 int script
:8; /* script in points: negative for subscript */
94 unsigned int RESERVED
:9;
98 /* somehow visible.h beats the hell outta visible.size.height :-) */
107 typedef struct W_Text
{
108 W_Class widgetClass
; /* the class number of this widget */
109 W_View
*view
; /* the view referring to this instance */
111 WMRuler
*ruler
; /* the ruler widget to manipulate paragraphs */
113 WMScroller
*vS
; /* the vertical scroller */
114 unsigned int vpos
; /* the current vertical position */
115 unsigned int prevVpos
; /* the previous vertical position */
117 WMScroller
*hS
; /* the horizontal scroller */
118 unsigned short hpos
; /* the current horizontal position */
119 unsigned short prevHpos
; /* the previous horizontal position */
121 WMFont
*dFont
; /* the default font */
122 WMColor
*dColor
; /* the default color */
123 WMPixmap
*dBulletPix
; /* the default pixmap for bullets */
124 WMRulerMargins dmargins
; /* default margins */
126 GC bgGC
; /* the background GC to draw with */
127 GC fgGC
; /* the foreground GC to draw with */
128 Pixmap db
; /* the buffer on which to draw */
130 myRect visible
; /* the actual rectangle that can be drawn into */
131 myRect cursor
; /* the position and (height) of cursor */
132 myRect sel
; /* the selection rectangle */
134 WMPoint clicked
; /* where in the _document_ was clicked */
136 unsigned short tpos
; /* the position in the currentTextBlock */
137 unsigned short docWidth
; /* the width of the entire document */
138 unsigned int docHeight
; /* the height of the entire document */
140 TextBlock
*firstTextBlock
;
141 TextBlock
*lastTextBlock
;
142 TextBlock
*currentTextBlock
;
144 WMBag
*gfxItems
; /* a nice bag containing graphic items */
147 WMHandlerID timerID
; /* for nice twinky-winky */
154 unsigned int monoFont
:1; /* whether to ignore formats */
155 unsigned int focused
:1; /* whether this instance has input focus */
156 unsigned int editable
:1; /* "silly user, you can't edit me" */
157 unsigned int ownsSelection
:1; /* "I ownz the current selection!" */
158 unsigned int pointerGrabbed
:1;/* "heh, gib me pointer" */
159 unsigned int buttonHeld
:1; /* the user is holding down the button */
160 unsigned int waitingForSelection
:1; /* dum dee dumm... */
161 unsigned int extendSelection
:1; /* shift-drag to select more regions */
163 unsigned int rulerShown
:1; /* whether the ruler is shown or not */
164 unsigned int frozen
:1; /* whether screen updates are to be made */
165 unsigned int cursorShown
:1; /* whether to show the cursor */
166 unsigned int clickPos
:1; /* clicked before=0 or after=1 a graphic: */
167 /* (within counts as after too) */
169 unsigned int ignoreNewLine
:1;/* turn it into a ' ' in streams > 1 */
170 unsigned int laidOut
:1; /* have the TextBlocks all been laid out */
171 unsigned int prepend
:1; /* prepend=1, append=0 (for parsers) */
172 WMAlignment alignment
:2; /* the alignment for text */
173 WMReliefType relief
:3; /* the relief to display with */
174 unsigned int RESERVED
:12;
179 static char *default_bullet
[] = {
181 " c None s None", ". c black",
182 "X c white", "o c #808080",
192 sectionWasSelected(Text
*tPtr
, TextBlock
*tb
, XRectangle
*rect
, int s
)
194 unsigned short i
, w
, lw
, selected
= False
, extend
= False
;
198 /* if selection rectangle completely encloses the section */
199 if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
200 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
201 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
203 sel
.w
= tPtr
->visible
.w
;
204 selected
= extend
= True
;
206 /* or if it starts on a line and then goes further down */
207 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
208 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
209 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
210 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
211 >= tPtr
->visible
.y
+ tPtr
->sel
.y
) ) {
212 sel
.x
= WMAX(tPtr
->sel
.x
, tPtr
->clicked
.x
);
213 sel
.w
= tPtr
->visible
.w
;
214 selected
= extend
= True
;
216 /* or if it begins before a line, but ends on it */
217 } else if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
218 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
219 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
220 && (tb
->sections
[s
]._y
221 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
223 if (1||tPtr
->sel
.x
+ tPtr
->sel
.w
> tPtr
->clicked
.x
)
224 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 && (tPtr
->sel
.w
>= 2)
234 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
235 >= 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
)
250 if ( tb
->sections
[s
].x
+ tb
->sections
[s
].w
<= sel
.x
+ sel
.w
251 && tb
->sections
[s
].x
>= sel
.x
) {
252 rect
->width
= tb
->sections
[s
].w
;
253 rect
->x
= tb
->sections
[s
].x
;
258 i
= tb
->sections
[s
].begin
;
261 if (0&& tb
->sections
[s
].x
>= sel
.x
) {
262 tb
->s_begin
= tb
->sections
[s
].begin
;
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");
285 _selEnd
: rect
->x
= tb
->sections
[s
].x
+ lw
;
287 while(++i
<= tb
->sections
[s
].end
) {
289 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
292 if (lw
+ rect
->x
>= sel
.x
+ sel
.w
293 || i
== tb
->sections
[s
].end
) {
295 if (i
!= tb
->sections
[s
].end
) {
301 if (tb
->sections
[s
].last
&& sel
.x
+ sel
.w
302 >= tb
->sections
[s
].x
+ tb
->sections
[s
].w
304 rect
->width
+= (tPtr
->visible
.w
- rect
->x
- lw
);
307 tb
->s_end
= (tb
->selected
? WMAX(tb
->s_end
, i
) : i
);
313 rect
->y
= tb
->sections
[s
]._y
- tPtr
->vpos
;
314 rect
->height
= tb
->sections
[s
].h
;
315 if(tb
->graphic
) { printf("graphic s%d h%d\n", s
,tb
->sections
[s
].h
);}
322 removeSelection(Text
*tPtr
)
324 TextBlock
*tb
= NULL
;
326 if (!(tb
= tPtr
->firstTextBlock
))
332 if ( (tb
->s_end
- tb
->s_begin
== tb
->used
) || tb
->graphic
) {
333 tPtr
->currentTextBlock
= tb
;
334 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
335 tb
= tPtr
->currentTextBlock
;
340 } else if (tb
->s_end
<= tb
->used
) {
341 memmove(&(tb
->text
[tb
->s_begin
]),
342 &(tb
->text
[tb
->s_end
]), tb
->used
- tb
->s_end
);
343 tb
->used
-= (tb
->s_end
- tb
->s_begin
);
344 tb
->selected
= False
;
345 tPtr
->tpos
= tb
->s_begin
;
356 paintText(Text
*tPtr
)
358 TextBlock
*tb
= tPtr
->firstTextBlock
;
362 int len
, y
, c
, s
, done
=False
;
364 WMScreen
*scr
= tPtr
->view
->screen
;
365 Display
*dpy
= tPtr
->view
->screen
->display
;
366 Window win
= tPtr
->view
->window
;
368 if (!tPtr
->view
->flags
.realized
|| !tPtr
->db
|| tPtr
->flags
.frozen
)
371 XFillRectangle(dpy
, tPtr
->db
, tPtr
->bgGC
,
372 0, 0, WMWidgetWidth(tPtr
), WMWidgetWidth(tPtr
));
373 //tPtr->visible.w, tPtr->visible.h);
375 tb
= tPtr
->firstTextBlock
;
380 if (tPtr
->flags
.ownsSelection
)
381 greyGC
= WMColorGC(WMGrayColor(scr
));
385 while (!done
&& tb
) {
392 tb
->selected
= False
;
394 for(s
=0; s
<tb
->nsections
&& !done
; s
++) {
396 if (tb
->sections
[s
]._y
> tPtr
->vpos
+ tPtr
->visible
.h
) {
401 if ( tb
->sections
[s
].y
+ tb
->sections
[s
].h
< tPtr
->vpos
)
404 if (tPtr
->flags
.monoFont
) {
409 gc
= WMColorGC(tb
->color
);
412 if (tPtr
->flags
.ownsSelection
) {
415 if ( sectionWasSelected(tPtr
, tb
, &rect
, s
)) {
417 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
418 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
422 prev_y
= tb
->sections
[s
]._y
;
424 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
425 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
426 y
= tb
->sections
[s
].y
- tPtr
->vpos
;
427 WMDrawString(scr
, tPtr
->db
, gc
, font
,
428 tb
->sections
[s
].x
, y
, text
, len
);
430 if (tb
->underlined
) {
431 XDrawLine(dpy
, tPtr
->db
, gc
,
432 tb
->sections
[s
].x
, y
+ font
->y
+ 1,
433 tb
->sections
[s
].x
+ tb
->sections
[s
].w
, y
+ font
->y
+ 1);
438 tb
= (!done
? tb
->next
: NULL
);
442 c
= WMGetBagItemCount(tPtr
->gfxItems
);
443 if (c
> 0 && !tPtr
->flags
.monoFont
) {
447 tb
= (TextBlock
*) WMGetFromBag(tPtr
->gfxItems
, j
);
448 if (tb
->sections
[0]._y
+ tb
->sections
[0].h
<= tPtr
->vpos
449 || tb
->sections
[0]._y
>= tPtr
->vpos
+ tPtr
->visible
.h
) {
452 if ((W_VIEW(tb
->d
.widget
))->flags
.mapped
) {
453 WMUnmapWidget(tb
->d
.widget
);
458 if (!(W_VIEW(tb
->d
.widget
))->flags
.mapped
) {
459 if (!(W_VIEW(tb
->d
.widget
))->flags
.realized
)
460 WMRealizeWidget(tb
->d
.widget
);
461 WMMapWidget(tb
->d
.widget
);
462 WMLowerWidget(tb
->d
.widget
);
466 if (tPtr
->flags
.ownsSelection
) {
469 if ( sectionWasSelected(tPtr
, tb
, &rect
, s
)) {
471 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
472 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
477 WMMoveWidget(tb
->d
.widget
,
479 tb
->sections
[0].y
- tPtr
->vpos
);
480 h
= WMWidgetHeight(tb
->d
.widget
) + 1;
483 WMDrawPixmap(tb
->d
.pixmap
, tPtr
->db
,
485 tb
->sections
[0].y
- tPtr
->vpos
);
486 h
= tb
->d
.pixmap
->height
+ 1;
489 if (tb
->underlined
) {
490 XDrawLine(dpy
, tPtr
->db
, WMColorGC(tb
->color
),
492 tb
->sections
[0].y
+ h
,
493 tb
->sections
[0].x
+ tb
->sections
[0].w
,
494 tb
->sections
[0].y
+ h
);
499 if (tPtr
->flags
.editable
&& tPtr
->flags
.cursorShown
500 && tPtr
->cursor
.x
!= -23 && tPtr
->flags
.focused
) {
501 int y
= tPtr
->cursor
.y
- tPtr
->vpos
;
502 XDrawLine(dpy
, tPtr
->db
, tPtr
->fgGC
,
504 tPtr
->cursor
.x
, y
+ tPtr
->cursor
.h
);
507 XCopyArea(dpy
, tPtr
->db
, win
, tPtr
->bgGC
,
509 tPtr
->visible
.w
, tPtr
->visible
.h
,
510 tPtr
->visible
.x
, tPtr
->visible
.y
);
512 W_DrawRelief(scr
, win
, 0, 0,
513 tPtr
->view
->size
.width
, tPtr
->view
->size
.height
,
516 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)
519 tPtr
->view
->size
.width
-4, 42);
526 #define CURSOR_BLINK_ON_DELAY 600
527 #define CURSOR_BLINK_OFF_DELAY 400
530 blinkCursor(void *data
)
532 Text
*tPtr
= (Text
*)data
;
534 if (tPtr
->flags
.cursorShown
) {
535 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY
,
538 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
,
542 tPtr
->flags
.cursorShown
= !tPtr
->flags
.cursorShown
;
547 getFirstNonGraphicBlockFor(TextBlock
*tb
, short dir
)
554 tb
= (dir
? tb
->next
: tb
->prior
);
562 cursorToTextPosition(Text
*tPtr
, int x
, int y
)
564 TextBlock
*tb
= NULL
;
565 int done
=False
, s
, pos
, len
, _w
, _y
, dir
=1; /* 1 == "down" */
568 y
+= (tPtr
->vpos
- tPtr
->visible
.y
);
572 x
-= (tPtr
->visible
.x
- 2);
576 /* clicked is relative to document, not window... */
580 if (! (tb
= tPtr
->currentTextBlock
)) {
581 if (! (tb
= tPtr
->firstTextBlock
)) {
583 tPtr
->cursor
.h
= tPtr
->dFont
->height
;
590 /* first, which direction? Most likely, newly clicked
591 position will be close to previous */
592 dir
= !(y
<= tb
->sections
[0].y
);
593 if ( ( y
<= tb
->sections
[0]._y
+ tb
->sections
[0].h
)
594 && (y
>= tb
->sections
[0]._y
) ) {
595 /* if it's on the same line */
596 if(x
< tb
->sections
[0].x
)
598 if(x
>= tb
->sections
[0].x
)
602 tb
= tPtr
->firstTextBlock
;
605 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
606 tb
= getFirstNonGraphicBlockFor(tb
, 1);
608 tPtr
->currentTextBlock
=
609 (dir
? tPtr
->lastTextBlock
: tPtr
->firstTextBlock
);
615 s
= (dir
? 0 : tb
->nsections
-1);
616 if ( y
>= tb
->sections
[s
]._y
617 && y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) {
621 /* get the first section of the TextBlock that lies about
622 the vertical click point */
624 while (!done
&& tb
) {
626 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
632 s
= (dir
? 0 : tb
->nsections
-1);
633 while (!done
&& (dir
? (s
<tb
->nsections
) : (s
>=0) )) {
635 if ( (dir
? (y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) :
636 ( y
>= tb
->sections
[s
]._y
) ) ) {
644 if ( (dir
? tb
->next
: tb
->prior
)) {
645 tb
= (dir
? tb
->next
: tb
->prior
);
648 break; //goto _doneH;
654 if (s
<0 || s
>=tb
->nsections
) {
655 s
= (dir
? tb
->nsections
-1 : 0);
659 /* we have the line, which TextBlock on that line is it? */
661 if (tPtr
->flags
.monoFont
&& tb
->graphic
)
662 tb
= getFirstNonGraphicBlockFor(tb
, dir
);
664 if ((dir
? tb
->sections
[s
].x
>= x
: tb
->sections
[s
].x
< x
))
672 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
673 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
674 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
676 printf("here %d %d \n", tb
->sections
[s
].x
+ _w
, x
);
677 if ((dir
? tb
->sections
[s
].x
+ _w
< x
: tb
->sections
[s
].x
+ _w
>= x
)) {
678 pos
= tb
->sections
[s
].end
;
679 tPtr
->cursor
.x
= tb
->sections
[s
].x
+ _w
;
683 _y
= tb
->sections
[s
]._y
;
688 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
689 tb
= (dir
? tb
->next
: tb
->prior
);
696 _w
= WMWidgetWidth(tb
->d
.widget
);
698 _w
= tb
->d
.pixmap
->width
;
700 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
701 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
702 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
703 if (tb
->sections
[s
].x
+ _w
>= x
)
708 if (tb
->sections
[s
].x
<= x
)
712 if ((dir
? tb
->next
: tb
->prior
)) {
713 TextBlock
*nxt
= (dir
? tb
->next
: tb
->prior
);
714 if (tPtr
->flags
.monoFont
&& nxt
->graphic
) {
715 nxt
= getFirstNonGraphicBlockFor(nxt
, dir
);
718 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
723 if (_y
!= nxt
->sections
[0]._y
) {
724 /* this must be the last/first on this line. stop */
725 pos
= (dir
? tb
->sections
[s
].end
: 0);
726 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
730 tPtr
->cursor
.x
+= WMWidgetWidth(tb
->d
.widget
);
732 tPtr
->cursor
.x
+= tb
->d
.pixmap
->width
;
733 } else if (pos
> tb
->sections
[s
].begin
) {
735 WMWidthOfString(tb
->d
.font
,
736 &(tb
->text
[tb
->sections
[s
].begin
]),
737 pos
- tb
->sections
[s
].begin
);
744 if ( (dir
? tb
->next
: tb
->prior
)) {
745 tb
= (dir
? tb
->next
: tb
->prior
);
752 s
= (dir
? 0 : tb
->nsections
-1);
755 /* we have said TextBlock, now where within it? */
756 if (tb
&& !tb
->graphic
) {
757 WMFont
*f
= tb
->d
.font
;
758 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
759 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
761 _w
= x
- tb
->sections
[s
].x
;
764 while (pos
<len
&& WMWidthOfString(f
, text
, pos
+1) < _w
)
767 tPtr
->cursor
.x
= tb
->sections
[s
].x
+
768 (pos
? WMWidthOfString(f
, text
, pos
) : 0);
770 pos
+= tb
->sections
[s
].begin
;
772 tPtr
->tpos
= (pos
<tb
->used
)? pos
: tb
->used
;
775 tPtr
->currentTextBlock
= tb
;
776 tPtr
->cursor
.h
= tb
->sections
[s
].h
;
777 tPtr
->cursor
.y
= tb
->sections
[s
]._y
;
780 printf("will hang :-)\n");
785 updateScrollers(Text
*tPtr
)
788 if (tPtr
->flags
.frozen
)
792 if (tPtr
->docHeight
< tPtr
->visible
.h
) {
793 WMSetScrollerParameters(tPtr
->vS
, 0, 1);
796 float vmax
= (float)(tPtr
->docHeight
);
797 WMSetScrollerParameters(tPtr
->vS
,
798 ((float)tPtr
->vpos
)/(vmax
- (float)tPtr
->visible
.h
),
799 (float)tPtr
->visible
.h
/vmax
);
801 } else tPtr
->vpos
= 0;
808 scrollersCallBack(WMWidget
*w
, void *self
)
810 Text
*tPtr
= (Text
*)self
;
815 if (!tPtr
->view
->flags
.realized
|| tPtr
->flags
.frozen
)
821 vmax
= (float)(tPtr
->docHeight
);
822 height
= tPtr
->visible
.h
;
824 which
= WMGetScrollerHitPart(tPtr
->vS
);
826 case WSDecrementLine
:
827 if (tPtr
->vpos
> 0) {
828 if (tPtr
->vpos
>16) tPtr
->vpos
-=16;
832 case WSIncrementLine
: {
833 int limit
= tPtr
->docHeight
- height
;
834 if (tPtr
->vpos
< limit
) {
835 if (tPtr
->vpos
<limit
-16) tPtr
->vpos
+=16;
836 else tPtr
->vpos
=limit
;
839 case WSDecrementPage
:
840 tPtr
->vpos
-= height
;
846 printf("dimple needs to jump to mouse location ;-/\n");
848 case WSIncrementPage
:
849 tPtr
->vpos
+= height
;
850 if (tPtr
->vpos
> (tPtr
->docHeight
- height
))
851 tPtr
->vpos
= tPtr
->docHeight
- height
;
854 printf("dimple needs to jump to mouse location ;-/\n");
859 tPtr
->vpos
= WMGetScrollerValue(tPtr
->vS
)
860 * (float)(tPtr
->docHeight
- height
);
866 printf("WSNoPart, WSKnobSlot\n");
868 float vmax
= (float)(tPtr
->docHeight
);
869 ((float)tPtr
->vpos
)/(vmax
- (float)tPtr
->visible
.h
),
870 (float)tPtr
->visible
.h
/vmax
;
871 dimple
=where mouse is
.
875 scroll
= (tPtr
->vpos
!= tPtr
->prevVpos
);
876 tPtr
->prevVpos
= tPtr
->vpos
;
885 if (tPtr->rulerShown)
886 XClearArea(tPtr->view->screen->display, tPtr->view->window, 22, 47,
887 tPtr->view->size.width-24, tPtr->view->size.height-49, True);
889 XClearArea(tPtr->view->screen->display, tPtr->view->window, 22, 2,
890 tPtr->view->size.width-24, tPtr->view->size.height-4, True);
893 if (dimple
|| which
== WSDecrementLine
|| which
== WSIncrementLine
)
894 updateScrollers(tPtr
);
903 unsigned short begin
, end
; /* what part of the text block */
908 layOutLine(Text
*tPtr
, myLineItems
*items
, int nitems
, int x
, int y
)
910 int i
, j
=0, lw
= 0, line_height
=0, max_d
=0, len
, n
;
914 TextBlock
*tbsame
=NULL
;
916 for(i
=0; i
<nitems
; i
++) {
920 if (!tPtr
->flags
.monoFont
) {
922 WMWidget
*wdt
= tb
->d
.widget
;
923 line_height
= WMAX(line_height
, WMWidgetHeight(wdt
));
924 if (tPtr
->flags
.alignment
!= WALeft
)
925 lw
+= WMWidgetWidth(wdt
);
927 line_height
= WMAX(line_height
, tb
->d
.pixmap
->height
+ max_d
);
928 if (tPtr
->flags
.alignment
!= WALeft
)
929 lw
+= tb
->d
.pixmap
->width
;
934 font
= (tPtr
->flags
.monoFont
)?tPtr
->dFont
: tb
->d
.font
;
935 max_d
= WMAX(max_d
, abs(font
->height
-font
->y
));
936 line_height
= WMAX(line_height
, font
->height
+ max_d
);
937 text
= &(tb
->text
[items
[i
].begin
]);
938 len
= items
[i
].end
- items
[i
].begin
;
939 if (tPtr
->flags
.alignment
!= WALeft
)
940 lw
+= WMWidthOfString(font
, text
, len
);
944 if (tPtr
->flags
.alignment
== WARight
) {
945 j
= tPtr
->visible
.w
- lw
;
946 } else if (tPtr
->flags
.alignment
== WACenter
) {
947 j
= (int) ((float)(tPtr
->visible
.w
- lw
))/2.0;
950 for(i
=0; i
<nitems
; i
++) {
953 if (tbsame
== tb
) { /*extend it, since it's on same line */
954 tb
->sections
[tb
->nsections
-1].end
= items
[i
].end
;
957 tb
->sections
= wrealloc(tb
->sections
,
958 (++tb
->nsections
)*sizeof(Section
));
960 tb
->sections
[n
]._y
= y
+ max_d
;
961 tb
->sections
[n
].x
= x
+j
;
962 tb
->sections
[n
].h
= line_height
;
963 tb
->sections
[n
].begin
= items
[i
].begin
;
964 tb
->sections
[n
].end
= items
[i
].end
;
966 if (tb
->graphic
&& tb
->object
) {
967 tb
->sections
[n
].x
+= tPtr
->visible
.x
;
968 tb
->sections
[n
].y
+= tPtr
->visible
.y
;
972 tb
->sections
[n
].last
= (i
+1 == nitems
);
975 if (!tPtr
->flags
.monoFont
) {
977 WMWidget
*wdt
= tb
->d
.widget
;
978 tb
->sections
[n
].y
= max_d
+ y
979 + line_height
- WMWidgetHeight(wdt
);
980 tb
->sections
[n
].w
= WMWidgetWidth(wdt
);
982 tb
->sections
[n
].y
= y
+ max_d
;
983 tb
->sections
[n
].w
= tb
->d
.pixmap
->width
;
985 x
+= tb
->sections
[n
].w
;
988 font
= (tPtr
->flags
.monoFont
)? tPtr
->dFont
: tb
->d
.font
;
989 len
= items
[i
].end
- items
[i
].begin
;
990 text
= &(tb
->text
[items
[i
].begin
]);
992 tb
->sections
[n
].y
= y
+line_height
-font
->y
;
994 WMWidthOfString(font
,
995 &(tb
->text
[tb
->sections
[n
].begin
]),
996 tb
->sections
[n
].end
- tb
->sections
[n
].begin
);
998 x
+= WMWidthOfString(font
, text
, len
);
1010 output(char *ptr
, int len
)
1013 memcpy(s
, ptr
, len
);
1015 //printf(" s is [%s] (%d)\n", s, strlen(s));
1016 printf("[%s]\n", s
);
1020 /* tb->text doesn't necessarily end in '\0' hmph! (strchr) */
1021 static inline char *
1022 mystrchr(char *s
, char needle
, unsigned short len
)
1026 if (!haystack
|| len
< 1)
1029 while ( (int) (haystack
- s
) < len
) {
1030 if (*haystack
== needle
)
1037 #define MAX_TB_PER_LINE 64
1040 layOutDocument(Text
*tPtr
)
1043 myLineItems items
[MAX_TB_PER_LINE
];
1045 Bool lhc
= !tPtr
->flags
.laidOut
; /* line height changed? */
1046 int prev_y
, nitems
=0, x
=0, y
=0, lw
= 0, width
=0;
1048 char *start
=NULL
, *mark
=NULL
;
1051 if (tPtr
->flags
.frozen
)
1054 if (!(tb
= tPtr
->firstTextBlock
))
1057 if (0&&tPtr
->flags
.laidOut
) {
1058 tb
= tPtr
->currentTextBlock
;
1059 if (tb
->sections
&& tb
->nsections
>0)
1060 prev_y
= tb
->sections
[tb
->nsections
-1]._y
;
1062 printf("1 prev_y %d \n", prev_y
);
1064 /* search backwards for textblocks on same line */
1066 if (!tb
->sections
|| tb
->nsections
<1) {
1067 tb
= tPtr
->firstTextBlock
;
1070 if (tb
->sections
[tb
->nsections
-1]._y
!= prev_y
) {
1074 // prev_y = tb->sections[tb->nsections-1]._y;
1077 y
= 0;//tb->sections[tb->nsections-1]._y;
1078 printf("2 prev_y %d \n\n", tb
->sections
[tb
->nsections
-1]._y
);
1084 if (tb
->sections
&& tb
->nsections
>0) {
1085 wfree(tb
->sections
);
1086 tb
->sections
= NULL
;
1091 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1092 x
= 0;//tb->margins.first;
1098 if (!tPtr
->flags
.monoFont
) {
1100 width
= WMWidgetWidth(tb
->d
.widget
);
1102 width
= tb
->d
.pixmap
->width
;
1104 if (width
> tPtr
->visible
.w
)printf("rescale graphix to fit?\n");
1106 if (lw
>= tPtr
->visible
.w
- x
1107 || nitems
>= MAX_TB_PER_LINE
) {
1108 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1110 x
= 0;//tb->margins.first;
1114 items
[nitems
].tb
= tb
;
1115 items
[nitems
].begin
= 0;
1116 items
[nitems
].end
= 0;
1120 } else if ((start
= tb
->text
)) {
1122 font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
1125 mark
= mystrchr(start
, ' ', tb
->used
);
1127 end
+= (int)(mark
-start
)+1;
1130 end
+= strlen(start
);
1137 if (end
-begin
> 0) {
1139 width
= WMWidthOfString(font
,
1140 &tb
->text
[begin
], end
-begin
);
1142 if (width
> tPtr
->visible
.w
) { /* break this tb up */
1143 char *t
= &tb
->text
[begin
];
1144 int l
=end
-begin
, i
=0;
1146 width
= WMWidthOfString(font
, t
, ++i
);
1147 } while (width
< tPtr
->visible
.w
&& i
< l
);
1149 if (start
) // and since (nil)-4 = 0xfffffffd
1156 if ((lw
>= tPtr
->visible
.w
- x
)
1157 || nitems
>= MAX_TB_PER_LINE
) {
1158 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1160 x
= 0;//tb->margins.first;
1164 items
[nitems
].tb
= tb
;
1165 items
[nitems
].begin
= begin
;
1166 items
[nitems
].end
= end
;
1177 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1179 tPtr
->docHeight
= y
+10;
1180 updateScrollers(tPtr
);
1182 tPtr
->flags
.laidOut
= True
;
1188 textDidResize(W_ViewDelegate
*self
, WMView
*view
)
1190 Text
*tPtr
= (Text
*)view
->self
;
1191 unsigned short w
= WMWidgetWidth(tPtr
);
1192 unsigned short h
= WMWidgetHeight(tPtr
);
1193 unsigned short rh
= 0, vw
= 0;
1195 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
) {
1196 WMMoveWidget(tPtr
->ruler
, 2, 2);
1197 WMResizeWidget(tPtr
->ruler
, w
- 4, 40);
1202 WMMoveWidget(tPtr
->vS
, 1, rh
+ 1);
1203 WMResizeWidget(tPtr
->vS
, 20, h
- rh
- 2);
1205 WMSetRulerOffset(tPtr
->ruler
,22);
1206 } else WMSetRulerOffset(tPtr
->ruler
, 2);
1210 WMMoveWidget(tPtr
->hS
, vw
, h
- 21);
1211 WMResizeWidget(tPtr
->hS
, w
- vw
- 1, 20);
1213 WMMoveWidget(tPtr
->hS
, vw
+1, h
- 21);
1214 WMResizeWidget(tPtr
->hS
, w
- vw
- 2, 20);
1218 tPtr
->visible
.x
= (tPtr
->vS
)?22:2;
1219 tPtr
->visible
.y
= (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)?43:3;
1220 tPtr
->visible
.w
= tPtr
->view
->size
.width
- tPtr
->visible
.x
- 4;
1221 tPtr
->visible
.h
= tPtr
->view
->size
.height
- tPtr
->visible
.y
;
1222 tPtr
->visible
.h
-= (tPtr
->hS
)?20:0;
1224 tPtr
->dmargins
= WMGetRulerMargins(tPtr
->ruler
);
1226 if (tPtr
->view
->flags
.realized
) {
1229 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
1230 tPtr
->db
= (Pixmap
) NULL
;
1233 if (tPtr
->visible
.w
< 40)
1234 tPtr
->visible
.w
= 40;
1235 if (tPtr
->visible
.h
< 20)
1236 tPtr
->visible
.h
= 20;
1238 //if (size change or !db
1240 tPtr
->db
= XCreatePixmap(tPtr
->view
->screen
->display
,
1241 tPtr
->view
->window
, tPtr
->visible
.w
,
1242 tPtr
->visible
.h
, tPtr
->view
->screen
->depth
);
1246 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1249 W_ViewDelegate _TextViewDelegate
=
1257 /* nice, divisble-by-16 blocks */
1258 static inline unsigned short
1259 reqBlockSize(unsigned short requested
)
1261 return requested
+ 16 - (requested
%16);
1266 clearText(Text
*tPtr
)
1268 if (!tPtr
->firstTextBlock
)
1271 while (tPtr
->currentTextBlock
)
1272 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1274 tPtr
->firstTextBlock
= NULL
;
1275 tPtr
->currentTextBlock
= NULL
;
1276 tPtr
->lastTextBlock
= NULL
;
1280 deleteTextInteractively(Text
*tPtr
, KeySym ksym
)
1282 TextBlock
*tb
= tPtr
->currentTextBlock
;
1283 Bool back
= (Bool
) (ksym
== XK_BackSpace
);
1286 if (!tPtr
->flags
.editable
|| tPtr
->flags
.buttonHeld
) {
1287 XBell(tPtr
->view
->screen
->display
, 0);
1294 if (tPtr
->flags
.ownsSelection
) {
1295 removeSelection(tPtr
);
1299 if (back
&& tPtr
->tpos
< 1) {
1302 tPtr
->tpos
= tb
->used
;
1303 tPtr
->currentTextBlock
= tb
;
1308 if ( (tb
->used
> 0) && ((back
?tPtr
->tpos
> 0:1))
1309 && (tPtr
->tpos
<= tb
->used
) && !tb
->graphic
) {
1312 memmove(&(tb
->text
[tPtr
->tpos
]),
1313 &(tb
->text
[tPtr
->tpos
+ 1]), tb
->used
- tPtr
->tpos
);
1318 if ( (back
? (tPtr
->tpos
< 1 && !done
) : ( tPtr
->tpos
>= tb
->used
))
1321 TextBlock
*sibling
= (back
? tb
->prior
: tb
->next
);
1323 if(tb
->used
== 0 || tb
->graphic
)
1324 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1327 tPtr
->currentTextBlock
= sibling
;
1328 tPtr
->tpos
= (back
? sibling
->used
: 0);
1335 insertTextInteractively(Text
*tPtr
, char *text
, int len
)
1338 char *newline
= NULL
;
1340 if (!tPtr
->flags
.editable
|| tPtr
->flags
.buttonHeld
) {
1341 XBell(tPtr
->view
->screen
->display
, 0);
1347 WMColor
*color
= WMCreateNamedColor(W_VIEW_SCREEN(tPtr
->view
),
1349 WMSetTextSelectionColor(tPtr
, color
);
1354 if (len
< 1 || !text
)
1357 if (tPtr
->flags
.ownsSelection
)
1358 removeSelection(tPtr
);
1360 if(tPtr
->flags
.ignoreNewLine
&& *text
== '\n' && len
== 1)
1363 if (tPtr
->flags
.ignoreNewLine
) {
1365 for(i
=0; i
<len
; i
++) {
1366 if (text
[i
] == '\n')
1371 tb
= tPtr
->currentTextBlock
;
1372 if (!tb
|| tb
->graphic
) {
1374 WMAppendTextStream(tPtr
, text
);
1375 if (tPtr
->currentTextBlock
) {
1376 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
1381 if ((newline
= strchr(text
, '\n'))) {
1382 int nlen
= (int)(newline
-text
);
1383 int s
= tb
->used
- tPtr
->tpos
;
1386 if (!tb
->blank
&& nlen
>0) {
1388 memcpy(save
, &tb
->text
[tPtr
->tpos
], s
);
1389 tb
->used
-= (tb
->used
- tPtr
->tpos
);
1392 insertTextInteractively(tPtr
, text
, nlen
);
1394 WMAppendTextStream(tPtr
, newline
);
1396 insertTextInteractively(tPtr
, save
, s
);
1399 if (tPtr
->tpos
>0 && tPtr
->tpos
< tb
->used
1400 && !tb
->graphic
&& tb
->text
) {
1402 void *ntb
= WMCreateTextBlockWithText(&tb
->text
[tPtr
->tpos
],
1403 tb
->d
.font
, tb
->color
, True
, tb
->used
- tPtr
->tpos
);
1404 tb
->used
= tPtr
->tpos
;
1405 WMAppendTextBlock(tPtr
, ntb
);
1407 } else if (tPtr
->tpos
== tb
->used
|| tPtr
->tpos
== 0) {
1408 void *ntb
= WMCreateTextBlockWithText(NULL
,
1409 tb
->d
.font
, tb
->color
, True
, 0);
1412 WMAppendTextBlock(tPtr
, ntb
);
1414 WMPrependTextBlock(tPtr
, ntb
);
1421 if (tb
->used
+ len
>= tb
->allocated
) {
1422 tb
->allocated
= reqBlockSize(tb
->used
+len
);
1423 tb
->text
= wrealloc(tb
->text
, tb
->allocated
);
1427 memcpy(tb
->text
, text
, len
);
1432 memmove(&(tb
->text
[tPtr
->tpos
+len
]), &tb
->text
[tPtr
->tpos
],
1433 tb
->used
-tPtr
->tpos
+1);
1434 memmove(&tb
->text
[tPtr
->tpos
], text
, len
);
1444 selectRegion(Text
*tPtr
, int x
, int y
)
1450 y
+= (tPtr
->flags
.rulerShown
? 40: 0);
1453 y
-= 10; /* the original offset */
1455 x
-= tPtr
->visible
.x
-2;
1459 tPtr
->sel
.x
= WMAX(0, WMIN(tPtr
->clicked
.x
, x
));
1460 tPtr
->sel
.w
= abs(tPtr
->clicked
.x
- x
);
1461 tPtr
->sel
.y
= WMAX(0, WMIN(tPtr
->clicked
.y
, y
));
1462 tPtr
->sel
.h
= abs(tPtr
->clicked
.y
- y
);
1464 tPtr
->flags
.ownsSelection
= True
;
1470 pasteText(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
1471 void *cdata
, WMData
*data
)
1473 Text
*tPtr
= (Text
*)view
->self
;
1476 tPtr
->flags
.waitingForSelection
= False
;
1478 str
= (char*)WMDataBytes(data
);
1479 if (0&&tPtr
->parser
) {
1480 /* parser is not yet well behaved to do this properly..*/
1481 (tPtr
->parser
) (tPtr
, (void *) str
);
1483 insertTextInteractively(tPtr
, str
, strlen(str
));
1485 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1488 str
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
1491 if (0&&tPtr
->parser
) {
1492 /* parser is not yet well behaved to do this properly..*/
1493 (tPtr
->parser
) (tPtr
, (void *) str
);
1495 insertTextInteractively(tPtr
, str
, n
);
1497 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1505 releaseSelection(Text
*tPtr
)
1507 TextBlock
*tb
= tPtr
->firstTextBlock
;
1510 tb
->selected
= False
;
1513 tPtr
->flags
.ownsSelection
= False
;
1514 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
,
1521 requestHandler(WMView
*view
, Atom selection
, Atom target
,
1522 void *cdata
, Atom
*type
)
1524 Text
*tPtr
= view
->self
;
1525 Display
*dpy
= tPtr
->view
->screen
->display
;
1526 Atom TEXT
= XInternAtom(dpy
, "TEXT", False
);
1527 Atom COMPOUND_TEXT
= XInternAtom(dpy
, "COMPOUND_TEXT", False
);
1531 if (target
== XA_STRING
|| target
== TEXT
|| target
== COMPOUND_TEXT
) {
1532 char *text
= WMGetTextSelected(tPtr
);
1535 WMData
*data
= WMCreateDataWithBytes(text
, strlen(text
));
1536 WMSetDataFormat(data
, 8);
1542 } else if(target
== XInternAtom(dpy
, "PIXMAP", False
)) {
1543 data
= WMCreateDataWithBytes("paste a pixmap", 14);
1544 WMSetDataFormat(data
, 8);
1549 _TARGETS
= XInternAtom(dpy
, "TARGETS", False
);
1550 if (target
== _TARGETS
) {
1553 ptr
= wmalloc(4 * sizeof(Atom
));
1557 ptr
[3] = COMPOUND_TEXT
;
1559 data
= WMCreateDataWithBytes(ptr
, 4*4);
1560 WMSetDataFormat(data
, 32);
1571 lostHandler(WMView
*view
, Atom selection
, void *cdata
)
1573 releaseSelection((WMText
*)view
->self
);
1576 static WMSelectionProcs selectionHandler
= {
1577 requestHandler
, lostHandler
, NULL
1581 ownershipObserver(void *observerData
, WMNotification
*notification
)
1583 WMText
*to
= (WMText
*)observerData
;
1584 WMText
*tw
= (WMText
*)WMGetNotificationClientData(notification
);
1586 lostHandler(to
->view
, XA_PRIMARY
, NULL
);
1591 handleTextKeyPress(Text
*tPtr
, XEvent
*event
)
1595 int control_pressed
= False
;
1598 if (((XKeyEvent
*) event
)->state
& ControlMask
)
1599 control_pressed
= True
;
1600 buffer
[XLookupString(&event
->xkey
, buffer
, 1, &ksym
, NULL
)] = 0;
1606 TextBlock
*tb
= tPtr
->currentTextBlock
;
1607 int x
= tPtr
->cursor
.x
+ tPtr
->visible
.x
;
1608 int y
= tPtr
->visible
.y
+ tPtr
->cursor
.y
+ tPtr
->cursor
.h
;
1616 w
= WMWidgetWidth(tb
->d
.widget
);
1618 w
= tb
->d
.pixmap
->width
;
1622 w
= WMWidthOfString(tb
->d
.font
, &tb
->text
[pos
], 1);
1625 cursorToTextPosition(tPtr
, w
+ tPtr
->cursor
.x
+ tPtr
->visible
.x
,
1626 3 + tPtr
->visible
.y
+ tPtr
->cursor
.y
1627 + tPtr
->cursor
.h
- tPtr
->vpos
);
1628 if(x
== tPtr
->cursor
.x
+ tPtr
->visible
.x
) {
1629 printf("same %d %d\n", x
, tPtr
->cursor
.x
+ tPtr
->visible
.x
);
1630 cursorToTextPosition(tPtr
, tPtr
->visible
.x
,
1631 3 + tPtr
->visible
.y
+ tPtr
->cursor
.y
+ tPtr
->cursor
.h
);
1639 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
1640 tPtr
->clicked
.y
+ tPtr
->cursor
.h
- tPtr
->vpos
);
1645 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
1646 tPtr
->visible
.y
+ tPtr
->cursor
.y
- tPtr
->vpos
- 3);
1653 deleteTextInteractively(tPtr
, ksym
);
1654 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1659 control_pressed
= True
;
1665 if (buffer
[0] != 0 && !control_pressed
) {
1666 insertTextInteractively(tPtr
, buffer
, 1);
1667 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1669 } else if (control_pressed
&& ksym
==XK_r
) {
1670 Bool i
= !tPtr
->flags
.rulerShown
;
1671 WMShowTextRuler(tPtr
, i
);
1672 tPtr
->flags
.rulerShown
= i
;
1674 else if (control_pressed
&& buffer
[0] == '\a')
1675 XBell(tPtr
->view
->screen
->display
, 0);
1678 if (!control_pressed
&& tPtr
->flags
.ownsSelection
)
1679 releaseSelection(tPtr
);
1683 handleWidgetPress(XEvent
*event
, void *data
)
1685 TextBlock
*tb
= (TextBlock
*)data
;
1691 /* this little bit of nastiness here saves a boatload of trouble */
1692 w
= (WMWidget
*)(((W_VIEW(tb
->d
.widget
))->parent
)->self
);
1693 if (W_CLASS(w
) != WC_Text
)
1696 tPtr
->currentTextBlock
= getFirstNonGraphicBlockFor(tb
, 1);
1697 if (!tPtr
->currentTextBlock
)
1698 tPtr
->currentTextBlock
= tb
;
1700 output(tPtr
->currentTextBlock
->text
, tPtr
->currentTextBlock
->used
);
1701 //if (!tPtr->flags.focused) {
1702 // WMSetFocusToWidget(tPtr);
1703 // tPtr->flags.focused = True;
1709 handleActionEvents(XEvent
*event
, void *data
)
1711 Text
*tPtr
= (Text
*)data
;
1712 Display
*dpy
= event
->xany
.display
;
1716 switch (event
->type
) {
1718 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
1719 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
1720 tPtr
->flags
.extendSelection
= True
;
1724 if (tPtr
->flags
.waitingForSelection
)
1726 if (tPtr
->flags
.focused
) {
1727 XGrabPointer(dpy
, W_VIEW(tPtr
)->window
, False
,
1728 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
1729 GrabModeAsync
, GrabModeAsync
, None
,
1730 tPtr
->view
->screen
->invisibleCursor
, CurrentTime
);
1731 tPtr
->flags
.pointerGrabbed
= True
;
1732 handleTextKeyPress(tPtr
, event
);
1737 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
1738 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
1739 tPtr
->flags
.extendSelection
= False
;
1741 //end modify flag so selection can be extended
1747 if (tPtr
->flags
.pointerGrabbed
) {
1748 tPtr
->flags
.pointerGrabbed
= False
;
1749 XUngrabPointer(dpy
, CurrentTime
);
1752 if ((event
->xmotion
.state
& Button1Mask
)) {
1753 if (!tPtr
->flags
.ownsSelection
) {
1754 WMCreateSelectionHandler(tPtr
->view
, XA_PRIMARY
,
1755 event
->xbutton
.time
, &selectionHandler
, NULL
);
1756 tPtr
->flags
.ownsSelection
= True
;
1758 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
1764 tPtr
->flags
.buttonHeld
= True
;
1765 if (tPtr
->flags
.extendSelection
) {
1766 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
1769 if (event
->xbutton
.button
== Button1
) {
1771 if (!tPtr
->flags
.focused
) {
1772 WMSetFocusToWidget(tPtr
);
1773 tPtr
->flags
.focused
= True
;
1776 if (tPtr
->flags
.ownsSelection
)
1777 releaseSelection(tPtr
);
1778 cursorToTextPosition(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
1780 if (tPtr
->flags
.pointerGrabbed
) {
1781 tPtr
->flags
.pointerGrabbed
= False
;
1782 XUngrabPointer(dpy
, CurrentTime
);
1787 if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelDown
)
1788 WMScrollText(tPtr
, -16);
1789 else if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelUp
)
1790 WMScrollText(tPtr
, 16);
1794 tPtr
->flags
.buttonHeld
= False
;
1795 if (tPtr
->flags
.pointerGrabbed
) {
1796 tPtr
->flags
.pointerGrabbed
= False
;
1797 XUngrabPointer(dpy
, CurrentTime
);
1800 if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelDown
1801 || event
->xbutton
.button
== WINGsConfiguration
.mouseWheelUp
)
1804 if (event
->xbutton
.button
== Button2
) {
1808 if (!tPtr
->flags
.editable
) {
1813 if (!WMRequestSelection(tPtr
->view
, XA_PRIMARY
, XA_STRING
,
1814 event
->xbutton
.time
, pasteText
, NULL
)) {
1815 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
1818 if (0&&tPtr
->parser
) {
1819 /* parser is not yet well behaved to do this properly..*/
1820 (tPtr
->parser
) (tPtr
, (void *) text
);
1822 insertTextInteractively(tPtr
, text
, n
-1);
1824 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1826 } else tPtr
->flags
.waitingForSelection
= True
;
1837 handleEvents(XEvent
*event
, void *data
)
1839 Text
*tPtr
= (Text
*)data
;
1841 switch(event
->type
) {
1845 if (!(W_VIEW(tPtr
->hS
))->flags
.realized
)
1846 WMRealizeWidget(tPtr
->hS
);
1847 if (!((W_VIEW(tPtr
->hS
))->flags
.mapped
))
1848 WMMapWidget(tPtr
->hS
);
1852 if (!(W_VIEW(tPtr
->vS
))->flags
.realized
)
1853 WMRealizeWidget(tPtr
->vS
);
1854 if (!((W_VIEW(tPtr
->vS
))->flags
.mapped
))
1855 WMMapWidget(tPtr
->vS
);
1859 if (!(W_VIEW(tPtr
->ruler
))->flags
.realized
)
1860 WMRealizeWidget(tPtr
->ruler
);
1862 if (!((W_VIEW(tPtr
->ruler
))->flags
.mapped
)
1863 && tPtr
->flags
.rulerShown
)
1864 WMMapWidget(tPtr
->ruler
);
1867 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
1869 if (!event
->xexpose
.count
&& tPtr
->view
->flags
.realized
)
1874 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))
1877 tPtr
->flags
.focused
= True
;
1879 if (tPtr
->flags
.editable
&& !tPtr
->timerID
) {
1880 tPtr
->timerID
= WMAddTimerHandler(12+0*CURSOR_BLINK_ON_DELAY
,
1888 tPtr
->flags
.focused
= False
;
1891 if (tPtr
->timerID
) {
1892 WMDeleteTimerHandler(tPtr
->timerID
);
1893 tPtr
->timerID
= NULL
;
1901 WMDestroyWidget(tPtr
->hS
);
1903 WMDestroyWidget(tPtr
->vS
);
1905 WMDestroyWidget(tPtr
->ruler
);
1907 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
1909 WMFreeBag(tPtr
->gfxItems
);
1912 WMDeleteTimerHandler(tPtr
->timerID
);
1914 WMReleaseFont(tPtr
->dFont
);
1915 WMReleaseColor(tPtr
->dColor
);
1916 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
, CurrentTime
);
1917 WMRemoveNotificationObserver(tPtr
);
1928 insertPlainText(WMText
*tPtr
, char *text
)
1940 mark
= strchr(start
, '\n');
1942 tb
= WMCreateTextBlockWithText(start
, tPtr
->dFont
,
1943 tPtr
->dColor
, True
, (int)(mark
-start
));
1946 if (start
&& strlen(start
)) {
1947 tb
= WMCreateTextBlockWithText(start
, tPtr
->dFont
,
1948 tPtr
->dColor
, False
, strlen(start
));
1953 if (tPtr
->flags
.prepend
)
1954 WMPrependTextBlock(tPtr
, tb
);
1956 WMAppendTextBlock(tPtr
, tb
);
1964 rulerMoveCallBack(WMWidget
*w
, void *self
)
1966 Text
*tPtr
= (Text
*)self
;
1969 if (W_CLASS(tPtr
) != WC_Text
)
1977 rulerReleaseCallBack(WMWidget
*w
, void *self
)
1979 Text
*tPtr
= (Text
*)self
;
1982 if (W_CLASS(tPtr
) != WC_Text
)
1985 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1992 draggingEntered(WMView
*self
, WMDraggingInfo
*info
)
1994 printf("draggingEntered\n");
1995 return WDOperationCopy
;
2000 draggingUpdated(WMView
*self
, WMDraggingInfo
*info
)
2002 printf("draggingUpdated\n");
2003 return WDOperationCopy
;
2008 draggingExited(WMView
*self
, WMDraggingInfo
*info
)
2010 printf("draggingExited\n");
2014 prepareForDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2016 printf("draggingExited\n");
2017 return;//"bll"; //"application/X-color";
2022 performDragOperation(WMView
*self
, WMDraggingInfo
*info
) //, WMData *data)
2024 char *colorName
= "Blue";// (char*)WMDataBytes(data);
2026 WMText
*tPtr
= (WMText
*)self
->self
;
2031 if (tPtr
->flags
.monoFont
)
2034 color
= WMCreateNamedColor(W_VIEW_SCREEN(self
), colorName
, True
);
2035 printf("color [%s] %p\n", colorName
, color
);
2037 WMSetTextSelectionColor(tPtr
, color
);
2038 WMReleaseColor(color
);
2045 concludeDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2047 printf("concludeDragOperation\n");
2051 static WMDragDestinationProcs _DragDestinationProcs
= {
2055 prepareForDragOperation
,
2056 performDragOperation
,
2057 concludeDragOperation
2062 releaseBagData(void *data
)
2070 getStream(WMText
*tPtr
, int sel
)
2072 TextBlock
*tb
= NULL
;
2074 unsigned long length
= 0, where
= 0;
2079 if (!(tb
= tPtr
->firstTextBlock
))
2082 /* this might be tricky to get right... not yet implemented */
2084 (tPtr
->writer
) (tPtr
, (void *) text
);
2089 /* first, how large a buffer would we want? */
2092 if (!tb
->graphic
|| (tb
->graphic
&& !tPtr
->flags
.monoFont
)) {
2095 if (!sel
|| (tb
->graphic
&& tb
->selected
)) {
2097 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
))
2100 length
+= 1; /* field markers 0xFA and 0xCE */
2101 } else if (sel
&& tb
->selected
) {
2102 length
+= (tb
->s_end
- tb
->s_begin
);
2103 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
))
2111 text
= wmalloc(length
+1); /* +1 for the end of string, let's be nice */
2112 tb
= tPtr
->firstTextBlock
;
2115 if (!tb
->graphic
|| (tb
->graphic
&& !tPtr
->flags
.monoFont
)) {
2118 if (!sel
|| (tb
->graphic
&& tb
->selected
)) {
2119 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
))
2120 text
[where
++] = '\n';
2122 text
[where
++] = 0xFA;
2123 memcpy(&text
[where
], tb
->text
, tb
->used
);
2126 text
[where
++] = 0xCE;
2128 } else if (sel
&& tb
->selected
) {
2129 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
))
2130 text
[where
++] = '\n';
2131 memcpy(&text
[where
], &tb
->text
[tb
->s_begin
],
2132 tb
->s_end
- tb
->s_begin
);
2133 where
+= tb
->s_end
- tb
->s_begin
;
2147 getStreamIntoBag(WMText
*tPtr
, int sel
)
2149 char *stream
, *start
= NULL
, *fa
= NULL
, *ce
= NULL
;
2156 stream
= getStream(tPtr
, sel
);
2160 bag
= WMCreateArrayBagWithDestructor(4, releaseBagData
);
2164 fa
= strchr(start
, 0xFA);
2166 data
= WMCreateDataWithBytes((void *)start
, (int)(fa
- start
));
2167 WMSetDataFormat(data
, 8);
2168 //desc = wmalloc((int)(fa - start));
2169 //memcpy(desc, start, (int)(fa - start));
2170 WMPutInBag(bag
, (void *) data
);
2172 ce
= strchr(fa
, 0xCE);
2174 data
= WMCreateDataWithBytes(fa
+1, ((int)(ce
- fa
))-1);
2175 WMSetDataFormat(data
, 32);
2176 WMPutInBag(bag
, (void *) data
);
2183 if (start
&& strlen(start
)) {
2184 data
= WMCreateDataWithBytes((void *)start
, strlen(start
));
2185 WMSetDataFormat(data
, 8);
2186 // desc = wmalloc(strlen(start));
2187 // memcpy(desc, start, strlen(start));
2188 WMPutInBag(bag
, (void *) data
);
2200 WMCreateText(WMWidget
*parent
)
2202 Text
*tPtr
= wmalloc(sizeof(Text
));
2204 printf("could not create text widget\n");
2209 printf("sizeof:\n");
2210 printf(" TextBlock %d\n", sizeof(TextBlock
));
2211 printf(" Section %d\n", sizeof(Section
));
2212 printf(" WMRulerMargins %d\n", sizeof(WMRulerMargins
));
2213 printf(" char * %d\n", sizeof(char *));
2214 printf(" void * %d\n", sizeof(void *));
2215 printf(" short %d\n", sizeof(short));
2216 printf(" Text %d\n", sizeof(Text
));
2219 memset(tPtr
, 0, sizeof(Text
));
2220 tPtr
->widgetClass
= WC_Text
;
2221 tPtr
->view
= W_CreateView(W_VIEW(parent
));
2223 perror("could not create text's view\n");
2227 tPtr
->view
->self
= tPtr
;
2228 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->textCursor
;
2229 tPtr
->view
->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2230 W_ResizeView(tPtr
->view
, 250, 200);
2231 tPtr
->bgGC
= WMColorGC(tPtr
->view
->screen
->white
);
2232 tPtr
->fgGC
= WMColorGC(tPtr
->view
->screen
->black
);
2233 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->view
->screen
->white
);
2239 tPtr
->dFont
= WMRetainFont(tPtr
->view
->screen
->normalFont
);
2241 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
2243 tPtr
->view
->delegate
= &_TextViewDelegate
;
2246 tPtr
->timerID
= NULL
;
2249 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
2250 |EnterWindowMask
|LeaveWindowMask
|FocusChangeMask
,
2251 handleEvents
, tPtr
);
2253 WMCreateEventHandler(tPtr
->view
, ButtonReleaseMask
|ButtonPressMask
2254 |KeyReleaseMask
|KeyPressMask
|Button1MotionMask
,
2255 handleActionEvents
, tPtr
);
2257 WMAddNotificationObserver(ownershipObserver
, tPtr
, "_lostOwnership", tPtr
);
2260 WMSetViewDragDestinationProcs(tPtr
->view
, &_DragDestinationProcs
);
2262 char *types
[2] = {"application/X-color", NULL
};
2263 WMRegisterViewForDraggedTypes(tPtr
->view
, types
);
2267 tPtr
->firstTextBlock
= NULL
;
2268 tPtr
->lastTextBlock
= NULL
;
2269 tPtr
->currentTextBlock
= NULL
;
2272 tPtr
->gfxItems
= WMCreateArrayBag(4);
2274 tPtr
->parser
= NULL
;
2275 tPtr
->writer
= NULL
;
2277 tPtr
->sel
.x
= tPtr
->sel
.y
= 2;
2278 tPtr
->sel
.w
= tPtr
->sel
.h
= 0;
2280 tPtr
->clicked
.x
= tPtr
->clicked
.y
= 2;
2282 tPtr
->visible
.x
= tPtr
->visible
.y
= 2;
2283 tPtr
->visible
.h
= tPtr
->view
->size
.height
;
2284 tPtr
->visible
.w
= tPtr
->view
->size
.width
- 4;
2286 tPtr
->cursor
.x
= -23;
2289 tPtr
->docHeight
= 0;
2290 tPtr
->dBulletPix
= WMCreatePixmapFromXPMData(tPtr
->view
->screen
,
2292 tPtr
->db
= (Pixmap
) NULL
;
2294 tPtr
->dmargins
= WMGetRulerMargins(tPtr
->ruler
);
2296 tPtr
->flags
.rulerShown
= False
;
2297 tPtr
->flags
.monoFont
= False
;
2298 tPtr
->flags
.focused
= False
;
2299 tPtr
->flags
.editable
= True
;
2300 tPtr
->flags
.ownsSelection
= False
;
2301 tPtr
->flags
.pointerGrabbed
= False
;
2302 tPtr
->flags
.buttonHeld
= False
;
2303 tPtr
->flags
.waitingForSelection
= False
;
2304 tPtr
->flags
.extendSelection
= False
;
2305 tPtr
->flags
.frozen
= False
;
2306 tPtr
->flags
.cursorShown
= True
;
2307 tPtr
->flags
.clickPos
= 1;
2308 tPtr
->flags
.ignoreNewLine
= False
;
2309 tPtr
->flags
.laidOut
= False
;
2310 tPtr
->flags
.prepend
= False
;
2311 tPtr
->flags
.relief
= WRFlat
;
2312 tPtr
->flags
.alignment
= WALeft
;
2318 WMPrependTextStream(WMText
*tPtr
, char *text
)
2324 releaseSelection(tPtr
);
2326 tPtr
->flags
.prepend
= True
;
2327 if (text
&& tPtr
->parser
)
2328 (tPtr
->parser
) (tPtr
, (void *) text
);
2330 insertPlainText(tPtr
, text
);
2336 WMAppendTextStream(WMText
*tPtr
, char *text
)
2342 releaseSelection(tPtr
);
2344 tPtr
->flags
.prepend
= False
;
2345 if (text
&& tPtr
->parser
)
2346 (tPtr
->parser
) (tPtr
, (void *) text
);
2348 insertPlainText(tPtr
, text
);
2354 WMGetTextStream(WMText
*tPtr
)
2356 return getStream(tPtr
, 0);
2360 WMGetTextSelected(WMText
*tPtr
)
2362 return getStream(tPtr
, 1);
2366 WMGetTextStreamIntoBag(WMText
*tPtr
)
2368 return getStreamIntoBag(tPtr
, 0);
2372 WMGetTextSelectedIntoBag(WMText
*tPtr
)
2374 return getStreamIntoBag(tPtr
, 1);
2379 WMCreateTextBlockWithObject(WMWidget
*w
, char *description
, WMColor
*color
,
2380 unsigned short first
, unsigned short reserved
)
2383 unsigned short length
;
2385 if (!w
|| !description
|| !color
)
2388 tb
= wmalloc(sizeof(TextBlock
));
2392 length
= strlen(description
);
2393 tb
->text
= (char *)wmalloc(length
);
2394 memset(tb
->text
, 0, length
);
2395 memcpy(tb
->text
, description
, length
);
2399 tb
->color
= WMRetainColor(color
);
2400 //&tb->margins = NULL;
2406 tb
->underlined
= False
;
2407 tb
->selected
= False
;
2409 tb
->sections
= NULL
;
2419 WMCreateTextBlockWithPixmap(WMPixmap
*p
, char *description
, WMColor
*color
,
2420 unsigned short first
, unsigned short reserved
)
2423 unsigned short length
;
2425 if (!p
|| !description
|| !color
)
2428 tb
= wmalloc(sizeof(TextBlock
));
2432 length
= strlen(description
);
2433 tb
->text
= (char *)wmalloc(length
);
2434 memset(tb
->text
, 0, length
);
2435 memcpy(tb
->text
, description
, length
);
2439 tb
->color
= WMRetainColor(color
);
2440 //&tb->margins = NULL;
2446 tb
->underlined
= False
;
2447 tb
->selected
= False
;
2449 tb
->sections
= NULL
;
2458 WMCreateTextBlockWithText(char *text
, WMFont
*font
, WMColor
*color
,
2459 unsigned short first
, unsigned short length
)
2463 if (!font
|| !color
)
2466 tb
= wmalloc(sizeof(TextBlock
));
2470 tb
->allocated
= reqBlockSize(length
);
2471 tb
->text
= (char *)wmalloc(tb
->allocated
);
2472 memset(tb
->text
, 0, tb
->allocated
);
2474 if (length
< 1|| !text
) { // || *text == '\n') {
2479 memcpy(tb
->text
, text
, length
);
2484 tb
->d
.font
= WMRetainFont(font
);
2485 tb
->color
= WMRetainColor(color
);
2488 tb
->graphic
= False
;
2489 tb
->underlined
= False
;
2490 tb
->selected
= False
;
2492 tb
->sections
= NULL
;
2500 WMSetTextBlockProperties(void *vtb
, unsigned int first
,
2501 unsigned int kanji
, unsigned int underlined
, int script
,
2502 WMRulerMargins margins
)
2504 TextBlock
*tb
= (TextBlock
*) vtb
;
2510 tb
->underlined
= underlined
;
2511 tb
->script
= script
;
2513 tb
->margins
.left
= margins
.left
;
2514 tb
->margins
.first
= margins
.first
;
2515 tb
->margins
.body
= margins
.body
;
2516 tb
->margins
.right
= margins
.right
;
2517 for: tb
->margins
.tabs
= margins
.tabs
;
2522 WMGetTextBlockProperties(void *vtb
, unsigned int *first
,
2523 unsigned int *kanji
, unsigned int *underlined
, int *script
,
2524 WMRulerMargins
*margins
)
2526 TextBlock
*tb
= (TextBlock
*) vtb
;
2530 if (first
) *first
= tb
->first
;
2531 if (kanji
) *kanji
= tb
->kanji
;
2532 if (underlined
) *underlined
= tb
->underlined
;
2533 if (script
) *script
= tb
->script
;
2537 (*margins
).left
= tb
->margins
.left
;
2538 (*margins
).first
= tb
->margins
.first
;
2539 (*margins
).body
= tb
->margins
.body
;
2540 (*margins
).right
= tb
->margins
.right
;
2541 //for: (*margins).tabs = tb->margins.tabs;
2549 WMPrependTextBlock(WMText
*tPtr
, void *vtb
)
2551 TextBlock
*tb
= (TextBlock
*)vtb
;
2558 WMWidget
*w
= tb
->d
.widget
;
2559 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
2560 handleWidgetPress
, tb
);
2561 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
2562 (W_VIEW(w
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
2563 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2566 WMPutInBag(tPtr
->gfxItems
, (void *)tb
);
2568 } else tPtr
->tpos
= tb
->used
;
2570 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
2571 tb
->next
= tb
->prior
= NULL
;
2572 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
2573 = tPtr
->currentTextBlock
= tb
;
2577 tb
->next
= tPtr
->currentTextBlock
;
2578 tb
->prior
= tPtr
->currentTextBlock
->prior
;
2579 if (tPtr
->currentTextBlock
->prior
)
2580 tPtr
->currentTextBlock
->prior
->next
= tb
;
2582 tPtr
->currentTextBlock
->prior
= tb
;
2584 tPtr
->firstTextBlock
= tb
;
2586 tPtr
->currentTextBlock
= tb
;
2591 WMAppendTextBlock(WMText
*tPtr
, void *vtb
)
2593 TextBlock
*tb
= (TextBlock
*)vtb
;
2600 WMWidget
*w
= tb
->d
.widget
;
2601 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
2602 handleWidgetPress
, tb
);
2603 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
2604 (W_VIEW(w
))->attribs
.cursor
=
2605 tPtr
->view
->screen
->defaultCursor
;
2606 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2609 WMPutInBag(tPtr
->gfxItems
, (void *)tb
);
2611 } else tPtr
->tpos
= tb
->used
;
2613 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
2614 tb
->next
= tb
->prior
= NULL
;
2615 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
2616 = tPtr
->currentTextBlock
= tb
;
2620 tb
->next
= tPtr
->currentTextBlock
->next
;
2621 tb
->prior
= tPtr
->currentTextBlock
;
2622 if (tPtr
->currentTextBlock
->next
)
2623 tPtr
->currentTextBlock
->next
->prior
= tb
;
2625 tPtr
->currentTextBlock
->next
= tb
;
2628 tPtr
->lastTextBlock
= tb
;
2630 tPtr
->currentTextBlock
= tb
;
2634 WMRemoveTextBlock(WMText
*tPtr
)
2636 TextBlock
*tb
= NULL
;
2638 if (!tPtr
|| !tPtr
->firstTextBlock
|| !tPtr
->lastTextBlock
2639 || !tPtr
->currentTextBlock
) {
2640 printf("cannot remove non existent TextBlock!\b");
2644 tb
= tPtr
->currentTextBlock
;
2646 WMRemoveFromBag(tPtr
->gfxItems
, (void *)tb
);
2649 WMDeleteEventHandler(W_VIEW(tb
->d
.widget
), ButtonPressMask
,
2650 handleWidgetPress
, tb
);
2651 WMUnmapWidget(tb
->d
.widget
);
2655 if (tPtr
->currentTextBlock
== tPtr
->firstTextBlock
) {
2656 if (tPtr
->currentTextBlock
->next
)
2657 tPtr
->currentTextBlock
->next
->prior
= NULL
;
2659 tPtr
->firstTextBlock
= tPtr
->currentTextBlock
->next
;
2660 tPtr
->currentTextBlock
= tPtr
->firstTextBlock
;
2662 } else if (tPtr
->currentTextBlock
== tPtr
->lastTextBlock
) {
2663 tPtr
->currentTextBlock
->prior
->next
= NULL
;
2664 tPtr
->lastTextBlock
= tPtr
->currentTextBlock
->prior
;
2665 tPtr
->currentTextBlock
= tPtr
->lastTextBlock
;
2667 tPtr
->currentTextBlock
->prior
->next
= tPtr
->currentTextBlock
->next
;
2668 tPtr
->currentTextBlock
->next
->prior
= tPtr
->currentTextBlock
->prior
;
2669 tPtr
->currentTextBlock
= tPtr
->currentTextBlock
->next
;
2676 WMDestroyTextBlock(WMText
*tPtr
, void *vtb
)
2678 TextBlock
*tb
= (TextBlock
*)vtb
;
2684 /* naturally, there's a danger to destroying
2685 widgets whose action brings us here:
2686 ie. press a button to destroy it... need to
2687 find a safer way. till then... this stays commented out */
2688 //WMDestroyWidget(tb->d.widget);
2689 //wfree(tb->d.widget);
2690 tb
->d
.widget
= NULL
;
2692 WMReleasePixmap(tb
->d
.pixmap
);
2693 tb
->d
.pixmap
= NULL
;
2696 WMReleaseFont(tb
->d
.font
);
2699 WMReleaseColor(tb
->color
);
2700 if (tb
->sections
&& tb
->nsections
> 0)
2701 wfree(tb
->sections
);
2709 WMRefreshText(WMText
*tPtr
, int vpos
, int hpos
)
2711 if (!tPtr
|| vpos
<0 || hpos
<0)
2714 if (tPtr
->flags
.frozen
)
2717 if(tPtr
->flags
.monoFont
) {
2718 int j
, c
= WMGetBagItemCount(tPtr
->gfxItems
);
2721 /* make sure to unmap widgets no matter where they are */
2722 for(j
=0; j
<c
; j
++) {
2723 if ((tb
= (TextBlock
*) WMGetFromBag(tPtr
->gfxItems
, j
))) {
2724 if (tb
->object
&& ((W_VIEW(tb
->d
.widget
))->flags
.mapped
))
2725 WMUnmapWidget(tb
->d
.widget
);
2731 if (tPtr
->vpos
!= vpos
) {
2732 if (vpos
< 0 || tPtr
->docHeight
< tPtr
->visible
.h
) {
2734 } else if(tPtr
->docHeight
- vpos
> tPtr
->visible
.h
- tPtr
->visible
.y
) {
2737 tPtr
->vpos
= tPtr
->docHeight
- tPtr
->visible
.h
;
2741 tPtr
->flags
.laidOut
= False
;
2742 layOutDocument(tPtr
);
2743 updateScrollers(tPtr
);
2749 WMSetTextForegroundColor(WMText
*tPtr
, WMColor
*color
)
2755 tPtr
->fgGC
= WMColorGC(color
);
2757 tPtr
->fgGC
= WMColorGC(WMBlackColor(tPtr
->view
->screen
));
2759 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2763 WMSetTextBackgroundColor(WMText
*tPtr
, WMColor
*color
)
2769 tPtr
->bgGC
= WMColorGC(color
);
2770 W_SetViewBackgroundColor(tPtr
->view
, color
);
2772 tPtr
->bgGC
= WMColorGC(WMWhiteColor(tPtr
->view
->screen
));
2773 W_SetViewBackgroundColor(tPtr
->view
,
2774 WMWhiteColor(tPtr
->view
->screen
));
2777 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2781 WMSetTextRelief(WMText
*tPtr
, WMReliefType relief
)
2785 tPtr
->flags
.relief
= relief
;
2790 WMSetTextHasHorizontalScroller(WMText
*tPtr
, Bool shouldhave
)
2795 if (shouldhave
&& !tPtr
->hS
) {
2796 tPtr
->hS
= WMCreateScroller(tPtr
);
2797 (W_VIEW(tPtr
->hS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
2798 (W_VIEW(tPtr
->hS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2799 WMSetScrollerArrowsPosition(tPtr
->hS
, WSAMaxEnd
);
2800 WMSetScrollerAction(tPtr
->hS
, scrollersCallBack
, tPtr
);
2801 } else if (!shouldhave
&& tPtr
->hS
) {
2802 WMUnmapWidget(tPtr
->hS
);
2803 WMDestroyWidget(tPtr
->hS
);
2809 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2814 WMSetTextHasRuler(WMText
*tPtr
, Bool shouldhave
)
2819 if(shouldhave
&& !tPtr
->ruler
) {
2820 tPtr
->ruler
= WMCreateRuler(tPtr
);
2821 (W_VIEW(tPtr
->ruler
))->attribs
.cursor
=
2822 tPtr
->view
->screen
->defaultCursor
;
2823 (W_VIEW(tPtr
->ruler
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2824 WMSetRulerReleaseAction(tPtr
->ruler
, rulerReleaseCallBack
, tPtr
);
2825 WMSetRulerMoveAction(tPtr
->ruler
, rulerMoveCallBack
, tPtr
);
2826 } else if(!shouldhave
&& tPtr
->ruler
) {
2827 WMShowTextRuler(tPtr
, False
);
2828 WMDestroyWidget(tPtr
->ruler
);
2831 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2835 WMShowTextRuler(WMText
*tPtr
, Bool show
)
2842 if(tPtr
->flags
.monoFont
)
2845 tPtr
->flags
.rulerShown
= show
;
2847 WMMapWidget(tPtr
->ruler
);
2849 WMUnmapWidget(tPtr
->ruler
);
2852 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2856 WMGetTextRulerShown(WMText
*tPtr
)
2864 return tPtr
->flags
.rulerShown
;
2869 WMSetTextHasVerticalScroller(WMText
*tPtr
, Bool shouldhave
)
2874 if (shouldhave
&& !tPtr
->vS
) {
2875 tPtr
->vS
= WMCreateScroller(tPtr
);
2876 (W_VIEW(tPtr
->vS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
2877 (W_VIEW(tPtr
->vS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2878 WMSetScrollerArrowsPosition(tPtr
->vS
, WSAMaxEnd
);
2879 WMSetScrollerAction(tPtr
->vS
, scrollersCallBack
, tPtr
);
2880 } else if (!shouldhave
&& tPtr
->vS
) {
2881 WMUnmapWidget(tPtr
->vS
);
2882 WMDestroyWidget(tPtr
->vS
);
2888 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2894 WMScrollText(WMText
*tPtr
, int amount
)
2899 if (amount
== 0 || !tPtr
->view
->flags
.realized
)
2903 if (tPtr
->vpos
> 0) {
2904 if (tPtr
->vpos
> amount
) tPtr
->vpos
+= amount
;
2908 int limit
= tPtr
->docHeight
- tPtr
->visible
.h
;
2909 if (tPtr
->vpos
< limit
) {
2910 if (tPtr
->vpos
< limit
-amount
) tPtr
->vpos
+= amount
;
2911 else tPtr
->vpos
= limit
;
2915 if (scroll
&& tPtr
->vpos
!= tPtr
->prevVpos
) {
2916 updateScrollers(tPtr
);
2919 tPtr
->prevVpos
= tPtr
->vpos
;
2924 WMPageText(WMText
*tPtr
, Bool direction
)
2926 if (!tPtr
) return False
;
2927 if (!tPtr
->view
->flags
.realized
) return False
;
2929 return WMScrollText(tPtr
, direction
?tPtr
->visible
.h
:-tPtr
->visible
.h
);
2933 WMSetTextEditable(WMText
*tPtr
, Bool editable
)
2937 tPtr
->flags
.editable
= editable
;
2941 WMGetTextEditable(WMText
*tPtr
)
2945 return tPtr
->flags
.editable
;
2949 WMSetTextIgnoresNewline(WMText
*tPtr
, Bool ignore
)
2953 tPtr
->flags
.ignoreNewLine
= ignore
;
2957 WMGetTextIgnoresNewline(WMText
*tPtr
)
2961 return tPtr
->flags
.ignoreNewLine
;
2965 WMSetTextUsesMonoFont(WMText
*tPtr
, Bool mono
)
2969 if (mono
&& tPtr
->flags
.rulerShown
)
2970 WMShowTextRuler(tPtr
, False
);
2972 tPtr
->flags
.monoFont
= mono
;
2973 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2977 WMGetTextUsesMonoFont(WMText
*tPtr
)
2981 return tPtr
->flags
.monoFont
;
2986 WMSetTextDefaultFont(WMText
*tPtr
, WMFont
*font
)
2991 WMReleaseFont(tPtr
->dFont
);
2995 tPtr
->dFont
= WMRetainFont(tPtr
->view
->screen
->normalFont
);
2999 WMGetTextDefaultFont(WMText
*tPtr
)
3008 WMSetTextAlignment(WMText
*tPtr
, WMAlignment alignment
)
3012 tPtr
->flags
.alignment
= alignment
;
3013 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
3017 WMSetTextParser(WMText
*tPtr
, WMAction
*parser
)
3021 tPtr
->parser
= parser
;
3025 WMSetTextWriter(WMText
*tPtr
, WMAction
*writer
)
3029 tPtr
->writer
= writer
;
3033 WMGetTextInsertType(WMText
*tPtr
)
3037 return tPtr
->flags
.prepend
;
3042 WMSetTextSelectionColor(WMText
*tPtr
, WMColor
*color
)
3045 if (!tPtr
|| !color
)
3048 tb
= tPtr
->firstTextBlock
;
3049 if (!tb
|| !tPtr
->flags
.ownsSelection
)
3055 if ( (tb
->s_end
- tb
->s_begin
== tb
->used
) || tb
->graphic
) {
3057 WMReleaseColor(tb
->color
);
3058 tb
->color
= WMRetainColor(color
);
3060 } else if (tb
->s_end
<= tb
->used
) {
3062 TextBlock
*otb
= tb
;
3064 TextBlock
*ntb
= (TextBlock
*) WMCreateTextBlockWithText(
3065 &(tb
->text
[tb
->s_begin
]),
3066 tb
->d
.font
, color
, False
, (tb
->s_end
- tb
->s_begin
));
3069 ntb
->selected
= True
;
3071 ntb
->s_end
= ntb
->used
;
3072 WMAppendTextBlock(tPtr
, ntb
);
3077 if (tb
->used
> tb
->s_end
) {
3078 ntb
= (TextBlock
*) WMCreateTextBlockWithText(
3079 &(tb
->text
[tb
->s_end
]),
3080 tb
->d
.font
, tb
->color
, False
, tb
->used
- tb
->s_end
);
3082 ntb
->selected
= True
;
3084 ntb
->s_end
= ntb
->used
;
3085 WMAppendTextBlock(tPtr
, ntb
);
3093 else if (count
== 2)
3094 tb
= otb
->next
->next
;
3096 tb
->used
= tb
->s_end
= tb
->s_begin
;
3103 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
3107 WMSetTextSelectionFont(WMText
*tPtr
, WMFont
*font
)
3113 tb
= tPtr
->firstTextBlock
;
3114 if (!tb
|| !tPtr
->flags
.ownsSelection
)
3119 tb
->d
.font
= WMRetainFont(font
);
3122 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
3126 WMFreezeText(WMText
*tPtr
)
3131 tPtr
->flags
.frozen
= True
;
3135 WMThawText(WMText
*tPtr
)
3140 tPtr
->flags
.frozen
= False
;
3145 WMFindInTextStream(WMText
*tPtr
, char *needle
)
3147 char *haystack
= NULL
;
3150 if (!tPtr
|| !needle
)
3153 if ( !(haystack
= "WMGetTextStream(tPtr)"))
3156 result
= (Bool
) strstr(haystack
, needle
);