2 /* WINGs WMText: multi-line/font/color/graphic text widget, by Nwanua. */
7 #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 * - assess danger of destroying widgets whose actions link to other pages
20 * - Tabs now are simply replaced by 4 spaces...
21 * - redo blink code to reduce paint event... use pixmap buffer...
22 * - add paragraph support (full) and '\n' code in getStream..
26 /* a Section is a section of a TextBlock that describes what parts
27 of a TextBlock has been laid out on which "line"...
28 o this greatly aids redraw, scroll and selection.
29 o this is created during layoutLine, but may be later modified.
30 o there may be many Sections per TextBlock, hence the array */
32 unsigned int x
, y
; /* where to draw it from */
33 unsigned short w
, h
; /* its width and height */
34 unsigned short begin
; /* where the layout begins */
35 unsigned short end
; /* where it ends */
36 unsigned short max_d
; /* a quick hack for layOut if(laidOut) */
37 unsigned short last
:1; /* is it the last section on a "line"? */
38 unsigned int _y
:31; /* the "line" it and other textblocks are on */
42 /* a TextBlock is a node in a doubly-linked list of TextBlocks containing:
43 o text for the block, color and font
44 o or a pointer to the pixmap
45 o OR a pointer to the widget and the (text) description for its graphic
48 typedef struct _TextBlock
{
49 struct _TextBlock
*next
; /* next text block in linked list */
50 struct _TextBlock
*prior
; /* prior text block in linked list */
52 char *text
; /* pointer to text (could be kanji) */
53 /* or to the object's description */
55 WMFont
*font
; /* the font */
56 WMWidget
*widget
; /* the embedded widget */
57 WMPixmap
*pixmap
; /* the pixmap */
58 } d
; /* description */
60 unsigned short used
; /* number of chars in this block */
61 unsigned short allocated
; /* size of allocation (in chars) */
62 WMColor
*color
; /* the color */
64 Section
*sections
; /* the region for layouts (a growable array) */
65 /* an _array_! of size _nsections_ */
67 unsigned short s_begin
; /* where the selection begins */
68 unsigned short s_end
; /* where it ends */
70 unsigned int first
:1; /* first TextBlock in paragraph */
71 unsigned int blank
:1; /* ie. blank paragraph */
72 unsigned int kanji
:1; /* is of 16-bit characters or not */
73 unsigned int graphic
:1; /* graphic or text: text=0 */
74 unsigned int object
:1; /* embedded object or pixmap */
75 unsigned int underlined
:1; /* underlined or not */
76 unsigned int selected
:1; /* selected or not */
77 unsigned int nsections
:8; /* over how many "lines" a TextBlock wraps */
78 int script
:8; /* script in points: negative for subscript */
79 unsigned int marginN
:8; /* which of the margins in the tPtr to use */
80 unsigned int nClicks
:2; /* single, double, triple clicks */
81 unsigned int RESERVED
:7;
85 /* I'm lazy: visible.h vs. visible.size.height :-) */
91 typedef struct W_Text
{
92 W_Class widgetClass
; /* the class number of this widget */
93 W_View
*view
; /* the view referring to this instance */
95 WMRuler
*ruler
; /* the ruler widget to manipulate paragraphs */
97 WMScroller
*vS
; /* the vertical scroller */
98 unsigned int vpos
; /* the current vertical position */
99 unsigned int prevVpos
; /* the previous vertical position */
101 WMScroller
*hS
; /* the horizontal scroller */
102 unsigned int hpos
; /* the current horizontal position */
103 unsigned int prevHpos
; /* the previous horizontal position */
105 WMFont
*dFont
; /* the default font */
106 WMColor
*dColor
; /* the default color */
107 WMPixmap
*dBulletPix
; /* the default pixmap for bullets */
109 GC bgGC
; /* the background GC to draw with */
110 GC fgGC
; /* the foreground GC to draw with */
111 Pixmap db
; /* the buffer on which to draw */
113 myRect visible
; /* the actual rectangle that can be drawn into */
114 myRect cursor
; /* the position and (height) of cursor */
115 myRect sel
; /* the selection rectangle */
117 WMPoint clicked
; /* where in the _document_ was clicked */
119 unsigned short tpos
; /* the position in the currentTextBlock */
120 unsigned short docWidth
; /* the width of the entire document */
121 unsigned int docHeight
; /* the height of the entire document */
123 TextBlock
*firstTextBlock
;
124 TextBlock
*lastTextBlock
;
125 TextBlock
*currentTextBlock
;
127 WMArray
*gfxItems
; /* a nice array of graphic items */
130 WMHandlerID timerID
; /* for nice twinky-winky */
135 WMTextDelegate
*delegate
;
138 WMRulerMargins
*margins
; /* an array of margins */
140 unsigned int nMargins
:7; /* the total number of margins in use */
142 unsigned int monoFont
:1; /* whether to ignore formats and graphic */
143 unsigned int focused
:1; /* whether this instance has input focus */
144 unsigned int editable
:1; /* "silly user, you can't edit me" */
145 unsigned int ownsSelection
:1; /* "I ownz the current selection!" */
146 unsigned int pointerGrabbed
:1;/* "heh, gib me pointer" */
147 unsigned int extendSelection
:1; /* shift-drag to select more regions */
149 unsigned int rulerShown
:1; /* whether the ruler is shown or not */
150 unsigned int frozen
:1; /* whether screen updates are to be made */
151 unsigned int cursorShown
:1; /* whether to show the cursor */
152 unsigned int acceptsGraphic
:1;/* accept graphic when dropped */
153 unsigned int horizOnDemand
:1;/* if a large image should appear*/
154 unsigned int needsLayOut
:1; /* in case of Append/Deletes */
155 unsigned int ignoreNewLine
:1;/* turn it into a ' ' in streams > 1 */
156 unsigned int indentNewLine
:1;/* add " " for a newline typed */
157 unsigned int laidOut
:1; /* have the TextBlocks all been laid out */
158 unsigned int waitingForSelection
:1; /* I don't wanna wait in vain... */
159 unsigned int prepend
:1; /* prepend=1, append=0 (for parsers) */
160 WMAlignment alignment
:2; /* the alignment for text */
161 WMReliefType relief
:3; /* the relief to display with */
162 unsigned int isOverGraphic
:2;/* the mouse is over a graphic */
163 unsigned int first
:1; /* for plain text parsing, newline? */
164 /* unsigned int RESERVED:1; */
169 #define NOTIFY(T,C,N,A) { WMNotification *notif = WMCreateNotification(N,T,A);\
170 if ((T)->delegate && (T)->delegate->C)\
171 (*(T)->delegate->C)((T)->delegate,notif);\
172 WMPostNotification(notif);\
173 WMReleaseNotification(notif);}
179 output(char *ptr
, int len
)
184 /* printf(" s is [%s] (%d)\n", s, strlen(s)); */
190 #define CURSOR_BLINK_ON_DELAY 600
191 #define CURSOR_BLINK_OFF_DELAY 400
194 static char *default_bullet
[] = {
196 " c None s None", ". c black",
197 "X c white", "o c #808080",
205 static void handleEvents(XEvent
*event
, void *data
);
206 static void layOutDocument(Text
*tPtr
);
207 static void updateScrollers(Text
*tPtr
);
211 getMarginNumber(Text
*tPtr
, WMRulerMargins
*margins
)
215 for(i
=0; i
< tPtr
->nMargins
; i
++) {
217 if(WMIsMarginEqualToMargin(&tPtr
->margins
[i
], margins
))
227 newMargin(Text
*tPtr
, WMRulerMargins
*margins
)
232 tPtr
->margins
[0].retainCount
++;
236 n
= getMarginNumber(tPtr
, margins
);
240 tPtr
->margins
= wrealloc(tPtr
->margins
,
241 (++tPtr
->nMargins
)*sizeof(WMRulerMargins
));
243 n
= tPtr
->nMargins
-1;
244 tPtr
->margins
[n
].left
= margins
->left
;
245 tPtr
->margins
[n
].first
= margins
->first
;
246 tPtr
->margins
[n
].body
= margins
->body
;
247 tPtr
->margins
[n
].right
= margins
->right
;
248 /* for each tab... */
249 tPtr
->margins
[n
].retainCount
= 1;
251 tPtr
->margins
[n
].retainCount
++;
258 sectionWasSelected(Text
*tPtr
, TextBlock
*tb
, XRectangle
*rect
, int s
)
260 unsigned short i
, w
, lw
, selected
= False
, extend
= False
;
264 /* if selection rectangle completely encloses the section */
265 if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
266 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
267 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
269 sel
.w
= tPtr
->visible
.w
;
270 selected
= extend
= True
;
272 /* or if it starts on a line and then goes further down */
273 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
274 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
275 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
276 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
277 >= tPtr
->visible
.y
+ tPtr
->sel
.y
) ) {
278 sel
.x
= WMAX(tPtr
->sel
.x
, tPtr
->clicked
.x
);
279 sel
.w
= tPtr
->visible
.w
;
280 selected
= extend
= True
;
282 /* or if it begins before a line, but ends on it */
283 } else if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
284 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
285 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
286 && (tb
->sections
[s
]._y
287 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
289 if (1||tPtr
->sel
.x
+ tPtr
->sel
.w
> tPtr
->clicked
.x
)
290 sel
.w
= tPtr
->sel
.x
+ tPtr
->sel
.w
;
297 /* or if the selection rectangle lies entirely within a line */
298 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
299 && (tPtr
->sel
.w
>= 2)
300 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
301 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
310 /* if not within (modified) selection rectangle */
311 if ( tb
->sections
[s
].x
> sel
.x
+ sel
.w
312 || tb
->sections
[s
].x
+ tb
->sections
[s
].w
< sel
.x
)
316 if ( tb
->sections
[s
].x
+ tb
->sections
[s
].w
<= sel
.x
+ sel
.w
317 && tb
->sections
[s
].x
>= sel
.x
) {
318 rect
->width
= tb
->sections
[s
].w
;
319 rect
->x
= tb
->sections
[s
].x
;
324 i
= tb
->sections
[s
].begin
;
327 if (0&& tb
->sections
[s
].x
>= sel
.x
) {
328 tb
->s_begin
= tb
->sections
[s
].begin
;
332 while (++i
<= tb
->sections
[s
].end
) {
334 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
337 if (lw
+ tb
->sections
[s
].x
>= sel
.x
338 || i
== tb
->sections
[s
].end
) {
341 tb
->s_begin
= (tb
->selected
? WMIN(tb
->s_begin
, i
) : i
);
346 if (i
> tb
->sections
[s
].end
) {
347 printf("WasSelected: (i > tb->sections[s].end) \n");
351 _selEnd
: rect
->x
= tb
->sections
[s
].x
+ lw
;
353 while(++i
<= tb
->sections
[s
].end
) {
355 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
358 if (lw
+ rect
->x
>= sel
.x
+ sel
.w
359 || i
== tb
->sections
[s
].end
) {
361 if (i
!= tb
->sections
[s
].end
) {
367 if (tb
->sections
[s
].last
&& sel
.x
+ sel
.w
368 >= tb
->sections
[s
].x
+ tb
->sections
[s
].w
370 rect
->width
+= (tPtr
->visible
.w
- rect
->x
- lw
);
373 tb
->s_end
= (tb
->selected
? WMAX(tb
->s_end
, i
) : i
);
379 rect
->y
= tb
->sections
[s
]._y
- tPtr
->vpos
;
380 rect
->height
= tb
->sections
[s
].h
;
381 if(tb
->graphic
) { printf("graphic s%d h%d\n", s
,tb
->sections
[s
].h
);}
388 setSelectionProperty(WMText
*tPtr
, WMFont
*font
, WMColor
*color
, int underlined
)
393 tb
= tPtr
->firstTextBlock
;
394 if (!tb
|| !tPtr
->flags
.ownsSelection
)
397 if(font
&& (!color
|| underlined
==-1))
401 if (tPtr
->flags
.monoFont
|| tb
->selected
) {
403 if (tPtr
->flags
.monoFont
|| (tb
->s_end
- tb
->s_begin
== tb
->used
)
408 WMReleaseFont(tb
->d
.font
);
409 tb
->d
.font
= WMRetainFont(font
);
411 } else if(underlined
!=-1) {
412 tb
->underlined
= underlined
;
414 WMReleaseColor(tb
->color
);
415 tb
->color
= WMRetainColor(color
);
418 } else if (tb
->s_end
<= tb
->used
&& tb
->s_begin
< tb
->s_end
) {
420 TextBlock
*midtb
, *otb
= tb
;
422 if(underlined
!= -1) {
423 midtb
= (TextBlock
*) WMCreateTextBlockWithText(tPtr
,
424 &(tb
->text
[tb
->s_begin
]), tb
->d
.font
, tb
->color
,
425 False
, (tb
->s_end
- tb
->s_begin
));
427 midtb
= (TextBlock
*) WMCreateTextBlockWithText(tPtr
,
428 &(tb
->text
[tb
->s_begin
]),
429 (isFont
?font
:tb
->d
.font
),
430 (isFont
?tb
->color
:color
),
431 False
, (tb
->s_end
- tb
->s_begin
));
436 if(underlined
!= -1) {
437 midtb
->underlined
= underlined
;
439 midtb
->underlined
= otb
->underlined
;
442 midtb
->selected
= !True
;
444 midtb
->s_end
= midtb
->used
;
445 tPtr
->currentTextBlock
= tb
;
446 WMAppendTextBlock(tPtr
, midtb
);
447 tb
= tPtr
->currentTextBlock
;
450 if (otb
->used
- otb
->s_end
> 0) {
453 WMCreateTextBlockWithText(tPtr
,
454 &(otb
->text
[otb
->s_end
]), otb
->d
.font
, otb
->color
,
455 False
, otb
->used
- otb
->s_end
);
458 ntb
->underlined
= otb
->underlined
;
459 ntb
->selected
= False
;
460 WMAppendTextBlock(tPtr
, ntb
);
461 tb
= tPtr
->currentTextBlock
;
466 tPtr
->currentTextBlock
= midtb
;
469 otb
->selected
= False
;
470 otb
->used
= otb
->s_begin
;
477 tPtr
->flags
.needsLayOut
= True
;
480 /* in case the size changed... */
481 if(isFont
&& tPtr
->currentTextBlock
) {
482 TextBlock
*tb
= tPtr
->currentTextBlock
;
484 printf("%d %d %d\n", tPtr
->sel
.y
, tPtr
->sel
.h
, tPtr
->sel
.w
);
485 tPtr
->sel
.y
= 3 + tb
->sections
[0]._y
;
486 tPtr
->sel
.h
= tb
->sections
[tb
->nsections
-1]._y
- tb
->sections
[0]._y
;
487 tPtr
->sel
.w
= tb
->sections
[tb
->nsections
-1].w
;
488 if(tb
->sections
[tb
->nsections
-1]._y
!= tb
->sections
[0]._y
) {
491 printf("%d %d %d\n\n\n", tPtr
->sel
.y
, tPtr
->sel
.h
, tPtr
->sel
.w
);
498 removeSelection(Text
*tPtr
)
500 TextBlock
*tb
= NULL
;
503 if (!(tb
= tPtr
->firstTextBlock
))
508 if(!first
&& !tb
->graphic
) {
509 WMReleaseFont(tPtr
->dFont
);
510 tPtr
->dFont
= WMRetainFont(tb
->d
.font
);
514 if ( (tb
->s_end
- tb
->s_begin
== tb
->used
) || tb
->graphic
) {
515 tPtr
->currentTextBlock
= tb
;
516 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
517 tb
= tPtr
->currentTextBlock
;
522 } else if (tb
->s_end
<= tb
->used
) {
523 memmove(&(tb
->text
[tb
->s_begin
]),
524 &(tb
->text
[tb
->s_end
]), tb
->used
- tb
->s_end
);
525 tb
->used
-= (tb
->s_end
- tb
->s_begin
);
526 tb
->selected
= False
;
527 tPtr
->tpos
= tb
->s_begin
;
538 getFirstNonGraphicBlockFor(TextBlock
*tb
, short dir
)
540 TextBlock
*hold
= tb
;
548 tb
= (dir
? tb
->next
: tb
->prior
);
556 tb
= (dir
? tb
->prior
: tb
->next
);
568 updateStartForCurrentTextBlock(Text
*tPtr
, int x
, int y
, int *dir
,
571 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
572 tb
= getFirstNonGraphicBlockFor(tb
, *dir
);
577 tPtr
->currentTextBlock
=
578 (dir
? tPtr
->lastTextBlock
: tPtr
->firstTextBlock
);
584 *dir
= !(y
<= tb
->sections
[0].y
);
586 if ( ( y
<= tb
->sections
[0]._y
+ tb
->sections
[0].h
)
587 && (y
>= tb
->sections
[0]._y
) ) {
588 /* if it's on the same line */
589 if(x
< tb
->sections
[0].x
)
593 if ( ( y
<= tb
->sections
[tb
->nsections
-1]._y
594 + tb
->sections
[tb
->nsections
-1].h
)
595 && (y
>= tb
->sections
[tb
->nsections
-1]._y
) ) {
596 /* if it's on the same line */
597 if(x
> tb
->sections
[tb
->nsections
-1].x
)
607 paintText(Text
*tPtr
)
613 int len
, y
, c
, s
, done
=False
, prev_y
=-23, dir
/* 1 = down */;
614 WMScreen
*scr
= tPtr
->view
->screen
;
615 Display
*dpy
= tPtr
->view
->screen
->display
;
616 Window win
= tPtr
->view
->window
;
618 if (!tPtr
->view
->flags
.realized
|| !tPtr
->db
|| tPtr
->flags
.frozen
)
621 XFillRectangle(dpy
, tPtr
->db
, tPtr
->bgGC
,
622 0, 0, tPtr
->visible
.w
, tPtr
->visible
.h
);
624 if (! (tb
= tPtr
->currentTextBlock
)) {
625 if (! (tb
= tPtr
->firstTextBlock
)) {
630 if (tPtr
->flags
.ownsSelection
)
631 greyGC
= WMColorGC(WMGrayColor(scr
));
637 /* first, which direction? Don't waste time looking all over,
638 since the parts to be drawn will most likely be near what
639 was previously drawn */
640 if(!updateStartForCurrentTextBlock(tPtr
, 0, tPtr
->vpos
, &dir
, tb
))
645 if (tb
->graphic
&& tPtr
->flags
.monoFont
)
649 if(tPtr
->vpos
<= tb
->sections
[tb
->nsections
-1]._y
650 + tb
->sections
[tb
->nsections
-1].h
)
653 if(tPtr
->vpos
>= tb
->sections
[tb
->nsections
-1]._y
654 + tb
->sections
[tb
->nsections
-1].h
)
671 /* first, place all text that can be viewed */
672 while (!done
&& tb
) {
674 /* paragraph diagnostic
675 if(tb->blank) {tb->text[0] = 'F'; } */
682 tb
->selected
= False
;
684 for(s
=0; s
<tb
->nsections
&& !done
; s
++) {
686 if (tb
->sections
[s
]._y
> tPtr
->vpos
+ tPtr
->visible
.h
) {
691 if ( tb
->sections
[s
].y
+ tb
->sections
[s
].h
< tPtr
->vpos
)
694 if (tPtr
->flags
.monoFont
) {
699 gc
= WMColorGC(tb
->color
);
702 if (tPtr
->flags
.ownsSelection
) {
705 if ( sectionWasSelected(tPtr
, tb
, &rect
, s
)) {
707 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
708 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
712 prev_y
= tb
->sections
[s
]._y
;
714 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
715 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
716 y
= tb
->sections
[s
].y
- tPtr
->vpos
;
717 WMDrawString(scr
, tPtr
->db
, gc
, font
,
718 tb
->sections
[s
].x
- tPtr
->hpos
, y
, text
, len
);
720 if (!tPtr
->flags
.monoFont
&& tb
->underlined
) {
721 XDrawLine(dpy
, tPtr
->db
, gc
,
722 tb
->sections
[s
].x
- tPtr
->hpos
,
724 tb
->sections
[s
].x
+ tb
->sections
[s
].w
- tPtr
->hpos
,
730 tb
= (!done
? tb
->next
: NULL
);
734 /* now , show all graphic items that can be viewed */
735 c
= WMGetArrayItemCount(tPtr
->gfxItems
);
736 if (c
> 0 && !tPtr
->flags
.monoFont
) {
740 tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
);
742 /* if it's not viewable, and mapped, unmap it */
743 if (tb
->sections
[0]._y
+ tb
->sections
[0].h
<= tPtr
->vpos
744 || tb
->sections
[0]._y
>= tPtr
->vpos
+ tPtr
->visible
.h
) {
747 if ((W_VIEW(tb
->d
.widget
))->flags
.mapped
) {
748 WMUnmapWidget(tb
->d
.widget
);
752 /* if it's viewable, and not mapped, map it */
754 W_View
*view
= W_VIEW(tb
->d
.widget
);
756 if (!view
->flags
.realized
)
757 WMRealizeWidget(tb
->d
.widget
);
758 if(!view
->flags
.mapped
) {
759 XMapWindow(view
->screen
->display
, view
->window
);
760 XFlush(view
->screen
->display
);
761 view
->flags
.mapped
= 1;
765 if (tPtr
->flags
.ownsSelection
) {
768 if ( sectionWasSelected(tPtr
, tb
, &rect
, 0)) {
770 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
771 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
776 WMMoveWidget(tb
->d
.widget
,
777 tb
->sections
[0].x
+ tPtr
->visible
.x
- tPtr
->hpos
,
778 tb
->sections
[0].y
+ tPtr
->visible
.y
- tPtr
->vpos
);
779 h
= WMWidgetHeight(tb
->d
.widget
) + 1;
782 WMDrawPixmap(tb
->d
.pixmap
, tPtr
->db
,
783 tb
->sections
[0].x
- tPtr
->hpos
,
784 tb
->sections
[0].y
- tPtr
->vpos
);
785 h
= tb
->d
.pixmap
->height
+ 1;
789 if (!tPtr
->flags
.monoFont
&& tb
->underlined
) {
790 XDrawLine(dpy
, tPtr
->db
, WMColorGC(tb
->color
),
791 tb
->sections
[0].x
- tPtr
->hpos
,
792 tb
->sections
[0].y
+ h
- tPtr
->vpos
,
793 tb
->sections
[0].x
+ tb
->sections
[0].w
- tPtr
->hpos
,
794 tb
->sections
[0].y
+ h
- tPtr
->vpos
);
799 if (tPtr
->flags
.editable
&& tPtr
->flags
.cursorShown
800 && tPtr
->cursor
.x
!= -23 && tPtr
->flags
.focused
) {
801 int y
= tPtr
->cursor
.y
- tPtr
->vpos
;
802 XDrawLine(dpy
, tPtr
->db
, tPtr
->fgGC
,
804 tPtr
->cursor
.x
, y
+ tPtr
->cursor
.h
);
807 XCopyArea(dpy
, tPtr
->db
, win
, tPtr
->bgGC
, 0, 0,
808 tPtr
->visible
.w
, tPtr
->visible
.h
,
809 tPtr
->visible
.x
, tPtr
->visible
.y
);
811 W_DrawRelief(scr
, win
, 0, 0,
812 tPtr
->view
->size
.width
, tPtr
->view
->size
.height
,
815 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)
816 XDrawLine(dpy
, win
, tPtr
->fgGC
,
817 2, 42, tPtr
->view
->size
.width
-4, 42);
822 mouseOverObject(Text
*tPtr
, int x
, int y
)
827 x
-= tPtr
->visible
.x
;
829 y
-= tPtr
->visible
.y
;
832 if(tPtr
->flags
.ownsSelection
) {
835 && tPtr
->sel
.x
+ tPtr
->sel
.w
>= x
836 && tPtr
->sel
.y
+ tPtr
->sel
.h
>= y
) {
837 tPtr
->flags
.isOverGraphic
= 1;
844 int j
, c
= WMGetArrayItemCount(tPtr
->gfxItems
);
847 tPtr
->flags
.isOverGraphic
= 0;
851 tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
);
853 if(!tb
|| !tb
->sections
) {
854 tPtr
->flags
.isOverGraphic
= 0;
859 if(tb
->sections
[0].x
<= x
860 && tb
->sections
[0].y
<= y
861 && tb
->sections
[0].x
+ tb
->sections
[0].w
>= x
862 && tb
->sections
[0].y
+ tb
->d
.pixmap
->height
>= y
) {
863 tPtr
->flags
.isOverGraphic
= 3;
874 tPtr
->flags
.isOverGraphic
= 0;
877 tPtr
->view
->attribs
.cursor
= (result
?
878 tPtr
->view
->screen
->defaultCursor
879 : tPtr
->view
->screen
->textCursor
);
881 XSetWindowAttributes attribs
;
882 attribs
.cursor
= tPtr
->view
->attribs
.cursor
;
883 XChangeWindowAttributes(tPtr
->view
->screen
->display
,
884 tPtr
->view
->window
, CWCursor
,
892 blinkCursor(void *data
)
894 Text
*tPtr
= (Text
*)data
;
896 if (tPtr
->flags
.cursorShown
) {
897 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY
,
900 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
,
904 tPtr
->flags
.cursorShown
= !tPtr
->flags
.cursorShown
;
909 updateCursorPosition(Text
*tPtr
)
911 TextBlock
*tb
= NULL
;
914 if(tPtr
->flags
.needsLayOut
)
915 layOutDocument(tPtr
);
917 if (! (tb
= tPtr
->currentTextBlock
)) {
918 if (! (tb
= tPtr
->firstTextBlock
)) {
920 tPtr
->cursor
.h
= tPtr
->dFont
->height
;
930 y
= tb
->sections
[0].y
;
931 h
= tb
->sections
[0].h
;
932 x
= tb
->sections
[0].x
;
934 } else if(tb
->graphic
) {
935 y
= tb
->sections
[0].y
;
936 h
= tb
->sections
[0].h
;
937 x
= tb
->sections
[0].x
;
940 if(tPtr
->tpos
> tb
->used
)
941 tPtr
->tpos
= tb
->used
;
943 for(s
=0; s
<tb
->nsections
-1; s
++) {
945 if(tPtr
->tpos
>= tb
->sections
[s
].begin
946 && tPtr
->tpos
<= tb
->sections
[s
].end
)
950 y
= tb
->sections
[s
]._y
;
951 h
= tb
->sections
[s
].h
;
952 x
= tb
->sections
[s
].x
+ WMWidthOfString(
953 (tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
),
954 &tb
->text
[tb
->sections
[s
].begin
],
955 tPtr
->tpos
- tb
->sections
[s
].begin
);
963 /* scroll the bars if the cursor is not visible */
964 if(tPtr
->flags
.editable
&& tPtr
->cursor
.x
!= -23) {
965 if(tPtr
->cursor
.y
+tPtr
->cursor
.h
966 > tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
) {
968 (tPtr
->cursor
.y
+tPtr
->cursor
.h
+10
969 - (tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
));
970 } else if(tPtr
->cursor
.y
< tPtr
->vpos
+tPtr
->visible
.y
) {
971 tPtr
->vpos
-= (tPtr
->vpos
+tPtr
->visible
.y
-tPtr
->cursor
.y
);
976 updateScrollers(tPtr
);
981 cursorToTextPosition(Text
*tPtr
, int x
, int y
)
983 TextBlock
*tb
= NULL
;
984 int done
=False
, s
, pos
, len
, _w
, _y
, dir
=1; /* 1 == "down" */
987 if(tPtr
->flags
.needsLayOut
)
988 layOutDocument(tPtr
);
990 y
+= (tPtr
->vpos
- tPtr
->visible
.y
);
994 x
-= (tPtr
->visible
.x
- 2);
998 /* clicked is relative to document, not window... */
1000 tPtr
->clicked
.y
= y
;
1002 if (! (tb
= tPtr
->currentTextBlock
)) {
1003 if (! (tb
= tPtr
->firstTextBlock
)) {
1005 tPtr
->cursor
.h
= tPtr
->dFont
->height
;
1012 /* first, which direction? Most likely, newly clicked
1013 position will be close to previous */
1014 if(!updateStartForCurrentTextBlock(tPtr
, x
, y
, &dir
, tb
))
1018 s
= (dir
? 0 : tb
->nsections
-1);
1019 if ( y
>= tb
->sections
[s
]._y
1020 && y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) {
1024 /* get the first (or last) section of the TextBlock that
1025 lies about the vertical click point */
1027 while (!done
&& tb
) {
1029 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1030 if( (dir
?tb
->next
:tb
->prior
))
1031 tb
= (dir
?tb
->next
:tb
->prior
);
1035 s
= (dir
? 0 : tb
->nsections
-1);
1036 while (!done
&& (dir
? (s
<tb
->nsections
) : (s
>=0) )) {
1038 if ( (dir
? (y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) :
1039 ( y
>= tb
->sections
[s
]._y
) ) ) {
1047 if ( (dir
? tb
->next
: tb
->prior
)) {
1048 tb
= (dir
? tb
->next
: tb
->prior
);
1051 break; /* goto _doneH; */
1057 if (s
<0 || s
>=tb
->nsections
) {
1058 s
= (dir
? tb
->nsections
-1 : 0);
1062 /* we have the line, which TextBlock on that line is it? */
1063 pos
= (dir
?0:tb
->sections
[s
].begin
);
1064 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1065 TextBlock
*hold
= tb
;
1066 tb
= getFirstNonGraphicBlockFor(hold
, dir
);
1080 _y
= tb
->sections
[s
]._y
;
1084 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1085 tb
= (dir
? tb
->next
: tb
->prior
);
1092 _w
= WMWidgetWidth(tb
->d
.widget
)-5;
1094 _w
= tb
->d
.pixmap
->width
-5;
1096 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
1097 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
1098 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
1099 if (tb
->sections
[s
].x
+ _w
>= x
)
1104 if (tb
->sections
[s
].x
<= x
)
1108 if ((dir
? tb
->next
: tb
->prior
)) {
1109 TextBlock
*nxt
= (dir
? tb
->next
: tb
->prior
);
1110 if (tPtr
->flags
.monoFont
&& nxt
->graphic
) {
1111 nxt
= getFirstNonGraphicBlockFor(nxt
, dir
);
1113 pos
= (dir
?0:tb
->sections
[s
].begin
);
1114 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
1119 if (_y
!= nxt
->sections
[dir
?0:nxt
->nsections
-1]._y
) {
1120 /* this must be the last/first on this line. stop */
1121 pos
= (dir
? tb
->sections
[s
].end
: 0);
1122 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
1126 tPtr
->cursor
.x
+= WMWidgetWidth(tb
->d
.widget
);
1128 tPtr
->cursor
.x
+= tb
->d
.pixmap
->width
;
1129 } else if (pos
> tb
->sections
[s
].begin
) {
1131 WMWidthOfString(tb
->d
.font
,
1132 &(tb
->text
[tb
->sections
[s
].begin
]),
1133 pos
- tb
->sections
[s
].begin
);
1140 if ( (dir
? tb
->next
: tb
->prior
)) {
1141 tb
= (dir
? tb
->next
: tb
->prior
);
1148 s
= (dir
? 0 : tb
->nsections
-1);
1151 /* we have said TextBlock, now where within it? */
1152 if (tb
&& !tb
->graphic
) {
1153 WMFont
*f
= tb
->d
.font
;
1154 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
1155 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
1157 _w
= x
- tb
->sections
[s
].x
;
1160 while (pos
<len
&& WMWidthOfString(f
, text
, pos
+1) < _w
)
1163 tPtr
->cursor
.x
= tb
->sections
[s
].x
+
1164 (pos
? WMWidthOfString(f
, text
, pos
) : 0);
1166 pos
+= tb
->sections
[s
].begin
;
1168 tPtr
->tpos
= (pos
<tb
->used
)? pos
: tb
->used
;
1173 printf("...for this app will surely crash :-)\n");
1175 tPtr
->currentTextBlock
= tb
;
1176 tPtr
->cursor
.h
= tb
->sections
[s
].h
;
1177 tPtr
->cursor
.y
= tb
->sections
[s
]._y
;
1179 /* scroll the bars if the cursor is not visible */
1180 if(tPtr
->flags
.editable
&& tPtr
->cursor
.x
!= -23) {
1181 if(tPtr
->cursor
.y
+tPtr
->cursor
.h
1182 > tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
) {
1184 (tPtr
->cursor
.y
+tPtr
->cursor
.h
+10
1185 - (tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
));
1186 updateScrollers(tPtr
);
1187 } else if(tPtr
->cursor
.y
< tPtr
->vpos
+tPtr
->visible
.y
) {
1188 tPtr
->vpos
-= (tPtr
->vpos
+tPtr
->visible
.y
-tPtr
->cursor
.y
);
1189 updateScrollers(tPtr
);
1197 autoSelectText(Text
*tPtr
, int clicks
)
1201 char *mark
= NULL
, behind
, ahead
;
1203 if(!(tb
= tPtr
->currentTextBlock
))
1209 switch(tb
->text
[tPtr
->tpos
]) {
1212 case '<': case '>': behind = '<'; ahead = '>'; break;
1213 case '{': case '}': behind = '{'; ahead = '}'; break;
1214 case '[': case ']': behind = '['; ahead = ']'; break;
1216 default: behind
= ahead
= ' ';
1219 tPtr
->sel
.y
= tPtr
->cursor
.y
+5;
1220 tPtr
->sel
.h
= 6;/*tPtr->cursor.h-10;*/
1223 tPtr
->sel
.x
= tb
->sections
[0].x
;
1224 tPtr
->sel
.w
= tb
->sections
[0].w
;
1226 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
1229 while(start
> 0 && tb
->text
[start
-1] != behind
)
1233 if(tPtr
->tpos
> start
){
1234 x
-= WMWidthOfString(font
, &tb
->text
[start
],
1235 tPtr
->tpos
- start
);
1237 tPtr
->sel
.x
= (x
<0?0:x
)+1;
1239 if((mark
= strchr(&tb
->text
[start
], ahead
))) {
1240 tPtr
->sel
.w
= WMWidthOfString(font
, &tb
->text
[start
],
1241 (int)(mark
- &tb
->text
[start
]));
1242 } else if(tb
->used
> start
) {
1243 tPtr
->sel
.w
= WMWidthOfString(font
, &tb
->text
[start
],
1248 } else if(clicks
== 3) {
1249 TextBlock
*cur
= tb
;
1251 while(tb
&& !tb
->first
) {
1254 tPtr
->sel
.y
= tb
->sections
[0]._y
;
1257 while(tb
->next
&& !tb
->next
->first
) {
1260 tPtr
->sel
.h
= tb
->sections
[tb
->nsections
-1]._y
1264 tPtr
->sel
.w
= tPtr
->docWidth
;
1265 tPtr
->clicked
.x
= 0; /* only for now, fix sel. code */
1268 tPtr
->flags
.ownsSelection
= True
;
1275 updateScrollers(Text
*tPtr
)
1278 if (tPtr
->flags
.frozen
)
1282 if (tPtr
->docHeight
< tPtr
->visible
.h
) {
1283 WMSetScrollerParameters(tPtr
->vS
, 0, 1);
1286 float hmax
= (float)(tPtr
->docHeight
);
1287 WMSetScrollerParameters(tPtr
->vS
,
1288 ((float)tPtr
->vpos
)/(hmax
- (float)tPtr
->visible
.h
),
1289 (float)tPtr
->visible
.h
/hmax
);
1291 } else tPtr
->vpos
= 0;
1294 if (tPtr
->docWidth
< tPtr
->visible
.w
) {
1295 WMSetScrollerParameters(tPtr
->hS
, 0, 1);
1298 float wmax
= (float)(tPtr
->docWidth
);
1299 WMSetScrollerParameters(tPtr
->hS
,
1300 ((float)tPtr
->hpos
)/(wmax
- (float)tPtr
->visible
.w
),
1301 (float)tPtr
->visible
.w
/wmax
);
1303 } else tPtr
->hpos
= 0;
1307 scrollersCallBack(WMWidget
*w
, void *self
)
1309 Text
*tPtr
= (Text
*)self
;
1310 Bool scroll
= False
;
1313 if (!tPtr
->view
->flags
.realized
|| tPtr
->flags
.frozen
)
1316 if (w
== tPtr
->vS
) {
1318 height
= tPtr
->visible
.h
;
1320 which
= WMGetScrollerHitPart(tPtr
->vS
);
1323 case WSDecrementLine
:
1324 if (tPtr
->vpos
> 0) {
1325 if (tPtr
->vpos
>16) tPtr
->vpos
-=16;
1331 case WSIncrementLine
: {
1332 int limit
= tPtr
->docHeight
- height
;
1333 if (tPtr
->vpos
< limit
) {
1334 if (tPtr
->vpos
<limit
-16) tPtr
->vpos
+=16;
1335 else tPtr
->vpos
=limit
;
1341 case WSDecrementPage
:
1342 if(((int)tPtr
->vpos
- (int)height
) >= 0)
1343 tPtr
->vpos
-= height
;
1350 case WSIncrementPage
:
1351 tPtr
->vpos
+= height
;
1352 if (tPtr
->vpos
> (tPtr
->docHeight
- height
))
1353 tPtr
->vpos
= tPtr
->docHeight
- height
;
1359 tPtr
->vpos
= WMGetScrollerValue(tPtr
->vS
)
1360 * (float)(tPtr
->docHeight
- height
);
1368 scroll
= (tPtr
->vpos
!= tPtr
->prevVpos
);
1369 tPtr
->prevVpos
= tPtr
->vpos
;
1373 if (w
== tPtr
->hS
) {
1374 int width
= tPtr
->visible
.w
;
1376 which
= WMGetScrollerHitPart(tPtr
->hS
);
1379 case WSDecrementLine
:
1380 if (tPtr
->hpos
> 0) {
1381 if (tPtr
->hpos
>16) tPtr
->hpos
-=16;
1386 case WSIncrementLine
: {
1387 int limit
= tPtr
->docWidth
- width
;
1388 if (tPtr
->hpos
< limit
) {
1389 if (tPtr
->hpos
<limit
-16) tPtr
->hpos
+=16;
1390 else tPtr
->hpos
=limit
;
1394 case WSDecrementPage
:
1395 if(((int)tPtr
->hpos
- (int)width
) >= 0)
1396 tPtr
->hpos
-= width
;
1403 case WSIncrementPage
:
1404 tPtr
->hpos
+= width
;
1405 if (tPtr
->hpos
> (tPtr
->docWidth
- width
))
1406 tPtr
->hpos
= tPtr
->docWidth
- width
;
1412 tPtr
->hpos
= WMGetScrollerValue(tPtr
->hS
)
1413 * (float)(tPtr
->docWidth
- width
);
1421 scroll
= (tPtr
->hpos
!= tPtr
->prevHpos
);
1422 tPtr
->prevHpos
= tPtr
->hpos
;
1426 updateScrollers(tPtr
);
1435 unsigned short begin
, end
; /* what part of the text block */
1440 layOutLine(Text
*tPtr
, myLineItems
*items
, int nitems
, int x
, int y
)
1442 int i
, j
=0, lw
= 0, line_height
=0, max_d
=0, len
, n
;
1445 TextBlock
*tb
, *tbsame
=NULL
;
1447 if(!items
|| nitems
== 0)
1450 for(i
=0; i
<nitems
; i
++) {
1454 if (!tPtr
->flags
.monoFont
) {
1456 WMWidget
*wdt
= tb
->d
.widget
;
1457 line_height
= WMAX(line_height
, WMWidgetHeight(wdt
));
1458 if (tPtr
->flags
.alignment
!= WALeft
)
1459 lw
+= WMWidgetWidth(wdt
);
1461 line_height
= WMAX(line_height
,
1462 tb
->d
.pixmap
->height
+ max_d
);
1463 if (tPtr
->flags
.alignment
!= WALeft
)
1464 lw
+= tb
->d
.pixmap
->width
;
1469 font
= (tPtr
->flags
.monoFont
)?tPtr
->dFont
: tb
->d
.font
;
1470 max_d
= WMAX(max_d
, abs(font
->height
-font
->y
));
1471 line_height
= WMAX(line_height
, font
->height
+ max_d
);
1472 text
= &(tb
->text
[items
[i
].begin
]);
1473 len
= items
[i
].end
- items
[i
].begin
;
1474 if (tPtr
->flags
.alignment
!= WALeft
)
1475 lw
+= WMWidthOfString(font
, text
, len
);
1479 if (tPtr
->flags
.alignment
== WARight
) {
1480 j
= tPtr
->visible
.w
- lw
;
1481 } else if (tPtr
->flags
.alignment
== WACenter
) {
1482 j
= (int) ((float)(tPtr
->visible
.w
- lw
))/2.0;
1485 for(i
=0; i
<nitems
; i
++) {
1488 if (tbsame
== tb
) { /* extend it, since it's on same line */
1489 tb
->sections
[tb
->nsections
-1].end
= items
[i
].end
;
1490 n
= tb
->nsections
-1;
1492 tb
->sections
= wrealloc(tb
->sections
,
1493 (++tb
->nsections
)*sizeof(Section
));
1494 n
= tb
->nsections
-1;
1495 tb
->sections
[n
]._y
= y
+ max_d
;
1496 tb
->sections
[n
].max_d
= max_d
;
1497 tb
->sections
[n
].x
= x
+j
;
1498 tb
->sections
[n
].h
= line_height
;
1499 tb
->sections
[n
].begin
= items
[i
].begin
;
1500 tb
->sections
[n
].end
= items
[i
].end
;
1503 tb
->sections
[n
].last
= (i
+1 == nitems
);
1506 if (!tPtr
->flags
.monoFont
) {
1508 WMWidget
*wdt
= tb
->d
.widget
;
1509 tb
->sections
[n
].y
= max_d
+ y
1510 + line_height
- WMWidgetHeight(wdt
);
1511 tb
->sections
[n
].w
= WMWidgetWidth(wdt
);
1513 tb
->sections
[n
].y
= y
+ line_height
1514 + max_d
- tb
->d
.pixmap
->height
;
1515 tb
->sections
[n
].w
= tb
->d
.pixmap
->width
;
1517 x
+= tb
->sections
[n
].w
;
1520 font
= (tPtr
->flags
.monoFont
)? tPtr
->dFont
: tb
->d
.font
;
1521 len
= items
[i
].end
- items
[i
].begin
;
1522 text
= &(tb
->text
[items
[i
].begin
]);
1524 tb
->sections
[n
].y
= y
+line_height
-font
->y
;
1526 WMWidthOfString(font
,
1527 &(tb
->text
[tb
->sections
[n
].begin
]),
1528 tb
->sections
[n
].end
- tb
->sections
[n
].begin
);
1530 x
+= WMWidthOfString(font
, text
, len
);
1542 layOutDocument(Text
*tPtr
)
1545 myLineItems
*items
= NULL
;
1546 unsigned int itemsSize
=0, nitems
=0, begin
, end
;
1548 unsigned int x
, y
=0, lw
= 0, width
=0, bmargin
;
1549 char *start
=NULL
, *mark
=NULL
;
1551 if ( tPtr
->flags
.frozen
|| (!(tb
= tPtr
->firstTextBlock
)) )
1554 assert(tPtr
->visible
.w
> 20);
1556 tPtr
->docWidth
= tPtr
->visible
.w
;
1557 x
= tPtr
->margins
[tb
->marginN
].first
;
1558 bmargin
= tPtr
->margins
[tb
->marginN
].body
;
1560 /* only partial layOut needed: re-Lay only affected textblocks */
1561 if (tPtr
->flags
.laidOut
) {
1562 tb
= tPtr
->currentTextBlock
;
1564 /* search backwards for textblocks on same line */
1566 if (!tb
->sections
|| tb
->nsections
<1) {
1567 tb
= tPtr
->firstTextBlock
;
1568 tPtr
->flags
.laidOut
= False
;
1573 if(!tb
->prior
->sections
|| tb
->prior
->nsections
<1) {
1574 tb
= tPtr
->firstTextBlock
;
1575 tPtr
->flags
.laidOut
= False
;
1580 if (tb
->sections
[0]._y
!=
1581 tb
->prior
->sections
[tb
->prior
->nsections
-1]._y
) {
1587 if(tb
->prior
&& tb
->prior
->sections
&& tb
->prior
->nsections
>0) {
1588 y
= tb
->prior
->sections
[tb
->prior
->nsections
-1]._y
+
1589 tb
->prior
->sections
[tb
->prior
->nsections
-1].h
-
1590 tb
->prior
->sections
[tb
->prior
->nsections
-1].max_d
;
1599 if (tb
->sections
&& tb
->nsections
>0) {
1600 wfree(tb
->sections
);
1601 tb
->sections
= NULL
;
1605 if (tb
->blank
&& tb
->next
&& !tb
->next
->first
) {
1606 TextBlock
*next
= tb
->next
;
1607 tPtr
->currentTextBlock
= tb
;
1608 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1614 if (tb
->first
&& tb
!= tPtr
->firstTextBlock
) {
1615 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1616 x
= tPtr
->margins
[tb
->marginN
].first
;
1617 bmargin
= tPtr
->margins
[tb
->marginN
].body
;
1623 if (!tPtr
->flags
.monoFont
) {
1625 width
= WMWidgetWidth(tb
->d
.widget
);
1627 width
= tb
->d
.pixmap
->width
;
1629 if (width
> tPtr
->docWidth
)
1630 tPtr
->docWidth
= width
;
1633 if (lw
>= tPtr
->visible
.w
- x
) {
1634 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1640 if(nitems
+ 1> itemsSize
) {
1641 items
= wrealloc(items
,
1642 (++itemsSize
)*sizeof(myLineItems
));
1645 items
[nitems
].tb
= tb
;
1646 items
[nitems
].begin
= 0;
1647 items
[nitems
].end
= 0;
1651 } else if ((start
= tb
->text
)) {
1653 font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
1656 mark
= strchr(start
, ' ');
1658 end
+= (int)(mark
-start
)+1;
1661 end
+= strlen(start
);
1668 if (end
-begin
> 0) {
1670 width
= WMWidthOfString(font
,
1671 &tb
->text
[begin
], end
-begin
);
1673 /* if it won't fit, char wrap it */
1674 if (width
>= tPtr
->visible
.w
) {
1675 char *t
= &tb
->text
[begin
];
1676 int l
=end
-begin
, i
=0;
1678 width
= WMWidthOfString(font
, t
, ++i
);
1679 } while (width
< tPtr
->visible
.w
&& i
< l
);
1682 start
= &tb
->text
[end
];
1688 if (lw
>= tPtr
->visible
.w
- x
) {
1689 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1695 if(nitems
+ 1 > itemsSize
) {
1696 items
= wrealloc(items
,
1697 (++itemsSize
)*sizeof(myLineItems
));
1700 items
[nitems
].tb
= tb
;
1701 items
[nitems
].begin
= begin
;
1702 items
[nitems
].end
= end
;
1710 /* not yet fully ready. but is already VERY FAST for a 3Mbyte file ;-) */
1711 if(0&&tPtr
->flags
.laidOut
1712 && tb
->next
&& tb
->next
->sections
&& tb
->next
->nsections
>0
1713 && (tPtr
->vpos
+ tPtr
->visible
.h
1714 < tb
->next
->sections
[0]._y
)) {
1715 if(tPtr
->lastTextBlock
->sections
1716 && tPtr
->lastTextBlock
->nsections
> 0 ) {
1717 TextBlock
*ltb
= tPtr
->lastTextBlock
;
1718 int ly
= ltb
->sections
[ltb
->nsections
-1]._y
;
1719 int lh
= ltb
->sections
[ltb
->nsections
-1].h
;
1722 lh
+= 1 + tPtr
->visible
.y
+ ltb
->sections
[ltb
->nsections
-1].max_d
;
1723 printf("it's %d\n", tPtr
->visible
.y
+ ltb
->sections
[ltb
->nsections
-1].max_d
);
1725 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1727 sd
= tPtr
->docHeight
-y
;
1729 printf("dif %d-%d: %d\n", ss
, sd
, ss
-sd
);
1730 y
+= tb
->next
->sections
[0]._y
-y
;
1732 printf("nitems%d\n", nitems
);
1734 y
= tPtr
->docHeight
+ss
-sd
;
1738 tPtr
->flags
.laidOut
= False
;
1747 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1749 if (tPtr
->docHeight
!= y
+10) {
1750 tPtr
->docHeight
= y
+10;
1751 updateScrollers(tPtr
);
1754 if(tPtr
->docWidth
> tPtr
->visible
.w
&& !tPtr
->hS
) {
1757 tPtr
->flags
.horizOnDemand
= True
;
1758 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, True
);
1759 event
.type
= Expose
;
1760 handleEvents(&event
, (void *)tPtr
);
1762 } else if(tPtr
->docWidth
<= tPtr
->visible
.w
1763 && tPtr
->hS
&& tPtr
->flags
.horizOnDemand
) {
1764 tPtr
->flags
.horizOnDemand
= False
;
1765 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, False
);
1768 tPtr
->flags
.laidOut
= True
;
1770 if(items
&& itemsSize
> 0)
1776 textDidResize(W_ViewDelegate
*self
, WMView
*view
)
1778 Text
*tPtr
= (Text
*)view
->self
;
1779 unsigned short w
= tPtr
->view
->size
.width
;
1780 unsigned short h
= tPtr
->view
->size
.height
;
1781 unsigned short rh
= 0, vw
= 0, rel
;
1783 rel
= (tPtr
->flags
.relief
== WRFlat
);
1785 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
) {
1786 WMMoveWidget(tPtr
->ruler
, 2, 2);
1787 WMResizeWidget(tPtr
->ruler
, w
- 4, 40);
1792 WMMoveWidget(tPtr
->vS
, 1 - (rel
?1:0), rh
+ 1 - (rel
?1:0));
1793 WMResizeWidget(tPtr
->vS
, 20, h
- rh
- 2 + (rel
?2:0));
1795 WMSetRulerOffset(tPtr
->ruler
,22);
1796 } else WMSetRulerOffset(tPtr
->ruler
, 2);
1800 WMMoveWidget(tPtr
->hS
, vw
, h
- 21);
1801 WMResizeWidget(tPtr
->hS
, w
- vw
- 1, 20);
1803 WMMoveWidget(tPtr
->hS
, vw
+1, h
- 21);
1804 WMResizeWidget(tPtr
->hS
, w
- vw
- 2, 20);
1808 tPtr
->visible
.x
= (tPtr
->vS
)?24:4;
1809 tPtr
->visible
.y
= (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)?43:3;
1810 tPtr
->visible
.w
= tPtr
->view
->size
.width
- tPtr
->visible
.x
- 8;
1811 tPtr
->visible
.h
= tPtr
->view
->size
.height
- tPtr
->visible
.y
;
1812 tPtr
->visible
.h
-= (tPtr
->hS
)?20:0;
1813 tPtr
->margins
[0].right
= tPtr
->visible
.w
;
1815 if (tPtr
->view
->flags
.realized
) {
1818 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
1819 tPtr
->db
= (Pixmap
) NULL
;
1822 if (tPtr
->visible
.w
< 40)
1823 tPtr
->visible
.w
= 40;
1824 if (tPtr
->visible
.h
< 20)
1825 tPtr
->visible
.h
= 20;
1828 tPtr
->db
= XCreatePixmap(tPtr
->view
->screen
->display
,
1829 tPtr
->view
->window
, tPtr
->visible
.w
,
1830 tPtr
->visible
.h
, tPtr
->view
->screen
->depth
);
1837 W_ViewDelegate _TextViewDelegate
=
1845 /* nice, divisble-by-16 blocks */
1846 static inline unsigned short
1847 reqBlockSize(unsigned short requested
)
1849 return requested
+ 16 - (requested
%16);
1854 clearText(Text
*tPtr
)
1856 tPtr
->vpos
= tPtr
->hpos
= 0;
1857 tPtr
->docHeight
= tPtr
->docWidth
= 0;
1858 tPtr
->cursor
.x
= -23;
1860 if (!tPtr
->firstTextBlock
)
1863 while (tPtr
->currentTextBlock
)
1864 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1866 tPtr
->firstTextBlock
= NULL
;
1867 tPtr
->currentTextBlock
= NULL
;
1868 tPtr
->lastTextBlock
= NULL
;
1869 WMEmptyArray(tPtr
->gfxItems
);
1873 deleteTextInteractively(Text
*tPtr
, KeySym ksym
)
1876 Bool back
= (Bool
) (ksym
== XK_BackSpace
);
1880 if (!tPtr
->flags
.editable
) {
1881 XBell(tPtr
->view
->screen
->display
, 0);
1885 if ( !(tb
= tPtr
->currentTextBlock
) )
1888 if (tPtr
->flags
.ownsSelection
) {
1889 if(removeSelection(tPtr
))
1890 layOutDocument(tPtr
);
1894 wasFirst
= tb
->first
;
1895 if (back
&& tPtr
->tpos
< 1) {
1897 if(tb
->prior
->blank
) {
1898 tPtr
->currentTextBlock
= tb
->prior
;
1899 WMRemoveTextBlock(tPtr
);
1900 tPtr
->currentTextBlock
= tb
;
1902 layOutDocument(tPtr
);
1906 TextBlock
*prior
= tb
->prior
;
1907 tPtr
->currentTextBlock
= tb
;
1908 WMRemoveTextBlock(tPtr
);
1914 tPtr
->tpos
= tb
->used
;
1915 tPtr
->currentTextBlock
= tb
;
1919 tb
->next
->first
= False
;
1920 layOutDocument(tPtr
);
1927 if ( (tb
->used
> 0) && ((back
?tPtr
->tpos
> 0:1))
1928 && (tPtr
->tpos
<= tb
->used
) && !tb
->graphic
) {
1931 memmove(&(tb
->text
[tPtr
->tpos
]),
1932 &(tb
->text
[tPtr
->tpos
+ 1]), tb
->used
- tPtr
->tpos
);
1937 if ( (back
? (tPtr
->tpos
< 1 && !done
) : ( tPtr
->tpos
>= tb
->used
))
1940 TextBlock
*sibling
= (back
? tb
->prior
: tb
->next
);
1942 if(tb
->used
== 0 || tb
->graphic
)
1943 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1946 tPtr
->currentTextBlock
= sibling
;
1947 tPtr
->tpos
= (back
? sibling
->used
: 0);
1951 layOutDocument(tPtr
);
1956 insertTextInteractively(Text
*tPtr
, char *text
, int len
)
1959 char *newline
= NULL
;
1961 if (!tPtr
->flags
.editable
) {
1962 XBell(tPtr
->view
->screen
->display
, 0);
1966 if (len
< 1 || !text
)
1970 if(tPtr
->flags
.ignoreNewLine
&& *text
== '\n' && len
== 1)
1974 if (tPtr
->flags
.ownsSelection
)
1975 removeSelection(tPtr
);
1978 if (tPtr
->flags
.ignoreNewLine
) {
1980 for(i
=0; i
<len
; i
++) {
1981 if (text
[i
] == '\n')
1986 tb
= tPtr
->currentTextBlock
;
1987 if (!tb
|| tb
->graphic
) {
1989 WMAppendTextStream(tPtr
, text
);
1990 layOutDocument(tPtr
);
1994 if ((newline
= strchr(text
, '\n'))) {
1995 int nlen
= (int)(newline
-text
);
1996 int s
= tb
->used
- tPtr
->tpos
;
1998 if (!tb
->blank
&& nlen
>0) {
2000 memcpy(save
, &tb
->text
[tPtr
->tpos
], s
);
2001 tb
->used
-= (tb
->used
- tPtr
->tpos
);
2003 insertTextInteractively(tPtr
, text
, nlen
);
2005 WMAppendTextStream(tPtr
, newline
);
2007 insertTextInteractively(tPtr
, save
, s
);
2010 if (tPtr
->tpos
>0 && tPtr
->tpos
< tb
->used
2011 && !tb
->graphic
&& tb
->text
) {
2013 void *ntb
= WMCreateTextBlockWithText(
2014 tPtr
, &tb
->text
[tPtr
->tpos
],
2015 tb
->d
.font
, tb
->color
, True
, tb
->used
- tPtr
->tpos
);
2016 tb
->used
= tPtr
->tpos
;
2017 WMAppendTextBlock(tPtr
, ntb
);
2020 } else if (tPtr
->tpos
== tb
->used
|| tPtr
->tpos
== 0) {
2021 if(tPtr
->flags
.indentNewLine
) {
2022 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
2023 " ", tb
->d
.font
, tb
->color
, True
, 4));
2026 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
2027 NULL
, tb
->d
.font
, tb
->color
, True
, 0));
2034 if (tb
->used
+ len
>= tb
->allocated
) {
2035 tb
->allocated
= reqBlockSize(tb
->used
+len
);
2036 tb
->text
= wrealloc(tb
->text
, tb
->allocated
);
2040 memcpy(tb
->text
, text
, len
);
2043 tb
->text
[tb
->used
] = 0;
2047 memmove(&(tb
->text
[tPtr
->tpos
+len
]), &tb
->text
[tPtr
->tpos
],
2048 tb
->used
-tPtr
->tpos
+1);
2049 memmove(&tb
->text
[tPtr
->tpos
], text
, len
);
2052 tb
->text
[tb
->used
] = 0;
2057 layOutDocument(tPtr
);
2062 selectRegion(Text
*tPtr
, int x
, int y
)
2068 y
+= (tPtr
->flags
.rulerShown
? 40: 0);
2071 y
-= 10; /* the original offset */
2073 x
-= tPtr
->visible
.x
-2;
2077 tPtr
->sel
.x
= WMAX(0, WMIN(tPtr
->clicked
.x
, x
));
2078 tPtr
->sel
.w
= abs(tPtr
->clicked
.x
- x
);
2079 tPtr
->sel
.y
= WMAX(0, WMIN(tPtr
->clicked
.y
, y
));
2080 tPtr
->sel
.h
= abs(tPtr
->clicked
.y
- y
);
2082 tPtr
->flags
.ownsSelection
= True
;
2088 releaseSelection(Text
*tPtr
)
2090 TextBlock
*tb
= tPtr
->firstTextBlock
;
2093 tb
->selected
= False
;
2096 tPtr
->flags
.ownsSelection
= False
;
2097 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
,
2105 requestHandler(WMView
*view
, Atom selection
, Atom target
, void *cdata
,
2108 Text
*tPtr
= view
->self
;
2109 Display
*dpy
= tPtr
->view
->screen
->display
;
2111 Atom TEXT
= XInternAtom(dpy
, "TEXT", False
);
2112 Atom COMPOUND_TEXT
= XInternAtom(dpy
, "COMPOUND_TEXT", False
);
2113 WMData
*data
= NULL
;
2116 if (target
== XA_STRING
|| target
== TEXT
|| target
== COMPOUND_TEXT
) {
2117 char *text
= WMGetTextSelectedStream(tPtr
);
2120 printf("got text [%s]\n", text
);
2121 data
= WMCreateDataWithBytes(text
, strlen(text
));
2122 WMSetDataFormat(data
, TYPETEXT
);
2126 } else printf("didn't get it\n");
2128 _TARGETS
= XInternAtom(dpy
, "TARGETS", False
);
2129 if (target
== _TARGETS
) {
2132 ptr
= wmalloc(4 * sizeof(Atom
));
2136 ptr
[3] = COMPOUND_TEXT
;
2138 data
= WMCreateDataWithBytes(ptr
, 4*4);
2139 WMSetDataFormat(data
, 32);
2149 lostHandler(WMView
*view
, Atom selection
, void *cdata
)
2151 releaseSelection((WMText
*)view
->self
);
2154 static WMSelectionProcs selectionHandler
= {
2155 requestHandler
, lostHandler
, NULL
2160 ownershipObserver(void *observerData
, WMNotification
*notification
)
2162 if (observerData
!= WMGetNotificationClientData(notification
))
2163 lostHandler(WMWidgetView(observerData
), XA_PRIMARY
, NULL
);
2168 fontChanged(void *observerData
, WMNotification
*notification
)
2170 WMText
*tPtr
= (WMText
*) observerData
;
2171 WMFont
*font
= (WMFont
*)WMGetNotificationClientData(notification
);
2172 printf("fontChanged\n");
2177 if (tPtr
->flags
.ownsSelection
)
2178 WMSetTextSelectionFont(tPtr
, font
);
2183 handleTextKeyPress(Text
*tPtr
, XEvent
*event
)
2187 int control_pressed
= False
;
2188 TextBlock
*tb
= NULL
;
2190 if (((XKeyEvent
*) event
)->state
& ControlMask
)
2191 control_pressed
= True
;
2192 buffer
[XLookupString(&event
->xkey
, buffer
, 1, &ksym
, NULL
)] = 0;
2197 if(!(tb
= tPtr
->currentTextBlock
))
2203 L_imaGFX
: if(tb
->prior
) {
2204 tPtr
->currentTextBlock
= tb
->prior
;
2205 tPtr
->tpos
= tPtr
->currentTextBlock
->used
-1;
2206 } else tPtr
->tpos
= 0;
2207 } else tPtr
->tpos
--;
2208 updateCursorPosition(tPtr
);
2213 if(!(tb
= tPtr
->currentTextBlock
))
2217 if(tPtr
->tpos
== tb
->used
) {
2218 R_imaGFX
: if(tb
->next
) {
2219 tPtr
->currentTextBlock
= tb
->next
;
2221 } else tPtr
->tpos
= tb
->used
;
2222 } else tPtr
->tpos
++;
2223 updateCursorPosition(tPtr
);
2228 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
2229 tPtr
->clicked
.y
+ tPtr
->cursor
.h
- tPtr
->vpos
);
2234 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
2235 tPtr
->visible
.y
+ tPtr
->cursor
.y
- tPtr
->vpos
- 3);
2242 deleteTextInteractively(tPtr
, ksym
);
2243 updateCursorPosition(tPtr
);
2249 control_pressed
= True
;
2253 insertTextInteractively(tPtr
, " ", 4);
2254 updateCursorPosition(tPtr
);
2261 if (buffer
[0] != 0 && !control_pressed
) {
2262 insertTextInteractively(tPtr
, buffer
, 1);
2263 updateCursorPosition(tPtr
);
2266 } else if (control_pressed
&& ksym
==XK_r
) {
2267 Bool i
= !tPtr
->flags
.rulerShown
;
2268 WMShowTextRuler(tPtr
, i
);
2269 tPtr
->flags
.rulerShown
= i
;
2271 else if (control_pressed
&& buffer
[0] == '\a')
2272 XBell(tPtr
->view
->screen
->display
, 0);
2275 if (!control_pressed
&& tPtr
->flags
.ownsSelection
)
2276 ;//releaseSelection(tPtr);
2280 handleWidgetPress(XEvent
*event
, void *data
)
2282 TextBlock
*tb
= (TextBlock
*)data
;
2290 tPtr
->currentTextBlock
= tb
;
2291 tPtr
->flags
.isOverGraphic
= 2;
2293 output(tb
->text
, tb
->used
);
2295 if (!tPtr
->flags
.focused
) {
2296 WMSetFocusToWidget(tPtr
);
2297 tPtr
->flags
.focused
= True
;
2304 handleActionEvents(XEvent
*event
, void *data
)
2306 Text
*tPtr
= (Text
*)data
;
2307 Display
*dpy
= event
->xany
.display
;
2311 switch (event
->type
) {
2313 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2314 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2315 tPtr
->flags
.extendSelection
= True
;
2319 if (tPtr
->flags
.focused
) {
2320 XGrabPointer(dpy
, W_VIEW(tPtr
)->window
, False
,
2321 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
2322 GrabModeAsync
, GrabModeAsync
, None
,
2323 tPtr
->view
->screen
->invisibleCursor
, CurrentTime
);
2324 tPtr
->flags
.pointerGrabbed
= True
;
2325 handleTextKeyPress(tPtr
, event
);
2330 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2331 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2332 tPtr
->flags
.extendSelection
= False
;
2334 /* end modify flag so selection can be extended */
2341 if (tPtr
->flags
.pointerGrabbed
) {
2342 tPtr
->flags
.pointerGrabbed
= False
;
2343 XUngrabPointer(dpy
, CurrentTime
);
2346 if(tPtr
->flags
.waitingForSelection
)
2349 if ((event
->xmotion
.state
& Button1Mask
)) {
2350 if (!tPtr
->flags
.ownsSelection
) {
2351 WMCreateSelectionHandler(tPtr
->view
,
2352 XA_PRIMARY
, event
->xbutton
.time
,
2353 &selectionHandler
, NULL
);
2354 tPtr
->flags
.ownsSelection
= True
;
2356 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2360 mouseOverObject(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2366 if (tPtr
->flags
.pointerGrabbed
) {
2367 tPtr
->flags
.pointerGrabbed
= False
;
2368 XUngrabPointer(dpy
, CurrentTime
);
2372 if (tPtr
->flags
.waitingForSelection
)
2375 if (tPtr
->flags
.extendSelection
) {
2376 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2381 if (event
->xbutton
.button
== Button1
) {
2383 if(WMIsDoubleClick(event
)) {
2384 TextBlock
*tb
= tPtr
->currentTextBlock
;
2386 if(tb
&& tb
->graphic
&& !tb
->object
) {
2387 char desc
[tb
->used
+1];
2388 memcpy(desc
, tb
->text
, tb
->used
);
2390 if(tPtr
->delegate
) {
2391 if(tPtr
->delegate
->didDoubleClickOnPicture
)
2392 (*tPtr
->delegate
->didDoubleClickOnPicture
)
2393 (tPtr
->delegate
, desc
);
2396 autoSelectText(tPtr
, 2);
2398 tPtr
->lastClickTime
= event
->xbutton
.time
;
2400 } else if(event
->xbutton
.time
- tPtr
->lastClickTime
2401 < WINGsConfiguration
.doubleClickDelay
) {
2402 autoSelectText(tPtr
, 3);
2406 if (!tPtr
->flags
.focused
) {
2407 WMSetFocusToWidget(tPtr
);
2408 tPtr
->flags
.focused
= True
;
2411 if (tPtr
->flags
.ownsSelection
)
2412 releaseSelection(tPtr
);
2414 tPtr
->lastClickTime
= event
->xbutton
.time
;
2415 cursorToTextPosition(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2419 if (event
->xbutton
.button
2420 == WINGsConfiguration
.mouseWheelDown
) {
2421 WMScrollText(tPtr
, 16);
2425 if (event
->xbutton
.button
2426 == WINGsConfiguration
.mouseWheelUp
) {
2427 WMScrollText(tPtr
, -16);
2431 if (event
->xbutton
.button
== Button2
) {
2435 if (!tPtr
->flags
.editable
) {
2441 if (!WMRequestSelection(tPtr
->view
, XA_PRIMARY
, XA_STRING
,
2442 event
->xbutton
.time
, pasteText
, NULL
)) {
2446 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
2452 (tPtr
->parser
) (tPtr
, (void *) text
);
2454 insertTextInteractively(tPtr
, text
, n
);
2458 NOTIFY(tPtr
, didChange
, WMTextDidChangeNotification
,
2459 (void*)WMInsertTextEvent
);
2463 tPtr
->flags
.waitingForSelection
= True
;
2472 if (tPtr
->flags
.pointerGrabbed
) {
2473 tPtr
->flags
.pointerGrabbed
= False
;
2474 XUngrabPointer(dpy
, CurrentTime
);
2478 if (tPtr
->flags
.waitingForSelection
)
2486 handleEvents(XEvent
*event
, void *data
)
2488 Text
*tPtr
= (Text
*)data
;
2490 switch(event
->type
) {
2493 if (event
->xexpose
.count
!=0)
2497 if (!(W_VIEW(tPtr
->hS
))->flags
.realized
)
2498 WMRealizeWidget(tPtr
->hS
);
2502 if (!(W_VIEW(tPtr
->vS
))->flags
.realized
)
2503 WMRealizeWidget(tPtr
->vS
);
2507 if (!(W_VIEW(tPtr
->ruler
))->flags
.realized
)
2508 WMRealizeWidget(tPtr
->ruler
);
2513 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2519 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))
2522 tPtr
->flags
.focused
= True
;
2524 if (tPtr
->flags
.editable
&& !tPtr
->timerID
) {
2525 tPtr
->timerID
= WMAddTimerHandler(12+0*CURSOR_BLINK_ON_DELAY
,
2533 tPtr
->flags
.focused
= False
;
2536 if (tPtr
->timerID
) {
2537 WMDeleteTimerHandler(tPtr
->timerID
);
2538 tPtr
->timerID
= NULL
;
2547 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
2549 WMEmptyArray(tPtr
->gfxItems
);
2552 WMDeleteTimerHandler(tPtr
->timerID
);
2554 WMReleaseFont(tPtr
->dFont
);
2555 WMReleaseColor(tPtr
->dColor
);
2556 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
, CurrentTime
);
2557 WMRemoveNotificationObserver(tPtr
);
2568 insertPlainText(Text
*tPtr
, char *text
)
2575 mark
= strchr(start
, '\n');
2577 tb
= WMCreateTextBlockWithText(tPtr
,
2579 tPtr
->dColor
, tPtr
->flags
.first
, (int)(mark
-start
));
2581 tPtr
->flags
.first
= True
;
2583 if (start
&& strlen(start
)) {
2584 tb
= WMCreateTextBlockWithText(tPtr
, start
, tPtr
->dFont
,
2585 tPtr
->dColor
, tPtr
->flags
.first
, strlen(start
));
2587 tPtr
->flags
.first
= False
;
2591 if (tPtr
->flags
.prepend
)
2592 WMPrependTextBlock(tPtr
, tb
);
2594 WMAppendTextBlock(tPtr
, tb
);
2602 rulerMoveCallBack(WMWidget
*w
, void *self
)
2604 Text
*tPtr
= (Text
*)self
;
2607 if (W_CLASS(tPtr
) != WC_Text
)
2615 rulerReleaseCallBack(WMWidget
*w
, void *self
)
2617 Text
*tPtr
= (Text
*)self
;
2620 if (W_CLASS(tPtr
) != WC_Text
)
2629 draggingEntered(WMView
*self
, WMDraggingInfo
*info
)
2631 printf("draggingEntered\n");
2632 return WDOperationCopy
;
2637 draggingUpdated(WMView
*self
, WMDraggingInfo
*info
)
2639 return WDOperationCopy
;
2644 draggingExited(WMView
*self
, WMDraggingInfo
*info
)
2646 printf("draggingExited\n");
2650 prepareForDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2652 printf("prepareForDragOperation\n");
2660 receivedData(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
2661 void *cdata
, WMData
*data
)
2663 badbadbad
= wstrdup((char *)WMDataBytes(data
));
2667 /* when it's done in WINGs, remove this */
2669 Bool
requestDroppedData(WMView
*view
, WMDraggingInfo
*info
, char *type
)
2671 WMScreen
*scr
= W_VIEW_SCREEN(view
);
2673 if (!WMRequestSelection(scr
->dragInfo
.destView
,
2674 scr
->xdndSelectionAtom
,
2675 XInternAtom(scr
->display
, type
, False
),
2676 scr
->dragInfo
.timestamp
,
2677 receivedData
, &scr
->dragInfo
)) {
2678 wwarning("could not request data for dropped data");
2685 ev
.type
= ClientMessage
;
2686 ev
.xclient
.message_type
= scr
->xdndFinishedAtom
;
2687 ev
.xclient
.format
= 32;
2688 ev
.xclient
.window
= info
->destinationWindow
;
2689 ev
.xclient
.data
.l
[0] = 0;
2690 ev
.xclient
.data
.l
[1] = 0;
2691 ev
.xclient
.data
.l
[2] = 0;
2692 ev
.xclient
.data
.l
[3] = 0;
2693 ev
.xclient
.data
.l
[4] = 0;
2695 XSendEvent(scr
->display
, info
->sourceWindow
, False
, 0, &ev
);
2696 XFlush(scr
->display
);
2702 performDragOperation(WMView
*self
, WMDraggingInfo
*info
, WMData
*data
)
2705 WMText
*tPtr
= (WMText
*)self
->self
;
2710 requestDroppedData(tPtr
->view
, info
, "application/X-color");
2711 color
= WMCreateNamedColor(W_VIEW_SCREEN(self
), badbadbad
, True
);
2713 WMSetTextSelectionColor(tPtr
, color
);
2714 WMReleaseColor(color
);
2723 concludeDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2725 printf("concludeDragOperation\n");
2729 static WMDragDestinationProcs _DragDestinationProcs
= {
2733 prepareForDragOperation
,
2734 performDragOperation
,
2735 concludeDragOperation
2740 getStream(WMText
*tPtr
, int sel
, int array
)
2742 TextBlock
*tb
= NULL
;
2744 unsigned long where
= 0;
2749 if (!(tb
= tPtr
->firstTextBlock
))
2753 (tPtr
->writer
) (tPtr
, (void *) text
);
2757 tb
= tPtr
->firstTextBlock
;
2760 if (!tb
->graphic
|| (tb
->graphic
&& !tPtr
->flags
.monoFont
)) {
2762 if (!sel
|| (tb
->graphic
&& tb
->selected
)) {
2764 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
)
2765 && tb
!= tPtr
->firstTextBlock
) {
2766 text
= wrealloc(text
, where
+1);
2767 text
[where
++] = '\n';
2773 if(tb
->graphic
&& array
) {
2774 text
= wrealloc(text
, where
+4);
2775 text
[where
++] = 0xFA;
2776 text
[where
++] = (tb
->used
>>8)&0x0ff;
2777 text
[where
++] = tb
->used
&0x0ff;
2778 text
[where
++] = tb
->allocated
; /* extra info */
2780 text
= wrealloc(text
, where
+tb
->used
);
2781 memcpy(&text
[where
], tb
->text
, tb
->used
);
2785 } else if (sel
&& tb
->selected
) {
2787 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
)
2788 && tb
!= tPtr
->firstTextBlock
) {
2789 text
= wrealloc(text
, where
+1);
2790 text
[where
++] = '\n';
2796 text
= wrealloc(text
, where
+(tb
->s_end
- tb
->s_begin
));
2797 memcpy(&text
[where
], &tb
->text
[tb
->s_begin
],
2798 tb
->s_end
- tb
->s_begin
);
2799 where
+= tb
->s_end
- tb
->s_begin
;
2804 _gSnext
:tb
= tb
->next
;
2807 /* +1 for the end of string, let's be nice */
2808 text
= wrealloc(text
, where
+1);
2815 releaseStreamObjects(void *data
)
2822 getStreamObjects(WMText
*tPtr
, int sel
)
2824 WMArray
*array
= WMCreateArrayWithDestructor(4, releaseStreamObjects
);
2828 char *start
, *fa
, *desc
;
2830 stream
= getStream(tPtr
, sel
, 1);
2837 fa
= strchr(start
, 0xFA);
2839 if((int)(fa
- start
)>0) {
2841 desc
[(int)(fa
- start
)] = 0;
2842 data
= WMCreateDataWithBytes((void *)desc
, (int)(fa
- start
));
2843 WMSetDataFormat(data
, TYPETEXT
);
2844 WMAddToArray(array
, (void *) data
);
2847 len
= *(fa
+1)*0xff + *(fa
+2);
2848 data
= WMCreateDataWithBytes((void *)(fa
+4), len
);
2849 WMSetDataFormat(data
, *(fa
+3));
2850 WMAddToArray(array
, (void *) data
);
2851 start
= fa
+ len
+ 4;
2854 if (start
&& strlen(start
)) {
2855 data
= WMCreateDataWithBytes((void *)start
, strlen(start
));
2856 WMSetDataFormat(data
, TYPETEXT
);
2857 WMAddToArray(array
, (void *) data
);
2870 WMCreateTextForDocumentType(WMWidget
*parent
,
2871 WMAction
*parser
, WMAction
*writer
)
2873 Text
*tPtr
= wmalloc(sizeof(Text
));
2875 printf("could not create text widget\n");
2880 memset(tPtr
, 0, sizeof(Text
));
2881 tPtr
->widgetClass
= WC_Text
;
2882 tPtr
->view
= W_CreateView(W_VIEW(parent
));
2884 perror("could not create text's view\n");
2888 tPtr
->view
->self
= tPtr
;
2889 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->textCursor
;
2890 tPtr
->view
->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2891 W_ResizeView(tPtr
->view
, 250, 200);
2893 tPtr
->dColor
= WMWhiteColor(tPtr
->view
->screen
);
2894 tPtr
->bgGC
= WMColorGC(tPtr
->dColor
);
2895 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->dColor
);
2896 WMReleaseColor(tPtr
->dColor
);
2898 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
2899 tPtr
->fgGC
= WMColorGC(tPtr
->dColor
);
2905 tPtr
->dFont
= WMRetainFont(WMSystemFontOfSize(tPtr
->view
->screen
, 12));
2907 tPtr
->view
->delegate
= &_TextViewDelegate
;
2909 tPtr
->delegate
= NULL
;
2912 tPtr
->timerID
= NULL
;
2915 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
2916 |EnterWindowMask
|LeaveWindowMask
|FocusChangeMask
,
2917 handleEvents
, tPtr
);
2919 WMCreateEventHandler(tPtr
->view
, ButtonReleaseMask
|ButtonPressMask
2920 |KeyReleaseMask
|KeyPressMask
|Button1MotionMask
,
2921 handleActionEvents
, tPtr
);
2923 WMAddNotificationObserver(ownershipObserver
, tPtr
,
2924 "_lostOwnership", tPtr
);
2927 char *types
[2] = {"application/X-color", NULL
};
2928 WMSetViewDragDestinationProcs(tPtr
->view
, &_DragDestinationProcs
);
2929 WMRegisterViewForDraggedTypes(tPtr
->view
, types
);
2932 WMAddNotificationObserver(fontChanged
, tPtr
,
2933 "WMFontPanelDidChangeNotification", tPtr
);
2935 tPtr
->firstTextBlock
= NULL
;
2936 tPtr
->lastTextBlock
= NULL
;
2937 tPtr
->currentTextBlock
= NULL
;
2940 tPtr
->gfxItems
= WMCreateArray(4);
2942 tPtr
->parser
= parser
;
2943 tPtr
->writer
= writer
;
2945 tPtr
->sel
.x
= tPtr
->sel
.y
= 2;
2946 tPtr
->sel
.w
= tPtr
->sel
.h
= 0;
2948 tPtr
->clicked
.x
= tPtr
->clicked
.y
= 2;
2950 tPtr
->visible
.x
= tPtr
->visible
.y
= 2;
2951 tPtr
->visible
.h
= tPtr
->view
->size
.height
;
2952 tPtr
->visible
.w
= tPtr
->view
->size
.width
- 4;
2954 tPtr
->cursor
.x
= -23;
2957 tPtr
->docHeight
= 0;
2958 tPtr
->dBulletPix
= WMCreatePixmapFromXPMData(tPtr
->view
->screen
,
2960 tPtr
->db
= (Pixmap
) NULL
;
2962 tPtr
->margins
= WMGetRulerMargins(NULL
);
2963 tPtr
->margins
->right
= tPtr
->visible
.w
;
2966 tPtr
->flags
.rulerShown
= False
;
2967 tPtr
->flags
.monoFont
= False
;
2968 tPtr
->flags
.focused
= False
;
2969 tPtr
->flags
.editable
= True
;
2970 tPtr
->flags
.ownsSelection
= False
;
2971 tPtr
->flags
.pointerGrabbed
= False
;
2972 tPtr
->flags
.extendSelection
= False
;
2973 tPtr
->flags
.frozen
= False
;
2974 tPtr
->flags
.cursorShown
= True
;
2975 tPtr
->flags
.acceptsGraphic
= False
;
2976 tPtr
->flags
.horizOnDemand
= False
;
2977 tPtr
->flags
.needsLayOut
= False
;
2978 tPtr
->flags
.ignoreNewLine
= False
;
2979 tPtr
->flags
.indentNewLine
= False
;
2980 tPtr
->flags
.laidOut
= False
;
2981 tPtr
->flags
.waitingForSelection
= False
;
2982 tPtr
->flags
.prepend
= False
;
2983 tPtr
->flags
.isOverGraphic
= False
;
2984 tPtr
->flags
.relief
= WRSunken
;
2985 tPtr
->flags
.isOverGraphic
= 0;
2986 tPtr
->flags
.alignment
= WALeft
;
2987 tPtr
->flags
.first
= True
;
2993 WMPrependTextStream(WMText
*tPtr
, char *text
)
2995 CHECK_CLASS(tPtr
, WC_Text
);
2998 if(tPtr
->flags
.ownsSelection
)
2999 releaseSelection(tPtr
);
3002 updateScrollers(tPtr
);
3007 tPtr
->flags
.prepend
= True
;
3008 if (text
&& tPtr
->parser
)
3009 (tPtr
->parser
) (tPtr
, (void *) text
);
3011 insertPlainText(tPtr
, text
);
3013 tPtr
->flags
.needsLayOut
= True
;
3019 WMAppendTextStream(WMText
*tPtr
, char *text
)
3021 CHECK_CLASS(tPtr
, WC_Text
);
3024 if(tPtr
->flags
.ownsSelection
)
3025 releaseSelection(tPtr
);
3028 updateScrollers(tPtr
);
3033 tPtr
->flags
.prepend
= False
;
3034 if (text
&& tPtr
->parser
)
3035 (tPtr
->parser
) (tPtr
, (void *) text
);
3037 insertPlainText(tPtr
, text
);
3039 tPtr
->flags
.needsLayOut
= True
;
3040 if(tPtr
->currentTextBlock
)
3041 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
3048 WMGetTextStream(WMText
*tPtr
)
3050 CHECK_CLASS(tPtr
, WC_Text
);
3051 return getStream(tPtr
, 0, 0);
3055 WMGetTextSelectedStream(WMText
*tPtr
)
3057 CHECK_CLASS(tPtr
, WC_Text
);
3058 return getStream(tPtr
, 1, 0);
3062 WMGetTextObjects(WMText
*tPtr
)
3064 CHECK_CLASS(tPtr
, WC_Text
);
3065 return getStreamObjects(tPtr
, 0);
3069 WMGetTextSelectedObjects(WMText
*tPtr
)
3071 CHECK_CLASS(tPtr
, WC_Text
);
3072 return getStreamObjects(tPtr
, 1);
3077 WMSetTextDelegate(WMText
*tPtr
, WMTextDelegate
*delegate
)
3079 CHECK_CLASS(tPtr
, WC_Text
);
3081 tPtr
->delegate
= delegate
;
3086 WMCreateTextBlockWithObject(WMText
*tPtr
, WMWidget
*w
,
3087 char *description
, WMColor
*color
,
3088 unsigned short first
, unsigned short extraInfo
)
3092 if (!w
|| !description
|| !color
)
3095 tb
= wmalloc(sizeof(TextBlock
));
3099 tb
->text
= wstrdup(description
);
3100 tb
->used
= strlen(description
);
3103 tb
->color
= WMRetainColor(color
);
3104 tb
->marginN
= newMargin(tPtr
, NULL
);
3105 tb
->allocated
= extraInfo
;
3110 tb
->underlined
= False
;
3111 tb
->selected
= False
;
3113 tb
->sections
= NULL
;
3123 WMCreateTextBlockWithPixmap(WMText
*tPtr
, WMPixmap
*p
,
3124 char *description
, WMColor
*color
,
3125 unsigned short first
, unsigned short extraInfo
)
3129 if (!p
|| !description
|| !color
)
3132 tb
= wmalloc(sizeof(TextBlock
));
3136 tb
->text
= wstrdup(description
);
3137 tb
->used
= strlen(description
);
3139 tb
->d
.pixmap
= WMRetainPixmap(p
);
3140 tb
->color
= WMRetainColor(color
);
3141 tb
->marginN
= newMargin(tPtr
, NULL
);
3142 tb
->allocated
= extraInfo
;
3147 tb
->underlined
= False
;
3148 tb
->selected
= False
;
3150 tb
->sections
= NULL
;
3159 WMCreateTextBlockWithText(WMText
*tPtr
, char *text
, WMFont
*font
, WMColor
*color
,
3160 unsigned short first
, unsigned short len
)
3164 if (!font
|| !color
)
3167 tb
= wmalloc(sizeof(TextBlock
));
3171 tb
->allocated
= reqBlockSize(len
);
3172 tb
->text
= (char *)wmalloc(tb
->allocated
);
3173 memset(tb
->text
, 0, tb
->allocated
);
3175 if (len
< 1|| !text
|| (*text
== '\n' && len
==1 )) {
3180 memcpy(tb
->text
, text
, len
);
3184 tb
->text
[tb
->used
] = 0;
3186 tb
->d
.font
= WMRetainFont(font
);
3187 tb
->color
= WMRetainColor(color
);
3188 tb
->marginN
= newMargin(tPtr
, NULL
);
3191 tb
->graphic
= False
;
3192 tb
->underlined
= False
;
3193 tb
->selected
= False
;
3195 tb
->sections
= NULL
;
3203 WMSetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int first
,
3204 unsigned int kanji
, unsigned int underlined
, int script
,
3205 WMRulerMargins
*margins
)
3207 TextBlock
*tb
= (TextBlock
*) vtb
;
3213 tb
->underlined
= underlined
;
3214 tb
->script
= script
;
3215 tb
->marginN
= newMargin(tPtr
, margins
);
3219 WMGetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int *first
,
3220 unsigned int *kanji
, unsigned int *underlined
, int *script
,
3221 WMRulerMargins
*margins
)
3223 TextBlock
*tb
= (TextBlock
*) vtb
;
3227 if (first
) *first
= tb
->first
;
3228 if (kanji
) *kanji
= tb
->kanji
;
3229 if (underlined
) *underlined
= tb
->underlined
;
3230 if (script
) *script
= tb
->script
;
3231 if (margins
) margins
= &tPtr
->margins
[tb
->marginN
];
3237 WMPrependTextBlock(WMText
*tPtr
, void *vtb
)
3239 TextBlock
*tb
= (TextBlock
*)vtb
;
3246 WMWidget
*w
= tb
->d
.widget
;
3247 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
3248 handleWidgetPress
, tb
);
3249 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
3250 (W_VIEW(w
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3251 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3254 WMAddToArray(tPtr
->gfxItems
, (void *)tb
);
3256 } else tPtr
->tpos
= tb
->used
;
3258 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
3259 tb
->next
= tb
->prior
= NULL
;
3261 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
3262 = tPtr
->currentTextBlock
= tb
;
3267 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
3270 tb
->next
= tPtr
->currentTextBlock
;
3271 tb
->prior
= tPtr
->currentTextBlock
->prior
;
3272 if (tPtr
->currentTextBlock
->prior
)
3273 tPtr
->currentTextBlock
->prior
->next
= tb
;
3275 tPtr
->currentTextBlock
->prior
= tb
;
3277 tPtr
->firstTextBlock
= tb
;
3279 tPtr
->currentTextBlock
= tb
;
3284 WMAppendTextBlock(WMText
*tPtr
, void *vtb
)
3286 TextBlock
*tb
= (TextBlock
*)vtb
;
3293 WMWidget
*w
= tb
->d
.widget
;
3294 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
3295 handleWidgetPress
, tb
);
3296 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
3297 (W_VIEW(w
))->attribs
.cursor
=
3298 tPtr
->view
->screen
->defaultCursor
;
3299 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3302 WMAddToArray(tPtr
->gfxItems
, (void *)tb
);
3304 } else tPtr
->tpos
= tb
->used
;
3306 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
3307 tb
->next
= tb
->prior
= NULL
;
3309 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
3310 = tPtr
->currentTextBlock
= tb
;
3315 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
3318 tb
->next
= tPtr
->currentTextBlock
->next
;
3319 tb
->prior
= tPtr
->currentTextBlock
;
3320 if (tPtr
->currentTextBlock
->next
)
3321 tPtr
->currentTextBlock
->next
->prior
= tb
;
3323 tPtr
->currentTextBlock
->next
= tb
;
3326 tPtr
->lastTextBlock
= tb
;
3328 tPtr
->currentTextBlock
= tb
;
3332 WMRemoveTextBlock(WMText
*tPtr
)
3334 TextBlock
*tb
= NULL
;
3336 if (!tPtr
|| !tPtr
->firstTextBlock
|| !tPtr
->lastTextBlock
3337 || !tPtr
->currentTextBlock
) {
3338 printf("cannot remove non existent TextBlock!\b");
3342 tb
= tPtr
->currentTextBlock
;
3344 WMRemoveFromArray(tPtr
->gfxItems
, (void *)tb
);
3347 WMDeleteEventHandler(W_VIEW(tb
->d
.widget
), ButtonPressMask
,
3348 handleWidgetPress
, tb
);
3349 WMUnmapWidget(tb
->d
.widget
);
3353 if (tPtr
->currentTextBlock
== tPtr
->firstTextBlock
) {
3354 if (tPtr
->currentTextBlock
->next
)
3355 tPtr
->currentTextBlock
->next
->prior
= NULL
;
3357 tPtr
->firstTextBlock
= tPtr
->currentTextBlock
->next
;
3358 tPtr
->currentTextBlock
= tPtr
->firstTextBlock
;
3360 } else if (tPtr
->currentTextBlock
== tPtr
->lastTextBlock
) {
3361 tPtr
->currentTextBlock
->prior
->next
= NULL
;
3362 tPtr
->lastTextBlock
= tPtr
->currentTextBlock
->prior
;
3363 tPtr
->currentTextBlock
= tPtr
->lastTextBlock
;
3365 tPtr
->currentTextBlock
->prior
->next
= tPtr
->currentTextBlock
->next
;
3366 tPtr
->currentTextBlock
->next
->prior
= tPtr
->currentTextBlock
->prior
;
3367 tPtr
->currentTextBlock
= tPtr
->currentTextBlock
->next
;
3374 WMDestroyTextBlock(WMText
*tPtr
, void *vtb
)
3376 TextBlock
*tb
= (TextBlock
*)vtb
;
3382 /* naturally, there's a danger to destroying
3383 widgets whose action brings us here:
3384 ie. press a button to destroy it... need to
3385 find a safer way. till then... this stays commented out */
3386 /* WMDestroyWidget(tb->d.widget);
3387 wfree(tb->d.widget); */
3388 tb
->d
.widget
= NULL
;
3390 WMReleasePixmap(tb
->d
.pixmap
);
3391 tb
->d
.pixmap
= NULL
;
3394 WMReleaseFont(tb
->d
.font
);
3397 WMReleaseColor(tb
->color
);
3398 if (tb
->sections
&& tb
->nsections
> 0)
3399 wfree(tb
->sections
);
3408 WMSetTextForegroundColor(WMText
*tPtr
, WMColor
*color
)
3414 tPtr
->fgGC
= WMColorGC(color
);
3416 tPtr
->fgGC
= WMColorGC(WMBlackColor(tPtr
->view
->screen
));
3422 WMSetTextBackgroundColor(WMText
*tPtr
, WMColor
*color
)
3428 tPtr
->bgGC
= WMColorGC(color
);
3429 W_SetViewBackgroundColor(tPtr
->view
, color
);
3431 tPtr
->bgGC
= WMColorGC(WMWhiteColor(tPtr
->view
->screen
));
3432 W_SetViewBackgroundColor(tPtr
->view
,
3433 WMWhiteColor(tPtr
->view
->screen
));
3440 WMSetTextRelief(WMText
*tPtr
, WMReliefType relief
)
3444 tPtr
->flags
.relief
= relief
;
3445 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3449 WMSetTextHasHorizontalScroller(WMText
*tPtr
, Bool shouldhave
)
3454 if (shouldhave
&& !tPtr
->hS
) {
3455 tPtr
->hS
= WMCreateScroller(tPtr
);
3456 (W_VIEW(tPtr
->hS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3457 (W_VIEW(tPtr
->hS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3458 WMSetScrollerArrowsPosition(tPtr
->hS
, WSAMinEnd
);
3459 WMSetScrollerAction(tPtr
->hS
, scrollersCallBack
, tPtr
);
3460 WMMapWidget(tPtr
->hS
);
3461 } else if (!shouldhave
&& tPtr
->hS
) {
3462 WMUnmapWidget(tPtr
->hS
);
3463 WMDestroyWidget(tPtr
->hS
);
3469 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3474 WMSetTextHasRuler(WMText
*tPtr
, Bool shouldhave
)
3479 if(shouldhave
&& !tPtr
->ruler
) {
3480 tPtr
->ruler
= WMCreateRuler(tPtr
);
3481 (W_VIEW(tPtr
->ruler
))->attribs
.cursor
=
3482 tPtr
->view
->screen
->defaultCursor
;
3483 (W_VIEW(tPtr
->ruler
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3484 WMSetRulerReleaseAction(tPtr
->ruler
, rulerReleaseCallBack
, tPtr
);
3485 WMSetRulerMoveAction(tPtr
->ruler
, rulerMoveCallBack
, tPtr
);
3486 } else if(!shouldhave
&& tPtr
->ruler
) {
3487 WMShowTextRuler(tPtr
, False
);
3488 WMDestroyWidget(tPtr
->ruler
);
3491 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3495 WMShowTextRuler(WMText
*tPtr
, Bool show
)
3502 if(tPtr
->flags
.monoFont
)
3505 tPtr
->flags
.rulerShown
= show
;
3507 WMMapWidget(tPtr
->ruler
);
3509 WMUnmapWidget(tPtr
->ruler
);
3512 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3516 WMGetTextRulerShown(WMText
*tPtr
)
3524 return tPtr
->flags
.rulerShown
;
3529 WMSetTextHasVerticalScroller(WMText
*tPtr
, Bool shouldhave
)
3534 if (shouldhave
&& !tPtr
->vS
) {
3535 tPtr
->vS
= WMCreateScroller(tPtr
);
3536 (W_VIEW(tPtr
->vS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3537 (W_VIEW(tPtr
->vS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3538 WMSetScrollerArrowsPosition(tPtr
->vS
, WSAMaxEnd
);
3539 WMSetScrollerAction(tPtr
->vS
, scrollersCallBack
, tPtr
);
3540 WMMapWidget(tPtr
->vS
);
3541 } else if (!shouldhave
&& tPtr
->vS
) {
3542 WMUnmapWidget(tPtr
->vS
);
3543 WMDestroyWidget(tPtr
->vS
);
3549 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3555 WMScrollText(WMText
*tPtr
, int amount
)
3560 if (amount
== 0 || !tPtr
->view
->flags
.realized
)
3564 if (tPtr
->vpos
> 0) {
3565 if (tPtr
->vpos
> abs(amount
)) tPtr
->vpos
+= amount
;
3569 int limit
= tPtr
->docHeight
- tPtr
->visible
.h
;
3570 if (tPtr
->vpos
< limit
) {
3571 if (tPtr
->vpos
< limit
-amount
) tPtr
->vpos
+= amount
;
3572 else tPtr
->vpos
= limit
;
3576 if (scroll
&& tPtr
->vpos
!= tPtr
->prevVpos
) {
3577 updateScrollers(tPtr
);
3580 tPtr
->prevVpos
= tPtr
->vpos
;
3585 WMPageText(WMText
*tPtr
, Bool direction
)
3587 if (!tPtr
) return False
;
3588 if (!tPtr
->view
->flags
.realized
) return False
;
3590 return WMScrollText(tPtr
, direction
?tPtr
->visible
.h
:-tPtr
->visible
.h
);
3594 WMSetTextEditable(WMText
*tPtr
, Bool editable
)
3598 tPtr
->flags
.editable
= editable
;
3602 WMGetTextEditable(WMText
*tPtr
)
3606 return tPtr
->flags
.editable
;
3610 WMSetTextIndentNewLines(WMText
*tPtr
, Bool indent
)
3614 tPtr
->flags
.indentNewLine
= indent
;
3618 WMSetTextIgnoresNewline(WMText
*tPtr
, Bool ignore
)
3622 tPtr
->flags
.ignoreNewLine
= ignore
;
3626 WMGetTextIgnoresNewline(WMText
*tPtr
)
3630 return tPtr
->flags
.ignoreNewLine
;
3634 WMSetTextUsesMonoFont(WMText
*tPtr
, Bool mono
)
3640 if(tPtr
->flags
.rulerShown
)
3641 WMShowTextRuler(tPtr
, False
);
3642 if(tPtr
->flags
.alignment
!= WALeft
)
3643 tPtr
->flags
.alignment
= WALeft
;
3646 tPtr
->flags
.monoFont
= mono
;
3647 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3651 WMGetTextUsesMonoFont(WMText
*tPtr
)
3655 return tPtr
->flags
.monoFont
;
3660 WMSetTextDefaultFont(WMText
*tPtr
, WMFont
*font
)
3665 WMReleaseFont(tPtr
->dFont
);
3667 tPtr
->dFont
= WMRetainFont(font
);
3669 tPtr
->dFont
= WMRetainFont(WMSystemFontOfSize(tPtr
->view
->screen
, 12));
3673 WMGetTextDefaultFont(WMText
*tPtr
)
3678 return WMRetainFont(tPtr
->dFont
);
3682 WMSetTextDefaultColor(WMText
*tPtr
, WMColor
*color
)
3687 WMReleaseColor(tPtr
->dColor
);
3689 tPtr
->dColor
= WMRetainColor(color
);
3691 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
3695 WMGetTextDefaultColor(WMText
*tPtr
)
3700 return WMRetainColor(tPtr
->dColor
);
3704 WMSetTextAlignment(WMText
*tPtr
, WMAlignment alignment
)
3708 if(tPtr
->flags
.monoFont
)
3709 tPtr
->flags
.alignment
= WALeft
;
3711 tPtr
->flags
.alignment
= alignment
;
3716 WMGetTextInsertType(WMText
*tPtr
)
3720 return tPtr
->flags
.prepend
;
3725 WMSetTextSelectionColor(WMText
*tPtr
, WMColor
*color
)
3727 if (!tPtr
|| !color
)
3730 setSelectionProperty(tPtr
, NULL
, color
, -1);
3734 WMGetTextSelectionColor(WMText
*tPtr
)
3741 tb
= tPtr
->currentTextBlock
;
3743 if (!tb
|| !tPtr
->flags
.ownsSelection
)
3754 WMSetTextSelectionFont(WMText
*tPtr
, WMFont
*font
)
3759 setSelectionProperty(tPtr
, font
, NULL
, -1) ;
3763 WMGetTextSelectionFont(WMText
*tPtr
)
3770 tb
= tPtr
->currentTextBlock
;
3772 if (!tb
|| !tPtr
->flags
.ownsSelection
)
3779 tb
= getFirstNonGraphicBlockFor(tb
, 1);
3783 return (tb
->selected
? tb
->d
.font
: NULL
);
3788 WMSetTextSelectionUnderlined(WMText
*tPtr
, int underlined
)
3790 if (!tPtr
|| (underlined
!=0 && underlined
!=1))
3793 setSelectionProperty(tPtr
, NULL
, NULL
, underlined
);
3798 WMGetTextSelectionUnderlined(WMText
*tPtr
)
3805 tb
= tPtr
->currentTextBlock
;
3807 if (!tb
|| !tPtr
->flags
.ownsSelection
)
3813 return tb
->underlined
;
3818 WMFreezeText(WMText
*tPtr
)
3823 tPtr
->flags
.frozen
= True
;
3828 WMThawText(WMText
*tPtr
)
3833 tPtr
->flags
.frozen
= False
;
3835 if(tPtr
->flags
.monoFont
) {
3836 int j
, c
= WMGetArrayItemCount(tPtr
->gfxItems
);
3839 /* make sure to unmap widgets no matter where they are */
3840 /* they'll be later remapped if needed by paintText */
3841 for(j
=0; j
<c
; j
++) {
3842 if ((tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
))) {
3843 if (tb
->object
&& ((W_VIEW(tb
->d
.widget
))->flags
.mapped
))
3844 WMUnmapWidget(tb
->d
.widget
);
3850 tPtr
->flags
.laidOut
= False
;
3851 layOutDocument(tPtr
);
3852 updateScrollers(tPtr
);
3854 tPtr
->flags
.needsLayOut
= False
;
3858 /* find first occurence of a string */
3860 mystrstr(char *haystack
, char *needle
, unsigned short len
, char *end
,
3865 if(!haystack
|| !needle
|| !end
)
3868 for (ptr
= haystack
; ptr
< end
; ptr
++) {
3870 if (*ptr
== *needle
&& !strncmp(ptr
, needle
, len
))
3874 if (tolower(*ptr
) == tolower(*needle
) &&
3875 !strncasecmp(ptr
, needle
, len
))
3883 /* find last occurence of a string */
3885 mystrrstr(char *haystack
, char *needle
, unsigned short len
, char *end
,
3890 if(!haystack
|| !needle
|| !end
)
3893 for (ptr
= haystack
-2; ptr
> end
; ptr
--) {
3895 if (*ptr
== *needle
&& !strncmp(ptr
, needle
, len
))
3898 if (tolower(*ptr
) == tolower(*needle
) &&
3899 !strncasecmp(ptr
, needle
, len
))
3909 WMFindInTextStream(WMText
*tPtr
, char *needle
, Bool direction
,
3916 if (!tPtr
|| !needle
)
3920 if (! (tb
= tPtr
->currentTextBlock
)) {
3921 if (! (tb
= ( (direction
> 0) ?
3922 tPtr
->firstTextBlock
: tPtr
->lastTextBlock
) ) ){
3926 /* if(tb != ((direction>0) ?tPtr->firstTextBlock : tPtr->lastTextBlock))
3927 tb = (direction>0) ? tb->next : tb->prior; */
3928 if(tb
!= tPtr
->lastTextBlock
)
3932 tb
= tPtr
->currentTextBlock
;
3940 if(pos
+1 < tb
->used
)
3943 if(tb
->used
- pos
> 0 && pos
> 0) {
3944 mark
= mystrstr(&tb
->text
[pos
], needle
,
3945 strlen(needle
), &tb
->text
[tb
->used
], caseSensitive
);
3958 mark
= mystrrstr(&tb
->text
[pos
], needle
,
3959 strlen(needle
), tb
->text
, caseSensitive
);
3971 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
3973 tPtr
->tpos
= (int)(mark
- tb
->text
);
3974 tPtr
->currentTextBlock
= tb
;
3975 updateCursorPosition(tPtr
);
3976 tPtr
->sel
.y
= tPtr
->cursor
.y
+5;
3977 tPtr
->sel
.h
= tPtr
->cursor
.h
-10;
3978 tPtr
->sel
.x
= tPtr
->cursor
.x
+1;
3979 tPtr
->sel
.w
= WMIN(WMWidthOfString(font
,
3980 &tb
->text
[tPtr
->tpos
], strlen(needle
)),
3981 tPtr
->docWidth
- tPtr
->sel
.x
);
3982 tPtr
->flags
.ownsSelection
= True
;
3989 tb
= (direction
>0) ? tb
->next
: tb
->prior
;
3991 pos
= (direction
>0) ? 0 : tb
->used
;
4000 WMReplaceTextSelection(WMText
*tPtr
, char *replacement
)
4005 if (!tPtr
->flags
.ownsSelection
)
4008 removeSelection(tPtr
);
4011 insertTextInteractively(tPtr
, replacement
, strlen(replacement
));
4012 updateCursorPosition(tPtr
);