2 /* WINGs WMText: multi-line/font/color/graphic text widget, by Nwanua. */
7 #include <X11/keysym.h>
13 * - verify what happens with XK_return in insertTextInt...
14 * - selection code... selects can be funny if it crosses over. use rect?
15 * - also inspect behaviour for WACenter and WARight
16 * - what if a widget grabs the click... howto say: "pressed me"?
17 * note that WMCreateEventHandler takes one data, but need widget & tPtr
18 * - FIX: graphix blocks MUST be skipped if monoFont even though they exist!
19 * - check if support for Horizontal Scroll is complete
20 * - assess danger of destroying widgets whose actions link to other pages
21 * - Tabs now are simply replaced by 4 spaces...
22 * - redo blink code to reduce paint event... use pixmap buffer...
23 * - add paragraph support (full) and '\n' code in getStream..
27 /* a Section is a section of a TextBlock that describes what parts
28 of a TextBlock has been laid out on which "line"...
29 o this greatly aids redraw, scroll and selection.
30 o this is created during layoutLine, but may be later modified.
31 o there may be many Sections per TextBlock, hence the array */
33 unsigned int x
, y
; /* where to draw it from */
34 unsigned short w
, h
; /* its width and height */
35 unsigned short begin
; /* where the layout begins */
36 unsigned short end
; /* where it ends */
37 unsigned short max_d
; /* a quick hack for layOut if(laidOut) */
38 unsigned short last
:1; /* is it the last section on a "line"? */
39 unsigned int _y
:31; /* the "line" it and other textblocks are on */
43 /* a TextBlock is a node in a doubly-linked list of TextBlocks containing:
44 o text for the block, color and font
45 o or a pointer to the pixmap
46 o OR a pointer to the widget and the (text) description for its graphic
49 typedef struct _TextBlock
{
50 struct _TextBlock
*next
; /* next text block in linked list */
51 struct _TextBlock
*prior
; /* prior text block in linked list */
53 char *text
; /* pointer to text (could be kanji) */
54 /* or to the object's description */
56 WMFont
*font
; /* the font */
57 WMWidget
*widget
; /* the embedded widget */
58 WMPixmap
*pixmap
; /* the pixmap */
59 } d
; /* description */
61 unsigned short used
; /* number of chars in this block */
62 unsigned short allocated
; /* size of allocation (in chars) */
63 WMColor
*color
; /* the color */
65 Section
*sections
; /* the region for layouts (a growable array) */
66 /* an _array_! of size _nsections_ */
68 unsigned short s_begin
; /* where the selection begins */
69 unsigned short s_end
; /* where it ends */
71 unsigned int first
:1; /* first TextBlock in paragraph */
72 unsigned int blank
:1; /* ie. blank paragraph */
73 unsigned int kanji
:1; /* is of 16-bit characters or not */
74 unsigned int graphic
:1; /* graphic or text: text=0 */
75 unsigned int object
:1; /* embedded object or pixmap */
76 unsigned int underlined
:1; /* underlined or not */
77 unsigned int selected
:1; /* selected or not */
78 unsigned int nsections
:8; /* over how many "lines" a TextBlock wraps */
79 int script
:8; /* script in points: negative for subscript */
80 unsigned int marginN
:8; /* which of the margins in the tPtr to use */
81 unsigned int nClicks
:2; /* single, double, triple clicks */
82 unsigned int RESERVED
:7;
86 /* I'm lazy: visible.h vs. visible.size.height :-) */
92 typedef struct W_Text
{
93 W_Class widgetClass
; /* the class number of this widget */
94 W_View
*view
; /* the view referring to this instance */
96 WMRuler
*ruler
; /* the ruler widget to manipulate paragraphs */
98 WMScroller
*vS
; /* the vertical scroller */
99 unsigned int vpos
; /* the current vertical position */
100 unsigned int prevVpos
; /* the previous vertical position */
102 WMScroller
*hS
; /* the horizontal scroller */
103 unsigned int hpos
; /* the current horizontal position */
104 unsigned int prevHpos
; /* the previous horizontal position */
106 WMFont
*dFont
; /* the default font */
107 WMColor
*dColor
; /* the default color */
108 WMPixmap
*dBulletPix
; /* the default pixmap for bullets */
110 GC bgGC
; /* the background GC to draw with */
111 GC fgGC
; /* the foreground GC to draw with */
112 Pixmap db
; /* the buffer on which to draw */
113 WMPixmap
*bgPixmap
; /* the background pixmap */
115 myRect visible
; /* the actual rectangle that can be drawn into */
116 myRect cursor
; /* the position and (height) of cursor */
117 myRect sel
; /* the selection rectangle */
119 WMPoint clicked
; /* where in the _document_ was clicked */
121 unsigned short tpos
; /* the position in the currentTextBlock */
122 unsigned short docWidth
; /* the width of the entire document */
123 unsigned int docHeight
; /* the height of the entire document */
125 TextBlock
*firstTextBlock
;
126 TextBlock
*lastTextBlock
;
127 TextBlock
*currentTextBlock
;
129 WMArray
*gfxItems
; /* a nice array of graphic items */
132 WMHandlerID timerID
; /* for nice twinky-winky */
137 WMTextDelegate
*delegate
;
140 WMRulerMargins
*margins
; /* an array of margins */
142 unsigned int nMargins
:7; /* the total number of margins in use */
144 unsigned int monoFont
:1; /* whether to ignore formats and graphic */
145 unsigned int focused
:1; /* whether this instance has input focus */
146 unsigned int editable
:1; /* "silly user, you can't edit me" */
147 unsigned int ownsSelection
:1; /* "I ownz the current selection!" */
148 unsigned int pointerGrabbed
:1;/* "heh, gib me pointer" */
149 unsigned int extendSelection
:1; /* shift-drag to select more regions */
151 unsigned int rulerShown
:1; /* whether the ruler is shown or not */
152 unsigned int frozen
:1; /* whether screen updates are to be made */
153 unsigned int cursorShown
:1; /* whether to show the cursor */
154 unsigned int acceptsGraphic
:1;/* accept graphic when dropped */
155 unsigned int horizOnDemand
:1;/* if a large image should appear*/
156 unsigned int needsLayOut
:1; /* in case of Append/Deletes */
157 unsigned int ignoreNewLine
:1;/* turn it into a ' ' in streams > 1 */
158 unsigned int indentNewLine
:1;/* add " " for a newline typed */
159 unsigned int laidOut
:1; /* have the TextBlocks all been laid out */
160 unsigned int waitingForSelection
:1; /* I don't wanna wait in vain... */
161 unsigned int prepend
:1; /* prepend=1, append=0 (for parsers) */
162 WMAlignment alignment
:2; /* the alignment for text */
163 WMReliefType relief
:3; /* the relief to display with */
164 unsigned int isOverGraphic
:2;/* the mouse is over a graphic */
165 unsigned int first
:1; /* for plain text parsing, newline? */
166 /* unsigned int RESERVED:1; */
171 #define NOTIFY(T,C,N,A) {\
172 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);}
181 /* just to print blocks of text not terminated by \0 */
183 output(char *ptr
, int len
)
188 /* printf(" s is [%s] (%d)\n", s, strlen(s)); */
194 #define CURSOR_BLINK_ON_DELAY 600
195 #define CURSOR_BLINK_OFF_DELAY 400
198 static char *default_bullet
[] = {
200 " c None s None", ". c black",
201 "X c white", "o c #808080",
209 static void handleEvents(XEvent
*event
, void *data
);
210 static void layOutDocument(Text
*tPtr
);
211 static void updateScrollers(Text
*tPtr
);
215 getMarginNumber(Text
*tPtr
, WMRulerMargins
*margins
)
219 for(i
=0; i
< tPtr
->nMargins
; i
++) {
221 if(WMIsMarginEqualToMargin(&tPtr
->margins
[i
], margins
))
231 newMargin(Text
*tPtr
, WMRulerMargins
*margins
)
236 tPtr
->margins
[0].retainCount
++;
240 n
= getMarginNumber(tPtr
, margins
);
244 if(tPtr
->nMargins
>= 127) {
245 n
= tPtr
->nMargins
-1;
249 tPtr
->margins
= wrealloc(tPtr
->margins
,
250 (++tPtr
->nMargins
)*sizeof(WMRulerMargins
));
252 n
= tPtr
->nMargins
-1;
253 tPtr
->margins
[n
].left
= margins
->left
;
254 tPtr
->margins
[n
].first
= margins
->first
;
255 tPtr
->margins
[n
].body
= margins
->body
;
256 tPtr
->margins
[n
].right
= margins
->right
;
257 /* for each tab... */
258 tPtr
->margins
[n
].retainCount
= 1;
260 tPtr
->margins
[n
].retainCount
++;
267 sectionWasSelected(Text
*tPtr
, TextBlock
*tb
, XRectangle
*rect
, int s
)
269 unsigned short i
, w
, lw
, selected
= False
, extend
= False
;
273 /* if selection rectangle completely encloses the section */
274 if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
275 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
276 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
278 sel
.w
= tPtr
->visible
.w
;
279 selected
= extend
= True
;
281 /* or if it starts on a line and then goes further down */
282 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
283 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
284 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
285 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
286 >= tPtr
->visible
.y
+ tPtr
->sel
.y
) ) {
287 sel
.x
= WMAX(tPtr
->sel
.x
, tPtr
->clicked
.x
);
288 sel
.w
= tPtr
->visible
.w
;
289 selected
= extend
= True
;
291 /* or if it begins before a line, but ends on it */
292 } else if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
293 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
294 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
295 && (tb
->sections
[s
]._y
296 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
298 if (1||tPtr
->sel
.x
+ tPtr
->sel
.w
> tPtr
->clicked
.x
)
299 sel
.w
= tPtr
->sel
.x
+ tPtr
->sel
.w
;
306 /* or if the selection rectangle lies entirely within a line */
307 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
308 && (tPtr
->sel
.w
>= 2)
309 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
310 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
319 /* if not within (modified) selection rectangle */
320 if ( tb
->sections
[s
].x
> sel
.x
+ sel
.w
321 || tb
->sections
[s
].x
+ tb
->sections
[s
].w
< sel
.x
)
325 if ( tb
->sections
[s
].x
+ tb
->sections
[s
].w
<= sel
.x
+ sel
.w
326 && tb
->sections
[s
].x
>= sel
.x
) {
327 rect
->width
= tb
->sections
[s
].w
;
328 rect
->x
= tb
->sections
[s
].x
;
333 i
= tb
->sections
[s
].begin
;
336 if (0&& tb
->sections
[s
].x
>= sel
.x
) {
337 tb
->s_begin
= tb
->sections
[s
].begin
;
341 while (++i
<= tb
->sections
[s
].end
) {
343 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
346 if (lw
+ tb
->sections
[s
].x
>= sel
.x
347 || i
== tb
->sections
[s
].end
) {
350 tb
->s_begin
= (tb
->selected
? WMIN(tb
->s_begin
, i
) : i
);
355 if (i
> tb
->sections
[s
].end
) {
356 printf("WasSelected: (i > tb->sections[s].end) \n");
360 _selEnd
: rect
->x
= tb
->sections
[s
].x
+ lw
;
362 while(++i
<= tb
->sections
[s
].end
) {
364 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
367 if (lw
+ rect
->x
>= sel
.x
+ sel
.w
368 || i
== tb
->sections
[s
].end
) {
370 if (i
!= tb
->sections
[s
].end
) {
376 if (tb
->sections
[s
].last
&& sel
.x
+ sel
.w
377 >= tb
->sections
[s
].x
+ tb
->sections
[s
].w
379 rect
->width
+= (tPtr
->visible
.w
- rect
->x
- lw
);
382 tb
->s_end
= (tb
->selected
? WMAX(tb
->s_end
, i
) : i
);
391 rect
->y
= tb
->sections
[s
]._y
- tPtr
->vpos
;
392 rect
->height
= tb
->sections
[s
].h
;
393 if(tb
->graphic
) { printf("graphic s%d h%d\n", s
,tb
->sections
[s
].h
);}
400 setSelectionProperty(WMText
*tPtr
, WMFont
*font
, WMColor
*color
, int underlined
)
405 tb
= tPtr
->firstTextBlock
;
406 if (!tb
|| !tPtr
->flags
.ownsSelection
)
409 if(font
&& (!color
|| underlined
==-1))
413 if (tPtr
->flags
.monoFont
|| tb
->selected
) {
415 if (tPtr
->flags
.monoFont
|| (tb
->s_end
- tb
->s_begin
== tb
->used
)
420 WMReleaseFont(tb
->d
.font
);
421 tb
->d
.font
= WMRetainFont(font
);
423 } else if(underlined
!=-1) {
424 tb
->underlined
= underlined
;
426 WMReleaseColor(tb
->color
);
427 tb
->color
= WMRetainColor(color
);
430 } else if (tb
->s_end
<= tb
->used
&& tb
->s_begin
< tb
->s_end
) {
432 TextBlock
*midtb
, *otb
= tb
;
434 if(underlined
!= -1) {
435 midtb
= (TextBlock
*) WMCreateTextBlockWithText(tPtr
,
436 &(tb
->text
[tb
->s_begin
]), tb
->d
.font
, tb
->color
,
437 False
, (tb
->s_end
- tb
->s_begin
));
439 midtb
= (TextBlock
*) WMCreateTextBlockWithText(tPtr
,
440 &(tb
->text
[tb
->s_begin
]),
441 (isFont
?font
:tb
->d
.font
),
442 (isFont
?tb
->color
:color
),
443 False
, (tb
->s_end
- tb
->s_begin
));
448 if(underlined
!= -1) {
449 midtb
->underlined
= underlined
;
451 midtb
->underlined
= otb
->underlined
;
454 midtb
->selected
= !True
;
456 midtb
->s_end
= midtb
->used
;
457 tPtr
->currentTextBlock
= tb
;
458 WMAppendTextBlock(tPtr
, midtb
);
459 tb
= tPtr
->currentTextBlock
;
462 if (otb
->used
- otb
->s_end
> 0) {
465 WMCreateTextBlockWithText(tPtr
,
466 &(otb
->text
[otb
->s_end
]), otb
->d
.font
, otb
->color
,
467 False
, otb
->used
- otb
->s_end
);
470 ntb
->underlined
= otb
->underlined
;
471 ntb
->selected
= False
;
472 WMAppendTextBlock(tPtr
, ntb
);
473 tb
= tPtr
->currentTextBlock
;
478 tPtr
->currentTextBlock
= midtb
;
481 otb
->selected
= False
;
482 otb
->used
= otb
->s_begin
;
489 tPtr
->flags
.needsLayOut
= True
;
492 /* in case the size changed... */
493 if(isFont
&& tPtr
->currentTextBlock
) {
494 TextBlock
*tb
= tPtr
->currentTextBlock
;
496 printf("%d %d %d\n", tPtr
->sel
.y
, tPtr
->sel
.h
, tPtr
->sel
.w
);
497 tPtr
->sel
.y
= 3 + tb
->sections
[0]._y
;
498 tPtr
->sel
.h
= tb
->sections
[tb
->nsections
-1]._y
- tb
->sections
[0]._y
;
499 tPtr
->sel
.w
= tb
->sections
[tb
->nsections
-1].w
;
500 if(tb
->sections
[tb
->nsections
-1]._y
!= tb
->sections
[0]._y
) {
503 printf("%d %d %d\n\n\n", tPtr
->sel
.y
, tPtr
->sel
.h
, tPtr
->sel
.w
);
510 removeSelection(Text
*tPtr
)
512 TextBlock
*tb
= NULL
;
515 if (!(tb
= tPtr
->firstTextBlock
))
520 if(!first
&& !tb
->graphic
) {
521 WMReleaseFont(tPtr
->dFont
);
522 tPtr
->dFont
= WMRetainFont(tb
->d
.font
);
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 getFirstNonGraphicBlockFor(TextBlock
*tb
, short dir
)
552 TextBlock
*hold
= tb
;
560 tb
= (dir
? tb
->next
: tb
->prior
);
568 tb
= (dir
? tb
->prior
: tb
->next
);
580 updateStartForCurrentTextBlock(Text
*tPtr
, int x
, int y
, int *dir
,
583 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
584 tb
= getFirstNonGraphicBlockFor(tb
, *dir
);
589 tPtr
->currentTextBlock
=
590 (dir
? tPtr
->lastTextBlock
: tPtr
->firstTextBlock
);
598 layOutDocument(tPtr
);
602 *dir
= !(y
<= tb
->sections
[0].y
);
604 if ( ( y
<= tb
->sections
[0]._y
+ tb
->sections
[0].h
)
605 && (y
>= tb
->sections
[0]._y
) ) {
606 /* if it's on the same line */
607 if(x
< tb
->sections
[0].x
)
611 if ( ( y
<= tb
->sections
[tb
->nsections
-1]._y
612 + tb
->sections
[tb
->nsections
-1].h
)
613 && (y
>= tb
->sections
[tb
->nsections
-1]._y
) ) {
614 /* if it's on the same line */
615 if(x
> tb
->sections
[tb
->nsections
-1].x
)
625 paintText(Text
*tPtr
)
631 int len
, y
, c
, s
, done
=False
, prev_y
=-23, dir
/* 1 = down */;
632 WMScreen
*scr
= tPtr
->view
->screen
;
633 Display
*dpy
= tPtr
->view
->screen
->display
;
634 Window win
= tPtr
->view
->window
;
637 if (!tPtr
->view
->flags
.realized
|| !tPtr
->db
|| tPtr
->flags
.frozen
)
641 XFillRectangle(dpy
, tPtr
->db
, tPtr
->bgGC
,
642 0, 0, tPtr
->visible
.w
, tPtr
->visible
.h
);
644 if (tPtr
->bgPixmap
) {
645 WMDrawPixmap(tPtr
->bgPixmap
, tPtr
->db
,
646 (tPtr
->visible
.w
-tPtr
->visible
.x
-tPtr
->bgPixmap
->width
)/2,
647 (tPtr
->visible
.h
-tPtr
->visible
.y
-tPtr
->bgPixmap
->height
)/2);
650 if (! (tb
= tPtr
->currentTextBlock
)) {
651 if (! (tb
= tPtr
->firstTextBlock
)) {
656 if (tPtr
->flags
.ownsSelection
) {
657 color
= WMGrayColor(scr
);
658 greyGC
= WMColorGC(color
);
659 WMReleaseColor(color
);
666 /* first, which direction? Don't waste time looking all over,
667 since the parts to be drawn will most likely be near what
668 was previously drawn */
669 if(!updateStartForCurrentTextBlock(tPtr
, 0, tPtr
->vpos
, &dir
, tb
))
674 if (tb
->graphic
&& tPtr
->flags
.monoFont
)
678 if(tPtr
->vpos
<= tb
->sections
[tb
->nsections
-1]._y
679 + tb
->sections
[tb
->nsections
-1].h
)
682 if(tPtr
->vpos
>= tb
->sections
[tb
->nsections
-1]._y
683 + tb
->sections
[tb
->nsections
-1].h
)
700 /* first, place all text that can be viewed */
701 while (!done
&& tb
) {
703 /* paragraph diagnostic
704 if(tb->blank) {tb->text[0] = 'F'; } */
711 tb
->selected
= False
;
713 for(s
=0; s
<tb
->nsections
&& !done
; s
++) {
715 if (tb
->sections
[s
]._y
> tPtr
->vpos
+ tPtr
->visible
.h
) {
720 if ( tb
->sections
[s
].y
+ tb
->sections
[s
].h
< tPtr
->vpos
)
723 if (tPtr
->flags
.monoFont
) {
728 gc
= WMColorGC(tb
->color
);
731 if (tPtr
->flags
.ownsSelection
) {
734 if ( sectionWasSelected(tPtr
, tb
, &rect
, s
)) {
736 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
737 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
741 prev_y
= tb
->sections
[s
]._y
;
743 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
744 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
745 y
= tb
->sections
[s
].y
- tPtr
->vpos
;
746 WMDrawString(scr
, tPtr
->db
, gc
, font
,
747 tb
->sections
[s
].x
- tPtr
->hpos
, y
, text
, len
);
749 if (!tPtr
->flags
.monoFont
&& tb
->underlined
) {
750 XDrawLine(dpy
, tPtr
->db
, gc
,
751 tb
->sections
[s
].x
- tPtr
->hpos
,
753 tb
->sections
[s
].x
+ tb
->sections
[s
].w
- tPtr
->hpos
,
759 tb
= (!done
? tb
->next
: NULL
);
763 /* now , show all graphic items that can be viewed */
764 c
= WMGetArrayItemCount(tPtr
->gfxItems
);
765 if (c
> 0 && !tPtr
->flags
.monoFont
) {
769 tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
);
771 /* if it's not viewable, and mapped, unmap it */
772 if (tb
->sections
[0]._y
+ tb
->sections
[0].h
<= tPtr
->vpos
773 || tb
->sections
[0]._y
>= tPtr
->vpos
+ tPtr
->visible
.h
) {
776 if ((W_VIEW(tb
->d
.widget
))->flags
.mapped
) {
777 WMUnmapWidget(tb
->d
.widget
);
781 /* if it's viewable, and not mapped, map it */
783 W_View
*view
= W_VIEW(tb
->d
.widget
);
785 if (!view
->flags
.realized
)
786 WMRealizeWidget(tb
->d
.widget
);
787 if(!view
->flags
.mapped
) {
788 XMapWindow(view
->screen
->display
, view
->window
);
789 XFlush(view
->screen
->display
);
790 view
->flags
.mapped
= 1;
794 if (tPtr
->flags
.ownsSelection
) {
797 if ( sectionWasSelected(tPtr
, tb
, &rect
, 0)) {
799 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
800 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
805 WMMoveWidget(tb
->d
.widget
,
806 tb
->sections
[0].x
+ tPtr
->visible
.x
- tPtr
->hpos
,
807 tb
->sections
[0].y
+ tPtr
->visible
.y
- tPtr
->vpos
);
808 h
= WMWidgetHeight(tb
->d
.widget
) + 1;
811 WMDrawPixmap(tb
->d
.pixmap
, tPtr
->db
,
812 tb
->sections
[0].x
- tPtr
->hpos
,
813 tb
->sections
[0].y
- tPtr
->vpos
);
814 h
= tb
->d
.pixmap
->height
+ 1;
818 if (!tPtr
->flags
.monoFont
&& tb
->underlined
) {
819 XDrawLine(dpy
, tPtr
->db
, WMColorGC(tb
->color
),
820 tb
->sections
[0].x
- tPtr
->hpos
,
821 tb
->sections
[0].y
+ h
- tPtr
->vpos
,
822 tb
->sections
[0].x
+ tb
->sections
[0].w
- tPtr
->hpos
,
823 tb
->sections
[0].y
+ h
- tPtr
->vpos
);
831 if (tPtr
->flags
.editable
&& tPtr
->flags
.cursorShown
832 && tPtr
->cursor
.x
!= -23 && tPtr
->flags
.focused
) {
833 int y
= tPtr
->cursor
.y
- tPtr
->vpos
;
834 XDrawLine(dpy
, tPtr
->db
, tPtr
->fgGC
,
836 tPtr
->cursor
.x
, y
+ tPtr
->cursor
.h
);
839 XCopyArea(dpy
, tPtr
->db
, win
, tPtr
->bgGC
, 0, 0,
840 tPtr
->visible
.w
, tPtr
->visible
.h
,
841 tPtr
->visible
.x
, tPtr
->visible
.y
);
843 W_DrawRelief(scr
, win
, 0, 0,
844 tPtr
->view
->size
.width
, tPtr
->view
->size
.height
,
847 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)
848 XDrawLine(dpy
, win
, tPtr
->fgGC
,
849 2, 42, tPtr
->view
->size
.width
-4, 42);
854 mouseOverObject(Text
*tPtr
, int x
, int y
)
859 x
-= tPtr
->visible
.x
;
861 y
-= tPtr
->visible
.y
;
864 if(tPtr
->flags
.ownsSelection
) {
867 && tPtr
->sel
.x
+ tPtr
->sel
.w
>= x
868 && tPtr
->sel
.y
+ tPtr
->sel
.h
>= y
) {
869 tPtr
->flags
.isOverGraphic
= 1;
876 int j
, c
= WMGetArrayItemCount(tPtr
->gfxItems
);
879 tPtr
->flags
.isOverGraphic
= 0;
883 tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
);
885 if(!tb
|| !tb
->sections
) {
886 tPtr
->flags
.isOverGraphic
= 0;
891 if(tb
->sections
[0].x
<= x
892 && tb
->sections
[0].y
<= y
893 && tb
->sections
[0].x
+ tb
->sections
[0].w
>= x
894 && tb
->sections
[0].y
+ tb
->d
.pixmap
->height
>= y
) {
895 tPtr
->flags
.isOverGraphic
= 3;
906 tPtr
->flags
.isOverGraphic
= 0;
909 tPtr
->view
->attribs
.cursor
= (result
?
910 tPtr
->view
->screen
->defaultCursor
911 : tPtr
->view
->screen
->textCursor
);
913 XSetWindowAttributes attribs
;
914 attribs
.cursor
= tPtr
->view
->attribs
.cursor
;
915 XChangeWindowAttributes(tPtr
->view
->screen
->display
,
916 tPtr
->view
->window
, CWCursor
,
924 blinkCursor(void *data
)
926 Text
*tPtr
= (Text
*)data
;
928 if (tPtr
->flags
.cursorShown
) {
929 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY
,
932 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
,
936 tPtr
->flags
.cursorShown
= !tPtr
->flags
.cursorShown
;
941 updateCursorPosition(Text
*tPtr
)
943 TextBlock
*tb
= NULL
;
946 if(tPtr
->flags
.needsLayOut
)
947 layOutDocument(tPtr
);
949 if (! (tb
= tPtr
->currentTextBlock
)) {
950 if (! (tb
= tPtr
->firstTextBlock
)) {
951 WMFont
*font
= tPtr
->dFont
;
953 tPtr
->cursor
.h
= font
->height
+ abs(font
->height
-font
->y
);
964 y
= tb
->sections
[0].y
;
965 h
= tb
->sections
[0].h
;
966 x
= tb
->sections
[0].x
;
968 } else if(tb
->graphic
) {
969 y
= tb
->sections
[0].y
;
970 h
= tb
->sections
[0].h
;
971 x
= tb
->sections
[0].x
;
974 if(tPtr
->tpos
> tb
->used
)
975 tPtr
->tpos
= tb
->used
;
977 for(s
=0; s
<tb
->nsections
-1; s
++) {
979 if(tPtr
->tpos
>= tb
->sections
[s
].begin
980 && tPtr
->tpos
<= tb
->sections
[s
].end
)
984 y
= tb
->sections
[s
]._y
;
985 h
= tb
->sections
[s
].h
;
986 x
= tb
->sections
[s
].x
+ WMWidthOfString(
987 (tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
),
988 &tb
->text
[tb
->sections
[s
].begin
],
989 tPtr
->tpos
- tb
->sections
[s
].begin
);
997 /* scroll the bars if the cursor is not visible */
998 if(tPtr
->flags
.editable
&& tPtr
->cursor
.x
!= -23) {
999 if(tPtr
->cursor
.y
+tPtr
->cursor
.h
1000 > tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
) {
1002 (tPtr
->cursor
.y
+tPtr
->cursor
.h
+10
1003 - (tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
));
1004 } else if(tPtr
->cursor
.y
< tPtr
->vpos
+tPtr
->visible
.y
) {
1005 tPtr
->vpos
-= (tPtr
->vpos
+tPtr
->visible
.y
-tPtr
->cursor
.y
);
1010 updateScrollers(tPtr
);
1015 cursorToTextPosition(Text
*tPtr
, int x
, int y
)
1017 TextBlock
*tb
= NULL
;
1018 int done
=False
, s
, pos
, len
, _w
, _y
, dir
=1; /* 1 == "down" */
1021 if(tPtr
->flags
.needsLayOut
)
1022 layOutDocument(tPtr
);
1024 y
+= (tPtr
->vpos
- tPtr
->visible
.y
);
1028 x
-= (tPtr
->visible
.x
- 2);
1032 /* clicked is relative to document, not window... */
1033 tPtr
->clicked
.x
= x
;
1034 tPtr
->clicked
.y
= y
;
1036 if (! (tb
= tPtr
->currentTextBlock
)) {
1037 if (! (tb
= tPtr
->firstTextBlock
)) {
1038 WMFont
*font
= tPtr
->dFont
;
1040 tPtr
->cursor
.h
= font
->height
+ abs(font
->height
-font
->y
);
1047 /* first, which direction? Most likely, newly clicked
1048 position will be close to previous */
1049 if(!updateStartForCurrentTextBlock(tPtr
, x
, y
, &dir
, tb
))
1053 s
= (dir
? 0 : tb
->nsections
-1);
1054 if ( y
>= tb
->sections
[s
]._y
1055 && y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) {
1059 /* get the first (or last) section of the TextBlock that
1060 lies about the vertical click point */
1062 while (!done
&& tb
) {
1064 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1065 if( (dir
?tb
->next
:tb
->prior
))
1066 tb
= (dir
?tb
->next
:tb
->prior
);
1070 s
= (dir
? 0 : tb
->nsections
-1);
1071 while (!done
&& (dir
? (s
<tb
->nsections
) : (s
>=0) )) {
1073 if ( (dir
? (y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) :
1074 ( y
>= tb
->sections
[s
]._y
) ) ) {
1082 if ( (dir
? tb
->next
: tb
->prior
)) {
1083 tb
= (dir
? tb
->next
: tb
->prior
);
1086 break; /* goto _doneH; */
1092 if (s
<0 || s
>=tb
->nsections
) {
1093 s
= (dir
? tb
->nsections
-1 : 0);
1097 /* we have the line, which TextBlock on that line is it? */
1098 pos
= (dir
?0:tb
->sections
[s
].begin
);
1099 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1100 TextBlock
*hold
= tb
;
1101 tb
= getFirstNonGraphicBlockFor(hold
, dir
);
1115 _y
= tb
->sections
[s
]._y
;
1119 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1120 tb
= (dir
? tb
->next
: tb
->prior
);
1127 _w
= WMWidgetWidth(tb
->d
.widget
)-5;
1129 _w
= tb
->d
.pixmap
->width
-5;
1131 if (tb
->sections
[0].x
+ _w
>= x
)
1134 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
1135 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
1136 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
1137 if (tb
->sections
[s
].x
+ _w
>= x
)
1142 if (tb
->sections
[s
].x
<= x
)
1146 if ((dir
? tb
->next
: tb
->prior
)) {
1147 TextBlock
*nxt
= (dir
? tb
->next
: tb
->prior
);
1148 if (tPtr
->flags
.monoFont
&& nxt
->graphic
) {
1149 nxt
= getFirstNonGraphicBlockFor(nxt
, dir
);
1151 pos
= (dir
?0:tb
->sections
[s
].begin
);
1152 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
1157 if (_y
!= nxt
->sections
[dir
?0:nxt
->nsections
-1]._y
) {
1158 /* this must be the last/first on this line. stop */
1159 pos
= (dir
? tb
->sections
[s
].end
: 0);
1160 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
1164 tPtr
->cursor
.x
+= WMWidgetWidth(tb
->d
.widget
);
1166 tPtr
->cursor
.x
+= tb
->d
.pixmap
->width
;
1167 } else if (pos
> tb
->sections
[s
].begin
) {
1169 WMWidthOfString(tb
->d
.font
,
1170 &(tb
->text
[tb
->sections
[s
].begin
]),
1171 pos
- tb
->sections
[s
].begin
);
1178 if ( (dir
? tb
->next
: tb
->prior
)) {
1179 tb
= (dir
? tb
->next
: tb
->prior
);
1186 s
= (dir
? 0 : tb
->nsections
-1);
1189 /* we have said TextBlock, now where within it? */
1192 int gw
= (tb
->object
?
1193 WMWidgetWidth(tb
->d
.widget
) : tb
->d
.pixmap
->width
);
1195 tPtr
->cursor
.x
= tb
->sections
[0].x
;
1197 if(x
> tPtr
->cursor
.x
+ gw
/2) {
1199 printf("here x%d: %d\n", x
, tPtr
->cursor
.x
+ gw
/2);
1200 tPtr
->cursor
.x
+= gw
;
1207 WMFont
*f
= tb
->d
.font
;
1208 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
1209 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
1211 _w
= x
- tb
->sections
[s
].x
;
1214 while (pos
<len
&& WMWidthOfString(f
, text
, pos
+1) < _w
)
1217 tPtr
->cursor
.x
= tb
->sections
[s
].x
+
1218 (pos
? WMWidthOfString(f
, text
, pos
) : 0);
1220 pos
+= tb
->sections
[s
].begin
;
1225 tPtr
->tpos
= (pos
<tb
->used
)? pos
: tb
->used
;
1228 printf("...for this app will surely crash :-)\n");
1230 tPtr
->currentTextBlock
= tb
;
1231 tPtr
->cursor
.h
= tb
->sections
[s
].h
;
1232 tPtr
->cursor
.y
= tb
->sections
[s
]._y
;
1234 /* scroll the bars if the cursor is not visible */
1235 if(tPtr
->flags
.editable
&& tPtr
->cursor
.x
!= -23) {
1236 if(tPtr
->cursor
.y
+tPtr
->cursor
.h
1237 > tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
) {
1239 (tPtr
->cursor
.y
+tPtr
->cursor
.h
+10
1240 - (tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
));
1241 updateScrollers(tPtr
);
1242 } else if(tPtr
->cursor
.y
< tPtr
->vpos
+tPtr
->visible
.y
) {
1243 tPtr
->vpos
-= (tPtr
->vpos
+tPtr
->visible
.y
-tPtr
->cursor
.y
);
1244 updateScrollers(tPtr
);
1253 updateScrollers(Text
*tPtr
)
1256 if (tPtr
->flags
.frozen
)
1260 if (tPtr
->docHeight
< tPtr
->visible
.h
) {
1261 WMSetScrollerParameters(tPtr
->vS
, 0, 1);
1264 float hmax
= (float)(tPtr
->docHeight
);
1265 WMSetScrollerParameters(tPtr
->vS
,
1266 ((float)tPtr
->vpos
)/(hmax
- (float)tPtr
->visible
.h
),
1267 (float)tPtr
->visible
.h
/hmax
);
1269 } else tPtr
->vpos
= 0;
1272 if (tPtr
->docWidth
< tPtr
->visible
.w
) {
1273 WMSetScrollerParameters(tPtr
->hS
, 0, 1);
1276 float wmax
= (float)(tPtr
->docWidth
);
1277 WMSetScrollerParameters(tPtr
->hS
,
1278 ((float)tPtr
->hpos
)/(wmax
- (float)tPtr
->visible
.w
),
1279 (float)tPtr
->visible
.w
/wmax
);
1281 } else tPtr
->hpos
= 0;
1285 scrollersCallBack(WMWidget
*w
, void *self
)
1287 Text
*tPtr
= (Text
*)self
;
1288 Bool scroll
= False
;
1291 if (!tPtr
->view
->flags
.realized
|| tPtr
->flags
.frozen
)
1294 if (w
== tPtr
->vS
) {
1296 height
= tPtr
->visible
.h
;
1298 which
= WMGetScrollerHitPart(tPtr
->vS
);
1301 case WSDecrementLine
:
1302 if (tPtr
->vpos
> 0) {
1303 if (tPtr
->vpos
>16) tPtr
->vpos
-=16;
1309 case WSIncrementLine
: {
1310 int limit
= tPtr
->docHeight
- height
;
1311 if (tPtr
->vpos
< limit
) {
1312 if (tPtr
->vpos
<limit
-16) tPtr
->vpos
+=16;
1313 else tPtr
->vpos
=limit
;
1319 case WSDecrementPage
:
1320 if(((int)tPtr
->vpos
- (int)height
) >= 0)
1321 tPtr
->vpos
-= height
;
1328 case WSIncrementPage
:
1329 tPtr
->vpos
+= height
;
1330 if (tPtr
->vpos
> (tPtr
->docHeight
- height
))
1331 tPtr
->vpos
= tPtr
->docHeight
- height
;
1337 tPtr
->vpos
= WMGetScrollerValue(tPtr
->vS
)
1338 * (float)(tPtr
->docHeight
- height
);
1346 scroll
= (tPtr
->vpos
!= tPtr
->prevVpos
);
1347 tPtr
->prevVpos
= tPtr
->vpos
;
1351 if (w
== tPtr
->hS
) {
1352 int width
= tPtr
->visible
.w
;
1354 which
= WMGetScrollerHitPart(tPtr
->hS
);
1357 case WSDecrementLine
:
1358 if (tPtr
->hpos
> 0) {
1359 if (tPtr
->hpos
>16) tPtr
->hpos
-=16;
1364 case WSIncrementLine
: {
1365 int limit
= tPtr
->docWidth
- width
;
1366 if (tPtr
->hpos
< limit
) {
1367 if (tPtr
->hpos
<limit
-16) tPtr
->hpos
+=16;
1368 else tPtr
->hpos
=limit
;
1373 case WSDecrementPage
:
1374 if(((int)tPtr
->hpos
- (int)width
) >= 0)
1375 tPtr
->hpos
-= width
;
1382 case WSIncrementPage
:
1383 tPtr
->hpos
+= width
;
1384 if (tPtr
->hpos
> (tPtr
->docWidth
- width
))
1385 tPtr
->hpos
= tPtr
->docWidth
- width
;
1391 tPtr
->hpos
= WMGetScrollerValue(tPtr
->hS
)
1392 * (float)(tPtr
->docWidth
- width
);
1400 scroll
= (tPtr
->hpos
!= tPtr
->prevHpos
);
1401 tPtr
->prevHpos
= tPtr
->hpos
;
1405 updateScrollers(tPtr
);
1414 unsigned short begin
, end
; /* what part of the text block */
1419 layOutLine(Text
*tPtr
, myLineItems
*items
, int nitems
, int x
, int y
)
1421 int i
, j
=0, lw
= 0, line_height
=0, max_d
=0, len
, n
;
1424 TextBlock
*tb
, *tbsame
=NULL
;
1426 if(!items
|| nitems
== 0)
1429 for(i
=0; i
<nitems
; i
++) {
1433 if (!tPtr
->flags
.monoFont
) {
1435 WMWidget
*wdt
= tb
->d
.widget
;
1436 line_height
= WMAX(line_height
, WMWidgetHeight(wdt
));
1437 if (tPtr
->flags
.alignment
!= WALeft
)
1438 lw
+= WMWidgetWidth(wdt
);
1440 line_height
= WMAX(line_height
,
1441 tb
->d
.pixmap
->height
+ max_d
);
1442 if (tPtr
->flags
.alignment
!= WALeft
)
1443 lw
+= tb
->d
.pixmap
->width
;
1448 font
= (tPtr
->flags
.monoFont
)?tPtr
->dFont
: tb
->d
.font
;
1449 max_d
= WMAX(max_d
, abs(font
->height
-font
->y
));
1450 line_height
= WMAX(line_height
, font
->height
+ max_d
);
1451 text
= &(tb
->text
[items
[i
].begin
]);
1452 len
= items
[i
].end
- items
[i
].begin
;
1453 if (tPtr
->flags
.alignment
!= WALeft
)
1454 lw
+= WMWidthOfString(font
, text
, len
);
1458 if (tPtr
->flags
.alignment
== WARight
) {
1459 j
= tPtr
->visible
.w
- lw
;
1460 } else if (tPtr
->flags
.alignment
== WACenter
) {
1461 j
= (int) ((float)(tPtr
->visible
.w
- lw
))/2.0;
1464 for(i
=0; i
<nitems
; i
++) {
1467 if (tbsame
== tb
) { /* extend it, since it's on same line */
1468 tb
->sections
[tb
->nsections
-1].end
= items
[i
].end
;
1469 n
= tb
->nsections
-1;
1471 tb
->sections
= wrealloc(tb
->sections
,
1472 (++tb
->nsections
)*sizeof(Section
));
1473 n
= tb
->nsections
-1;
1474 tb
->sections
[n
]._y
= y
+ max_d
;
1475 tb
->sections
[n
].max_d
= max_d
;
1476 tb
->sections
[n
].x
= x
+j
;
1477 tb
->sections
[n
].h
= line_height
;
1478 tb
->sections
[n
].begin
= items
[i
].begin
;
1479 tb
->sections
[n
].end
= items
[i
].end
;
1482 tb
->sections
[n
].last
= (i
+1 == nitems
);
1485 if (!tPtr
->flags
.monoFont
) {
1487 WMWidget
*wdt
= tb
->d
.widget
;
1488 tb
->sections
[n
].y
= max_d
+ y
1489 + line_height
- WMWidgetHeight(wdt
);
1490 tb
->sections
[n
].w
= WMWidgetWidth(wdt
);
1492 tb
->sections
[n
].y
= y
+ line_height
1493 + max_d
- tb
->d
.pixmap
->height
;
1494 tb
->sections
[n
].w
= tb
->d
.pixmap
->width
;
1496 x
+= tb
->sections
[n
].w
;
1499 font
= (tPtr
->flags
.monoFont
)? tPtr
->dFont
: tb
->d
.font
;
1500 len
= items
[i
].end
- items
[i
].begin
;
1501 text
= &(tb
->text
[items
[i
].begin
]);
1503 tb
->sections
[n
].y
= y
+line_height
-font
->y
;
1505 WMWidthOfString(font
,
1506 &(tb
->text
[tb
->sections
[n
].begin
]),
1507 tb
->sections
[n
].end
- tb
->sections
[n
].begin
);
1509 x
+= WMWidthOfString(font
, text
, len
);
1521 layOutDocument(Text
*tPtr
)
1524 myLineItems
*items
= NULL
;
1525 unsigned int itemsSize
=0, nitems
=0, begin
, end
;
1527 unsigned int x
, y
=0, lw
= 0, width
=0, bmargin
;
1528 char *start
=NULL
, *mark
=NULL
;
1530 if ( tPtr
->flags
.frozen
|| (!(tb
= tPtr
->firstTextBlock
)) )
1533 assert(tPtr
->visible
.w
> 20);
1535 tPtr
->docWidth
= tPtr
->visible
.w
;
1536 x
= tPtr
->margins
[tb
->marginN
].first
;
1537 bmargin
= tPtr
->margins
[tb
->marginN
].body
;
1539 /* only partial layOut needed: re-Lay only affected textblocks */
1540 if (tPtr
->flags
.laidOut
) {
1541 tb
= tPtr
->currentTextBlock
;
1543 /* search backwards for textblocks on same line */
1545 if (!tb
->sections
|| tb
->nsections
<1) {
1546 tb
= tPtr
->firstTextBlock
;
1547 tPtr
->flags
.laidOut
= False
;
1552 if(!tb
->prior
->sections
|| tb
->prior
->nsections
<1) {
1553 tb
= tPtr
->firstTextBlock
;
1554 tPtr
->flags
.laidOut
= False
;
1559 if (tb
->sections
[0]._y
!=
1560 tb
->prior
->sections
[tb
->prior
->nsections
-1]._y
) {
1566 if(tb
->prior
&& tb
->prior
->sections
&& tb
->prior
->nsections
>0) {
1567 y
= tb
->prior
->sections
[tb
->prior
->nsections
-1]._y
+
1568 tb
->prior
->sections
[tb
->prior
->nsections
-1].h
-
1569 tb
->prior
->sections
[tb
->prior
->nsections
-1].max_d
;
1578 if (tb
->sections
&& tb
->nsections
>0) {
1579 wfree(tb
->sections
);
1580 tb
->sections
= NULL
;
1584 if (tb
->blank
&& tb
->next
&& !tb
->next
->first
) {
1585 TextBlock
*next
= tb
->next
;
1586 tPtr
->currentTextBlock
= tb
;
1587 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1593 if (tb
->first
&& tb
!= tPtr
->firstTextBlock
) {
1594 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1595 x
= tPtr
->margins
[tb
->marginN
].first
;
1596 bmargin
= tPtr
->margins
[tb
->marginN
].body
;
1602 if (!tPtr
->flags
.monoFont
) {
1604 width
= WMWidgetWidth(tb
->d
.widget
);
1606 width
= tb
->d
.pixmap
->width
;
1608 if (width
> tPtr
->docWidth
)
1609 tPtr
->docWidth
= width
;
1612 if (lw
>= tPtr
->visible
.w
- x
) {
1613 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1619 if(nitems
+ 1> itemsSize
) {
1620 items
= wrealloc(items
,
1621 (++itemsSize
)*sizeof(myLineItems
));
1624 items
[nitems
].tb
= tb
;
1625 items
[nitems
].begin
= 0;
1626 items
[nitems
].end
= 0;
1630 } else if ((start
= tb
->text
)) {
1632 font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
1635 mark
= strchr(start
, ' ');
1637 end
+= (int)(mark
-start
)+1;
1640 end
+= strlen(start
);
1647 if (end
-begin
> 0) {
1649 width
= WMWidthOfString(font
,
1650 &tb
->text
[begin
], end
-begin
);
1652 /* if it won't fit, char wrap it */
1653 if (width
>= tPtr
->visible
.w
) {
1654 char *t
= &tb
->text
[begin
];
1655 int l
=end
-begin
, i
=0;
1657 width
= WMWidthOfString(font
, t
, ++i
);
1658 } while (width
< tPtr
->visible
.w
&& i
< l
);
1661 start
= &tb
->text
[end
];
1667 if (lw
>= tPtr
->visible
.w
- x
) {
1668 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1674 if(nitems
+ 1 > itemsSize
) {
1675 items
= wrealloc(items
,
1676 (++itemsSize
)*sizeof(myLineItems
));
1679 items
[nitems
].tb
= tb
;
1680 items
[nitems
].begin
= begin
;
1681 items
[nitems
].end
= end
;
1689 /* not yet fully ready. but is already VERY FAST for a 3Mbyte file ;-) */
1690 if(0&&tPtr
->flags
.laidOut
1691 && tb
->next
&& tb
->next
->sections
&& tb
->next
->nsections
>0
1692 && (tPtr
->vpos
+ tPtr
->visible
.h
1693 < tb
->next
->sections
[0]._y
)) {
1694 if(tPtr
->lastTextBlock
->sections
1695 && tPtr
->lastTextBlock
->nsections
> 0 ) {
1696 TextBlock
*ltb
= tPtr
->lastTextBlock
;
1697 int ly
= ltb
->sections
[ltb
->nsections
-1]._y
;
1698 int lh
= ltb
->sections
[ltb
->nsections
-1].h
;
1701 lh
+= 1 + tPtr
->visible
.y
+ ltb
->sections
[ltb
->nsections
-1].max_d
;
1702 printf("it's %d\n", tPtr
->visible
.y
+ ltb
->sections
[ltb
->nsections
-1].max_d
);
1704 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1706 sd
= tPtr
->docHeight
-y
;
1708 printf("dif %d-%d: %d\n", ss
, sd
, ss
-sd
);
1709 y
+= tb
->next
->sections
[0]._y
-y
;
1711 printf("nitems%d\n", nitems
);
1713 y
= tPtr
->docHeight
+ss
-sd
;
1717 tPtr
->flags
.laidOut
= False
;
1726 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1728 if (tPtr
->docHeight
!= y
+10) {
1729 tPtr
->docHeight
= y
+10;
1730 updateScrollers(tPtr
);
1733 if(tPtr
->docWidth
> tPtr
->visible
.w
&& !tPtr
->hS
) {
1736 tPtr
->flags
.horizOnDemand
= True
;
1737 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, True
);
1738 event
.type
= Expose
;
1739 handleEvents(&event
, (void *)tPtr
);
1741 } else if(tPtr
->docWidth
<= tPtr
->visible
.w
1742 && tPtr
->hS
&& tPtr
->flags
.horizOnDemand
) {
1743 tPtr
->flags
.horizOnDemand
= False
;
1744 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, False
);
1747 tPtr
->flags
.laidOut
= True
;
1749 if(items
&& itemsSize
> 0)
1756 textDidResize(W_ViewDelegate
*self
, WMView
*view
)
1758 Text
*tPtr
= (Text
*)view
->self
;
1759 unsigned short w
= tPtr
->view
->size
.width
;
1760 unsigned short h
= tPtr
->view
->size
.height
;
1761 unsigned short rh
= 0, vw
= 0, rel
;
1763 rel
= (tPtr
->flags
.relief
== WRFlat
);
1765 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
) {
1766 WMMoveWidget(tPtr
->ruler
, 2, 2);
1767 WMResizeWidget(tPtr
->ruler
, w
- 4, 40);
1772 WMMoveWidget(tPtr
->vS
, 1 - (rel
?1:0), rh
+ 1 - (rel
?1:0));
1773 WMResizeWidget(tPtr
->vS
, 20, h
- rh
- 2 + (rel
?2:0));
1775 WMSetRulerOffset(tPtr
->ruler
,22);
1776 } else WMSetRulerOffset(tPtr
->ruler
, 2);
1780 WMMoveWidget(tPtr
->hS
, vw
, h
- 21);
1781 WMResizeWidget(tPtr
->hS
, w
- vw
- 1, 20);
1783 WMMoveWidget(tPtr
->hS
, vw
+1, h
- 21);
1784 WMResizeWidget(tPtr
->hS
, w
- vw
- 2, 20);
1788 tPtr
->visible
.x
= (tPtr
->vS
)?24:4;
1789 tPtr
->visible
.y
= (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)?43:3;
1790 tPtr
->visible
.w
= tPtr
->view
->size
.width
- tPtr
->visible
.x
- 8;
1791 tPtr
->visible
.h
= tPtr
->view
->size
.height
- tPtr
->visible
.y
;
1792 tPtr
->visible
.h
-= (tPtr
->hS
)?20:0;
1793 tPtr
->margins
[0].right
= tPtr
->visible
.w
;
1795 if (tPtr
->view
->flags
.realized
) {
1798 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
1799 tPtr
->db
= (Pixmap
) NULL
;
1802 if (tPtr
->visible
.w
< 40)
1803 tPtr
->visible
.w
= 40;
1804 if (tPtr
->visible
.h
< 20)
1805 tPtr
->visible
.h
= 20;
1808 tPtr
->db
= XCreatePixmap(tPtr
->view
->screen
->display
,
1809 tPtr
->view
->window
, tPtr
->visible
.w
,
1810 tPtr
->visible
.h
, tPtr
->view
->screen
->depth
);
1817 W_ViewDelegate _TextViewDelegate
=
1825 #define TEXT_BUFFER_INCR 8
1826 #define reqBlockSize(requested) (requested + TEXT_BUFFER_INCR)
1829 clearText(Text
*tPtr
)
1831 tPtr
->vpos
= tPtr
->hpos
= 0;
1832 tPtr
->docHeight
= tPtr
->docWidth
= 0;
1833 tPtr
->cursor
.x
= -23;
1835 if (!tPtr
->firstTextBlock
)
1838 while (tPtr
->currentTextBlock
)
1839 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1841 tPtr
->firstTextBlock
= NULL
;
1842 tPtr
->currentTextBlock
= NULL
;
1843 tPtr
->lastTextBlock
= NULL
;
1844 WMEmptyArray(tPtr
->gfxItems
);
1847 /* possibly remove a single character from the currentTextBlock,
1848 or if there's a selection, remove it...
1849 note that Delete and Backspace are treated differently */
1851 deleteTextInteractively(Text
*tPtr
, KeySym ksym
)
1854 Bool back
= (Bool
) (ksym
== XK_BackSpace
);
1855 Bool done
= 1, wasFirst
= 0;
1857 if (!tPtr
->flags
.editable
)
1860 if ( !(tb
= tPtr
->currentTextBlock
) )
1863 if (tPtr
->flags
.ownsSelection
) {
1864 if(removeSelection(tPtr
))
1865 layOutDocument(tPtr
);
1869 wasFirst
= tb
->first
;
1870 if (back
&& tPtr
->tpos
< 1) {
1872 if(tb
->prior
->blank
) {
1873 tPtr
->currentTextBlock
= tb
->prior
;
1874 WMRemoveTextBlock(tPtr
);
1875 tPtr
->currentTextBlock
= tb
;
1877 layOutDocument(tPtr
);
1881 TextBlock
*prior
= tb
->prior
;
1882 tPtr
->currentTextBlock
= tb
;
1883 WMRemoveTextBlock(tPtr
);
1889 tPtr
->tpos
= tb
->used
;
1890 tPtr
->currentTextBlock
= tb
;
1894 tb
->next
->first
= False
;
1895 layOutDocument(tPtr
);
1902 if ( (tb
->used
> 0) && ((back
?tPtr
->tpos
> 0:1))
1903 && (tPtr
->tpos
<= tb
->used
) && !tb
->graphic
) {
1906 memmove(&(tb
->text
[tPtr
->tpos
]),
1907 &(tb
->text
[tPtr
->tpos
+ 1]), tb
->used
- tPtr
->tpos
);
1912 /* if there are no characters left to back over in the textblock,
1913 but it still has characters to the right of the cursor: */
1914 if ( (back
? (tPtr
->tpos
== 0 && !done
) : ( tPtr
->tpos
>= tb
->used
))
1917 /* no more chars, and it's marked as blank? */
1919 TextBlock
*sibling
= (back
? tb
->prior
: tb
->next
);
1921 if(tb
->used
== 0 || tb
->graphic
)
1922 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1925 tPtr
->currentTextBlock
= sibling
;
1926 tPtr
->tpos
= (back
? sibling
->used
: 0);
1928 /* no more chars, so mark it as blank */
1929 } else if(tb
->used
== 0)
1933 layOutDocument(tPtr
);
1938 insertTextInteractively(Text
*tPtr
, char *text
, int len
)
1941 char *newline
= NULL
;
1943 if (!tPtr
->flags
.editable
) {
1947 if (len
< 1 || !text
)
1951 if(tPtr
->flags
.ignoreNewLine
&& *text
== '\n' && len
== 1)
1955 if (tPtr
->flags
.ownsSelection
)
1956 removeSelection(tPtr
);
1959 if (tPtr
->flags
.ignoreNewLine
) {
1961 for(i
=0; i
<len
; i
++) {
1962 if (text
[i
] == '\n')
1967 tb
= tPtr
->currentTextBlock
;
1968 if (!tb
|| tb
->graphic
) {
1970 WMAppendTextStream(tPtr
, text
);
1971 layOutDocument(tPtr
);
1975 if ((newline
= strchr(text
, '\n'))) {
1976 int nlen
= (int)(newline
-text
);
1977 int s
= tb
->used
- tPtr
->tpos
;
1979 if (!tb
->blank
&& nlen
>0) {
1981 memcpy(save
, &tb
->text
[tPtr
->tpos
], s
);
1982 tb
->used
-= (tb
->used
- tPtr
->tpos
);
1984 insertTextInteractively(tPtr
, text
, nlen
);
1986 WMAppendTextStream(tPtr
, newline
);
1988 insertTextInteractively(tPtr
, save
, s
);
1991 if (tPtr
->tpos
>0 && tPtr
->tpos
< tb
->used
1992 && !tb
->graphic
&& tb
->text
) {
1994 void *ntb
= WMCreateTextBlockWithText(
1995 tPtr
, &tb
->text
[tPtr
->tpos
],
1996 tb
->d
.font
, tb
->color
, True
, tb
->used
- tPtr
->tpos
);
1997 tb
->used
= tPtr
->tpos
;
1998 WMAppendTextBlock(tPtr
, ntb
);
2001 } else if (tPtr
->tpos
== tb
->used
|| tPtr
->tpos
== 0) {
2002 if(tPtr
->flags
.indentNewLine
) {
2003 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
2004 " ", tb
->d
.font
, tb
->color
, True
, 4));
2007 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
2008 NULL
, tb
->d
.font
, tb
->color
, True
, 0));
2015 if (tb
->used
+ len
>= tb
->allocated
) {
2016 tb
->allocated
= reqBlockSize(tb
->used
+len
);
2017 tb
->text
= wrealloc(tb
->text
, tb
->allocated
);
2021 memcpy(tb
->text
, text
, len
);
2024 tb
->text
[tb
->used
] = 0;
2028 memmove(&(tb
->text
[tPtr
->tpos
+len
]), &tb
->text
[tPtr
->tpos
],
2029 tb
->used
-tPtr
->tpos
+1);
2030 memmove(&tb
->text
[tPtr
->tpos
], text
, len
);
2033 tb
->text
[tb
->used
] = 0;
2038 layOutDocument(tPtr
);
2043 selectRegion(Text
*tPtr
, int x
, int y
)
2049 y
+= (tPtr
->flags
.rulerShown
? 40: 0);
2052 y
-= 10; /* the original offset */
2054 x
-= tPtr
->visible
.x
-2;
2058 tPtr
->sel
.x
= WMAX(0, WMIN(tPtr
->clicked
.x
, x
));
2059 tPtr
->sel
.w
= abs(tPtr
->clicked
.x
- x
);
2060 tPtr
->sel
.y
= WMAX(0, WMIN(tPtr
->clicked
.y
, y
));
2061 tPtr
->sel
.h
= abs(tPtr
->clicked
.y
- y
);
2063 tPtr
->flags
.ownsSelection
= True
;
2069 releaseSelection(Text
*tPtr
)
2071 TextBlock
*tb
= tPtr
->firstTextBlock
;
2074 tb
->selected
= False
;
2077 tPtr
->flags
.ownsSelection
= False
;
2078 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
,
2086 requestHandler(WMView
*view
, Atom selection
, Atom target
, void *cdata
,
2089 Text
*tPtr
= view
->self
;
2090 Display
*dpy
= tPtr
->view
->screen
->display
;
2092 Atom TEXT
= XInternAtom(dpy
, "TEXT", False
);
2093 Atom COMPOUND_TEXT
= XInternAtom(dpy
, "COMPOUND_TEXT", False
);
2094 WMData
*data
= NULL
;
2097 if (target
== XA_STRING
|| target
== TEXT
|| target
== COMPOUND_TEXT
) {
2098 char *text
= WMGetTextSelectedStream(tPtr
);
2101 data
= WMCreateDataWithBytes(text
, strlen(text
));
2102 WMSetDataFormat(data
, TYPETEXT
);
2106 } else printf("didn't get it\n");
2108 _TARGETS
= XInternAtom(dpy
, "TARGETS", False
);
2109 if (target
== _TARGETS
) {
2112 ptr
= wmalloc(4 * sizeof(Atom
));
2116 ptr
[3] = COMPOUND_TEXT
;
2118 data
= WMCreateDataWithBytes(ptr
, 4*4);
2119 WMSetDataFormat(data
, 32);
2129 lostHandler(WMView
*view
, Atom selection
, void *cdata
)
2131 releaseSelection((WMText
*)view
->self
);
2134 static WMSelectionProcs selectionHandler
= {
2135 requestHandler
, lostHandler
, NULL
2140 ownershipObserver(void *observerData
, WMNotification
*notification
)
2142 if (observerData
!= WMGetNotificationClientData(notification
))
2143 lostHandler(WMWidgetView(observerData
), XA_PRIMARY
, NULL
);
2147 autoSelectText(Text
*tPtr
, int clicks
)
2151 char *mark
= NULL
, behind
, ahead
;
2153 if(!(tb
= tPtr
->currentTextBlock
))
2159 switch(tb
->text
[tPtr
->tpos
]) {
2162 case '<': case '>': behind = '<'; ahead = '>'; break;
2163 case '{': case '}': behind = '{'; ahead = '}'; break;
2164 case '[': case ']': behind = '['; ahead = ']'; break;
2166 default: behind
= ahead
= ' ';
2169 tPtr
->sel
.y
= tPtr
->cursor
.y
+5;
2170 tPtr
->sel
.h
= 6;/*tPtr->cursor.h-10;*/
2173 tPtr
->sel
.x
= tb
->sections
[0].x
;
2174 tPtr
->sel
.w
= tb
->sections
[0].w
;
2176 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
2179 while(start
> 0 && tb
->text
[start
-1] != behind
)
2183 if(tPtr
->tpos
> start
){
2184 x
-= WMWidthOfString(font
, &tb
->text
[start
],
2185 tPtr
->tpos
- start
);
2187 tPtr
->sel
.x
= (x
<0?0:x
)+1;
2189 if((mark
= strchr(&tb
->text
[start
], ahead
))) {
2190 tPtr
->sel
.w
= WMWidthOfString(font
, &tb
->text
[start
],
2191 (int)(mark
- &tb
->text
[start
]));
2192 } else if(tb
->used
> start
) {
2193 tPtr
->sel
.w
= WMWidthOfString(font
, &tb
->text
[start
],
2198 } else if(clicks
== 3) {
2199 TextBlock
*cur
= tb
;
2201 while(tb
&& !tb
->first
) {
2204 tPtr
->sel
.y
= tb
->sections
[0]._y
;
2207 while(tb
->next
&& !tb
->next
->first
) {
2210 tPtr
->sel
.h
= tb
->sections
[tb
->nsections
-1]._y
2214 tPtr
->sel
.w
= tPtr
->docWidth
;
2215 tPtr
->clicked
.x
= 0; /* only for now, fix sel. code */
2218 if (!tPtr
->flags
.ownsSelection
) {
2219 WMCreateSelectionHandler(tPtr
->view
,
2220 XA_PRIMARY
, tPtr
->lastClickTime
, &selectionHandler
, NULL
);
2221 tPtr
->flags
.ownsSelection
= True
;
2229 fontChanged(void *observerData
, WMNotification
*notification
)
2231 WMText
*tPtr
= (WMText
*) observerData
;
2232 WMFont
*font
= (WMFont
*)WMGetNotificationClientData(notification
);
2233 printf("fontChanged\n");
2238 if (tPtr
->flags
.ownsSelection
)
2239 WMSetTextSelectionFont(tPtr
, font
);
2244 handleTextKeyPress(Text
*tPtr
, XEvent
*event
)
2248 int control_pressed
= False
;
2249 TextBlock
*tb
= NULL
;
2251 if (((XKeyEvent
*) event
)->state
& ControlMask
)
2252 control_pressed
= True
;
2253 buffer
[XLookupString(&event
->xkey
, buffer
, 63, &ksym
, NULL
)] = 0;
2258 if(!(tb
= tPtr
->currentTextBlock
))
2264 L_imaGFX
: if(tb
->prior
) {
2265 tPtr
->currentTextBlock
= tb
->prior
;
2266 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
2267 if(!tb
->first
&& tPtr
->tpos
> 0)
2269 } else tPtr
->tpos
= 0;
2270 } else tPtr
->tpos
--;
2271 updateCursorPosition(tPtr
);
2276 if(!(tb
= tPtr
->currentTextBlock
))
2280 if(tPtr
->tpos
== tb
->used
) {
2281 R_imaGFX
: if(tb
->next
) {
2282 tPtr
->currentTextBlock
= tb
->next
;
2284 if(!tb
->next
->first
&& tb
->next
->used
>0)
2286 } else tPtr
->tpos
= tb
->used
;
2287 } else tPtr
->tpos
++;
2288 updateCursorPosition(tPtr
);
2293 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
2294 tPtr
->clicked
.y
+ tPtr
->cursor
.h
- tPtr
->vpos
);
2299 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
2300 tPtr
->visible
.y
+ tPtr
->cursor
.y
- tPtr
->vpos
- 3);
2309 deleteTextInteractively(tPtr
, ksym
);
2310 updateCursorPosition(tPtr
);
2316 control_pressed
= True
;
2320 insertTextInteractively(tPtr
, " ", 4);
2321 updateCursorPosition(tPtr
);
2328 if (*buffer
!= 0 && !control_pressed
) {
2329 insertTextInteractively(tPtr
, buffer
, strlen(buffer
));
2330 updateCursorPosition(tPtr
);
2333 } else if (control_pressed
&& ksym
==XK_r
) {
2334 Bool i
= !tPtr
->flags
.rulerShown
;
2335 WMShowTextRuler(tPtr
, i
);
2336 tPtr
->flags
.rulerShown
= i
;
2338 else if (control_pressed
&& *buffer
== '\a')
2339 XBell(tPtr
->view
->screen
->display
, 0);
2341 WMRelayToNextResponder(tPtr
->view
, event
);
2344 if (!control_pressed
&& tPtr
->flags
.ownsSelection
)
2345 releaseSelection(tPtr
);
2350 pasteText(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
2351 void *cdata
, WMData
*data
)
2353 Text
*tPtr
= (Text
*)view
->self
;
2356 tPtr
->flags
.waitingForSelection
= 0;
2359 text
= (char*)WMDataBytes(data
);
2362 (tPtr
->parser
) (tPtr
, (void *) text
);
2363 layOutDocument(tPtr
);
2364 } else insertTextInteractively(tPtr
, text
, strlen(text
));
2365 updateCursorPosition(tPtr
);
2371 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
2376 (tPtr
->parser
) (tPtr
, (void *) text
);
2377 layOutDocument(tPtr
);
2378 } else insertTextInteractively(tPtr
, text
, n
);
2379 updateCursorPosition(tPtr
);
2391 handleActionEvents(XEvent
*event
, void *data
)
2393 Text
*tPtr
= (Text
*)data
;
2394 Display
*dpy
= event
->xany
.display
;
2398 switch (event
->type
) {
2400 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2401 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2402 tPtr
->flags
.extendSelection
= True
;
2406 if (tPtr
->flags
.focused
) {
2407 XGrabPointer(dpy
, W_VIEW(tPtr
)->window
, False
,
2408 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
2409 GrabModeAsync
, GrabModeAsync
, None
,
2410 tPtr
->view
->screen
->invisibleCursor
, CurrentTime
);
2411 tPtr
->flags
.pointerGrabbed
= True
;
2412 handleTextKeyPress(tPtr
, event
);
2417 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2418 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2419 tPtr
->flags
.extendSelection
= False
;
2421 /* end modify flag so selection can be extended */
2428 if (tPtr
->flags
.pointerGrabbed
) {
2429 tPtr
->flags
.pointerGrabbed
= False
;
2430 XUngrabPointer(dpy
, CurrentTime
);
2433 if(tPtr
->flags
.waitingForSelection
)
2436 if ((event
->xmotion
.state
& Button1Mask
)) {
2437 TextBlock
*tb
= tPtr
->currentTextBlock
;
2439 if(tb
&& tPtr
->flags
.isOverGraphic
&&
2440 tb
->graphic
&& !tb
->object
) {
2442 WMPixmap
*pixmap
= tb
->d
.pixmap
;
2443 char *types
[2] = {"application/X-image", NULL
};
2448 WMDragImageFromView(tPtr
->view
, pixmap
, types
,
2449 wmkpoint(event
->xmotion
.x_root
, event
->xmotion
.y_root
),
2454 if (!tPtr
->flags
.ownsSelection
) {
2455 WMCreateSelectionHandler(tPtr
->view
,
2456 XA_PRIMARY
, event
->xbutton
.time
,
2457 &selectionHandler
, NULL
);
2458 tPtr
->flags
.ownsSelection
= True
;
2461 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2465 mouseOverObject(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2471 if (tPtr
->flags
.pointerGrabbed
) {
2472 tPtr
->flags
.pointerGrabbed
= False
;
2473 XUngrabPointer(dpy
, CurrentTime
);
2477 if (tPtr
->flags
.waitingForSelection
)
2480 if (tPtr
->flags
.extendSelection
&& tPtr
->flags
.ownsSelection
) {
2481 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2485 if (tPtr
->flags
.ownsSelection
)
2486 releaseSelection(tPtr
);
2489 if (event
->xbutton
.button
== Button1
) {
2491 if(WMIsDoubleClick(event
)) {
2492 TextBlock
*tb
= tPtr
->currentTextBlock
;
2494 tPtr
->lastClickTime
= event
->xbutton
.time
;
2495 if(tb
&& tb
->graphic
&& !tb
->object
) {
2496 char desc
[tb
->used
+1];
2497 memcpy(desc
, tb
->text
, tb
->used
);
2499 if(tPtr
->delegate
) {
2500 if(tPtr
->delegate
->didDoubleClickOnPicture
)
2501 (*tPtr
->delegate
->didDoubleClickOnPicture
)
2502 (tPtr
->delegate
, desc
);
2505 autoSelectText(tPtr
, 2);
2508 } else if(event
->xbutton
.time
- tPtr
->lastClickTime
2509 < WINGsConfiguration
.doubleClickDelay
) {
2510 tPtr
->lastClickTime
= event
->xbutton
.time
;
2511 autoSelectText(tPtr
, 3);
2515 if (!tPtr
->flags
.focused
) {
2516 WMSetFocusToWidget(tPtr
);
2517 tPtr
->flags
.focused
= True
;
2520 tPtr
->lastClickTime
= event
->xbutton
.time
;
2521 cursorToTextPosition(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2525 if (event
->xbutton
.button
2526 == WINGsConfiguration
.mouseWheelDown
) {
2527 WMScrollText(tPtr
, 16);
2531 if (event
->xbutton
.button
2532 == WINGsConfiguration
.mouseWheelUp
) {
2533 WMScrollText(tPtr
, -16);
2537 if (event
->xbutton
.button
== Button2
) {
2541 if (!tPtr
->flags
.editable
) {
2546 if (!WMRequestSelection(tPtr
->view
, XA_PRIMARY
, XA_STRING
,
2547 event
->xbutton
.time
, pasteText
, NULL
)) {
2549 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
2550 tPtr
->flags
.waitingForSelection
= 0;
2556 (tPtr
->parser
) (tPtr
, (void *) text
);
2557 layOutDocument(tPtr
);
2560 insertTextInteractively(tPtr
, text
, n
);
2564 NOTIFY(tPtr
, didChange
, WMTextDidChangeNotification
,
2565 (void*)WMInsertTextEvent
);
2567 updateCursorPosition(tPtr
);
2571 tPtr
->flags
.waitingForSelection
= True
;
2579 if (tPtr
->flags
.pointerGrabbed
) {
2580 tPtr
->flags
.pointerGrabbed
= False
;
2581 XUngrabPointer(dpy
, CurrentTime
);
2585 if (tPtr
->flags
.waitingForSelection
)
2593 handleEvents(XEvent
*event
, void *data
)
2595 Text
*tPtr
= (Text
*)data
;
2597 switch(event
->type
) {
2600 if (event
->xexpose
.count
!=0)
2604 if (!(W_VIEW(tPtr
->hS
))->flags
.realized
)
2605 WMRealizeWidget(tPtr
->hS
);
2609 if (!(W_VIEW(tPtr
->vS
))->flags
.realized
)
2610 WMRealizeWidget(tPtr
->vS
);
2614 if (!(W_VIEW(tPtr
->ruler
))->flags
.realized
)
2615 WMRealizeWidget(tPtr
->ruler
);
2620 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2626 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))
2629 tPtr
->flags
.focused
= True
;
2631 if (tPtr
->flags
.editable
&& !tPtr
->timerID
) {
2632 tPtr
->timerID
= WMAddTimerHandler(12+0*CURSOR_BLINK_ON_DELAY
,
2640 tPtr
->flags
.focused
= False
;
2643 if (tPtr
->timerID
) {
2644 WMDeleteTimerHandler(tPtr
->timerID
);
2645 tPtr
->timerID
= NULL
;
2654 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
2656 WMEmptyArray(tPtr
->gfxItems
);
2659 WMDeleteTimerHandler(tPtr
->timerID
);
2661 WMReleaseFont(tPtr
->dFont
);
2662 WMReleaseColor(tPtr
->dColor
);
2663 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
, CurrentTime
);
2664 WMRemoveNotificationObserver(tPtr
);
2675 insertPlainText(Text
*tPtr
, char *text
)
2682 mark
= strchr(start
, '\n');
2684 tb
= WMCreateTextBlockWithText(tPtr
,
2686 tPtr
->dColor
, tPtr
->flags
.first
, (int)(mark
-start
));
2688 tPtr
->flags
.first
= True
;
2690 if (start
&& strlen(start
)) {
2691 tb
= WMCreateTextBlockWithText(tPtr
, start
, tPtr
->dFont
,
2692 tPtr
->dColor
, tPtr
->flags
.first
, strlen(start
));
2694 tPtr
->flags
.first
= False
;
2698 if (tPtr
->flags
.prepend
)
2699 WMPrependTextBlock(tPtr
, tb
);
2701 WMAppendTextBlock(tPtr
, tb
);
2707 rulerMoveCallBack(WMWidget
*w
, void *self
)
2709 Text
*tPtr
= (Text
*)self
;
2713 if (W_CLASS(tPtr
) != WC_Text
)
2721 rulerReleaseCallBack(WMWidget
*w
, void *self
)
2723 Text
*tPtr
= (Text
*)self
;
2727 if (W_CLASS(tPtr
) != WC_Text
)
2735 draggingSourceOperation(WMView
*self
, Bool local
)
2737 return WDOperationCopy
;
2741 fetchDragData(WMView
*self
, char *type
)
2743 TextBlock
*tb
= ((WMText
*)self
->self
)->currentTextBlock
;
2750 printf("type is [%s]\n", type
);
2751 desc
= wmalloc(tb
->used
+1);
2752 memcpy(desc
, tb
->text
, tb
->used
);
2754 data
= WMCreateDataWithBytes(desc
, strlen(desc
)+1);
2762 static WMDragSourceProcs _DragSourceProcs
= {
2763 draggingSourceOperation
,
2771 draggingEntered(WMView
*self
, WMDraggingInfo
*info
)
2773 printf("draggingEntered\n");
2774 return WDOperationCopy
;
2779 draggingUpdated(WMView
*self
, WMDraggingInfo
*info
)
2781 return WDOperationCopy
;
2786 draggingExited(WMView
*self
, WMDraggingInfo
*info
)
2788 printf("draggingExited\n");
2792 prepareForDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2794 printf("prepareForDragOperation\n");
2802 receivedData(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
2803 void *cdata
, WMData
*data
)
2805 badbadbad
= wstrdup((char *)WMDataBytes(data
));
2809 /* when it's done in WINGs, remove this */
2812 requestDroppedData(WMView
*view
, WMDraggingInfo
*info
, char *type
)
2814 WMScreen
*scr
= W_VIEW_SCREEN(view
);
2816 if (!WMRequestSelection(scr
->dragInfo
.destView
,
2817 scr
->xdndSelectionAtom
,
2818 XInternAtom(scr
->display
, type
, False
),
2819 scr
->dragInfo
.timestamp
,
2820 receivedData
, &scr
->dragInfo
)) {
2821 wwarning("could not request data for dropped data");
2827 ev
.type
= ClientMessage
;
2828 ev
.xclient
.message_type
= scr
->xdndFinishedAtom
;
2829 ev
.xclient
.format
= 32;
2830 ev
.xclient
.window
= info
->destinationWindow
;
2831 ev
.xclient
.data
.l
[0] = 0;
2832 ev
.xclient
.data
.l
[1] = 0;
2833 ev
.xclient
.data
.l
[2] = 0;
2834 ev
.xclient
.data
.l
[3] = 0;
2835 ev
.xclient
.data
.l
[4] = 0;
2837 XSendEvent(scr
->display
, info
->sourceWindow
, False
, 0, &ev
);
2838 XFlush(scr
->display
);
2844 performDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2847 WMText
*tPtr
= (WMText
*)self
->self
;
2852 requestDroppedData(tPtr
->view
, info
, "application/X-color");
2853 color
= WMCreateNamedColor(W_VIEW_SCREEN(self
), badbadbad
, True
);
2855 WMSetTextSelectionColor(tPtr
, color
);
2856 WMReleaseColor(color
);
2865 concludeDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2867 printf("concludeDragOperation\n");
2871 static WMDragDestinationProcs _DragDestinationProcs
= {
2875 prepareForDragOperation
,
2876 performDragOperation
,
2877 concludeDragOperation
2882 getStream(WMText
*tPtr
, int sel
, int array
)
2884 TextBlock
*tb
= NULL
;
2886 unsigned long where
= 0;
2891 if (!(tb
= tPtr
->firstTextBlock
))
2895 (tPtr
->writer
) (tPtr
, (void *) text
);
2899 tb
= tPtr
->firstTextBlock
;
2902 if (!tb
->graphic
|| (tb
->graphic
&& !tPtr
->flags
.monoFont
)) {
2904 if (!sel
|| (tb
->graphic
&& tb
->selected
)) {
2906 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
)
2907 && tb
!= tPtr
->firstTextBlock
) {
2908 text
= wrealloc(text
, where
+1);
2909 text
[where
++] = '\n';
2915 if(tb
->graphic
&& array
) {
2916 text
= wrealloc(text
, where
+4);
2917 text
[where
++] = 0xFA;
2918 text
[where
++] = (tb
->used
>>8)&0x0ff;
2919 text
[where
++] = tb
->used
&0x0ff;
2920 text
[where
++] = tb
->allocated
; /* extra info */
2922 text
= wrealloc(text
, where
+tb
->used
);
2923 memcpy(&text
[where
], tb
->text
, tb
->used
);
2927 } else if (sel
&& tb
->selected
) {
2929 if (!tPtr
->flags
.ignoreNewLine
&& tb
->blank
) {
2930 text
= wrealloc(text
, where
+1);
2931 text
[where
++] = '\n';
2937 text
= wrealloc(text
, where
+(tb
->s_end
- tb
->s_begin
));
2938 memcpy(&text
[where
], &tb
->text
[tb
->s_begin
],
2939 tb
->s_end
- tb
->s_begin
);
2940 where
+= tb
->s_end
- tb
->s_begin
;
2945 _gSnext
:tb
= tb
->next
;
2948 /* +1 for the end of string, let's be nice */
2949 text
= wrealloc(text
, where
+1);
2956 releaseStreamObjects(void *data
)
2963 getStreamObjects(WMText
*tPtr
, int sel
)
2965 WMArray
*array
= WMCreateArrayWithDestructor(4, releaseStreamObjects
);
2969 char *start
, *fa
, *desc
;
2971 stream
= getStream(tPtr
, sel
, 1);
2978 fa
= strchr(start
, 0xFA);
2980 if((int)(fa
- start
)>0) {
2982 desc
[(int)(fa
- start
)] = 0;
2983 data
= WMCreateDataWithBytes((void *)desc
, (int)(fa
- start
));
2984 WMSetDataFormat(data
, TYPETEXT
);
2985 WMAddToArray(array
, (void *) data
);
2988 len
= *(fa
+1)*0xff + *(fa
+2);
2989 data
= WMCreateDataWithBytes((void *)(fa
+4), len
);
2990 WMSetDataFormat(data
, *(fa
+3));
2991 WMAddToArray(array
, (void *) data
);
2992 start
= fa
+ len
+ 4;
2995 if (start
&& strlen(start
)) {
2996 data
= WMCreateDataWithBytes((void *)start
, strlen(start
));
2997 WMSetDataFormat(data
, TYPETEXT
);
2998 WMAddToArray(array
, (void *) data
);
3010 WMCreateTextForDocumentType(WMWidget
*parent
, WMAction
*parser
, WMAction
*writer
)
3014 tPtr
= wmalloc(sizeof(Text
));
3015 memset(tPtr
, 0, sizeof(Text
));
3016 tPtr
->widgetClass
= WC_Text
;
3017 tPtr
->view
= W_CreateView(W_VIEW(parent
));
3019 perror("could not create text's view\n");
3023 tPtr
->view
->self
= tPtr
;
3024 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->textCursor
;
3025 tPtr
->view
->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3026 W_ResizeView(tPtr
->view
, 250, 200);
3028 tPtr
->dColor
= WMWhiteColor(tPtr
->view
->screen
);
3029 tPtr
->bgGC
= WMColorGC(tPtr
->dColor
);
3030 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->dColor
);
3031 WMReleaseColor(tPtr
->dColor
);
3033 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
3034 tPtr
->fgGC
= WMColorGC(tPtr
->dColor
);
3040 tPtr
->dFont
= WMRetainFont(WMSystemFontOfSize(tPtr
->view
->screen
, 12));
3042 tPtr
->view
->delegate
= &_TextViewDelegate
;
3044 tPtr
->delegate
= NULL
;
3047 tPtr
->timerID
= NULL
;
3050 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
3051 |EnterWindowMask
|LeaveWindowMask
|FocusChangeMask
,
3052 handleEvents
, tPtr
);
3054 WMCreateEventHandler(tPtr
->view
, ButtonReleaseMask
|ButtonPressMask
3055 |KeyReleaseMask
|KeyPressMask
|Button1MotionMask
,
3056 handleActionEvents
, tPtr
);
3058 WMAddNotificationObserver(ownershipObserver
, tPtr
,
3059 "_lostOwnership", tPtr
);
3061 WMSetViewDragSourceProcs(tPtr
->view
, &_DragSourceProcs
);
3062 WMSetViewDragDestinationProcs(tPtr
->view
, &_DragDestinationProcs
);
3066 char *types
[3] = {"application/X-color", "application/X-image", NULL
};
3067 WMRegisterViewForDraggedTypes(tPtr
->view
, types
);
3070 WMAddNotificationObserver(fontChanged
, tPtr
,
3071 "WMFontPanelDidChangeNotification", tPtr
);
3073 tPtr
->firstTextBlock
= NULL
;
3074 tPtr
->lastTextBlock
= NULL
;
3075 tPtr
->currentTextBlock
= NULL
;
3078 tPtr
->gfxItems
= WMCreateArray(4);
3080 tPtr
->parser
= parser
;
3081 tPtr
->writer
= writer
;
3083 tPtr
->sel
.x
= tPtr
->sel
.y
= 2;
3084 tPtr
->sel
.w
= tPtr
->sel
.h
= 0;
3086 tPtr
->clicked
.x
= tPtr
->clicked
.y
= 2;
3088 tPtr
->visible
.x
= tPtr
->visible
.y
= 2;
3089 tPtr
->visible
.h
= tPtr
->view
->size
.height
;
3090 tPtr
->visible
.w
= tPtr
->view
->size
.width
- 4;
3092 tPtr
->cursor
.x
= -23;
3095 tPtr
->docHeight
= 0;
3096 tPtr
->dBulletPix
= WMCreatePixmapFromXPMData(tPtr
->view
->screen
,
3098 tPtr
->db
= (Pixmap
) NULL
;
3099 tPtr
->bgPixmap
= NULL
;
3101 tPtr
->margins
= WMGetRulerMargins(NULL
);
3102 tPtr
->margins
->right
= tPtr
->visible
.w
;
3105 tPtr
->flags
.rulerShown
= False
;
3106 tPtr
->flags
.monoFont
= False
;
3107 tPtr
->flags
.focused
= False
;
3108 tPtr
->flags
.editable
= True
;
3109 tPtr
->flags
.ownsSelection
= False
;
3110 tPtr
->flags
.pointerGrabbed
= False
;
3111 tPtr
->flags
.extendSelection
= False
;
3112 tPtr
->flags
.frozen
= False
;
3113 tPtr
->flags
.cursorShown
= True
;
3114 tPtr
->flags
.acceptsGraphic
= False
;
3115 tPtr
->flags
.horizOnDemand
= False
;
3116 tPtr
->flags
.needsLayOut
= False
;
3117 tPtr
->flags
.ignoreNewLine
= False
;
3118 tPtr
->flags
.indentNewLine
= False
;
3119 tPtr
->flags
.laidOut
= False
;
3120 tPtr
->flags
.ownsSelection
= False
;
3121 tPtr
->flags
.waitingForSelection
= False
;
3122 tPtr
->flags
.prepend
= False
;
3123 tPtr
->flags
.isOverGraphic
= False
;
3124 tPtr
->flags
.relief
= WRSunken
;
3125 tPtr
->flags
.isOverGraphic
= 0;
3126 tPtr
->flags
.alignment
= WALeft
;
3127 tPtr
->flags
.first
= True
;
3133 WMPrependTextStream(WMText
*tPtr
, char *text
)
3135 CHECK_CLASS(tPtr
, WC_Text
);
3138 if (tPtr
->flags
.ownsSelection
)
3139 releaseSelection(tPtr
);
3141 updateScrollers(tPtr
);
3145 tPtr
->flags
.prepend
= True
;
3146 if (text
&& tPtr
->parser
)
3147 (tPtr
->parser
) (tPtr
, (void *) text
);
3149 insertPlainText(tPtr
, text
);
3151 tPtr
->flags
.needsLayOut
= True
;
3153 if(!tPtr
->flags
.frozen
) {
3154 layOutDocument(tPtr
);
3160 WMAppendTextStream(WMText
*tPtr
, char *text
)
3162 CHECK_CLASS(tPtr
, WC_Text
);
3165 if (tPtr
->flags
.ownsSelection
)
3166 releaseSelection(tPtr
);
3168 updateScrollers(tPtr
);
3172 tPtr
->flags
.prepend
= False
;
3173 if (text
&& tPtr
->parser
)
3174 (tPtr
->parser
) (tPtr
, (void *) text
);
3176 insertPlainText(tPtr
, text
);
3178 tPtr
->flags
.needsLayOut
= True
;
3179 if(tPtr
->currentTextBlock
)
3180 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
3182 if(!tPtr
->flags
.frozen
) {
3183 layOutDocument(tPtr
);
3189 WMGetTextStream(WMText
*tPtr
)
3191 CHECK_CLASS(tPtr
, WC_Text
);
3192 return getStream(tPtr
, 0, 0);
3196 WMGetTextSelectedStream(WMText
*tPtr
)
3198 CHECK_CLASS(tPtr
, WC_Text
);
3199 return getStream(tPtr
, 1, 0);
3203 WMGetTextObjects(WMText
*tPtr
)
3205 CHECK_CLASS(tPtr
, WC_Text
);
3206 return getStreamObjects(tPtr
, 0);
3210 WMGetTextSelectedObjects(WMText
*tPtr
)
3212 CHECK_CLASS(tPtr
, WC_Text
);
3213 return getStreamObjects(tPtr
, 1);
3218 WMSetTextDelegate(WMText
*tPtr
, WMTextDelegate
*delegate
)
3220 CHECK_CLASS(tPtr
, WC_Text
);
3222 tPtr
->delegate
= delegate
;
3227 WMCreateTextBlockWithObject(WMText
*tPtr
, WMWidget
*w
,
3228 char *description
, WMColor
*color
,
3229 unsigned short first
, unsigned short extraInfo
)
3233 if (!w
|| !description
|| !color
)
3236 tb
= wmalloc(sizeof(TextBlock
));
3240 tb
->text
= wstrdup(description
);
3241 tb
->used
= strlen(description
);
3244 tb
->color
= WMRetainColor(color
);
3245 tb
->marginN
= newMargin(tPtr
, NULL
);
3246 tb
->allocated
= extraInfo
;
3251 tb
->underlined
= False
;
3252 tb
->selected
= False
;
3254 tb
->sections
= NULL
;
3264 WMCreateTextBlockWithPixmap(WMText
*tPtr
, WMPixmap
*p
,
3265 char *description
, WMColor
*color
,
3266 unsigned short first
, unsigned short extraInfo
)
3270 if (!p
|| !description
|| !color
)
3273 tb
= wmalloc(sizeof(TextBlock
));
3277 tb
->text
= wstrdup(description
);
3278 tb
->used
= strlen(description
);
3280 tb
->d
.pixmap
= WMRetainPixmap(p
);
3281 tb
->color
= WMRetainColor(color
);
3282 tb
->marginN
= newMargin(tPtr
, NULL
);
3283 tb
->allocated
= extraInfo
;
3288 tb
->underlined
= False
;
3289 tb
->selected
= False
;
3291 tb
->sections
= NULL
;
3301 WMCreateTextBlockWithText(WMText
*tPtr
, char *text
, WMFont
*font
, WMColor
*color
,
3302 unsigned short first
, unsigned short len
)
3306 if (!font
|| !color
)
3309 tb
= wmalloc(sizeof(TextBlock
));
3313 tb
->allocated
= reqBlockSize(len
);
3314 tb
->text
= (char *)wmalloc(tb
->allocated
);
3315 memset(tb
->text
, 0, tb
->allocated
);
3317 if (len
< 1|| !text
|| (*text
== '\n' && len
==1 )) {
3322 memcpy(tb
->text
, text
, len
);
3326 tb
->text
[tb
->used
] = 0;
3328 tb
->d
.font
= WMRetainFont(font
);
3329 tb
->color
= WMRetainColor(color
);
3330 tb
->marginN
= newMargin(tPtr
, NULL
);
3333 tb
->graphic
= False
;
3334 tb
->underlined
= False
;
3335 tb
->selected
= False
;
3337 tb
->sections
= NULL
;
3345 WMSetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int first
,
3346 unsigned int kanji
, unsigned int underlined
, int script
,
3347 WMRulerMargins
*margins
)
3349 TextBlock
*tb
= (TextBlock
*) vtb
;
3355 tb
->underlined
= underlined
;
3356 tb
->script
= script
;
3357 tb
->marginN
= newMargin(tPtr
, margins
);
3361 WMGetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int *first
,
3362 unsigned int *kanji
, unsigned int *underlined
, int *script
,
3363 WMRulerMargins
*margins
)
3365 TextBlock
*tb
= (TextBlock
*) vtb
;
3369 if (first
) *first
= tb
->first
;
3370 if (kanji
) *kanji
= tb
->kanji
;
3371 if (underlined
) *underlined
= tb
->underlined
;
3372 if (script
) *script
= tb
->script
;
3373 if (margins
) margins
= &tPtr
->margins
[tb
->marginN
];
3379 WMPrependTextBlock(WMText
*tPtr
, void *vtb
)
3381 TextBlock
*tb
= (TextBlock
*)vtb
;
3388 WMWidget
*w
= tb
->d
.widget
;
3389 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
3390 (W_VIEW(w
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3391 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3394 WMAddToArray(tPtr
->gfxItems
, (void *)tb
);
3396 } else tPtr
->tpos
= tb
->used
;
3398 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
3399 tb
->next
= tb
->prior
= NULL
;
3401 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
3402 = tPtr
->currentTextBlock
= tb
;
3407 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
3410 tb
->next
= tPtr
->currentTextBlock
;
3411 tb
->prior
= tPtr
->currentTextBlock
->prior
;
3412 if (tPtr
->currentTextBlock
->prior
)
3413 tPtr
->currentTextBlock
->prior
->next
= tb
;
3415 tPtr
->currentTextBlock
->prior
= tb
;
3417 tPtr
->firstTextBlock
= tb
;
3419 tPtr
->currentTextBlock
= tb
;
3424 WMAppendTextBlock(WMText
*tPtr
, void *vtb
)
3426 TextBlock
*tb
= (TextBlock
*)vtb
;
3433 WMWidget
*w
= tb
->d
.widget
;
3434 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
3435 (W_VIEW(w
))->attribs
.cursor
=
3436 tPtr
->view
->screen
->defaultCursor
;
3437 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3440 WMAddToArray(tPtr
->gfxItems
, (void *)tb
);
3442 } else tPtr
->tpos
= tb
->used
;
3444 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
3445 tb
->next
= tb
->prior
= NULL
;
3447 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
3448 = tPtr
->currentTextBlock
= tb
;
3453 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
3456 tb
->next
= tPtr
->currentTextBlock
->next
;
3457 tb
->prior
= tPtr
->currentTextBlock
;
3458 if (tPtr
->currentTextBlock
->next
)
3459 tPtr
->currentTextBlock
->next
->prior
= tb
;
3461 tPtr
->currentTextBlock
->next
= tb
;
3464 tPtr
->lastTextBlock
= tb
;
3466 tPtr
->currentTextBlock
= tb
;
3470 WMRemoveTextBlock(WMText
*tPtr
)
3472 TextBlock
*tb
= NULL
;
3474 if (!tPtr
|| !tPtr
->firstTextBlock
|| !tPtr
->lastTextBlock
3475 || !tPtr
->currentTextBlock
) {
3476 /* printf("cannot remove non existent TextBlock!\n"); */
3480 tb
= tPtr
->currentTextBlock
;
3482 WMRemoveFromArray(tPtr
->gfxItems
, (void *)tb
);
3485 WMUnmapWidget(tb
->d
.widget
);
3489 if (tPtr
->currentTextBlock
== tPtr
->firstTextBlock
) {
3490 if (tPtr
->currentTextBlock
->next
)
3491 tPtr
->currentTextBlock
->next
->prior
= NULL
;
3493 tPtr
->firstTextBlock
= tPtr
->currentTextBlock
->next
;
3494 tPtr
->currentTextBlock
= tPtr
->firstTextBlock
;
3496 } else if (tPtr
->currentTextBlock
== tPtr
->lastTextBlock
) {
3497 tPtr
->currentTextBlock
->prior
->next
= NULL
;
3498 tPtr
->lastTextBlock
= tPtr
->currentTextBlock
->prior
;
3499 tPtr
->currentTextBlock
= tPtr
->lastTextBlock
;
3501 tPtr
->currentTextBlock
->prior
->next
= tPtr
->currentTextBlock
->next
;
3502 tPtr
->currentTextBlock
->next
->prior
= tPtr
->currentTextBlock
->prior
;
3503 tPtr
->currentTextBlock
= tPtr
->currentTextBlock
->next
;
3510 WMDestroyTextBlock(WMText
*tPtr
, void *vtb
)
3512 TextBlock
*tb
= (TextBlock
*)vtb
;
3518 /* naturally, there's a danger to destroying
3519 widgets whose action brings us here:
3520 ie. press a button to destroy it... need to
3521 find a safer way. till then... this stays commented out */
3522 /* WMDestroyWidget(tb->d.widget);
3523 wfree(tb->d.widget); */
3524 tb
->d
.widget
= NULL
;
3526 WMReleasePixmap(tb
->d
.pixmap
);
3527 tb
->d
.pixmap
= NULL
;
3530 WMReleaseFont(tb
->d
.font
);
3533 WMReleaseColor(tb
->color
);
3534 if (tb
->sections
&& tb
->nsections
> 0)
3535 wfree(tb
->sections
);
3544 WMSetTextForegroundColor(WMText
*tPtr
, WMColor
*color
)
3550 tPtr
->fgGC
= WMColorGC(color
);
3552 WMColor
*color
= WMBlackColor(tPtr
->view
->screen
);
3553 tPtr
->fgGC
= WMColorGC(color
);
3554 WMReleaseColor(color
);
3561 WMSetTextBackgroundColor(WMText
*tPtr
, WMColor
*color
)
3567 tPtr
->bgGC
= WMColorGC(color
);
3568 W_SetViewBackgroundColor(tPtr
->view
, color
);
3570 tPtr
->bgGC
= WMColorGC(WMWhiteColor(tPtr
->view
->screen
));
3571 W_SetViewBackgroundColor(tPtr
->view
,
3572 WMWhiteColor(tPtr
->view
->screen
));
3578 void WMSetTextBackgroundPixmap(WMText
*tPtr
, WMPixmap
*pixmap
)
3584 WMReleasePixmap(tPtr
->bgPixmap
);
3587 tPtr
->bgPixmap
= WMRetainPixmap(pixmap
);
3589 tPtr
->bgPixmap
= NULL
;
3593 WMSetTextRelief(WMText
*tPtr
, WMReliefType relief
)
3597 tPtr
->flags
.relief
= relief
;
3598 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3602 WMSetTextHasHorizontalScroller(WMText
*tPtr
, Bool shouldhave
)
3607 if (shouldhave
&& !tPtr
->hS
) {
3608 tPtr
->hS
= WMCreateScroller(tPtr
);
3609 (W_VIEW(tPtr
->hS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3610 (W_VIEW(tPtr
->hS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3611 WMSetScrollerArrowsPosition(tPtr
->hS
, WSAMinEnd
);
3612 WMSetScrollerAction(tPtr
->hS
, scrollersCallBack
, tPtr
);
3613 WMMapWidget(tPtr
->hS
);
3614 } else if (!shouldhave
&& tPtr
->hS
) {
3615 WMUnmapWidget(tPtr
->hS
);
3616 WMDestroyWidget(tPtr
->hS
);
3622 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3627 WMSetTextHasRuler(WMText
*tPtr
, Bool shouldhave
)
3632 if(shouldhave
&& !tPtr
->ruler
) {
3633 tPtr
->ruler
= WMCreateRuler(tPtr
);
3634 (W_VIEW(tPtr
->ruler
))->attribs
.cursor
=
3635 tPtr
->view
->screen
->defaultCursor
;
3636 (W_VIEW(tPtr
->ruler
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3637 WMSetRulerReleaseAction(tPtr
->ruler
, rulerReleaseCallBack
, tPtr
);
3638 WMSetRulerMoveAction(tPtr
->ruler
, rulerMoveCallBack
, tPtr
);
3639 } else if(!shouldhave
&& tPtr
->ruler
) {
3640 WMShowTextRuler(tPtr
, False
);
3641 WMDestroyWidget(tPtr
->ruler
);
3644 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3648 WMShowTextRuler(WMText
*tPtr
, Bool show
)
3655 if(tPtr
->flags
.monoFont
)
3658 tPtr
->flags
.rulerShown
= show
;
3660 WMMapWidget(tPtr
->ruler
);
3662 WMUnmapWidget(tPtr
->ruler
);
3665 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3669 WMGetTextRulerShown(WMText
*tPtr
)
3677 return tPtr
->flags
.rulerShown
;
3682 WMSetTextHasVerticalScroller(WMText
*tPtr
, Bool shouldhave
)
3687 if (shouldhave
&& !tPtr
->vS
) {
3688 tPtr
->vS
= WMCreateScroller(tPtr
);
3689 (W_VIEW(tPtr
->vS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3690 (W_VIEW(tPtr
->vS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3691 WMSetScrollerArrowsPosition(tPtr
->vS
, WSAMaxEnd
);
3692 WMSetScrollerAction(tPtr
->vS
, scrollersCallBack
, tPtr
);
3693 WMMapWidget(tPtr
->vS
);
3694 } else if (!shouldhave
&& tPtr
->vS
) {
3695 WMUnmapWidget(tPtr
->vS
);
3696 WMDestroyWidget(tPtr
->vS
);
3702 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3708 WMScrollText(WMText
*tPtr
, int amount
)
3713 if (amount
== 0 || !tPtr
->view
->flags
.realized
)
3717 if (tPtr
->vpos
> 0) {
3718 if (tPtr
->vpos
> abs(amount
)) tPtr
->vpos
+= amount
;
3723 int limit
= tPtr
->docHeight
- tPtr
->visible
.h
;
3724 if (tPtr
->vpos
< limit
) {
3725 if (tPtr
->vpos
< limit
-amount
) tPtr
->vpos
+= amount
;
3726 else tPtr
->vpos
= limit
;
3731 if (scroll
&& tPtr
->vpos
!= tPtr
->prevVpos
) {
3732 updateScrollers(tPtr
);
3735 tPtr
->prevVpos
= tPtr
->vpos
;
3740 WMPageText(WMText
*tPtr
, Bool direction
)
3742 if (!tPtr
) return False
;
3743 if (!tPtr
->view
->flags
.realized
) return False
;
3745 return WMScrollText(tPtr
, direction
?tPtr
->visible
.h
:-tPtr
->visible
.h
);
3749 WMSetTextEditable(WMText
*tPtr
, Bool editable
)
3753 tPtr
->flags
.editable
= editable
;
3757 WMGetTextEditable(WMText
*tPtr
)
3761 return tPtr
->flags
.editable
;
3765 WMSetTextIndentNewLines(WMText
*tPtr
, Bool indent
)
3769 tPtr
->flags
.indentNewLine
= indent
;
3773 WMSetTextIgnoresNewline(WMText
*tPtr
, Bool ignore
)
3777 tPtr
->flags
.ignoreNewLine
= ignore
;
3781 WMGetTextIgnoresNewline(WMText
*tPtr
)
3785 return tPtr
->flags
.ignoreNewLine
;
3789 WMSetTextUsesMonoFont(WMText
*tPtr
, Bool mono
)
3795 if(tPtr
->flags
.rulerShown
)
3796 WMShowTextRuler(tPtr
, False
);
3797 if(tPtr
->flags
.alignment
!= WALeft
)
3798 tPtr
->flags
.alignment
= WALeft
;
3801 tPtr
->flags
.monoFont
= mono
;
3802 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3806 WMGetTextUsesMonoFont(WMText
*tPtr
)
3810 return tPtr
->flags
.monoFont
;
3815 WMSetTextDefaultFont(WMText
*tPtr
, WMFont
*font
)
3820 WMReleaseFont(tPtr
->dFont
);
3822 tPtr
->dFont
= WMRetainFont(font
);
3824 tPtr
->dFont
= WMRetainFont(WMSystemFontOfSize(tPtr
->view
->screen
, 12));
3828 WMGetTextDefaultFont(WMText
*tPtr
)
3833 return WMRetainFont(tPtr
->dFont
);
3837 WMSetTextDefaultColor(WMText
*tPtr
, WMColor
*color
)
3842 WMReleaseColor(tPtr
->dColor
);
3844 tPtr
->dColor
= WMRetainColor(color
);
3846 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
3850 WMGetTextDefaultColor(WMText
*tPtr
)
3855 return WMRetainColor(tPtr
->dColor
);
3859 WMSetTextAlignment(WMText
*tPtr
, WMAlignment alignment
)
3863 if(tPtr
->flags
.monoFont
)
3864 tPtr
->flags
.alignment
= WALeft
;
3866 tPtr
->flags
.alignment
= alignment
;
3871 WMGetTextInsertType(WMText
*tPtr
)
3875 return tPtr
->flags
.prepend
;
3880 WMSetTextSelectionColor(WMText
*tPtr
, WMColor
*color
)
3882 if (!tPtr
|| !color
)
3885 setSelectionProperty(tPtr
, NULL
, color
, -1);
3889 WMGetTextSelectionColor(WMText
*tPtr
)
3896 tb
= tPtr
->currentTextBlock
;
3898 if (!tb
|| !tPtr
->flags
.ownsSelection
)
3909 WMSetTextSelectionFont(WMText
*tPtr
, WMFont
*font
)
3914 setSelectionProperty(tPtr
, font
, NULL
, -1) ;
3918 WMGetTextSelectionFont(WMText
*tPtr
)
3925 tb
= tPtr
->currentTextBlock
;
3927 if (!tb
|| !tPtr
->flags
.ownsSelection
)
3934 tb
= getFirstNonGraphicBlockFor(tb
, 1);
3938 return (tb
->selected
? tb
->d
.font
: NULL
);
3943 WMSetTextSelectionUnderlined(WMText
*tPtr
, int underlined
)
3945 if (!tPtr
|| (underlined
!=0 && underlined
!=1))
3948 setSelectionProperty(tPtr
, NULL
, NULL
, underlined
);
3953 WMGetTextSelectionUnderlined(WMText
*tPtr
)
3960 tb
= tPtr
->currentTextBlock
;
3962 if (!tb
|| !tPtr
->flags
.ownsSelection
)
3968 return tb
->underlined
;
3973 WMFreezeText(WMText
*tPtr
)
3978 tPtr
->flags
.frozen
= True
;
3983 WMThawText(WMText
*tPtr
)
3988 tPtr
->flags
.frozen
= False
;
3990 if(tPtr
->flags
.monoFont
) {
3991 int j
, c
= WMGetArrayItemCount(tPtr
->gfxItems
);
3994 /* make sure to unmap widgets no matter where they are */
3995 /* they'll be later remapped if needed by paintText */
3996 for(j
=0; j
<c
; j
++) {
3997 if ((tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
))) {
3998 if (tb
->object
&& ((W_VIEW(tb
->d
.widget
))->flags
.mapped
))
3999 WMUnmapWidget(tb
->d
.widget
);
4005 tPtr
->flags
.laidOut
= False
;
4006 layOutDocument(tPtr
);
4007 updateScrollers(tPtr
);
4009 tPtr
->flags
.needsLayOut
= False
;
4013 /* find first occurence of a string */
4015 mystrstr(char *haystack
, char *needle
, unsigned short len
, char *end
,
4020 if(!haystack
|| !needle
|| !end
)
4023 for (ptr
= haystack
; ptr
< end
; ptr
++) {
4025 if (*ptr
== *needle
&& !strncmp(ptr
, needle
, len
))
4029 if (tolower(*ptr
) == tolower(*needle
) &&
4030 !strncasecmp(ptr
, needle
, len
))
4038 /* find last occurence of a string */
4040 mystrrstr(char *haystack
, char *needle
, unsigned short len
, char *end
,
4045 if(!haystack
|| !needle
|| !end
)
4048 for (ptr
= haystack
-2; ptr
> end
; ptr
--) {
4050 if (*ptr
== *needle
&& !strncmp(ptr
, needle
, len
))
4053 if (tolower(*ptr
) == tolower(*needle
) &&
4054 !strncasecmp(ptr
, needle
, len
))
4064 WMFindInTextStream(WMText
*tPtr
, char *needle
, Bool direction
,
4071 if (!tPtr
|| !needle
)
4075 if (! (tb
= tPtr
->currentTextBlock
)) {
4076 if (! (tb
= ( (direction
> 0) ?
4077 tPtr
->firstTextBlock
: tPtr
->lastTextBlock
) ) ){
4081 /* if(tb != ((direction>0) ?tPtr->firstTextBlock : tPtr->lastTextBlock))
4082 tb = (direction>0) ? tb->next : tb->prior; */
4083 if(tb
!= tPtr
->lastTextBlock
)
4087 tb
= tPtr
->currentTextBlock
;
4095 if(pos
+1 < tb
->used
)
4098 if(tb
->used
- pos
> 0 && pos
> 0) {
4099 mark
= mystrstr(&tb
->text
[pos
], needle
,
4100 strlen(needle
), &tb
->text
[tb
->used
], caseSensitive
);
4113 mark
= mystrrstr(&tb
->text
[pos
], needle
,
4114 strlen(needle
), tb
->text
, caseSensitive
);
4126 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
4128 tPtr
->tpos
= (int)(mark
- tb
->text
);
4129 tPtr
->currentTextBlock
= tb
;
4130 updateCursorPosition(tPtr
);
4131 tPtr
->sel
.y
= tPtr
->cursor
.y
+5;
4132 tPtr
->sel
.h
= tPtr
->cursor
.h
-10;
4133 tPtr
->sel
.x
= tPtr
->cursor
.x
+1;
4134 tPtr
->sel
.w
= WMIN(WMWidthOfString(font
,
4135 &tb
->text
[tPtr
->tpos
], strlen(needle
)),
4136 tPtr
->docWidth
- tPtr
->sel
.x
);
4137 tPtr
->flags
.ownsSelection
= True
;
4144 tb
= (direction
>0) ? tb
->next
: tb
->prior
;
4146 pos
= (direction
>0) ? 0 : tb
->used
;
4155 WMReplaceTextSelection(WMText
*tPtr
, char *replacement
)
4160 if (!tPtr
->flags
.ownsSelection
)
4163 removeSelection(tPtr
);
4166 insertTextInteractively(tPtr
, replacement
, strlen(replacement
));
4167 updateCursorPosition(tPtr
);