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>
28 WMFont
* WMGetFontPlain(WMScreen
*scrPtr
, WMFont
*font
);
29 WMFont
* WMGetFontBold(WMScreen
*scrPtr
, WMFont
*font
);
30 WMFont
* WMGetFontItalic(WMScreen
*scrPtr
, WMFont
*font
);
31 WMFont
* WMGetFontOfSize(WMScreen
*scrPtr
, WMFont
*font
, int size
);
35 * - FIX html parser: 1. <b>foo</i> should STILL BE BOLD!
36 * - 2. " foo > bar " should not confuse it.
37 * - change Bag stuffs to WMArray
38 * - assess danger of destroying widgets whose actions link to other pages
39 * - integrate WMGetFont* functions into WINGs proper (fontpanel)?
40 * - change cursor shape around pixmaps
41 * - redo blink code to reduce paint event... use pixmap buffer...
42 * - add paragraph support (full) and '\n' code in getStream..
43 * - use currentTextBlock and neighbours for fast paint and layout
44 * - replace copious uses of Refreshtext with appropriate layOut()...
45 * - WMFindInTextStream should also highlight found text...
46 * - add full support for Horizontal Scroll
50 /* a Section is a section of a TextBlock that describes what parts
51 of a TextBlock has been laid out on which "line"...
52 o this greatly aids redraw, scroll and selection.
53 o this is created during layoutLine, but may be later modified.
54 o there may be many Sections per TextBlock, hence the array */
56 unsigned int x
, y
; /* where to draw it from */
57 unsigned short w
, h
; /* its width and height */
58 unsigned short begin
; /* where the layout begins */
59 unsigned short end
; /* where it ends */
60 unsigned short last
:1; /* is it the last section on a "line"? */
61 unsigned int _y
:31; /* the "line" it and other textblocks are on */
65 /* a TextBlock is a doubly-linked list of TextBlocks containing:
66 o text for the block, color and font
67 o or a pointer to the pixmap
68 o OR a pointer to the widget and the (text) description for its graphic
71 typedef struct _TextBlock
{
72 struct _TextBlock
*next
; /* next text block in linked list */
73 struct _TextBlock
*prior
; /* prior text block in linked list */
75 char *text
; /* pointer to text (could be kanji) */
76 /* or to the object's description */
78 WMFont
*font
; /* the font */
79 WMWidget
*widget
; /* the embedded widget */
80 WMPixmap
*pixmap
; /* the pixmap */
81 } d
; /* description */
83 unsigned short used
; /* number of chars in this block */
84 unsigned short allocated
; /* size of allocation (in chars) */
85 WMColor
*color
; /* the color */
87 Section
*sections
; /* the region for layouts (a growable array) */
88 /* an _array_! of size _nsections_ */
90 unsigned short s_begin
; /* where the selection begins */
91 unsigned short s_end
; /* where it ends */
93 unsigned int first
:1; /* first TextBlock in paragraph */
94 unsigned int blank
:1; /* ie. blank paragraph */
95 unsigned int kanji
:1; /* is of 16-bit characters or not */
96 unsigned int graphic
:1; /* graphic or text: text=0 */
97 unsigned int object
:1; /* embedded object or pixmap */
98 unsigned int underlined
:1; /* underlined or not */
99 unsigned int selected
:1; /* selected or not */
100 unsigned int nsections
:8; /* over how many "lines" a TextBlock wraps */
101 int script
:8; /* script in points: negative for subscript */
102 unsigned int marginN
:8; /* which of the margins in the tPtr to use */
103 unsigned int RESERVED
:9;
107 /* somehow visible.h beats the hell outta visible.size.height :-) */
116 typedef struct W_Text
{
117 W_Class widgetClass
; /* the class number of this widget */
118 W_View
*view
; /* the view referring to this instance */
120 WMRuler
*ruler
; /* the ruler widget to manipulate paragraphs */
122 WMScroller
*vS
; /* the vertical scroller */
123 unsigned int vpos
; /* the current vertical position */
124 unsigned int prevVpos
; /* the previous vertical position */
126 WMScroller
*hS
; /* the horizontal scroller */
127 unsigned int hpos
; /* the current horizontal position */
128 unsigned int prevHpos
; /* the previous horizontal position */
130 WMFont
*dFont
; /* the default font */
131 WMColor
*dColor
; /* the default color */
132 WMPixmap
*dBulletPix
; /* the default pixmap for bullets */
134 GC bgGC
; /* the background GC to draw with */
135 GC fgGC
; /* the foreground GC to draw with */
136 Pixmap db
; /* the buffer on which to draw */
138 myRect visible
; /* the actual rectangle that can be drawn into */
139 myRect cursor
; /* the position and (height) of cursor */
140 myRect sel
; /* the selection rectangle */
142 WMPoint clicked
; /* where in the _document_ was clicked */
144 unsigned short tpos
; /* the position in the currentTextBlock */
145 unsigned short docWidth
; /* the width of the entire document */
146 unsigned int docHeight
; /* the height of the entire document */
148 TextBlock
*firstTextBlock
;
149 TextBlock
*lastTextBlock
;
150 TextBlock
*currentTextBlock
;
152 WMBag
*gfxItems
; /* a nice bag containing graphic items */
155 WMHandlerID timerID
; /* for nice twinky-winky */
160 WMTextDelegate
*delegate
;
162 WMRulerMargins
*margins
; /* an array of margins */
164 unsigned int nMargins
:8; /* the total number of margins in use */
166 unsigned int monoFont
:1; /* whether to ignore formats */
167 unsigned int focused
:1; /* whether this instance has input focus */
168 unsigned int editable
:1; /* "silly user, you can't edit me" */
169 unsigned int ownsSelection
:1; /* "I ownz the current selection!" */
170 unsigned int pointerGrabbed
:1;/* "heh, gib me pointer" */
171 unsigned int buttonHeld
:1; /* the user is holding down the button */
172 unsigned int extendSelection
:1; /* shift-drag to select more regions */
174 unsigned int rulerShown
:1; /* whether the ruler is shown or not */
175 unsigned int frozen
:1; /* whether screen updates are to be made */
176 unsigned int cursorShown
:1; /* whether to show the cursor */
177 unsigned int clickPos
:1; /* clicked before=0 or after=1 a graphic: */
178 /* (within counts as after too) */
180 unsigned int horizOnDemand
:1;/* if a large image should appear*/
181 unsigned int needsRefresh
:1; /* in case of Append/Deletes */
182 unsigned int ignoreNewLine
:1;/* turn it into a ' ' in streams > 1 */
183 unsigned int laidOut
:1; /* have the TextBlocks all been laid out */
184 unsigned int waitingForSelection
:1; /* I don't wanna wait in vain... */
185 unsigned int prepend
:1; /* prepend=1, append=0 (for parsers) */
186 unsigned int parsingHTML
:1; /* how to interpret a stream of text */
187 WMAlignment alignment
:2; /* the alignment for text */
188 WMReliefType relief
:3; /* the relief to display with */
189 unsigned int RESERVED
:2;
194 #define NOTIFY(T,C,N,A) { WMNotification *notif = WMCreateNotification(N,T,A);\
195 if ((T)->delegate && (T)->delegate->C)\
196 (*(T)->delegate->C)((T)->delegate,notif);\
197 WMPostNotification(notif);\
198 WMReleaseNotification(notif);}
203 * A hack to speed up caseless_equal. Thanks to Quincey Koziol for
204 * developing it for the "chimera" folks so I could use it 7 years later ;-)
205 * Constraint: nothing but '\0' may map to 0
207 static unsigned char map_table
[256] = {
208 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,
209 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
210 52,53,54,55,56,57,58,59,60,61,62,63,64,97,98,99,100,101,102,103,104,105,
211 106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,91,
212 92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,
213 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,
214 130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,
215 148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,
216 166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,
217 184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,
218 202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,
219 220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,
220 238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255};
222 void HTMLParser(Text
*tPtr
, char *stream
);
223 #define MAX_TOKEN_SIZE 255
224 #define MAX_TEXT_SIZE 1023
226 #define TOLOWER(x) (map_table[(int)x])
228 #define ISALNUM(x) ( ((x>='0') && (x<='9')) \
229 || ((x>='a') && (x<='z')) || ((x>='A') && x<='Z'))
232 #define CURSOR_BLINK_ON_DELAY 600
233 #define CURSOR_BLINK_OFF_DELAY 400
236 static char *default_bullet
[] = {
238 " c None s None", ". c black",
239 "X c white", "o c #808080",
248 handleEvents(XEvent
*event
, void *data
);
252 getMarginNumber(Text
*tPtr
, WMRulerMargins
*margins
)
256 for(i
=0; i
< tPtr
->nMargins
; i
++) {
258 if(WMIsMarginEqualToMargin(&tPtr
->margins
[i
], margins
))
268 newMargin(Text
*tPtr
, WMRulerMargins
*margins
)
273 tPtr
->margins
[0].retainCount
++;
277 n
= getMarginNumber(tPtr
, margins
);
281 tPtr
->margins
= wrealloc(tPtr
->margins
,
282 (++tPtr
->nMargins
)*sizeof(WMRulerMargins
));
284 n
= tPtr
->nMargins
-1;
285 tPtr
->margins
[n
].left
= margins
->left
;
286 tPtr
->margins
[n
].first
= margins
->first
;
287 tPtr
->margins
[n
].body
= margins
->body
;
288 tPtr
->margins
[n
].right
= margins
->right
;
290 tPtr
->margins
[n
].retainCount
= 1;
292 tPtr
->margins
[n
].retainCount
++;
299 sectionWasSelected(Text
*tPtr
, TextBlock
*tb
, XRectangle
*rect
, int s
)
301 unsigned short i
, w
, lw
, selected
= False
, extend
= False
;
305 /* if selection rectangle completely encloses the section */
306 if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
307 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
308 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
310 sel
.w
= tPtr
->visible
.w
;
311 selected
= extend
= True
;
313 /* or if it starts on a line and then goes further down */
314 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
315 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
316 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
317 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
318 >= tPtr
->visible
.y
+ tPtr
->sel
.y
) ) {
319 sel
.x
= WMAX(tPtr
->sel
.x
, tPtr
->clicked
.x
);
320 sel
.w
= tPtr
->visible
.w
;
321 selected
= extend
= True
;
323 /* or if it begins before a line, but ends on it */
324 } else if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
325 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
326 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
327 && (tb
->sections
[s
]._y
328 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
330 if (1||tPtr
->sel
.x
+ tPtr
->sel
.w
> tPtr
->clicked
.x
)
331 sel
.w
= tPtr
->sel
.x
+ tPtr
->sel
.w
;
338 /* or if the selection rectangle lies entirely within a line */
339 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
340 && (tPtr
->sel
.w
>= 2)
341 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
342 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
351 /* if not within (modified) selection rectangle */
352 if ( tb
->sections
[s
].x
> sel
.x
+ sel
.w
353 || tb
->sections
[s
].x
+ tb
->sections
[s
].w
< sel
.x
)
357 if ( tb
->sections
[s
].x
+ tb
->sections
[s
].w
<= sel
.x
+ sel
.w
358 && tb
->sections
[s
].x
>= sel
.x
) {
359 rect
->width
= tb
->sections
[s
].w
;
360 rect
->x
= tb
->sections
[s
].x
;
365 i
= tb
->sections
[s
].begin
;
368 if (0&& tb
->sections
[s
].x
>= sel
.x
) {
369 tb
->s_begin
= tb
->sections
[s
].begin
;
373 while (++i
<= tb
->sections
[s
].end
) {
375 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
378 if (lw
+ tb
->sections
[s
].x
>= sel
.x
379 || i
== tb
->sections
[s
].end
) {
382 tb
->s_begin
= (tb
->selected
? WMIN(tb
->s_begin
, i
) : i
);
387 if (i
> tb
->sections
[s
].end
) {
388 printf("WasSelected: (i > tb->sections[s].end) \n");
392 _selEnd
: rect
->x
= tb
->sections
[s
].x
+ lw
;
394 while(++i
<= tb
->sections
[s
].end
) {
396 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
399 if (lw
+ rect
->x
>= sel
.x
+ sel
.w
400 || i
== tb
->sections
[s
].end
) {
402 if (i
!= tb
->sections
[s
].end
) {
408 if (tb
->sections
[s
].last
&& sel
.x
+ sel
.w
409 >= tb
->sections
[s
].x
+ tb
->sections
[s
].w
411 rect
->width
+= (tPtr
->visible
.w
- rect
->x
- lw
);
414 tb
->s_end
= (tb
->selected
? WMAX(tb
->s_end
, i
) : i
);
420 rect
->y
= tb
->sections
[s
]._y
- tPtr
->vpos
;
421 rect
->height
= tb
->sections
[s
].h
;
422 if(tb
->graphic
) { printf("graphic s%d h%d\n", s
,tb
->sections
[s
].h
);}
429 setSelectionProperty(WMText
*tPtr
, WMFont
*font
, WMColor
*color
)
434 if((font
&& color
) || (!font
&& !color
))
441 tb
= tPtr
->firstTextBlock
;
442 if (!tb
|| !tPtr
->flags
.ownsSelection
)
449 if ( (tb
->s_end
- tb
->s_begin
== tb
->used
) || tb
->graphic
) {
453 WMReleaseFont(tb
->d
.font
);
454 tb
->d
.font
= WMRetainFont(font
);
457 WMReleaseColor(tb
->color
);
458 tb
->color
= WMRetainColor(color
);
461 } else if (tb
->s_end
<= tb
->used
) {
465 TextBlock
*ntb
= (TextBlock
*)
466 WMCreateTextBlockWithText(tPtr
,
467 &(tb
->text
[tb
->s_begin
]),
468 (isFont
?font
:tb
->d
.font
),
469 (isFont
?tb
->color
:color
),
470 False
, (tb
->s_end
- tb
->s_begin
));
473 ntb
->selected
= True
;
475 ntb
->s_end
= ntb
->used
;
476 WMAppendTextBlock(tPtr
, ntb
);
481 if (tb
->used
> tb
->s_end
) {
483 WMCreateTextBlockWithText(tPtr
,
484 &(tb
->text
[tb
->s_end
]),
485 (isFont
?font
:tb
->d
.font
),
486 (isFont
?tb
->color
:color
),
487 False
, tb
->used
- tb
->s_end
);
490 ntb
->selected
= True
;
492 ntb
->s_end
= ntb
->used
;
493 WMAppendTextBlock(tPtr
, ntb
);
502 tb
= otb
->next
->next
;
504 tb
->used
= tb
->s_end
= tb
->s_begin
;
511 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
516 removeSelection(Text
*tPtr
)
518 TextBlock
*tb
= NULL
;
520 if (!(tb
= tPtr
->firstTextBlock
))
526 if ( (tb
->s_end
- tb
->s_begin
== tb
->used
) || tb
->graphic
) {
527 tPtr
->currentTextBlock
= tb
;
528 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
529 tb
= tPtr
->currentTextBlock
;
534 } else if (tb
->s_end
<= tb
->used
) {
535 memmove(&(tb
->text
[tb
->s_begin
]),
536 &(tb
->text
[tb
->s_end
]), tb
->used
- tb
->s_end
);
537 tb
->used
-= (tb
->s_end
- tb
->s_begin
);
538 tb
->selected
= False
;
539 tPtr
->tpos
= tb
->s_begin
;
550 paintText(Text
*tPtr
)
552 TextBlock
*tb
= tPtr
->firstTextBlock
;
556 int len
, y
, c
, s
, done
=False
;
558 WMScreen
*scr
= tPtr
->view
->screen
;
559 Display
*dpy
= tPtr
->view
->screen
->display
;
560 Window win
= tPtr
->view
->window
;
562 if (!tPtr
->view
->flags
.realized
|| !tPtr
->db
|| tPtr
->flags
.frozen
)
565 XFillRectangle(dpy
, tPtr
->db
, tPtr
->bgGC
,
566 0, 0, tPtr
->visible
.w
, tPtr
->visible
.h
);
568 tb
= tPtr
->firstTextBlock
;
573 if (tPtr
->flags
.ownsSelection
)
574 greyGC
= WMColorGC(WMGrayColor(scr
));
578 while (!done
&& tb
) {
585 tb
->selected
= False
;
587 for(s
=0; s
<tb
->nsections
&& !done
; s
++) {
589 if (tb
->sections
[s
]._y
> tPtr
->vpos
+ tPtr
->visible
.h
) {
594 if ( tb
->sections
[s
].y
+ tb
->sections
[s
].h
< tPtr
->vpos
)
597 if (tPtr
->flags
.monoFont
) {
602 gc
= WMColorGC(tb
->color
);
605 if (tPtr
->flags
.ownsSelection
) {
608 if ( sectionWasSelected(tPtr
, tb
, &rect
, s
)) {
610 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
611 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
615 prev_y
= tb
->sections
[s
]._y
;
617 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
618 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
619 y
= tb
->sections
[s
].y
- tPtr
->vpos
;
620 WMDrawString(scr
, tPtr
->db
, gc
, font
,
621 tb
->sections
[s
].x
- tPtr
->hpos
, y
, text
, len
);
623 if (tb
->underlined
) {
624 XDrawLine(dpy
, tPtr
->db
, gc
,
625 tb
->sections
[s
].x
- tPtr
->hpos
,
627 tb
->sections
[s
].x
+ tb
->sections
[s
].w
- tPtr
->hpos
,
633 tb
= (!done
? tb
->next
: NULL
);
637 c
= WMGetBagItemCount(tPtr
->gfxItems
);
638 if (c
> 0 && !tPtr
->flags
.monoFont
) {
642 tb
= (TextBlock
*) WMGetFromBag(tPtr
->gfxItems
, j
);
643 if (tb
->sections
[0]._y
+ tb
->sections
[0].h
<= tPtr
->vpos
644 || tb
->sections
[0]._y
>= tPtr
->vpos
+ tPtr
->visible
.h
) {
647 if ((W_VIEW(tb
->d
.widget
))->flags
.mapped
) {
648 WMUnmapWidget(tb
->d
.widget
);
653 if (!(W_VIEW(tb
->d
.widget
))->flags
.mapped
) {
654 if (!(W_VIEW(tb
->d
.widget
))->flags
.realized
)
655 WMRealizeWidget(tb
->d
.widget
);
656 WMMapWidget(tb
->d
.widget
);
657 WMLowerWidget(tb
->d
.widget
);
661 if (tPtr
->flags
.ownsSelection
) {
664 if ( sectionWasSelected(tPtr
, tb
, &rect
, s
)) {
666 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
667 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
672 WMMoveWidget(tb
->d
.widget
,
673 tb
->sections
[0].x
- tPtr
->hpos
,
674 tb
->sections
[0].y
- tPtr
->vpos
);
675 h
= WMWidgetHeight(tb
->d
.widget
) + 1;
678 WMDrawPixmap(tb
->d
.pixmap
, tPtr
->db
,
679 tb
->sections
[0].x
- tPtr
->hpos
,
680 tb
->sections
[0].y
- tPtr
->vpos
);
681 h
= tb
->d
.pixmap
->height
+ 1;
685 if (tb
->underlined
) {
686 XDrawLine(dpy
, tPtr
->db
, WMColorGC(tb
->color
),
688 tb
->sections
[0].y
+ h
,
689 tb
->sections
[0].x
+ tb
->sections
[0].w
,
690 tb
->sections
[0].y
+ h
);
695 if (tPtr
->flags
.editable
&& tPtr
->flags
.cursorShown
696 && tPtr
->cursor
.x
!= -23 && tPtr
->flags
.focused
) {
697 int y
= tPtr
->cursor
.y
- tPtr
->vpos
;
698 XDrawLine(dpy
, tPtr
->db
, tPtr
->fgGC
,
700 tPtr
->cursor
.x
, y
+ tPtr
->cursor
.h
);
703 XCopyArea(dpy
, tPtr
->db
, win
, tPtr
->bgGC
,
705 tPtr
->visible
.w
, tPtr
->visible
.h
,
706 tPtr
->visible
.x
, tPtr
->visible
.y
);
709 W_DrawRelief(scr
, win
, 0, 0,
710 tPtr
->view
->size
.width
, tPtr
->view
->size
.height
,
713 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)
716 tPtr
->view
->size
.width
-4, 42);
724 blinkCursor(void *data
)
726 Text
*tPtr
= (Text
*)data
;
728 if (tPtr
->flags
.cursorShown
) {
729 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY
,
732 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
,
736 tPtr
->flags
.cursorShown
= !tPtr
->flags
.cursorShown
;
741 getFirstNonGraphicBlockFor(TextBlock
*tb
, short dir
)
748 tb
= (dir
? tb
->next
: tb
->prior
);
756 cursorToTextPosition(Text
*tPtr
, int x
, int y
)
758 TextBlock
*tb
= NULL
;
759 int done
=False
, s
, pos
, len
, _w
, _y
, dir
=1; /* 1 == "down" */
762 if(tPtr
->flags
.needsRefresh
)
763 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
765 y
+= (tPtr
->vpos
- tPtr
->visible
.y
);
769 x
-= (tPtr
->visible
.x
- 2);
773 /* clicked is relative to document, not window... */
777 if (! (tb
= tPtr
->currentTextBlock
)) {
778 if (! (tb
= tPtr
->firstTextBlock
)) {
780 tPtr
->cursor
.h
= tPtr
->dFont
->height
;
787 /* first, which direction? Most likely, newly clicked
788 position will be close to previous */
789 dir
= !(y
<= tb
->sections
[0].y
);
790 if ( ( y
<= tb
->sections
[0]._y
+ tb
->sections
[0].h
)
791 && (y
>= tb
->sections
[0]._y
) ) {
792 /* if it's on the same line */
793 if(x
< tb
->sections
[0].x
)
795 if(x
>= tb
->sections
[0].x
)
799 tb
= tPtr
->firstTextBlock
;
802 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
803 tb
= getFirstNonGraphicBlockFor(tb
, 1);
805 tPtr
->currentTextBlock
=
806 (dir
? tPtr
->lastTextBlock
: tPtr
->firstTextBlock
);
812 s
= (dir
? 0 : tb
->nsections
-1);
813 if ( y
>= tb
->sections
[s
]._y
814 && y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) {
818 /* get the first section of the TextBlock that lies about
819 the vertical click point */
821 while (!done
&& tb
) {
823 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
829 s
= (dir
? 0 : tb
->nsections
-1);
830 while (!done
&& (dir
? (s
<tb
->nsections
) : (s
>=0) )) {
832 if ( (dir
? (y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) :
833 ( y
>= tb
->sections
[s
]._y
) ) ) {
841 if ( (dir
? tb
->next
: tb
->prior
)) {
842 tb
= (dir
? tb
->next
: tb
->prior
);
845 break; //goto _doneH;
851 if (s
<0 || s
>=tb
->nsections
) {
852 s
= (dir
? tb
->nsections
-1 : 0);
856 /* we have the line, which TextBlock on that line is it? */
858 if (tPtr
->flags
.monoFont
&& tb
->graphic
)
859 tb
= getFirstNonGraphicBlockFor(tb
, dir
);
861 if ((dir
? tb
->sections
[s
].x
>= x
: tb
->sections
[s
].x
< x
))
869 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
870 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
871 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
873 printf("here %d %d \n", tb
->sections
[s
].x
+ _w
, x
);
874 if ((dir
? tb
->sections
[s
].x
+ _w
< x
: tb
->sections
[s
].x
+ _w
>= x
)) {
875 pos
= tb
->sections
[s
].end
;
876 tPtr
->cursor
.x
= tb
->sections
[s
].x
+ _w
;
880 _y
= tb
->sections
[s
]._y
;
885 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
886 tb
= (dir
? tb
->next
: tb
->prior
);
893 _w
= WMWidgetWidth(tb
->d
.widget
);
895 _w
= tb
->d
.pixmap
->width
;
897 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
898 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
899 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
900 if (tb
->sections
[s
].x
+ _w
>= x
)
905 if (tb
->sections
[s
].x
<= x
)
909 if ((dir
? tb
->next
: tb
->prior
)) {
910 TextBlock
*nxt
= (dir
? tb
->next
: tb
->prior
);
911 if (tPtr
->flags
.monoFont
&& nxt
->graphic
) {
912 nxt
= getFirstNonGraphicBlockFor(nxt
, dir
);
915 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
920 if (_y
!= nxt
->sections
[0]._y
) {
921 /* this must be the last/first on this line. stop */
922 pos
= (dir
? tb
->sections
[s
].end
: 0);
923 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
927 tPtr
->cursor
.x
+= WMWidgetWidth(tb
->d
.widget
);
929 tPtr
->cursor
.x
+= tb
->d
.pixmap
->width
;
930 } else if (pos
> tb
->sections
[s
].begin
) {
932 WMWidthOfString(tb
->d
.font
,
933 &(tb
->text
[tb
->sections
[s
].begin
]),
934 pos
- tb
->sections
[s
].begin
);
941 if ( (dir
? tb
->next
: tb
->prior
)) {
942 tb
= (dir
? tb
->next
: tb
->prior
);
949 s
= (dir
? 0 : tb
->nsections
-1);
952 /* we have said TextBlock, now where within it? */
953 if (tb
&& !tb
->graphic
) {
954 WMFont
*f
= tb
->d
.font
;
955 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
956 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
958 _w
= x
- tb
->sections
[s
].x
;
961 while (pos
<len
&& WMWidthOfString(f
, text
, pos
+1) < _w
)
964 tPtr
->cursor
.x
= tb
->sections
[s
].x
+
965 (pos
? WMWidthOfString(f
, text
, pos
) : 0);
967 pos
+= tb
->sections
[s
].begin
;
969 tPtr
->tpos
= (pos
<tb
->used
)? pos
: tb
->used
;
972 tPtr
->currentTextBlock
= tb
;
973 tPtr
->cursor
.h
= tb
->sections
[s
].h
;
974 tPtr
->cursor
.y
= tb
->sections
[s
]._y
;
977 printf("will hang :-)\n");
982 updateScrollers(Text
*tPtr
)
985 if (tPtr
->flags
.frozen
)
989 if (tPtr
->docHeight
< tPtr
->visible
.h
) {
990 WMSetScrollerParameters(tPtr
->vS
, 0, 1);
993 float hmax
= (float)(tPtr
->docHeight
);
994 WMSetScrollerParameters(tPtr
->vS
,
995 ((float)tPtr
->vpos
)/(hmax
- (float)tPtr
->visible
.h
),
996 (float)tPtr
->visible
.h
/hmax
);
998 } else tPtr
->vpos
= 0;
1001 if (tPtr
->docWidth
< tPtr
->visible
.w
) {
1002 WMSetScrollerParameters(tPtr
->hS
, 0, 1);
1005 float wmax
= (float)(tPtr
->docWidth
);
1006 WMSetScrollerParameters(tPtr
->hS
,
1007 ((float)tPtr
->hpos
)/(wmax
- (float)tPtr
->visible
.w
),
1008 (float)tPtr
->visible
.w
/wmax
);
1010 } else tPtr
->hpos
= 0;
1014 scrollersCallBack(WMWidget
*w
, void *self
)
1016 Text
*tPtr
= (Text
*)self
;
1017 Bool scroll
= False
;
1018 Bool dimple
= False
;
1021 if (!tPtr
->view
->flags
.realized
|| tPtr
->flags
.frozen
)
1024 if (w
== tPtr
->vS
) {
1026 height
= tPtr
->visible
.h
;
1028 which
= WMGetScrollerHitPart(tPtr
->vS
);
1030 case WSDecrementLine
:
1031 if (tPtr
->vpos
> 0) {
1032 if (tPtr
->vpos
>16) tPtr
->vpos
-=16;
1036 case WSIncrementLine
: {
1037 int limit
= tPtr
->docHeight
- height
;
1038 if (tPtr
->vpos
< limit
) {
1039 if (tPtr
->vpos
<limit
-16) tPtr
->vpos
+=16;
1040 else tPtr
->vpos
=limit
;
1043 case WSDecrementPage
:
1044 tPtr
->vpos
-= height
;
1050 printf("dimple needs to jump to mouse location ;-/\n");
1052 case WSIncrementPage
:
1053 tPtr
->vpos
+= height
;
1054 if (tPtr
->vpos
> (tPtr
->docHeight
- height
))
1055 tPtr
->vpos
= tPtr
->docHeight
- height
;
1058 printf("dimple needs to jump to mouse location ;-/\n");
1063 tPtr
->vpos
= WMGetScrollerValue(tPtr
->vS
)
1064 * (float)(tPtr
->docHeight
- height
);
1070 printf("WSNoPart, WSKnobSlot\n");
1072 float hmax
= (float)(tPtr
->docHeight
);
1073 ((float)tPtr
->vpos
)/(hmax
- (float)tPtr
->visible
.h
),
1074 (float)tPtr
->visible
.h
/hmax
;
1075 dimple
=where mouse is
.
1079 scroll
= (tPtr
->vpos
!= tPtr
->prevVpos
);
1080 tPtr
->prevVpos
= tPtr
->vpos
;
1083 if (w
== tPtr
->hS
) {
1084 int width
= tPtr
->visible
.w
;
1086 which
= WMGetScrollerHitPart(tPtr
->hS
);
1088 case WSDecrementLine
:
1089 if (tPtr
->hpos
> 0) {
1090 if (tPtr
->hpos
>16) tPtr
->hpos
-=16;
1094 case WSIncrementLine
: {
1095 int limit
= tPtr
->docWidth
- width
;
1096 if (tPtr
->hpos
< limit
) {
1097 if (tPtr
->hpos
<limit
-16) tPtr
->hpos
+=16;
1098 else tPtr
->hpos
=limit
;
1101 case WSDecrementPage
:
1102 tPtr
->hpos
-= width
;
1108 printf("dimple needs to jump to mouse location ;-/\n");
1110 case WSIncrementPage
:
1111 tPtr
->hpos
+= width
;
1112 if (tPtr
->hpos
> (tPtr
->docWidth
- width
))
1113 tPtr
->hpos
= tPtr
->docWidth
- width
;
1116 printf("dimple needs to jump to mouse location ;-/\n");
1121 tPtr
->hpos
= WMGetScrollerValue(tPtr
->hS
)
1122 * (float)(tPtr
->docWidth
- width
);
1128 printf("WSNoPart, WSKnobSlot\n");
1130 float wmax
= (float)(tPtr
->docWidth
);
1131 ((float)tPtr
->vpos
)/(wmax
- (float)tPtr
->visible
.w
),
1132 (float)tPtr
->visible
.w
/wmax
;
1133 dimple
=where mouse is
.
1137 scroll
= (tPtr
->hpos
!= tPtr
->prevHpos
);
1138 tPtr
->prevHpos
= tPtr
->hpos
;
1144 if (tPtr->rulerShown)
1145 XClearArea(tPtr->view->screen->display, tPtr->view->window, 22, 47,
1146 tPtr->view->size.width-24, tPtr->view->size.height-49, True);
1148 XClearArea(tPtr->view->screen->display, tPtr->view->window, 22, 2,
1149 tPtr->view->size.width-24, tPtr->view->size.height-4, True);
1152 if (dimple
|| which
== WSDecrementLine
|| which
== WSIncrementLine
)
1153 updateScrollers(tPtr
);
1162 unsigned short begin
, end
; /* what part of the text block */
1167 layOutLine(Text
*tPtr
, myLineItems
*items
, int nitems
, int x
, int y
)
1169 int i
, j
=0, lw
= 0, line_height
=0, max_d
=0, len
, n
;
1173 TextBlock
*tbsame
=NULL
;
1175 if(!items
|| nitems
== 0)
1178 for(i
=0; i
<nitems
; i
++) {
1182 if (!tPtr
->flags
.monoFont
) {
1184 WMWidget
*wdt
= tb
->d
.widget
;
1185 line_height
= WMAX(line_height
, WMWidgetHeight(wdt
));
1186 if (tPtr
->flags
.alignment
!= WALeft
)
1187 lw
+= WMWidgetWidth(wdt
);
1189 line_height
= WMAX(line_height
, tb
->d
.pixmap
->height
+ max_d
);
1190 if (tPtr
->flags
.alignment
!= WALeft
)
1191 lw
+= tb
->d
.pixmap
->width
;
1196 font
= (tPtr
->flags
.monoFont
)?tPtr
->dFont
: tb
->d
.font
;
1197 max_d
= WMAX(max_d
, abs(font
->height
-font
->y
));
1198 line_height
= WMAX(line_height
, font
->height
+ max_d
);
1199 text
= &(tb
->text
[items
[i
].begin
]);
1200 len
= items
[i
].end
- items
[i
].begin
;
1201 if (tPtr
->flags
.alignment
!= WALeft
)
1202 lw
+= WMWidthOfString(font
, text
, len
);
1206 if (tPtr
->flags
.alignment
== WARight
) {
1207 j
= tPtr
->visible
.w
- lw
;
1208 } else if (tPtr
->flags
.alignment
== WACenter
) {
1209 j
= (int) ((float)(tPtr
->visible
.w
- lw
))/2.0;
1212 for(i
=0; i
<nitems
; i
++) {
1215 if (tbsame
== tb
) { /*extend it, since it's on same line */
1216 tb
->sections
[tb
->nsections
-1].end
= items
[i
].end
;
1217 n
= tb
->nsections
-1;
1219 tb
->sections
= wrealloc(tb
->sections
,
1220 (++tb
->nsections
)*sizeof(Section
));
1221 n
= tb
->nsections
-1;
1222 tb
->sections
[n
]._y
= y
+ max_d
;
1223 tb
->sections
[n
].x
= x
+j
;
1224 tb
->sections
[n
].h
= line_height
;
1225 tb
->sections
[n
].begin
= items
[i
].begin
;
1226 tb
->sections
[n
].end
= items
[i
].end
;
1228 if (tb
->graphic
&& tb
->object
) {
1229 tb
->sections
[n
].x
+= tPtr
->visible
.x
;
1230 tb
->sections
[n
].y
+= tPtr
->visible
.y
;
1234 tb
->sections
[n
].last
= (i
+1 == nitems
);
1237 if (!tPtr
->flags
.monoFont
) {
1239 WMWidget
*wdt
= tb
->d
.widget
;
1240 tb
->sections
[n
].y
= max_d
+ y
1241 + line_height
- WMWidgetHeight(wdt
);
1242 tb
->sections
[n
].w
= WMWidgetWidth(wdt
);
1244 tb
->sections
[n
].y
= y
+ max_d
;
1245 tb
->sections
[n
].w
= tb
->d
.pixmap
->width
;
1247 x
+= tb
->sections
[n
].w
;
1250 font
= (tPtr
->flags
.monoFont
)? tPtr
->dFont
: tb
->d
.font
;
1251 len
= items
[i
].end
- items
[i
].begin
;
1252 text
= &(tb
->text
[items
[i
].begin
]);
1254 tb
->sections
[n
].y
= y
+line_height
-font
->y
;
1256 WMWidthOfString(font
,
1257 &(tb
->text
[tb
->sections
[n
].begin
]),
1258 tb
->sections
[n
].end
- tb
->sections
[n
].begin
);
1260 x
+= WMWidthOfString(font
, text
, len
);
1272 output(char *ptr
, int len
)
1275 memcpy(s
, ptr
, len
);
1277 //printf(" s is [%s] (%d)\n", s, strlen(s));
1278 printf("[%s]\n", s
);
1282 /* tb->text doesn't necessarily end in '\0' hmph! (strchr) */
1283 static inline char *
1284 mystrchr(char *s
, char needle
, unsigned short len
)
1288 if (!haystack
|| len
< 1)
1291 while ( (int) (haystack
- s
) < len
) {
1292 if (*haystack
== needle
)
1300 mystrcasecmp(const unsigned char *s1
, const unsigned char *s2
)
1305 while (*s2
!= '\0') {
1306 if (TOLOWER (*s1
) != TOLOWER (*s2
)) /* true if *s1 == 0 ! */
1311 return (*s1
=='\0' || !ISALNUM(*s1
))?1:0;
1317 layOutDocument(Text
*tPtr
)
1320 myLineItems
*items
= NULL
;
1321 unsigned int itemsSize
=0, nitems
=0;
1323 unsigned int x
, y
=0, prev_y
, lw
= 0, width
=0, bmargin
;
1326 Bool lhc
= !tPtr
->flags
.laidOut
; /* line height changed? */
1328 char *start
=NULL
, *mark
=NULL
;
1329 unsigned int begin
, end
;
1331 if (tPtr
->flags
.frozen
)
1334 if (!(tb
= tPtr
->firstTextBlock
))
1337 tPtr
->docWidth
= tPtr
->visible
.w
;
1338 x
= 0;//tPtr->margins[tb->marginN].first;
1339 printf("x:%d\n", x
);
1340 bmargin
= tPtr
->margins
[tb
->marginN
].body
;
1342 if (0&&tPtr
->flags
.laidOut
) {
1343 tb
= tPtr
->currentTextBlock
;
1344 if (tb
->sections
&& tb
->nsections
>0)
1345 prev_y
= tb
->sections
[tb
->nsections
-1]._y
;
1347 printf("1 prev_y %d \n", prev_y
);
1349 /* search backwards for textblocks on same line */
1351 if (!tb
->sections
|| tb
->nsections
<1) {
1352 tb
= tPtr
->firstTextBlock
;
1355 if (tb
->sections
[tb
->nsections
-1]._y
!= prev_y
) {
1359 // prev_y = tb->sections[tb->nsections-1]._y;
1362 y
= 0;//tb->sections[tb->nsections-1]._y;
1363 printf("2 prev_y %d \n\n", tb
->sections
[tb
->nsections
-1]._y
);
1369 if (tb
->sections
&& tb
->nsections
>0) {
1370 wfree(tb
->sections
);
1371 tb
->sections
= NULL
;
1375 if (tb
->first
&& tb
!= tPtr
->firstTextBlock
) {
1376 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1377 x
= 0*tPtr
->margins
[tb
->marginN
].first
;
1378 bmargin
= tPtr
->margins
[tb
->marginN
].body
;
1384 if (!tPtr
->flags
.monoFont
) {
1386 width
= WMWidgetWidth(tb
->d
.widget
);
1388 width
= tb
->d
.pixmap
->width
;
1390 if (width
> tPtr
->docWidth
) { //tPtr->visible.w) {
1391 printf("rescale graphix to fit?\n");
1392 printf("%d %d\n", width
, tPtr
->visible
.w
);
1393 tPtr
->docWidth
= width
;//tPtr->visible.w + (width-tPtr->visible.w);
1397 if (lw
>= tPtr
->visible
.w
- x
) {
1398 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1404 if(nitems
+ 1> itemsSize
) {
1405 items
= wrealloc(items
,
1406 (++itemsSize
)*sizeof(myLineItems
));
1409 items
[nitems
].tb
= tb
;
1410 items
[nitems
].begin
= 0;
1411 items
[nitems
].end
= 0;
1415 } else if ((start
= tb
->text
)) {
1417 font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
1420 mark
= mystrchr(start
, ' ', tb
->used
);
1422 end
+= (int)(mark
-start
)+1;
1425 end
+= strlen(start
);
1432 if (end
-begin
> 0) {
1434 width
= WMWidthOfString(font
,
1435 &tb
->text
[begin
], end
-begin
);
1437 if (width
> tPtr
->visible
.w
) { /* break this tb up */
1438 char *t
= &tb
->text
[begin
];
1439 int l
=end
-begin
, i
=0;
1441 width
= WMWidthOfString(font
, t
, ++i
);
1442 } while (width
< tPtr
->visible
.w
&& i
< l
);
1444 if (start
) // and since (nil)-4 = 0xfffffffd
1451 if (lw
>= tPtr
->visible
.w
- x
) {
1452 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1458 if(nitems
+ 1 > itemsSize
) {
1459 items
= wrealloc(items
,
1460 (++itemsSize
)*sizeof(myLineItems
));
1463 items
[nitems
].tb
= tb
;
1464 items
[nitems
].begin
= begin
;
1465 items
[nitems
].end
= end
;
1476 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1478 tPtr
->docHeight
= y
+10;
1479 updateScrollers(tPtr
);
1482 if(tPtr
->docWidth
> tPtr
->visible
.w
&& !tPtr
->hS
) {
1485 tPtr
->flags
.horizOnDemand
= True
;
1486 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, True
);
1487 event
.type
= Expose
;
1488 handleEvents(&event
, (void *)tPtr
);
1490 } else if(tPtr
->docWidth
<= tPtr
->visible
.w
1491 && tPtr
->hS
&& tPtr
->flags
.horizOnDemand
) {
1492 tPtr
->flags
.horizOnDemand
= False
;
1493 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, False
);
1495 tPtr
->flags
.laidOut
= True
;
1498 if(items
&& itemsSize
> 0)
1504 textDidResize(W_ViewDelegate
*self
, WMView
*view
)
1506 Text
*tPtr
= (Text
*)view
->self
;
1507 unsigned short w
= tPtr
->view
->size
.width
;
1508 unsigned short h
= tPtr
->view
->size
.height
;
1509 unsigned short rh
= 0, vw
= 0;
1511 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
) {
1512 WMMoveWidget(tPtr
->ruler
, 2, 2);
1513 WMResizeWidget(tPtr
->ruler
, w
- 4, 40);
1518 WMMoveWidget(tPtr
->vS
, 1, rh
+ 1);
1519 WMResizeWidget(tPtr
->vS
, 20, h
- rh
- 2);
1521 WMSetRulerOffset(tPtr
->ruler
,22);
1522 } else WMSetRulerOffset(tPtr
->ruler
, 2);
1526 WMMoveWidget(tPtr
->hS
, vw
, h
- 21);
1527 WMResizeWidget(tPtr
->hS
, w
- vw
- 1, 20);
1529 WMMoveWidget(tPtr
->hS
, vw
+1, h
- 21);
1530 WMResizeWidget(tPtr
->hS
, w
- vw
- 2, 20);
1534 tPtr
->visible
.x
= (tPtr
->vS
)?24:4;
1535 tPtr
->visible
.y
= (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)?43:3;
1536 tPtr
->visible
.w
= tPtr
->view
->size
.width
- tPtr
->visible
.x
- 8;
1537 tPtr
->visible
.h
= tPtr
->view
->size
.height
- tPtr
->visible
.y
;
1538 tPtr
->visible
.h
-= (tPtr
->hS
)?20:0;
1539 tPtr
->margins
[0].right
= tPtr
->visible
.w
;
1541 if (tPtr
->view
->flags
.realized
) {
1544 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
1545 tPtr
->db
= (Pixmap
) NULL
;
1548 if (tPtr
->visible
.w
< 40)
1549 tPtr
->visible
.w
= 40;
1550 if (tPtr
->visible
.h
< 20)
1551 tPtr
->visible
.h
= 20;
1553 //if (size change or !db
1555 tPtr
->db
= XCreatePixmap(tPtr
->view
->screen
->display
,
1556 tPtr
->view
->window
, tPtr
->visible
.w
,
1557 tPtr
->visible
.h
, tPtr
->view
->screen
->depth
);
1561 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1564 W_ViewDelegate _TextViewDelegate
=
1572 /* nice, divisble-by-16 blocks */
1573 static inline unsigned short
1574 reqBlockSize(unsigned short requested
)
1576 return requested
+ 16 - (requested
%16);
1581 clearText(Text
*tPtr
)
1583 if (!tPtr
->firstTextBlock
)
1586 while (tPtr
->currentTextBlock
)
1587 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1589 tPtr
->firstTextBlock
= NULL
;
1590 tPtr
->currentTextBlock
= NULL
;
1591 tPtr
->lastTextBlock
= NULL
;
1595 deleteTextInteractively(Text
*tPtr
, KeySym ksym
)
1597 TextBlock
*tb
= tPtr
->currentTextBlock
;
1598 Bool back
= (Bool
) (ksym
== XK_BackSpace
);
1601 if (!tPtr
->flags
.editable
|| tPtr
->flags
.buttonHeld
) {
1602 XBell(tPtr
->view
->screen
->display
, 0);
1609 tPtr
->flags
.needsRefresh
= True
;
1611 if (tPtr
->flags
.ownsSelection
) {
1612 removeSelection(tPtr
);
1616 if (back
&& tPtr
->tpos
< 1) {
1620 tPtr
->tpos
= tb
->used
;
1621 tPtr
->currentTextBlock
= tb
;
1626 if ( (tb
->used
> 0) && ((back
?tPtr
->tpos
> 0:1))
1627 && (tPtr
->tpos
<= tb
->used
) && !tb
->graphic
) {
1630 memmove(&(tb
->text
[tPtr
->tpos
]),
1631 &(tb
->text
[tPtr
->tpos
+ 1]), tb
->used
- tPtr
->tpos
);
1636 if ( (back
? (tPtr
->tpos
< 1 && !done
) : ( tPtr
->tpos
>= tb
->used
))
1639 TextBlock
*sibling
= (back
? tb
->prior
: tb
->next
);
1641 if(tb
->used
== 0 || tb
->graphic
)
1642 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1645 tPtr
->currentTextBlock
= sibling
;
1646 tPtr
->tpos
= (back
? sibling
->used
: 0);
1650 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1655 insertTextInteractively(Text
*tPtr
, char *text
, int len
)
1658 char *newline
= NULL
;
1660 if (!tPtr
->flags
.editable
|| tPtr
->flags
.buttonHeld
) {
1661 XBell(tPtr
->view
->screen
->display
, 0);
1667 WMColor
*color
= WMCreateNamedColor(W_VIEW_SCREEN(tPtr
->view
),
1669 WMSetTextSelectionColor(tPtr
, color
);
1674 if (len
< 1 || !text
)
1678 if(tPtr
->flags
.ignoreNewLine
&& *text
== '\n' && len
== 1)
1681 if (tPtr
->flags
.ownsSelection
)
1682 removeSelection(tPtr
);
1684 tPtr
->flags
.needsRefresh
= True
;
1686 if (tPtr
->flags
.ignoreNewLine
) {
1688 for(i
=0; i
<len
; i
++) {
1689 if (text
[i
] == '\n')
1694 tb
= tPtr
->currentTextBlock
;
1695 if (!tb
|| tb
->graphic
) {
1697 WMAppendTextStream(tPtr
, text
);
1698 if (tPtr
->currentTextBlock
) {
1699 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
1701 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1705 if ((newline
= strchr(text
, '\n'))) {
1706 int nlen
= (int)(newline
-text
);
1707 int s
= tb
->used
- tPtr
->tpos
;
1710 if (!tb
->blank
&& nlen
>0) {
1712 memcpy(save
, &tb
->text
[tPtr
->tpos
], s
);
1713 tb
->used
-= (tb
->used
- tPtr
->tpos
);
1716 insertTextInteractively(tPtr
, text
, nlen
);
1718 WMAppendTextStream(tPtr
, newline
);
1720 insertTextInteractively(tPtr
, save
, s
);
1723 if (tPtr
->tpos
>0 && tPtr
->tpos
< tb
->used
1724 && !tb
->graphic
&& tb
->text
) {
1726 void *ntb
= WMCreateTextBlockWithText(
1727 tPtr
, &tb
->text
[tPtr
->tpos
],
1728 tb
->d
.font
, tb
->color
, True
, tb
->used
- tPtr
->tpos
);
1729 tb
->used
= tPtr
->tpos
;
1730 WMAppendTextBlock(tPtr
, ntb
);
1732 } else if (tPtr
->tpos
== tb
->used
|| tPtr
->tpos
== 0) {
1733 void *ntb
= WMCreateTextBlockWithText(tPtr
,
1734 NULL
, tb
->d
.font
, tb
->color
, True
, 0);
1737 WMAppendTextBlock(tPtr
, ntb
);
1739 WMPrependTextBlock(tPtr
, ntb
);
1746 if (tb
->used
+ len
>= tb
->allocated
) {
1747 tb
->allocated
= reqBlockSize(tb
->used
+len
);
1748 tb
->text
= wrealloc(tb
->text
, tb
->allocated
);
1752 memcpy(tb
->text
, text
, len
);
1757 memmove(&(tb
->text
[tPtr
->tpos
+len
]), &tb
->text
[tPtr
->tpos
],
1758 tb
->used
-tPtr
->tpos
+1);
1759 memmove(&tb
->text
[tPtr
->tpos
], text
, len
);
1766 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1771 selectRegion(Text
*tPtr
, int x
, int y
)
1777 y
+= (tPtr
->flags
.rulerShown
? 40: 0);
1780 y
-= 10; /* the original offset */
1782 x
-= tPtr
->visible
.x
-2;
1786 tPtr
->sel
.x
= WMAX(0, WMIN(tPtr
->clicked
.x
, x
));
1787 tPtr
->sel
.w
= abs(tPtr
->clicked
.x
- x
);
1788 tPtr
->sel
.y
= WMAX(0, WMIN(tPtr
->clicked
.y
, y
));
1789 tPtr
->sel
.h
= abs(tPtr
->clicked
.y
- y
);
1791 tPtr
->flags
.ownsSelection
= True
;
1797 releaseSelection(Text
*tPtr
)
1799 TextBlock
*tb
= tPtr
->firstTextBlock
;
1802 tb
->selected
= False
;
1805 tPtr
->flags
.ownsSelection
= False
;
1806 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
,
1809 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
1814 requestHandler(WMView
*view
, Atom selection
, Atom target
, void *cdata
,
1817 Text
*tPtr
= view
->self
;
1818 Display
*dpy
= tPtr
->view
->screen
->display
;
1820 Atom TEXT
= XInternAtom(dpy
, "TEXT", False
);
1821 Atom COMPOUND_TEXT
= XInternAtom(dpy
, "COMPOUND_TEXT", False
);
1822 WMData
*data
= NULL
;
1825 if (target
== XA_STRING
|| target
== TEXT
|| target
== COMPOUND_TEXT
) {
1826 char *text
= WMGetTextSelected(tPtr
);
1829 printf("got text [%s]\n", text
);
1830 data
= WMCreateDataWithBytes(text
, strlen(text
));
1831 WMSetDataFormat(data
, 8);
1835 } else printf("didn't get it\n");
1837 _TARGETS
= XInternAtom(dpy
, "TARGETS", False
);
1838 if (target
== _TARGETS
) {
1841 ptr
= wmalloc(4 * sizeof(Atom
));
1845 ptr
[3] = COMPOUND_TEXT
;
1847 data
= WMCreateDataWithBytes(ptr
, 4*4);
1848 WMSetDataFormat(data
, 32);
1858 lostHandler(WMView
*view
, Atom selection
, void *cdata
)
1860 releaseSelection((WMText
*)view
->self
);
1863 static WMSelectionProcs selectionHandler
= {
1864 requestHandler
, lostHandler
, NULL
1869 ownershipObserver(void *observerData
, WMNotification
*notification
)
1871 // if (observerData != WMGetNotificationClientData(notification))
1872 lostHandler(WMWidgetView(observerData
), XA_PRIMARY
, NULL
);
1873 printf("lost ownership\n");
1878 fontChanged(void *observerData
, WMNotification
*notification
)
1880 WMText
*tPtr
= (WMText
*) observerData
;
1881 WMFont
*font
= (WMFont
*)WMGetNotificationClientData(notification
);
1882 printf("fontChanged\n");
1887 if (tPtr
->flags
.ownsSelection
)
1888 WMSetTextSelectionFont(tPtr
, font
);
1892 handleTextKeyPress(Text
*tPtr
, XEvent
*event
)
1896 int control_pressed
= False
;
1899 if (((XKeyEvent
*) event
)->state
& ControlMask
)
1900 control_pressed
= True
;
1901 buffer
[XLookupString(&event
->xkey
, buffer
, 1, &ksym
, NULL
)] = 0;
1906 WMScrollText(tPtr
, -14);
1908 TextBlock
*tb
= tPtr
->currentTextBlock
;
1909 int x
= tPtr
->cursor
.x
+ tPtr
->visible
.x
;
1910 int y
= tPtr
->visible
.y
+ tPtr
->cursor
.y
+ tPtr
->cursor
.h
;
1918 w
= WMWidgetWidth(tb
->d
.widget
);
1920 w
= tb
->d
.pixmap
->width
;
1924 w
= WMWidthOfString(tb
->d
.font
, &tb
->text
[pos
], 1);
1927 cursorToTextPosition(tPtr
, w
+ tPtr
->cursor
.x
+ tPtr
->visible
.x
,
1928 3 + tPtr
->visible
.y
+ tPtr
->cursor
.y
1929 + tPtr
->cursor
.h
- tPtr
->vpos
);
1930 if(x
== tPtr
->cursor
.x
+ tPtr
->visible
.x
) {
1931 printf("same %d %d\n", x
, tPtr
->cursor
.x
+ tPtr
->visible
.x
);
1932 cursorToTextPosition(tPtr
, tPtr
->visible
.x
,
1933 3 + tPtr
->visible
.y
+ tPtr
->cursor
.y
+ tPtr
->cursor
.h
);
1941 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
1942 tPtr
->clicked
.y
+ tPtr
->cursor
.h
- tPtr
->vpos
);
1947 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
1948 tPtr
->visible
.y
+ tPtr
->cursor
.y
- tPtr
->vpos
- 3);
1955 deleteTextInteractively(tPtr
, ksym
);
1960 control_pressed
= True
;
1966 if (buffer
[0] != 0 && !control_pressed
) {
1967 insertTextInteractively(tPtr
, buffer
, 1);
1969 } else if (control_pressed
&& ksym
==XK_r
) {
1970 Bool i
= !tPtr
->flags
.rulerShown
;
1971 WMShowTextRuler(tPtr
, i
);
1972 tPtr
->flags
.rulerShown
= i
;
1974 else if (control_pressed
&& buffer
[0] == '\a')
1975 XBell(tPtr
->view
->screen
->display
, 0);
1978 if (!control_pressed
&& tPtr
->flags
.ownsSelection
)
1979 releaseSelection(tPtr
);
1983 handleWidgetPress(XEvent
*event
, void *data
)
1985 TextBlock
*tb
= (TextBlock
*)data
;
1991 /* this little bit of nastiness here saves a boatload of trouble */
1992 w
= (WMWidget
*)(((W_VIEW(tb
->d
.widget
))->parent
)->self
);
1993 if (W_CLASS(w
) != WC_Text
)
1996 tPtr
->currentTextBlock
= getFirstNonGraphicBlockFor(tb
, 1);
1997 if (!tPtr
->currentTextBlock
)
1998 tPtr
->currentTextBlock
= tb
;
2000 output(tPtr
->currentTextBlock
->text
, tPtr
->currentTextBlock
->used
);
2001 //if (!tPtr->flags.focused) {
2002 // WMSetFocusToWidget(tPtr);
2003 // tPtr->flags.focused = True;
2009 handleActionEvents(XEvent
*event
, void *data
)
2011 Text
*tPtr
= (Text
*)data
;
2012 Display
*dpy
= event
->xany
.display
;
2016 switch (event
->type
) {
2018 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2019 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2020 tPtr
->flags
.extendSelection
= True
;
2024 if (tPtr
->flags
.focused
) {
2025 XGrabPointer(dpy
, W_VIEW(tPtr
)->window
, False
,
2026 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
2027 GrabModeAsync
, GrabModeAsync
, None
,
2028 tPtr
->view
->screen
->invisibleCursor
, CurrentTime
);
2029 tPtr
->flags
.pointerGrabbed
= True
;
2030 handleTextKeyPress(tPtr
, event
);
2035 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2036 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2037 tPtr
->flags
.extendSelection
= False
;
2039 //end modify flag so selection can be extended
2046 if (tPtr
->flags
.pointerGrabbed
) {
2047 tPtr
->flags
.pointerGrabbed
= False
;
2048 XUngrabPointer(dpy
, CurrentTime
);
2051 if(tPtr
->flags
.waitingForSelection
)
2054 if ((event
->xmotion
.state
& Button1Mask
)) {
2055 if (!tPtr
->flags
.ownsSelection
) {
2056 WMCreateSelectionHandler(tPtr
->view
,
2057 XA_PRIMARY
, event
->xbutton
.time
,
2058 &selectionHandler
, NULL
);
2059 tPtr
->flags
.ownsSelection
= True
;
2061 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2068 tPtr
->flags
.buttonHeld
= True
;
2070 if (tPtr
->flags
.pointerGrabbed
) {
2071 tPtr
->flags
.pointerGrabbed
= False
;
2072 XUngrabPointer(dpy
, CurrentTime
);
2076 if (tPtr
->flags
.waitingForSelection
)
2079 if (tPtr
->flags
.extendSelection
) {
2080 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2085 if (event
->xbutton
.button
== Button1
) {
2087 if (!tPtr
->flags
.focused
) {
2088 WMSetFocusToWidget(tPtr
);
2089 tPtr
->flags
.focused
= True
;
2092 if (tPtr
->flags
.ownsSelection
)
2093 releaseSelection(tPtr
);
2094 cursorToTextPosition(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2098 if (event
->xbutton
.button
2099 == WINGsConfiguration
.mouseWheelDown
) {
2100 WMScrollText(tPtr
, -16);
2104 if (event
->xbutton
.button
2105 == WINGsConfiguration
.mouseWheelUp
) {
2106 WMScrollText(tPtr
, 16);
2110 if (event
->xbutton
.button
== Button2
) {
2114 if (!tPtr
->flags
.editable
) {
2120 if (!WMRequestSelection(tPtr
->view
, XA_PRIMARY
, XA_STRING
,
2121 event
->xbutton
.time
, pasteText
, NULL
)) {
2125 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
2131 (tPtr
->parser
) (tPtr
, (void *) text
);
2133 insertTextInteractively(tPtr
, text
, n
);
2136 NOTIFY(tPtr
, didChange
, WMTextDidChangeNotification
,
2137 (void*)WMInsertTextEvent
);
2140 tPtr
->flags
.waitingForSelection
= True
;
2149 tPtr
->flags
.buttonHeld
= False
;
2151 if (tPtr
->flags
.pointerGrabbed
) {
2152 tPtr
->flags
.pointerGrabbed
= False
;
2153 XUngrabPointer(dpy
, CurrentTime
);
2157 if (tPtr
->flags
.waitingForSelection
)
2165 handleEvents(XEvent
*event
, void *data
)
2167 Text
*tPtr
= (Text
*)data
;
2169 switch(event
->type
) {
2172 if (event
->xexpose
.count
!=0)
2176 if (!(W_VIEW(tPtr
->hS
))->flags
.realized
)
2177 WMRealizeWidget(tPtr
->hS
);
2178 if (!((W_VIEW(tPtr
->hS
))->flags
.mapped
))
2179 WMMapWidget(tPtr
->hS
);
2183 if (!(W_VIEW(tPtr
->vS
))->flags
.realized
)
2184 WMRealizeWidget(tPtr
->vS
);
2185 if (!((W_VIEW(tPtr
->vS
))->flags
.mapped
))
2186 WMMapWidget(tPtr
->vS
);
2190 if (!(W_VIEW(tPtr
->ruler
))->flags
.realized
)
2191 WMRealizeWidget(tPtr
->ruler
);
2193 if (!((W_VIEW(tPtr
->ruler
))->flags
.mapped
)
2194 && tPtr
->flags
.rulerShown
)
2195 WMMapWidget(tPtr
->ruler
);
2199 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2205 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))
2208 tPtr
->flags
.focused
= True
;
2210 if (tPtr
->flags
.editable
&& !tPtr
->timerID
) {
2211 tPtr
->timerID
= WMAddTimerHandler(12+0*CURSOR_BLINK_ON_DELAY
,
2219 tPtr
->flags
.focused
= False
;
2222 if (tPtr
->timerID
) {
2223 WMDeleteTimerHandler(tPtr
->timerID
);
2224 tPtr
->timerID
= NULL
;
2233 WMDestroyWidget(tPtr
->hS
);
2235 WMDestroyWidget(tPtr
->vS
);
2237 WMDestroyWidget(tPtr
->ruler
);
2239 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
2241 WMFreeBag(tPtr
->gfxItems
);
2244 WMDeleteTimerHandler(tPtr
->timerID
);
2246 WMReleaseFont(tPtr
->dFont
);
2247 WMReleaseColor(tPtr
->dColor
);
2248 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
, CurrentTime
);
2249 WMRemoveNotificationObserver(tPtr
);
2260 insertText(WMText
*tPtr
, char *text
)
2272 mark
= strchr(start
, '\n');
2274 tb
= WMCreateTextBlockWithText(tPtr
,
2276 tPtr
->dColor
, True
, (int)(mark
-start
));
2279 if (start
&& strlen(start
)) {
2280 tb
= WMCreateTextBlockWithText(tPtr
, start
, tPtr
->dFont
,
2281 tPtr
->dColor
, False
, strlen(start
));
2286 if (tPtr
->flags
.prepend
)
2287 WMPrependTextBlock(tPtr
, tb
);
2289 WMAppendTextBlock(tPtr
, tb
);
2297 rulerMoveCallBack(WMWidget
*w
, void *self
)
2299 Text
*tPtr
= (Text
*)self
;
2302 if (W_CLASS(tPtr
) != WC_Text
)
2310 rulerReleaseCallBack(WMWidget
*w
, void *self
)
2312 Text
*tPtr
= (Text
*)self
;
2315 if (W_CLASS(tPtr
) != WC_Text
)
2318 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
2325 draggingEntered(WMView
*self
, WMDraggingInfo
*info
)
2327 printf("draggingEntered\n");
2328 return WDOperationCopy
;
2333 draggingUpdated(WMView
*self
, WMDraggingInfo
*info
)
2335 printf("draggingUpdated\n");
2336 return WDOperationCopy
;
2341 draggingExited(WMView
*self
, WMDraggingInfo
*info
)
2343 printf("draggingExited\n");
2347 prepareForDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2349 printf("draggingExited\n");
2350 return;//"bll"; //"application/X-color";
2355 performDragOperation(WMView
*self
, WMDraggingInfo
*info
) //, WMData *data)
2357 char *colorName
= "Blue";// (char*)WMDataBytes(data);
2359 WMText
*tPtr
= (WMText
*)self
->self
;
2364 if (tPtr
->flags
.monoFont
)
2367 color
= WMCreateNamedColor(W_VIEW_SCREEN(self
), colorName
, True
);
2368 printf("color [%s] %p\n", colorName
, color
);
2370 WMSetTextSelectionColor(tPtr
, color
);
2371 WMReleaseColor(color
);
2378 concludeDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2380 printf("concludeDragOperation\n");
2384 static WMDragDestinationProcs _DragDestinationProcs
= {
2388 prepareForDragOperation
,
2389 performDragOperation
,
2390 concludeDragOperation
2395 releaseBagData(void *data
)
2403 getStream(WMText
*tPtr
, int sel
)
2405 TextBlock
*tb
= NULL
;
2407 unsigned long where
= 0;
2412 if (!(tb
= tPtr
->firstTextBlock
))
2415 /* this might be tricky to get right... not yet implemented */
2417 (tPtr
->writer
) (tPtr
, (void *) text
);
2421 tb
= tPtr
->firstTextBlock
;
2424 if (!tb
->graphic
|| (tb
->graphic
&& !tPtr
->flags
.monoFont
)) {
2427 if (!sel
|| (tb
->graphic
&& tb
->selected
)) {
2428 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
)) {
2429 text
= wrealloc(text
, 1);
2430 text
[where
++] = '\n';
2434 text
= wrealloc(text
, 2);
2435 text
[where
++] = 0xFA;
2436 text
[where
++] = tb
->used
;
2439 text
= wrealloc(text
, tb
->used
);
2440 memcpy(&text
[where
], tb
->text
, tb
->used
);
2443 } else if (sel
&& tb
->selected
) {
2445 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
)) {
2446 text
= wrealloc(text
, 1);
2447 text
[where
++] = '\n';
2450 text
= wrealloc(text
, (tb
->s_end
- tb
->s_begin
));
2451 memcpy(&text
[where
], &tb
->text
[tb
->s_begin
],
2452 tb
->s_end
- tb
->s_begin
);
2453 where
+= tb
->s_end
- tb
->s_begin
;
2460 text
= wrealloc(text
, 1); /* +1 for the end of string, let's be nice */
2468 getStreamIntoBag(WMText
*tPtr
, int sel
)
2470 char *stream
, *start
= NULL
, *fa
= NULL
;
2478 stream
= getStream(tPtr
, sel
);
2482 bag
= WMCreateBagWithDestructor(4, releaseBagData
);
2486 fa
= strchr(start
, 0xFA);
2488 unsigned char len
= *(fa
+1);
2491 data
= WMCreateDataWithBytes((void *)start
, (int)(fa
- start
));
2492 WMSetDataFormat(data
, 8);
2493 WMPutInBag(bag
, (void *) data
);
2496 data
= WMCreateDataWithBytes((void *)(fa
+2), len
);
2497 WMSetDataFormat(data
, 32);
2498 WMPutInBag(bag
, (void *) data
);
2499 start
= fa
+ len
+ 2;
2502 if (start
&& strlen(start
)) {
2503 data
= WMCreateDataWithBytes((void *)start
, strlen(start
));
2504 WMSetDataFormat(data
, 8);
2505 WMPutInBag(bag
, (void *) data
);
2517 WMCreateText(WMWidget
*parent
)
2519 Text
*tPtr
= wmalloc(sizeof(Text
));
2521 printf("could not create text widget\n");
2526 printf("sizeof:\n");
2527 printf(" TextBlock %d\n", sizeof(TextBlock
));
2528 printf(" Section %d\n", sizeof(Section
));
2529 printf(" WMRulerMargins %d\n", sizeof(WMRulerMargins
));
2530 printf(" char * %d\n", sizeof(char *));
2531 printf(" void * %d\n", sizeof(void *));
2532 printf(" short %d\n", sizeof(short));
2533 printf(" Text %d\n", sizeof(Text
));
2536 memset(tPtr
, 0, sizeof(Text
));
2537 tPtr
->widgetClass
= WC_Text
;
2538 tPtr
->view
= W_CreateView(W_VIEW(parent
));
2540 perror("could not create text's view\n");
2544 tPtr
->view
->self
= tPtr
;
2545 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->textCursor
;
2546 tPtr
->view
->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2547 W_ResizeView(tPtr
->view
, 250, 200);
2548 tPtr
->bgGC
= WMColorGC(tPtr
->view
->screen
->white
);
2549 tPtr
->fgGC
= WMColorGC(tPtr
->view
->screen
->black
);
2550 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->view
->screen
->white
);
2556 tPtr
->dFont
= WMRetainFont(tPtr
->view
->screen
->normalFont
);
2558 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
2560 tPtr
->view
->delegate
= &_TextViewDelegate
;
2563 tPtr
->timerID
= NULL
;
2566 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
2567 |EnterWindowMask
|LeaveWindowMask
|FocusChangeMask
,
2568 handleEvents
, tPtr
);
2570 WMCreateEventHandler(tPtr
->view
, ButtonReleaseMask
|ButtonPressMask
2571 |KeyReleaseMask
|KeyPressMask
|Button1MotionMask
,
2572 handleActionEvents
, tPtr
);
2574 WMAddNotificationObserver(ownershipObserver
, tPtr
,
2575 "_lostOwnership", tPtr
);
2578 WMSetViewDragDestinationProcs(tPtr
->view
, &_DragDestinationProcs
);
2580 char *types
[2] = {"application/X-color", NULL
};
2581 WMRegisterViewForDraggedTypes(tPtr
->view
, types
);
2585 WMAddNotificationObserver(fontChanged
, tPtr
,
2586 "WMFontPanelDidChangeNotification", tPtr
);
2588 tPtr
->firstTextBlock
= NULL
;
2589 tPtr
->lastTextBlock
= NULL
;
2590 tPtr
->currentTextBlock
= NULL
;
2593 tPtr
->gfxItems
= WMCreateBag(4);
2595 tPtr
->parser
= NULL
;
2596 tPtr
->writer
= NULL
;
2598 tPtr
->sel
.x
= tPtr
->sel
.y
= 2;
2599 tPtr
->sel
.w
= tPtr
->sel
.h
= 0;
2601 tPtr
->clicked
.x
= tPtr
->clicked
.y
= 2;
2603 tPtr
->visible
.x
= tPtr
->visible
.y
= 2;
2604 tPtr
->visible
.h
= tPtr
->view
->size
.height
;
2605 tPtr
->visible
.w
= tPtr
->view
->size
.width
- 4;
2607 tPtr
->cursor
.x
= -23;
2610 tPtr
->docHeight
= 0;
2611 tPtr
->dBulletPix
= WMCreatePixmapFromXPMData(tPtr
->view
->screen
,
2613 tPtr
->db
= (Pixmap
) NULL
;
2615 tPtr
->margins
= WMGetRulerMargins(NULL
);
2616 tPtr
->margins
->right
= tPtr
->visible
.w
;
2619 tPtr
->flags
.rulerShown
= False
;
2620 tPtr
->flags
.monoFont
= False
;
2621 tPtr
->flags
.focused
= False
;
2622 tPtr
->flags
.editable
= True
;
2623 tPtr
->flags
.ownsSelection
= False
;
2624 tPtr
->flags
.pointerGrabbed
= False
;
2625 tPtr
->flags
.buttonHeld
= False
;
2626 tPtr
->flags
.extendSelection
= False
;
2627 tPtr
->flags
.frozen
= False
;
2628 tPtr
->flags
.cursorShown
= True
;
2629 tPtr
->flags
.clickPos
= 1;
2630 tPtr
->flags
.horizOnDemand
= False
;
2631 tPtr
->flags
.needsRefresh
= False
;
2632 tPtr
->flags
.ignoreNewLine
= False
;
2633 tPtr
->flags
.laidOut
= False
;
2634 tPtr
->flags
.waitingForSelection
= False
;
2635 tPtr
->flags
.prepend
= False
;
2636 tPtr
->flags
.parsingHTML
= False
;
2637 tPtr
->flags
.relief
= WRSunken
;
2638 tPtr
->flags
.alignment
= WALeft
;
2644 WMPrependTextStream(WMText
*tPtr
, char *text
)
2646 CHECK_CLASS(tPtr
, WC_Text
);
2649 releaseSelection(tPtr
);
2651 tPtr
->flags
.prepend
= True
;
2652 if (text
&& tPtr
->parser
)
2653 (tPtr
->parser
) (tPtr
, (void *) text
);
2655 insertText(tPtr
, text
);
2657 tPtr
->flags
.needsRefresh
= True
;
2662 WMAppendTextStream(WMText
*tPtr
, char *text
)
2664 CHECK_CLASS(tPtr
, WC_Text
);
2667 releaseSelection(tPtr
);
2669 tPtr
->flags
.prepend
= False
;
2670 if (text
&& tPtr
->parser
)
2671 (tPtr
->parser
) (tPtr
, (void *) text
);
2673 insertText(tPtr
, text
);
2675 tPtr
->flags
.needsRefresh
= True
;
2681 WMGetTextStream(WMText
*tPtr
)
2683 CHECK_CLASS(tPtr
, WC_Text
);
2684 return getStream(tPtr
, 0);
2688 WMGetTextSelected(WMText
*tPtr
)
2690 CHECK_CLASS(tPtr
, WC_Text
);
2691 return getStream(tPtr
, 1);
2695 WMGetTextStreamIntoBag(WMText
*tPtr
)
2697 CHECK_CLASS(tPtr
, WC_Text
);
2698 return getStreamIntoBag(tPtr
, 0);
2702 WMGetTextSelectedIntoBag(WMText
*tPtr
)
2704 CHECK_CLASS(tPtr
, WC_Text
);
2705 return getStreamIntoBag(tPtr
, 1);
2710 WMSetTextDelegate(WMText
*tPtr
, WMTextDelegate
*delegate
)
2712 CHECK_CLASS(tPtr
, WC_Text
);
2714 tPtr
->delegate
= delegate
;
2719 WMCreateTextBlockWithObject(WMText
*tPtr
, WMWidget
*w
,
2720 char *description
, WMColor
*color
,
2721 unsigned short first
, unsigned short reserved
)
2724 unsigned short length
;
2726 if (!w
|| !description
|| !color
)
2729 tb
= wmalloc(sizeof(TextBlock
));
2733 length
= strlen(description
);
2734 tb
->text
= (char *)wmalloc(length
);
2735 memset(tb
->text
, 0, length
);
2736 memcpy(tb
->text
, description
, length
);
2740 tb
->color
= WMRetainColor(color
);
2741 tb
->marginN
= newMargin(tPtr
, NULL
);
2747 tb
->underlined
= False
;
2748 tb
->selected
= False
;
2750 tb
->sections
= NULL
;
2760 WMCreateTextBlockWithPixmap(WMText
*tPtr
, WMPixmap
*p
,
2761 char *description
, WMColor
*color
,
2762 unsigned short first
, unsigned short reserved
)
2765 unsigned short length
;
2767 if (!p
|| !description
|| !color
)
2770 tb
= wmalloc(sizeof(TextBlock
));
2774 length
= strlen(description
);
2775 tb
->text
= (char *)wmalloc(length
);
2776 memset(tb
->text
, 0, length
);
2777 memcpy(tb
->text
, description
, length
);
2781 tb
->color
= WMRetainColor(color
);
2782 tb
->marginN
= newMargin(tPtr
, NULL
);
2788 tb
->underlined
= False
;
2789 tb
->selected
= False
;
2791 tb
->sections
= NULL
;
2800 WMCreateTextBlockWithText(WMText
*tPtr
, char *text
, WMFont
*font
, WMColor
*color
,
2801 unsigned short first
, unsigned short length
)
2805 if (!font
|| !color
)
2808 tb
= wmalloc(sizeof(TextBlock
));
2812 tb
->allocated
= reqBlockSize(length
);
2813 tb
->text
= (char *)wmalloc(tb
->allocated
);
2814 memset(tb
->text
, 0, tb
->allocated
);
2816 if (length
< 1|| !text
) { // || *text == '\n') {
2821 memcpy(tb
->text
, text
, length
);
2826 tb
->d
.font
= WMRetainFont(font
);
2827 tb
->color
= WMRetainColor(color
);
2828 tb
->marginN
= newMargin(tPtr
, NULL
);
2831 tb
->graphic
= False
;
2832 tb
->underlined
= False
;
2833 tb
->selected
= False
;
2835 tb
->sections
= NULL
;
2843 WMSetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int first
,
2844 unsigned int kanji
, unsigned int underlined
, int script
,
2845 WMRulerMargins
*margins
)
2847 TextBlock
*tb
= (TextBlock
*) vtb
;
2853 tb
->underlined
= underlined
;
2854 tb
->script
= script
;
2855 tb
->marginN
= newMargin(tPtr
, margins
);
2859 WMGetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int *first
,
2860 unsigned int *kanji
, unsigned int *underlined
, int *script
,
2861 WMRulerMargins
*margins
)
2863 TextBlock
*tb
= (TextBlock
*) vtb
;
2867 if (first
) *first
= tb
->first
;
2868 if (kanji
) *kanji
= tb
->kanji
;
2869 if (underlined
) *underlined
= tb
->underlined
;
2870 if (script
) *script
= tb
->script
;
2871 if (margins
) margins
= &tPtr
->margins
[tb
->marginN
];
2877 WMPrependTextBlock(WMText
*tPtr
, void *vtb
)
2879 TextBlock
*tb
= (TextBlock
*)vtb
;
2886 WMWidget
*w
= tb
->d
.widget
;
2887 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
2888 handleWidgetPress
, tb
);
2889 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
2890 (W_VIEW(w
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
2891 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2894 WMPutInBag(tPtr
->gfxItems
, (void *)tb
);
2896 } else tPtr
->tpos
= tb
->used
;
2898 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
2899 tb
->next
= tb
->prior
= NULL
;
2901 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
2902 = tPtr
->currentTextBlock
= tb
;
2907 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
2910 tb
->next
= tPtr
->currentTextBlock
;
2911 tb
->prior
= tPtr
->currentTextBlock
->prior
;
2912 if (tPtr
->currentTextBlock
->prior
)
2913 tPtr
->currentTextBlock
->prior
->next
= tb
;
2915 tPtr
->currentTextBlock
->prior
= tb
;
2917 tPtr
->firstTextBlock
= tb
;
2919 tPtr
->currentTextBlock
= tb
;
2924 WMAppendTextBlock(WMText
*tPtr
, void *vtb
)
2926 TextBlock
*tb
= (TextBlock
*)vtb
;
2933 WMWidget
*w
= tb
->d
.widget
;
2934 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
2935 handleWidgetPress
, tb
);
2936 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
2937 (W_VIEW(w
))->attribs
.cursor
=
2938 tPtr
->view
->screen
->defaultCursor
;
2939 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2942 WMPutInBag(tPtr
->gfxItems
, (void *)tb
);
2944 } else tPtr
->tpos
= tb
->used
;
2946 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
2947 tb
->next
= tb
->prior
= NULL
;
2949 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
2950 = tPtr
->currentTextBlock
= tb
;
2955 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
2958 tb
->next
= tPtr
->currentTextBlock
->next
;
2959 tb
->prior
= tPtr
->currentTextBlock
;
2960 if (tPtr
->currentTextBlock
->next
)
2961 tPtr
->currentTextBlock
->next
->prior
= tb
;
2963 tPtr
->currentTextBlock
->next
= tb
;
2966 tPtr
->lastTextBlock
= tb
;
2968 tPtr
->currentTextBlock
= tb
;
2972 WMRemoveTextBlock(WMText
*tPtr
)
2974 TextBlock
*tb
= NULL
;
2976 if (!tPtr
|| !tPtr
->firstTextBlock
|| !tPtr
->lastTextBlock
2977 || !tPtr
->currentTextBlock
) {
2978 printf("cannot remove non existent TextBlock!\b");
2982 tb
= tPtr
->currentTextBlock
;
2984 WMRemoveFromBag(tPtr
->gfxItems
, (void *)tb
);
2987 WMDeleteEventHandler(W_VIEW(tb
->d
.widget
), ButtonPressMask
,
2988 handleWidgetPress
, tb
);
2989 WMUnmapWidget(tb
->d
.widget
);
2993 if (tPtr
->currentTextBlock
== tPtr
->firstTextBlock
) {
2994 if (tPtr
->currentTextBlock
->next
)
2995 tPtr
->currentTextBlock
->next
->prior
= NULL
;
2997 tPtr
->firstTextBlock
= tPtr
->currentTextBlock
->next
;
2998 tPtr
->currentTextBlock
= tPtr
->firstTextBlock
;
3000 } else if (tPtr
->currentTextBlock
== tPtr
->lastTextBlock
) {
3001 tPtr
->currentTextBlock
->prior
->next
= NULL
;
3002 tPtr
->lastTextBlock
= tPtr
->currentTextBlock
->prior
;
3003 tPtr
->currentTextBlock
= tPtr
->lastTextBlock
;
3005 tPtr
->currentTextBlock
->prior
->next
= tPtr
->currentTextBlock
->next
;
3006 tPtr
->currentTextBlock
->next
->prior
= tPtr
->currentTextBlock
->prior
;
3007 tPtr
->currentTextBlock
= tPtr
->currentTextBlock
->next
;
3014 WMDestroyTextBlock(WMText
*tPtr
, void *vtb
)
3016 TextBlock
*tb
= (TextBlock
*)vtb
;
3022 /* naturally, there's a danger to destroying
3023 widgets whose action brings us here:
3024 ie. press a button to destroy it... need to
3025 find a safer way. till then... this stays commented out */
3026 //WMDestroyWidget(tb->d.widget);
3027 //wfree(tb->d.widget);
3028 tb
->d
.widget
= NULL
;
3030 WMReleasePixmap(tb
->d
.pixmap
);
3031 tb
->d
.pixmap
= NULL
;
3034 WMReleaseFont(tb
->d
.font
);
3037 WMReleaseColor(tb
->color
);
3038 if (tb
->sections
&& tb
->nsections
> 0)
3039 wfree(tb
->sections
);
3047 WMRefreshText(WMText
*tPtr
, int vpos
, int hpos
)
3049 if (!tPtr
|| vpos
<0 || hpos
<0)
3052 if (tPtr
->flags
.frozen
&& !tPtr
->flags
.needsRefresh
)
3055 if(tPtr
->flags
.monoFont
) {
3056 int j
, c
= WMGetBagItemCount(tPtr
->gfxItems
);
3059 /* make sure to unmap widgets no matter where they are */
3060 for(j
=0; j
<c
; j
++) {
3061 if ((tb
= (TextBlock
*) WMGetFromBag(tPtr
->gfxItems
, j
))) {
3062 if (tb
->object
&& ((W_VIEW(tb
->d
.widget
))->flags
.mapped
))
3063 WMUnmapWidget(tb
->d
.widget
);
3069 if (tPtr
->vpos
!= vpos
) {
3070 if (vpos
< 0 || tPtr
->docHeight
< tPtr
->visible
.h
) {
3072 } else if(tPtr
->docHeight
- vpos
> tPtr
->visible
.h
- tPtr
->visible
.y
) {
3075 tPtr
->vpos
= tPtr
->docHeight
- tPtr
->visible
.h
;
3079 if (tPtr
->hpos
!= hpos
) {
3080 if (hpos
< 0 || tPtr
->docWidth
< tPtr
->visible
.w
) {
3082 } else if(tPtr
->docWidth
- hpos
> tPtr
->visible
.w
- tPtr
->visible
.x
) {
3085 tPtr
->hpos
= tPtr
->docWidth
- tPtr
->visible
.w
;
3090 tPtr
->flags
.laidOut
= False
;
3091 layOutDocument(tPtr
);
3092 updateScrollers(tPtr
);
3094 tPtr
->flags
.needsRefresh
= False
;
3099 WMSetTextForegroundColor(WMText
*tPtr
, WMColor
*color
)
3105 tPtr
->fgGC
= WMColorGC(color
);
3107 tPtr
->fgGC
= WMColorGC(WMBlackColor(tPtr
->view
->screen
));
3109 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
3113 WMSetTextBackgroundColor(WMText
*tPtr
, WMColor
*color
)
3119 tPtr
->bgGC
= WMColorGC(color
);
3120 W_SetViewBackgroundColor(tPtr
->view
, color
);
3122 tPtr
->bgGC
= WMColorGC(WMWhiteColor(tPtr
->view
->screen
));
3123 W_SetViewBackgroundColor(tPtr
->view
,
3124 WMWhiteColor(tPtr
->view
->screen
));
3127 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
3131 WMSetTextRelief(WMText
*tPtr
, WMReliefType relief
)
3135 tPtr
->flags
.relief
= relief
;
3140 WMSetTextHasHorizontalScroller(WMText
*tPtr
, Bool shouldhave
)
3145 if (shouldhave
&& !tPtr
->hS
) {
3146 tPtr
->hS
= WMCreateScroller(tPtr
);
3147 (W_VIEW(tPtr
->hS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3148 (W_VIEW(tPtr
->hS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3149 WMSetScrollerArrowsPosition(tPtr
->hS
, WSAMinEnd
);
3150 WMSetScrollerAction(tPtr
->hS
, scrollersCallBack
, tPtr
);
3151 WMMapWidget(tPtr
->hS
);
3152 } else if (!shouldhave
&& tPtr
->hS
) {
3153 WMUnmapWidget(tPtr
->hS
);
3154 WMDestroyWidget(tPtr
->hS
);
3160 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3165 WMSetTextHasRuler(WMText
*tPtr
, Bool shouldhave
)
3170 if(shouldhave
&& !tPtr
->ruler
) {
3171 tPtr
->ruler
= WMCreateRuler(tPtr
);
3172 (W_VIEW(tPtr
->ruler
))->attribs
.cursor
=
3173 tPtr
->view
->screen
->defaultCursor
;
3174 (W_VIEW(tPtr
->ruler
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3175 WMSetRulerReleaseAction(tPtr
->ruler
, rulerReleaseCallBack
, tPtr
);
3176 WMSetRulerMoveAction(tPtr
->ruler
, rulerMoveCallBack
, tPtr
);
3177 } else if(!shouldhave
&& tPtr
->ruler
) {
3178 WMShowTextRuler(tPtr
, False
);
3179 WMDestroyWidget(tPtr
->ruler
);
3182 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3186 WMShowTextRuler(WMText
*tPtr
, Bool show
)
3193 if(tPtr
->flags
.monoFont
)
3196 tPtr
->flags
.rulerShown
= show
;
3198 WMMapWidget(tPtr
->ruler
);
3200 WMUnmapWidget(tPtr
->ruler
);
3203 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3207 WMGetTextRulerShown(WMText
*tPtr
)
3215 return tPtr
->flags
.rulerShown
;
3220 WMSetTextHasVerticalScroller(WMText
*tPtr
, Bool shouldhave
)
3225 if (shouldhave
&& !tPtr
->vS
) {
3226 tPtr
->vS
= WMCreateScroller(tPtr
);
3227 (W_VIEW(tPtr
->vS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3228 (W_VIEW(tPtr
->vS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3229 WMSetScrollerArrowsPosition(tPtr
->vS
, WSAMaxEnd
);
3230 WMSetScrollerAction(tPtr
->vS
, scrollersCallBack
, tPtr
);
3231 WMMapWidget(tPtr
->vS
);
3232 } else if (!shouldhave
&& tPtr
->vS
) {
3233 WMUnmapWidget(tPtr
->vS
);
3234 WMDestroyWidget(tPtr
->vS
);
3240 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3246 WMScrollText(WMText
*tPtr
, int amount
)
3251 if (amount
== 0 || !tPtr
->view
->flags
.realized
)
3255 if (tPtr
->vpos
> 0) {
3256 if (tPtr
->vpos
> abs(amount
)) tPtr
->vpos
+= amount
;
3260 int limit
= tPtr
->docHeight
- tPtr
->visible
.h
;
3261 if (tPtr
->vpos
< limit
) {
3262 if (tPtr
->vpos
< limit
-amount
) tPtr
->vpos
+= amount
;
3263 else tPtr
->vpos
= limit
;
3267 if (scroll
&& tPtr
->vpos
!= tPtr
->prevVpos
) {
3268 updateScrollers(tPtr
);
3271 tPtr
->prevVpos
= tPtr
->vpos
;
3276 WMPageText(WMText
*tPtr
, Bool direction
)
3278 if (!tPtr
) return False
;
3279 if (!tPtr
->view
->flags
.realized
) return False
;
3281 return WMScrollText(tPtr
, direction
?tPtr
->visible
.h
:-tPtr
->visible
.h
);
3285 WMSetTextEditable(WMText
*tPtr
, Bool editable
)
3289 tPtr
->flags
.editable
= editable
;
3293 WMGetTextEditable(WMText
*tPtr
)
3297 return tPtr
->flags
.editable
;
3301 WMSetTextIgnoresNewline(WMText
*tPtr
, Bool ignore
)
3305 tPtr
->flags
.ignoreNewLine
= ignore
;
3309 WMGetTextIgnoresNewline(WMText
*tPtr
)
3313 return tPtr
->flags
.ignoreNewLine
;
3317 WMSetTextUsesMonoFont(WMText
*tPtr
, Bool mono
)
3321 if (mono
&& tPtr
->flags
.rulerShown
)
3322 WMShowTextRuler(tPtr
, False
);
3324 tPtr
->flags
.monoFont
= mono
;
3325 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
3329 WMGetTextUsesMonoFont(WMText
*tPtr
)
3333 return tPtr
->flags
.monoFont
;
3338 WMSetTextDefaultFont(WMText
*tPtr
, WMFont
*font
)
3343 WMReleaseFont(tPtr
->dFont
);
3347 tPtr
->dFont
= WMRetainFont(tPtr
->view
->screen
->normalFont
);
3351 WMGetTextDefaultFont(WMText
*tPtr
)
3360 WMSetTextAlignment(WMText
*tPtr
, WMAlignment alignment
)
3364 tPtr
->flags
.alignment
= alignment
;
3365 WMRefreshText(tPtr
, tPtr
->vpos
, tPtr
->hpos
);
3369 WMSetTextParser(WMText
*tPtr
, WMAction
*parser
)
3373 tPtr
->parser
= parser
;
3377 WMSetTextWriter(WMText
*tPtr
, WMAction
*writer
)
3381 tPtr
->writer
= writer
;
3385 WMGetTextInsertType(WMText
*tPtr
)
3389 return tPtr
->flags
.prepend
;
3394 WMSetTextSelectionColor(WMText
*tPtr
, WMColor
*color
)
3396 if (!tPtr
|| !color
)
3399 setSelectionProperty(tPtr
, NULL
, color
);
3405 WMSetTextSelectionFont(WMText
*tPtr
, WMFont
*font
)
3410 setSelectionProperty(tPtr
, font
, NULL
);
3415 WMFreezeText(WMText
*tPtr
)
3420 tPtr
->flags
.frozen
= True
;
3424 WMThawText(WMText
*tPtr
)
3429 tPtr
->flags
.frozen
= False
;
3434 WMFindInTextStream(WMText
*tPtr
, char *needle
)
3436 char *haystack
= NULL
;
3439 if (!tPtr
|| !needle
)
3442 if ( !(haystack
= "WMGetTextStream(tPtr)"))
3445 result
= (Bool
) strstr(haystack
, needle
);
3450 /* would be nice to have in WINGs proper... */
3452 changeFontProp(char *fname
, char *newprop
, int which
)
3454 char before
[128], prop
[128], after
[128];
3466 if(part
==which
) bptr
= prop
;
3467 else if(part
==which
+1) bptr
= after
;
3474 snprintf(fname
, 255, "%s-%s%s", before
, newprop
, after
);
3479 WMGetFontPlain(WMScreen
*scrPtr
, WMFont
*font
)
3490 WMGetFontBold(WMScreen
*scrPtr
, WMFont
*font
)
3492 WMFont
*newfont
=NULL
;
3494 if(!scrPtr
|| !font
)
3496 snprintf(fname
, 255, font
->name
);
3497 changeFontProp(fname
, "bold", 2);
3498 newfont
= WMCreateNormalFont(scrPtr
, fname
);
3507 WMGetFontItalic(WMScreen
*scrPtr
, WMFont
*font
)
3509 WMFont
*newfont
=NULL
;
3511 if(!scrPtr
|| !font
)
3513 snprintf(fname
, 255, font
->name
);
3514 changeFontProp(fname
, "o", 3);
3515 newfont
= WMCreateNormalFont(scrPtr
, fname
);
3523 WMGetFontOfSize(WMScreen
*scrPtr
, WMFont
*font
, int size
)
3526 if(!scrPtr
|| !font
|| size
<1)
3534 typedef struct _currentFormat
{
3539 WMRulerMargins margins
;
3540 //WMBag *aligns; // for tables...
3541 /* the following are "nested"
3542 i.e.: <b><b><i></b><b></i>
3543 1 2 1 1 2 0 get it? */
3551 WMAlignment align
:2;
3552 short ul
:3; /* how "nested"... up to 8 levels deep */
3553 short comment
:1; /* ignore text till --> */
3561 getArg(char *t
, short type
, void *arg
)
3564 while(*(++t
) && !d
) {
3566 if(*t
>='0' && *t
<='9') {
3567 sscanf(t
, "%d", arg
);
3568 while(*t
&& (*t
<'0' || *t
>'9'))
3577 void parseToken(WMText
*tPtr
, char *token
, short tk
)
3579 short open
=0; /* 0 starts, 1 closes */
3581 int prepend
= WMGetTextInsertType(tPtr
);
3582 WMScreen
*scr
= tPtr
->view
->screen
;
3585 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
3586 NULL
, cfmt
.cfont
, cfmt
.ccolor
, True
, 0));
3591 while(*token
&& *token
== ' ')
3598 while(*token
== ' ')
3602 if(!tPtr
->flags
.parsingHTML
) {
3603 if(mystrcasecmp(token
, "html")) {
3604 printf("got HTMLLLL: [%s]\n", token
);
3605 tPtr
->flags
.parsingHTML
= True
;
3607 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
3608 token
, cfmt
.cfont
, cfmt
.ccolor
, cfmt
.first
, strlen(token
)));
3615 if(strlen(token
)==1) {
3616 /* nice and fast for small tokens... no need for too much brain
3618 switch(TOLOWER(*token
)) {
3621 cfmt
.cfont
= WMGetFontItalic(scr
, cfmt
.cfont
);
3622 WMPutInBag(cfmt
.fonts
, (void *)cfmt
.cfont
);
3623 } else { /*dun wanna remove the baseFont eh? */
3624 int count
= WMGetBagItemCount(cfmt
.fonts
);
3626 WMDeleteFromBag(cfmt
.fonts
, count
-1);
3628 cfmt
.cfont
= (WMFont
*)WMGetFromBag(cfmt
.fonts
,
3629 WMGetBagItemCount(cfmt
.fonts
)-1);
3630 }printf("i\n"); break;
3634 cfmt
.cfont
= WMGetFontBold(scr
, cfmt
.cfont
);
3635 WMPutInBag(cfmt
.fonts
, (void *)cfmt
.cfont
);
3636 } else { /*dun wanna remove the baseFont eh? */
3637 int count
= WMGetBagItemCount(cfmt
.fonts
);
3639 WMDeleteFromBag(cfmt
.fonts
, count
-1);
3640 cfmt
.cfont
= (WMFont
*)WMGetFromBag(cfmt
.fonts
,
3641 WMGetBagItemCount(cfmt
.fonts
)-1);
3645 tb
= WMCreateTextBlockWithText(tPtr
, NULL
, cfmt
.cfont
,
3646 cfmt
.ccolor
, cfmt
.first
, 0);
3647 // WMSetTextBlockProperties(tb, cfmt.first, False, (cfmt.u?1:0), 0, cfmt.margins);
3648 WMAppendTextBlock(tPtr
, tb
);
3651 case 'u': cfmt
.u
= !open
; break;
3654 if(mystrcasecmp(token
, "br")) {
3657 else if(mystrcasecmp(token
, "ul")) {
3659 if(cfmt
.ul
>1) cfmt
.ul
--;
3662 cfmt
.bmargin
= cfmt
.ul
*30;
3663 cfmt
.fmargin
= cfmt
.bmargin
-10;
3664 } else cfmt
.fmargin
= cfmt
.bmargin
= 0;
3665 } else if(mystrcasecmp(token
, "li")) {
3667 //change margins... create a new margin....
3668 //(cfmt.fmargin, cfmt.bmargin,
3669 } else if(mystrcasecmp(token
, "html")) {
3670 tPtr
->flags
.parsingHTML
= !open
;
3672 } else if(mystrcasecmp(token
, "align"))
3674 else if(mystrcasecmp(token
, "img")) {
3679 while(*token
== ' ') token
++;
3681 switch(TOLOWER(*token
)) {
3683 if(TOLOWER(*(1+token
)) == 'r' && TOLOWER(*(2+token
)) == 'c') {
3684 mark
= strchr(token
, '=');
3686 char img
[256], *iptr
;
3689 sscanf(token
, "%s", img
);
3691 if(*img
== '\"') { img
[strlen(img
)-1] = 0; iptr
++;}
3692 pixmap
= WMCreatePixmapFromFile(scr
, iptr
);
3694 tb
= WMCreateTextBlockWithPixmap(tPtr
, pixmap
,
3695 iptr
, cfmt
.ccolor
, cfmt
.first
, 0);
3696 // WMSetTextBlockProperties(tb, cfmt.first,
3697 // False, (cfmt.u?1:0), 0, cfmt.margins);
3698 WMAppendTextBlock(tPtr
, tb
);
3701 //printf("[%s]\n", iptr);
3702 } } break; } } while(*(token
++));
3704 } else if(mystrcasecmp(token
, "font")) {
3707 cfmt
.cfont
= (WMFont
*)WMGetFromBag(cfmt
.fonts
,
3708 WMGetBagItemCount(cfmt
.fonts
)-1);
3710 (WMColor
*)WMGetFromBag(cfmt
.colors
,
3711 WMGetBagItemCount(cfmt
.colors
)-1),
3714 else if(mystrcasecmp(token
, "center")) {
3716 if(open
) cfmt
.align
= WALeft
;
3717 else cfmt
.align
= WACenter
;
3726 //printf("parse token (%s)[%s]\n", open?"close":"open", token);
3729 //while(*token && !isspace(*(token))) token++;
3730 //printf("A:%d a:%d z%d Z%d\n", '1', 'a', 'Z', 'z');
3733 if(c
>=65 && c
<=122) { major
[i
++] = c
;
3734 } else if(c
==' ' || c
=='='){ major
[i
] = 0; i
=0; mm
=1;
3735 printf("\nmajor: [%s]", major
);}
3739 } else { minor
[i
] = 0; i
=0; printf(" minor: [%s] ", minor
);}
3741 }while((c
= *(++token
)));
3745 //printf("parse token (%s)[%s]\n", open?"close":"open", token);