2 * WINGs WMText: multi-line/font/color/graphic text widget
4 * Copyright (c) 1999-2000 Nwanua Elumeze <nwanua@windowmaker.org>
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>
30 * - FIX: graphix blocks MUST be skipped if monoFont even though they exist!
31 * - FIX wrap... long lines that don't fit are not char wrapped yet.
32 * - check if support for Horizontal Scroll is complete
33 * - FIX html parser: 1. <b>foo</i> should STILL BE BOLD!
34 * - 2. " foo > bar " should not confuse it.
35 * - assess danger of destroying widgets whose actions link to other pages
36 * - change cursor shape around pixmaps
37 * - redo blink code to reduce paint event... use pixmap buffer...
38 * - add paragraph support (full) and '\n' code in getStream..
39 * - use currentTextBlock and neighbours for fast paint and layout
40 * - replace copious uses of Refreshtext with appropriate layOut()...
44 /* a Section is a section of a TextBlock that describes what parts
45 of a TextBlock has been laid out on which "line"...
46 o this greatly aids redraw, scroll and selection.
47 o this is created during layoutLine, but may be later modified.
48 o there may be many Sections per TextBlock, hence the array */
50 unsigned int x
, y
; /* where to draw it from */
51 unsigned short w
, h
; /* its width and height */
52 unsigned short begin
; /* where the layout begins */
53 unsigned short end
; /* where it ends */
54 unsigned short last
:1; /* is it the last section on a "line"? */
55 unsigned int _y
:31; /* the "line" it and other textblocks are on */
59 /* a TextBlock is a doubly-linked list of TextBlocks containing:
60 o text for the block, color and font
61 o or a pointer to the pixmap
62 o OR a pointer to the widget and the (text) description for its graphic
65 typedef struct _TextBlock
{
66 struct _TextBlock
*next
; /* next text block in linked list */
67 struct _TextBlock
*prior
; /* prior text block in linked list */
69 char *text
; /* pointer to text (could be kanji) */
70 /* or to the object's description */
72 WMFont
*font
; /* the font */
73 WMWidget
*widget
; /* the embedded widget */
74 WMPixmap
*pixmap
; /* the pixmap */
75 } d
; /* description */
77 unsigned short used
; /* number of chars in this block */
78 unsigned short allocated
; /* size of allocation (in chars) */
79 WMColor
*color
; /* the color */
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 marginN
:8; /* which of the margins in the tPtr to use */
97 unsigned int nClicks
:2; /* single, double, triple clicks */
98 unsigned int RESERVED
:7;
102 /* somehow visible.h beats the hell outta visible.size.height :-) */
111 typedef struct W_Text
{
112 W_Class widgetClass
; /* the class number of this widget */
113 W_View
*view
; /* the view referring to this instance */
115 WMRuler
*ruler
; /* the ruler widget to manipulate paragraphs */
117 WMScroller
*vS
; /* the vertical scroller */
118 unsigned int vpos
; /* the current vertical position */
119 unsigned int prevVpos
; /* the previous vertical position */
121 WMScroller
*hS
; /* the horizontal scroller */
122 unsigned int hpos
; /* the current horizontal position */
123 unsigned int prevHpos
; /* the previous horizontal position */
125 WMFont
*dFont
; /* the default font */
126 WMColor
*dColor
; /* the default color */
127 WMPixmap
*dBulletPix
; /* the default pixmap for bullets */
129 GC bgGC
; /* the background GC to draw with */
130 GC fgGC
; /* the foreground GC to draw with */
131 Pixmap db
; /* the buffer on which to draw */
133 myRect visible
; /* the actual rectangle that can be drawn into */
134 myRect cursor
; /* the position and (height) of cursor */
135 myRect sel
; /* the selection rectangle */
137 WMPoint clicked
; /* where in the _document_ was clicked */
139 unsigned short tpos
; /* the position in the currentTextBlock */
140 unsigned short docWidth
; /* the width of the entire document */
141 unsigned int docHeight
; /* the height of the entire document */
143 TextBlock
*firstTextBlock
;
144 TextBlock
*lastTextBlock
;
145 TextBlock
*currentTextBlock
;
147 WMArray
*gfxItems
; /* a nice array of graphic items */
150 WMHandlerID timerID
; /* for nice twinky-winky */
155 WMTextDelegate
*delegate
;
158 WMRulerMargins
*margins
; /* an array of margins */
160 unsigned int nMargins
:8; /* the total number of margins in use */
162 unsigned int monoFont
:1; /* whether to ignore formats */
163 unsigned int focused
:1; /* whether this instance has input focus */
164 unsigned int editable
:1; /* "silly user, you can't edit me" */
165 unsigned int ownsSelection
:1; /* "I ownz the current selection!" */
166 unsigned int pointerGrabbed
:1;/* "heh, gib me pointer" */
167 unsigned int buttonHeld
:1; /* the user is holding down the button */
168 unsigned int extendSelection
:1; /* shift-drag to select more regions */
170 unsigned int rulerShown
:1; /* whether the ruler is shown or not */
171 unsigned int frozen
:1; /* whether screen updates are to be made */
172 unsigned int cursorShown
:1; /* whether to show the cursor */
173 unsigned int clickPos
:1; /* clicked before=0 or after=1 a graphic: */
174 /* (within counts as after too) */
176 unsigned int horizOnDemand
:1;/* if a large image should appear*/
177 unsigned int needsRefresh
:1; /* in case of Append/Deletes */
178 unsigned int ignoreNewLine
:1;/* turn it into a ' ' in streams > 1 */
179 unsigned int laidOut
:1; /* have the TextBlocks all been laid out */
180 unsigned int waitingForSelection
:1; /* I don't wanna wait in vain... */
181 unsigned int prepend
:1; /* prepend=1, append=0 (for parsers) */
182 unsigned int parsingHTML
:1; /* how to interpret a stream of text */
183 WMAlignment alignment
:2; /* the alignment for text */
184 WMReliefType relief
:3; /* the relief to display with */
185 unsigned int RESERVED
:2;
190 #define NOTIFY(T,C,N,A) { WMNotification *notif = WMCreateNotification(N,T,A);\
191 if ((T)->delegate && (T)->delegate->C)\
192 (*(T)->delegate->C)((T)->delegate,notif);\
193 WMPostNotification(notif);\
194 WMReleaseNotification(notif);}
199 * A hack to speed up caseless_equal. Thanks to Quincey Koziol for
200 * developing it for the "chimera" folks so I could use it 7 years later ;-)
201 * Constraint: nothing but '\0' may map to 0
203 static unsigned char map_table
[256] = {
204 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,
205 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
206 52,53,54,55,56,57,58,59,60,61,62,63,64,97,98,99,100,101,102,103,104,105,
207 106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,91,
208 92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,
209 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,
210 130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,
211 148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,
212 166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,
213 184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,
214 202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,
215 220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,
216 238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255};
218 void HTMLParser(Text
*tPtr
, char *stream
);
219 #define MAX_TOKEN_SIZE 255
220 #define MAX_TEXT_SIZE 1023
222 #define TOLOWER(x) (map_table[(int)x])
224 #define ISALNUM(x) ( ((x>='0') && (x<='9')) \
225 || ((x>='a') && (x<='z')) || ((x>='A') && x<='Z'))
228 output(char *ptr
, int len
)
233 /* printf(" s is [%s] (%d)\n", s, strlen(s)); */
238 /* tb->text doesn't necessarily end in '\0' hmph! (strchr) */
240 mystrchr(char *s
, char needle
, unsigned short len
)
244 if (!haystack
|| len
< 1)
247 while ( (int) (haystack
- s
) < len
) {
248 if (*haystack
== needle
)
256 /* tb->text doesn't necessarily end in '\0' hmph! (strchr) */
258 mystrrstr(char *haystack
, char *needle
, unsigned short len
, char *end
)
262 if(!haystack
|| !needle
)
265 for (ptr
= haystack
-2; ptr
> end
; ptr
--) {
266 if (*ptr
== *needle
&& !strncmp(ptr
, needle
, len
))
273 mystrcasecmp(const unsigned char *s1
, const unsigned char *s2
,
274 int len
, Bool caseSensitive
)
276 if (!*s1
|| !*s2
|| len
<1)
279 while (*s2
!= '\0' && len
>0) {
280 if ( (caseSensitive
? (*s1
) : TOLOWER (*s1
))
281 != (caseSensitive
? (*s2
) : TOLOWER (*s2
)))
288 return (*s1
=='\0' || !ISALNUM(*s1
))?1:0;
294 #define CURSOR_BLINK_ON_DELAY 600
295 #define CURSOR_BLINK_OFF_DELAY 400
298 static char *default_bullet
[] = {
300 " c None s None", ". c black",
301 "X c white", "o c #808080",
310 handleEvents(XEvent
*event
, void *data
);
314 getMarginNumber(Text
*tPtr
, WMRulerMargins
*margins
)
318 for(i
=0; i
< tPtr
->nMargins
; i
++) {
320 if(WMIsMarginEqualToMargin(&tPtr
->margins
[i
], margins
))
330 newMargin(Text
*tPtr
, WMRulerMargins
*margins
)
335 tPtr
->margins
[0].retainCount
++;
339 n
= getMarginNumber(tPtr
, margins
);
343 tPtr
->margins
= wrealloc(tPtr
->margins
,
344 (++tPtr
->nMargins
)*sizeof(WMRulerMargins
));
346 n
= tPtr
->nMargins
-1;
347 tPtr
->margins
[n
].left
= margins
->left
;
348 tPtr
->margins
[n
].first
= margins
->first
;
349 tPtr
->margins
[n
].body
= margins
->body
;
350 tPtr
->margins
[n
].right
= margins
->right
;
351 /* for each tab... */
352 tPtr
->margins
[n
].retainCount
= 1;
354 tPtr
->margins
[n
].retainCount
++;
361 sectionWasSelected(Text
*tPtr
, TextBlock
*tb
, XRectangle
*rect
, int s
)
363 unsigned short i
, w
, lw
, selected
= False
, extend
= False
;
367 /* if selection rectangle completely encloses the section */
368 if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
369 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
370 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
372 sel
.w
= tPtr
->visible
.w
;
373 selected
= extend
= True
;
375 /* or if it starts on a line and then goes further down */
376 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
377 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
378 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
379 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
380 >= tPtr
->visible
.y
+ tPtr
->sel
.y
) ) {
381 sel
.x
= WMAX(tPtr
->sel
.x
, tPtr
->clicked
.x
);
382 sel
.w
= tPtr
->visible
.w
;
383 selected
= extend
= True
;
385 /* or if it begins before a line, but ends on it */
386 } else if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
387 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
388 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
389 && (tb
->sections
[s
]._y
390 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
392 if (1||tPtr
->sel
.x
+ tPtr
->sel
.w
> tPtr
->clicked
.x
)
393 sel
.w
= tPtr
->sel
.x
+ tPtr
->sel
.w
;
400 /* or if the selection rectangle lies entirely within a line */
401 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
402 && (tPtr
->sel
.w
>= 2)
403 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
404 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
413 /* if not within (modified) selection rectangle */
414 if ( tb
->sections
[s
].x
> sel
.x
+ sel
.w
415 || tb
->sections
[s
].x
+ tb
->sections
[s
].w
< sel
.x
)
419 if ( tb
->sections
[s
].x
+ tb
->sections
[s
].w
<= sel
.x
+ sel
.w
420 && tb
->sections
[s
].x
>= sel
.x
) {
421 rect
->width
= tb
->sections
[s
].w
;
422 rect
->x
= tb
->sections
[s
].x
;
427 i
= tb
->sections
[s
].begin
;
430 if (0&& tb
->sections
[s
].x
>= sel
.x
) {
431 tb
->s_begin
= tb
->sections
[s
].begin
;
435 while (++i
<= tb
->sections
[s
].end
) {
437 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
440 if (lw
+ tb
->sections
[s
].x
>= sel
.x
441 || i
== tb
->sections
[s
].end
) {
444 tb
->s_begin
= (tb
->selected
? WMIN(tb
->s_begin
, i
) : i
);
449 if (i
> tb
->sections
[s
].end
) {
450 printf("WasSelected: (i > tb->sections[s].end) \n");
454 _selEnd
: rect
->x
= tb
->sections
[s
].x
+ lw
;
456 while(++i
<= tb
->sections
[s
].end
) {
458 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
461 if (lw
+ rect
->x
>= sel
.x
+ sel
.w
462 || i
== tb
->sections
[s
].end
) {
464 if (i
!= tb
->sections
[s
].end
) {
470 if (tb
->sections
[s
].last
&& sel
.x
+ sel
.w
471 >= tb
->sections
[s
].x
+ tb
->sections
[s
].w
473 rect
->width
+= (tPtr
->visible
.w
- rect
->x
- lw
);
476 tb
->s_end
= (tb
->selected
? WMAX(tb
->s_end
, i
) : i
);
482 rect
->y
= tb
->sections
[s
]._y
- tPtr
->vpos
;
483 rect
->height
= tb
->sections
[s
].h
;
484 if(tb
->graphic
) { printf("graphic s%d h%d\n", s
,tb
->sections
[s
].h
);}
491 setSelectionProperty(WMText
*tPtr
, WMFont
*font
, WMColor
*color
)
496 if((font
&& color
) || (!font
&& !color
))
502 tb
= tPtr
->firstTextBlock
;
503 if (!tb
|| !tPtr
->flags
.ownsSelection
)
507 if (tPtr
->flags
.monoFont
|| tb
->selected
) {
509 if (tPtr
->flags
.monoFont
|| (tb
->s_end
- tb
->s_begin
== tb
->used
)
514 WMReleaseFont(tb
->d
.font
);
515 tb
->d
.font
= WMRetainFont(font
);
518 WMReleaseColor(tb
->color
);
519 tb
->color
= WMRetainColor(color
);
522 } else if (tb
->s_end
<= tb
->used
&& tb
->s_begin
< tb
->s_end
) {
526 TextBlock
*ntb
= (TextBlock
*)
527 WMCreateTextBlockWithText(tPtr
,
528 &(tb
->text
[tb
->s_begin
]),
529 (isFont
?font
:tb
->d
.font
),
530 (isFont
?tb
->color
:color
),
531 False
, (tb
->s_end
- tb
->s_begin
));
534 ntb
->selected
= True
;
536 ntb
->s_end
= ntb
->used
;
537 tPtr
->currentTextBlock
= tb
;
538 WMAppendTextBlock(tPtr
, ntb
);
539 tb
= tPtr
->currentTextBlock
;
542 if (otb
->used
- otb
->s_end
> 0) {
544 WMCreateTextBlockWithText(tPtr
,
545 &(otb
->text
[otb
->s_end
]), otb
->d
.font
, otb
->color
,
546 False
, otb
->used
- otb
->s_end
);
549 ntb
->selected
= False
;
550 WMAppendTextBlock(tPtr
, ntb
);
551 tb
= tPtr
->currentTextBlock
;
555 otb
->selected
= False
;
556 otb
->used
= otb
->s_begin
;
563 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
568 removeSelection(Text
*tPtr
)
570 TextBlock
*tb
= NULL
;
572 if (!(tb
= tPtr
->firstTextBlock
))
578 if ( (tb
->s_end
- tb
->s_begin
== tb
->used
) || tb
->graphic
) {
579 tPtr
->currentTextBlock
= tb
;
580 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
581 tb
= tPtr
->currentTextBlock
;
586 } else if (tb
->s_end
<= tb
->used
) {
587 memmove(&(tb
->text
[tb
->s_begin
]),
588 &(tb
->text
[tb
->s_end
]), tb
->used
- tb
->s_end
);
589 tb
->used
-= (tb
->s_end
- tb
->s_begin
);
590 tb
->selected
= False
;
591 tPtr
->tpos
= tb
->s_begin
;
602 paintText(Text
*tPtr
)
608 int len
, y
, c
, s
, done
=False
, prev_y
=-23;
609 WMScreen
*scr
= tPtr
->view
->screen
;
610 Display
*dpy
= tPtr
->view
->screen
->display
;
611 Window win
= tPtr
->view
->window
;
613 if (!tPtr
->view
->flags
.realized
|| !tPtr
->db
|| tPtr
->flags
.frozen
)
616 XFillRectangle(dpy
, tPtr
->db
, tPtr
->bgGC
,
617 0, 0, tPtr
->visible
.w
, tPtr
->visible
.h
);
619 if(!(tb
= tPtr
->firstTextBlock
))
622 if (tPtr
->flags
.ownsSelection
)
623 greyGC
= WMColorGC(WMGrayColor(scr
));
627 /* first, place all text that can be viewed */
628 while (!done
&& tb
) {
635 tb
->selected
= False
;
637 for(s
=0; s
<tb
->nsections
&& !done
; s
++) {
639 if (tb
->sections
[s
]._y
> tPtr
->vpos
+ tPtr
->visible
.h
) {
644 if ( tb
->sections
[s
].y
+ tb
->sections
[s
].h
< tPtr
->vpos
)
647 if (tPtr
->flags
.monoFont
) {
652 gc
= WMColorGC(tb
->color
);
655 if (tPtr
->flags
.ownsSelection
) {
658 if ( sectionWasSelected(tPtr
, tb
, &rect
, s
)) {
660 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
661 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
665 prev_y
= tb
->sections
[s
]._y
;
667 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
668 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
669 y
= tb
->sections
[s
].y
- tPtr
->vpos
;
670 WMDrawString(scr
, tPtr
->db
, gc
, font
,
671 tb
->sections
[s
].x
- tPtr
->hpos
, y
, text
, len
);
673 if (tb
->underlined
) {
674 XDrawLine(dpy
, tPtr
->db
, gc
,
675 tb
->sections
[s
].x
- tPtr
->hpos
,
677 tb
->sections
[s
].x
+ tb
->sections
[s
].w
- tPtr
->hpos
,
683 tb
= (!done
? tb
->next
: NULL
);
687 /* now , show all graphic items that can be viewed */
688 c
= WMGetArrayItemCount(tPtr
->gfxItems
);
689 if (c
> 0 && !tPtr
->flags
.monoFont
) {
693 tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
);
694 if (tb
->sections
[0]._y
+ tb
->sections
[0].h
<= tPtr
->vpos
695 || tb
->sections
[0]._y
>= tPtr
->vpos
+ tPtr
->visible
.h
) {
698 if ((W_VIEW(tb
->d
.widget
))->flags
.mapped
) {
699 WMUnmapWidget(tb
->d
.widget
);
704 if (!(W_VIEW(tb
->d
.widget
))->flags
.mapped
) {
705 if (!(W_VIEW(tb
->d
.widget
))->flags
.realized
)
706 WMRealizeWidget(tb
->d
.widget
);
707 WMMapWidget(tb
->d
.widget
);
708 WMLowerWidget(tb
->d
.widget
);
712 if (tPtr
->flags
.ownsSelection
) {
715 if ( sectionWasSelected(tPtr
, tb
, &rect
, s
)) {
717 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
718 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
723 WMMoveWidget(tb
->d
.widget
,
724 tb
->sections
[0].x
- tPtr
->hpos
,
725 tb
->sections
[0].y
- tPtr
->vpos
);
726 h
= WMWidgetHeight(tb
->d
.widget
) + 1;
729 WMDrawPixmap(tb
->d
.pixmap
, tPtr
->db
,
730 tb
->sections
[0].x
- tPtr
->hpos
,
731 tb
->sections
[0].y
- tPtr
->vpos
);
732 h
= tb
->d
.pixmap
->height
+ 1;
736 if (tb
->underlined
) {
737 XDrawLine(dpy
, tPtr
->db
, WMColorGC(tb
->color
),
739 tb
->sections
[0].y
+ h
,
740 tb
->sections
[0].x
+ tb
->sections
[0].w
,
741 tb
->sections
[0].y
+ h
);
746 if (tPtr
->flags
.editable
&& tPtr
->flags
.cursorShown
747 && tPtr
->cursor
.x
!= -23 && tPtr
->flags
.focused
) {
748 int y
= tPtr
->cursor
.y
- tPtr
->vpos
;
749 XDrawLine(dpy
, tPtr
->db
, tPtr
->fgGC
,
751 tPtr
->cursor
.x
, y
+ tPtr
->cursor
.h
);
754 XCopyArea(dpy
, tPtr
->db
, win
, tPtr
->bgGC
, 0, 0,
755 tPtr
->visible
.w
, tPtr
->visible
.h
,
756 tPtr
->visible
.x
, tPtr
->visible
.y
);
758 W_DrawRelief(scr
, win
, 0, 0,
759 tPtr
->view
->size
.width
, tPtr
->view
->size
.height
,
762 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)
763 XDrawLine(dpy
, win
, tPtr
->fgGC
,
764 2, 42, tPtr
->view
->size
.width
-4, 42);
772 blinkCursor(void *data
)
774 Text
*tPtr
= (Text
*)data
;
776 if (tPtr
->flags
.cursorShown
) {
777 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY
,
780 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
,
784 tPtr
->flags
.cursorShown
= !tPtr
->flags
.cursorShown
;
789 getFirstNonGraphicBlockFor(TextBlock
*tb
, short dir
)
796 tb
= (dir
? tb
->next
: tb
->prior
);
804 updateCursorPosition(Text
*tPtr
)
806 TextBlock
*tb
= NULL
;
809 if(tPtr
->flags
.needsRefresh
)
810 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
812 if (! (tb
= tPtr
->currentTextBlock
)) {
813 if (! (tb
= tPtr
->firstTextBlock
)) {
815 tPtr
->cursor
.h
= tPtr
->dFont
->height
;
823 y
= tb
->sections
[0].y
;
824 h
= tb
->sections
[0].h
;
825 x
= tb
->sections
[0].x
;
827 if(tPtr
->tpos
> tb
->used
)
828 tPtr
->tpos
= tb
->used
;
830 for(s
=0; s
<tb
->nsections
; s
++) {
832 if(tPtr
->tpos
>= tb
->sections
[s
].begin
833 && tPtr
->tpos
<= tb
->sections
[s
].end
)
837 y
= tb
->sections
[s
]._y
;
838 h
= tb
->sections
[s
].h
;
839 x
= tb
->sections
[s
].x
+ WMWidthOfString(
840 (tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
),
841 &tb
->text
[tb
->sections
[s
].begin
],
842 tPtr
->tpos
- tb
->sections
[s
].begin
);
852 cursorToTextPosition(Text
*tPtr
, int x
, int y
)
854 TextBlock
*tb
= NULL
;
855 int done
=False
, s
, pos
, len
, _w
, _y
, dir
=1; /* 1 == "down" */
858 if(tPtr
->flags
.needsRefresh
)
859 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
861 y
+= (tPtr
->vpos
- tPtr
->visible
.y
);
865 x
-= (tPtr
->visible
.x
- 2);
869 /* clicked is relative to document, not window... */
873 if (! (tb
= tPtr
->currentTextBlock
)) {
874 if (! (tb
= tPtr
->firstTextBlock
)) {
876 tPtr
->cursor
.h
= tPtr
->dFont
->height
;
883 /* first, which direction? Most likely, newly clicked
884 position will be close to previous */
885 dir
= !(y
<= tb
->sections
[0].y
);
886 if ( ( y
<= tb
->sections
[0]._y
+ tb
->sections
[0].h
)
887 && (y
>= tb
->sections
[0]._y
) ) {
888 /* if it's on the same line */
889 if(x
< tb
->sections
[0].x
)
891 if(x
>= tb
->sections
[0].x
)
895 tb
= tPtr
->firstTextBlock
;
898 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
899 tb
= getFirstNonGraphicBlockFor(tb
, 1);
901 tPtr
->currentTextBlock
=
902 (dir
? tPtr
->lastTextBlock
: tPtr
->firstTextBlock
);
908 s
= (dir
? 0 : tb
->nsections
-1);
909 if ( y
>= tb
->sections
[s
]._y
910 && y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) {
914 /* get the first section of the TextBlock that lies about
915 the vertical click point */
917 while (!done
&& tb
) {
919 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
925 s
= (dir
? 0 : tb
->nsections
-1);
926 while (!done
&& (dir
? (s
<tb
->nsections
) : (s
>=0) )) {
928 if ( (dir
? (y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) :
929 ( y
>= tb
->sections
[s
]._y
) ) ) {
937 if ( (dir
? tb
->next
: tb
->prior
)) {
938 tb
= (dir
? tb
->next
: tb
->prior
);
941 break; /* goto _doneH; */
947 if (s
<0 || s
>=tb
->nsections
) {
948 s
= (dir
? tb
->nsections
-1 : 0);
952 /* we have the line, which TextBlock on that line is it? */
954 if (tPtr
->flags
.monoFont
&& tb
->graphic
)
955 tb
= getFirstNonGraphicBlockFor(tb
, dir
);
957 if ((dir
? tb
->sections
[s
].x
>= x
: tb
->sections
[s
].x
< x
))
965 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
966 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
967 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
969 printf("here %d %d \n", tb
->sections
[s
].x
+ _w
, x
);
970 if ((dir
? tb
->sections
[s
].x
+ _w
< x
: tb
->sections
[s
].x
+ _w
>= x
)) {
971 pos
= tb
->sections
[s
].end
;
972 tPtr
->cursor
.x
= tb
->sections
[s
].x
+ _w
;
976 _y
= tb
->sections
[s
]._y
;
981 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
982 tb
= (dir
? tb
->next
: tb
->prior
);
989 _w
= WMWidgetWidth(tb
->d
.widget
);
991 _w
= tb
->d
.pixmap
->width
;
993 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
994 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
995 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
996 if (tb
->sections
[s
].x
+ _w
>= x
)
1001 if (tb
->sections
[s
].x
<= x
)
1005 if ((dir
? tb
->next
: tb
->prior
)) {
1006 TextBlock
*nxt
= (dir
? tb
->next
: tb
->prior
);
1007 if (tPtr
->flags
.monoFont
&& nxt
->graphic
) {
1008 nxt
= getFirstNonGraphicBlockFor(nxt
, dir
);
1011 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
1016 if (_y
!= nxt
->sections
[0]._y
) {
1017 /* this must be the last/first on this line. stop */
1018 pos
= (dir
? tb
->sections
[s
].end
: 0);
1019 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
1023 tPtr
->cursor
.x
+= WMWidgetWidth(tb
->d
.widget
);
1025 tPtr
->cursor
.x
+= tb
->d
.pixmap
->width
;
1026 } else if (pos
> tb
->sections
[s
].begin
) {
1028 WMWidthOfString(tb
->d
.font
,
1029 &(tb
->text
[tb
->sections
[s
].begin
]),
1030 pos
- tb
->sections
[s
].begin
);
1037 if ( (dir
? tb
->next
: tb
->prior
)) {
1038 tb
= (dir
? tb
->next
: tb
->prior
);
1045 s
= (dir
? 0 : tb
->nsections
-1);
1048 /* we have said TextBlock, now where within it? */
1049 if (tb
&& !tb
->graphic
) {
1050 WMFont
*f
= tb
->d
.font
;
1051 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
1052 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
1054 _w
= x
- tb
->sections
[s
].x
;
1057 while (pos
<len
&& WMWidthOfString(f
, text
, pos
+1) < _w
)
1060 tPtr
->cursor
.x
= tb
->sections
[s
].x
+
1061 (pos
? WMWidthOfString(f
, text
, pos
) : 0);
1063 pos
+= tb
->sections
[s
].begin
;
1065 tPtr
->tpos
= (pos
<tb
->used
)? pos
: tb
->used
;
1069 printf("this app will surely crash :-)\n");
1071 tPtr
->currentTextBlock
= tb
;
1072 tPtr
->cursor
.h
= tb
->sections
[s
].h
;
1073 tPtr
->cursor
.y
= tb
->sections
[s
]._y
;
1078 autoSelectText(Text
*tPtr
, int clicks
)
1085 if(!(tb
= tPtr
->currentTextBlock
))
1090 if(tb
->text
[tPtr
->tpos
] == ' ')
1093 tPtr
->sel
.y
= tPtr
->cursor
.y
+5;
1094 tPtr
->sel
.h
= tPtr
->cursor
.h
-10;
1097 tPtr
->sel
.x
= tb
->sections
[0].x
;
1098 tPtr
->sel
.w
= tb
->sections
[0].w
;
1100 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
1103 while(start
> 0 && tb
->text
[start
-1] != ' ')
1106 x
= tPtr
->cursor
.x
+ 0*WMWidthOfString(font
, &tb
->text
[start
], 1);
1107 if(tPtr
->tpos
> start
){
1108 output(&tb
->text
[start
], tPtr
->tpos
- start
);
1109 x
-= WMWidthOfString(font
, &tb
->text
[start
],
1110 tPtr
->tpos
- start
);
1112 tPtr
->sel
.x
= (x
<0?0:x
)+1;
1114 if((mark
= mystrchr(&tb
->text
[start
], ' ', tb
->used
-start
))) {
1115 tPtr
->sel
.w
= WMWidthOfString(font
, &tb
->text
[start
],
1116 (int)(mark
- &tb
->text
[start
]));
1118 tPtr
->sel
.w
= tPtr
->docWidth
- tPtr
->sel
.x
;
1122 } else if(clicks
== 3) {
1123 tPtr
->sel
.x
= tPtr
->visible
.x
;
1124 tPtr
->sel
.w
= tPtr
->docWidth
;
1127 tPtr
->flags
.ownsSelection
= True
;
1133 updateScrollers(Text
*tPtr
)
1136 if (tPtr
->flags
.frozen
)
1140 if (tPtr
->docHeight
< tPtr
->visible
.h
) {
1141 WMSetScrollerParameters(tPtr
->vS
, 0, 1);
1144 float hmax
= (float)(tPtr
->docHeight
);
1145 WMSetScrollerParameters(tPtr
->vS
,
1146 ((float)tPtr
->vpos
)/(hmax
- (float)tPtr
->visible
.h
),
1147 (float)tPtr
->visible
.h
/hmax
);
1149 } else tPtr
->vpos
= 0;
1152 if (tPtr
->docWidth
< tPtr
->visible
.w
) {
1153 WMSetScrollerParameters(tPtr
->hS
, 0, 1);
1156 float wmax
= (float)(tPtr
->docWidth
);
1157 WMSetScrollerParameters(tPtr
->hS
,
1158 ((float)tPtr
->hpos
)/(wmax
- (float)tPtr
->visible
.w
),
1159 (float)tPtr
->visible
.w
/wmax
);
1161 } else tPtr
->hpos
= 0;
1165 scrollersCallBack(WMWidget
*w
, void *self
)
1167 Text
*tPtr
= (Text
*)self
;
1168 Bool scroll
= False
;
1169 Bool dimple
= False
;
1172 if (!tPtr
->view
->flags
.realized
|| tPtr
->flags
.frozen
)
1175 if (w
== tPtr
->vS
) {
1177 height
= tPtr
->visible
.h
;
1179 which
= WMGetScrollerHitPart(tPtr
->vS
);
1181 case WSDecrementLine
:
1182 if (tPtr
->vpos
> 0) {
1183 if (tPtr
->vpos
>16) tPtr
->vpos
-=16;
1187 case WSIncrementLine
: {
1188 int limit
= tPtr
->docHeight
- height
;
1189 if (tPtr
->vpos
< limit
) {
1190 if (tPtr
->vpos
<limit
-16) tPtr
->vpos
+=16;
1191 else tPtr
->vpos
=limit
;
1194 case WSDecrementPage
:
1195 tPtr
->vpos
-= height
;
1201 printf("dimple needs to jump to mouse location ;-/\n");
1203 case WSIncrementPage
:
1204 tPtr
->vpos
+= height
;
1205 if (tPtr
->vpos
> (tPtr
->docHeight
- height
))
1206 tPtr
->vpos
= tPtr
->docHeight
- height
;
1209 printf("dimple needs to jump to mouse location ;-/\n");
1214 tPtr
->vpos
= WMGetScrollerValue(tPtr
->vS
)
1215 * (float)(tPtr
->docHeight
- height
);
1221 printf("WSNoPart, WSKnobSlot\n");
1223 float hmax
= (float)(tPtr
->docHeight
);
1224 ((float)tPtr
->vpos
)/(hmax
- (float)tPtr
->visible
.h
),
1225 (float)tPtr
->visible
.h
/hmax
;
1226 dimple
=where mouse is
.
1230 scroll
= (tPtr
->vpos
!= tPtr
->prevVpos
);
1231 tPtr
->prevVpos
= tPtr
->vpos
;
1234 if (w
== tPtr
->hS
) {
1235 int width
= tPtr
->visible
.w
;
1237 which
= WMGetScrollerHitPart(tPtr
->hS
);
1239 case WSDecrementLine
:
1240 if (tPtr
->hpos
> 0) {
1241 if (tPtr
->hpos
>16) tPtr
->hpos
-=16;
1245 case WSIncrementLine
: {
1246 int limit
= tPtr
->docWidth
- width
;
1247 if (tPtr
->hpos
< limit
) {
1248 if (tPtr
->hpos
<limit
-16) tPtr
->hpos
+=16;
1249 else tPtr
->hpos
=limit
;
1252 case WSDecrementPage
:
1253 tPtr
->hpos
-= width
;
1259 printf("dimple needs to jump to mouse location ;-/\n");
1261 case WSIncrementPage
:
1262 tPtr
->hpos
+= width
;
1263 if (tPtr
->hpos
> (tPtr
->docWidth
- width
))
1264 tPtr
->hpos
= tPtr
->docWidth
- width
;
1267 printf("dimple needs to jump to mouse location ;-/\n");
1272 tPtr
->hpos
= WMGetScrollerValue(tPtr
->hS
)
1273 * (float)(tPtr
->docWidth
- width
);
1279 printf("WSNoPart, WSKnobSlot\n");
1281 float wmax
= (float)(tPtr
->docWidth
);
1282 ((float)tPtr
->vpos
)/(wmax
- (float)tPtr
->visible
.w
),
1283 (float)tPtr
->visible
.w
/wmax
;
1284 dimple
=where mouse is
.
1288 scroll
= (tPtr
->hpos
!= tPtr
->prevHpos
);
1289 tPtr
->prevHpos
= tPtr
->hpos
;
1295 if (tPtr->rulerShown)
1296 XClearArea(tPtr->view->screen->display, tPtr->view->window, 22, 47,
1297 tPtr->view->size.width-24, tPtr->view->size.height-49, True);
1299 XClearArea(tPtr->view->screen->display, tPtr->view->window, 22, 2,
1300 tPtr->view->size.width-24, tPtr->view->size.height-4, True);
1303 if (dimple
|| which
== WSDecrementLine
|| which
== WSIncrementLine
)
1304 updateScrollers(tPtr
);
1313 unsigned short begin
, end
; /* what part of the text block */
1318 layOutLine(Text
*tPtr
, myLineItems
*items
, int nitems
, int x
, int y
)
1320 int i
, j
=0, lw
= 0, line_height
=0, max_d
=0, len
, n
;
1324 TextBlock
*tbsame
=NULL
;
1326 if(!items
|| nitems
== 0)
1329 for(i
=0; i
<nitems
; i
++) {
1333 if (!tPtr
->flags
.monoFont
) {
1335 WMWidget
*wdt
= tb
->d
.widget
;
1336 line_height
= WMAX(line_height
, WMWidgetHeight(wdt
));
1337 if (tPtr
->flags
.alignment
!= WALeft
)
1338 lw
+= WMWidgetWidth(wdt
);
1340 line_height
= WMAX(line_height
, tb
->d
.pixmap
->height
+ max_d
);
1341 if (tPtr
->flags
.alignment
!= WALeft
)
1342 lw
+= tb
->d
.pixmap
->width
;
1347 font
= (tPtr
->flags
.monoFont
)?tPtr
->dFont
: tb
->d
.font
;
1348 max_d
= WMAX(max_d
, abs(font
->height
-font
->y
));
1349 line_height
= WMAX(line_height
, font
->height
+ max_d
);
1350 text
= &(tb
->text
[items
[i
].begin
]);
1351 len
= items
[i
].end
- items
[i
].begin
;
1352 if (tPtr
->flags
.alignment
!= WALeft
)
1353 lw
+= WMWidthOfString(font
, text
, len
);
1357 if (tPtr
->flags
.alignment
== WARight
) {
1358 j
= tPtr
->visible
.w
- lw
;
1359 } else if (tPtr
->flags
.alignment
== WACenter
) {
1360 j
= (int) ((float)(tPtr
->visible
.w
- lw
))/2.0;
1363 for(i
=0; i
<nitems
; i
++) {
1366 if (tbsame
== tb
) { /*extend it, since it's on same line */
1367 tb
->sections
[tb
->nsections
-1].end
= items
[i
].end
;
1368 n
= tb
->nsections
-1;
1370 tb
->sections
= wrealloc(tb
->sections
,
1371 (++tb
->nsections
)*sizeof(Section
));
1372 n
= tb
->nsections
-1;
1373 tb
->sections
[n
]._y
= y
+ max_d
;
1374 tb
->sections
[n
].x
= x
+j
;
1375 tb
->sections
[n
].h
= line_height
;
1376 tb
->sections
[n
].begin
= items
[i
].begin
;
1377 tb
->sections
[n
].end
= items
[i
].end
;
1379 if (tb
->graphic
&& tb
->object
) {
1380 tb
->sections
[n
].x
+= tPtr
->visible
.x
;
1381 tb
->sections
[n
].y
+= tPtr
->visible
.y
;
1385 tb
->sections
[n
].last
= (i
+1 == nitems
);
1388 if (!tPtr
->flags
.monoFont
) {
1390 WMWidget
*wdt
= tb
->d
.widget
;
1391 tb
->sections
[n
].y
= max_d
+ y
1392 + line_height
- WMWidgetHeight(wdt
);
1393 tb
->sections
[n
].w
= WMWidgetWidth(wdt
);
1395 tb
->sections
[n
].y
= y
+ max_d
;
1396 tb
->sections
[n
].w
= tb
->d
.pixmap
->width
;
1398 x
+= tb
->sections
[n
].w
;
1401 font
= (tPtr
->flags
.monoFont
)? tPtr
->dFont
: tb
->d
.font
;
1402 len
= items
[i
].end
- items
[i
].begin
;
1403 text
= &(tb
->text
[items
[i
].begin
]);
1405 tb
->sections
[n
].y
= y
+line_height
-font
->y
;
1407 WMWidthOfString(font
,
1408 &(tb
->text
[tb
->sections
[n
].begin
]),
1409 tb
->sections
[n
].end
- tb
->sections
[n
].begin
);
1411 x
+= WMWidthOfString(font
, text
, len
);
1423 layOutDocument(Text
*tPtr
)
1426 myLineItems
*items
= NULL
;
1427 unsigned int itemsSize
=0, nitems
=0;
1429 unsigned int x
, y
=0, prev_y
, lw
= 0, width
=0, bmargin
;
1432 Bool lhc
= !tPtr
->flags
.laidOut
; /* line height changed? */
1434 char *start
=NULL
, *mark
=NULL
;
1435 unsigned int begin
, end
;
1437 if (tPtr
->flags
.frozen
)
1440 if (!(tb
= tPtr
->firstTextBlock
))
1443 tPtr
->docWidth
= tPtr
->visible
.w
;
1444 x
= 0; /* tPtr->margins[tb->marginN].first; */
1445 printf("x:%d\n", x
);
1446 bmargin
= tPtr
->margins
[tb
->marginN
].body
;
1448 if (0&&tPtr
->flags
.laidOut
) {
1449 tb
= tPtr
->currentTextBlock
;
1450 if (tb
->sections
&& tb
->nsections
>0)
1451 prev_y
= tb
->sections
[tb
->nsections
-1]._y
;
1453 printf("1 prev_y %d \n", prev_y
);
1455 /* search backwards for textblocks on same line */
1457 if (!tb
->sections
|| tb
->nsections
<1) {
1458 tb
= tPtr
->firstTextBlock
;
1461 if (tb
->sections
[tb
->nsections
-1]._y
!= prev_y
) {
1465 /* prev_y = tb->sections[tb->nsections-1]._y; */
1468 y
= 0; /* tb->sections[tb->nsections-1]._y; */
1469 printf("2 prev_y %d \n\n", tb
->sections
[tb
->nsections
-1]._y
);
1475 if (tb
->sections
&& tb
->nsections
>0) {
1476 wfree(tb
->sections
);
1477 tb
->sections
= NULL
;
1481 if (tb
->first
&& tb
!= tPtr
->firstTextBlock
) {
1482 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1483 x
= 0*tPtr
->margins
[tb
->marginN
].first
;
1484 bmargin
= tPtr
->margins
[tb
->marginN
].body
;
1490 if (!tPtr
->flags
.monoFont
) {
1492 width
= WMWidgetWidth(tb
->d
.widget
);
1494 width
= tb
->d
.pixmap
->width
;
1496 if (width
> tPtr
->docWidth
)
1497 tPtr
->docWidth
= width
;
1500 if (lw
>= tPtr
->visible
.w
- x
) {
1501 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1507 if(nitems
+ 1> itemsSize
) {
1508 items
= wrealloc(items
,
1509 (++itemsSize
)*sizeof(myLineItems
));
1512 items
[nitems
].tb
= tb
;
1513 items
[nitems
].begin
= 0;
1514 items
[nitems
].end
= 0;
1518 } else if ((start
= tb
->text
)) {
1520 font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
1523 mark
= mystrchr(start
, ' ', tb
->used
);
1525 end
+= (int)(mark
-start
)+1;
1528 end
+= strlen(start
);
1535 if (end
-begin
> 0) {
1537 width
= WMWidthOfString(font
,
1538 &tb
->text
[begin
], end
-begin
);
1540 /* if it won't fit, break it up */
1541 if (width
> tPtr
->visible
.w
) {
1542 char *t
= &tb
->text
[begin
];
1543 int l
=end
-begin
, i
=0;
1545 width
= WMWidthOfString(font
, t
, ++i
);
1546 } while (width
< tPtr
->visible
.w
&& i
< l
);
1555 if (lw
>= tPtr
->visible
.w
- x
) {
1556 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1562 if(nitems
+ 1 > itemsSize
) {
1563 items
= wrealloc(items
,
1564 (++itemsSize
)*sizeof(myLineItems
));
1567 items
[nitems
].tb
= tb
;
1568 items
[nitems
].begin
= begin
;
1569 items
[nitems
].end
= end
;
1580 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1582 tPtr
->docHeight
= y
+10;
1583 updateScrollers(tPtr
);
1586 if(tPtr
->docWidth
> tPtr
->visible
.w
&& !tPtr
->hS
) {
1589 tPtr
->flags
.horizOnDemand
= True
;
1590 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, True
);
1591 event
.type
= Expose
;
1592 handleEvents(&event
, (void *)tPtr
);
1594 } else if(tPtr
->docWidth
<= tPtr
->visible
.w
1595 && tPtr
->hS
&& tPtr
->flags
.horizOnDemand
) {
1596 tPtr
->flags
.horizOnDemand
= False
;
1597 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, False
);
1599 tPtr
->flags
.laidOut
= True
;
1602 if(items
&& itemsSize
> 0)
1608 textDidResize(W_ViewDelegate
*self
, WMView
*view
)
1610 Text
*tPtr
= (Text
*)view
->self
;
1611 unsigned short w
= tPtr
->view
->size
.width
;
1612 unsigned short h
= tPtr
->view
->size
.height
;
1613 unsigned short rh
= 0, vw
= 0;
1615 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
) {
1616 WMMoveWidget(tPtr
->ruler
, 2, 2);
1617 WMResizeWidget(tPtr
->ruler
, w
- 4, 40);
1622 WMMoveWidget(tPtr
->vS
, 1, rh
+ 1);
1623 WMResizeWidget(tPtr
->vS
, 20, h
- rh
- 2);
1625 WMSetRulerOffset(tPtr
->ruler
,22);
1626 } else WMSetRulerOffset(tPtr
->ruler
, 2);
1630 WMMoveWidget(tPtr
->hS
, vw
, h
- 21);
1631 WMResizeWidget(tPtr
->hS
, w
- vw
- 1, 20);
1633 WMMoveWidget(tPtr
->hS
, vw
+1, h
- 21);
1634 WMResizeWidget(tPtr
->hS
, w
- vw
- 2, 20);
1638 tPtr
->visible
.x
= (tPtr
->vS
)?24:4;
1639 tPtr
->visible
.y
= (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)?43:3;
1640 tPtr
->visible
.w
= tPtr
->view
->size
.width
- tPtr
->visible
.x
- 8;
1641 tPtr
->visible
.h
= tPtr
->view
->size
.height
- tPtr
->visible
.y
;
1642 tPtr
->visible
.h
-= (tPtr
->hS
)?20:0;
1643 tPtr
->margins
[0].right
= tPtr
->visible
.w
;
1645 if (tPtr
->view
->flags
.realized
) {
1648 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
1649 tPtr
->db
= (Pixmap
) NULL
;
1652 if (tPtr
->visible
.w
< 40)
1653 tPtr
->visible
.w
= 40;
1654 if (tPtr
->visible
.h
< 20)
1655 tPtr
->visible
.h
= 20;
1658 tPtr
->db
= XCreatePixmap(tPtr
->view
->screen
->display
,
1659 tPtr
->view
->window
, tPtr
->visible
.w
,
1660 tPtr
->visible
.h
, tPtr
->view
->screen
->depth
);
1664 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1667 W_ViewDelegate _TextViewDelegate
=
1675 /* nice, divisble-by-16 blocks */
1676 static inline unsigned short
1677 reqBlockSize(unsigned short requested
)
1679 return requested
+ 16 - (requested
%16);
1684 clearText(Text
*tPtr
)
1686 if (!tPtr
->firstTextBlock
)
1689 while (tPtr
->currentTextBlock
)
1690 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1692 tPtr
->firstTextBlock
= NULL
;
1693 tPtr
->currentTextBlock
= NULL
;
1694 tPtr
->lastTextBlock
= NULL
;
1698 deleteTextInteractively(Text
*tPtr
, KeySym ksym
)
1700 TextBlock
*tb
= tPtr
->currentTextBlock
;
1701 Bool back
= (Bool
) (ksym
== XK_BackSpace
);
1704 if (!tPtr
->flags
.editable
|| tPtr
->flags
.buttonHeld
) {
1705 XBell(tPtr
->view
->screen
->display
, 0);
1712 tPtr
->flags
.needsRefresh
= True
;
1714 if (tPtr
->flags
.ownsSelection
) {
1715 removeSelection(tPtr
);
1719 if (back
&& tPtr
->tpos
< 1) {
1723 tPtr
->tpos
= tb
->used
;
1724 tPtr
->currentTextBlock
= tb
;
1729 if ( (tb
->used
> 0) && ((back
?tPtr
->tpos
> 0:1))
1730 && (tPtr
->tpos
<= tb
->used
) && !tb
->graphic
) {
1733 memmove(&(tb
->text
[tPtr
->tpos
]),
1734 &(tb
->text
[tPtr
->tpos
+ 1]), tb
->used
- tPtr
->tpos
);
1739 if ( (back
? (tPtr
->tpos
< 1 && !done
) : ( tPtr
->tpos
>= tb
->used
))
1742 TextBlock
*sibling
= (back
? tb
->prior
: tb
->next
);
1744 if(tb
->used
== 0 || tb
->graphic
)
1745 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1748 tPtr
->currentTextBlock
= sibling
;
1749 tPtr
->tpos
= (back
? sibling
->used
: 0);
1753 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1758 insertTextInteractively(Text
*tPtr
, char *text
, int len
)
1761 char *newline
= NULL
;
1763 if (!tPtr
->flags
.editable
|| tPtr
->flags
.buttonHeld
) {
1764 XBell(tPtr
->view
->screen
->display
, 0);
1768 if (len
< 1 || !text
)
1772 if(tPtr
->flags
.ignoreNewLine
&& *text
== '\n' && len
== 1)
1775 if (tPtr
->flags
.ownsSelection
)
1776 removeSelection(tPtr
);
1778 tPtr
->flags
.needsRefresh
= True
;
1780 if (tPtr
->flags
.ignoreNewLine
) {
1782 for(i
=0; i
<len
; i
++) {
1783 if (text
[i
] == '\n')
1788 tb
= tPtr
->currentTextBlock
;
1789 if (!tb
|| tb
->graphic
) {
1791 WMAppendTextStream(tPtr
, text
);
1792 if (tPtr
->currentTextBlock
) {
1793 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
1795 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1799 if ((newline
= mystrchr(text
, '\n', len
))) {
1800 int nlen
= (int)(newline
-text
);
1801 int s
= tb
->used
- tPtr
->tpos
;
1804 if (!tb
->blank
&& nlen
>0) {
1806 memcpy(save
, &tb
->text
[tPtr
->tpos
], s
);
1807 tb
->used
-= (tb
->used
- tPtr
->tpos
);
1810 insertTextInteractively(tPtr
, text
, nlen
);
1812 WMAppendTextStream(tPtr
, newline
);
1814 insertTextInteractively(tPtr
, save
, s
);
1817 if (tPtr
->tpos
>0 && tPtr
->tpos
< tb
->used
1818 && !tb
->graphic
&& tb
->text
) {
1820 void *ntb
= WMCreateTextBlockWithText(
1821 tPtr
, &tb
->text
[tPtr
->tpos
],
1822 tb
->d
.font
, tb
->color
, True
, tb
->used
- tPtr
->tpos
);
1823 tb
->used
= tPtr
->tpos
;
1824 WMAppendTextBlock(tPtr
, ntb
);
1826 } else if (tPtr
->tpos
== tb
->used
|| tPtr
->tpos
== 0) {
1827 void *ntb
= WMCreateTextBlockWithText(tPtr
,
1828 NULL
, tb
->d
.font
, tb
->color
, True
, 0);
1831 WMAppendTextBlock(tPtr
, ntb
);
1833 WMPrependTextBlock(tPtr
, ntb
);
1840 if (tb
->used
+ len
>= tb
->allocated
) {
1841 tb
->allocated
= reqBlockSize(tb
->used
+len
);
1842 tb
->text
= wrealloc(tb
->text
, tb
->allocated
);
1846 memcpy(tb
->text
, text
, len
);
1851 memmove(&(tb
->text
[tPtr
->tpos
+len
]), &tb
->text
[tPtr
->tpos
],
1852 tb
->used
-tPtr
->tpos
+1);
1853 memmove(&tb
->text
[tPtr
->tpos
], text
, len
);
1860 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1865 selectRegion(Text
*tPtr
, int x
, int y
)
1871 y
+= (tPtr
->flags
.rulerShown
? 40: 0);
1874 y
-= 10; /* the original offset */
1876 x
-= tPtr
->visible
.x
-2;
1880 tPtr
->sel
.x
= WMAX(0, WMIN(tPtr
->clicked
.x
, x
));
1881 tPtr
->sel
.w
= abs(tPtr
->clicked
.x
- x
);
1882 tPtr
->sel
.y
= WMAX(0, WMIN(tPtr
->clicked
.y
, y
));
1883 tPtr
->sel
.h
= abs(tPtr
->clicked
.y
- y
);
1885 tPtr
->flags
.ownsSelection
= True
;
1891 releaseSelection(Text
*tPtr
)
1893 TextBlock
*tb
= tPtr
->firstTextBlock
;
1896 tb
->selected
= False
;
1899 tPtr
->flags
.ownsSelection
= False
;
1900 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
,
1903 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1908 requestHandler(WMView
*view
, Atom selection
, Atom target
, void *cdata
,
1911 Text
*tPtr
= view
->self
;
1912 Display
*dpy
= tPtr
->view
->screen
->display
;
1914 Atom TEXT
= XInternAtom(dpy
, "TEXT", False
);
1915 Atom COMPOUND_TEXT
= XInternAtom(dpy
, "COMPOUND_TEXT", False
);
1916 WMData
*data
= NULL
;
1919 if (target
== XA_STRING
|| target
== TEXT
|| target
== COMPOUND_TEXT
) {
1920 char *text
= WMGetTextSelected(tPtr
);
1923 printf("got text [%s]\n", text
);
1924 data
= WMCreateDataWithBytes(text
, strlen(text
));
1925 WMSetDataFormat(data
, 8);
1929 } else printf("didn't get it\n");
1931 _TARGETS
= XInternAtom(dpy
, "TARGETS", False
);
1932 if (target
== _TARGETS
) {
1935 ptr
= wmalloc(4 * sizeof(Atom
));
1939 ptr
[3] = COMPOUND_TEXT
;
1941 data
= WMCreateDataWithBytes(ptr
, 4*4);
1942 WMSetDataFormat(data
, 32);
1952 lostHandler(WMView
*view
, Atom selection
, void *cdata
)
1954 releaseSelection((WMText
*)view
->self
);
1957 static WMSelectionProcs selectionHandler
= {
1958 requestHandler
, lostHandler
, NULL
1963 ownershipObserver(void *observerData
, WMNotification
*notification
)
1965 if (observerData
!= WMGetNotificationClientData(notification
))
1966 lostHandler(WMWidgetView(observerData
), XA_PRIMARY
, NULL
);
1971 fontChanged(void *observerData
, WMNotification
*notification
)
1973 WMText
*tPtr
= (WMText
*) observerData
;
1974 WMFont
*font
= (WMFont
*)WMGetNotificationClientData(notification
);
1975 printf("fontChanged\n");
1980 if (tPtr
->flags
.ownsSelection
)
1981 WMSetTextSelectionFont(tPtr
, font
);
1986 handleTextKeyPress(Text
*tPtr
, XEvent
*event
)
1990 int control_pressed
= False
;
1991 TextBlock
*tb
= NULL
;
1993 if (((XKeyEvent
*) event
)->state
& ControlMask
)
1994 control_pressed
= True
;
1995 buffer
[XLookupString(&event
->xkey
, buffer
, 1, &ksym
, NULL
)] = 0;
2000 if(!(tb
= tPtr
->currentTextBlock
))
2006 L_imaGFX
: if(tb
->prior
) {
2007 tPtr
->currentTextBlock
= tb
->prior
;
2008 tPtr
->tpos
= tPtr
->currentTextBlock
->used
-1;
2009 } else tPtr
->tpos
= 0;
2010 } else tPtr
->tpos
--;
2011 updateCursorPosition(tPtr
);
2016 if(!(tb
= tPtr
->currentTextBlock
))
2020 if(tPtr
->tpos
== tb
->used
) {
2021 R_imaGFX
: if(tb
->next
) {
2022 tPtr
->currentTextBlock
= tb
->next
;
2024 } else tPtr
->tpos
= tb
->used
;
2025 } else tPtr
->tpos
++;
2026 updateCursorPosition(tPtr
);
2031 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
2032 tPtr
->clicked
.y
+ tPtr
->cursor
.h
- tPtr
->vpos
);
2037 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
2038 tPtr
->visible
.y
+ tPtr
->cursor
.y
- tPtr
->vpos
- 3);
2045 deleteTextInteractively(tPtr
, ksym
);
2046 updateCursorPosition(tPtr
);
2052 control_pressed
= True
;
2058 if (buffer
[0] != 0 && !control_pressed
) {
2059 insertTextInteractively(tPtr
, buffer
, 1);
2060 updateCursorPosition(tPtr
);
2063 } else if (control_pressed
&& ksym
==XK_r
) {
2064 Bool i
= !tPtr
->flags
.rulerShown
;
2065 WMShowTextRuler(tPtr
, i
);
2066 tPtr
->flags
.rulerShown
= i
;
2068 else if (control_pressed
&& buffer
[0] == '\a')
2069 XBell(tPtr
->view
->screen
->display
, 0);
2072 if (!control_pressed
&& tPtr
->flags
.ownsSelection
)
2073 releaseSelection(tPtr
);
2077 handleWidgetPress(XEvent
*event
, void *data
)
2079 TextBlock
*tb
= (TextBlock
*)data
;
2085 /* this little bit of nastiness here saves a boatload of trouble */
2086 w
= (WMWidget
*)(((W_VIEW(tb
->d
.widget
))->parent
)->self
);
2087 if (W_CLASS(w
) != WC_Text
)
2090 tPtr
->currentTextBlock
= getFirstNonGraphicBlockFor(tb
, 1);
2091 if (!tPtr
->currentTextBlock
)
2092 tPtr
->currentTextBlock
= tb
;
2094 output(tPtr
->currentTextBlock
->text
, tPtr
->currentTextBlock
->used
);
2096 if (!tPtr
->flags
.focused
) {
2097 WMSetFocusToWidget(tPtr
);
2098 tPtr
->flags
.focused
= True
;
2105 handleActionEvents(XEvent
*event
, void *data
)
2107 Text
*tPtr
= (Text
*)data
;
2108 Display
*dpy
= event
->xany
.display
;
2112 switch (event
->type
) {
2114 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2115 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2116 tPtr
->flags
.extendSelection
= True
;
2120 if (tPtr
->flags
.focused
) {
2121 XGrabPointer(dpy
, W_VIEW(tPtr
)->window
, False
,
2122 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
2123 GrabModeAsync
, GrabModeAsync
, None
,
2124 tPtr
->view
->screen
->invisibleCursor
, CurrentTime
);
2125 tPtr
->flags
.pointerGrabbed
= True
;
2126 handleTextKeyPress(tPtr
, event
);
2131 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2132 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2133 tPtr
->flags
.extendSelection
= False
;
2135 /* end modify flag so selection can be extended */
2142 if (tPtr
->flags
.pointerGrabbed
) {
2143 tPtr
->flags
.pointerGrabbed
= False
;
2144 XUngrabPointer(dpy
, CurrentTime
);
2147 if(tPtr
->flags
.waitingForSelection
)
2150 if ((event
->xmotion
.state
& Button1Mask
)) {
2151 if (!tPtr
->flags
.ownsSelection
) {
2152 WMCreateSelectionHandler(tPtr
->view
,
2153 XA_PRIMARY
, event
->xbutton
.time
,
2154 &selectionHandler
, NULL
);
2155 tPtr
->flags
.ownsSelection
= True
;
2157 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2164 tPtr
->flags
.buttonHeld
= True
;
2166 if (tPtr
->flags
.pointerGrabbed
) {
2167 tPtr
->flags
.pointerGrabbed
= False
;
2168 XUngrabPointer(dpy
, CurrentTime
);
2172 if (tPtr
->flags
.waitingForSelection
)
2175 if (tPtr
->flags
.extendSelection
) {
2176 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2181 if (event
->xbutton
.button
== Button1
) {
2183 if(WMIsDoubleClick(event
)) {
2184 printf("lastClickTime: %d \n", event
->xbutton
.time
-tPtr
->lastClickTime
);
2185 autoSelectText(tPtr
, 2);
2186 tPtr
->lastClickTime
= event
->xbutton
.time
;
2189 if(0&&event
->xbutton
.time
- tPtr
->lastClickTime
2190 < 1.5*WINGsConfiguration
.doubleClickDelay
) {
2191 ;// autoSelectText(tPtr, 3);
2195 //WMGetTextStreamIntoArray(tPtr);
2197 if (!tPtr
->flags
.focused
) {
2198 WMSetFocusToWidget(tPtr
);
2199 tPtr
->flags
.focused
= True
;
2202 if (tPtr
->flags
.ownsSelection
)
2203 releaseSelection(tPtr
);
2205 tPtr
->lastClickTime
= event
->xbutton
.time
;
2206 cursorToTextPosition(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2210 if (event
->xbutton
.button
2211 == WINGsConfiguration
.mouseWheelDown
) {
2212 WMScrollText(tPtr
, -16);
2216 if (event
->xbutton
.button
2217 == WINGsConfiguration
.mouseWheelUp
) {
2218 WMScrollText(tPtr
, 16);
2222 if (event
->xbutton
.button
== Button2
) {
2226 if (!tPtr
->flags
.editable
) {
2232 if (!WMRequestSelection(tPtr
->view
, XA_PRIMARY
, XA_STRING
,
2233 event
->xbutton
.time
, pasteText
, NULL
)) {
2237 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
2243 (tPtr
->parser
) (tPtr
, (void *) text
);
2245 insertTextInteractively(tPtr
, text
, n
);
2248 NOTIFY(tPtr
, didChange
, WMTextDidChangeNotification
,
2249 (void*)WMInsertTextEvent
);
2252 tPtr
->flags
.waitingForSelection
= True
;
2261 tPtr
->flags
.buttonHeld
= False
;
2263 if (tPtr
->flags
.pointerGrabbed
) {
2264 tPtr
->flags
.pointerGrabbed
= False
;
2265 XUngrabPointer(dpy
, CurrentTime
);
2269 if (tPtr
->flags
.waitingForSelection
)
2277 handleEvents(XEvent
*event
, void *data
)
2279 Text
*tPtr
= (Text
*)data
;
2281 switch(event
->type
) {
2284 if (event
->xexpose
.count
!=0)
2288 if (!(W_VIEW(tPtr
->hS
))->flags
.realized
)
2289 WMRealizeWidget(tPtr
->hS
);
2290 if (!((W_VIEW(tPtr
->hS
))->flags
.mapped
))
2291 WMMapWidget(tPtr
->hS
);
2295 if (!(W_VIEW(tPtr
->vS
))->flags
.realized
)
2296 WMRealizeWidget(tPtr
->vS
);
2297 if (!((W_VIEW(tPtr
->vS
))->flags
.mapped
))
2298 WMMapWidget(tPtr
->vS
);
2302 if (!(W_VIEW(tPtr
->ruler
))->flags
.realized
)
2303 WMRealizeWidget(tPtr
->ruler
);
2305 if (!((W_VIEW(tPtr
->ruler
))->flags
.mapped
)
2306 && tPtr
->flags
.rulerShown
)
2307 WMMapWidget(tPtr
->ruler
);
2311 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2317 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))
2320 tPtr
->flags
.focused
= True
;
2322 if (tPtr
->flags
.editable
&& !tPtr
->timerID
) {
2323 tPtr
->timerID
= WMAddTimerHandler(12+0*CURSOR_BLINK_ON_DELAY
,
2331 tPtr
->flags
.focused
= False
;
2334 if (tPtr
->timerID
) {
2335 WMDeleteTimerHandler(tPtr
->timerID
);
2336 tPtr
->timerID
= NULL
;
2345 WMDestroyWidget(tPtr
->hS
);
2347 WMDestroyWidget(tPtr
->vS
);
2349 WMDestroyWidget(tPtr
->ruler
);
2351 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
2353 WMFreeArray(tPtr
->gfxItems
);
2356 WMDeleteTimerHandler(tPtr
->timerID
);
2358 WMReleaseFont(tPtr
->dFont
);
2359 WMReleaseColor(tPtr
->dColor
);
2360 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
, CurrentTime
);
2361 WMRemoveNotificationObserver(tPtr
);
2372 insertText(WMText
*tPtr
, char *stream
)
2374 char *ptr
, *begin
, *end
;
2377 char b
, e
, again
=False
;
2378 unsigned long tokenLength
, tk
;
2379 unsigned long textLength
, tx
;
2386 WMAppendTextBlock(tPtr
,
2387 WMCreateTextBlockWithText(tPtr
, stream
, tPtr
->dFont
, tPtr
->dColor
,
2388 1, strlen(stream
)));
2395 begin
= strchr(ptr
, b
);
2397 end
= strchr(begin
+1, e
);
2399 if((int)(end
-begin
)-1 > 1)
2400 output(begin
+1, (int)(end
-begin
)-1);
2409 if (ptr
&& strlen(ptr
)) {
2417 while( (c
=*(stream
++))) {
2419 if((c
== '\n' && tPtr
->flags
.parsingHTML
) || c
=='\t')
2420 //c = ' '; //continue;
2429 parseToken(tPtr
, token
, -1);
2431 } else if(c
== '<' && !open
) {
2435 tb
= WMCreateTextBlockWithText(tPtr
, text
, cfmt
.cfont
,
2436 cfmt
.ccolor
, cfmt
.first
, textlen
);
2437 //WMSetTextBlockProperties(tb, cfmt.first, False, (cfmt.u?1:0), 0, cfmt.margins);
2438 WMAppendTextBlock(tPtr
, tb
);
2440 //printf("%s\n", text);
2443 } else if(c
== '>' && open
) {
2445 if(tk
>0) parseToken(tPtr
, token
, tk
);
2450 if(tk
< MAX_TOKEN_SIZE
) token
[tk
++] = c
;
2451 } else if(textlen
< MAX_TEXT_SIZE
) text
[textlen
++] = c
;
2455 if(tk
>0) { token
[tk
] = 0; parseToken(tPtr
, token
, tk
);}
2458 //printf("%s\n", text);
2459 tb
= WMCreateTextBlockWithText(tPtr
, text
,
2460 (WMFont
*)WMGetFromArray(cfmt
.fonts
,
2461 WMGetArrayItemCount(cfmt
.fonts
)-1),
2462 (WMColor
*)WMGetFromArray(cfmt
.colors
,
2463 WMGetArrayItemCount(cfmt
.colors
)-1),
2464 cfmt
.first
, textlen
);
2465 //WMSetTextBlockProperties(tb, cfmt.first, False, (cfmt.u?1:0), 0, cfmt.margins);
2466 WMAppendTextBlock(tPtr
, tb
);
2477 mark
= strchr(start
, '\n');
2479 tb
= WMCreateTextBlockWithText(tPtr
,
2481 tPtr
->dColor
, True
, (int)(mark
-start
));
2484 if (start
&& strlen(start
)) {
2485 tb
= WMCreateTextBlockWithText(tPtr
, start
, tPtr
->dFont
,
2486 tPtr
->dColor
, False
, strlen(start
));
2491 if (tPtr
->flags
.prepend
)
2492 WMPrependTextBlock(tPtr
, tb
);
2494 WMAppendTextBlock(tPtr
, tb
);
2503 rulerMoveCallBack(WMWidget
*w
, void *self
)
2505 Text
*tPtr
= (Text
*)self
;
2508 if (W_CLASS(tPtr
) != WC_Text
)
2516 rulerReleaseCallBack(WMWidget
*w
, void *self
)
2518 Text
*tPtr
= (Text
*)self
;
2521 if (W_CLASS(tPtr
) != WC_Text
)
2524 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2530 draggingEntered(WMView
*self
, WMDraggingInfo
*info
)
2532 printf("draggingEntered\n");
2533 return WDOperationCopy
;
2538 draggingUpdated(WMView
*self
, WMDraggingInfo
*info
)
2540 return WDOperationCopy
;
2545 draggingExited(WMView
*self
, WMDraggingInfo
*info
)
2547 printf("draggingExited\n");
2551 prepareForDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2553 printf("prepareForDragOperation\n");
2560 receivedData(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
2561 void *cdata
, WMData
*data
)
2563 badbadbad
= wstrdup((char *)WMDataBytes(data
));
2567 /* when it's done in WINGs, remove this */
2569 Bool
requestDroppedData(WMView
*view
, WMDraggingInfo
*info
, char *type
)
2571 WMScreen
*scr
= W_VIEW_SCREEN(view
);
2573 if (!WMRequestSelection(scr
->dragInfo
.destView
,
2574 scr
->xdndSelectionAtom
,
2575 XInternAtom(scr
->display
, type
, False
),
2576 scr
->dragInfo
.timestamp
,
2577 receivedData
, &scr
->dragInfo
)) {
2578 wwarning("could not request data for dropped data");
2585 ev
.type
= ClientMessage
;
2586 ev
.xclient
.message_type
= scr
->xdndFinishedAtom
;
2587 ev
.xclient
.format
= 32;
2588 ev
.xclient
.window
= info
->destinationWindow
;
2589 ev
.xclient
.data
.l
[0] = 0;
2590 ev
.xclient
.data
.l
[1] = 0;
2591 ev
.xclient
.data
.l
[2] = 0;
2592 ev
.xclient
.data
.l
[3] = 0;
2593 ev
.xclient
.data
.l
[4] = 0;
2595 XSendEvent(scr
->display
, info
->sourceWindow
, False
, 0, &ev
);
2596 XFlush(scr
->display
);
2601 performDragOperation(WMView
*self
, WMDraggingInfo
*info
, WMData
*data
)
2604 WMText
*tPtr
= (WMText
*)self
->self
;
2609 requestDroppedData(tPtr
->view
, info
, "application/X-color");
2610 color
= WMCreateNamedColor(W_VIEW_SCREEN(self
), badbadbad
, True
);
2612 WMSetTextSelectionColor(tPtr
, color
);
2613 WMReleaseColor(color
);
2622 concludeDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2624 printf("concludeDragOperation\n");
2628 static WMDragDestinationProcs _DragDestinationProcs
= {
2632 prepareForDragOperation
,
2633 performDragOperation
,
2634 concludeDragOperation
2638 releaseArrayData(void *data
)
2646 getStream(WMText
*tPtr
, int sel
, int array
)
2648 TextBlock
*tb
= NULL
;
2650 unsigned long where
= 0;
2655 if (!(tb
= tPtr
->firstTextBlock
))
2658 /* this might be tricky to get right... not yet implemented */
2660 (tPtr
->writer
) (tPtr
, (void *) text
);
2664 tb
= tPtr
->firstTextBlock
;
2667 if (!tb
->graphic
|| (tb
->graphic
&& !tPtr
->flags
.monoFont
)) {
2669 if (!sel
|| (tb
->graphic
&& tb
->selected
)) {
2671 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
)) {
2672 text
= wrealloc(text
, where
+1);
2673 text
[where
++] = '\n';
2676 if(tb
->graphic
&& array
) {
2677 text
= wrealloc(text
, where
+3);
2678 text
[where
++] = 'G';//0xFA;
2679 text
[where
++] = 'A';//tb->used;
2680 text
[where
++] = 'H';//18+tb->allocated;
2683 text
= wrealloc(text
, where
+tb
->used
);
2684 memcpy(&text
[where
], tb
->text
, tb
->used
);
2688 } else if (sel
&& tb
->selected
) {
2690 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
)) {
2691 text
= wrealloc(text
, where
+1);
2692 text
[where
++] = '\n';
2695 text
= wrealloc(text
, where
+(tb
->s_end
- tb
->s_begin
));
2696 memcpy(&text
[where
], &tb
->text
[tb
->s_begin
],
2697 tb
->s_end
- tb
->s_begin
);
2698 where
+= tb
->s_end
- tb
->s_begin
;
2706 /* +1 for the end of string, let's be nice */
2707 text
= wrealloc(text
, where
+1);
2715 getStreamIntoArray(WMText
*tPtr
, int sel
)
2717 WMArray
*array
= WMCreateArray(4);
2720 unsigned long loc
=0, len
;
2725 stream
= getStream(tPtr
, sel
, 0);
2732 end
= strlen(stream
);
2735 data
= WMCreateDataWithBytes((void *)(fa
+2), len
);
2736 WMSetDataFormat(data
, 32);
2737 WMAddToArray(array
, (void *) data
);
2738 start
= fa
+ len
+ 2;
2741 if (start
&& strlen(start
)) {
2742 data
= WMCreateDataWithBytes((void *)start
, strlen(start
));
2743 WMSetDataFormat(data
, 8);
2744 WMAddToArray(array
, (void *) data
);
2758 WMCreateText(WMWidget
*parent
)
2760 Text
*tPtr
= wmalloc(sizeof(Text
));
2762 printf("could not create text widget\n");
2767 memset(tPtr
, 0, sizeof(Text
));
2768 tPtr
->widgetClass
= WC_Text
;
2769 tPtr
->view
= W_CreateView(W_VIEW(parent
));
2771 perror("could not create text's view\n");
2775 tPtr
->view
->self
= tPtr
;
2776 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->textCursor
;
2777 tPtr
->view
->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2778 W_ResizeView(tPtr
->view
, 250, 200);
2780 tPtr
->dColor
= WMWhiteColor(tPtr
->view
->screen
);
2781 tPtr
->bgGC
= WMColorGC(tPtr
->dColor
);
2782 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->dColor
);
2783 WMReleaseColor(tPtr
->dColor
);
2785 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
2786 tPtr
->fgGC
= WMColorGC(tPtr
->dColor
);
2792 tPtr
->dFont
= WMRetainFont(WMSystemFontOfSize(tPtr
->view
->screen
, 12));
2794 tPtr
->view
->delegate
= &_TextViewDelegate
;
2797 tPtr
->timerID
= NULL
;
2800 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
2801 |EnterWindowMask
|LeaveWindowMask
|FocusChangeMask
,
2802 handleEvents
, tPtr
);
2804 WMCreateEventHandler(tPtr
->view
, ButtonReleaseMask
|ButtonPressMask
2805 |KeyReleaseMask
|KeyPressMask
|Button1MotionMask
,
2806 handleActionEvents
, tPtr
);
2808 WMAddNotificationObserver(ownershipObserver
, tPtr
,
2809 "_lostOwnership", tPtr
);
2811 WMSetViewDragDestinationProcs(tPtr
->view
, &_DragDestinationProcs
);
2813 char *types
[2] = {"application/X-color", NULL
};
2814 WMRegisterViewForDraggedTypes(tPtr
->view
, types
);
2817 WMAddNotificationObserver(fontChanged
, tPtr
,
2818 "WMFontPanelDidChangeNotification", tPtr
);
2820 tPtr
->firstTextBlock
= NULL
;
2821 tPtr
->lastTextBlock
= NULL
;
2822 tPtr
->currentTextBlock
= NULL
;
2825 tPtr
->gfxItems
= WMCreateArray(4);
2827 tPtr
->parser
= NULL
;
2828 tPtr
->writer
= NULL
;
2830 tPtr
->sel
.x
= tPtr
->sel
.y
= 2;
2831 tPtr
->sel
.w
= tPtr
->sel
.h
= 0;
2833 tPtr
->clicked
.x
= tPtr
->clicked
.y
= 2;
2835 tPtr
->visible
.x
= tPtr
->visible
.y
= 2;
2836 tPtr
->visible
.h
= tPtr
->view
->size
.height
;
2837 tPtr
->visible
.w
= tPtr
->view
->size
.width
- 4;
2839 tPtr
->cursor
.x
= -23;
2842 tPtr
->docHeight
= 0;
2843 tPtr
->dBulletPix
= WMCreatePixmapFromXPMData(tPtr
->view
->screen
,
2845 tPtr
->db
= (Pixmap
) NULL
;
2847 tPtr
->margins
= WMGetRulerMargins(NULL
);
2848 tPtr
->margins
->right
= tPtr
->visible
.w
;
2851 tPtr
->flags
.rulerShown
= False
;
2852 tPtr
->flags
.monoFont
= False
;
2853 tPtr
->flags
.focused
= False
;
2854 tPtr
->flags
.editable
= True
;
2855 tPtr
->flags
.ownsSelection
= False
;
2856 tPtr
->flags
.pointerGrabbed
= False
;
2857 tPtr
->flags
.buttonHeld
= False
;
2858 tPtr
->flags
.extendSelection
= False
;
2859 tPtr
->flags
.frozen
= False
;
2860 tPtr
->flags
.cursorShown
= True
;
2861 tPtr
->flags
.clickPos
= 1;
2862 tPtr
->flags
.horizOnDemand
= False
;
2863 tPtr
->flags
.needsRefresh
= False
;
2864 tPtr
->flags
.ignoreNewLine
= False
;
2865 tPtr
->flags
.laidOut
= False
;
2866 tPtr
->flags
.waitingForSelection
= False
;
2867 tPtr
->flags
.prepend
= False
;
2868 tPtr
->flags
.parsingHTML
= False
;
2869 tPtr
->flags
.relief
= WRSunken
;
2870 tPtr
->flags
.alignment
= WALeft
;
2876 WMPrependTextStream(WMText
*tPtr
, char *text
)
2878 CHECK_CLASS(tPtr
, WC_Text
);
2881 releaseSelection(tPtr
);
2883 tPtr
->flags
.prepend
= True
;
2884 if (text
&& tPtr
->parser
)
2885 (tPtr
->parser
) (tPtr
, (void *) text
);
2887 insertText(tPtr
, text
);
2889 tPtr
->flags
.needsRefresh
= True
;
2894 WMAppendTextStream(WMText
*tPtr
, char *text
)
2896 CHECK_CLASS(tPtr
, WC_Text
);
2899 releaseSelection(tPtr
);
2901 tPtr
->flags
.prepend
= False
;
2902 if (text
&& tPtr
->parser
)
2903 (tPtr
->parser
) (tPtr
, (void *) text
);
2905 insertText(tPtr
, text
);
2907 tPtr
->flags
.needsRefresh
= True
;
2913 WMGetTextStream(WMText
*tPtr
)
2915 CHECK_CLASS(tPtr
, WC_Text
);
2916 return getStream(tPtr
, 0, 0);
2920 WMGetTextSelected(WMText
*tPtr
)
2922 CHECK_CLASS(tPtr
, WC_Text
);
2923 return getStream(tPtr
, 1, 0);
2927 WMGetTextStreamIntoArray(WMText
*tPtr
)
2929 CHECK_CLASS(tPtr
, WC_Text
);
2930 return getStreamIntoArray(tPtr
, 0);
2934 WMGetTextSelectedIntoArray(WMText
*tPtr
)
2936 CHECK_CLASS(tPtr
, WC_Text
);
2937 return getStreamIntoArray(tPtr
, 1);
2942 WMSetTextDelegate(WMText
*tPtr
, WMTextDelegate
*delegate
)
2944 CHECK_CLASS(tPtr
, WC_Text
);
2946 tPtr
->delegate
= delegate
;
2951 WMCreateTextBlockWithObject(WMText
*tPtr
, WMWidget
*w
,
2952 char *description
, WMColor
*color
,
2953 unsigned short first
, unsigned short extraInfo
)
2956 unsigned short length
;
2958 if (!w
|| !description
|| !color
)
2961 tb
= wmalloc(sizeof(TextBlock
));
2965 length
= strlen(description
);
2966 tb
->text
= (char *)wmalloc(length
);
2967 memset(tb
->text
, 0, length
);
2968 memcpy(tb
->text
, description
, length
);
2972 tb
->color
= WMRetainColor(color
);
2973 tb
->marginN
= newMargin(tPtr
, NULL
);
2974 tb
->allocated
= extraInfo
;
2979 tb
->underlined
= False
;
2980 tb
->selected
= False
;
2982 tb
->sections
= NULL
;
2992 WMCreateTextBlockWithPixmap(WMText
*tPtr
, WMPixmap
*p
,
2993 char *description
, WMColor
*color
,
2994 unsigned short first
, unsigned short extraInfo
)
2997 unsigned short length
;
2999 if (!p
|| !description
|| !color
)
3002 tb
= wmalloc(sizeof(TextBlock
));
3006 length
= strlen(description
);
3007 tb
->text
= (char *)wmalloc(length
);
3008 memset(tb
->text
, 0, length
);
3009 memcpy(tb
->text
, description
, length
);
3013 tb
->color
= WMRetainColor(color
);
3014 tb
->marginN
= newMargin(tPtr
, NULL
);
3015 tb
->allocated
= extraInfo
;
3020 tb
->underlined
= False
;
3021 tb
->selected
= False
;
3023 tb
->sections
= NULL
;
3032 WMCreateTextBlockWithText(WMText
*tPtr
, char *text
, WMFont
*font
, WMColor
*color
,
3033 unsigned short first
, unsigned short length
)
3037 if (!font
|| !color
)
3040 tb
= wmalloc(sizeof(TextBlock
));
3044 tb
->allocated
= reqBlockSize(length
);
3045 tb
->text
= (char *)wmalloc(tb
->allocated
);
3046 memset(tb
->text
, 0, tb
->allocated
);
3048 if (length
< 1|| !text
) {
3053 memcpy(tb
->text
, text
, length
);
3058 tb
->d
.font
= WMRetainFont(font
);
3059 tb
->color
= WMRetainColor(color
);
3060 tb
->marginN
= newMargin(tPtr
, NULL
);
3063 tb
->graphic
= False
;
3064 tb
->underlined
= False
;
3065 tb
->selected
= False
;
3067 tb
->sections
= NULL
;
3075 WMSetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int first
,
3076 unsigned int kanji
, unsigned int underlined
, int script
,
3077 WMRulerMargins
*margins
)
3079 TextBlock
*tb
= (TextBlock
*) vtb
;
3085 tb
->underlined
= underlined
;
3086 tb
->script
= script
;
3087 tb
->marginN
= newMargin(tPtr
, margins
);
3091 WMGetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int *first
,
3092 unsigned int *kanji
, unsigned int *underlined
, int *script
,
3093 WMRulerMargins
*margins
)
3095 TextBlock
*tb
= (TextBlock
*) vtb
;
3099 if (first
) *first
= tb
->first
;
3100 if (kanji
) *kanji
= tb
->kanji
;
3101 if (underlined
) *underlined
= tb
->underlined
;
3102 if (script
) *script
= tb
->script
;
3103 if (margins
) margins
= &tPtr
->margins
[tb
->marginN
];
3109 WMPrependTextBlock(WMText
*tPtr
, void *vtb
)
3111 TextBlock
*tb
= (TextBlock
*)vtb
;
3118 WMWidget
*w
= tb
->d
.widget
;
3119 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
3120 handleWidgetPress
, tb
);
3121 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
3122 (W_VIEW(w
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3123 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3126 WMAddToArray(tPtr
->gfxItems
, (void *)tb
);
3128 } else tPtr
->tpos
= tb
->used
;
3130 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
3131 tb
->next
= tb
->prior
= NULL
;
3133 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
3134 = tPtr
->currentTextBlock
= tb
;
3139 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
3142 tb
->next
= tPtr
->currentTextBlock
;
3143 tb
->prior
= tPtr
->currentTextBlock
->prior
;
3144 if (tPtr
->currentTextBlock
->prior
)
3145 tPtr
->currentTextBlock
->prior
->next
= tb
;
3147 tPtr
->currentTextBlock
->prior
= tb
;
3149 tPtr
->firstTextBlock
= tb
;
3151 tPtr
->currentTextBlock
= tb
;
3156 WMAppendTextBlock(WMText
*tPtr
, void *vtb
)
3158 TextBlock
*tb
= (TextBlock
*)vtb
;
3165 WMWidget
*w
= tb
->d
.widget
;
3166 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
3167 handleWidgetPress
, tb
);
3168 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
3169 (W_VIEW(w
))->attribs
.cursor
=
3170 tPtr
->view
->screen
->defaultCursor
;
3171 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3174 WMAddToArray(tPtr
->gfxItems
, (void *)tb
);
3176 } else tPtr
->tpos
= tb
->used
;
3178 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
3179 tb
->next
= tb
->prior
= NULL
;
3181 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
3182 = tPtr
->currentTextBlock
= tb
;
3187 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
3190 tb
->next
= tPtr
->currentTextBlock
->next
;
3191 tb
->prior
= tPtr
->currentTextBlock
;
3192 if (tPtr
->currentTextBlock
->next
)
3193 tPtr
->currentTextBlock
->next
->prior
= tb
;
3195 tPtr
->currentTextBlock
->next
= tb
;
3198 tPtr
->lastTextBlock
= tb
;
3200 tPtr
->currentTextBlock
= tb
;
3204 WMRemoveTextBlock(WMText
*tPtr
)
3206 TextBlock
*tb
= NULL
;
3208 if (!tPtr
|| !tPtr
->firstTextBlock
|| !tPtr
->lastTextBlock
3209 || !tPtr
->currentTextBlock
) {
3210 printf("cannot remove non existent TextBlock!\b");
3214 tb
= tPtr
->currentTextBlock
;
3216 WMRemoveFromArray(tPtr
->gfxItems
, (void *)tb
);
3219 WMDeleteEventHandler(W_VIEW(tb
->d
.widget
), ButtonPressMask
,
3220 handleWidgetPress
, tb
);
3221 WMUnmapWidget(tb
->d
.widget
);
3225 if (tPtr
->currentTextBlock
== tPtr
->firstTextBlock
) {
3226 if (tPtr
->currentTextBlock
->next
)
3227 tPtr
->currentTextBlock
->next
->prior
= NULL
;
3229 tPtr
->firstTextBlock
= tPtr
->currentTextBlock
->next
;
3230 tPtr
->currentTextBlock
= tPtr
->firstTextBlock
;
3232 } else if (tPtr
->currentTextBlock
== tPtr
->lastTextBlock
) {
3233 tPtr
->currentTextBlock
->prior
->next
= NULL
;
3234 tPtr
->lastTextBlock
= tPtr
->currentTextBlock
->prior
;
3235 tPtr
->currentTextBlock
= tPtr
->lastTextBlock
;
3237 tPtr
->currentTextBlock
->prior
->next
= tPtr
->currentTextBlock
->next
;
3238 tPtr
->currentTextBlock
->next
->prior
= tPtr
->currentTextBlock
->prior
;
3239 tPtr
->currentTextBlock
= tPtr
->currentTextBlock
->next
;
3246 WMDestroyTextBlock(WMText
*tPtr
, void *vtb
)
3248 TextBlock
*tb
= (TextBlock
*)vtb
;
3254 /* naturally, there's a danger to destroying
3255 widgets whose action brings us here:
3256 ie. press a button to destroy it... need to
3257 find a safer way. till then... this stays commented out */
3258 /* WMDestroyWidget(tb->d.widget);
3259 wfree(tb->d.widget); */
3260 tb
->d
.widget
= NULL
;
3262 WMReleasePixmap(tb
->d
.pixmap
);
3263 tb
->d
.pixmap
= NULL
;
3266 WMReleaseFont(tb
->d
.font
);
3269 WMReleaseColor(tb
->color
);
3270 if (tb
->sections
&& tb
->nsections
> 0)
3271 wfree(tb
->sections
);
3279 WMRefreshText(WMText
*tPtr
, int vpos
, int hpos
)
3281 if (!tPtr
|| vpos
<0 || hpos
<0)
3284 if (tPtr
->flags
.frozen
&& !tPtr
->flags
.needsRefresh
)
3287 if(tPtr
->flags
.monoFont
) {
3288 int j
, c
= WMGetArrayItemCount(tPtr
->gfxItems
);
3291 /* make sure to unmap widgets no matter where they are */
3292 for(j
=0; j
<c
; j
++) {
3293 if ((tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
))) {
3294 if (tb
->object
&& ((W_VIEW(tb
->d
.widget
))->flags
.mapped
))
3295 WMUnmapWidget(tb
->d
.widget
);
3301 if (tPtr
->vpos
!= vpos
) {
3302 if (vpos
< 0 || tPtr
->docHeight
< tPtr
->visible
.h
) {
3304 } else if(tPtr
->docHeight
- vpos
> tPtr
->visible
.h
- tPtr
->visible
.y
) {
3307 tPtr
->vpos
= tPtr
->docHeight
- tPtr
->visible
.h
;
3311 if (tPtr
->hpos
!= hpos
) {
3312 if (hpos
< 0 || tPtr
->docWidth
< tPtr
->visible
.w
) {
3314 } else if(tPtr
->docWidth
- hpos
> tPtr
->visible
.w
- tPtr
->visible
.x
) {
3317 tPtr
->hpos
= tPtr
->docWidth
- tPtr
->visible
.w
;
3322 tPtr
->flags
.laidOut
= False
;
3323 layOutDocument(tPtr
);
3324 updateScrollers(tPtr
);
3326 tPtr
->flags
.needsRefresh
= False
;
3331 WMSetTextForegroundColor(WMText
*tPtr
, WMColor
*color
)
3337 tPtr
->fgGC
= WMColorGC(color
);
3339 tPtr
->fgGC
= WMColorGC(WMBlackColor(tPtr
->view
->screen
));
3341 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
3345 WMSetTextBackgroundColor(WMText
*tPtr
, WMColor
*color
)
3351 tPtr
->bgGC
= WMColorGC(color
);
3352 W_SetViewBackgroundColor(tPtr
->view
, color
);
3354 tPtr
->bgGC
= WMColorGC(WMWhiteColor(tPtr
->view
->screen
));
3355 W_SetViewBackgroundColor(tPtr
->view
,
3356 WMWhiteColor(tPtr
->view
->screen
));
3359 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
3363 WMSetTextRelief(WMText
*tPtr
, WMReliefType relief
)
3367 tPtr
->flags
.relief
= relief
;
3372 WMSetTextHasHorizontalScroller(WMText
*tPtr
, Bool shouldhave
)
3377 if (shouldhave
&& !tPtr
->hS
) {
3378 tPtr
->hS
= WMCreateScroller(tPtr
);
3379 (W_VIEW(tPtr
->hS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3380 (W_VIEW(tPtr
->hS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3381 WMSetScrollerArrowsPosition(tPtr
->hS
, WSAMinEnd
);
3382 WMSetScrollerAction(tPtr
->hS
, scrollersCallBack
, tPtr
);
3383 WMMapWidget(tPtr
->hS
);
3384 } else if (!shouldhave
&& tPtr
->hS
) {
3385 WMUnmapWidget(tPtr
->hS
);
3386 WMDestroyWidget(tPtr
->hS
);
3392 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3397 WMSetTextHasRuler(WMText
*tPtr
, Bool shouldhave
)
3402 if(shouldhave
&& !tPtr
->ruler
) {
3403 tPtr
->ruler
= WMCreateRuler(tPtr
);
3404 (W_VIEW(tPtr
->ruler
))->attribs
.cursor
=
3405 tPtr
->view
->screen
->defaultCursor
;
3406 (W_VIEW(tPtr
->ruler
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3407 WMSetRulerReleaseAction(tPtr
->ruler
, rulerReleaseCallBack
, tPtr
);
3408 WMSetRulerMoveAction(tPtr
->ruler
, rulerMoveCallBack
, tPtr
);
3409 } else if(!shouldhave
&& tPtr
->ruler
) {
3410 WMShowTextRuler(tPtr
, False
);
3411 WMDestroyWidget(tPtr
->ruler
);
3414 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3418 WMShowTextRuler(WMText
*tPtr
, Bool show
)
3425 if(tPtr
->flags
.monoFont
)
3428 tPtr
->flags
.rulerShown
= show
;
3430 WMMapWidget(tPtr
->ruler
);
3432 WMUnmapWidget(tPtr
->ruler
);
3435 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3439 WMGetTextRulerShown(WMText
*tPtr
)
3447 return tPtr
->flags
.rulerShown
;
3452 WMSetTextHasVerticalScroller(WMText
*tPtr
, Bool shouldhave
)
3457 if (shouldhave
&& !tPtr
->vS
) {
3458 tPtr
->vS
= WMCreateScroller(tPtr
);
3459 (W_VIEW(tPtr
->vS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3460 (W_VIEW(tPtr
->vS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3461 WMSetScrollerArrowsPosition(tPtr
->vS
, WSAMaxEnd
);
3462 WMSetScrollerAction(tPtr
->vS
, scrollersCallBack
, tPtr
);
3463 WMMapWidget(tPtr
->vS
);
3464 } else if (!shouldhave
&& tPtr
->vS
) {
3465 WMUnmapWidget(tPtr
->vS
);
3466 WMDestroyWidget(tPtr
->vS
);
3472 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3478 WMScrollText(WMText
*tPtr
, int amount
)
3483 if (amount
== 0 || !tPtr
->view
->flags
.realized
)
3487 if (tPtr
->vpos
> 0) {
3488 if (tPtr
->vpos
> abs(amount
)) tPtr
->vpos
+= amount
;
3492 int limit
= tPtr
->docHeight
- tPtr
->visible
.h
;
3493 if (tPtr
->vpos
< limit
) {
3494 if (tPtr
->vpos
< limit
-amount
) tPtr
->vpos
+= amount
;
3495 else tPtr
->vpos
= limit
;
3499 if (scroll
&& tPtr
->vpos
!= tPtr
->prevVpos
) {
3500 updateScrollers(tPtr
);
3503 tPtr
->prevVpos
= tPtr
->vpos
;
3508 WMPageText(WMText
*tPtr
, Bool direction
)
3510 if (!tPtr
) return False
;
3511 if (!tPtr
->view
->flags
.realized
) return False
;
3513 return WMScrollText(tPtr
, direction
?tPtr
->visible
.h
:-tPtr
->visible
.h
);
3517 WMSetTextEditable(WMText
*tPtr
, Bool editable
)
3521 tPtr
->flags
.editable
= editable
;
3525 WMGetTextEditable(WMText
*tPtr
)
3529 return tPtr
->flags
.editable
;
3533 WMSetTextIgnoresNewline(WMText
*tPtr
, Bool ignore
)
3537 tPtr
->flags
.ignoreNewLine
= ignore
;
3541 WMGetTextIgnoresNewline(WMText
*tPtr
)
3545 return tPtr
->flags
.ignoreNewLine
;
3549 WMSetTextUsesMonoFont(WMText
*tPtr
, Bool mono
)
3553 if (mono
&& tPtr
->flags
.rulerShown
)
3554 WMShowTextRuler(tPtr
, False
);
3556 tPtr
->flags
.monoFont
= mono
;
3557 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
3561 WMGetTextUsesMonoFont(WMText
*tPtr
)
3565 return tPtr
->flags
.monoFont
;
3570 WMSetTextDefaultFont(WMText
*tPtr
, WMFont
*font
)
3575 WMReleaseFont(tPtr
->dFont
);
3577 tPtr
->dFont
= WMRetainFont(font
);
3579 tPtr
->dFont
= WMRetainFont(WMSystemFontOfSize(tPtr
->view
->screen
, 12));
3583 WMGetTextDefaultFont(WMText
*tPtr
)
3592 WMSetTextAlignment(WMText
*tPtr
, WMAlignment alignment
)
3596 tPtr
->flags
.alignment
= alignment
;
3597 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
3601 WMSetTextParser(WMText
*tPtr
, WMAction
*parser
)
3605 tPtr
->parser
= parser
;
3609 WMSetTextWriter(WMText
*tPtr
, WMAction
*writer
)
3613 tPtr
->writer
= writer
;
3617 WMGetTextInsertType(WMText
*tPtr
)
3621 return tPtr
->flags
.prepend
;
3626 WMSetTextSelectionColor(WMText
*tPtr
, WMColor
*color
)
3628 if (!tPtr
|| !color
)
3631 setSelectionProperty(tPtr
, NULL
, color
);
3637 WMSetTextSelectionFont(WMText
*tPtr
, WMFont
*font
)
3642 setSelectionProperty(tPtr
, font
, NULL
);
3647 WMFreezeText(WMText
*tPtr
)
3652 tPtr
->flags
.frozen
= True
;
3656 WMThawText(WMText
*tPtr
)
3661 tPtr
->flags
.frozen
= False
;
3666 WMFindInTextStream(WMText
*tPtr
, char *needle
, Bool direction
,
3673 if (!tPtr
|| !needle
)
3676 if (! (tb
= tPtr
->currentTextBlock
)) {
3677 if (! (tb
= ( (direction
> 0) ?
3678 tPtr
->firstTextBlock
: tPtr
->lastTextBlock
) ) ){
3682 //if(tb != ((direction>0) ?tPtr->firstTextBlock : tPtr->lastTextBlock))
3683 // tb = (direction>0) ? tb->next : tb->prior;
3684 if(tb
!= tPtr
->lastTextBlock
)
3692 if(pos
+1 < tb
->used
)
3695 if(tb
->used
- pos
> 0 && pos
> 0) {
3696 char tmp
= tb
->text
[tb
->used
];
3697 tb
->text
[tb
->used
] = 0;
3700 mark
= strstr(&tb
->text
[pos
], needle
);
3702 mark
= mystrrstr(&tb
->text
[pos
], needle
,
3703 strlen(needle
), tb
->text
);
3704 tb
->text
[tb
->used
] = tmp
;
3711 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
3713 tPtr
->tpos
= (int)(mark
- tb
->text
);
3714 tPtr
->currentTextBlock
= tb
;
3715 updateCursorPosition(tPtr
);
3716 tPtr
->sel
.y
= tPtr
->cursor
.y
+5;
3717 tPtr
->sel
.h
= tPtr
->cursor
.h
-10;
3718 tPtr
->sel
.x
= tPtr
->cursor
.x
+1;
3719 tPtr
->sel
.w
= WMIN(WMWidthOfString(font
,
3720 &tb
->text
[tPtr
->tpos
], strlen(needle
)),
3721 tPtr
->docWidth
- tPtr
->sel
.x
);
3722 tPtr
->flags
.ownsSelection
= True
;
3729 tb
= (direction
>0) ? tb
->next
: tb
->prior
;
3737 typedef struct _currentFormat
{
3742 WMRulerMargins margins
;
3743 //WMArray *aligns; // for tables...
3744 /* the following are "nested"
3745 i.e.: <b><b><i></b><b></i>
3746 1 2 1 1 2 0 get it? */
3754 WMAlignment align
:2;
3755 short ul
:3; /* how "nested"... up to 8 levels deep */
3756 short comment
:1; /* ignore text till --> */
3764 getArg(char *t
, short type
, void *arg
)
3767 while(*(++t
) && !d
) {
3769 if(*t
>='0' && *t
<='9') {
3770 sscanf(t
, "%d", arg
);
3771 while(*t
&& (*t
<'0' || *t
>'9'))
3781 parseToken(WMText
*tPtr
, char *token
, short tk
)
3783 short open
=0; /* 0 starts, 1 closes */
3785 int prepend
= WMGetTextInsertType(tPtr
);
3786 WMScreen
*scr
= tPtr
->view
->screen
;
3789 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
3790 NULL
, cfmt
.cfont
, cfmt
.ccolor
, True
, 0));
3795 while(*token
&& *token
== ' ')
3802 while(*token
== ' ')
3806 if(!tPtr
->flags
.parsingHTML
) {
3807 if(mystrcasecmp(token
, "html", 4, False
)) {
3808 printf("got HTMLLLL: [%s]\n", token
);
3809 tPtr
->flags
.parsingHTML
= True
;
3811 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
3812 token
, cfmt
.cfont
, cfmt
.ccolor
, cfmt
.first
, strlen(token
)));
3819 if(strlen(token
)==1) {
3820 /* nice and fast for small tokens... no need for too much brain
3822 switch(TOLOWER(*token
)) {
3825 cfmt
.cfont
= WMConvertFontToItalic(scr
, cfmt
.cfont
);
3826 WMAddToArray(cfmt
.fonts
, (void *)cfmt
.cfont
);
3827 } else { /*dun wanna remove the baseFont eh? */
3828 int count
= WMGetArrayItemCount(cfmt
.fonts
);
3830 WMDeleteFromArray(cfmt
.fonts
, count
-1);
3832 cfmt
.cfont
= (WMFont
*)WMGetFromArray(cfmt
.fonts
,
3833 WMGetArrayItemCount(cfmt
.fonts
)-1);
3834 }printf("i\n"); break;
3838 cfmt
.cfont
= WMConvertFontToBold(scr
, cfmt
.cfont
);
3839 WMAddToArray(cfmt
.fonts
, (void *)cfmt
.cfont
);
3840 } else { /*dun wanna remove the baseFont eh? */
3841 int count
= WMGetArrayItemCount(cfmt
.fonts
);
3843 WMDeleteFromArray(cfmt
.fonts
, count
-1);
3844 cfmt
.cfont
= (WMFont
*)WMGetFromArray(cfmt
.fonts
,
3845 WMGetArrayItemCount(cfmt
.fonts
)-1);
3849 tb
= WMCreateTextBlockWithText(tPtr
, NULL
, cfmt
.cfont
,
3850 cfmt
.ccolor
, cfmt
.first
, 0);
3851 // WMSetTextBlockProperties(tb, cfmt.first, False, (cfmt.u?1:0), 0, cfmt.margins);
3852 WMAppendTextBlock(tPtr
, tb
);
3855 case 'u': cfmt
.u
= !open
; break;
3858 if(mystrcasecmp(token
, "br", 2, False
)) {
3861 else if(mystrcasecmp(token
, "ul", 2, False
)) {
3863 if(cfmt
.ul
>1) cfmt
.ul
--;
3866 cfmt
.bmargin
= cfmt
.ul
*30;
3867 cfmt
.fmargin
= cfmt
.bmargin
-10;
3868 } else cfmt
.fmargin
= cfmt
.bmargin
= 0;
3869 } else if(mystrcasecmp(token
, "li", 2, False
)) {
3871 //change margins... create a new margin....
3872 //(cfmt.fmargin, cfmt.bmargin,
3873 } else if(mystrcasecmp(token
, "html", 4, False
)) {
3874 tPtr
->flags
.parsingHTML
= !open
;
3876 } else if(mystrcasecmp(token
, "align", 5, False
))
3878 else if(mystrcasecmp(token
, "img", 3, False
)) {
3883 while(*token
== ' ') token
++;
3885 switch(TOLOWER(*token
)) {
3887 if(TOLOWER(*(1+token
)) == 'r' && TOLOWER(*(2+token
)) == 'c') {
3888 mark
= strchr(token
, '=');
3890 char img
[256], *iptr
;
3893 sscanf(token
, "%s", img
);
3895 if(*img
== '\"') { img
[strlen(img
)-1] = 0; iptr
++;}
3896 pixmap
= WMCreatePixmapFromFile(scr
, iptr
);
3898 tb
= WMCreateTextBlockWithPixmap(tPtr
, pixmap
,
3899 iptr
, cfmt
.ccolor
, cfmt
.first
, 0);
3900 // WMSetTextBlockProperties(tb, cfmt.first,
3901 // False, (cfmt.u?1:0), 0, cfmt.margins);
3902 WMAppendTextBlock(tPtr
, tb
);
3905 //printf("[%s]\n", iptr);
3906 } } break; } } while(*(token
++));
3908 } else if(mystrcasecmp(token
, "font", 4, False
)) {
3911 cfmt
.cfont
= (WMFont
*)WMGetFromArray(cfmt
.fonts
,
3912 WMGetArrayItemCount(cfmt
.fonts
)-1);
3914 (WMColor
*)WMGetFromArray(cfmt
.colors
,
3915 WMGetArrayItemCount(cfmt
.colors
)-1),
3918 else if(mystrcasecmp(token
, "center", 6, False
)) {
3920 if(open
) cfmt
.align
= WALeft
;
3921 else cfmt
.align
= WACenter
;
3930 //printf("parse token (%s)[%s]\n", open?"close":"open", token);
3933 //while(*token && !isspace(*(token))) token++;
3934 //printf("A:%d a:%d z%d Z%d\n", '1', 'a', 'Z', 'z');
3937 if(c
>=65 && c
<=122) { major
[i
++] = c
;
3938 } else if(c
==' ' || c
=='='){ major
[i
] = 0; i
=0; mm
=1;
3939 printf("\nmajor: [%s]", major
);}
3943 } else { minor
[i
] = 0; i
=0; printf(" minor: [%s] ", minor
);}
3945 }while((c
= *(++token
)));
3949 //printf("parse token (%s)[%s]\n", open?"close":"open", token);