2 /* WINGs WMText: multi-line/font/color/graphic text widget, by Nwanua. */
6 #include <X11/keysym.h>
13 * - FIX wrap... long lines that don't fit are not char wrapped yet.
14 * - hrm... something to do with already having tbs...
15 * - selection code... selects can be funny if it crosses over. use rect?
16 *- also inspect behaviour for WACenter and WARight
17 * - FIX: graphix blocks MUST be skipped if monoFont even though they exist!
18 * - check if support for Horizontal Scroll is complete
19 * - FIX html parser: 1. <b>foo</i> should STILL BE BOLD!
20 * - 2. " foo > bar " should not confuse it.
21 * - assess danger of destroying widgets whose actions link to other pages
22 * - Tabs now are simply replaced by 4 spaces...
23 * - redo blink code to reduce paint event... use pixmap buffer...
24 * - add paragraph support (full) and '\n' code in getStream..
28 /* a Section is a section of a TextBlock that describes what parts
29 of a TextBlock has been laid out on which "line"...
30 o this greatly aids redraw, scroll and selection.
31 o this is created during layoutLine, but may be later modified.
32 o there may be many Sections per TextBlock, hence the array */
34 unsigned int x
, y
; /* where to draw it from */
35 unsigned short w
, h
; /* its width and height */
36 unsigned short begin
; /* where the layout begins */
37 unsigned short end
; /* where it ends */
38 unsigned short max_d
; /* a quick hack for layOut if(laidOut) */
39 unsigned short last
:1; /* is it the last section on a "line"? */
40 unsigned int _y
:31; /* the "line" it and other textblocks are on */
44 /* a TextBlock is a doubly-linked list of TextBlocks containing:
45 o text for the block, color and font
46 o or a pointer to the pixmap
47 o OR a pointer to the widget and the (text) description for its graphic
50 typedef struct _TextBlock
{
51 struct _TextBlock
*next
; /* next text block in linked list */
52 struct _TextBlock
*prior
; /* prior text block in linked list */
54 char *text
; /* pointer to text (could be kanji) */
55 /* or to the object's description */
57 WMFont
*font
; /* the font */
58 WMWidget
*widget
; /* the embedded widget */
59 WMPixmap
*pixmap
; /* the pixmap */
60 } d
; /* description */
62 unsigned short used
; /* number of chars in this block */
63 unsigned short allocated
; /* size of allocation (in chars) */
64 WMColor
*color
; /* the color */
66 Section
*sections
; /* the region for layouts (a growable array) */
67 /* an _array_! of size _nsections_ */
69 unsigned short s_begin
; /* where the selection begins */
70 unsigned short s_end
; /* where it ends */
72 unsigned int first
:1; /* first TextBlock in paragraph */
73 unsigned int blank
:1; /* ie. blank paragraph */
74 unsigned int kanji
:1; /* is of 16-bit characters or not */
75 unsigned int graphic
:1; /* graphic or text: text=0 */
76 unsigned int object
:1; /* embedded object or pixmap */
77 unsigned int underlined
:1; /* underlined or not */
78 unsigned int selected
:1; /* selected or not */
79 unsigned int nsections
:8; /* over how many "lines" a TextBlock wraps */
80 int script
:8; /* script in points: negative for subscript */
81 unsigned int marginN
:8; /* which of the margins in the tPtr to use */
82 unsigned int nClicks
:2; /* single, double, triple clicks */
83 unsigned int RESERVED
:7;
87 /* I'm lazy: visible.h vs. visible.size.height :-) */
96 typedef struct W_Text
{
97 W_Class widgetClass
; /* the class number of this widget */
98 W_View
*view
; /* the view referring to this instance */
100 WMRuler
*ruler
; /* the ruler widget to manipulate paragraphs */
102 WMScroller
*vS
; /* the vertical scroller */
103 unsigned int vpos
; /* the current vertical position */
104 unsigned int prevVpos
; /* the previous vertical position */
106 WMScroller
*hS
; /* the horizontal scroller */
107 unsigned int hpos
; /* the current horizontal position */
108 unsigned int prevHpos
; /* the previous horizontal position */
110 WMFont
*dFont
; /* the default font */
111 WMColor
*dColor
; /* the default color */
112 WMPixmap
*dBulletPix
; /* the default pixmap for bullets */
114 GC bgGC
; /* the background GC to draw with */
115 GC fgGC
; /* the foreground GC to draw with */
116 Pixmap db
; /* the buffer on which to draw */
118 myRect visible
; /* the actual rectangle that can be drawn into */
119 myRect cursor
; /* the position and (height) of cursor */
120 myRect sel
; /* the selection rectangle */
122 WMPoint clicked
; /* where in the _document_ was clicked */
124 unsigned short tpos
; /* the position in the currentTextBlock */
125 unsigned short docWidth
; /* the width of the entire document */
126 unsigned int docHeight
; /* the height of the entire document */
128 TextBlock
*firstTextBlock
;
129 TextBlock
*lastTextBlock
;
130 TextBlock
*currentTextBlock
;
132 WMArray
*gfxItems
; /* a nice array of graphic items */
135 WMHandlerID timerID
; /* for nice twinky-winky */
140 WMTextDelegate
*delegate
;
143 WMRulerMargins
*margins
; /* an array of margins */
145 unsigned int nMargins
:8; /* the total number of margins in use */
147 unsigned int monoFont
:1; /* whether to ignore formats and graphic */
148 unsigned int focused
:1; /* whether this instance has input focus */
149 unsigned int editable
:1; /* "silly user, you can't edit me" */
150 unsigned int ownsSelection
:1; /* "I ownz the current selection!" */
151 unsigned int pointerGrabbed
:1;/* "heh, gib me pointer" */
152 unsigned int extendSelection
:1; /* shift-drag to select more regions */
154 unsigned int rulerShown
:1; /* whether the ruler is shown or not */
155 unsigned int frozen
:1; /* whether screen updates are to be made */
156 unsigned int cursorShown
:1; /* whether to show the cursor */
157 unsigned int acceptsGraphic
:1;/* accept graphic when dropped */
158 unsigned int horizOnDemand
:1;/* if a large image should appear*/
159 unsigned int needsLayOut
:1; /* in case of Append/Deletes */
160 unsigned int ignoreNewLine
:1;/* turn it into a ' ' in streams > 1 */
161 unsigned int laidOut
:1; /* have the TextBlocks all been laid out */
162 unsigned int waitingForSelection
:1; /* I don't wanna wait in vain... */
163 unsigned int prepend
:1; /* prepend=1, append=0 (for parsers) */
164 WMAlignment alignment
:2; /* the alignment for text */
165 WMReliefType relief
:3; /* the relief to display with */
166 unsigned int isOverGraphic
:2;/* the mouse is over a graphic */
167 unsigned int RESERVED
:1;
172 #define NOTIFY(T,C,N,A) { WMNotification *notif = WMCreateNotification(N,T,A);\
173 if ((T)->delegate && (T)->delegate->C)\
174 (*(T)->delegate->C)((T)->delegate,notif);\
175 WMPostNotification(notif);\
176 WMReleaseNotification(notif);}
182 output(char *ptr
, int len
)
187 /* printf(" s is [%s] (%d)\n", s, strlen(s)); */
193 #define CURSOR_BLINK_ON_DELAY 600
194 #define CURSOR_BLINK_OFF_DELAY 400
197 static char *default_bullet
[] = {
199 " c None s None", ". c black",
200 "X c white", "o c #808080",
208 static void handleEvents(XEvent
*event
, void *data
);
209 static void layOutDocument(Text
*tPtr
);
210 static void updateScrollers(Text
*tPtr
);
214 getMarginNumber(Text
*tPtr
, WMRulerMargins
*margins
)
218 for(i
=0; i
< tPtr
->nMargins
; i
++) {
220 if(WMIsMarginEqualToMargin(&tPtr
->margins
[i
], margins
))
230 newMargin(Text
*tPtr
, WMRulerMargins
*margins
)
235 tPtr
->margins
[0].retainCount
++;
239 n
= getMarginNumber(tPtr
, margins
);
243 tPtr
->margins
= wrealloc(tPtr
->margins
,
244 (++tPtr
->nMargins
)*sizeof(WMRulerMargins
));
246 n
= tPtr
->nMargins
-1;
247 tPtr
->margins
[n
].left
= margins
->left
;
248 tPtr
->margins
[n
].first
= margins
->first
;
249 tPtr
->margins
[n
].body
= margins
->body
;
250 tPtr
->margins
[n
].right
= margins
->right
;
251 /* for each tab... */
252 tPtr
->margins
[n
].retainCount
= 1;
254 tPtr
->margins
[n
].retainCount
++;
261 sectionWasSelected(Text
*tPtr
, TextBlock
*tb
, XRectangle
*rect
, int s
)
263 unsigned short i
, w
, lw
, selected
= False
, extend
= False
;
267 /* if selection rectangle completely encloses the section */
268 if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
269 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
270 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
272 sel
.w
= tPtr
->visible
.w
;
273 selected
= extend
= True
;
275 /* or if it starts on a line and then goes further down */
276 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
277 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
278 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
279 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
280 >= tPtr
->visible
.y
+ tPtr
->sel
.y
) ) {
281 sel
.x
= WMAX(tPtr
->sel
.x
, tPtr
->clicked
.x
);
282 sel
.w
= tPtr
->visible
.w
;
283 selected
= extend
= True
;
285 /* or if it begins before a line, but ends on it */
286 } else if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
287 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
288 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
289 && (tb
->sections
[s
]._y
290 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
292 if (1||tPtr
->sel
.x
+ tPtr
->sel
.w
> tPtr
->clicked
.x
)
293 sel
.w
= tPtr
->sel
.x
+ tPtr
->sel
.w
;
300 /* or if the selection rectangle lies entirely within a line */
301 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
302 && (tPtr
->sel
.w
>= 2)
303 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
304 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
313 /* if not within (modified) selection rectangle */
314 if ( tb
->sections
[s
].x
> sel
.x
+ sel
.w
315 || tb
->sections
[s
].x
+ tb
->sections
[s
].w
< sel
.x
)
319 if ( tb
->sections
[s
].x
+ tb
->sections
[s
].w
<= sel
.x
+ sel
.w
320 && tb
->sections
[s
].x
>= sel
.x
) {
321 rect
->width
= tb
->sections
[s
].w
;
322 rect
->x
= tb
->sections
[s
].x
;
327 i
= tb
->sections
[s
].begin
;
330 if (0&& tb
->sections
[s
].x
>= sel
.x
) {
331 tb
->s_begin
= tb
->sections
[s
].begin
;
335 while (++i
<= tb
->sections
[s
].end
) {
337 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
340 if (lw
+ tb
->sections
[s
].x
>= sel
.x
341 || i
== tb
->sections
[s
].end
) {
344 tb
->s_begin
= (tb
->selected
? WMIN(tb
->s_begin
, i
) : i
);
349 if (i
> tb
->sections
[s
].end
) {
350 printf("WasSelected: (i > tb->sections[s].end) \n");
354 _selEnd
: rect
->x
= tb
->sections
[s
].x
+ lw
;
356 while(++i
<= tb
->sections
[s
].end
) {
358 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
361 if (lw
+ rect
->x
>= sel
.x
+ sel
.w
362 || i
== tb
->sections
[s
].end
) {
364 if (i
!= tb
->sections
[s
].end
) {
370 if (tb
->sections
[s
].last
&& sel
.x
+ sel
.w
371 >= tb
->sections
[s
].x
+ tb
->sections
[s
].w
373 rect
->width
+= (tPtr
->visible
.w
- rect
->x
- lw
);
376 tb
->s_end
= (tb
->selected
? WMAX(tb
->s_end
, i
) : i
);
382 rect
->y
= tb
->sections
[s
]._y
- tPtr
->vpos
;
383 rect
->height
= tb
->sections
[s
].h
;
384 if(tb
->graphic
) { printf("graphic s%d h%d\n", s
,tb
->sections
[s
].h
);}
391 setSelectionProperty(WMText
*tPtr
, WMFont
*font
, WMColor
*color
, int underlined
)
396 tb
= tPtr
->firstTextBlock
;
397 if (!tb
|| !tPtr
->flags
.ownsSelection
)
400 if(font
&& (!color
|| underlined
==-1))
404 if (tPtr
->flags
.monoFont
|| tb
->selected
) {
406 if (tPtr
->flags
.monoFont
|| (tb
->s_end
- tb
->s_begin
== tb
->used
)
411 WMReleaseFont(tb
->d
.font
);
412 tb
->d
.font
= WMRetainFont(font
);
414 } else if(underlined
!=-1) {
415 tb
->underlined
= underlined
;
417 WMReleaseColor(tb
->color
);
418 tb
->color
= WMRetainColor(color
);
421 } else if (tb
->s_end
<= tb
->used
&& tb
->s_begin
< tb
->s_end
) {
423 TextBlock
*midtb
, *otb
= tb
;
425 if(underlined
!= -1) {
426 midtb
= (TextBlock
*) WMCreateTextBlockWithText(tPtr
,
427 &(tb
->text
[tb
->s_begin
]), tb
->d
.font
, tb
->color
,
428 False
, (tb
->s_end
- tb
->s_begin
));
430 midtb
= (TextBlock
*) WMCreateTextBlockWithText(tPtr
,
431 &(tb
->text
[tb
->s_begin
]),
432 (isFont
?font
:tb
->d
.font
),
433 (isFont
?tb
->color
:color
),
434 False
, (tb
->s_end
- tb
->s_begin
));
439 if(underlined
!= -1) {
440 midtb
->underlined
= underlined
;
442 midtb
->underlined
= otb
->underlined
;
445 midtb
->selected
= !True
;
447 midtb
->s_end
= midtb
->used
;
448 tPtr
->currentTextBlock
= tb
;
449 WMAppendTextBlock(tPtr
, midtb
);
450 tb
= tPtr
->currentTextBlock
;
453 if (otb
->used
- otb
->s_end
> 0) {
456 WMCreateTextBlockWithText(tPtr
,
457 &(otb
->text
[otb
->s_end
]), otb
->d
.font
, otb
->color
,
458 False
, otb
->used
- otb
->s_end
);
461 ntb
->underlined
= otb
->underlined
;
462 ntb
->selected
= False
;
463 WMAppendTextBlock(tPtr
, ntb
);
464 tb
= tPtr
->currentTextBlock
;
469 tPtr
->currentTextBlock
= midtb
;
472 otb
->selected
= False
;
473 otb
->used
= otb
->s_begin
;
480 tPtr
->flags
.needsLayOut
= True
;
483 /* in case the size changed... */
484 if(isFont
&& tPtr
->currentTextBlock
) {
485 TextBlock
*tb
= tPtr
->currentTextBlock
;
487 printf("%d %d %d\n", tPtr
->sel
.y
, tPtr
->sel
.h
, tPtr
->sel
.w
);
488 tPtr
->sel
.y
= 3 + tb
->sections
[0]._y
;
489 tPtr
->sel
.h
= tb
->sections
[tb
->nsections
-1]._y
- tb
->sections
[0]._y
;
490 tPtr
->sel
.w
= tb
->sections
[tb
->nsections
-1].w
;
491 if(tb
->sections
[tb
->nsections
-1]._y
!= tb
->sections
[0]._y
) {
494 printf("%d %d %d\n\n\n", tPtr
->sel
.y
, tPtr
->sel
.h
, tPtr
->sel
.w
);
501 removeSelection(Text
*tPtr
)
503 TextBlock
*tb
= NULL
;
506 if (!(tb
= tPtr
->firstTextBlock
))
511 if(!first
&& !tb
->graphic
) {
512 WMReleaseFont(tPtr
->dFont
);
513 tPtr
->dFont
= WMRetainFont(tb
->d
.font
);
517 if ( (tb
->s_end
- tb
->s_begin
== tb
->used
) || tb
->graphic
) {
518 tPtr
->currentTextBlock
= tb
;
519 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
520 tb
= tPtr
->currentTextBlock
;
525 } else if (tb
->s_end
<= tb
->used
) {
526 memmove(&(tb
->text
[tb
->s_begin
]),
527 &(tb
->text
[tb
->s_end
]), tb
->used
- tb
->s_end
);
528 tb
->used
-= (tb
->s_end
- tb
->s_begin
);
529 tb
->selected
= False
;
530 tPtr
->tpos
= tb
->s_begin
;
541 getFirstNonGraphicBlockFor(TextBlock
*tb
, short dir
)
543 TextBlock
*hold
= tb
;
551 tb
= (dir
? tb
->next
: tb
->prior
);
559 tb
= (dir
? tb
->prior
: tb
->next
);
570 updateStartForCurrentTextBlock(Text
*tPtr
, int x
, int y
, int *dir
,
573 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
574 tb
= getFirstNonGraphicBlockFor(tb
, *dir
);
576 tPtr
->currentTextBlock
=
577 (dir
? tPtr
->lastTextBlock
: tPtr
->firstTextBlock
);
583 *dir
= !(y
<= tb
->sections
[0].y
);
585 if ( ( y
<= tb
->sections
[0]._y
+ tb
->sections
[0].h
)
586 && (y
>= tb
->sections
[0]._y
) ) {
587 /* if it's on the same line */
588 if(x
< tb
->sections
[0].x
)
592 if ( ( y
<= tb
->sections
[tb
->nsections
-1]._y
593 + tb
->sections
[tb
->nsections
-1].h
)
594 && (y
>= tb
->sections
[tb
->nsections
-1]._y
) ) {
595 /* if it's on the same line */
596 if(x
> tb
->sections
[tb
->nsections
-1].x
)
606 paintText(Text
*tPtr
)
612 int len
, y
, c
, s
, done
=False
, prev_y
=-23, dir
/* 1 = down */;
613 WMScreen
*scr
= tPtr
->view
->screen
;
614 Display
*dpy
= tPtr
->view
->screen
->display
;
615 Window win
= tPtr
->view
->window
;
617 if (!tPtr
->view
->flags
.realized
|| !tPtr
->db
|| tPtr
->flags
.frozen
)
620 XFillRectangle(dpy
, tPtr
->db
, tPtr
->bgGC
,
621 0, 0, tPtr
->visible
.w
, tPtr
->visible
.h
);
623 if (! (tb
= tPtr
->currentTextBlock
)) {
624 if (! (tb
= tPtr
->firstTextBlock
)) {
629 if (tPtr
->flags
.ownsSelection
)
630 greyGC
= WMColorGC(WMGrayColor(scr
));
635 /* first, which direction? Don't waste time looking all over,
636 since the parts to be drawn will most likely be near what
637 was previously drawn */
638 if(!updateStartForCurrentTextBlock(tPtr
, 0, tPtr
->vpos
, &dir
, tb
))
643 if (tb
->graphic
&& tPtr
->flags
.monoFont
)
647 if(tPtr
->vpos
<= tb
->sections
[tb
->nsections
-1]._y
648 + tb
->sections
[tb
->nsections
-1].h
)
651 if(tPtr
->vpos
>= tb
->sections
[tb
->nsections
-1]._y
652 + tb
->sections
[tb
->nsections
-1].h
)
669 /* first, place all text that can be viewed */
670 while (!done
&& tb
) {
672 if(tb
->blank
) {tb
->text
[0] = 'F'; }
679 tb
->selected
= False
;
681 for(s
=0; s
<tb
->nsections
&& !done
; s
++) {
683 if (tb
->sections
[s
]._y
> tPtr
->vpos
+ tPtr
->visible
.h
) {
688 if ( tb
->sections
[s
].y
+ tb
->sections
[s
].h
< tPtr
->vpos
)
691 if (tPtr
->flags
.monoFont
) {
696 gc
= WMColorGC(tb
->color
);
699 if (tPtr
->flags
.ownsSelection
) {
702 if ( sectionWasSelected(tPtr
, tb
, &rect
, s
)) {
704 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
705 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
709 prev_y
= tb
->sections
[s
]._y
;
711 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
712 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
713 y
= tb
->sections
[s
].y
- tPtr
->vpos
;
714 WMDrawString(scr
, tPtr
->db
, gc
, font
,
715 tb
->sections
[s
].x
- tPtr
->hpos
, y
, text
, len
);
717 if (tb
->underlined
) {
718 XDrawLine(dpy
, tPtr
->db
, gc
,
719 tb
->sections
[s
].x
- tPtr
->hpos
,
721 tb
->sections
[s
].x
+ tb
->sections
[s
].w
- tPtr
->hpos
,
727 tb
= (!done
? tb
->next
: NULL
);
731 /* now , show all graphic items that can be viewed */
732 c
= WMGetArrayItemCount(tPtr
->gfxItems
);
733 if (c
> 0 && !tPtr
->flags
.monoFont
) {
737 tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
);
739 /* if it's not viewable, and mapped, unmap it */
740 if (tb
->sections
[0]._y
+ tb
->sections
[0].h
<= tPtr
->vpos
741 || tb
->sections
[0]._y
>= tPtr
->vpos
+ tPtr
->visible
.h
) {
744 if ((W_VIEW(tb
->d
.widget
))->flags
.mapped
) {
745 WMUnmapWidget(tb
->d
.widget
);
749 /* if it's viewable, and not mapped, map it */
751 W_View
*view
= W_VIEW(tb
->d
.widget
);
753 if (!view
->flags
.realized
)
754 WMRealizeWidget(tb
->d
.widget
);
755 if(!view
->flags
.mapped
) {
756 XMapWindow(view
->screen
->display
, view
->window
);
757 XFlush(view
->screen
->display
);
758 view
->flags
.mapped
= 1;
762 if (tPtr
->flags
.ownsSelection
) {
765 if ( sectionWasSelected(tPtr
, tb
, &rect
, 0)) {
767 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
768 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
773 WMMoveWidget(tb
->d
.widget
,
774 tb
->sections
[0].x
+ tPtr
->visible
.x
- tPtr
->hpos
,
775 tb
->sections
[0].y
+ tPtr
->visible
.y
- tPtr
->vpos
);
776 h
= WMWidgetHeight(tb
->d
.widget
) + 1;
779 WMDrawPixmap(tb
->d
.pixmap
, tPtr
->db
,
780 tb
->sections
[0].x
- tPtr
->hpos
,
781 tb
->sections
[0].y
- tPtr
->vpos
);
782 h
= tb
->d
.pixmap
->height
+ 1;
786 if (tb
->underlined
) {
787 XDrawLine(dpy
, tPtr
->db
, WMColorGC(tb
->color
),
788 tb
->sections
[0].x
- tPtr
->hpos
,
789 tb
->sections
[0].y
+ h
- tPtr
->vpos
,
790 tb
->sections
[0].x
+ tb
->sections
[0].w
- tPtr
->hpos
,
791 tb
->sections
[0].y
+ h
- tPtr
->vpos
);
796 if (tPtr
->flags
.editable
&& tPtr
->flags
.cursorShown
797 && tPtr
->cursor
.x
!= -23 && tPtr
->flags
.focused
) {
798 int y
= tPtr
->cursor
.y
- tPtr
->vpos
;
799 XDrawLine(dpy
, tPtr
->db
, tPtr
->fgGC
,
801 tPtr
->cursor
.x
, y
+ tPtr
->cursor
.h
);
804 XCopyArea(dpy
, tPtr
->db
, win
, tPtr
->bgGC
, 0, 0,
805 tPtr
->visible
.w
, tPtr
->visible
.h
,
806 tPtr
->visible
.x
, tPtr
->visible
.y
);
808 W_DrawRelief(scr
, win
, 0, 0,
809 tPtr
->view
->size
.width
, tPtr
->view
->size
.height
,
812 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)
813 XDrawLine(dpy
, win
, tPtr
->fgGC
,
814 2, 42, tPtr
->view
->size
.width
-4, 42);
819 mouseOverObject(Text
*tPtr
, int x
, int y
)
824 x
-= tPtr
->visible
.x
;
826 y
-= tPtr
->visible
.y
;
829 if(tPtr
->flags
.ownsSelection
) {
832 && tPtr
->sel
.x
+ tPtr
->sel
.w
>= x
833 && tPtr
->sel
.y
+ tPtr
->sel
.h
>= y
) {
834 tPtr
->flags
.isOverGraphic
= 1;
841 int j
, c
= WMGetArrayItemCount(tPtr
->gfxItems
);
844 tPtr
->flags
.isOverGraphic
= 0;
849 tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
);
851 if(!tb
|| !tb
->sections
) {
852 tPtr
->flags
.isOverGraphic
= 0;
857 if(tb
->sections
[0].x
<= x
858 && tb
->sections
[0].y
<= y
859 && tb
->sections
[0].x
+ tb
->sections
[0].w
>= x
860 && tb
->sections
[0].y
+ tb
->d
.pixmap
->height
>= y
) {
861 tPtr
->flags
.isOverGraphic
= 3;
871 tPtr
->flags
.isOverGraphic
= 0;
873 tPtr
->view
->attribs
.cursor
= (result
?
874 tPtr
->view
->screen
->defaultCursor
875 : tPtr
->view
->screen
->textCursor
);
877 XSetWindowAttributes attribs
;
878 attribs
.cursor
= tPtr
->view
->attribs
.cursor
;
879 XChangeWindowAttributes(tPtr
->view
->screen
->display
,
880 tPtr
->view
->window
, CWCursor
,
888 blinkCursor(void *data
)
890 Text
*tPtr
= (Text
*)data
;
892 if (tPtr
->flags
.cursorShown
) {
893 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY
,
896 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
,
900 tPtr
->flags
.cursorShown
= !tPtr
->flags
.cursorShown
;
905 updateCursorPosition(Text
*tPtr
)
907 TextBlock
*tb
= NULL
;
910 if(tPtr
->flags
.needsLayOut
)
911 layOutDocument(tPtr
);
913 if (! (tb
= tPtr
->currentTextBlock
)) {
914 if (! (tb
= tPtr
->firstTextBlock
)) {
916 tPtr
->cursor
.h
= tPtr
->dFont
->height
;
926 y
= tb
->sections
[0].y
;
927 h
= tb
->sections
[0].h
;
928 x
= tb
->sections
[0].x
;
930 } else if(tb
->graphic
) {
931 y
= tb
->sections
[0].y
;
932 h
= tb
->sections
[0].h
;
933 x
= tb
->sections
[0].x
;
936 if(tPtr
->tpos
> tb
->used
)
937 tPtr
->tpos
= tb
->used
;
939 for(s
=0; s
<tb
->nsections
; s
++) {
941 if(tPtr
->tpos
>= tb
->sections
[s
].begin
942 && tPtr
->tpos
<= tb
->sections
[s
].end
)
946 y
= tb
->sections
[s
]._y
;
947 h
= tb
->sections
[s
].h
;
948 x
= tb
->sections
[s
].x
+ WMWidthOfString(
949 (tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
),
950 &tb
->text
[tb
->sections
[s
].begin
],
951 tPtr
->tpos
- tb
->sections
[s
].begin
);
958 // printf("y:%d vpos%d\n", y,
959 //tPtr->vpos-tPtr->visible.h+tPtr->visible.y);
960 // tPtr->vpos = y - tPtr->visible.y;
961 updateScrollers(tPtr
);
966 cursorToTextPosition(Text
*tPtr
, int x
, int y
)
968 TextBlock
*tb
= NULL
;
969 int done
=False
, s
, pos
, len
, _w
, _y
, dir
=1; /* 1 == "down" */
972 if(tPtr
->flags
.needsLayOut
)
973 layOutDocument(tPtr
);
975 y
+= (tPtr
->vpos
- tPtr
->visible
.y
);
979 x
-= (tPtr
->visible
.x
- 2);
983 /* clicked is relative to document, not window... */
987 if (! (tb
= tPtr
->currentTextBlock
)) {
988 if (! (tb
= tPtr
->firstTextBlock
)) {
990 tPtr
->cursor
.h
= tPtr
->dFont
->height
;
997 /* first, which direction? Most likely, newly clicked
998 position will be close to previous */
999 if(!updateStartForCurrentTextBlock(tPtr
, x
, y
, &dir
, tb
))
1003 s
= (dir
? 0 : tb
->nsections
-1);
1004 if ( y
>= tb
->sections
[s
]._y
1005 && y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) {
1009 /* get the first (or last) section of the TextBlock that
1010 lies about the vertical click point */
1012 while (!done
&& tb
) {
1014 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1015 if( (dir
?tb
->next
:tb
->prior
))
1016 tb
= (dir
?tb
->next
:tb
->prior
);
1020 s
= (dir
? 0 : tb
->nsections
-1);
1021 while (!done
&& (dir
? (s
<tb
->nsections
) : (s
>=0) )) {
1023 if ( (dir
? (y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) :
1024 ( y
>= tb
->sections
[s
]._y
) ) ) {
1032 if ( (dir
? tb
->next
: tb
->prior
)) {
1033 tb
= (dir
? tb
->next
: tb
->prior
);
1036 break; /* goto _doneH; */
1042 if (s
<0 || s
>=tb
->nsections
) {
1043 s
= (dir
? tb
->nsections
-1 : 0);
1047 /* we have the line, which TextBlock on that line is it? */
1048 pos
= (dir
?0:tb
->sections
[s
].begin
);
1049 if (tPtr
->flags
.monoFont
&& tb
->graphic
)
1050 tb
= getFirstNonGraphicBlockFor(tb
, dir
);
1055 _y
= tb
->sections
[s
]._y
;
1059 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1060 tb
= (dir
? tb
->next
: tb
->prior
);
1067 _w
= WMWidgetWidth(tb
->d
.widget
)-5;
1069 _w
= tb
->d
.pixmap
->width
-5;
1071 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
1072 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
1073 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
1074 if (tb
->sections
[s
].x
+ _w
>= x
)
1079 if (tb
->sections
[s
].x
<= x
)
1086 if ((dir
? tb
->next
: tb
->prior
)) {
1087 TextBlock
*nxt
= (dir
? tb
->next
: tb
->prior
);
1088 if (tPtr
->flags
.monoFont
&& nxt
->graphic
) {
1089 nxt
= getFirstNonGraphicBlockFor(nxt
, dir
);
1091 pos
= (dir
?0:tb
->sections
[s
].begin
);
1092 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
1097 if (_y
!= nxt
->sections
[dir
?0:nxt
->nsections
-1]._y
) {
1098 /* this must be the last/first on this line. stop */
1099 pos
= (dir
? tb
->sections
[s
].end
: 0);
1100 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
1104 tPtr
->cursor
.x
+= WMWidgetWidth(tb
->d
.widget
);
1106 tPtr
->cursor
.x
+= tb
->d
.pixmap
->width
;
1107 } else if (pos
> tb
->sections
[s
].begin
) {
1109 WMWidthOfString(tb
->d
.font
,
1110 &(tb
->text
[tb
->sections
[s
].begin
]),
1111 pos
- tb
->sections
[s
].begin
);
1118 if ( (dir
? tb
->next
: tb
->prior
)) {
1119 tb
= (dir
? tb
->next
: tb
->prior
);
1126 s
= (dir
? 0 : tb
->nsections
-1);
1129 /* we have said TextBlock, now where within it? */
1130 if (tb
&& !tb
->graphic
) {
1131 WMFont
*f
= tb
->d
.font
;
1132 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
1133 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
1135 _w
= x
- tb
->sections
[s
].x
;
1138 while (pos
<len
&& WMWidthOfString(f
, text
, pos
+1) < _w
)
1141 tPtr
->cursor
.x
= tb
->sections
[s
].x
+
1142 (pos
? WMWidthOfString(f
, text
, pos
) : 0);
1144 pos
+= tb
->sections
[s
].begin
;
1146 tPtr
->tpos
= (pos
<tb
->used
)? pos
: tb
->used
;
1150 printf("...for this app will surely crash :-)\n");
1152 tPtr
->currentTextBlock
= tb
;
1153 tPtr
->cursor
.h
= tb
->sections
[s
].h
;
1154 tPtr
->cursor
.y
= tb
->sections
[s
]._y
;
1159 autoSelectText(Text
*tPtr
, int clicks
)
1163 char *mark
= NULL
, behind
, ahead
;
1165 if(!(tb
= tPtr
->currentTextBlock
))
1171 switch(tb
->text
[tPtr
->tpos
]) {
1174 case '<': case '>': behind = '<'; ahead = '>'; break;
1175 case '{': case '}': behind = '{'; ahead = '}'; break;
1176 case '[': case ']': behind = '['; ahead = ']'; break;
1178 default: behind
= ahead
= ' ';
1181 tPtr
->sel
.y
= tPtr
->cursor
.y
+5;
1182 tPtr
->sel
.h
= 6;/*tPtr->cursor.h-10;*/
1185 tPtr
->sel
.x
= tb
->sections
[0].x
;
1186 tPtr
->sel
.w
= tb
->sections
[0].w
;
1188 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
1191 while(start
> 0 && tb
->text
[start
-1] != behind
)
1195 if(tPtr
->tpos
> start
){
1196 x
-= WMWidthOfString(font
, &tb
->text
[start
],
1197 tPtr
->tpos
- start
);
1199 tPtr
->sel
.x
= (x
<0?0:x
)+1;
1201 if((mark
= strchr(&tb
->text
[start
], ahead
))) {
1202 tPtr
->sel
.w
= WMWidthOfString(font
, &tb
->text
[start
],
1203 (int)(mark
- &tb
->text
[start
]));
1204 } else if(tb
->used
> start
) {
1205 tPtr
->sel
.w
= WMWidthOfString(font
, &tb
->text
[start
],
1210 } else if(clicks
== 3) {
1211 TextBlock
*cur
= tb
;
1213 while(tb
&& !tb
->first
) {
1216 tPtr
->sel
.y
= tb
->sections
[0]._y
;
1219 while(tb
->next
&& !tb
->next
->first
) {
1222 tPtr
->sel
.h
= tb
->sections
[tb
->nsections
-1]._y
1226 tPtr
->sel
.w
= tPtr
->docWidth
;
1227 tPtr
->clicked
.x
= 0; /* only for now, fix sel. code */
1230 tPtr
->flags
.ownsSelection
= True
;
1237 updateScrollers(Text
*tPtr
)
1240 if (tPtr
->flags
.frozen
)
1244 if (tPtr
->docHeight
< tPtr
->visible
.h
) {
1245 WMSetScrollerParameters(tPtr
->vS
, 0, 1);
1248 float hmax
= (float)(tPtr
->docHeight
);
1249 WMSetScrollerParameters(tPtr
->vS
,
1250 ((float)tPtr
->vpos
)/(hmax
- (float)tPtr
->visible
.h
),
1251 (float)tPtr
->visible
.h
/hmax
);
1253 } else tPtr
->vpos
= 0;
1256 if (tPtr
->docWidth
< tPtr
->visible
.w
) {
1257 WMSetScrollerParameters(tPtr
->hS
, 0, 1);
1260 float wmax
= (float)(tPtr
->docWidth
);
1261 WMSetScrollerParameters(tPtr
->hS
,
1262 ((float)tPtr
->hpos
)/(wmax
- (float)tPtr
->visible
.w
),
1263 (float)tPtr
->visible
.w
/wmax
);
1265 } else tPtr
->hpos
= 0;
1269 scrollersCallBack(WMWidget
*w
, void *self
)
1271 Text
*tPtr
= (Text
*)self
;
1272 Bool scroll
= False
;
1275 if (!tPtr
->view
->flags
.realized
|| tPtr
->flags
.frozen
)
1278 if (w
== tPtr
->vS
) {
1280 height
= tPtr
->visible
.h
;
1282 which
= WMGetScrollerHitPart(tPtr
->vS
);
1285 case WSDecrementLine
:
1286 if (tPtr
->vpos
> 0) {
1287 if (tPtr
->vpos
>16) tPtr
->vpos
-=16;
1292 case WSIncrementLine
: {
1293 int limit
= tPtr
->docHeight
- height
;
1294 if (tPtr
->vpos
< limit
) {
1295 if (tPtr
->vpos
<limit
-16) tPtr
->vpos
+=16;
1296 else tPtr
->vpos
=limit
;
1300 case WSDecrementPage
:
1301 if(((int)tPtr
->vpos
- (int)height
) >= 0)
1302 tPtr
->vpos
-= height
;
1309 case WSIncrementPage
:
1310 tPtr
->vpos
+= height
;
1311 if (tPtr
->vpos
> (tPtr
->docHeight
- height
))
1312 tPtr
->vpos
= tPtr
->docHeight
- height
;
1318 tPtr
->vpos
= WMGetScrollerValue(tPtr
->vS
)
1319 * (float)(tPtr
->docHeight
- height
);
1327 scroll
= (tPtr
->vpos
!= tPtr
->prevVpos
);
1328 tPtr
->prevVpos
= tPtr
->vpos
;
1332 if (w
== tPtr
->hS
) {
1333 int width
= tPtr
->visible
.w
;
1335 which
= WMGetScrollerHitPart(tPtr
->hS
);
1338 case WSDecrementLine
:
1339 if (tPtr
->hpos
> 0) {
1340 if (tPtr
->hpos
>16) tPtr
->hpos
-=16;
1345 case WSIncrementLine
: {
1346 int limit
= tPtr
->docWidth
- width
;
1347 if (tPtr
->hpos
< limit
) {
1348 if (tPtr
->hpos
<limit
-16) tPtr
->hpos
+=16;
1349 else tPtr
->hpos
=limit
;
1353 case WSDecrementPage
:
1354 if(((int)tPtr
->hpos
- (int)width
) >= 0)
1355 tPtr
->hpos
-= width
;
1362 case WSIncrementPage
:
1363 tPtr
->hpos
+= width
;
1364 if (tPtr
->hpos
> (tPtr
->docWidth
- width
))
1365 tPtr
->hpos
= tPtr
->docWidth
- width
;
1371 tPtr
->hpos
= WMGetScrollerValue(tPtr
->hS
)
1372 * (float)(tPtr
->docWidth
- width
);
1380 scroll
= (tPtr
->hpos
!= tPtr
->prevHpos
);
1381 tPtr
->prevHpos
= tPtr
->hpos
;
1385 updateScrollers(tPtr
);
1394 unsigned short begin
, end
; /* what part of the text block */
1399 layOutLine(Text
*tPtr
, myLineItems
*items
, int nitems
, int x
, int y
)
1401 int i
, j
=0, lw
= 0, line_height
=0, max_d
=0, len
, n
;
1405 TextBlock
*tbsame
=NULL
;
1407 if(!items
|| nitems
== 0)
1410 for(i
=0; i
<nitems
; i
++) {
1414 if (!tPtr
->flags
.monoFont
) {
1416 WMWidget
*wdt
= tb
->d
.widget
;
1417 line_height
= WMAX(line_height
, WMWidgetHeight(wdt
));
1418 if (tPtr
->flags
.alignment
!= WALeft
)
1419 lw
+= WMWidgetWidth(wdt
);
1421 line_height
= WMAX(line_height
,
1422 tb
->d
.pixmap
->height
+ max_d
);
1423 if (tPtr
->flags
.alignment
!= WALeft
)
1424 lw
+= tb
->d
.pixmap
->width
;
1429 font
= (tPtr
->flags
.monoFont
)?tPtr
->dFont
: tb
->d
.font
;
1430 max_d
= WMAX(max_d
, abs(font
->height
-font
->y
));
1431 line_height
= WMAX(line_height
, font
->height
+ max_d
);
1432 text
= &(tb
->text
[items
[i
].begin
]);
1433 len
= items
[i
].end
- items
[i
].begin
;
1434 if (tPtr
->flags
.alignment
!= WALeft
)
1435 lw
+= WMWidthOfString(font
, text
, len
);
1439 if (tPtr
->flags
.alignment
== WARight
) {
1440 j
= tPtr
->visible
.w
- lw
;
1441 } else if (tPtr
->flags
.alignment
== WACenter
) {
1442 j
= (int) ((float)(tPtr
->visible
.w
- lw
))/2.0;
1445 for(i
=0; i
<nitems
; i
++) {
1448 if (tbsame
== tb
) { /* extend it, since it's on same line */
1449 tb
->sections
[tb
->nsections
-1].end
= items
[i
].end
;
1450 n
= tb
->nsections
-1;
1452 tb
->sections
= wrealloc(tb
->sections
,
1453 (++tb
->nsections
)*sizeof(Section
));
1454 n
= tb
->nsections
-1;
1455 tb
->sections
[n
]._y
= y
+ max_d
;
1456 tb
->sections
[n
].max_d
= max_d
;
1457 tb
->sections
[n
].x
= x
+j
;
1458 tb
->sections
[n
].h
= line_height
;
1459 tb
->sections
[n
].begin
= items
[i
].begin
;
1460 tb
->sections
[n
].end
= items
[i
].end
;
1463 tb
->sections
[n
].last
= (i
+1 == nitems
);
1466 if (!tPtr
->flags
.monoFont
) {
1468 WMWidget
*wdt
= tb
->d
.widget
;
1469 tb
->sections
[n
].y
= max_d
+ y
1470 + line_height
- WMWidgetHeight(wdt
);
1471 tb
->sections
[n
].w
= WMWidgetWidth(wdt
);
1473 tb
->sections
[n
].y
= y
+ line_height
-tb
->d
.pixmap
->height
+ max_d
;
1474 tb
->sections
[n
].w
= tb
->d
.pixmap
->width
;
1476 x
+= tb
->sections
[n
].w
;
1479 font
= (tPtr
->flags
.monoFont
)? tPtr
->dFont
: tb
->d
.font
;
1480 len
= items
[i
].end
- items
[i
].begin
;
1481 text
= &(tb
->text
[items
[i
].begin
]);
1483 tb
->sections
[n
].y
= y
+line_height
-font
->y
;
1485 WMWidthOfString(font
,
1486 &(tb
->text
[tb
->sections
[n
].begin
]),
1487 tb
->sections
[n
].end
- tb
->sections
[n
].begin
);
1489 x
+= WMWidthOfString(font
, text
, len
);
1501 layOutDocument(Text
*tPtr
)
1504 myLineItems
*items
= NULL
;
1505 unsigned int itemsSize
=0, nitems
=0, begin
, end
;
1507 unsigned int x
, y
=0, lw
= 0, width
=0, bmargin
;
1508 char *start
=NULL
, *mark
=NULL
;
1511 if ( tPtr
->flags
.frozen
|| (!(tb
= tPtr
->firstTextBlock
)) )
1514 tPtr
->docWidth
= tPtr
->visible
.w
;
1515 x
= tPtr
->margins
[tb
->marginN
].first
;
1516 bmargin
= tPtr
->margins
[tb
->marginN
].body
;
1518 /* only partial layOut needed: re-Lay only affected textblocks */
1519 if (tPtr
->flags
.laidOut
) {
1520 tb
= tPtr
->currentTextBlock
;
1522 /* search backwards for textblocks on same line */
1524 if (!tb
->sections
|| tb
->nsections
<1) {
1525 tb
= tPtr
->firstTextBlock
;
1526 tPtr
->flags
.laidOut
= False
;
1531 if(!tb
->prior
->sections
|| tb
->prior
->nsections
<1) {
1532 tb
= tPtr
->firstTextBlock
;
1533 tPtr
->flags
.laidOut
= False
;
1538 if (tb
->sections
[0]._y
!=
1539 tb
->prior
->sections
[tb
->prior
->nsections
-1]._y
) {
1545 /* a hack to get to the bottom, fix */
1549 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
1550 y
-= 2*(font
->height
- tb
->d
.font
->y
);
1554 if(tb
->prior
&& tb
->prior
->sections
&& tb
->prior
->nsections
>0) {
1555 y
= tb
->prior
->sections
[tb
->prior
->nsections
-1]._y
+
1556 tb
->prior
->sections
[tb
->prior
->nsections
-1].h
-
1557 tb
->prior
->sections
[tb
->prior
->nsections
-1].max_d
;
1566 if (tb
->sections
&& tb
->nsections
>0) {
1567 wfree(tb
->sections
);
1568 tb
->sections
= NULL
;
1572 if (tb
->blank
&& tb
->next
&& !tb
->next
->first
) {
1573 TextBlock
*next
= tb
->next
;
1574 tPtr
->currentTextBlock
= tb
;
1575 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1578 printf("yep that was me :-)\n");
1582 if (tb
->first
&& tb
!= tPtr
->firstTextBlock
) {
1583 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1584 x
= tPtr
->margins
[tb
->marginN
].first
;
1585 bmargin
= tPtr
->margins
[tb
->marginN
].body
;
1591 if (!tPtr
->flags
.monoFont
) {
1593 width
= WMWidgetWidth(tb
->d
.widget
);
1595 width
= tb
->d
.pixmap
->width
;
1597 if (width
> tPtr
->docWidth
)
1598 tPtr
->docWidth
= width
;
1601 if (lw
>= tPtr
->visible
.w
- x
) {
1602 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1608 if(nitems
+ 1> itemsSize
) {
1609 items
= wrealloc(items
,
1610 (++itemsSize
)*sizeof(myLineItems
));
1613 items
[nitems
].tb
= tb
;
1614 items
[nitems
].begin
= 0;
1615 items
[nitems
].end
= 0;
1619 } else if ((start
= tb
->text
)) {
1621 font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
1624 mark
= strchr(start
, ' ');//, tb->used);
1626 end
+= (int)(mark
-start
)+1;
1629 end
+= strlen(start
);
1636 if (end
-begin
> 0) {
1638 width
= WMWidthOfString(font
,
1639 &tb
->text
[begin
], end
-begin
);
1641 /* if it won't fit, break it up */
1642 if (width
> tPtr
->visible
.w
) {
1643 char *t
= &tb
->text
[begin
];
1644 int l
=end
-begin
, i
=0;
1646 width
= WMWidthOfString(font
, t
, ++i
);
1647 } while (width
< tPtr
->visible
.w
&& i
< l
);
1656 if (lw
>= tPtr
->visible
.w
- x
) {
1657 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1663 if(nitems
+ 1 > itemsSize
) {
1664 items
= wrealloc(items
,
1665 (++itemsSize
)*sizeof(myLineItems
));
1668 items
[nitems
].tb
= tb
;
1669 items
[nitems
].begin
= begin
;
1670 items
[nitems
].end
= end
;
1678 if(tPtr
->flags
.laidOut
1679 && tb
->next
&& tb
->next
->sections
&& tb
->next
->nsections
>0
1680 && (tPtr
->vpos
+ tPtr
->visible
.h
1681 < tb
->next
->sections
[0]._y
)) {
1682 if(tPtr
->lastTextBlock
->sections
1683 && tPtr
->lastTextBlock
->nsections
> 0 ) {
1684 TextBlock
*ltb
= tPtr
->lastTextBlock
;
1685 int ly
= ltb
->sections
[ltb
->nsections
-1]._y
;
1686 int lh
= ltb
->sections
[ltb
->nsections
-1].h
;
1689 lh
+= 1 + tPtr
->visible
.y
+ ltb
->sections
[ltb
->nsections
-1].max_d
;
1690 printf("it's %d\n", tPtr
->visible
.y
+ ltb
->sections
[ltb
->nsections
-1].max_d
);
1692 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1694 sd
= tPtr
->docHeight
-y
;
1696 printf("dif %d-%d: %d\n", ss
, sd
, ss
-sd
);
1697 y
+= tb
->next
->sections
[0]._y
-y
;
1699 printf("nitems%d\n", nitems
);
1701 y
= tPtr
->docHeight
+ss
-sd
;
1705 tPtr
->flags
.laidOut
= False
;
1714 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1716 if (tPtr
->docHeight
!= y
+10) {
1717 tPtr
->docHeight
= y
+10;
1718 updateScrollers(tPtr
);
1721 if(tPtr
->docWidth
> tPtr
->visible
.w
&& !tPtr
->hS
) {
1724 tPtr
->flags
.horizOnDemand
= True
;
1725 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, True
);
1726 event
.type
= Expose
;
1727 handleEvents(&event
, (void *)tPtr
);
1729 } else if(tPtr
->docWidth
<= tPtr
->visible
.w
1730 && tPtr
->hS
&& tPtr
->flags
.horizOnDemand
) {
1731 tPtr
->flags
.horizOnDemand
= False
;
1732 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, False
);
1735 tPtr
->flags
.laidOut
= True
;
1737 if(items
&& itemsSize
> 0)
1743 textDidResize(W_ViewDelegate
*self
, WMView
*view
)
1745 Text
*tPtr
= (Text
*)view
->self
;
1746 unsigned short w
= tPtr
->view
->size
.width
;
1747 unsigned short h
= tPtr
->view
->size
.height
;
1748 unsigned short rh
= 0, vw
= 0, rel
;
1750 rel
= (tPtr
->flags
.relief
== WRFlat
);
1752 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
) {
1753 WMMoveWidget(tPtr
->ruler
, 2, 2);
1754 WMResizeWidget(tPtr
->ruler
, w
- 4, 40);
1759 WMMoveWidget(tPtr
->vS
, 1 - (rel
?1:0), rh
+ 1 - (rel
?1:0));
1760 WMResizeWidget(tPtr
->vS
, 20, h
- rh
- 2 + (rel
?2:0));
1762 WMSetRulerOffset(tPtr
->ruler
,22);
1763 } else WMSetRulerOffset(tPtr
->ruler
, 2);
1767 WMMoveWidget(tPtr
->hS
, vw
, h
- 21);
1768 WMResizeWidget(tPtr
->hS
, w
- vw
- 1, 20);
1770 WMMoveWidget(tPtr
->hS
, vw
+1, h
- 21);
1771 WMResizeWidget(tPtr
->hS
, w
- vw
- 2, 20);
1775 tPtr
->visible
.x
= (tPtr
->vS
)?24:4;
1776 tPtr
->visible
.y
= (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)?43:3;
1777 tPtr
->visible
.w
= tPtr
->view
->size
.width
- tPtr
->visible
.x
- 8;
1778 tPtr
->visible
.h
= tPtr
->view
->size
.height
- tPtr
->visible
.y
;
1779 tPtr
->visible
.h
-= (tPtr
->hS
)?20:0;
1780 tPtr
->margins
[0].right
= tPtr
->visible
.w
;
1782 if (tPtr
->view
->flags
.realized
) {
1785 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
1786 tPtr
->db
= (Pixmap
) NULL
;
1789 if (tPtr
->visible
.w
< 40)
1790 tPtr
->visible
.w
= 40;
1791 if (tPtr
->visible
.h
< 20)
1792 tPtr
->visible
.h
= 20;
1795 tPtr
->db
= XCreatePixmap(tPtr
->view
->screen
->display
,
1796 tPtr
->view
->window
, tPtr
->visible
.w
,
1797 tPtr
->visible
.h
, tPtr
->view
->screen
->depth
);
1804 W_ViewDelegate _TextViewDelegate
=
1812 /* nice, divisble-by-16 blocks */
1813 static inline unsigned short
1814 reqBlockSize(unsigned short requested
)
1816 return requested
+ 16 - (requested
%16);
1821 clearText(Text
*tPtr
)
1823 if (!tPtr
->firstTextBlock
)
1826 while (tPtr
->currentTextBlock
)
1827 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1829 tPtr
->firstTextBlock
= NULL
;
1830 tPtr
->currentTextBlock
= NULL
;
1831 tPtr
->lastTextBlock
= NULL
;
1835 deleteTextInteractively(Text
*tPtr
, KeySym ksym
)
1838 Bool back
= (Bool
) (ksym
== XK_BackSpace
);
1842 if (!tPtr
->flags
.editable
) {
1843 XBell(tPtr
->view
->screen
->display
, 0);
1847 if ( !(tb
= tPtr
->currentTextBlock
) )
1850 if (tPtr
->flags
.ownsSelection
) {
1851 if(removeSelection(tPtr
))
1852 layOutDocument(tPtr
);
1856 wasFirst
= tb
->first
;
1857 if (back
&& tPtr
->tpos
< 1) {
1859 if(tb
->prior
->blank
) {
1860 tPtr
->currentTextBlock
= tb
->prior
;
1861 WMRemoveTextBlock(tPtr
);
1862 tPtr
->currentTextBlock
= tb
;
1864 layOutDocument(tPtr
);
1868 TextBlock
*prior
= tb
->prior
;
1869 tPtr
->currentTextBlock
= tb
;
1870 WMRemoveTextBlock(tPtr
);
1876 tPtr
->tpos
= tb
->used
;
1877 tPtr
->currentTextBlock
= tb
;
1881 tb
->next
->first
= False
;
1882 layOutDocument(tPtr
);
1889 if ( (tb
->used
> 0) && ((back
?tPtr
->tpos
> 0:1))
1890 && (tPtr
->tpos
<= tb
->used
) && !tb
->graphic
) {
1893 memmove(&(tb
->text
[tPtr
->tpos
]),
1894 &(tb
->text
[tPtr
->tpos
+ 1]), tb
->used
- tPtr
->tpos
);
1899 if ( (back
? (tPtr
->tpos
< 1 && !done
) : ( tPtr
->tpos
>= tb
->used
))
1902 TextBlock
*sibling
= (back
? tb
->prior
: tb
->next
);
1904 if(tb
->used
== 0 || tb
->graphic
)
1905 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1908 tPtr
->currentTextBlock
= sibling
;
1909 tPtr
->tpos
= (back
? sibling
->used
: 0);
1913 layOutDocument(tPtr
);
1918 insertTextInteractively(Text
*tPtr
, char *text
, int len
)
1921 char *newline
= NULL
;
1923 if (!tPtr
->flags
.editable
) {
1924 XBell(tPtr
->view
->screen
->display
, 0);
1928 if (len
< 1 || !text
)
1932 if(tPtr
->flags
.ignoreNewLine
&& *text
== '\n' && len
== 1)
1935 if (tPtr
->flags
.ownsSelection
)
1936 removeSelection(tPtr
);
1939 if (tPtr
->flags
.ignoreNewLine
) {
1941 for(i
=0; i
<len
; i
++) {
1942 if (text
[i
] == '\n')
1947 tb
= tPtr
->currentTextBlock
;
1948 if (!tb
|| tb
->graphic
) {
1950 WMAppendTextStream(tPtr
, text
);
1951 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
1952 layOutDocument(tPtr
);
1956 if ((newline
= strchr(text
, '\n'))) {
1957 int nlen
= (int)(newline
-text
);
1958 int s
= tb
->used
- tPtr
->tpos
;
1960 if (!tb
->blank
&& nlen
>0) {
1962 memcpy(save
, &tb
->text
[tPtr
->tpos
], s
);
1963 tb
->used
-= (tb
->used
- tPtr
->tpos
);
1966 insertTextInteractively(tPtr
, text
, nlen
);
1968 WMAppendTextStream(tPtr
, newline
);
1970 insertTextInteractively(tPtr
, save
, s
);
1973 if (tPtr
->tpos
>0 && tPtr
->tpos
< tb
->used
1974 && !tb
->graphic
&& tb
->text
) {
1976 void *ntb
= WMCreateTextBlockWithText(
1977 tPtr
, &tb
->text
[tPtr
->tpos
],
1978 tb
->d
.font
, tb
->color
, True
, tb
->used
- tPtr
->tpos
);
1979 tb
->used
= tPtr
->tpos
;
1980 WMAppendTextBlock(tPtr
, ntb
);
1983 } else if (tPtr
->tpos
== tb
->used
|| tPtr
->tpos
== 0) {
1984 void *ntb
= WMCreateTextBlockWithText(tPtr
,
1985 NULL
, tb
->d
.font
, tb
->color
, True
, 0);
1986 WMAppendTextBlock(tPtr
, ntb
);
1992 if (tb
->used
+ len
>= tb
->allocated
) {
1993 tb
->allocated
= reqBlockSize(tb
->used
+len
);
1994 tb
->text
= wrealloc(tb
->text
, tb
->allocated
);
1998 memcpy(tb
->text
, text
, len
);
2001 tb
->text
[tb
->used
] = 0;
2005 memmove(&(tb
->text
[tPtr
->tpos
+len
]), &tb
->text
[tPtr
->tpos
],
2006 tb
->used
-tPtr
->tpos
+1);
2007 memmove(&tb
->text
[tPtr
->tpos
], text
, len
);
2010 tb
->text
[tb
->used
] = 0;
2015 layOutDocument(tPtr
);
2020 selectRegion(Text
*tPtr
, int x
, int y
)
2026 y
+= (tPtr
->flags
.rulerShown
? 40: 0);
2029 y
-= 10; /* the original offset */
2031 x
-= tPtr
->visible
.x
-2;
2035 tPtr
->sel
.x
= WMAX(0, WMIN(tPtr
->clicked
.x
, x
));
2036 tPtr
->sel
.w
= abs(tPtr
->clicked
.x
- x
);
2037 tPtr
->sel
.y
= WMAX(0, WMIN(tPtr
->clicked
.y
, y
));
2038 tPtr
->sel
.h
= abs(tPtr
->clicked
.y
- y
);
2040 tPtr
->flags
.ownsSelection
= True
;
2046 releaseSelection(Text
*tPtr
)
2048 TextBlock
*tb
= tPtr
->firstTextBlock
;
2051 tb
->selected
= False
;
2054 tPtr
->flags
.ownsSelection
= False
;
2055 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
,
2063 requestHandler(WMView
*view
, Atom selection
, Atom target
, void *cdata
,
2066 Text
*tPtr
= view
->self
;
2067 Display
*dpy
= tPtr
->view
->screen
->display
;
2069 Atom TEXT
= XInternAtom(dpy
, "TEXT", False
);
2070 Atom COMPOUND_TEXT
= XInternAtom(dpy
, "COMPOUND_TEXT", False
);
2071 WMData
*data
= NULL
;
2074 if (target
== XA_STRING
|| target
== TEXT
|| target
== COMPOUND_TEXT
) {
2075 char *text
= WMGetTextSelectedStream(tPtr
);
2078 printf("got text [%s]\n", text
);
2079 data
= WMCreateDataWithBytes(text
, strlen(text
));
2080 WMSetDataFormat(data
, TYPETEXT
);
2084 } else printf("didn't get it\n");
2086 _TARGETS
= XInternAtom(dpy
, "TARGETS", False
);
2087 if (target
== _TARGETS
) {
2090 ptr
= wmalloc(4 * sizeof(Atom
));
2094 ptr
[3] = COMPOUND_TEXT
;
2096 data
= WMCreateDataWithBytes(ptr
, 4*4);
2097 WMSetDataFormat(data
, 32);
2107 lostHandler(WMView
*view
, Atom selection
, void *cdata
)
2109 releaseSelection((WMText
*)view
->self
);
2112 static WMSelectionProcs selectionHandler
= {
2113 requestHandler
, lostHandler
, NULL
2118 ownershipObserver(void *observerData
, WMNotification
*notification
)
2120 if (observerData
!= WMGetNotificationClientData(notification
))
2121 lostHandler(WMWidgetView(observerData
), XA_PRIMARY
, NULL
);
2126 fontChanged(void *observerData
, WMNotification
*notification
)
2128 WMText
*tPtr
= (WMText
*) observerData
;
2129 WMFont
*font
= (WMFont
*)WMGetNotificationClientData(notification
);
2130 printf("fontChanged\n");
2135 if (tPtr
->flags
.ownsSelection
)
2136 WMSetTextSelectionFont(tPtr
, font
);
2141 handleTextKeyPress(Text
*tPtr
, XEvent
*event
)
2145 int control_pressed
= False
;
2146 TextBlock
*tb
= NULL
;
2148 if (((XKeyEvent
*) event
)->state
& ControlMask
)
2149 control_pressed
= True
;
2150 buffer
[XLookupString(&event
->xkey
, buffer
, 1, &ksym
, NULL
)] = 0;
2155 if(!(tb
= tPtr
->currentTextBlock
))
2161 L_imaGFX
: if(tb
->prior
) {
2162 tPtr
->currentTextBlock
= tb
->prior
;
2163 tPtr
->tpos
= tPtr
->currentTextBlock
->used
-1;
2164 } else tPtr
->tpos
= 0;
2165 } else tPtr
->tpos
--;
2166 updateCursorPosition(tPtr
);
2171 if(!(tb
= tPtr
->currentTextBlock
))
2175 if(tPtr
->tpos
== tb
->used
) {
2176 R_imaGFX
: if(tb
->next
) {
2177 tPtr
->currentTextBlock
= tb
->next
;
2179 } else tPtr
->tpos
= tb
->used
;
2180 } else tPtr
->tpos
++;
2181 updateCursorPosition(tPtr
);
2186 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
2187 tPtr
->clicked
.y
+ tPtr
->cursor
.h
- tPtr
->vpos
);
2192 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
2193 tPtr
->visible
.y
+ tPtr
->cursor
.y
- tPtr
->vpos
- 3);
2200 deleteTextInteractively(tPtr
, ksym
);
2201 updateCursorPosition(tPtr
);
2207 control_pressed
= True
;
2211 insertTextInteractively(tPtr
, " ", 4);
2212 updateCursorPosition(tPtr
);
2219 if (buffer
[0] != 0 && !control_pressed
) {
2220 insertTextInteractively(tPtr
, buffer
, 1);
2221 updateCursorPosition(tPtr
);
2224 } else if (control_pressed
&& ksym
==XK_r
) {
2225 Bool i
= !tPtr
->flags
.rulerShown
;
2226 WMShowTextRuler(tPtr
, i
);
2227 tPtr
->flags
.rulerShown
= i
;
2229 else if (control_pressed
&& buffer
[0] == '\a')
2230 XBell(tPtr
->view
->screen
->display
, 0);
2233 if (!control_pressed
&& tPtr
->flags
.ownsSelection
)
2234 releaseSelection(tPtr
);
2238 handleWidgetPress(XEvent
*event
, void *data
)
2240 TextBlock
*tb
= (TextBlock
*)data
;
2248 tPtr
->currentTextBlock
= tb
;
2249 tPtr
->flags
.isOverGraphic
= 2;
2251 output(tb
->text
, tb
->used
);
2256 handleActionEvents(XEvent
*event
, void *data
)
2258 Text
*tPtr
= (Text
*)data
;
2259 Display
*dpy
= event
->xany
.display
;
2263 switch (event
->type
) {
2265 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2266 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2267 tPtr
->flags
.extendSelection
= True
;
2271 if (tPtr
->flags
.focused
) {
2272 XGrabPointer(dpy
, W_VIEW(tPtr
)->window
, False
,
2273 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
2274 GrabModeAsync
, GrabModeAsync
, None
,
2275 tPtr
->view
->screen
->invisibleCursor
, CurrentTime
);
2276 tPtr
->flags
.pointerGrabbed
= True
;
2277 handleTextKeyPress(tPtr
, event
);
2282 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2283 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2284 tPtr
->flags
.extendSelection
= False
;
2286 /* end modify flag so selection can be extended */
2293 if (tPtr
->flags
.pointerGrabbed
) {
2294 tPtr
->flags
.pointerGrabbed
= False
;
2295 XUngrabPointer(dpy
, CurrentTime
);
2298 if(tPtr
->flags
.waitingForSelection
)
2301 if ((event
->xmotion
.state
& Button1Mask
)) {
2302 if (!tPtr
->flags
.ownsSelection
) {
2303 WMCreateSelectionHandler(tPtr
->view
,
2304 XA_PRIMARY
, event
->xbutton
.time
,
2305 &selectionHandler
, NULL
);
2306 tPtr
->flags
.ownsSelection
= True
;
2308 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2312 mouseOverObject(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2318 if (tPtr
->flags
.pointerGrabbed
) {
2319 tPtr
->flags
.pointerGrabbed
= False
;
2320 XUngrabPointer(dpy
, CurrentTime
);
2324 if (tPtr
->flags
.waitingForSelection
)
2327 if (tPtr
->flags
.extendSelection
) {
2328 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2333 if (event
->xbutton
.button
== Button1
) {
2335 if(WMIsDoubleClick(event
)) {
2336 TextBlock
*tb
= tPtr
->currentTextBlock
;
2338 if(tb
&& tb
->graphic
&& !tb
->object
) {
2339 char desc
[tb
->used
+1];
2340 memcpy(desc
, tb
->text
, tb
->used
);
2342 printf("has delegate %p\n", tPtr
->delegate
);
2343 if(tPtr
->delegate
) {
2344 if(tPtr
->delegate
->didDoubleClickOnPicture
)
2345 printf("has didDoubleClickOnPicture%p\n",
2346 tPtr
->delegate
->didDoubleClickOnPicture
);
2347 (*tPtr
->delegate
->didDoubleClickOnPicture
)
2348 (tPtr
->delegate
, desc
);
2349 } else printf("you clicked on %s\n", desc
);
2351 autoSelectText(tPtr
, 2);
2353 tPtr
->lastClickTime
= event
->xbutton
.time
;
2355 } else if(event
->xbutton
.time
- tPtr
->lastClickTime
2356 < WINGsConfiguration
.doubleClickDelay
) {
2357 autoSelectText(tPtr
, 3);
2361 if (!tPtr
->flags
.focused
) {
2362 WMSetFocusToWidget(tPtr
);
2363 tPtr
->flags
.focused
= True
;
2366 if (tPtr
->flags
.ownsSelection
)
2367 releaseSelection(tPtr
);
2369 tPtr
->lastClickTime
= event
->xbutton
.time
;
2370 cursorToTextPosition(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2374 if (event
->xbutton
.button
2375 == WINGsConfiguration
.mouseWheelDown
) {
2376 WMScrollText(tPtr
, -16);
2380 if (event
->xbutton
.button
2381 == WINGsConfiguration
.mouseWheelUp
) {
2382 WMScrollText(tPtr
, 16);
2386 if (event
->xbutton
.button
== Button2
) {
2390 if (!tPtr
->flags
.editable
) {
2396 if (!WMRequestSelection(tPtr
->view
, XA_PRIMARY
, XA_STRING
,
2397 event
->xbutton
.time
, pasteText
, NULL
)) {
2401 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
2407 (tPtr
->parser
) (tPtr
, (void *) text
);
2409 insertTextInteractively(tPtr
, text
, n
);
2413 NOTIFY(tPtr
, didChange
, WMTextDidChangeNotification
,
2414 (void*)WMInsertTextEvent
);
2418 tPtr
->flags
.waitingForSelection
= True
;
2427 if (tPtr
->flags
.pointerGrabbed
) {
2428 tPtr
->flags
.pointerGrabbed
= False
;
2429 XUngrabPointer(dpy
, CurrentTime
);
2433 if (tPtr
->flags
.waitingForSelection
)
2441 handleEvents(XEvent
*event
, void *data
)
2443 Text
*tPtr
= (Text
*)data
;
2445 switch(event
->type
) {
2448 if (event
->xexpose
.count
!=0)
2452 if (!(W_VIEW(tPtr
->hS
))->flags
.realized
)
2455 WMRealizeWidget(tPtr
->hS
);
2461 if (!(W_VIEW(tPtr
->vS
))->flags
.realized
)
2462 WMRealizeWidget(tPtr
->vS
);
2466 if (!(W_VIEW(tPtr
->ruler
))->flags
.realized
)
2467 WMRealizeWidget(tPtr
->ruler
);
2472 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2478 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))
2481 tPtr
->flags
.focused
= True
;
2483 if (tPtr
->flags
.editable
&& !tPtr
->timerID
) {
2484 tPtr
->timerID
= WMAddTimerHandler(12+0*CURSOR_BLINK_ON_DELAY
,
2492 tPtr
->flags
.focused
= False
;
2495 if (tPtr
->timerID
) {
2496 WMDeleteTimerHandler(tPtr
->timerID
);
2497 tPtr
->timerID
= NULL
;
2506 WMDestroyWidget(tPtr
->hS
);
2508 WMDestroyWidget(tPtr
->vS
);
2510 WMDestroyWidget(tPtr
->ruler
);
2512 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
2514 WMFreeArray(tPtr
->gfxItems
);
2517 WMDeleteTimerHandler(tPtr
->timerID
);
2519 WMReleaseFont(tPtr
->dFont
);
2520 WMReleaseColor(tPtr
->dColor
);
2521 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
, CurrentTime
);
2522 WMRemoveNotificationObserver(tPtr
);
2533 insertText(WMText
*tPtr
, char *stream
)
2545 mark
= strchr(start
, '\n');
2547 tb
= WMCreateTextBlockWithText(tPtr
,
2549 tPtr
->dColor
, True
, (int)(mark
-start
));
2552 if (start
&& strlen(start
)) {
2553 tb
= WMCreateTextBlockWithText(tPtr
, start
, tPtr
->dFont
,
2554 tPtr
->dColor
, False
, strlen(start
));
2559 if (tPtr
->flags
.prepend
)
2560 WMPrependTextBlock(tPtr
, tb
);
2562 WMAppendTextBlock(tPtr
, tb
);
2570 rulerMoveCallBack(WMWidget
*w
, void *self
)
2572 Text
*tPtr
= (Text
*)self
;
2575 if (W_CLASS(tPtr
) != WC_Text
)
2583 rulerReleaseCallBack(WMWidget
*w
, void *self
)
2585 Text
*tPtr
= (Text
*)self
;
2588 if (W_CLASS(tPtr
) != WC_Text
)
2597 draggingEntered(WMView
*self
, WMDraggingInfo
*info
)
2599 printf("draggingEntered\n");
2600 return WDOperationCopy
;
2605 draggingUpdated(WMView
*self
, WMDraggingInfo
*info
)
2607 return WDOperationCopy
;
2612 draggingExited(WMView
*self
, WMDraggingInfo
*info
)
2614 printf("draggingExited\n");
2618 prepareForDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2620 printf("prepareForDragOperation\n");
2627 receivedData(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
2628 void *cdata
, WMData
*data
)
2630 badbadbad
= wstrdup((char *)WMDataBytes(data
));
2634 /* when it's done in WINGs, remove this */
2636 Bool
requestDroppedData(WMView
*view
, WMDraggingInfo
*info
, char *type
)
2638 WMScreen
*scr
= W_VIEW_SCREEN(view
);
2640 if (!WMRequestSelection(scr
->dragInfo
.destView
,
2641 scr
->xdndSelectionAtom
,
2642 XInternAtom(scr
->display
, type
, False
),
2643 scr
->dragInfo
.timestamp
,
2644 receivedData
, &scr
->dragInfo
)) {
2645 wwarning("could not request data for dropped data");
2652 ev
.type
= ClientMessage
;
2653 ev
.xclient
.message_type
= scr
->xdndFinishedAtom
;
2654 ev
.xclient
.format
= 32;
2655 ev
.xclient
.window
= info
->destinationWindow
;
2656 ev
.xclient
.data
.l
[0] = 0;
2657 ev
.xclient
.data
.l
[1] = 0;
2658 ev
.xclient
.data
.l
[2] = 0;
2659 ev
.xclient
.data
.l
[3] = 0;
2660 ev
.xclient
.data
.l
[4] = 0;
2662 XSendEvent(scr
->display
, info
->sourceWindow
, False
, 0, &ev
);
2663 XFlush(scr
->display
);
2668 performDragOperation(WMView
*self
, WMDraggingInfo
*info
, WMData
*data
)
2671 WMText
*tPtr
= (WMText
*)self
->self
;
2676 requestDroppedData(tPtr
->view
, info
, "application/X-color");
2677 color
= WMCreateNamedColor(W_VIEW_SCREEN(self
), badbadbad
, True
);
2679 WMSetTextSelectionColor(tPtr
, color
);
2680 WMReleaseColor(color
);
2689 concludeDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2691 printf("concludeDragOperation\n");
2695 static WMDragDestinationProcs _DragDestinationProcs
= {
2699 prepareForDragOperation
,
2700 performDragOperation
,
2701 concludeDragOperation
2706 getStream(WMText
*tPtr
, int sel
, int array
)
2708 TextBlock
*tb
= NULL
;
2710 unsigned long where
= 0;
2715 if (!(tb
= tPtr
->firstTextBlock
))
2719 (tPtr
->writer
) (tPtr
, (void *) text
);
2723 tb
= tPtr
->firstTextBlock
;
2726 if (!tb
->graphic
|| (tb
->graphic
&& !tPtr
->flags
.monoFont
)) {
2728 if (!sel
|| (tb
->graphic
&& tb
->selected
)) {
2730 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
)
2731 && tb
!= tPtr
->firstTextBlock
) {
2732 text
= wrealloc(text
, where
+1);
2733 text
[where
++] = '\n';
2739 if(tb
->graphic
&& array
) {
2740 text
= wrealloc(text
, where
+4);
2741 text
[where
++] = 0xFA;
2742 text
[where
++] = (tb
->used
>>8)&0x0ff;
2743 text
[where
++] = tb
->used
&0x0ff;
2744 text
[where
++] = tb
->allocated
; /* extra info */
2746 text
= wrealloc(text
, where
+tb
->used
);
2747 memcpy(&text
[where
], tb
->text
, tb
->used
);
2751 } else if (sel
&& tb
->selected
) {
2753 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
)
2754 && tb
!= tPtr
->firstTextBlock
) {
2755 text
= wrealloc(text
, where
+1);
2756 text
[where
++] = '\n';
2762 text
= wrealloc(text
, where
+(tb
->s_end
- tb
->s_begin
));
2763 memcpy(&text
[where
], &tb
->text
[tb
->s_begin
],
2764 tb
->s_end
- tb
->s_begin
);
2765 where
+= tb
->s_end
- tb
->s_begin
;
2770 _gSnext
:tb
= tb
->next
;
2773 /* +1 for the end of string, let's be nice */
2774 text
= wrealloc(text
, where
+1);
2781 releaseStreamObjects(void *data
)
2788 getStreamObjects(WMText
*tPtr
, int sel
)
2790 WMArray
*array
= WMCreateArrayWithDestructor(4, releaseStreamObjects
);
2794 char *start
, *fa
, *desc
;
2796 stream
= getStream(tPtr
, sel
, 1);
2803 fa
= strchr(start
, 0xFA);
2805 if((int)(fa
- start
)>0) {
2807 desc
[(int)(fa
- start
)] = 0;
2808 data
= WMCreateDataWithBytes((void *)desc
, (int)(fa
- start
));
2809 WMSetDataFormat(data
, TYPETEXT
);
2810 WMAddToArray(array
, (void *) data
);
2813 len
= *(fa
+1)*0xff + *(fa
+2);
2814 data
= WMCreateDataWithBytes((void *)(fa
+4), len
);
2815 WMSetDataFormat(data
, *(fa
+3));
2816 WMAddToArray(array
, (void *) data
);
2817 start
= fa
+ len
+ 4;
2820 if (start
&& strlen(start
)) {
2821 data
= WMCreateDataWithBytes((void *)start
, strlen(start
));
2822 WMSetDataFormat(data
, TYPETEXT
);
2823 WMAddToArray(array
, (void *) data
);
2836 WMCreateTextForDocumentType(WMWidget
*parent
,
2837 WMAction
*parser
, WMAction
*writer
)
2839 Text
*tPtr
= wmalloc(sizeof(Text
));
2841 printf("could not create text widget\n");
2846 memset(tPtr
, 0, sizeof(Text
));
2847 tPtr
->widgetClass
= WC_Text
;
2848 tPtr
->view
= W_CreateView(W_VIEW(parent
));
2850 perror("could not create text's view\n");
2854 tPtr
->view
->self
= tPtr
;
2855 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->textCursor
;
2856 tPtr
->view
->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2857 W_ResizeView(tPtr
->view
, 250, 200);
2859 tPtr
->dColor
= WMWhiteColor(tPtr
->view
->screen
);
2860 tPtr
->bgGC
= WMColorGC(tPtr
->dColor
);
2861 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->dColor
);
2862 WMReleaseColor(tPtr
->dColor
);
2864 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
2865 tPtr
->fgGC
= WMColorGC(tPtr
->dColor
);
2871 tPtr
->dFont
= WMRetainFont(WMSystemFontOfSize(tPtr
->view
->screen
, 12));
2873 tPtr
->view
->delegate
= &_TextViewDelegate
;
2875 tPtr
->delegate
= NULL
;
2878 tPtr
->timerID
= NULL
;
2881 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
2882 |EnterWindowMask
|LeaveWindowMask
|FocusChangeMask
,
2883 handleEvents
, tPtr
);
2885 WMCreateEventHandler(tPtr
->view
, ButtonReleaseMask
|ButtonPressMask
2886 |KeyReleaseMask
|KeyPressMask
|Button1MotionMask
,
2887 handleActionEvents
, tPtr
);
2889 WMAddNotificationObserver(ownershipObserver
, tPtr
,
2890 "_lostOwnership", tPtr
);
2892 WMSetViewDragDestinationProcs(tPtr
->view
, &_DragDestinationProcs
);
2894 char *types
[2] = {"application/X-color", NULL
};
2895 WMRegisterViewForDraggedTypes(tPtr
->view
, types
);
2898 WMAddNotificationObserver(fontChanged
, tPtr
,
2899 "WMFontPanelDidChangeNotification", tPtr
);
2901 tPtr
->firstTextBlock
= NULL
;
2902 tPtr
->lastTextBlock
= NULL
;
2903 tPtr
->currentTextBlock
= NULL
;
2906 tPtr
->gfxItems
= WMCreateArray(4);
2908 tPtr
->parser
= parser
;
2909 tPtr
->writer
= writer
;
2911 tPtr
->sel
.x
= tPtr
->sel
.y
= 2;
2912 tPtr
->sel
.w
= tPtr
->sel
.h
= 0;
2914 tPtr
->clicked
.x
= tPtr
->clicked
.y
= 2;
2916 tPtr
->visible
.x
= tPtr
->visible
.y
= 2;
2917 tPtr
->visible
.h
= tPtr
->view
->size
.height
;
2918 tPtr
->visible
.w
= tPtr
->view
->size
.width
- 4;
2920 tPtr
->cursor
.x
= -23;
2923 tPtr
->docHeight
= 0;
2924 tPtr
->dBulletPix
= WMCreatePixmapFromXPMData(tPtr
->view
->screen
,
2926 tPtr
->db
= (Pixmap
) NULL
;
2928 tPtr
->margins
= WMGetRulerMargins(NULL
);
2929 tPtr
->margins
->right
= tPtr
->visible
.w
;
2932 tPtr
->flags
.rulerShown
= False
;
2933 tPtr
->flags
.monoFont
= False
;
2934 tPtr
->flags
.focused
= False
;
2935 tPtr
->flags
.editable
= True
;
2936 tPtr
->flags
.ownsSelection
= False
;
2937 tPtr
->flags
.pointerGrabbed
= False
;
2938 tPtr
->flags
.extendSelection
= False
;
2939 tPtr
->flags
.frozen
= False
;
2940 tPtr
->flags
.cursorShown
= True
;
2941 tPtr
->flags
.acceptsGraphic
= False
;
2942 tPtr
->flags
.horizOnDemand
= False
;
2943 tPtr
->flags
.needsLayOut
= False
;
2944 tPtr
->flags
.ignoreNewLine
= False
;
2945 tPtr
->flags
.laidOut
= False
;
2946 tPtr
->flags
.waitingForSelection
= False
;
2947 tPtr
->flags
.prepend
= False
;
2948 tPtr
->flags
.isOverGraphic
= False
;
2949 tPtr
->flags
.relief
= WRSunken
;
2950 tPtr
->flags
.isOverGraphic
= 0;
2951 tPtr
->flags
.alignment
= WALeft
;
2957 WMPrependTextStream(WMText
*tPtr
, char *text
)
2959 CHECK_CLASS(tPtr
, WC_Text
);
2962 if(tPtr
->flags
.ownsSelection
)
2963 releaseSelection(tPtr
);
2968 tPtr
->flags
.prepend
= True
;
2969 if (text
&& tPtr
->parser
)
2970 (tPtr
->parser
) (tPtr
, (void *) text
);
2972 insertText(tPtr
, text
);
2974 tPtr
->flags
.needsLayOut
= True
;
2979 WMAppendTextStream(WMText
*tPtr
, char *text
)
2981 CHECK_CLASS(tPtr
, WC_Text
);
2984 if(tPtr
->flags
.ownsSelection
)
2985 releaseSelection(tPtr
);
2990 tPtr
->flags
.prepend
= False
;
2991 if (text
&& tPtr
->parser
)
2992 (tPtr
->parser
) (tPtr
, (void *) text
);
2994 insertText(tPtr
, text
);
2996 tPtr
->flags
.needsLayOut
= True
;
3002 WMGetTextStream(WMText
*tPtr
)
3004 CHECK_CLASS(tPtr
, WC_Text
);
3005 return getStream(tPtr
, 0, 0);
3009 WMGetTextSelectedStream(WMText
*tPtr
)
3011 CHECK_CLASS(tPtr
, WC_Text
);
3012 return getStream(tPtr
, 1, 0);
3016 WMGetTextObjects(WMText
*tPtr
)
3018 CHECK_CLASS(tPtr
, WC_Text
);
3019 return getStreamObjects(tPtr
, 0);
3023 WMGetTextSelectedObjects(WMText
*tPtr
)
3025 CHECK_CLASS(tPtr
, WC_Text
);
3026 return getStreamObjects(tPtr
, 1);
3031 WMSetTextDelegate(WMText
*tPtr
, WMTextDelegate
*delegate
)
3033 CHECK_CLASS(tPtr
, WC_Text
);
3035 tPtr
->delegate
= delegate
;
3040 WMCreateTextBlockWithObject(WMText
*tPtr
, WMWidget
*w
,
3041 char *description
, WMColor
*color
,
3042 unsigned short first
, unsigned short extraInfo
)
3047 if (!w
|| !description
|| !color
)
3050 tb
= wmalloc(sizeof(TextBlock
));
3054 len
= strlen(description
);
3055 tb
->text
= (char *)wmalloc(len
);
3056 memset(tb
->text
, 0, len
);
3057 memcpy(tb
->text
, description
, len
);
3061 tb
->color
= WMRetainColor(color
);
3062 tb
->marginN
= newMargin(tPtr
, NULL
);
3063 tb
->allocated
= extraInfo
;
3068 tb
->underlined
= False
;
3069 tb
->selected
= False
;
3071 tb
->sections
= NULL
;
3081 WMCreateTextBlockWithPixmap(WMText
*tPtr
, WMPixmap
*p
,
3082 char *description
, WMColor
*color
,
3083 unsigned short first
, unsigned short extraInfo
)
3088 if (!p
|| !description
|| !color
)
3091 tb
= wmalloc(sizeof(TextBlock
));
3095 len
= strlen(description
);
3096 tb
->text
= (char *)wmalloc(len
);
3097 memset(tb
->text
, 0, len
);
3098 memcpy(tb
->text
, description
, len
);
3101 tb
->d
.pixmap
= WMRetainPixmap(p
);
3102 tb
->color
= WMRetainColor(color
);
3103 tb
->marginN
= newMargin(tPtr
, NULL
);
3104 tb
->allocated
= extraInfo
;
3109 tb
->underlined
= False
;
3110 tb
->selected
= False
;
3112 tb
->sections
= NULL
;
3121 WMCreateTextBlockWithText(WMText
*tPtr
, char *text
, WMFont
*font
, WMColor
*color
,
3122 unsigned short first
, unsigned short len
)
3126 if (!font
|| !color
)
3129 tb
= wmalloc(sizeof(TextBlock
));
3133 tb
->allocated
= reqBlockSize(len
);
3134 tb
->text
= (char *)wmalloc(tb
->allocated
);
3135 memset(tb
->text
, 0, tb
->allocated
);
3137 if (len
< 1|| !text
|| (*text
== '\n' && len
==1 )) {
3142 memcpy(tb
->text
, text
, len
);
3146 tb
->text
[tb
->used
] = 0;
3148 tb
->d
.font
= WMRetainFont(font
);
3149 tb
->color
= WMRetainColor(color
);
3150 tb
->marginN
= newMargin(tPtr
, NULL
);
3153 tb
->graphic
= False
;
3154 tb
->underlined
= False
;
3155 tb
->selected
= False
;
3157 tb
->sections
= NULL
;
3165 WMSetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int first
,
3166 unsigned int kanji
, unsigned int underlined
, int script
,
3167 WMRulerMargins
*margins
)
3169 TextBlock
*tb
= (TextBlock
*) vtb
;
3175 tb
->underlined
= underlined
;
3176 tb
->script
= script
;
3177 tb
->marginN
= newMargin(tPtr
, margins
);
3181 WMGetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int *first
,
3182 unsigned int *kanji
, unsigned int *underlined
, int *script
,
3183 WMRulerMargins
*margins
)
3185 TextBlock
*tb
= (TextBlock
*) vtb
;
3189 if (first
) *first
= tb
->first
;
3190 if (kanji
) *kanji
= tb
->kanji
;
3191 if (underlined
) *underlined
= tb
->underlined
;
3192 if (script
) *script
= tb
->script
;
3193 if (margins
) margins
= &tPtr
->margins
[tb
->marginN
];
3199 WMPrependTextBlock(WMText
*tPtr
, void *vtb
)
3201 TextBlock
*tb
= (TextBlock
*)vtb
;
3208 WMWidget
*w
= tb
->d
.widget
;
3209 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
3210 handleWidgetPress
, tb
);
3211 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
3212 (W_VIEW(w
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3213 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3216 WMAddToArray(tPtr
->gfxItems
, (void *)tb
);
3218 } else tPtr
->tpos
= tb
->used
;
3220 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
3221 tb
->next
= tb
->prior
= NULL
;
3223 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
3224 = tPtr
->currentTextBlock
= tb
;
3229 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
3232 tb
->next
= tPtr
->currentTextBlock
;
3233 tb
->prior
= tPtr
->currentTextBlock
->prior
;
3234 if (tPtr
->currentTextBlock
->prior
)
3235 tPtr
->currentTextBlock
->prior
->next
= tb
;
3237 tPtr
->currentTextBlock
->prior
= tb
;
3239 tPtr
->firstTextBlock
= tb
;
3241 tPtr
->currentTextBlock
= tb
;
3246 WMAppendTextBlock(WMText
*tPtr
, void *vtb
)
3248 TextBlock
*tb
= (TextBlock
*)vtb
;
3255 WMWidget
*w
= tb
->d
.widget
;
3256 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
3257 handleWidgetPress
, tb
);
3258 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
3259 (W_VIEW(w
))->attribs
.cursor
=
3260 tPtr
->view
->screen
->defaultCursor
;
3261 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3264 WMAddToArray(tPtr
->gfxItems
, (void *)tb
);
3266 } else tPtr
->tpos
= tb
->used
;
3268 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
3269 tb
->next
= tb
->prior
= NULL
;
3271 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
3272 = tPtr
->currentTextBlock
= tb
;
3277 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
3280 tb
->next
= tPtr
->currentTextBlock
->next
;
3281 tb
->prior
= tPtr
->currentTextBlock
;
3282 if (tPtr
->currentTextBlock
->next
)
3283 tPtr
->currentTextBlock
->next
->prior
= tb
;
3285 tPtr
->currentTextBlock
->next
= tb
;
3288 tPtr
->lastTextBlock
= tb
;
3290 tPtr
->currentTextBlock
= tb
;
3294 WMRemoveTextBlock(WMText
*tPtr
)
3296 TextBlock
*tb
= NULL
;
3298 if (!tPtr
|| !tPtr
->firstTextBlock
|| !tPtr
->lastTextBlock
3299 || !tPtr
->currentTextBlock
) {
3300 printf("cannot remove non existent TextBlock!\b");
3304 tb
= tPtr
->currentTextBlock
;
3306 WMRemoveFromArray(tPtr
->gfxItems
, (void *)tb
);
3309 WMDeleteEventHandler(W_VIEW(tb
->d
.widget
), ButtonPressMask
,
3310 handleWidgetPress
, tb
);
3311 WMUnmapWidget(tb
->d
.widget
);
3315 if (tPtr
->currentTextBlock
== tPtr
->firstTextBlock
) {
3316 if (tPtr
->currentTextBlock
->next
)
3317 tPtr
->currentTextBlock
->next
->prior
= NULL
;
3319 tPtr
->firstTextBlock
= tPtr
->currentTextBlock
->next
;
3320 tPtr
->currentTextBlock
= tPtr
->firstTextBlock
;
3322 } else if (tPtr
->currentTextBlock
== tPtr
->lastTextBlock
) {
3323 tPtr
->currentTextBlock
->prior
->next
= NULL
;
3324 tPtr
->lastTextBlock
= tPtr
->currentTextBlock
->prior
;
3325 tPtr
->currentTextBlock
= tPtr
->lastTextBlock
;
3327 tPtr
->currentTextBlock
->prior
->next
= tPtr
->currentTextBlock
->next
;
3328 tPtr
->currentTextBlock
->next
->prior
= tPtr
->currentTextBlock
->prior
;
3329 tPtr
->currentTextBlock
= tPtr
->currentTextBlock
->next
;
3336 WMDestroyTextBlock(WMText
*tPtr
, void *vtb
)
3338 TextBlock
*tb
= (TextBlock
*)vtb
;
3344 /* naturally, there's a danger to destroying
3345 widgets whose action brings us here:
3346 ie. press a button to destroy it... need to
3347 find a safer way. till then... this stays commented out */
3348 /* WMDestroyWidget(tb->d.widget);
3349 wfree(tb->d.widget); */
3350 tb
->d
.widget
= NULL
;
3352 WMReleasePixmap(tb
->d
.pixmap
);
3353 tb
->d
.pixmap
= NULL
;
3356 WMReleaseFont(tb
->d
.font
);
3359 WMReleaseColor(tb
->color
);
3360 if (tb
->sections
&& tb
->nsections
> 0)
3361 wfree(tb
->sections
);
3370 WMSetTextForegroundColor(WMText
*tPtr
, WMColor
*color
)
3376 tPtr
->fgGC
= WMColorGC(color
);
3378 tPtr
->fgGC
= WMColorGC(WMBlackColor(tPtr
->view
->screen
));
3384 WMSetTextBackgroundColor(WMText
*tPtr
, WMColor
*color
)
3390 tPtr
->bgGC
= WMColorGC(color
);
3391 W_SetViewBackgroundColor(tPtr
->view
, color
);
3393 tPtr
->bgGC
= WMColorGC(WMWhiteColor(tPtr
->view
->screen
));
3394 W_SetViewBackgroundColor(tPtr
->view
,
3395 WMWhiteColor(tPtr
->view
->screen
));
3402 WMSetTextRelief(WMText
*tPtr
, WMReliefType relief
)
3406 tPtr
->flags
.relief
= relief
;
3407 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3411 WMSetTextHasHorizontalScroller(WMText
*tPtr
, Bool shouldhave
)
3416 if (shouldhave
&& !tPtr
->hS
) {
3417 tPtr
->hS
= WMCreateScroller(tPtr
);
3418 (W_VIEW(tPtr
->hS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3419 (W_VIEW(tPtr
->hS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3420 WMSetScrollerArrowsPosition(tPtr
->hS
, WSAMinEnd
);
3421 WMSetScrollerAction(tPtr
->hS
, scrollersCallBack
, tPtr
);
3422 WMMapWidget(tPtr
->hS
);
3423 } else if (!shouldhave
&& tPtr
->hS
) {
3424 WMUnmapWidget(tPtr
->hS
);
3425 WMDestroyWidget(tPtr
->hS
);
3431 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3436 WMSetTextHasRuler(WMText
*tPtr
, Bool shouldhave
)
3441 if(shouldhave
&& !tPtr
->ruler
) {
3442 tPtr
->ruler
= WMCreateRuler(tPtr
);
3443 (W_VIEW(tPtr
->ruler
))->attribs
.cursor
=
3444 tPtr
->view
->screen
->defaultCursor
;
3445 (W_VIEW(tPtr
->ruler
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3446 WMSetRulerReleaseAction(tPtr
->ruler
, rulerReleaseCallBack
, tPtr
);
3447 WMSetRulerMoveAction(tPtr
->ruler
, rulerMoveCallBack
, tPtr
);
3448 } else if(!shouldhave
&& tPtr
->ruler
) {
3449 WMShowTextRuler(tPtr
, False
);
3450 WMDestroyWidget(tPtr
->ruler
);
3453 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3457 WMShowTextRuler(WMText
*tPtr
, Bool show
)
3464 if(tPtr
->flags
.monoFont
)
3467 tPtr
->flags
.rulerShown
= show
;
3469 WMMapWidget(tPtr
->ruler
);
3471 WMUnmapWidget(tPtr
->ruler
);
3474 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3478 WMGetTextRulerShown(WMText
*tPtr
)
3486 return tPtr
->flags
.rulerShown
;
3491 WMSetTextHasVerticalScroller(WMText
*tPtr
, Bool shouldhave
)
3496 if (shouldhave
&& !tPtr
->vS
) {
3497 tPtr
->vS
= WMCreateScroller(tPtr
);
3498 (W_VIEW(tPtr
->vS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3499 (W_VIEW(tPtr
->vS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3500 WMSetScrollerArrowsPosition(tPtr
->vS
, WSAMaxEnd
);
3501 WMSetScrollerAction(tPtr
->vS
, scrollersCallBack
, tPtr
);
3502 WMMapWidget(tPtr
->vS
);
3503 } else if (!shouldhave
&& tPtr
->vS
) {
3504 WMUnmapWidget(tPtr
->vS
);
3505 WMDestroyWidget(tPtr
->vS
);
3511 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3517 WMScrollText(WMText
*tPtr
, int amount
)
3522 if (amount
== 0 || !tPtr
->view
->flags
.realized
)
3526 if (tPtr
->vpos
> 0) {
3527 if (tPtr
->vpos
> abs(amount
)) tPtr
->vpos
+= amount
;
3531 int limit
= tPtr
->docHeight
- tPtr
->visible
.h
;
3532 if (tPtr
->vpos
< limit
) {
3533 if (tPtr
->vpos
< limit
-amount
) tPtr
->vpos
+= amount
;
3534 else tPtr
->vpos
= limit
;
3538 if (scroll
&& tPtr
->vpos
!= tPtr
->prevVpos
) {
3539 updateScrollers(tPtr
);
3542 tPtr
->prevVpos
= tPtr
->vpos
;
3547 WMPageText(WMText
*tPtr
, Bool direction
)
3549 if (!tPtr
) return False
;
3550 if (!tPtr
->view
->flags
.realized
) return False
;
3552 return WMScrollText(tPtr
, direction
?tPtr
->visible
.h
:-tPtr
->visible
.h
);
3556 WMSetTextEditable(WMText
*tPtr
, Bool editable
)
3560 tPtr
->flags
.editable
= editable
;
3564 WMGetTextEditable(WMText
*tPtr
)
3568 return tPtr
->flags
.editable
;
3572 WMSetTextIgnoresNewline(WMText
*tPtr
, Bool ignore
)
3576 tPtr
->flags
.ignoreNewLine
= ignore
;
3580 WMGetTextIgnoresNewline(WMText
*tPtr
)
3584 return tPtr
->flags
.ignoreNewLine
;
3588 WMSetTextUsesMonoFont(WMText
*tPtr
, Bool mono
)
3592 if (mono
&& tPtr
->flags
.rulerShown
)
3593 WMShowTextRuler(tPtr
, False
);
3595 tPtr
->flags
.monoFont
= mono
;
3600 WMGetTextUsesMonoFont(WMText
*tPtr
)
3604 return tPtr
->flags
.monoFont
;
3609 WMSetTextDefaultFont(WMText
*tPtr
, WMFont
*font
)
3614 WMReleaseFont(tPtr
->dFont
);
3616 tPtr
->dFont
= WMRetainFont(font
);
3618 tPtr
->dFont
= WMRetainFont(WMSystemFontOfSize(tPtr
->view
->screen
, 12));
3622 WMGetTextDefaultFont(WMText
*tPtr
)
3631 WMSetTextAlignment(WMText
*tPtr
, WMAlignment alignment
)
3635 tPtr
->flags
.alignment
= alignment
;
3640 WMGetTextInsertType(WMText
*tPtr
)
3644 return tPtr
->flags
.prepend
;
3649 WMSetTextSelectionColor(WMText
*tPtr
, WMColor
*color
)
3651 if (!tPtr
|| !color
)
3654 setSelectionProperty(tPtr
, NULL
, color
, -1);
3658 WMSetTextSelectionFont(WMText
*tPtr
, WMFont
*font
)
3663 setSelectionProperty(tPtr
, font
, NULL
, -1) ;
3667 WMSetTextSelectionUnderlined(WMText
*tPtr
, int underlined
)
3669 if (!tPtr
|| (underlined
!=0 && underlined
!=1))
3672 setSelectionProperty(tPtr
, NULL
, NULL
, underlined
);
3679 WMFreezeText(WMText
*tPtr
)
3684 tPtr
->flags
.frozen
= True
;
3689 WMThawText(WMText
*tPtr
)
3694 tPtr
->flags
.frozen
= False
;
3696 if(tPtr
->flags
.monoFont
) {
3697 int j
, c
= WMGetArrayItemCount(tPtr
->gfxItems
);
3700 /* make sure to unmap widgets no matter where they are */
3701 /* they'll be later remapped if needed by paintText */
3702 for(j
=0; j
<c
; j
++) {
3703 if ((tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
))) {
3704 if (tb
->object
&& ((W_VIEW(tb
->d
.widget
))->flags
.mapped
))
3705 WMUnmapWidget(tb
->d
.widget
);
3711 tPtr
->flags
.laidOut
= False
;
3712 layOutDocument(tPtr
);
3713 updateScrollers(tPtr
);
3715 tPtr
->flags
.needsLayOut
= False
;
3721 mystrrstr(char *haystack
, char *needle
, unsigned short len
, char *end
,
3726 if(!haystack
|| !needle
)
3729 for (ptr
= haystack
-2; ptr
> end
; ptr
--) {
3731 if (*ptr
== *needle
&& !strncmp(ptr
, needle
, len
))
3734 if (tolower(*ptr
) == tolower(*needle
) &&
3735 strncasecmp(ptr
, needle
, len
))
3745 WMFindInTextStream(WMText
*tPtr
, char *needle
, Bool direction
,
3752 if (!tPtr
|| !needle
)
3755 if (! (tb
= tPtr
->currentTextBlock
)) {
3756 if (! (tb
= ( (direction
> 0) ?
3757 tPtr
->firstTextBlock
: tPtr
->lastTextBlock
) ) ){
3761 /* if(tb != ((direction>0) ?tPtr->firstTextBlock : tPtr->lastTextBlock))
3762 tb = (direction>0) ? tb->next : tb->prior; */
3763 if(tb
!= tPtr
->lastTextBlock
)
3771 if(pos
+1 < tb
->used
)
3774 if(tb
->used
- pos
> 0 && pos
> 0) {
3775 char tmp
= tb
->text
[tb
->used
];
3776 tb
->text
[tb
->used
] = 0;
3778 output(&tb
->text
[pos
], tb
->used
- pos
);
3780 mark
= strstr(&tb
->text
[pos
], needle
);
3782 mark
= mystrrstr(&tb
->text
[pos
], needle
,
3783 strlen(needle
), tb
->text
, caseSensitive
);
3785 tb
->text
[tb
->used
] = tmp
;
3792 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
3794 tPtr
->tpos
= (int)(mark
- tb
->text
);
3795 tPtr
->currentTextBlock
= tb
;
3796 updateCursorPosition(tPtr
);
3797 tPtr
->sel
.y
= tPtr
->cursor
.y
+5;
3798 tPtr
->sel
.h
= tPtr
->cursor
.h
-10;
3799 tPtr
->sel
.x
= tPtr
->cursor
.x
+1;
3800 tPtr
->sel
.w
= WMIN(WMWidthOfString(font
,
3801 &tb
->text
[tPtr
->tpos
], strlen(needle
)),
3802 tPtr
->docWidth
- tPtr
->sel
.x
);
3803 tPtr
->flags
.ownsSelection
= True
;
3810 tb
= (direction
>0) ? tb
->next
: tb
->prior
;