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.
22 #include <X11/keysym.h>
23 #include <X11/Xatom.h>
27 WMFont
* WMGetFontPlain(WMScreen
*scrPtr
, WMFont
*font
);
28 WMFont
* WMGetFontBold(WMScreen
*scrPtr
, WMFont
*font
);
29 WMFont
* WMGetFontItalic(WMScreen
*scrPtr
, WMFont
*font
);
30 WMFont
* WMGetFontOfSize(WMScreen
*scrPtr
, WMFont
*font
, int size
);
34 * - change Bag stuffs to WMArray
35 * - assess danger of destroying widgets whose actions link to other pages
36 * - integrate WMGetFont* functions into WINGs proper (fontpanel)?
37 * - change cursor shape around pixmaps
38 * - redo blink code to reduce paint event... use pixmap buffer...
39 * - add paragraph support (full) and '\n' code in getStream..
40 * - use currentTextBlock and neighbours for fast paint and layout
41 * - replace copious uses of Refreshtext with appropriate layOut()...
42 * - WMFindInTextStream should also highlight found text...
43 * - add full support for Horizontal Scroll
47 /* a Section is a section of a TextBlock that describes what parts
48 of a TextBlock has been laid out on which "line"...
49 o this greatly aids redraw, scroll and selection.
50 o this is created during layoutLine, but may be later modified.
51 o there may be many Sections per TextBlock, hence the array */
53 unsigned int x
, y
; /* where to draw it from */
54 unsigned short w
, h
; /* its width and height */
55 unsigned short begin
; /* where the layout begins */
56 unsigned short end
; /* where it ends */
57 unsigned short last
:1; /* is it the last section on a "line"? */
58 unsigned int _y
:31; /* the "line" it and other textblocks are on */
62 /* a TextBlock is a doubly-linked list of TextBlocks containing:
63 o text for the block, color and font
64 o or a pointer to the pixmap
65 o OR a pointer to the widget and the (text) description for its graphic
68 typedef struct _TextBlock
{
69 struct _TextBlock
*next
; /* next text block in linked list */
70 struct _TextBlock
*prior
; /* prior text block in linked list */
72 char *text
; /* pointer to text (could be kanji) */
73 /* or to the object's description */
75 WMFont
*font
; /* the font */
76 WMWidget
*widget
; /* the embedded widget */
77 WMPixmap
*pixmap
; /* the pixmap */
78 } d
; /* description */
80 unsigned short used
; /* number of chars in this block */
81 unsigned short allocated
; /* size of allocation (in chars) */
82 WMColor
*color
; /* the color */
84 Section
*sections
; /* the region for layouts (a growable array) */
85 /* an _array_! of size _nsections_ */
87 unsigned short s_begin
; /* where the selection begins */
88 unsigned short s_end
; /* where it ends */
90 unsigned int first
:1; /* first TextBlock in paragraph */
91 unsigned int blank
:1; /* ie. blank paragraph */
92 unsigned int kanji
:1; /* is of 16-bit characters or not */
93 unsigned int graphic
:1; /* graphic or text: text=0 */
94 unsigned int object
:1; /* embedded object or pixmap */
95 unsigned int underlined
:1; /* underlined or not */
96 unsigned int selected
:1; /* selected or not */
97 unsigned int nsections
:8; /* over how many "lines" a TextBlock wraps */
98 int script
:8; /* script in points: negative for subscript */
99 unsigned int marginN
:8; /* which of the margins in the tPtr to use */
100 unsigned int RESERVED
:9;
104 /* somehow visible.h beats the hell outta visible.size.height :-) */
113 typedef struct W_Text
{
114 W_Class widgetClass
; /* the class number of this widget */
115 W_View
*view
; /* the view referring to this instance */
117 WMRuler
*ruler
; /* the ruler widget to manipulate paragraphs */
119 WMScroller
*vS
; /* the vertical scroller */
120 unsigned int vpos
; /* the current vertical position */
121 unsigned int prevVpos
; /* the previous vertical position */
123 WMScroller
*hS
; /* the horizontal scroller */
124 unsigned int hpos
; /* the current horizontal position */
125 unsigned int prevHpos
; /* the previous horizontal position */
127 WMFont
*dFont
; /* the default font */
128 WMColor
*dColor
; /* the default color */
129 WMPixmap
*dBulletPix
; /* the default pixmap for bullets */
131 GC bgGC
; /* the background GC to draw with */
132 GC fgGC
; /* the foreground GC to draw with */
133 Pixmap db
; /* the buffer on which to draw */
135 myRect visible
; /* the actual rectangle that can be drawn into */
136 myRect cursor
; /* the position and (height) of cursor */
137 myRect sel
; /* the selection rectangle */
139 WMPoint clicked
; /* where in the _document_ was clicked */
141 unsigned short tpos
; /* the position in the currentTextBlock */
142 unsigned short docWidth
; /* the width of the entire document */
143 unsigned int docHeight
; /* the height of the entire document */
145 TextBlock
*firstTextBlock
;
146 TextBlock
*lastTextBlock
;
147 TextBlock
*currentTextBlock
;
149 WMBag
*gfxItems
; /* a nice bag containing graphic items */
152 WMHandlerID timerID
; /* for nice twinky-winky */
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 waitingForSelection
:1; /* dum dee dumm... */
169 unsigned int extendSelection
:1; /* shift-drag to select more regions */
171 unsigned int rulerShown
:1; /* whether the ruler is shown or not */
172 unsigned int frozen
:1; /* whether screen updates are to be made */
173 unsigned int cursorShown
:1; /* whether to show the cursor */
174 unsigned int clickPos
:1; /* clicked before=0 or after=1 a graphic: */
175 /* (within counts as after too) */
177 unsigned int horizOnDemand
:1;/* if a large image should appear*/
178 unsigned int needsRefresh
:1; /* in case of Append/Deletes */
179 unsigned int ignoreNewLine
:1;/* turn it into a ' ' in streams > 1 */
180 unsigned int laidOut
:1; /* have the TextBlocks all been laid out */
181 unsigned int prepend
:1; /* prepend=1, append=0 (for parsers) */
182 WMAlignment alignment
:2; /* the alignment for text */
183 WMReliefType relief
:3; /* the relief to display with */
184 unsigned int RESERVED
:2;
190 * A hack to speed up caseless_equal. Thanks to Quincey Koziol for
191 * developing it for the "chimera" folks so I could use it 7 years later ;-)
192 * Constraint: nothing but '\0' may map to 0
194 static unsigned char map_table
[256] = {
195 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,
196 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
197 52,53,54,55,56,57,58,59,60,61,62,63,64,97,98,99,100,101,102,103,104,105,
198 106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,91,
199 92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,
200 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,
201 130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,
202 148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,
203 166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,
204 184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,
205 202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,
206 220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,
207 238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255};
209 #define MAX_TB_PER_LINE 64
210 #define MAX_TOKEN_SIZE 255
211 #define MAX_TEXT_SIZE 1023
213 #define TOLOWER(x) (map_table[(int)x])
215 #define ISALNUM(x) ( ((x>='0') && (x<='9')) \
216 || ((x>='a') && (x<='z')) || ((x>='A') && x<='Z'))
219 #define CURSOR_BLINK_ON_DELAY 600
220 #define CURSOR_BLINK_OFF_DELAY 400
223 static char *default_bullet
[] = {
225 " c None s None", ". c black",
226 "X c white", "o c #808080",
235 handleEvents(XEvent
*event
, void *data
);
239 getMarginNumber(Text
*tPtr
, WMRulerMargins
*margins
)
243 for(i
=0; i
< tPtr
->nMargins
; i
++) {
245 if(WMIsMarginEqualToMargin(&tPtr
->margins
[i
], margins
))
256 newMargin(Text
*tPtr
, WMRulerMargins
*margins
)
261 tPtr
->margins
[0].retainCount
++;
265 n
= getMarginNumber(tPtr
, margins
);
269 tPtr
->margins
= wrealloc(tPtr
->margins
,
270 (++tPtr
->nMargins
)*sizeof(WMRulerMargins
));
272 n
= tPtr
->nMargins
-1;
273 tPtr
->margins
[n
].left
= margins
->left
;
274 tPtr
->margins
[n
].first
= margins
->first
;
275 tPtr
->margins
[n
].body
= margins
->body
;
276 tPtr
->margins
[n
].right
= margins
->right
;
278 tPtr
->margins
[n
].retainCount
= 1;
280 tPtr
->margins
[n
].retainCount
++;
287 sectionWasSelected(Text
*tPtr
, TextBlock
*tb
, XRectangle
*rect
, int s
)
289 unsigned short i
, w
, lw
, selected
= False
, extend
= False
;
293 /* if selection rectangle completely encloses the section */
294 if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
295 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
296 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
298 sel
.w
= tPtr
->visible
.w
;
299 selected
= extend
= True
;
301 /* or if it starts on a line and then goes further down */
302 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
303 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
304 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
305 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
306 >= tPtr
->visible
.y
+ tPtr
->sel
.y
) ) {
307 sel
.x
= WMAX(tPtr
->sel
.x
, tPtr
->clicked
.x
);
308 sel
.w
= tPtr
->visible
.w
;
309 selected
= extend
= True
;
311 /* or if it begins before a line, but ends on it */
312 } else if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
313 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
314 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
315 && (tb
->sections
[s
]._y
316 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
318 if (1||tPtr
->sel
.x
+ tPtr
->sel
.w
> tPtr
->clicked
.x
)
319 sel
.w
= tPtr
->sel
.x
+ tPtr
->sel
.w
;
326 /* or if the selection rectangle lies entirely within a line */
327 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
328 && (tPtr
->sel
.w
>= 2)
329 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
330 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
339 /* if not within (modified) selection rectangle */
340 if ( tb
->sections
[s
].x
> sel
.x
+ sel
.w
341 || tb
->sections
[s
].x
+ tb
->sections
[s
].w
< sel
.x
)
345 if ( tb
->sections
[s
].x
+ tb
->sections
[s
].w
<= sel
.x
+ sel
.w
346 && tb
->sections
[s
].x
>= sel
.x
) {
347 rect
->width
= tb
->sections
[s
].w
;
348 rect
->x
= tb
->sections
[s
].x
;
353 i
= tb
->sections
[s
].begin
;
356 if (0&& tb
->sections
[s
].x
>= sel
.x
) {
357 tb
->s_begin
= tb
->sections
[s
].begin
;
361 while (++i
<= tb
->sections
[s
].end
) {
363 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
366 if (lw
+ tb
->sections
[s
].x
>= sel
.x
367 || i
== tb
->sections
[s
].end
) {
370 tb
->s_begin
= (tb
->selected
? WMIN(tb
->s_begin
, i
) : i
);
375 if (i
> tb
->sections
[s
].end
) {
376 printf("WasSelected: (i > tb->sections[s].end) \n");
380 _selEnd
: rect
->x
= tb
->sections
[s
].x
+ lw
;
382 while(++i
<= tb
->sections
[s
].end
) {
384 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
387 if (lw
+ rect
->x
>= sel
.x
+ sel
.w
388 || i
== tb
->sections
[s
].end
) {
390 if (i
!= tb
->sections
[s
].end
) {
396 if (tb
->sections
[s
].last
&& sel
.x
+ sel
.w
397 >= tb
->sections
[s
].x
+ tb
->sections
[s
].w
399 rect
->width
+= (tPtr
->visible
.w
- rect
->x
- lw
);
402 tb
->s_end
= (tb
->selected
? WMAX(tb
->s_end
, i
) : i
);
408 rect
->y
= tb
->sections
[s
]._y
- tPtr
->vpos
;
409 rect
->height
= tb
->sections
[s
].h
;
410 if(tb
->graphic
) { printf("graphic s%d h%d\n", s
,tb
->sections
[s
].h
);}
417 setSelectionProperty(WMText
*tPtr
, WMFont
*font
, WMColor
*color
)
422 if((font
&& color
) || (!font
&& !color
))
429 tb
= tPtr
->firstTextBlock
;
430 if (!tb
|| !tPtr
->flags
.ownsSelection
)
437 if ( (tb
->s_end
- tb
->s_begin
== tb
->used
) || tb
->graphic
) {
441 WMReleaseFont(tb
->d
.font
);
442 tb
->d
.font
= WMRetainFont(font
);
445 WMReleaseColor(tb
->color
);
446 tb
->color
= WMRetainColor(color
);
449 } else if (tb
->s_end
<= tb
->used
) {
453 TextBlock
*ntb
= (TextBlock
*)
454 WMCreateTextBlockWithText(tPtr
,
455 &(tb
->text
[tb
->s_begin
]),
456 (isFont
?font
:tb
->d
.font
),
457 (isFont
?tb
->color
:color
),
458 False
, (tb
->s_end
- tb
->s_begin
));
461 ntb
->selected
= True
;
463 ntb
->s_end
= ntb
->used
;
464 WMAppendTextBlock(tPtr
, ntb
);
469 if (tb
->used
> tb
->s_end
) {
471 WMCreateTextBlockWithText(tPtr
,
472 &(tb
->text
[tb
->s_end
]),
473 (isFont
?font
:tb
->d
.font
),
474 (isFont
?tb
->color
:color
),
475 False
, tb
->used
- tb
->s_end
);
478 ntb
->selected
= True
;
480 ntb
->s_end
= ntb
->used
;
481 WMAppendTextBlock(tPtr
, ntb
);
490 tb
= otb
->next
->next
;
492 tb
->used
= tb
->s_end
= tb
->s_begin
;
499 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
504 removeSelection(Text
*tPtr
)
506 TextBlock
*tb
= NULL
;
508 if (!(tb
= tPtr
->firstTextBlock
))
514 if ( (tb
->s_end
- tb
->s_begin
== tb
->used
) || tb
->graphic
) {
515 tPtr
->currentTextBlock
= tb
;
516 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
517 tb
= tPtr
->currentTextBlock
;
522 } else if (tb
->s_end
<= tb
->used
) {
523 memmove(&(tb
->text
[tb
->s_begin
]),
524 &(tb
->text
[tb
->s_end
]), tb
->used
- tb
->s_end
);
525 tb
->used
-= (tb
->s_end
- tb
->s_begin
);
526 tb
->selected
= False
;
527 tPtr
->tpos
= tb
->s_begin
;
538 paintText(Text
*tPtr
)
540 TextBlock
*tb
= tPtr
->firstTextBlock
;
544 int len
, y
, c
, s
, done
=False
;
546 WMScreen
*scr
= tPtr
->view
->screen
;
547 Display
*dpy
= tPtr
->view
->screen
->display
;
548 Window win
= tPtr
->view
->window
;
550 if (!tPtr
->view
->flags
.realized
|| !tPtr
->db
|| tPtr
->flags
.frozen
)
553 XFillRectangle(dpy
, tPtr
->db
, tPtr
->bgGC
,
554 0, 0, tPtr
->visible
.w
, tPtr
->visible
.h
);
556 tb
= tPtr
->firstTextBlock
;
561 if (tPtr
->flags
.ownsSelection
)
562 greyGC
= WMColorGC(WMGrayColor(scr
));
566 while (!done
&& tb
) {
573 tb
->selected
= False
;
575 for(s
=0; s
<tb
->nsections
&& !done
; s
++) {
577 if (tb
->sections
[s
]._y
> tPtr
->vpos
+ tPtr
->visible
.h
) {
582 if ( tb
->sections
[s
].y
+ tb
->sections
[s
].h
< tPtr
->vpos
)
585 if (tPtr
->flags
.monoFont
) {
590 gc
= WMColorGC(tb
->color
);
593 if (tPtr
->flags
.ownsSelection
) {
596 if ( sectionWasSelected(tPtr
, tb
, &rect
, s
)) {
598 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
599 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
603 prev_y
= tb
->sections
[s
]._y
;
605 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
606 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
607 y
= tb
->sections
[s
].y
- tPtr
->vpos
;
608 WMDrawString(scr
, tPtr
->db
, gc
, font
,
609 tb
->sections
[s
].x
- tPtr
->hpos
, y
, text
, len
);
611 if (tb
->underlined
) {
612 XDrawLine(dpy
, tPtr
->db
, gc
,
613 tb
->sections
[s
].x
- tPtr
->hpos
,
615 tb
->sections
[s
].x
+ tb
->sections
[s
].w
- tPtr
->hpos
,
621 tb
= (!done
? tb
->next
: NULL
);
625 c
= WMGetBagItemCount(tPtr
->gfxItems
);
626 if (c
> 0 && !tPtr
->flags
.monoFont
) {
630 tb
= (TextBlock
*) WMGetFromBag(tPtr
->gfxItems
, j
);
631 if (tb
->sections
[0]._y
+ tb
->sections
[0].h
<= tPtr
->vpos
632 || tb
->sections
[0]._y
>= tPtr
->vpos
+ tPtr
->visible
.h
) {
635 if ((W_VIEW(tb
->d
.widget
))->flags
.mapped
) {
636 WMUnmapWidget(tb
->d
.widget
);
641 if (!(W_VIEW(tb
->d
.widget
))->flags
.mapped
) {
642 if (!(W_VIEW(tb
->d
.widget
))->flags
.realized
)
643 WMRealizeWidget(tb
->d
.widget
);
644 WMMapWidget(tb
->d
.widget
);
645 WMLowerWidget(tb
->d
.widget
);
649 if (tPtr
->flags
.ownsSelection
) {
652 if ( sectionWasSelected(tPtr
, tb
, &rect
, s
)) {
654 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
655 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
660 WMMoveWidget(tb
->d
.widget
,
661 tb
->sections
[0].x
- tPtr
->hpos
,
662 tb
->sections
[0].y
- tPtr
->vpos
);
663 h
= WMWidgetHeight(tb
->d
.widget
) + 1;
666 WMDrawPixmap(tb
->d
.pixmap
, tPtr
->db
,
667 tb
->sections
[0].x
- tPtr
->hpos
,
668 tb
->sections
[0].y
- tPtr
->vpos
);
669 h
= tb
->d
.pixmap
->height
+ 1;
673 if (tb
->underlined
) {
674 XDrawLine(dpy
, tPtr
->db
, WMColorGC(tb
->color
),
676 tb
->sections
[0].y
+ h
,
677 tb
->sections
[0].x
+ tb
->sections
[0].w
,
678 tb
->sections
[0].y
+ h
);
683 if (tPtr
->flags
.editable
&& tPtr
->flags
.cursorShown
684 && tPtr
->cursor
.x
!= -23 && tPtr
->flags
.focused
) {
685 int y
= tPtr
->cursor
.y
- tPtr
->vpos
;
686 XDrawLine(dpy
, tPtr
->db
, tPtr
->fgGC
,
688 tPtr
->cursor
.x
, y
+ tPtr
->cursor
.h
);
691 XCopyArea(dpy
, tPtr
->db
, win
, tPtr
->bgGC
,
693 tPtr
->visible
.w
, tPtr
->visible
.h
,
694 tPtr
->visible
.x
, tPtr
->visible
.y
);
697 W_DrawRelief(scr
, win
, 0, 0,
698 tPtr
->view
->size
.width
, tPtr
->view
->size
.height
,
701 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)
704 tPtr
->view
->size
.width
-4, 42);
712 blinkCursor(void *data
)
714 Text
*tPtr
= (Text
*)data
;
716 if (tPtr
->flags
.cursorShown
) {
717 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY
,
720 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
,
724 tPtr
->flags
.cursorShown
= !tPtr
->flags
.cursorShown
;
729 getFirstNonGraphicBlockFor(TextBlock
*tb
, short dir
)
736 tb
= (dir
? tb
->next
: tb
->prior
);
744 cursorToTextPosition(Text
*tPtr
, int x
, int y
)
746 TextBlock
*tb
= NULL
;
747 int done
=False
, s
, pos
, len
, _w
, _y
, dir
=1; /* 1 == "down" */
750 if(tPtr
->flags
.needsRefresh
)
751 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
753 y
+= (tPtr
->vpos
- tPtr
->visible
.y
);
757 x
-= (tPtr
->visible
.x
- 2);
761 /* clicked is relative to document, not window... */
765 if (! (tb
= tPtr
->currentTextBlock
)) {
766 if (! (tb
= tPtr
->firstTextBlock
)) {
768 tPtr
->cursor
.h
= tPtr
->dFont
->height
;
775 /* first, which direction? Most likely, newly clicked
776 position will be close to previous */
777 dir
= !(y
<= tb
->sections
[0].y
);
778 if ( ( y
<= tb
->sections
[0]._y
+ tb
->sections
[0].h
)
779 && (y
>= tb
->sections
[0]._y
) ) {
780 /* if it's on the same line */
781 if(x
< tb
->sections
[0].x
)
783 if(x
>= tb
->sections
[0].x
)
787 tb
= tPtr
->firstTextBlock
;
790 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
791 tb
= getFirstNonGraphicBlockFor(tb
, 1);
793 tPtr
->currentTextBlock
=
794 (dir
? tPtr
->lastTextBlock
: tPtr
->firstTextBlock
);
800 s
= (dir
? 0 : tb
->nsections
-1);
801 if ( y
>= tb
->sections
[s
]._y
802 && y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) {
806 /* get the first section of the TextBlock that lies about
807 the vertical click point */
809 while (!done
&& tb
) {
811 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
817 s
= (dir
? 0 : tb
->nsections
-1);
818 while (!done
&& (dir
? (s
<tb
->nsections
) : (s
>=0) )) {
820 if ( (dir
? (y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) :
821 ( y
>= tb
->sections
[s
]._y
) ) ) {
829 if ( (dir
? tb
->next
: tb
->prior
)) {
830 tb
= (dir
? tb
->next
: tb
->prior
);
833 break; //goto _doneH;
839 if (s
<0 || s
>=tb
->nsections
) {
840 s
= (dir
? tb
->nsections
-1 : 0);
844 /* we have the line, which TextBlock on that line is it? */
846 if (tPtr
->flags
.monoFont
&& tb
->graphic
)
847 tb
= getFirstNonGraphicBlockFor(tb
, dir
);
849 if ((dir
? tb
->sections
[s
].x
>= x
: tb
->sections
[s
].x
< x
))
857 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
858 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
859 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
861 printf("here %d %d \n", tb
->sections
[s
].x
+ _w
, x
);
862 if ((dir
? tb
->sections
[s
].x
+ _w
< x
: tb
->sections
[s
].x
+ _w
>= x
)) {
863 pos
= tb
->sections
[s
].end
;
864 tPtr
->cursor
.x
= tb
->sections
[s
].x
+ _w
;
868 _y
= tb
->sections
[s
]._y
;
873 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
874 tb
= (dir
? tb
->next
: tb
->prior
);
881 _w
= WMWidgetWidth(tb
->d
.widget
);
883 _w
= tb
->d
.pixmap
->width
;
885 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
886 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
887 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
888 if (tb
->sections
[s
].x
+ _w
>= x
)
893 if (tb
->sections
[s
].x
<= x
)
897 if ((dir
? tb
->next
: tb
->prior
)) {
898 TextBlock
*nxt
= (dir
? tb
->next
: tb
->prior
);
899 if (tPtr
->flags
.monoFont
&& nxt
->graphic
) {
900 nxt
= getFirstNonGraphicBlockFor(nxt
, dir
);
903 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
908 if (_y
!= nxt
->sections
[0]._y
) {
909 /* this must be the last/first on this line. stop */
910 pos
= (dir
? tb
->sections
[s
].end
: 0);
911 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
915 tPtr
->cursor
.x
+= WMWidgetWidth(tb
->d
.widget
);
917 tPtr
->cursor
.x
+= tb
->d
.pixmap
->width
;
918 } else if (pos
> tb
->sections
[s
].begin
) {
920 WMWidthOfString(tb
->d
.font
,
921 &(tb
->text
[tb
->sections
[s
].begin
]),
922 pos
- tb
->sections
[s
].begin
);
929 if ( (dir
? tb
->next
: tb
->prior
)) {
930 tb
= (dir
? tb
->next
: tb
->prior
);
937 s
= (dir
? 0 : tb
->nsections
-1);
940 /* we have said TextBlock, now where within it? */
941 if (tb
&& !tb
->graphic
) {
942 WMFont
*f
= tb
->d
.font
;
943 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
944 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
946 _w
= x
- tb
->sections
[s
].x
;
949 while (pos
<len
&& WMWidthOfString(f
, text
, pos
+1) < _w
)
952 tPtr
->cursor
.x
= tb
->sections
[s
].x
+
953 (pos
? WMWidthOfString(f
, text
, pos
) : 0);
955 pos
+= tb
->sections
[s
].begin
;
957 tPtr
->tpos
= (pos
<tb
->used
)? pos
: tb
->used
;
960 tPtr
->currentTextBlock
= tb
;
961 tPtr
->cursor
.h
= tb
->sections
[s
].h
;
962 tPtr
->cursor
.y
= tb
->sections
[s
]._y
;
965 printf("will hang :-)\n");
970 updateScrollers(Text
*tPtr
)
973 if (tPtr
->flags
.frozen
)
977 if (tPtr
->docHeight
< tPtr
->visible
.h
) {
978 WMSetScrollerParameters(tPtr
->vS
, 0, 1);
981 float hmax
= (float)(tPtr
->docHeight
);
982 WMSetScrollerParameters(tPtr
->vS
,
983 ((float)tPtr
->vpos
)/(hmax
- (float)tPtr
->visible
.h
),
984 (float)tPtr
->visible
.h
/hmax
);
986 } else tPtr
->vpos
= 0;
989 if (tPtr
->docWidth
< tPtr
->visible
.w
) {
990 WMSetScrollerParameters(tPtr
->hS
, 0, 1);
993 float wmax
= (float)(tPtr
->docWidth
);
994 WMSetScrollerParameters(tPtr
->hS
,
995 ((float)tPtr
->hpos
)/(wmax
- (float)tPtr
->visible
.w
),
996 (float)tPtr
->visible
.w
/wmax
);
998 } else tPtr
->hpos
= 0;
1002 scrollersCallBack(WMWidget
*w
, void *self
)
1004 Text
*tPtr
= (Text
*)self
;
1005 Bool scroll
= False
;
1006 Bool dimple
= False
;
1009 if (!tPtr
->view
->flags
.realized
|| tPtr
->flags
.frozen
)
1012 if (w
== tPtr
->vS
) {
1014 height
= tPtr
->visible
.h
;
1016 which
= WMGetScrollerHitPart(tPtr
->vS
);
1018 case WSDecrementLine
:
1019 if (tPtr
->vpos
> 0) {
1020 if (tPtr
->vpos
>16) tPtr
->vpos
-=16;
1024 case WSIncrementLine
: {
1025 int limit
= tPtr
->docHeight
- height
;
1026 if (tPtr
->vpos
< limit
) {
1027 if (tPtr
->vpos
<limit
-16) tPtr
->vpos
+=16;
1028 else tPtr
->vpos
=limit
;
1031 case WSDecrementPage
:
1032 tPtr
->vpos
-= height
;
1038 printf("dimple needs to jump to mouse location ;-/\n");
1040 case WSIncrementPage
:
1041 tPtr
->vpos
+= height
;
1042 if (tPtr
->vpos
> (tPtr
->docHeight
- height
))
1043 tPtr
->vpos
= tPtr
->docHeight
- height
;
1046 printf("dimple needs to jump to mouse location ;-/\n");
1051 tPtr
->vpos
= WMGetScrollerValue(tPtr
->vS
)
1052 * (float)(tPtr
->docHeight
- height
);
1058 printf("WSNoPart, WSKnobSlot\n");
1060 float hmax
= (float)(tPtr
->docHeight
);
1061 ((float)tPtr
->vpos
)/(hmax
- (float)tPtr
->visible
.h
),
1062 (float)tPtr
->visible
.h
/hmax
;
1063 dimple
=where mouse is
.
1067 scroll
= (tPtr
->vpos
!= tPtr
->prevVpos
);
1068 tPtr
->prevVpos
= tPtr
->vpos
;
1071 if (w
== tPtr
->hS
) {
1072 int width
= tPtr
->visible
.w
;
1074 which
= WMGetScrollerHitPart(tPtr
->hS
);
1076 case WSDecrementLine
:
1077 if (tPtr
->hpos
> 0) {
1078 if (tPtr
->hpos
>16) tPtr
->hpos
-=16;
1082 case WSIncrementLine
: {
1083 int limit
= tPtr
->docWidth
- width
;
1084 if (tPtr
->hpos
< limit
) {
1085 if (tPtr
->hpos
<limit
-16) tPtr
->hpos
+=16;
1086 else tPtr
->hpos
=limit
;
1089 case WSDecrementPage
:
1090 tPtr
->hpos
-= width
;
1096 printf("dimple needs to jump to mouse location ;-/\n");
1098 case WSIncrementPage
:
1099 tPtr
->hpos
+= width
;
1100 if (tPtr
->hpos
> (tPtr
->docWidth
- width
))
1101 tPtr
->hpos
= tPtr
->docWidth
- width
;
1104 printf("dimple needs to jump to mouse location ;-/\n");
1109 tPtr
->hpos
= WMGetScrollerValue(tPtr
->hS
)
1110 * (float)(tPtr
->docWidth
- width
);
1116 printf("WSNoPart, WSKnobSlot\n");
1118 float wmax
= (float)(tPtr
->docWidth
);
1119 ((float)tPtr
->vpos
)/(wmax
- (float)tPtr
->visible
.w
),
1120 (float)tPtr
->visible
.w
/wmax
;
1121 dimple
=where mouse is
.
1125 scroll
= (tPtr
->hpos
!= tPtr
->prevHpos
);
1126 tPtr
->prevHpos
= tPtr
->hpos
;
1132 if (tPtr->rulerShown)
1133 XClearArea(tPtr->view->screen->display, tPtr->view->window, 22, 47,
1134 tPtr->view->size.width-24, tPtr->view->size.height-49, True);
1136 XClearArea(tPtr->view->screen->display, tPtr->view->window, 22, 2,
1137 tPtr->view->size.width-24, tPtr->view->size.height-4, True);
1140 if (dimple
|| which
== WSDecrementLine
|| which
== WSIncrementLine
)
1141 updateScrollers(tPtr
);
1150 unsigned short begin
, end
; /* what part of the text block */
1155 layOutLine(Text
*tPtr
, myLineItems
*items
, int nitems
, int x
, int y
)
1157 int i
, j
=0, lw
= 0, line_height
=0, max_d
=0, len
, n
;
1161 TextBlock
*tbsame
=NULL
;
1163 for(i
=0; i
<nitems
; i
++) {
1167 if (!tPtr
->flags
.monoFont
) {
1169 WMWidget
*wdt
= tb
->d
.widget
;
1170 line_height
= WMAX(line_height
, WMWidgetHeight(wdt
));
1171 if (tPtr
->flags
.alignment
!= WALeft
)
1172 lw
+= WMWidgetWidth(wdt
);
1174 line_height
= WMAX(line_height
, tb
->d
.pixmap
->height
+ max_d
);
1175 if (tPtr
->flags
.alignment
!= WALeft
)
1176 lw
+= tb
->d
.pixmap
->width
;
1181 font
= (tPtr
->flags
.monoFont
)?tPtr
->dFont
: tb
->d
.font
;
1182 max_d
= WMAX(max_d
, abs(font
->height
-font
->y
));
1183 line_height
= WMAX(line_height
, font
->height
+ max_d
);
1184 text
= &(tb
->text
[items
[i
].begin
]);
1185 len
= items
[i
].end
- items
[i
].begin
;
1186 if (tPtr
->flags
.alignment
!= WALeft
)
1187 lw
+= WMWidthOfString(font
, text
, len
);
1191 if (tPtr
->flags
.alignment
== WARight
) {
1192 j
= tPtr
->visible
.w
- lw
;
1193 } else if (tPtr
->flags
.alignment
== WACenter
) {
1194 j
= (int) ((float)(tPtr
->visible
.w
- lw
))/2.0;
1197 for(i
=0; i
<nitems
; i
++) {
1200 if (tbsame
== tb
) { /*extend it, since it's on same line */
1201 tb
->sections
[tb
->nsections
-1].end
= items
[i
].end
;
1202 n
= tb
->nsections
-1;
1204 tb
->sections
= wrealloc(tb
->sections
,
1205 (++tb
->nsections
)*sizeof(Section
));
1206 n
= tb
->nsections
-1;
1207 tb
->sections
[n
]._y
= y
+ max_d
;
1208 tb
->sections
[n
].x
= x
+j
;
1209 tb
->sections
[n
].h
= line_height
;
1210 tb
->sections
[n
].begin
= items
[i
].begin
;
1211 tb
->sections
[n
].end
= items
[i
].end
;
1213 if (tb
->graphic
&& tb
->object
) {
1214 tb
->sections
[n
].x
+= tPtr
->visible
.x
;
1215 tb
->sections
[n
].y
+= tPtr
->visible
.y
;
1219 tb
->sections
[n
].last
= (i
+1 == nitems
);
1222 if (!tPtr
->flags
.monoFont
) {
1224 WMWidget
*wdt
= tb
->d
.widget
;
1225 tb
->sections
[n
].y
= max_d
+ y
1226 + line_height
- WMWidgetHeight(wdt
);
1227 tb
->sections
[n
].w
= WMWidgetWidth(wdt
);
1229 tb
->sections
[n
].y
= y
+ max_d
;
1230 tb
->sections
[n
].w
= tb
->d
.pixmap
->width
;
1232 x
+= tb
->sections
[n
].w
;
1235 font
= (tPtr
->flags
.monoFont
)? tPtr
->dFont
: tb
->d
.font
;
1236 len
= items
[i
].end
- items
[i
].begin
;
1237 text
= &(tb
->text
[items
[i
].begin
]);
1239 tb
->sections
[n
].y
= y
+line_height
-font
->y
;
1241 WMWidthOfString(font
,
1242 &(tb
->text
[tb
->sections
[n
].begin
]),
1243 tb
->sections
[n
].end
- tb
->sections
[n
].begin
);
1245 x
+= WMWidthOfString(font
, text
, len
);
1257 output(char *ptr
, int len
)
1260 memcpy(s
, ptr
, len
);
1262 //printf(" s is [%s] (%d)\n", s, strlen(s));
1263 printf("[%s]\n", s
);
1267 /* tb->text doesn't necessarily end in '\0' hmph! (strchr) */
1268 static inline char *
1269 mystrchr(char *s
, char needle
, unsigned short len
)
1273 if (!haystack
|| len
< 1)
1276 while ( (int) (haystack
- s
) < len
) {
1277 if (*haystack
== needle
)
1285 mystrcasecmp(const unsigned char *s1
, const unsigned char *s2
)
1290 while (*s2
!= '\0') {
1291 if (TOLOWER (*s1
) != TOLOWER (*s2
)) /* true if *s1 == 0 ! */
1296 return (*s1
=='\0' || !ISALNUM(*s1
))?1:0;
1301 layOutDocument(Text
*tPtr
)
1304 myLineItems items
[MAX_TB_PER_LINE
];
1306 Bool lhc
= !tPtr
->flags
.laidOut
; /* line height changed? */
1307 int prev_y
, nitems
=0, x
=0, y
=0, lw
= 0, width
=0;
1309 char *start
=NULL
, *mark
=NULL
;
1312 if (tPtr
->flags
.frozen
)
1315 if (!(tb
= tPtr
->firstTextBlock
))
1318 tPtr
->docWidth
= tPtr
->visible
.w
;
1320 if (0&&tPtr
->flags
.laidOut
) {
1321 tb
= tPtr
->currentTextBlock
;
1322 if (tb
->sections
&& tb
->nsections
>0)
1323 prev_y
= tb
->sections
[tb
->nsections
-1]._y
;
1325 printf("1 prev_y %d \n", prev_y
);
1327 /* search backwards for textblocks on same line */
1329 if (!tb
->sections
|| tb
->nsections
<1) {
1330 tb
= tPtr
->firstTextBlock
;
1333 if (tb
->sections
[tb
->nsections
-1]._y
!= prev_y
) {
1337 // prev_y = tb->sections[tb->nsections-1]._y;
1340 y
= 0;//tb->sections[tb->nsections-1]._y;
1341 printf("2 prev_y %d \n\n", tb
->sections
[tb
->nsections
-1]._y
);
1347 if (tb
->sections
&& tb
->nsections
>0) {
1348 wfree(tb
->sections
);
1349 tb
->sections
= NULL
;
1354 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1355 x
= 0;//tb->margins.first;
1361 if (!tPtr
->flags
.monoFont
) {
1363 width
= WMWidgetWidth(tb
->d
.widget
);
1365 width
= tb
->d
.pixmap
->width
;
1367 if (width
> tPtr
->docWidth
) { //tPtr->visible.w) {
1368 printf("rescale graphix to fit?\n");
1369 printf("%d %d\n", width
, tPtr
->visible
.w
);
1370 tPtr
->docWidth
= width
;//tPtr->visible.w + (width-tPtr->visible.w);
1374 if (lw
>= tPtr
->visible
.w
- x
1375 || nitems
>= MAX_TB_PER_LINE
) {
1376 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1378 x
= 0;//tb->margins.first;
1382 items
[nitems
].tb
= tb
;
1383 items
[nitems
].begin
= 0;
1384 items
[nitems
].end
= 0;
1388 } else if ((start
= tb
->text
)) {
1390 font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
1393 mark
= mystrchr(start
, ' ', tb
->used
);
1395 end
+= (int)(mark
-start
)+1;
1398 end
+= strlen(start
);
1405 if (end
-begin
> 0) {
1407 width
= WMWidthOfString(font
,
1408 &tb
->text
[begin
], end
-begin
);
1410 if (width
> tPtr
->visible
.w
) { /* break this tb up */
1411 char *t
= &tb
->text
[begin
];
1412 int l
=end
-begin
, i
=0;
1414 width
= WMWidthOfString(font
, t
, ++i
);
1415 } while (width
< tPtr
->visible
.w
&& i
< l
);
1417 if (start
) // and since (nil)-4 = 0xfffffffd
1424 if ((lw
>= tPtr
->visible
.w
- x
)
1425 || nitems
>= MAX_TB_PER_LINE
) {
1426 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1428 x
= 0;//tb->margins.first;
1432 items
[nitems
].tb
= tb
;
1433 items
[nitems
].begin
= begin
;
1434 items
[nitems
].end
= end
;
1445 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1447 tPtr
->docHeight
= y
+10;
1448 updateScrollers(tPtr
);
1451 if(tPtr
->docWidth
> tPtr
->visible
.w
&& !tPtr
->hS
) {
1454 tPtr
->flags
.horizOnDemand
= True
;
1455 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, True
);
1456 event
.type
= Expose
;
1457 handleEvents(&event
, (void *)tPtr
);
1459 } else if(tPtr
->docWidth
<= tPtr
->visible
.w
1460 && tPtr
->hS
&& tPtr
->flags
.horizOnDemand
) {
1461 tPtr
->flags
.horizOnDemand
= False
;
1462 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, False
);
1464 tPtr
->flags
.laidOut
= True
;
1470 textDidResize(W_ViewDelegate
*self
, WMView
*view
)
1472 Text
*tPtr
= (Text
*)view
->self
;
1473 unsigned short w
= tPtr
->view
->size
.width
;
1474 unsigned short h
= tPtr
->view
->size
.height
;
1475 unsigned short rh
= 0, vw
= 0;
1477 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
) {
1478 WMMoveWidget(tPtr
->ruler
, 2, 2);
1479 WMResizeWidget(tPtr
->ruler
, w
- 4, 40);
1484 WMMoveWidget(tPtr
->vS
, 1, rh
+ 1);
1485 WMResizeWidget(tPtr
->vS
, 20, h
- rh
- 2);
1487 WMSetRulerOffset(tPtr
->ruler
,22);
1488 } else WMSetRulerOffset(tPtr
->ruler
, 2);
1492 WMMoveWidget(tPtr
->hS
, vw
, h
- 21);
1493 WMResizeWidget(tPtr
->hS
, w
- vw
- 1, 20);
1495 WMMoveWidget(tPtr
->hS
, vw
+1, h
- 21);
1496 WMResizeWidget(tPtr
->hS
, w
- vw
- 2, 20);
1500 tPtr
->visible
.x
= (tPtr
->vS
)?21:1;
1501 tPtr
->visible
.y
= (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)?43:3;
1502 tPtr
->visible
.w
= tPtr
->view
->size
.width
- tPtr
->visible
.x
- 2;
1503 tPtr
->visible
.h
= tPtr
->view
->size
.height
- tPtr
->visible
.y
;
1504 tPtr
->visible
.h
-= (tPtr
->hS
)?20:0;
1505 tPtr
->margins
[0].right
= tPtr
->visible
.w
;
1507 if (tPtr
->view
->flags
.realized
) {
1510 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
1511 tPtr
->db
= (Pixmap
) NULL
;
1514 if (tPtr
->visible
.w
< 40)
1515 tPtr
->visible
.w
= 40;
1516 if (tPtr
->visible
.h
< 20)
1517 tPtr
->visible
.h
= 20;
1519 //if (size change or !db
1521 tPtr
->db
= XCreatePixmap(tPtr
->view
->screen
->display
,
1522 tPtr
->view
->window
, tPtr
->visible
.w
,
1523 tPtr
->visible
.h
, tPtr
->view
->screen
->depth
);
1527 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1530 W_ViewDelegate _TextViewDelegate
=
1538 /* nice, divisble-by-16 blocks */
1539 static inline unsigned short
1540 reqBlockSize(unsigned short requested
)
1542 return requested
+ 16 - (requested
%16);
1547 clearText(Text
*tPtr
)
1549 if (!tPtr
->firstTextBlock
)
1552 while (tPtr
->currentTextBlock
)
1553 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1555 tPtr
->firstTextBlock
= NULL
;
1556 tPtr
->currentTextBlock
= NULL
;
1557 tPtr
->lastTextBlock
= NULL
;
1561 deleteTextInteractively(Text
*tPtr
, KeySym ksym
)
1563 TextBlock
*tb
= tPtr
->currentTextBlock
;
1564 Bool back
= (Bool
) (ksym
== XK_BackSpace
);
1567 if (!tPtr
->flags
.editable
|| tPtr
->flags
.buttonHeld
) {
1568 XBell(tPtr
->view
->screen
->display
, 0);
1575 tPtr
->flags
.needsRefresh
= True
;
1577 if (tPtr
->flags
.ownsSelection
) {
1578 removeSelection(tPtr
);
1582 if (back
&& tPtr
->tpos
< 1) {
1586 tPtr
->tpos
= tb
->used
;
1587 tPtr
->currentTextBlock
= tb
;
1592 if ( (tb
->used
> 0) && ((back
?tPtr
->tpos
> 0:1))
1593 && (tPtr
->tpos
<= tb
->used
) && !tb
->graphic
) {
1596 memmove(&(tb
->text
[tPtr
->tpos
]),
1597 &(tb
->text
[tPtr
->tpos
+ 1]), tb
->used
- tPtr
->tpos
);
1602 if ( (back
? (tPtr
->tpos
< 1 && !done
) : ( tPtr
->tpos
>= tb
->used
))
1605 TextBlock
*sibling
= (back
? tb
->prior
: tb
->next
);
1607 if(tb
->used
== 0 || tb
->graphic
)
1608 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1611 tPtr
->currentTextBlock
= sibling
;
1612 tPtr
->tpos
= (back
? sibling
->used
: 0);
1616 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1621 insertTextInteractively(Text
*tPtr
, char *text
, int len
)
1624 char *newline
= NULL
;
1626 if (!tPtr
->flags
.editable
|| tPtr
->flags
.buttonHeld
) {
1627 XBell(tPtr
->view
->screen
->display
, 0);
1633 WMColor
*color
= WMCreateNamedColor(W_VIEW_SCREEN(tPtr
->view
),
1635 WMSetTextSelectionColor(tPtr
, color
);
1640 if (len
< 1 || !text
)
1644 if(tPtr
->flags
.ignoreNewLine
&& *text
== '\n' && len
== 1)
1647 if (tPtr
->flags
.ownsSelection
)
1648 removeSelection(tPtr
);
1650 tPtr
->flags
.needsRefresh
= True
;
1652 if (tPtr
->flags
.ignoreNewLine
) {
1654 for(i
=0; i
<len
; i
++) {
1655 if (text
[i
] == '\n')
1660 tb
= tPtr
->currentTextBlock
;
1661 if (!tb
|| tb
->graphic
) {
1663 WMAppendTextStream(tPtr
, text
);
1664 if (tPtr
->currentTextBlock
) {
1665 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
1667 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1671 if ((newline
= strchr(text
, '\n'))) {
1672 int nlen
= (int)(newline
-text
);
1673 int s
= tb
->used
- tPtr
->tpos
;
1676 if (!tb
->blank
&& nlen
>0) {
1678 memcpy(save
, &tb
->text
[tPtr
->tpos
], s
);
1679 tb
->used
-= (tb
->used
- tPtr
->tpos
);
1682 insertTextInteractively(tPtr
, text
, nlen
);
1684 WMAppendTextStream(tPtr
, newline
);
1686 insertTextInteractively(tPtr
, save
, s
);
1689 if (tPtr
->tpos
>0 && tPtr
->tpos
< tb
->used
1690 && !tb
->graphic
&& tb
->text
) {
1692 void *ntb
= WMCreateTextBlockWithText(
1693 tPtr
, &tb
->text
[tPtr
->tpos
],
1694 tb
->d
.font
, tb
->color
, True
, tb
->used
- tPtr
->tpos
);
1695 tb
->used
= tPtr
->tpos
;
1696 WMAppendTextBlock(tPtr
, ntb
);
1698 } else if (tPtr
->tpos
== tb
->used
|| tPtr
->tpos
== 0) {
1699 void *ntb
= WMCreateTextBlockWithText(tPtr
,
1700 NULL
, tb
->d
.font
, tb
->color
, True
, 0);
1703 WMAppendTextBlock(tPtr
, ntb
);
1705 WMPrependTextBlock(tPtr
, ntb
);
1712 if (tb
->used
+ len
>= tb
->allocated
) {
1713 tb
->allocated
= reqBlockSize(tb
->used
+len
);
1714 tb
->text
= wrealloc(tb
->text
, tb
->allocated
);
1718 memcpy(tb
->text
, text
, len
);
1723 memmove(&(tb
->text
[tPtr
->tpos
+len
]), &tb
->text
[tPtr
->tpos
],
1724 tb
->used
-tPtr
->tpos
+1);
1725 memmove(&tb
->text
[tPtr
->tpos
], text
, len
);
1732 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1737 selectRegion(Text
*tPtr
, int x
, int y
)
1743 y
+= (tPtr
->flags
.rulerShown
? 40: 0);
1746 y
-= 10; /* the original offset */
1748 x
-= tPtr
->visible
.x
-2;
1752 tPtr
->sel
.x
= WMAX(0, WMIN(tPtr
->clicked
.x
, x
));
1753 tPtr
->sel
.w
= abs(tPtr
->clicked
.x
- x
);
1754 tPtr
->sel
.y
= WMAX(0, WMIN(tPtr
->clicked
.y
, y
));
1755 tPtr
->sel
.h
= abs(tPtr
->clicked
.y
- y
);
1757 tPtr
->flags
.ownsSelection
= True
;
1763 pasteText(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
1764 void *cdata
, WMData
*data
)
1766 Text
*tPtr
= (Text
*)view
->self
;
1769 tPtr
->flags
.waitingForSelection
= False
;
1771 str
= (char*)WMDataBytes(data
);
1772 if (0&&tPtr
->parser
) {
1773 /* parser is not yet well behaved to do this properly..*/
1774 (tPtr
->parser
) (tPtr
, (void *) str
);
1776 insertTextInteractively(tPtr
, str
, strlen(str
));
1780 str
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
1783 if (0&&tPtr
->parser
) {
1784 /* parser is not yet well behaved to do this properly..*/
1785 (tPtr
->parser
) (tPtr
, (void *) str
);
1787 insertTextInteractively(tPtr
, str
, n
);
1796 releaseSelection(Text
*tPtr
)
1798 TextBlock
*tb
= tPtr
->firstTextBlock
;
1801 tb
->selected
= False
;
1804 tPtr
->flags
.ownsSelection
= False
;
1805 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
,
1808 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1812 requestHandler(WMView
*view
, Atom selection
, Atom target
,
1813 void *cdata
, Atom
*type
)
1815 Text
*tPtr
= view
->self
;
1816 Display
*dpy
= tPtr
->view
->screen
->display
;
1817 Atom TEXT
= XInternAtom(dpy
, "TEXT", False
);
1818 Atom COMPOUND_TEXT
= XInternAtom(dpy
, "COMPOUND_TEXT", False
);
1822 if (target
== XA_STRING
|| target
== TEXT
|| target
== COMPOUND_TEXT
) {
1823 char *text
= WMGetTextSelected(tPtr
);
1826 WMData
*data
= WMCreateDataWithBytes(text
, strlen(text
));
1827 WMSetDataFormat(data
, 8);
1833 } else if(target
== XInternAtom(dpy
, "PIXMAP", False
)) {
1834 data
= WMCreateDataWithBytes("paste a pixmap", 14);
1835 WMSetDataFormat(data
, 8);
1840 _TARGETS
= XInternAtom(dpy
, "TARGETS", False
);
1841 if (target
== _TARGETS
) {
1844 ptr
= wmalloc(4 * sizeof(Atom
));
1848 ptr
[3] = COMPOUND_TEXT
;
1850 data
= WMCreateDataWithBytes(ptr
, 4*4);
1851 WMSetDataFormat(data
, 32);
1862 lostHandler(WMView
*view
, Atom selection
, void *cdata
)
1864 releaseSelection((WMText
*)view
->self
);
1867 static WMSelectionProcs selectionHandler
= {
1868 requestHandler
, lostHandler
, NULL
1872 ownershipObserver(void *observerData
, WMNotification
*notification
)
1874 WMText
*to
= (WMText
*)observerData
;
1875 WMText
*tw
= (WMText
*)WMGetNotificationClientData(notification
);
1877 lostHandler(to
->view
, XA_PRIMARY
, NULL
);
1881 fontChanged(void *observerData
, WMNotification
*notification
)
1883 WMText
*tPtr
= (WMText
*) observerData
;
1884 WMFont
*font
= (WMFont
*)WMGetNotificationClientData(notification
);
1885 printf("fontChanged\n");
1890 if (tPtr
->flags
.ownsSelection
)
1891 WMSetTextSelectionFont(tPtr
, font
);
1895 handleTextKeyPress(Text
*tPtr
, XEvent
*event
)
1899 int control_pressed
= False
;
1902 if (((XKeyEvent
*) event
)->state
& ControlMask
)
1903 control_pressed
= True
;
1904 buffer
[XLookupString(&event
->xkey
, buffer
, 1, &ksym
, NULL
)] = 0;
1909 WMScrollText(tPtr
, -14);
1911 TextBlock
*tb
= tPtr
->currentTextBlock
;
1912 int x
= tPtr
->cursor
.x
+ tPtr
->visible
.x
;
1913 int y
= tPtr
->visible
.y
+ tPtr
->cursor
.y
+ tPtr
->cursor
.h
;
1921 w
= WMWidgetWidth(tb
->d
.widget
);
1923 w
= tb
->d
.pixmap
->width
;
1927 w
= WMWidthOfString(tb
->d
.font
, &tb
->text
[pos
], 1);
1930 cursorToTextPosition(tPtr
, w
+ tPtr
->cursor
.x
+ tPtr
->visible
.x
,
1931 3 + tPtr
->visible
.y
+ tPtr
->cursor
.y
1932 + tPtr
->cursor
.h
- tPtr
->vpos
);
1933 if(x
== tPtr
->cursor
.x
+ tPtr
->visible
.x
) {
1934 printf("same %d %d\n", x
, tPtr
->cursor
.x
+ tPtr
->visible
.x
);
1935 cursorToTextPosition(tPtr
, tPtr
->visible
.x
,
1936 3 + tPtr
->visible
.y
+ tPtr
->cursor
.y
+ tPtr
->cursor
.h
);
1944 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
1945 tPtr
->clicked
.y
+ tPtr
->cursor
.h
- tPtr
->vpos
);
1950 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
1951 tPtr
->visible
.y
+ tPtr
->cursor
.y
- tPtr
->vpos
- 3);
1958 deleteTextInteractively(tPtr
, ksym
);
1963 control_pressed
= True
;
1969 if (buffer
[0] != 0 && !control_pressed
) {
1970 insertTextInteractively(tPtr
, buffer
, 1);
1972 } else if (control_pressed
&& ksym
==XK_r
) {
1973 Bool i
= !tPtr
->flags
.rulerShown
;
1974 WMShowTextRuler(tPtr
, i
);
1975 tPtr
->flags
.rulerShown
= i
;
1977 else if (control_pressed
&& buffer
[0] == '\a')
1978 XBell(tPtr
->view
->screen
->display
, 0);
1981 if (!control_pressed
&& tPtr
->flags
.ownsSelection
)
1982 releaseSelection(tPtr
);
1986 handleWidgetPress(XEvent
*event
, void *data
)
1988 TextBlock
*tb
= (TextBlock
*)data
;
1994 /* this little bit of nastiness here saves a boatload of trouble */
1995 w
= (WMWidget
*)(((W_VIEW(tb
->d
.widget
))->parent
)->self
);
1996 if (W_CLASS(w
) != WC_Text
)
1999 tPtr
->currentTextBlock
= getFirstNonGraphicBlockFor(tb
, 1);
2000 if (!tPtr
->currentTextBlock
)
2001 tPtr
->currentTextBlock
= tb
;
2003 output(tPtr
->currentTextBlock
->text
, tPtr
->currentTextBlock
->used
);
2004 //if (!tPtr->flags.focused) {
2005 // WMSetFocusToWidget(tPtr);
2006 // tPtr->flags.focused = True;
2012 handleActionEvents(XEvent
*event
, void *data
)
2014 Text
*tPtr
= (Text
*)data
;
2015 Display
*dpy
= event
->xany
.display
;
2019 switch (event
->type
) {
2021 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2022 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2023 tPtr
->flags
.extendSelection
= True
;
2027 if (tPtr
->flags
.waitingForSelection
)
2029 if (tPtr
->flags
.focused
) {
2030 XGrabPointer(dpy
, W_VIEW(tPtr
)->window
, False
,
2031 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
2032 GrabModeAsync
, GrabModeAsync
, None
,
2033 tPtr
->view
->screen
->invisibleCursor
, CurrentTime
);
2034 tPtr
->flags
.pointerGrabbed
= True
;
2035 handleTextKeyPress(tPtr
, event
);
2040 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2041 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2042 tPtr
->flags
.extendSelection
= False
;
2044 //end modify flag so selection can be extended
2050 if (tPtr
->flags
.pointerGrabbed
) {
2051 tPtr
->flags
.pointerGrabbed
= False
;
2052 XUngrabPointer(dpy
, CurrentTime
);
2055 if ((event
->xmotion
.state
& Button1Mask
)) {
2056 if (!tPtr
->flags
.ownsSelection
) {
2057 WMCreateSelectionHandler(tPtr
->view
, XA_PRIMARY
,
2058 event
->xbutton
.time
, &selectionHandler
, NULL
);
2059 tPtr
->flags
.ownsSelection
= True
;
2061 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2067 tPtr
->flags
.buttonHeld
= True
;
2068 if (tPtr
->flags
.extendSelection
) {
2069 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2072 if (event
->xbutton
.button
== Button1
) {
2074 if (!tPtr
->flags
.focused
) {
2075 WMSetFocusToWidget(tPtr
);
2076 tPtr
->flags
.focused
= True
;
2079 if (tPtr
->flags
.ownsSelection
)
2080 releaseSelection(tPtr
);
2081 cursorToTextPosition(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2083 if (tPtr
->flags
.pointerGrabbed
) {
2084 tPtr
->flags
.pointerGrabbed
= False
;
2085 XUngrabPointer(dpy
, CurrentTime
);
2090 if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelDown
)
2091 WMScrollText(tPtr
, -16);
2092 else if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelUp
)
2093 WMScrollText(tPtr
, 16);
2097 tPtr
->flags
.buttonHeld
= False
;
2098 if (tPtr
->flags
.pointerGrabbed
) {
2099 tPtr
->flags
.pointerGrabbed
= False
;
2100 XUngrabPointer(dpy
, CurrentTime
);
2103 if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelDown
2104 || event
->xbutton
.button
== WINGsConfiguration
.mouseWheelUp
)
2107 if (event
->xbutton
.button
== Button2
) {
2111 if (!tPtr
->flags
.editable
) {
2116 if (!WMRequestSelection(tPtr
->view
, XA_PRIMARY
, XA_STRING
,
2117 event
->xbutton
.time
, pasteText
, NULL
)) {
2118 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
2121 if (0&&tPtr
->parser
) {
2122 /* parser is not yet well behaved to do this properly..*/
2123 (tPtr
->parser
) (tPtr
, (void *) text
);
2125 insertTextInteractively(tPtr
, text
, n
-1);
2128 } else tPtr
->flags
.waitingForSelection
= True
;
2139 handleEvents(XEvent
*event
, void *data
)
2141 Text
*tPtr
= (Text
*)data
;
2143 switch(event
->type
) {
2146 if (event
->xexpose
.count
!=0)
2150 if (!(W_VIEW(tPtr
->hS
))->flags
.realized
)
2151 WMRealizeWidget(tPtr
->hS
);
2152 if (!((W_VIEW(tPtr
->hS
))->flags
.mapped
))
2153 WMMapWidget(tPtr
->hS
);
2157 if (!(W_VIEW(tPtr
->vS
))->flags
.realized
)
2158 WMRealizeWidget(tPtr
->vS
);
2159 if (!((W_VIEW(tPtr
->vS
))->flags
.mapped
))
2160 WMMapWidget(tPtr
->vS
);
2164 if (!(W_VIEW(tPtr
->ruler
))->flags
.realized
)
2165 WMRealizeWidget(tPtr
->ruler
);
2167 if (!((W_VIEW(tPtr
->ruler
))->flags
.mapped
)
2168 && tPtr
->flags
.rulerShown
)
2169 WMMapWidget(tPtr
->ruler
);
2173 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2179 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))
2182 tPtr
->flags
.focused
= True
;
2184 if (tPtr
->flags
.editable
&& !tPtr
->timerID
) {
2185 tPtr
->timerID
= WMAddTimerHandler(12+0*CURSOR_BLINK_ON_DELAY
,
2193 tPtr
->flags
.focused
= False
;
2196 if (tPtr
->timerID
) {
2197 WMDeleteTimerHandler(tPtr
->timerID
);
2198 tPtr
->timerID
= NULL
;
2206 WMDestroyWidget(tPtr
->hS
);
2208 WMDestroyWidget(tPtr
->vS
);
2210 WMDestroyWidget(tPtr
->ruler
);
2212 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
2214 WMFreeBag(tPtr
->gfxItems
);
2217 WMDeleteTimerHandler(tPtr
->timerID
);
2219 WMReleaseFont(tPtr
->dFont
);
2220 WMReleaseColor(tPtr
->dColor
);
2221 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
, CurrentTime
);
2222 WMRemoveNotificationObserver(tPtr
);
2233 insertPlainText(WMText
*tPtr
, char *text
)
2245 mark
= strchr(start
, '\n');
2247 tb
= WMCreateTextBlockWithText(tPtr
,
2249 tPtr
->dColor
, True
, (int)(mark
-start
));
2252 if (start
&& strlen(start
)) {
2253 tb
= WMCreateTextBlockWithText(tPtr
, start
, tPtr
->dFont
,
2254 tPtr
->dColor
, False
, strlen(start
));
2259 if (tPtr
->flags
.prepend
)
2260 WMPrependTextBlock(tPtr
, tb
);
2262 WMAppendTextBlock(tPtr
, tb
);
2270 rulerMoveCallBack(WMWidget
*w
, void *self
)
2272 Text
*tPtr
= (Text
*)self
;
2275 if (W_CLASS(tPtr
) != WC_Text
)
2283 rulerReleaseCallBack(WMWidget
*w
, void *self
)
2285 Text
*tPtr
= (Text
*)self
;
2288 if (W_CLASS(tPtr
) != WC_Text
)
2291 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2298 draggingEntered(WMView
*self
, WMDraggingInfo
*info
)
2300 printf("draggingEntered\n");
2301 return WDOperationCopy
;
2306 draggingUpdated(WMView
*self
, WMDraggingInfo
*info
)
2308 printf("draggingUpdated\n");
2309 return WDOperationCopy
;
2314 draggingExited(WMView
*self
, WMDraggingInfo
*info
)
2316 printf("draggingExited\n");
2320 prepareForDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2322 printf("draggingExited\n");
2323 return;//"bll"; //"application/X-color";
2328 performDragOperation(WMView
*self
, WMDraggingInfo
*info
) //, WMData *data)
2330 char *colorName
= "Blue";// (char*)WMDataBytes(data);
2332 WMText
*tPtr
= (WMText
*)self
->self
;
2337 if (tPtr
->flags
.monoFont
)
2340 color
= WMCreateNamedColor(W_VIEW_SCREEN(self
), colorName
, True
);
2341 printf("color [%s] %p\n", colorName
, color
);
2343 WMSetTextSelectionColor(tPtr
, color
);
2344 WMReleaseColor(color
);
2351 concludeDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2353 printf("concludeDragOperation\n");
2357 static WMDragDestinationProcs _DragDestinationProcs
= {
2361 prepareForDragOperation
,
2362 performDragOperation
,
2363 concludeDragOperation
2368 releaseBagData(void *data
)
2376 getStream(WMText
*tPtr
, int sel
)
2378 TextBlock
*tb
= NULL
;
2380 unsigned long length
= 0, where
= 0;
2385 if (!(tb
= tPtr
->firstTextBlock
))
2388 /* this might be tricky to get right... not yet implemented */
2390 (tPtr
->writer
) (tPtr
, (void *) text
);
2395 /* first, how large a buffer would we want? */
2398 if (!tb
->graphic
|| (tb
->graphic
&& !tPtr
->flags
.monoFont
)) {
2401 if (!sel
|| (tb
->graphic
&& tb
->selected
)) {
2403 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
))
2406 length
+= 2; /* field markers 0xFA and size */
2407 } else if (sel
&& tb
->selected
) {
2408 length
+= (tb
->s_end
- tb
->s_begin
);
2409 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
))
2417 text
= wmalloc(length
+1); /* +1 for the end of string, let's be nice */
2418 tb
= tPtr
->firstTextBlock
;
2421 if (!tb
->graphic
|| (tb
->graphic
&& !tPtr
->flags
.monoFont
)) {
2424 if (!sel
|| (tb
->graphic
&& tb
->selected
)) {
2425 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
))
2426 text
[where
++] = '\n';
2428 text
[where
++] = 0xFA;
2429 text
[where
++] = tb
->used
;
2431 memcpy(&text
[where
], tb
->text
, tb
->used
);
2434 } else if (sel
&& tb
->selected
) {
2435 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
))
2436 text
[where
++] = '\n';
2437 memcpy(&text
[where
], &tb
->text
[tb
->s_begin
],
2438 tb
->s_end
- tb
->s_begin
);
2439 where
+= tb
->s_end
- tb
->s_begin
;
2453 getStreamIntoBag(WMText
*tPtr
, int sel
)
2455 char *stream
, *start
= NULL
, *fa
= NULL
;
2463 stream
= getStream(tPtr
, sel
);
2467 bag
= WMCreateBagWithDestructor(4, releaseBagData
);
2471 fa
= strchr(start
, 0xFA);
2473 unsigned char len
= *(fa
+1);
2476 data
= WMCreateDataWithBytes((void *)start
, (int)(fa
- start
));
2477 WMSetDataFormat(data
, 8);
2478 WMPutInBag(bag
, (void *) data
);
2481 data
= WMCreateDataWithBytes((void *)(fa
+2), len
);
2482 WMSetDataFormat(data
, 32);
2483 WMPutInBag(bag
, (void *) data
);
2484 start
= fa
+ len
+ 2;
2487 if (start
&& strlen(start
)) {
2488 data
= WMCreateDataWithBytes((void *)start
, strlen(start
));
2489 WMSetDataFormat(data
, 8);
2490 WMPutInBag(bag
, (void *) data
);
2502 WMCreateText(WMWidget
*parent
)
2504 Text
*tPtr
= wmalloc(sizeof(Text
));
2506 printf("could not create text widget\n");
2511 printf("sizeof:\n");
2512 printf(" TextBlock %d\n", sizeof(TextBlock
));
2513 printf(" Section %d\n", sizeof(Section
));
2514 printf(" WMRulerMargins %d\n", sizeof(WMRulerMargins
));
2515 printf(" char * %d\n", sizeof(char *));
2516 printf(" void * %d\n", sizeof(void *));
2517 printf(" short %d\n", sizeof(short));
2518 printf(" Text %d\n", sizeof(Text
));
2521 memset(tPtr
, 0, sizeof(Text
));
2522 tPtr
->widgetClass
= WC_Text
;
2523 tPtr
->view
= W_CreateView(W_VIEW(parent
));
2525 perror("could not create text's view\n");
2529 tPtr
->view
->self
= tPtr
;
2530 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->textCursor
;
2531 tPtr
->view
->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2532 W_ResizeView(tPtr
->view
, 250, 200);
2533 tPtr
->bgGC
= WMColorGC(tPtr
->view
->screen
->white
);
2534 tPtr
->fgGC
= WMColorGC(tPtr
->view
->screen
->black
);
2535 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->view
->screen
->white
);
2541 tPtr
->dFont
= WMRetainFont(tPtr
->view
->screen
->normalFont
);
2543 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
2545 tPtr
->view
->delegate
= &_TextViewDelegate
;
2548 tPtr
->timerID
= NULL
;
2551 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
2552 |EnterWindowMask
|LeaveWindowMask
|FocusChangeMask
,
2553 handleEvents
, tPtr
);
2555 WMCreateEventHandler(tPtr
->view
, ButtonReleaseMask
|ButtonPressMask
2556 |KeyReleaseMask
|KeyPressMask
|Button1MotionMask
,
2557 handleActionEvents
, tPtr
);
2559 WMAddNotificationObserver(ownershipObserver
, tPtr
, "_lostOwnership", tPtr
);
2562 WMSetViewDragDestinationProcs(tPtr
->view
, &_DragDestinationProcs
);
2564 char *types
[2] = {"application/X-color", NULL
};
2565 WMRegisterViewForDraggedTypes(tPtr
->view
, types
);
2569 WMAddNotificationObserver(fontChanged
, tPtr
,
2570 "WMFontPanelDidChangeNotification", tPtr
);
2572 tPtr
->firstTextBlock
= NULL
;
2573 tPtr
->lastTextBlock
= NULL
;
2574 tPtr
->currentTextBlock
= NULL
;
2577 tPtr
->gfxItems
= WMCreateBag(4);
2579 tPtr
->parser
= NULL
;
2580 tPtr
->writer
= NULL
;
2582 tPtr
->sel
.x
= tPtr
->sel
.y
= 2;
2583 tPtr
->sel
.w
= tPtr
->sel
.h
= 0;
2585 tPtr
->clicked
.x
= tPtr
->clicked
.y
= 2;
2587 tPtr
->visible
.x
= tPtr
->visible
.y
= 2;
2588 tPtr
->visible
.h
= tPtr
->view
->size
.height
;
2589 tPtr
->visible
.w
= tPtr
->view
->size
.width
- 4;
2591 tPtr
->cursor
.x
= -23;
2594 tPtr
->docHeight
= 0;
2595 tPtr
->dBulletPix
= WMCreatePixmapFromXPMData(tPtr
->view
->screen
,
2597 tPtr
->db
= (Pixmap
) NULL
;
2599 tPtr
->margins
= WMGetRulerMargins(NULL
);
2600 tPtr
->margins
->right
= tPtr
->visible
.w
;
2603 tPtr
->flags
.rulerShown
= False
;
2604 tPtr
->flags
.monoFont
= False
;
2605 tPtr
->flags
.focused
= False
;
2606 tPtr
->flags
.editable
= True
;
2607 tPtr
->flags
.ownsSelection
= False
;
2608 tPtr
->flags
.pointerGrabbed
= False
;
2609 tPtr
->flags
.buttonHeld
= False
;
2610 tPtr
->flags
.waitingForSelection
= False
;
2611 tPtr
->flags
.extendSelection
= False
;
2612 tPtr
->flags
.frozen
= False
;
2613 tPtr
->flags
.cursorShown
= True
;
2614 tPtr
->flags
.clickPos
= 1;
2615 tPtr
->flags
.horizOnDemand
= False
;
2616 tPtr
->flags
.needsRefresh
= False
;
2617 tPtr
->flags
.ignoreNewLine
= False
;
2618 tPtr
->flags
.laidOut
= False
;
2619 tPtr
->flags
.prepend
= False
;
2620 tPtr
->flags
.relief
= WRFlat
;
2621 tPtr
->flags
.alignment
= WALeft
;
2627 WMPrependTextStream(WMText
*tPtr
, char *text
)
2633 releaseSelection(tPtr
);
2635 tPtr
->flags
.prepend
= True
;
2636 if (text
&& tPtr
->parser
)
2637 (tPtr
->parser
) (tPtr
, (void *) text
);
2639 insertPlainText(tPtr
, text
);
2641 tPtr
->flags
.needsRefresh
= True
;
2646 WMAppendTextStream(WMText
*tPtr
, char *text
)
2652 releaseSelection(tPtr
);
2654 tPtr
->flags
.prepend
= False
;
2655 if (text
&& tPtr
->parser
)
2656 (tPtr
->parser
) (tPtr
, (void *) text
);
2658 insertPlainText(tPtr
, text
);
2660 tPtr
->flags
.needsRefresh
= True
;
2666 WMGetTextStream(WMText
*tPtr
)
2668 return getStream(tPtr
, 0);
2672 WMGetTextSelected(WMText
*tPtr
)
2674 return getStream(tPtr
, 1);
2678 WMGetTextStreamIntoBag(WMText
*tPtr
)
2680 return getStreamIntoBag(tPtr
, 0);
2684 WMGetTextSelectedIntoBag(WMText
*tPtr
)
2686 return getStreamIntoBag(tPtr
, 1);
2691 WMCreateTextBlockWithObject(WMText
*tPtr
, WMWidget
*w
,
2692 char *description
, WMColor
*color
,
2693 unsigned short first
, unsigned short reserved
)
2696 unsigned short length
;
2698 if (!w
|| !description
|| !color
)
2701 tb
= wmalloc(sizeof(TextBlock
));
2705 length
= strlen(description
);
2706 tb
->text
= (char *)wmalloc(length
);
2707 memset(tb
->text
, 0, length
);
2708 memcpy(tb
->text
, description
, length
);
2712 tb
->color
= WMRetainColor(color
);
2713 tb
->marginN
= newMargin(tPtr
, NULL
);
2719 tb
->underlined
= False
;
2720 tb
->selected
= False
;
2722 tb
->sections
= NULL
;
2732 WMCreateTextBlockWithPixmap(WMText
*tPtr
, WMPixmap
*p
,
2733 char *description
, WMColor
*color
,
2734 unsigned short first
, unsigned short reserved
)
2737 unsigned short length
;
2739 if (!p
|| !description
|| !color
)
2742 tb
= wmalloc(sizeof(TextBlock
));
2746 length
= strlen(description
);
2747 tb
->text
= (char *)wmalloc(length
);
2748 memset(tb
->text
, 0, length
);
2749 memcpy(tb
->text
, description
, length
);
2753 tb
->color
= WMRetainColor(color
);
2754 tb
->marginN
= newMargin(tPtr
, NULL
);
2760 tb
->underlined
= False
;
2761 tb
->selected
= False
;
2763 tb
->sections
= NULL
;
2772 WMCreateTextBlockWithText(WMText
*tPtr
, char *text
, WMFont
*font
, WMColor
*color
,
2773 unsigned short first
, unsigned short length
)
2777 if (!font
|| !color
)
2780 tb
= wmalloc(sizeof(TextBlock
));
2784 tb
->allocated
= reqBlockSize(length
);
2785 tb
->text
= (char *)wmalloc(tb
->allocated
);
2786 memset(tb
->text
, 0, tb
->allocated
);
2788 if (length
< 1|| !text
) { // || *text == '\n') {
2793 memcpy(tb
->text
, text
, length
);
2798 tb
->d
.font
= WMRetainFont(font
);
2799 tb
->color
= WMRetainColor(color
);
2800 tb
->marginN
= newMargin(tPtr
, NULL
);
2803 tb
->graphic
= False
;
2804 tb
->underlined
= False
;
2805 tb
->selected
= False
;
2807 tb
->sections
= NULL
;
2815 WMSetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int first
,
2816 unsigned int kanji
, unsigned int underlined
, int script
,
2817 WMRulerMargins
*margins
)
2819 TextBlock
*tb
= (TextBlock
*) vtb
;
2825 tb
->underlined
= underlined
;
2826 tb
->script
= script
;
2827 tb
->marginN
= newMargin(tPtr
, margins
);
2831 WMGetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int *first
,
2832 unsigned int *kanji
, unsigned int *underlined
, int *script
,
2833 WMRulerMargins
*margins
)
2835 TextBlock
*tb
= (TextBlock
*) vtb
;
2839 if (first
) *first
= tb
->first
;
2840 if (kanji
) *kanji
= tb
->kanji
;
2841 if (underlined
) *underlined
= tb
->underlined
;
2842 if (script
) *script
= tb
->script
;
2843 if (margins
) margins
= &tPtr
->margins
[tb
->marginN
];
2849 WMPrependTextBlock(WMText
*tPtr
, void *vtb
)
2851 TextBlock
*tb
= (TextBlock
*)vtb
;
2858 WMWidget
*w
= tb
->d
.widget
;
2859 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
2860 handleWidgetPress
, tb
);
2861 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
2862 (W_VIEW(w
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
2863 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2866 WMPutInBag(tPtr
->gfxItems
, (void *)tb
);
2868 } else tPtr
->tpos
= tb
->used
;
2870 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
2871 tb
->next
= tb
->prior
= NULL
;
2872 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
2873 = tPtr
->currentTextBlock
= tb
;
2877 tb
->next
= tPtr
->currentTextBlock
;
2878 tb
->prior
= tPtr
->currentTextBlock
->prior
;
2879 if (tPtr
->currentTextBlock
->prior
)
2880 tPtr
->currentTextBlock
->prior
->next
= tb
;
2882 tPtr
->currentTextBlock
->prior
= tb
;
2884 tPtr
->firstTextBlock
= tb
;
2886 tPtr
->currentTextBlock
= tb
;
2891 WMAppendTextBlock(WMText
*tPtr
, void *vtb
)
2893 TextBlock
*tb
= (TextBlock
*)vtb
;
2900 WMWidget
*w
= tb
->d
.widget
;
2901 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
2902 handleWidgetPress
, tb
);
2903 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
2904 (W_VIEW(w
))->attribs
.cursor
=
2905 tPtr
->view
->screen
->defaultCursor
;
2906 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2909 WMPutInBag(tPtr
->gfxItems
, (void *)tb
);
2911 } else tPtr
->tpos
= tb
->used
;
2913 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
2914 tb
->next
= tb
->prior
= NULL
;
2915 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
2916 = tPtr
->currentTextBlock
= tb
;
2920 tb
->next
= tPtr
->currentTextBlock
->next
;
2921 tb
->prior
= tPtr
->currentTextBlock
;
2922 if (tPtr
->currentTextBlock
->next
)
2923 tPtr
->currentTextBlock
->next
->prior
= tb
;
2925 tPtr
->currentTextBlock
->next
= tb
;
2928 tPtr
->lastTextBlock
= tb
;
2930 tPtr
->currentTextBlock
= tb
;
2934 WMRemoveTextBlock(WMText
*tPtr
)
2936 TextBlock
*tb
= NULL
;
2938 if (!tPtr
|| !tPtr
->firstTextBlock
|| !tPtr
->lastTextBlock
2939 || !tPtr
->currentTextBlock
) {
2940 printf("cannot remove non existent TextBlock!\b");
2944 tb
= tPtr
->currentTextBlock
;
2946 WMRemoveFromBag(tPtr
->gfxItems
, (void *)tb
);
2949 WMDeleteEventHandler(W_VIEW(tb
->d
.widget
), ButtonPressMask
,
2950 handleWidgetPress
, tb
);
2951 WMUnmapWidget(tb
->d
.widget
);
2955 if (tPtr
->currentTextBlock
== tPtr
->firstTextBlock
) {
2956 if (tPtr
->currentTextBlock
->next
)
2957 tPtr
->currentTextBlock
->next
->prior
= NULL
;
2959 tPtr
->firstTextBlock
= tPtr
->currentTextBlock
->next
;
2960 tPtr
->currentTextBlock
= tPtr
->firstTextBlock
;
2962 } else if (tPtr
->currentTextBlock
== tPtr
->lastTextBlock
) {
2963 tPtr
->currentTextBlock
->prior
->next
= NULL
;
2964 tPtr
->lastTextBlock
= tPtr
->currentTextBlock
->prior
;
2965 tPtr
->currentTextBlock
= tPtr
->lastTextBlock
;
2967 tPtr
->currentTextBlock
->prior
->next
= tPtr
->currentTextBlock
->next
;
2968 tPtr
->currentTextBlock
->next
->prior
= tPtr
->currentTextBlock
->prior
;
2969 tPtr
->currentTextBlock
= tPtr
->currentTextBlock
->next
;
2976 WMDestroyTextBlock(WMText
*tPtr
, void *vtb
)
2978 TextBlock
*tb
= (TextBlock
*)vtb
;
2984 /* naturally, there's a danger to destroying
2985 widgets whose action brings us here:
2986 ie. press a button to destroy it... need to
2987 find a safer way. till then... this stays commented out */
2988 //WMDestroyWidget(tb->d.widget);
2989 //wfree(tb->d.widget);
2990 tb
->d
.widget
= NULL
;
2992 WMReleasePixmap(tb
->d
.pixmap
);
2993 tb
->d
.pixmap
= NULL
;
2996 WMReleaseFont(tb
->d
.font
);
2999 WMReleaseColor(tb
->color
);
3000 if (tb
->sections
&& tb
->nsections
> 0)
3001 wfree(tb
->sections
);
3009 WMRefreshText(WMText
*tPtr
, int vpos
, int hpos
)
3011 if (!tPtr
|| vpos
<0 || hpos
<0)
3014 if (tPtr
->flags
.frozen
&& !tPtr
->flags
.needsRefresh
)
3017 if(tPtr
->flags
.monoFont
) {
3018 int j
, c
= WMGetBagItemCount(tPtr
->gfxItems
);
3021 /* make sure to unmap widgets no matter where they are */
3022 for(j
=0; j
<c
; j
++) {
3023 if ((tb
= (TextBlock
*) WMGetFromBag(tPtr
->gfxItems
, j
))) {
3024 if (tb
->object
&& ((W_VIEW(tb
->d
.widget
))->flags
.mapped
))
3025 WMUnmapWidget(tb
->d
.widget
);
3031 if (tPtr
->vpos
!= vpos
) {
3032 if (vpos
< 0 || tPtr
->docHeight
< tPtr
->visible
.h
) {
3034 } else if(tPtr
->docHeight
- vpos
> tPtr
->visible
.h
- tPtr
->visible
.y
) {
3037 tPtr
->vpos
= tPtr
->docHeight
- tPtr
->visible
.h
;
3041 if (tPtr
->hpos
!= hpos
) {
3042 if (hpos
< 0 || tPtr
->docWidth
< tPtr
->visible
.w
) {
3044 } else if(tPtr
->docWidth
- hpos
> tPtr
->visible
.w
- tPtr
->visible
.x
) {
3047 tPtr
->hpos
= tPtr
->docWidth
- tPtr
->visible
.w
;
3052 tPtr
->flags
.laidOut
= False
;
3053 layOutDocument(tPtr
);
3054 updateScrollers(tPtr
);
3056 tPtr
->flags
.needsRefresh
= False
;
3061 WMSetTextForegroundColor(WMText
*tPtr
, WMColor
*color
)
3067 tPtr
->fgGC
= WMColorGC(color
);
3069 tPtr
->fgGC
= WMColorGC(WMBlackColor(tPtr
->view
->screen
));
3071 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
3075 WMSetTextBackgroundColor(WMText
*tPtr
, WMColor
*color
)
3081 tPtr
->bgGC
= WMColorGC(color
);
3082 W_SetViewBackgroundColor(tPtr
->view
, color
);
3084 tPtr
->bgGC
= WMColorGC(WMWhiteColor(tPtr
->view
->screen
));
3085 W_SetViewBackgroundColor(tPtr
->view
,
3086 WMWhiteColor(tPtr
->view
->screen
));
3089 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
3093 WMSetTextRelief(WMText
*tPtr
, WMReliefType relief
)
3097 tPtr
->flags
.relief
= relief
;
3102 WMSetTextHasHorizontalScroller(WMText
*tPtr
, Bool shouldhave
)
3107 if (shouldhave
&& !tPtr
->hS
) {
3108 tPtr
->hS
= WMCreateScroller(tPtr
);
3109 (W_VIEW(tPtr
->hS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3110 (W_VIEW(tPtr
->hS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3111 WMSetScrollerArrowsPosition(tPtr
->hS
, WSAMinEnd
);
3112 WMSetScrollerAction(tPtr
->hS
, scrollersCallBack
, tPtr
);
3113 WMMapWidget(tPtr
->hS
);
3114 } else if (!shouldhave
&& tPtr
->hS
) {
3115 WMUnmapWidget(tPtr
->hS
);
3116 WMDestroyWidget(tPtr
->hS
);
3122 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3127 WMSetTextHasRuler(WMText
*tPtr
, Bool shouldhave
)
3132 if(shouldhave
&& !tPtr
->ruler
) {
3133 tPtr
->ruler
= WMCreateRuler(tPtr
);
3134 (W_VIEW(tPtr
->ruler
))->attribs
.cursor
=
3135 tPtr
->view
->screen
->defaultCursor
;
3136 (W_VIEW(tPtr
->ruler
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3137 WMSetRulerReleaseAction(tPtr
->ruler
, rulerReleaseCallBack
, tPtr
);
3138 WMSetRulerMoveAction(tPtr
->ruler
, rulerMoveCallBack
, tPtr
);
3139 } else if(!shouldhave
&& tPtr
->ruler
) {
3140 WMShowTextRuler(tPtr
, False
);
3141 WMDestroyWidget(tPtr
->ruler
);
3144 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3148 WMShowTextRuler(WMText
*tPtr
, Bool show
)
3155 if(tPtr
->flags
.monoFont
)
3158 tPtr
->flags
.rulerShown
= show
;
3160 WMMapWidget(tPtr
->ruler
);
3162 WMUnmapWidget(tPtr
->ruler
);
3165 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3169 WMGetTextRulerShown(WMText
*tPtr
)
3177 return tPtr
->flags
.rulerShown
;
3182 WMSetTextHasVerticalScroller(WMText
*tPtr
, Bool shouldhave
)
3187 if (shouldhave
&& !tPtr
->vS
) {
3188 tPtr
->vS
= WMCreateScroller(tPtr
);
3189 (W_VIEW(tPtr
->vS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3190 (W_VIEW(tPtr
->vS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3191 WMSetScrollerArrowsPosition(tPtr
->vS
, WSAMaxEnd
);
3192 WMSetScrollerAction(tPtr
->vS
, scrollersCallBack
, tPtr
);
3193 WMMapWidget(tPtr
->vS
);
3194 } else if (!shouldhave
&& tPtr
->vS
) {
3195 WMUnmapWidget(tPtr
->vS
);
3196 WMDestroyWidget(tPtr
->vS
);
3202 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3208 WMScrollText(WMText
*tPtr
, int amount
)
3213 if (amount
== 0 || !tPtr
->view
->flags
.realized
)
3217 if (tPtr
->vpos
> 0) {
3218 if (tPtr
->vpos
> abs(amount
)) tPtr
->vpos
+= amount
;
3222 int limit
= tPtr
->docHeight
- tPtr
->visible
.h
;
3223 if (tPtr
->vpos
< limit
) {
3224 if (tPtr
->vpos
< limit
-amount
) tPtr
->vpos
+= amount
;
3225 else tPtr
->vpos
= limit
;
3229 if (scroll
&& tPtr
->vpos
!= tPtr
->prevVpos
) {
3230 updateScrollers(tPtr
);
3233 tPtr
->prevVpos
= tPtr
->vpos
;
3238 WMPageText(WMText
*tPtr
, Bool direction
)
3240 if (!tPtr
) return False
;
3241 if (!tPtr
->view
->flags
.realized
) return False
;
3243 return WMScrollText(tPtr
, direction
?tPtr
->visible
.h
:-tPtr
->visible
.h
);
3247 WMSetTextEditable(WMText
*tPtr
, Bool editable
)
3251 tPtr
->flags
.editable
= editable
;
3255 WMGetTextEditable(WMText
*tPtr
)
3259 return tPtr
->flags
.editable
;
3263 WMSetTextIgnoresNewline(WMText
*tPtr
, Bool ignore
)
3267 tPtr
->flags
.ignoreNewLine
= ignore
;
3271 WMGetTextIgnoresNewline(WMText
*tPtr
)
3275 return tPtr
->flags
.ignoreNewLine
;
3279 WMSetTextUsesMonoFont(WMText
*tPtr
, Bool mono
)
3283 if (mono
&& tPtr
->flags
.rulerShown
)
3284 WMShowTextRuler(tPtr
, False
);
3286 tPtr
->flags
.monoFont
= mono
;
3287 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
3291 WMGetTextUsesMonoFont(WMText
*tPtr
)
3295 return tPtr
->flags
.monoFont
;
3300 WMSetTextDefaultFont(WMText
*tPtr
, WMFont
*font
)
3305 WMReleaseFont(tPtr
->dFont
);
3309 tPtr
->dFont
= WMRetainFont(tPtr
->view
->screen
->normalFont
);
3313 WMGetTextDefaultFont(WMText
*tPtr
)
3322 WMSetTextAlignment(WMText
*tPtr
, WMAlignment alignment
)
3326 tPtr
->flags
.alignment
= alignment
;
3327 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
3331 WMSetTextParser(WMText
*tPtr
, WMAction
*parser
)
3335 tPtr
->parser
= parser
;
3339 WMSetTextWriter(WMText
*tPtr
, WMAction
*writer
)
3343 tPtr
->writer
= writer
;
3347 WMGetTextInsertType(WMText
*tPtr
)
3351 return tPtr
->flags
.prepend
;
3356 WMSetTextSelectionColor(WMText
*tPtr
, WMColor
*color
)
3358 if (!tPtr
|| !color
)
3361 setSelectionProperty(tPtr
, NULL
, color
);
3367 WMSetTextSelectionFont(WMText
*tPtr
, WMFont
*font
)
3372 setSelectionProperty(tPtr
, font
, NULL
);
3377 WMFreezeText(WMText
*tPtr
)
3382 tPtr
->flags
.frozen
= True
;
3386 WMThawText(WMText
*tPtr
)
3391 tPtr
->flags
.frozen
= False
;
3396 WMFindInTextStream(WMText
*tPtr
, char *needle
)
3398 char *haystack
= NULL
;
3401 if (!tPtr
|| !needle
)
3404 if ( !(haystack
= "WMGetTextStream(tPtr)"))
3407 result
= (Bool
) strstr(haystack
, needle
);
3416 typedef struct _currentFormat
{
3421 WMRulerMargins margins
;
3422 //WMBag *aligns; // for tables...
3423 /* the following are "nested"
3424 i.e.: <b><b><i></b><b></i>
3425 1 2 1 1 2 0 get it? */
3433 WMAlignment align
:2;
3434 short ul
:3; /* how "nested"... up to 8 levels deep */
3435 short comment
:1; /* ignore text till --> */
3443 getArg(char *t
, short type
, void *arg
)
3446 while(*(++t
) && !d
) {
3448 if(*t
>='0' && *t
<='9') {
3449 sscanf(t
, "%d", arg
);
3450 while(*t
&& (*t
<'0' || *t
>'9'))
3459 void parseToken(WMText
*tPtr
, char *token
, short tk
)
3461 short mode
=0; /* 0 starts, 1 closes */
3463 int prepend
= WMGetTextInsertType(tPtr
);
3465 while(*token
&& isspace(*(token
))) token
++;
3469 while(isspace(*(token
))) token
++;
3472 if(strlen(token
)==1) {
3473 /* nice and fast for small tokens... no need for too much brain
3475 switch(TOLOWER(*token
)) {
3478 cfmt
.cfont
= WMGetFontItalic(scr
, cfmt
.cfont
);
3479 WMPutInBag(cfmt
.fonts
, (void *)cfmt
.cfont
);
3480 } else { /*dun wanna remove the baseFont eh? */
3481 int count
= WMGetBagItemCount(cfmt
.fonts
);
3483 WMDeleteFromBag(cfmt
.fonts
, count
-1);
3484 cfmt
.cfont
= (WMFont
*)WMGetFromBag(cfmt
.fonts
,
3485 WMGetBagItemCount(cfmt
.fonts
)-1);
3489 cfmt
.cfont
= WMGetFontBold(scr
, cfmt
.cfont
);
3490 WMPutInBag(cfmt
.fonts
, (void *)cfmt
.cfont
);
3491 } else { /*dun wanna remove the baseFont eh? */
3492 int count
= WMGetBagItemCount(cfmt
.fonts
);
3494 WMDeleteFromBag(cfmt
.fonts
, count
-1);
3495 cfmt
.cfont
= (WMFont
*)WMGetFromBag(cfmt
.fonts
,
3496 WMGetBagItemCount(cfmt
.fonts
)-1);
3500 tb
= WMCreateTextBlockWithText(NULL
, cfmt
.cfont
,
3501 cfmt
.ccolor
, cfmt
.first
, 0);
3502 WMSetTextBlockProperties(tb
, cfmt
.first
, False
, (cfmt
.u
?1:0), 0, cfmt
.margins
);
3503 //WMAppendTextBlock(tPtr, tb);
3506 case 'u': cfmt
.u
= !mode
; break;
3508 } else { /* the <HTML> tag is, as far as I'm concerned, useless */
3509 if(mystrcasecmp(token
, "br")) {
3512 else if(mystrcasecmp(token
, "ul")) {
3514 if(cfmt
.ul
>1) cfmt
.ul
--;
3517 cfmt
.bmargin
= cfmt
.ul
*30;
3518 cfmt
.fmargin
= cfmt
.bmargin
-10;
3519 } else cfmt
.fmargin
= cfmt
.bmargin
= 0;
3520 } else if(mystrcasecmp(token
, "li")) {
3522 //change margins... create a new margin....
3523 //(cfmt.fmargin, cfmt.bmargin,
3524 } else if(mystrcasecmp(token
, "align"))
3526 else if(mystrcasecmp(token
, "img")) {
3531 while(isspace(*(token
))) token
++;
3533 switch(TOLOWER(*token
)) {
3535 if(TOLOWER(*(1+token
)) == 'r' && TOLOWER(*(2+token
)) == 'c') {
3536 mark
= strchr(token
, '=');
3538 char img
[256], *iptr
;
3541 sscanf(token
, "%s", img
);
3543 if(*img
== '\"') { img
[strlen(img
)-1] = 0; iptr
++;}
3544 pixmap
= WMCreatePixmapFromFile(scr
, iptr
);
3546 tb
= WMCreateTextBlockWithPixmap(pixmap
,
3547 iptr
, cfmt
.ccolor
, cfmt
.first
, 0);
3548 WMSetTextBlockProperties(tb
, cfmt
.first
,
3549 False
, (cfmt
.u
?1:0), 0, cfmt
.margins
);
3550 WMAppendTextBlock(tPtr
, tb
);
3553 //printf("[%s]\n", iptr);
3554 } } break; } } while(*(token
++));
3556 } else if(mystrcasecmp(token
, "font")) {
3559 cfmt
.cfont
= (WMFont
*)WMGetFromBag(cfmt
.fonts
,
3560 WMGetBagItemCount(cfmt
.fonts
)-1);
3562 (WMColor
*)WMGetFromBag(cfmt
.colors
,
3563 WMGetBagItemCount(cfmt
.colors
)-1),
3566 else if(mystrcasecmp(token
, "center")) {
3568 if(mode
) cfmt
.align
= WALeft
;
3569 else cfmt
.align
= WACenter
;
3578 //printf("parse token (%s)[%s]\n", mode?"close":"open", token);
3581 //while(*token && !isspace(*(token))) token++;
3582 //printf("A:%d a:%d z%d Z%d\n", '1', 'a', 'Z', 'z');
3585 if(c
>=65 && c
<=122) { major
[i
++] = c
;
3586 } else if(c
==' ' || c
=='='){ major
[i
] = 0; i
=0; mm
=1;
3587 printf("\nmajor: [%s]", major
);}
3591 } else { minor
[i
] = 0; i
=0; printf(" minor: [%s] ", minor
);}
3593 }while((c
= *(++token
)));
3597 //printf("parse token (%s)[%s]\n", mode?"close":"open", token);
3600 void HTMLParser(WMWidget
*w
, void *clientData
)
3602 static short init
=1; /* have we been here at least once before? */
3603 char *stream
= (char *) clientData
;
3604 WMText
*tPtr
= (WMText
*)w
;
3607 char token
[MAX_TOKEN_SIZE
+1];
3608 char text
[MAX_TEXT_SIZE
+1];
3610 short tk
=0, textlen
=0;
3613 if(!tPtr
|| !stream
)
3616 cfmt
.type
= WMGetTextInsertType(tPtr
);
3618 cfmt
.fonts
= WMCreateBag(4); /* there sould always be at least 1 font... */
3619 cfmt
.cfont
= WMGetTextDefaultFont(tPtr
);
3620 WMPutInBag(cfmt
.fonts
, (void *)cfmt
.cfont
);
3621 cfmt
.colors
= WMCreateBag(4);
3622 cfmt
.ccolor
= WMBlackColor(scr
);
3623 WMPutInBag(cfmt
.colors
, (void *)cfmt
.ccolor
);
3624 cfmt
.i
= cfmt
.b
= cfmt
.u
= cfmt
.ul
= 0;
3625 cfmt
.align
= WALeft
;
3626 cfmt
.fmargin
= cfmt
.bmargin
= 0;
3631 if(strlen(stream
) == 1 && stream
[0] == '\n') {
3632 /* sometimes if the text entered is a single char AND is a newline,
3633 the user prolly typed it */
3634 cfmt
.para
= (cfmt
.actions
.createParagraph
) (cfmt
.fmargin
, cfmt
.bmargin
,
3635 WMWidgetWidth(tPtr
)-30, NULL
, 0, cfmt
.align
);
3636 (cfmt
.actions
.insertParagraph
) (tPtr
, cfmt
.para
, cfmt
.type
);
3645 while( (c
=*(stream
++))) {
3647 if(c
== '\n' || c
=='\t')
3648 //c = ' '; //continue;
3656 if(c
== '<' && !mode
) {
3660 tb
= WMCreateTextBlockWithText(text
, cfmt
.cfont
,
3661 cfmt
.ccolor
, cfmt
.first
, textlen
);
3662 WMSetTextBlockProperties(tb
, cfmt
.first
, False
, (cfmt
.u
?1:0), 0, cfmt
.margins
);
3663 WMAppendTextBlock(tPtr
, tb
);
3665 //printf("%s\n", text);
3668 } else if(c
== '>' && mode
) {
3670 if(tk
>0) parseToken(tPtr
, token
, tk
);
3675 if(tk
< MAX_TOKEN_SIZE
) token
[tk
++] = c
;
3676 } else if(textlen
< MAX_TEXT_SIZE
) text
[textlen
++] = c
;
3680 if(tk
>0) { token
[tk
] = 0; parseToken(tPtr
, token
, tk
);}
3683 //printf("%s\n", text);
3684 tb
= WMCreateTextBlockWithText(text
,
3685 (WMFont
*)WMGetFromBag(cfmt
.fonts
,
3686 WMGetBagItemCount(cfmt
.fonts
)-1),
3687 (WMColor
*)WMGetFromBag(cfmt
.colors
,
3688 WMGetBagItemCount(cfmt
.colors
)-1),
3689 cfmt
.first
, textlen
);
3690 WMSetTextBlockProperties(tb
, cfmt
.first
, False
, (cfmt
.u
?1:0), 0, cfmt
.margins
);
3691 WMAppendTextBlock(tPtr
, tb
);