2 /* WINGs WMText: multi-line/font/color/graphic text widget, by Nwanua. */
6 #include <X11/keysym.h>
12 * - FIX wrap... long lines that don't fit are not char wrapped yet.
13 * - hrm... something to do with already having tbs...
14 * - selection code... selects can be funny if it crosses over. use rect?
15 *- also inspect behaviour for WACenter and WARight
16 * - FIX: graphix blocks MUST be skipped if monoFont even though they exist!
17 * - check if support for Horizontal Scroll is complete
18 * - assess danger of destroying widgets whose actions link to other pages
19 * - Tabs now are simply replaced by 4 spaces...
20 * - redo blink code to reduce paint event... use pixmap buffer...
21 * - add paragraph support (full) and '\n' code in getStream..
25 /* a Section is a section of a TextBlock that describes what parts
26 of a TextBlock has been laid out on which "line"...
27 o this greatly aids redraw, scroll and selection.
28 o this is created during layoutLine, but may be later modified.
29 o there may be many Sections per TextBlock, hence the array */
31 unsigned int x
, y
; /* where to draw it from */
32 unsigned short w
, h
; /* its width and height */
33 unsigned short begin
; /* where the layout begins */
34 unsigned short end
; /* where it ends */
35 unsigned short max_d
; /* a quick hack for layOut if(laidOut) */
36 unsigned short last
:1; /* is it the last section on a "line"? */
37 unsigned int _y
:31; /* the "line" it and other textblocks are on */
41 /* a TextBlock is a doubly-linked list of TextBlocks containing:
42 o text for the block, color and font
43 o or a pointer to the pixmap
44 o OR a pointer to the widget and the (text) description for its graphic
47 typedef struct _TextBlock
{
48 struct _TextBlock
*next
; /* next text block in linked list */
49 struct _TextBlock
*prior
; /* prior text block in linked list */
51 char *text
; /* pointer to text (could be kanji) */
52 /* or to the object's description */
54 WMFont
*font
; /* the font */
55 WMWidget
*widget
; /* the embedded widget */
56 WMPixmap
*pixmap
; /* the pixmap */
57 } d
; /* description */
59 unsigned short used
; /* number of chars in this block */
60 unsigned short allocated
; /* size of allocation (in chars) */
61 WMColor
*color
; /* the color */
63 Section
*sections
; /* the region for layouts (a growable array) */
64 /* an _array_! of size _nsections_ */
66 unsigned short s_begin
; /* where the selection begins */
67 unsigned short s_end
; /* where it ends */
69 unsigned int first
:1; /* first TextBlock in paragraph */
70 unsigned int blank
:1; /* ie. blank paragraph */
71 unsigned int kanji
:1; /* is of 16-bit characters or not */
72 unsigned int graphic
:1; /* graphic or text: text=0 */
73 unsigned int object
:1; /* embedded object or pixmap */
74 unsigned int underlined
:1; /* underlined or not */
75 unsigned int selected
:1; /* selected or not */
76 unsigned int nsections
:8; /* over how many "lines" a TextBlock wraps */
77 int script
:8; /* script in points: negative for subscript */
78 unsigned int marginN
:8; /* which of the margins in the tPtr to use */
79 unsigned int nClicks
:2; /* single, double, triple clicks */
80 unsigned int RESERVED
:7;
84 /* I'm lazy: visible.h vs. visible.size.height :-) */
93 typedef struct W_Text
{
94 W_Class widgetClass
; /* the class number of this widget */
95 W_View
*view
; /* the view referring to this instance */
97 WMRuler
*ruler
; /* the ruler widget to manipulate paragraphs */
99 WMScroller
*vS
; /* the vertical scroller */
100 unsigned int vpos
; /* the current vertical position */
101 unsigned int prevVpos
; /* the previous vertical position */
103 WMScroller
*hS
; /* the horizontal scroller */
104 unsigned int hpos
; /* the current horizontal position */
105 unsigned int prevHpos
; /* the previous horizontal position */
107 WMFont
*dFont
; /* the default font */
108 WMColor
*dColor
; /* the default color */
109 WMPixmap
*dBulletPix
; /* the default pixmap for bullets */
111 GC bgGC
; /* the background GC to draw with */
112 GC fgGC
; /* the foreground GC to draw with */
113 Pixmap db
; /* the buffer on which to draw */
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) { WMNotification *notif = WMCreateNotification(N,T,A);\
172 if ((T)->delegate && (T)->delegate->C)\
173 (*(T)->delegate->C)((T)->delegate,notif);\
174 WMPostNotification(notif);\
175 WMReleaseNotification(notif);}
181 output(char *ptr
, int len
)
186 /* printf(" s is [%s] (%d)\n", s, strlen(s)); */
192 #define CURSOR_BLINK_ON_DELAY 600
193 #define CURSOR_BLINK_OFF_DELAY 400
196 static char *default_bullet
[] = {
198 " c None s None", ". c black",
199 "X c white", "o c #808080",
207 static void handleEvents(XEvent
*event
, void *data
);
208 static void layOutDocument(Text
*tPtr
);
209 static void updateScrollers(Text
*tPtr
);
213 getMarginNumber(Text
*tPtr
, WMRulerMargins
*margins
)
217 for(i
=0; i
< tPtr
->nMargins
; i
++) {
219 if(WMIsMarginEqualToMargin(&tPtr
->margins
[i
], margins
))
229 newMargin(Text
*tPtr
, WMRulerMargins
*margins
)
234 tPtr
->margins
[0].retainCount
++;
238 n
= getMarginNumber(tPtr
, margins
);
242 tPtr
->margins
= wrealloc(tPtr
->margins
,
243 (++tPtr
->nMargins
)*sizeof(WMRulerMargins
));
245 n
= tPtr
->nMargins
-1;
246 tPtr
->margins
[n
].left
= margins
->left
;
247 tPtr
->margins
[n
].first
= margins
->first
;
248 tPtr
->margins
[n
].body
= margins
->body
;
249 tPtr
->margins
[n
].right
= margins
->right
;
250 /* for each tab... */
251 tPtr
->margins
[n
].retainCount
= 1;
253 tPtr
->margins
[n
].retainCount
++;
260 sectionWasSelected(Text
*tPtr
, TextBlock
*tb
, XRectangle
*rect
, int s
)
262 unsigned short i
, w
, lw
, selected
= False
, extend
= False
;
266 /* if selection rectangle completely encloses the section */
267 if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
268 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
269 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
271 sel
.w
= tPtr
->visible
.w
;
272 selected
= extend
= True
;
274 /* or if it starts on a line and then goes further down */
275 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
276 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
277 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
278 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
279 >= tPtr
->visible
.y
+ tPtr
->sel
.y
) ) {
280 sel
.x
= WMAX(tPtr
->sel
.x
, tPtr
->clicked
.x
);
281 sel
.w
= tPtr
->visible
.w
;
282 selected
= extend
= True
;
284 /* or if it begins before a line, but ends on it */
285 } else if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
286 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
287 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
288 && (tb
->sections
[s
]._y
289 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
291 if (1||tPtr
->sel
.x
+ tPtr
->sel
.w
> tPtr
->clicked
.x
)
292 sel
.w
= tPtr
->sel
.x
+ tPtr
->sel
.w
;
299 /* or if the selection rectangle lies entirely within a line */
300 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
301 && (tPtr
->sel
.w
>= 2)
302 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
303 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
312 /* if not within (modified) selection rectangle */
313 if ( tb
->sections
[s
].x
> sel
.x
+ sel
.w
314 || tb
->sections
[s
].x
+ tb
->sections
[s
].w
< sel
.x
)
318 if ( tb
->sections
[s
].x
+ tb
->sections
[s
].w
<= sel
.x
+ sel
.w
319 && tb
->sections
[s
].x
>= sel
.x
) {
320 rect
->width
= tb
->sections
[s
].w
;
321 rect
->x
= tb
->sections
[s
].x
;
326 i
= tb
->sections
[s
].begin
;
329 if (0&& tb
->sections
[s
].x
>= sel
.x
) {
330 tb
->s_begin
= tb
->sections
[s
].begin
;
334 while (++i
<= tb
->sections
[s
].end
) {
336 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
339 if (lw
+ tb
->sections
[s
].x
>= sel
.x
340 || i
== tb
->sections
[s
].end
) {
343 tb
->s_begin
= (tb
->selected
? WMIN(tb
->s_begin
, i
) : i
);
348 if (i
> tb
->sections
[s
].end
) {
349 printf("WasSelected: (i > tb->sections[s].end) \n");
353 _selEnd
: rect
->x
= tb
->sections
[s
].x
+ lw
;
355 while(++i
<= tb
->sections
[s
].end
) {
357 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
360 if (lw
+ rect
->x
>= sel
.x
+ sel
.w
361 || i
== tb
->sections
[s
].end
) {
363 if (i
!= tb
->sections
[s
].end
) {
369 if (tb
->sections
[s
].last
&& sel
.x
+ sel
.w
370 >= tb
->sections
[s
].x
+ tb
->sections
[s
].w
372 rect
->width
+= (tPtr
->visible
.w
- rect
->x
- lw
);
375 tb
->s_end
= (tb
->selected
? WMAX(tb
->s_end
, i
) : i
);
381 rect
->y
= tb
->sections
[s
]._y
- tPtr
->vpos
;
382 rect
->height
= tb
->sections
[s
].h
;
383 if(tb
->graphic
) { printf("graphic s%d h%d\n", s
,tb
->sections
[s
].h
);}
390 setSelectionProperty(WMText
*tPtr
, WMFont
*font
, WMColor
*color
, int underlined
)
395 tb
= tPtr
->firstTextBlock
;
396 if (!tb
|| !tPtr
->flags
.ownsSelection
)
399 if(font
&& (!color
|| underlined
==-1))
403 if (tPtr
->flags
.monoFont
|| tb
->selected
) {
405 if (tPtr
->flags
.monoFont
|| (tb
->s_end
- tb
->s_begin
== tb
->used
)
410 WMReleaseFont(tb
->d
.font
);
411 tb
->d
.font
= WMRetainFont(font
);
413 } else if(underlined
!=-1) {
414 tb
->underlined
= underlined
;
416 WMReleaseColor(tb
->color
);
417 tb
->color
= WMRetainColor(color
);
420 } else if (tb
->s_end
<= tb
->used
&& tb
->s_begin
< tb
->s_end
) {
422 TextBlock
*midtb
, *otb
= tb
;
424 if(underlined
!= -1) {
425 midtb
= (TextBlock
*) WMCreateTextBlockWithText(tPtr
,
426 &(tb
->text
[tb
->s_begin
]), tb
->d
.font
, tb
->color
,
427 False
, (tb
->s_end
- tb
->s_begin
));
429 midtb
= (TextBlock
*) WMCreateTextBlockWithText(tPtr
,
430 &(tb
->text
[tb
->s_begin
]),
431 (isFont
?font
:tb
->d
.font
),
432 (isFont
?tb
->color
:color
),
433 False
, (tb
->s_end
- tb
->s_begin
));
438 if(underlined
!= -1) {
439 midtb
->underlined
= underlined
;
441 midtb
->underlined
= otb
->underlined
;
444 midtb
->selected
= !True
;
446 midtb
->s_end
= midtb
->used
;
447 tPtr
->currentTextBlock
= tb
;
448 WMAppendTextBlock(tPtr
, midtb
);
449 tb
= tPtr
->currentTextBlock
;
452 if (otb
->used
- otb
->s_end
> 0) {
455 WMCreateTextBlockWithText(tPtr
,
456 &(otb
->text
[otb
->s_end
]), otb
->d
.font
, otb
->color
,
457 False
, otb
->used
- otb
->s_end
);
460 ntb
->underlined
= otb
->underlined
;
461 ntb
->selected
= False
;
462 WMAppendTextBlock(tPtr
, ntb
);
463 tb
= tPtr
->currentTextBlock
;
468 tPtr
->currentTextBlock
= midtb
;
471 otb
->selected
= False
;
472 otb
->used
= otb
->s_begin
;
479 tPtr
->flags
.needsLayOut
= True
;
482 /* in case the size changed... */
483 if(isFont
&& tPtr
->currentTextBlock
) {
484 TextBlock
*tb
= tPtr
->currentTextBlock
;
486 printf("%d %d %d\n", tPtr
->sel
.y
, tPtr
->sel
.h
, tPtr
->sel
.w
);
487 tPtr
->sel
.y
= 3 + tb
->sections
[0]._y
;
488 tPtr
->sel
.h
= tb
->sections
[tb
->nsections
-1]._y
- tb
->sections
[0]._y
;
489 tPtr
->sel
.w
= tb
->sections
[tb
->nsections
-1].w
;
490 if(tb
->sections
[tb
->nsections
-1]._y
!= tb
->sections
[0]._y
) {
493 printf("%d %d %d\n\n\n", tPtr
->sel
.y
, tPtr
->sel
.h
, tPtr
->sel
.w
);
500 removeSelection(Text
*tPtr
)
502 TextBlock
*tb
= NULL
;
505 if (!(tb
= tPtr
->firstTextBlock
))
510 if(!first
&& !tb
->graphic
) {
511 WMReleaseFont(tPtr
->dFont
);
512 tPtr
->dFont
= WMRetainFont(tb
->d
.font
);
516 if ( (tb
->s_end
- tb
->s_begin
== tb
->used
) || tb
->graphic
) {
517 tPtr
->currentTextBlock
= tb
;
518 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
519 tb
= tPtr
->currentTextBlock
;
524 } else if (tb
->s_end
<= tb
->used
) {
525 memmove(&(tb
->text
[tb
->s_begin
]),
526 &(tb
->text
[tb
->s_end
]), tb
->used
- tb
->s_end
);
527 tb
->used
-= (tb
->s_end
- tb
->s_begin
);
528 tb
->selected
= False
;
529 tPtr
->tpos
= tb
->s_begin
;
540 getFirstNonGraphicBlockFor(TextBlock
*tb
, short dir
)
542 TextBlock
*hold
= tb
;
550 tb
= (dir
? tb
->next
: tb
->prior
);
558 tb
= (dir
? tb
->prior
: tb
->next
);
569 updateStartForCurrentTextBlock(Text
*tPtr
, int x
, int y
, int *dir
,
572 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
573 tb
= getFirstNonGraphicBlockFor(tb
, *dir
);
575 tPtr
->currentTextBlock
=
576 (dir
? tPtr
->lastTextBlock
: tPtr
->firstTextBlock
);
582 *dir
= !(y
<= tb
->sections
[0].y
);
584 if ( ( y
<= tb
->sections
[0]._y
+ tb
->sections
[0].h
)
585 && (y
>= tb
->sections
[0]._y
) ) {
586 /* if it's on the same line */
587 if(x
< tb
->sections
[0].x
)
591 if ( ( y
<= tb
->sections
[tb
->nsections
-1]._y
592 + tb
->sections
[tb
->nsections
-1].h
)
593 && (y
>= tb
->sections
[tb
->nsections
-1]._y
) ) {
594 /* if it's on the same line */
595 if(x
> tb
->sections
[tb
->nsections
-1].x
)
605 paintText(Text
*tPtr
)
611 int len
, y
, c
, s
, done
=False
, prev_y
=-23, dir
/* 1 = down */;
612 WMScreen
*scr
= tPtr
->view
->screen
;
613 Display
*dpy
= tPtr
->view
->screen
->display
;
614 Window win
= tPtr
->view
->window
;
616 if (!tPtr
->view
->flags
.realized
|| !tPtr
->db
|| tPtr
->flags
.frozen
)
619 XFillRectangle(dpy
, tPtr
->db
, tPtr
->bgGC
,
620 0, 0, tPtr
->visible
.w
, tPtr
->visible
.h
);
622 if (! (tb
= tPtr
->currentTextBlock
)) {
623 if (! (tb
= tPtr
->firstTextBlock
)) {
628 if (tPtr
->flags
.ownsSelection
)
629 greyGC
= WMColorGC(WMGrayColor(scr
));
635 /* first, which direction? Don't waste time looking all over,
636 since the parts to be drawn will most likely be near what
637 was previously drawn */
638 if(!updateStartForCurrentTextBlock(tPtr
, 0, tPtr
->vpos
, &dir
, tb
))
643 if (tb
->graphic
&& tPtr
->flags
.monoFont
)
647 if(tPtr
->vpos
<= tb
->sections
[tb
->nsections
-1]._y
648 + tb
->sections
[tb
->nsections
-1].h
)
651 if(tPtr
->vpos
>= tb
->sections
[tb
->nsections
-1]._y
652 + tb
->sections
[tb
->nsections
-1].h
)
669 /* first, place all text that can be viewed */
670 while (!done
&& tb
) {
672 /* paragraph diagnostic
673 if(tb->blank) {tb->text[0] = 'F'; } */
680 tb
->selected
= False
;
682 for(s
=0; s
<tb
->nsections
&& !done
; s
++) {
684 if (tb
->sections
[s
]._y
> tPtr
->vpos
+ tPtr
->visible
.h
) {
689 if ( tb
->sections
[s
].y
+ tb
->sections
[s
].h
< tPtr
->vpos
)
692 if (tPtr
->flags
.monoFont
) {
697 gc
= WMColorGC(tb
->color
);
700 if (tPtr
->flags
.ownsSelection
) {
703 if ( sectionWasSelected(tPtr
, tb
, &rect
, s
)) {
705 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
706 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
710 prev_y
= tb
->sections
[s
]._y
;
712 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
713 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
714 y
= tb
->sections
[s
].y
- tPtr
->vpos
;
715 WMDrawString(scr
, tPtr
->db
, gc
, font
,
716 tb
->sections
[s
].x
- tPtr
->hpos
, y
, text
, len
);
718 if (!tPtr
->flags
.monoFont
&& tb
->underlined
) {
719 XDrawLine(dpy
, tPtr
->db
, gc
,
720 tb
->sections
[s
].x
- tPtr
->hpos
,
722 tb
->sections
[s
].x
+ tb
->sections
[s
].w
- tPtr
->hpos
,
728 tb
= (!done
? tb
->next
: NULL
);
732 /* now , show all graphic items that can be viewed */
733 c
= WMGetArrayItemCount(tPtr
->gfxItems
);
734 if (c
> 0 && !tPtr
->flags
.monoFont
) {
738 tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
);
740 /* if it's not viewable, and mapped, unmap it */
741 if (tb
->sections
[0]._y
+ tb
->sections
[0].h
<= tPtr
->vpos
742 || tb
->sections
[0]._y
>= tPtr
->vpos
+ tPtr
->visible
.h
) {
745 if ((W_VIEW(tb
->d
.widget
))->flags
.mapped
) {
746 WMUnmapWidget(tb
->d
.widget
);
750 /* if it's viewable, and not mapped, map it */
752 W_View
*view
= W_VIEW(tb
->d
.widget
);
754 if (!view
->flags
.realized
)
755 WMRealizeWidget(tb
->d
.widget
);
756 if(!view
->flags
.mapped
) {
757 XMapWindow(view
->screen
->display
, view
->window
);
758 XFlush(view
->screen
->display
);
759 view
->flags
.mapped
= 1;
763 if (tPtr
->flags
.ownsSelection
) {
766 if ( sectionWasSelected(tPtr
, tb
, &rect
, 0)) {
768 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
769 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
774 WMMoveWidget(tb
->d
.widget
,
775 tb
->sections
[0].x
+ tPtr
->visible
.x
- tPtr
->hpos
,
776 tb
->sections
[0].y
+ tPtr
->visible
.y
- tPtr
->vpos
);
777 h
= WMWidgetHeight(tb
->d
.widget
) + 1;
780 WMDrawPixmap(tb
->d
.pixmap
, tPtr
->db
,
781 tb
->sections
[0].x
- tPtr
->hpos
,
782 tb
->sections
[0].y
- tPtr
->vpos
);
783 h
= tb
->d
.pixmap
->height
+ 1;
787 if (!tPtr
->flags
.monoFont
&& tb
->underlined
) {
788 XDrawLine(dpy
, tPtr
->db
, WMColorGC(tb
->color
),
789 tb
->sections
[0].x
- tPtr
->hpos
,
790 tb
->sections
[0].y
+ h
- tPtr
->vpos
,
791 tb
->sections
[0].x
+ tb
->sections
[0].w
- tPtr
->hpos
,
792 tb
->sections
[0].y
+ h
- tPtr
->vpos
);
797 if (tPtr
->flags
.editable
&& tPtr
->flags
.cursorShown
798 && tPtr
->cursor
.x
!= -23 && tPtr
->flags
.focused
) {
799 int y
= tPtr
->cursor
.y
- tPtr
->vpos
;
800 XDrawLine(dpy
, tPtr
->db
, tPtr
->fgGC
,
802 tPtr
->cursor
.x
, y
+ tPtr
->cursor
.h
);
805 XCopyArea(dpy
, tPtr
->db
, win
, tPtr
->bgGC
, 0, 0,
806 tPtr
->visible
.w
, tPtr
->visible
.h
,
807 tPtr
->visible
.x
, tPtr
->visible
.y
);
809 W_DrawRelief(scr
, win
, 0, 0,
810 tPtr
->view
->size
.width
, tPtr
->view
->size
.height
,
813 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)
814 XDrawLine(dpy
, win
, tPtr
->fgGC
,
815 2, 42, tPtr
->view
->size
.width
-4, 42);
820 mouseOverObject(Text
*tPtr
, int x
, int y
)
825 x
-= tPtr
->visible
.x
;
827 y
-= tPtr
->visible
.y
;
830 if(tPtr
->flags
.ownsSelection
) {
833 && tPtr
->sel
.x
+ tPtr
->sel
.w
>= x
834 && tPtr
->sel
.y
+ tPtr
->sel
.h
>= y
) {
835 tPtr
->flags
.isOverGraphic
= 1;
842 int j
, c
= WMGetArrayItemCount(tPtr
->gfxItems
);
845 tPtr
->flags
.isOverGraphic
= 0;
849 tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
);
851 if(!tb
|| !tb
->sections
) {
852 tPtr
->flags
.isOverGraphic
= 0;
857 if(tb
->sections
[0].x
<= x
858 && tb
->sections
[0].y
<= y
859 && tb
->sections
[0].x
+ tb
->sections
[0].w
>= x
860 && tb
->sections
[0].y
+ tb
->d
.pixmap
->height
>= y
) {
861 tPtr
->flags
.isOverGraphic
= 3;
872 tPtr
->flags
.isOverGraphic
= 0;
875 tPtr
->view
->attribs
.cursor
= (result
?
876 tPtr
->view
->screen
->defaultCursor
877 : tPtr
->view
->screen
->textCursor
);
879 XSetWindowAttributes attribs
;
880 attribs
.cursor
= tPtr
->view
->attribs
.cursor
;
881 XChangeWindowAttributes(tPtr
->view
->screen
->display
,
882 tPtr
->view
->window
, CWCursor
,
890 blinkCursor(void *data
)
892 Text
*tPtr
= (Text
*)data
;
894 if (tPtr
->flags
.cursorShown
) {
895 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY
,
898 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
,
902 tPtr
->flags
.cursorShown
= !tPtr
->flags
.cursorShown
;
907 updateCursorPosition(Text
*tPtr
)
909 TextBlock
*tb
= NULL
;
912 if(tPtr
->flags
.needsLayOut
)
913 layOutDocument(tPtr
);
915 if (! (tb
= tPtr
->currentTextBlock
)) {
916 if (! (tb
= tPtr
->firstTextBlock
)) {
918 tPtr
->cursor
.h
= tPtr
->dFont
->height
;
928 y
= tb
->sections
[0].y
;
929 h
= tb
->sections
[0].h
;
930 x
= tb
->sections
[0].x
;
932 } else if(tb
->graphic
) {
933 y
= tb
->sections
[0].y
;
934 h
= tb
->sections
[0].h
;
935 x
= tb
->sections
[0].x
;
938 if(tPtr
->tpos
> tb
->used
)
939 tPtr
->tpos
= tb
->used
;
941 for(s
=0; s
<tb
->nsections
-1; s
++) {
943 if(tPtr
->tpos
>= tb
->sections
[s
].begin
944 && tPtr
->tpos
<= tb
->sections
[s
].end
)
948 y
= tb
->sections
[s
]._y
;
949 h
= tb
->sections
[s
].h
;
950 x
= tb
->sections
[s
].x
+ WMWidthOfString(
951 (tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
),
952 &tb
->text
[tb
->sections
[s
].begin
],
953 tPtr
->tpos
- tb
->sections
[s
].begin
);
961 /* scroll the bars if the cursor is not visible */
962 if(tPtr
->flags
.editable
&& tPtr
->cursor
.x
!= -23) {
963 if(tPtr
->cursor
.y
+tPtr
->cursor
.h
964 > tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
) {
966 (tPtr
->cursor
.y
+tPtr
->cursor
.h
+10
967 - (tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
));
968 } else if(tPtr
->cursor
.y
< tPtr
->vpos
+tPtr
->visible
.y
) {
969 tPtr
->vpos
-= (tPtr
->vpos
+tPtr
->visible
.y
-tPtr
->cursor
.y
);
974 updateScrollers(tPtr
);
979 cursorToTextPosition(Text
*tPtr
, int x
, int y
)
981 TextBlock
*tb
= NULL
;
982 int done
=False
, s
, pos
, len
, _w
, _y
, dir
=1; /* 1 == "down" */
985 if(tPtr
->flags
.needsLayOut
)
986 layOutDocument(tPtr
);
988 y
+= (tPtr
->vpos
- tPtr
->visible
.y
);
992 x
-= (tPtr
->visible
.x
- 2);
996 /* clicked is relative to document, not window... */
1000 if (! (tb
= tPtr
->currentTextBlock
)) {
1001 if (! (tb
= tPtr
->firstTextBlock
)) {
1003 tPtr
->cursor
.h
= tPtr
->dFont
->height
;
1010 /* first, which direction? Most likely, newly clicked
1011 position will be close to previous */
1012 if(!updateStartForCurrentTextBlock(tPtr
, x
, y
, &dir
, tb
))
1016 s
= (dir
? 0 : tb
->nsections
-1);
1017 if ( y
>= tb
->sections
[s
]._y
1018 && y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) {
1022 /* get the first (or last) section of the TextBlock that
1023 lies about the vertical click point */
1025 while (!done
&& tb
) {
1027 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1028 if( (dir
?tb
->next
:tb
->prior
))
1029 tb
= (dir
?tb
->next
:tb
->prior
);
1033 s
= (dir
? 0 : tb
->nsections
-1);
1034 while (!done
&& (dir
? (s
<tb
->nsections
) : (s
>=0) )) {
1036 if ( (dir
? (y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) :
1037 ( y
>= tb
->sections
[s
]._y
) ) ) {
1045 if ( (dir
? tb
->next
: tb
->prior
)) {
1046 tb
= (dir
? tb
->next
: tb
->prior
);
1049 break; /* goto _doneH; */
1055 if (s
<0 || s
>=tb
->nsections
) {
1056 s
= (dir
? tb
->nsections
-1 : 0);
1060 /* we have the line, which TextBlock on that line is it? */
1061 pos
= (dir
?0:tb
->sections
[s
].begin
);
1062 if (tPtr
->flags
.monoFont
&& tb
->graphic
)
1063 tb
= getFirstNonGraphicBlockFor(tb
, dir
);
1068 _y
= tb
->sections
[s
]._y
;
1072 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1073 tb
= (dir
? tb
->next
: tb
->prior
);
1080 _w
= WMWidgetWidth(tb
->d
.widget
)-5;
1082 _w
= tb
->d
.pixmap
->width
-5;
1084 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
1085 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
1086 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
1087 if (tb
->sections
[s
].x
+ _w
>= x
)
1092 if (tb
->sections
[s
].x
<= x
)
1096 if ((dir
? tb
->next
: tb
->prior
)) {
1097 TextBlock
*nxt
= (dir
? tb
->next
: tb
->prior
);
1098 if (tPtr
->flags
.monoFont
&& nxt
->graphic
) {
1099 nxt
= getFirstNonGraphicBlockFor(nxt
, dir
);
1101 pos
= (dir
?0:tb
->sections
[s
].begin
);
1102 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
1107 if (_y
!= nxt
->sections
[dir
?0:nxt
->nsections
-1]._y
) {
1108 /* this must be the last/first on this line. stop */
1109 pos
= (dir
? tb
->sections
[s
].end
: 0);
1110 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
1114 tPtr
->cursor
.x
+= WMWidgetWidth(tb
->d
.widget
);
1116 tPtr
->cursor
.x
+= tb
->d
.pixmap
->width
;
1117 } else if (pos
> tb
->sections
[s
].begin
) {
1119 WMWidthOfString(tb
->d
.font
,
1120 &(tb
->text
[tb
->sections
[s
].begin
]),
1121 pos
- tb
->sections
[s
].begin
);
1128 if ( (dir
? tb
->next
: tb
->prior
)) {
1129 tb
= (dir
? tb
->next
: tb
->prior
);
1136 s
= (dir
? 0 : tb
->nsections
-1);
1139 /* we have said TextBlock, now where within it? */
1140 if (tb
&& !tb
->graphic
) {
1141 WMFont
*f
= tb
->d
.font
;
1142 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
1143 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
1145 _w
= x
- tb
->sections
[s
].x
;
1148 while (pos
<len
&& WMWidthOfString(f
, text
, pos
+1) < _w
)
1151 tPtr
->cursor
.x
= tb
->sections
[s
].x
+
1152 (pos
? WMWidthOfString(f
, text
, pos
) : 0);
1154 pos
+= tb
->sections
[s
].begin
;
1156 tPtr
->tpos
= (pos
<tb
->used
)? pos
: tb
->used
;
1160 printf("...for this app will surely crash :-)\n");
1162 tPtr
->currentTextBlock
= tb
;
1163 tPtr
->cursor
.h
= tb
->sections
[s
].h
;
1164 tPtr
->cursor
.y
= tb
->sections
[s
]._y
;
1166 /* scroll the bars if the cursor is not visible */
1167 if(tPtr
->flags
.editable
&& tPtr
->cursor
.x
!= -23) {
1168 if(tPtr
->cursor
.y
+tPtr
->cursor
.h
1169 > tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
) {
1171 (tPtr
->cursor
.y
+tPtr
->cursor
.h
+10
1172 - (tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
));
1173 updateScrollers(tPtr
);
1174 } else if(tPtr
->cursor
.y
< tPtr
->vpos
+tPtr
->visible
.y
) {
1175 tPtr
->vpos
-= (tPtr
->vpos
+tPtr
->visible
.y
-tPtr
->cursor
.y
);
1176 updateScrollers(tPtr
);
1184 autoSelectText(Text
*tPtr
, int clicks
)
1188 char *mark
= NULL
, behind
, ahead
;
1190 if(!(tb
= tPtr
->currentTextBlock
))
1196 switch(tb
->text
[tPtr
->tpos
]) {
1199 case '<': case '>': behind = '<'; ahead = '>'; break;
1200 case '{': case '}': behind = '{'; ahead = '}'; break;
1201 case '[': case ']': behind = '['; ahead = ']'; break;
1203 default: behind
= ahead
= ' ';
1206 tPtr
->sel
.y
= tPtr
->cursor
.y
+5;
1207 tPtr
->sel
.h
= 6;/*tPtr->cursor.h-10;*/
1210 tPtr
->sel
.x
= tb
->sections
[0].x
;
1211 tPtr
->sel
.w
= tb
->sections
[0].w
;
1213 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
1216 while(start
> 0 && tb
->text
[start
-1] != behind
)
1220 if(tPtr
->tpos
> start
){
1221 x
-= WMWidthOfString(font
, &tb
->text
[start
],
1222 tPtr
->tpos
- start
);
1224 tPtr
->sel
.x
= (x
<0?0:x
)+1;
1226 if((mark
= strchr(&tb
->text
[start
], ahead
))) {
1227 tPtr
->sel
.w
= WMWidthOfString(font
, &tb
->text
[start
],
1228 (int)(mark
- &tb
->text
[start
]));
1229 } else if(tb
->used
> start
) {
1230 tPtr
->sel
.w
= WMWidthOfString(font
, &tb
->text
[start
],
1235 } else if(clicks
== 3) {
1236 TextBlock
*cur
= tb
;
1238 while(tb
&& !tb
->first
) {
1241 tPtr
->sel
.y
= tb
->sections
[0]._y
;
1244 while(tb
->next
&& !tb
->next
->first
) {
1247 tPtr
->sel
.h
= tb
->sections
[tb
->nsections
-1]._y
1251 tPtr
->sel
.w
= tPtr
->docWidth
;
1252 tPtr
->clicked
.x
= 0; /* only for now, fix sel. code */
1255 tPtr
->flags
.ownsSelection
= True
;
1262 updateScrollers(Text
*tPtr
)
1265 if (tPtr
->flags
.frozen
)
1269 if (tPtr
->docHeight
< tPtr
->visible
.h
) {
1270 WMSetScrollerParameters(tPtr
->vS
, 0, 1);
1273 float hmax
= (float)(tPtr
->docHeight
);
1274 WMSetScrollerParameters(tPtr
->vS
,
1275 ((float)tPtr
->vpos
)/(hmax
- (float)tPtr
->visible
.h
),
1276 (float)tPtr
->visible
.h
/hmax
);
1278 } else tPtr
->vpos
= 0;
1281 if (tPtr
->docWidth
< tPtr
->visible
.w
) {
1282 WMSetScrollerParameters(tPtr
->hS
, 0, 1);
1285 float wmax
= (float)(tPtr
->docWidth
);
1286 WMSetScrollerParameters(tPtr
->hS
,
1287 ((float)tPtr
->hpos
)/(wmax
- (float)tPtr
->visible
.w
),
1288 (float)tPtr
->visible
.w
/wmax
);
1290 } else tPtr
->hpos
= 0;
1294 scrollersCallBack(WMWidget
*w
, void *self
)
1296 Text
*tPtr
= (Text
*)self
;
1297 Bool scroll
= False
;
1300 if (!tPtr
->view
->flags
.realized
|| tPtr
->flags
.frozen
)
1303 if (w
== tPtr
->vS
) {
1305 height
= tPtr
->visible
.h
;
1307 which
= WMGetScrollerHitPart(tPtr
->vS
);
1310 case WSDecrementLine
:
1311 if (tPtr
->vpos
> 0) {
1312 if (tPtr
->vpos
>16) tPtr
->vpos
-=16;
1318 case WSIncrementLine
: {
1319 int limit
= tPtr
->docHeight
- height
;
1320 if (tPtr
->vpos
< limit
) {
1321 if (tPtr
->vpos
<limit
-16) tPtr
->vpos
+=16;
1322 else tPtr
->vpos
=limit
;
1328 case WSDecrementPage
:
1329 if(((int)tPtr
->vpos
- (int)height
) >= 0)
1330 tPtr
->vpos
-= height
;
1337 case WSIncrementPage
:
1338 tPtr
->vpos
+= height
;
1339 if (tPtr
->vpos
> (tPtr
->docHeight
- height
))
1340 tPtr
->vpos
= tPtr
->docHeight
- height
;
1346 tPtr
->vpos
= WMGetScrollerValue(tPtr
->vS
)
1347 * (float)(tPtr
->docHeight
- height
);
1355 scroll
= (tPtr
->vpos
!= tPtr
->prevVpos
);
1356 tPtr
->prevVpos
= tPtr
->vpos
;
1360 if (w
== tPtr
->hS
) {
1361 int width
= tPtr
->visible
.w
;
1363 which
= WMGetScrollerHitPart(tPtr
->hS
);
1366 case WSDecrementLine
:
1367 if (tPtr
->hpos
> 0) {
1368 if (tPtr
->hpos
>16) tPtr
->hpos
-=16;
1373 case WSIncrementLine
: {
1374 int limit
= tPtr
->docWidth
- width
;
1375 if (tPtr
->hpos
< limit
) {
1376 if (tPtr
->hpos
<limit
-16) tPtr
->hpos
+=16;
1377 else tPtr
->hpos
=limit
;
1381 case WSDecrementPage
:
1382 if(((int)tPtr
->hpos
- (int)width
) >= 0)
1383 tPtr
->hpos
-= width
;
1390 case WSIncrementPage
:
1391 tPtr
->hpos
+= width
;
1392 if (tPtr
->hpos
> (tPtr
->docWidth
- width
))
1393 tPtr
->hpos
= tPtr
->docWidth
- width
;
1399 tPtr
->hpos
= WMGetScrollerValue(tPtr
->hS
)
1400 * (float)(tPtr
->docWidth
- width
);
1408 scroll
= (tPtr
->hpos
!= tPtr
->prevHpos
);
1409 tPtr
->prevHpos
= tPtr
->hpos
;
1413 updateScrollers(tPtr
);
1422 unsigned short begin
, end
; /* what part of the text block */
1427 layOutLine(Text
*tPtr
, myLineItems
*items
, int nitems
, int x
, int y
)
1429 int i
, j
=0, lw
= 0, line_height
=0, max_d
=0, len
, n
;
1432 TextBlock
*tb
, *tbsame
=NULL
;
1434 if(!items
|| nitems
== 0)
1437 for(i
=0; i
<nitems
; i
++) {
1441 if (!tPtr
->flags
.monoFont
) {
1443 WMWidget
*wdt
= tb
->d
.widget
;
1444 line_height
= WMAX(line_height
, WMWidgetHeight(wdt
));
1445 if (tPtr
->flags
.alignment
!= WALeft
)
1446 lw
+= WMWidgetWidth(wdt
);
1448 line_height
= WMAX(line_height
,
1449 tb
->d
.pixmap
->height
+ max_d
);
1450 if (tPtr
->flags
.alignment
!= WALeft
)
1451 lw
+= tb
->d
.pixmap
->width
;
1456 font
= (tPtr
->flags
.monoFont
)?tPtr
->dFont
: tb
->d
.font
;
1457 max_d
= WMAX(max_d
, abs(font
->height
-font
->y
));
1458 line_height
= WMAX(line_height
, font
->height
+ max_d
);
1459 text
= &(tb
->text
[items
[i
].begin
]);
1460 len
= items
[i
].end
- items
[i
].begin
;
1461 if (tPtr
->flags
.alignment
!= WALeft
)
1462 lw
+= WMWidthOfString(font
, text
, len
);
1466 if (tPtr
->flags
.alignment
== WARight
) {
1467 j
= tPtr
->visible
.w
- lw
;
1468 } else if (tPtr
->flags
.alignment
== WACenter
) {
1469 j
= (int) ((float)(tPtr
->visible
.w
- lw
))/2.0;
1472 for(i
=0; i
<nitems
; i
++) {
1475 if (tbsame
== tb
) { /* extend it, since it's on same line */
1476 tb
->sections
[tb
->nsections
-1].end
= items
[i
].end
;
1477 n
= tb
->nsections
-1;
1479 tb
->sections
= wrealloc(tb
->sections
,
1480 (++tb
->nsections
)*sizeof(Section
));
1481 n
= tb
->nsections
-1;
1482 tb
->sections
[n
]._y
= y
+ max_d
;
1483 tb
->sections
[n
].max_d
= max_d
;
1484 tb
->sections
[n
].x
= x
+j
;
1485 tb
->sections
[n
].h
= line_height
;
1486 tb
->sections
[n
].begin
= items
[i
].begin
;
1487 tb
->sections
[n
].end
= items
[i
].end
;
1490 tb
->sections
[n
].last
= (i
+1 == nitems
);
1493 if (!tPtr
->flags
.monoFont
) {
1495 WMWidget
*wdt
= tb
->d
.widget
;
1496 tb
->sections
[n
].y
= max_d
+ y
1497 + line_height
- WMWidgetHeight(wdt
);
1498 tb
->sections
[n
].w
= WMWidgetWidth(wdt
);
1500 tb
->sections
[n
].y
= y
+ line_height
1501 + max_d
- tb
->d
.pixmap
->height
;
1502 tb
->sections
[n
].w
= tb
->d
.pixmap
->width
;
1504 x
+= tb
->sections
[n
].w
;
1507 font
= (tPtr
->flags
.monoFont
)? tPtr
->dFont
: tb
->d
.font
;
1508 len
= items
[i
].end
- items
[i
].begin
;
1509 text
= &(tb
->text
[items
[i
].begin
]);
1511 tb
->sections
[n
].y
= y
+line_height
-font
->y
;
1513 WMWidthOfString(font
,
1514 &(tb
->text
[tb
->sections
[n
].begin
]),
1515 tb
->sections
[n
].end
- tb
->sections
[n
].begin
);
1517 x
+= WMWidthOfString(font
, text
, len
);
1529 layOutDocument(Text
*tPtr
)
1532 myLineItems
*items
= NULL
;
1533 unsigned int itemsSize
=0, nitems
=0, begin
, end
;
1535 unsigned int x
, y
=0, lw
= 0, width
=0, bmargin
;
1536 char *start
=NULL
, *mark
=NULL
;
1538 if ( tPtr
->flags
.frozen
|| (!(tb
= tPtr
->firstTextBlock
)) )
1541 tPtr
->docWidth
= tPtr
->visible
.w
;
1542 x
= tPtr
->margins
[tb
->marginN
].first
;
1543 bmargin
= tPtr
->margins
[tb
->marginN
].body
;
1545 /* only partial layOut needed: re-Lay only affected textblocks */
1546 if (tPtr
->flags
.laidOut
) {
1547 tb
= tPtr
->currentTextBlock
;
1549 /* search backwards for textblocks on same line */
1551 if (!tb
->sections
|| tb
->nsections
<1) {
1552 tb
= tPtr
->firstTextBlock
;
1553 tPtr
->flags
.laidOut
= False
;
1558 if(!tb
->prior
->sections
|| tb
->prior
->nsections
<1) {
1559 tb
= tPtr
->firstTextBlock
;
1560 tPtr
->flags
.laidOut
= False
;
1565 if (tb
->sections
[0]._y
!=
1566 tb
->prior
->sections
[tb
->prior
->nsections
-1]._y
) {
1572 if(tb
->prior
&& tb
->prior
->sections
&& tb
->prior
->nsections
>0) {
1573 y
= tb
->prior
->sections
[tb
->prior
->nsections
-1]._y
+
1574 tb
->prior
->sections
[tb
->prior
->nsections
-1].h
-
1575 tb
->prior
->sections
[tb
->prior
->nsections
-1].max_d
;
1584 if (tb
->sections
&& tb
->nsections
>0) {
1585 wfree(tb
->sections
);
1586 tb
->sections
= NULL
;
1590 if (tb
->blank
&& tb
->next
&& !tb
->next
->first
) {
1591 TextBlock
*next
= tb
->next
;
1592 tPtr
->currentTextBlock
= tb
;
1593 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1599 if (tb
->first
&& tb
!= tPtr
->firstTextBlock
) {
1600 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1601 x
= tPtr
->margins
[tb
->marginN
].first
;
1602 bmargin
= tPtr
->margins
[tb
->marginN
].body
;
1608 if (!tPtr
->flags
.monoFont
) {
1610 width
= WMWidgetWidth(tb
->d
.widget
);
1612 width
= tb
->d
.pixmap
->width
;
1614 if (width
> tPtr
->docWidth
)
1615 tPtr
->docWidth
= width
;
1618 if (lw
>= tPtr
->visible
.w
- x
) {
1619 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1625 if(nitems
+ 1> itemsSize
) {
1626 items
= wrealloc(items
,
1627 (++itemsSize
)*sizeof(myLineItems
));
1630 items
[nitems
].tb
= tb
;
1631 items
[nitems
].begin
= 0;
1632 items
[nitems
].end
= 0;
1636 } else if ((start
= tb
->text
)) {
1638 font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
1641 mark
= strchr(start
, ' ');
1643 end
+= (int)(mark
-start
)+1;
1646 end
+= strlen(start
);
1653 if (end
-begin
> 0) {
1655 width
= WMWidthOfString(font
,
1656 &tb
->text
[begin
], end
-begin
);
1658 /* if it won't fit, break it up */
1659 if (width
> tPtr
->visible
.w
) {
1660 char *t
= &tb
->text
[begin
];
1661 int l
=end
-begin
, i
=0;
1663 width
= WMWidthOfString(font
, t
, ++i
);
1664 } while (width
< tPtr
->visible
.w
&& i
< l
);
1673 if (lw
>= tPtr
->visible
.w
- x
) {
1674 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1680 if(nitems
+ 1 > itemsSize
) {
1681 items
= wrealloc(items
,
1682 (++itemsSize
)*sizeof(myLineItems
));
1685 items
[nitems
].tb
= tb
;
1686 items
[nitems
].begin
= begin
;
1687 items
[nitems
].end
= end
;
1695 /* not yet fully ready. but is already VERY FAST for a 3Mbyte file ;-) */
1696 if(0&&tPtr
->flags
.laidOut
1697 && tb
->next
&& tb
->next
->sections
&& tb
->next
->nsections
>0
1698 && (tPtr
->vpos
+ tPtr
->visible
.h
1699 < tb
->next
->sections
[0]._y
)) {
1700 if(tPtr
->lastTextBlock
->sections
1701 && tPtr
->lastTextBlock
->nsections
> 0 ) {
1702 TextBlock
*ltb
= tPtr
->lastTextBlock
;
1703 int ly
= ltb
->sections
[ltb
->nsections
-1]._y
;
1704 int lh
= ltb
->sections
[ltb
->nsections
-1].h
;
1707 lh
+= 1 + tPtr
->visible
.y
+ ltb
->sections
[ltb
->nsections
-1].max_d
;
1708 printf("it's %d\n", tPtr
->visible
.y
+ ltb
->sections
[ltb
->nsections
-1].max_d
);
1710 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1712 sd
= tPtr
->docHeight
-y
;
1714 printf("dif %d-%d: %d\n", ss
, sd
, ss
-sd
);
1715 y
+= tb
->next
->sections
[0]._y
-y
;
1717 printf("nitems%d\n", nitems
);
1719 y
= tPtr
->docHeight
+ss
-sd
;
1723 tPtr
->flags
.laidOut
= False
;
1732 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1734 if (tPtr
->docHeight
!= y
+10) {
1735 tPtr
->docHeight
= y
+10;
1736 updateScrollers(tPtr
);
1739 if(tPtr
->docWidth
> tPtr
->visible
.w
&& !tPtr
->hS
) {
1742 tPtr
->flags
.horizOnDemand
= True
;
1743 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, True
);
1744 event
.type
= Expose
;
1745 handleEvents(&event
, (void *)tPtr
);
1747 } else if(tPtr
->docWidth
<= tPtr
->visible
.w
1748 && tPtr
->hS
&& tPtr
->flags
.horizOnDemand
) {
1749 tPtr
->flags
.horizOnDemand
= False
;
1750 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, False
);
1753 tPtr
->flags
.laidOut
= True
;
1755 if(items
&& itemsSize
> 0)
1761 textDidResize(W_ViewDelegate
*self
, WMView
*view
)
1763 Text
*tPtr
= (Text
*)view
->self
;
1764 unsigned short w
= tPtr
->view
->size
.width
;
1765 unsigned short h
= tPtr
->view
->size
.height
;
1766 unsigned short rh
= 0, vw
= 0, rel
;
1768 rel
= (tPtr
->flags
.relief
== WRFlat
);
1770 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
) {
1771 WMMoveWidget(tPtr
->ruler
, 2, 2);
1772 WMResizeWidget(tPtr
->ruler
, w
- 4, 40);
1777 WMMoveWidget(tPtr
->vS
, 1 - (rel
?1:0), rh
+ 1 - (rel
?1:0));
1778 WMResizeWidget(tPtr
->vS
, 20, h
- rh
- 2 + (rel
?2:0));
1780 WMSetRulerOffset(tPtr
->ruler
,22);
1781 } else WMSetRulerOffset(tPtr
->ruler
, 2);
1785 WMMoveWidget(tPtr
->hS
, vw
, h
- 21);
1786 WMResizeWidget(tPtr
->hS
, w
- vw
- 1, 20);
1788 WMMoveWidget(tPtr
->hS
, vw
+1, h
- 21);
1789 WMResizeWidget(tPtr
->hS
, w
- vw
- 2, 20);
1793 tPtr
->visible
.x
= (tPtr
->vS
)?24:4;
1794 tPtr
->visible
.y
= (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)?43:3;
1795 tPtr
->visible
.w
= tPtr
->view
->size
.width
- tPtr
->visible
.x
- 8;
1796 tPtr
->visible
.h
= tPtr
->view
->size
.height
- tPtr
->visible
.y
;
1797 tPtr
->visible
.h
-= (tPtr
->hS
)?20:0;
1798 tPtr
->margins
[0].right
= tPtr
->visible
.w
;
1800 if (tPtr
->view
->flags
.realized
) {
1803 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
1804 tPtr
->db
= (Pixmap
) NULL
;
1807 if (tPtr
->visible
.w
< 40)
1808 tPtr
->visible
.w
= 40;
1809 if (tPtr
->visible
.h
< 20)
1810 tPtr
->visible
.h
= 20;
1813 tPtr
->db
= XCreatePixmap(tPtr
->view
->screen
->display
,
1814 tPtr
->view
->window
, tPtr
->visible
.w
,
1815 tPtr
->visible
.h
, tPtr
->view
->screen
->depth
);
1822 W_ViewDelegate _TextViewDelegate
=
1830 /* nice, divisble-by-16 blocks */
1831 static inline unsigned short
1832 reqBlockSize(unsigned short requested
)
1834 return requested
+ 16 - (requested
%16);
1839 clearText(Text
*tPtr
)
1841 tPtr
->vpos
= tPtr
->hpos
= 0;
1842 tPtr
->docHeight
= tPtr
->docWidth
= 0;
1844 if (!tPtr
->firstTextBlock
)
1847 while (tPtr
->currentTextBlock
)
1848 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1850 tPtr
->firstTextBlock
= NULL
;
1851 tPtr
->currentTextBlock
= NULL
;
1852 tPtr
->lastTextBlock
= NULL
;
1853 WMEmptyArray(tPtr
->gfxItems
);
1857 deleteTextInteractively(Text
*tPtr
, KeySym ksym
)
1860 Bool back
= (Bool
) (ksym
== XK_BackSpace
);
1864 if (!tPtr
->flags
.editable
) {
1865 XBell(tPtr
->view
->screen
->display
, 0);
1869 if ( !(tb
= tPtr
->currentTextBlock
) )
1872 if (tPtr
->flags
.ownsSelection
) {
1873 if(removeSelection(tPtr
))
1874 layOutDocument(tPtr
);
1878 wasFirst
= tb
->first
;
1879 if (back
&& tPtr
->tpos
< 1) {
1881 if(tb
->prior
->blank
) {
1882 tPtr
->currentTextBlock
= tb
->prior
;
1883 WMRemoveTextBlock(tPtr
);
1884 tPtr
->currentTextBlock
= tb
;
1886 layOutDocument(tPtr
);
1890 TextBlock
*prior
= tb
->prior
;
1891 tPtr
->currentTextBlock
= tb
;
1892 WMRemoveTextBlock(tPtr
);
1898 tPtr
->tpos
= tb
->used
;
1899 tPtr
->currentTextBlock
= tb
;
1903 tb
->next
->first
= False
;
1904 layOutDocument(tPtr
);
1911 if ( (tb
->used
> 0) && ((back
?tPtr
->tpos
> 0:1))
1912 && (tPtr
->tpos
<= tb
->used
) && !tb
->graphic
) {
1915 memmove(&(tb
->text
[tPtr
->tpos
]),
1916 &(tb
->text
[tPtr
->tpos
+ 1]), tb
->used
- tPtr
->tpos
);
1921 if ( (back
? (tPtr
->tpos
< 1 && !done
) : ( tPtr
->tpos
>= tb
->used
))
1924 TextBlock
*sibling
= (back
? tb
->prior
: tb
->next
);
1926 if(tb
->used
== 0 || tb
->graphic
)
1927 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1930 tPtr
->currentTextBlock
= sibling
;
1931 tPtr
->tpos
= (back
? sibling
->used
: 0);
1935 layOutDocument(tPtr
);
1940 insertTextInteractively(Text
*tPtr
, char *text
, int len
)
1943 char *newline
= NULL
;
1945 if (!tPtr
->flags
.editable
) {
1946 XBell(tPtr
->view
->screen
->display
, 0);
1950 if (len
< 1 || !text
)
1954 if(tPtr
->flags
.ignoreNewLine
&& *text
== '\n' && len
== 1)
1958 if (tPtr
->flags
.ownsSelection
)
1959 removeSelection(tPtr
);
1962 if (tPtr
->flags
.ignoreNewLine
) {
1964 for(i
=0; i
<len
; i
++) {
1965 if (text
[i
] == '\n')
1970 tb
= tPtr
->currentTextBlock
;
1971 if (!tb
|| tb
->graphic
) {
1973 WMAppendTextStream(tPtr
, text
);
1974 layOutDocument(tPtr
);
1978 if ((newline
= strchr(text
, '\n'))) {
1979 int nlen
= (int)(newline
-text
);
1980 int s
= tb
->used
- tPtr
->tpos
;
1982 if (!tb
->blank
&& nlen
>0) {
1984 memcpy(save
, &tb
->text
[tPtr
->tpos
], s
);
1985 tb
->used
-= (tb
->used
- tPtr
->tpos
);
1987 insertTextInteractively(tPtr
, text
, nlen
);
1989 WMAppendTextStream(tPtr
, newline
);
1991 insertTextInteractively(tPtr
, save
, s
);
1994 if (tPtr
->tpos
>0 && tPtr
->tpos
< tb
->used
1995 && !tb
->graphic
&& tb
->text
) {
1997 void *ntb
= WMCreateTextBlockWithText(
1998 tPtr
, &tb
->text
[tPtr
->tpos
],
1999 tb
->d
.font
, tb
->color
, True
, tb
->used
- tPtr
->tpos
);
2000 tb
->used
= tPtr
->tpos
;
2001 WMAppendTextBlock(tPtr
, ntb
);
2004 } else if (tPtr
->tpos
== tb
->used
|| tPtr
->tpos
== 0) {
2005 if(tPtr
->flags
.indentNewLine
) {
2006 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
2007 " ", tb
->d
.font
, tb
->color
, True
, 4));
2010 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
2011 NULL
, tb
->d
.font
, tb
->color
, True
, 0));
2018 if (tb
->used
+ len
>= tb
->allocated
) {
2019 tb
->allocated
= reqBlockSize(tb
->used
+len
);
2020 tb
->text
= wrealloc(tb
->text
, tb
->allocated
);
2024 memcpy(tb
->text
, text
, len
);
2027 tb
->text
[tb
->used
] = 0;
2031 memmove(&(tb
->text
[tPtr
->tpos
+len
]), &tb
->text
[tPtr
->tpos
],
2032 tb
->used
-tPtr
->tpos
+1);
2033 memmove(&tb
->text
[tPtr
->tpos
], text
, len
);
2036 tb
->text
[tb
->used
] = 0;
2041 layOutDocument(tPtr
);
2046 selectRegion(Text
*tPtr
, int x
, int y
)
2052 y
+= (tPtr
->flags
.rulerShown
? 40: 0);
2055 y
-= 10; /* the original offset */
2057 x
-= tPtr
->visible
.x
-2;
2061 tPtr
->sel
.x
= WMAX(0, WMIN(tPtr
->clicked
.x
, x
));
2062 tPtr
->sel
.w
= abs(tPtr
->clicked
.x
- x
);
2063 tPtr
->sel
.y
= WMAX(0, WMIN(tPtr
->clicked
.y
, y
));
2064 tPtr
->sel
.h
= abs(tPtr
->clicked
.y
- y
);
2066 tPtr
->flags
.ownsSelection
= True
;
2072 releaseSelection(Text
*tPtr
)
2074 TextBlock
*tb
= tPtr
->firstTextBlock
;
2077 tb
->selected
= False
;
2080 tPtr
->flags
.ownsSelection
= False
;
2081 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
,
2089 requestHandler(WMView
*view
, Atom selection
, Atom target
, void *cdata
,
2092 Text
*tPtr
= view
->self
;
2093 Display
*dpy
= tPtr
->view
->screen
->display
;
2095 Atom TEXT
= XInternAtom(dpy
, "TEXT", False
);
2096 Atom COMPOUND_TEXT
= XInternAtom(dpy
, "COMPOUND_TEXT", False
);
2097 WMData
*data
= NULL
;
2100 if (target
== XA_STRING
|| target
== TEXT
|| target
== COMPOUND_TEXT
) {
2101 char *text
= WMGetTextSelectedStream(tPtr
);
2104 printf("got text [%s]\n", text
);
2105 data
= WMCreateDataWithBytes(text
, strlen(text
));
2106 WMSetDataFormat(data
, TYPETEXT
);
2110 } else printf("didn't get it\n");
2112 _TARGETS
= XInternAtom(dpy
, "TARGETS", False
);
2113 if (target
== _TARGETS
) {
2116 ptr
= wmalloc(4 * sizeof(Atom
));
2120 ptr
[3] = COMPOUND_TEXT
;
2122 data
= WMCreateDataWithBytes(ptr
, 4*4);
2123 WMSetDataFormat(data
, 32);
2133 lostHandler(WMView
*view
, Atom selection
, void *cdata
)
2135 releaseSelection((WMText
*)view
->self
);
2138 static WMSelectionProcs selectionHandler
= {
2139 requestHandler
, lostHandler
, NULL
2144 ownershipObserver(void *observerData
, WMNotification
*notification
)
2146 if (observerData
!= WMGetNotificationClientData(notification
))
2147 lostHandler(WMWidgetView(observerData
), XA_PRIMARY
, NULL
);
2152 fontChanged(void *observerData
, WMNotification
*notification
)
2154 WMText
*tPtr
= (WMText
*) observerData
;
2155 WMFont
*font
= (WMFont
*)WMGetNotificationClientData(notification
);
2156 printf("fontChanged\n");
2161 if (tPtr
->flags
.ownsSelection
)
2162 WMSetTextSelectionFont(tPtr
, font
);
2167 handleTextKeyPress(Text
*tPtr
, XEvent
*event
)
2171 int control_pressed
= False
;
2172 TextBlock
*tb
= NULL
;
2174 if (((XKeyEvent
*) event
)->state
& ControlMask
)
2175 control_pressed
= True
;
2176 buffer
[XLookupString(&event
->xkey
, buffer
, 1, &ksym
, NULL
)] = 0;
2181 if(!(tb
= tPtr
->currentTextBlock
))
2187 L_imaGFX
: if(tb
->prior
) {
2188 tPtr
->currentTextBlock
= tb
->prior
;
2189 tPtr
->tpos
= tPtr
->currentTextBlock
->used
-1;
2190 } else tPtr
->tpos
= 0;
2191 } else tPtr
->tpos
--;
2192 updateCursorPosition(tPtr
);
2197 if(!(tb
= tPtr
->currentTextBlock
))
2201 if(tPtr
->tpos
== tb
->used
) {
2202 R_imaGFX
: if(tb
->next
) {
2203 tPtr
->currentTextBlock
= tb
->next
;
2205 } else tPtr
->tpos
= tb
->used
;
2206 } else tPtr
->tpos
++;
2207 updateCursorPosition(tPtr
);
2212 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
2213 tPtr
->clicked
.y
+ tPtr
->cursor
.h
- tPtr
->vpos
);
2218 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
2219 tPtr
->visible
.y
+ tPtr
->cursor
.y
- tPtr
->vpos
- 3);
2226 deleteTextInteractively(tPtr
, ksym
);
2227 updateCursorPosition(tPtr
);
2233 control_pressed
= True
;
2237 insertTextInteractively(tPtr
, " ", 4);
2238 updateCursorPosition(tPtr
);
2245 if (buffer
[0] != 0 && !control_pressed
) {
2246 insertTextInteractively(tPtr
, buffer
, 1);
2247 updateCursorPosition(tPtr
);
2250 } else if (control_pressed
&& ksym
==XK_r
) {
2251 Bool i
= !tPtr
->flags
.rulerShown
;
2252 WMShowTextRuler(tPtr
, i
);
2253 tPtr
->flags
.rulerShown
= i
;
2255 else if (control_pressed
&& buffer
[0] == '\a')
2256 XBell(tPtr
->view
->screen
->display
, 0);
2259 if (!control_pressed
&& tPtr
->flags
.ownsSelection
)
2260 releaseSelection(tPtr
);
2264 handleWidgetPress(XEvent
*event
, void *data
)
2266 TextBlock
*tb
= (TextBlock
*)data
;
2274 tPtr
->currentTextBlock
= tb
;
2275 tPtr
->flags
.isOverGraphic
= 2;
2277 output(tb
->text
, tb
->used
);
2279 if (!tPtr
->flags
.focused
) {
2280 WMSetFocusToWidget(tPtr
);
2281 tPtr
->flags
.focused
= True
;
2288 handleActionEvents(XEvent
*event
, void *data
)
2290 Text
*tPtr
= (Text
*)data
;
2291 Display
*dpy
= event
->xany
.display
;
2295 switch (event
->type
) {
2297 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2298 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2299 tPtr
->flags
.extendSelection
= True
;
2303 if (tPtr
->flags
.focused
) {
2304 XGrabPointer(dpy
, W_VIEW(tPtr
)->window
, False
,
2305 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
2306 GrabModeAsync
, GrabModeAsync
, None
,
2307 tPtr
->view
->screen
->invisibleCursor
, CurrentTime
);
2308 tPtr
->flags
.pointerGrabbed
= True
;
2309 handleTextKeyPress(tPtr
, event
);
2314 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2315 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2316 tPtr
->flags
.extendSelection
= False
;
2318 /* end modify flag so selection can be extended */
2325 if (tPtr
->flags
.pointerGrabbed
) {
2326 tPtr
->flags
.pointerGrabbed
= False
;
2327 XUngrabPointer(dpy
, CurrentTime
);
2330 if(tPtr
->flags
.waitingForSelection
)
2333 if ((event
->xmotion
.state
& Button1Mask
)) {
2334 if (!tPtr
->flags
.ownsSelection
) {
2335 WMCreateSelectionHandler(tPtr
->view
,
2336 XA_PRIMARY
, event
->xbutton
.time
,
2337 &selectionHandler
, NULL
);
2338 tPtr
->flags
.ownsSelection
= True
;
2340 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2344 mouseOverObject(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2350 if (tPtr
->flags
.pointerGrabbed
) {
2351 tPtr
->flags
.pointerGrabbed
= False
;
2352 XUngrabPointer(dpy
, CurrentTime
);
2356 if (tPtr
->flags
.waitingForSelection
)
2359 if (tPtr
->flags
.extendSelection
) {
2360 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2365 if (event
->xbutton
.button
== Button1
) {
2367 if(WMIsDoubleClick(event
)) {
2368 TextBlock
*tb
= tPtr
->currentTextBlock
;
2370 if(tb
&& tb
->graphic
&& !tb
->object
) {
2371 char desc
[tb
->used
+1];
2372 memcpy(desc
, tb
->text
, tb
->used
);
2374 if(tPtr
->delegate
) {
2375 if(tPtr
->delegate
->didDoubleClickOnPicture
)
2376 (*tPtr
->delegate
->didDoubleClickOnPicture
)
2377 (tPtr
->delegate
, desc
);
2380 autoSelectText(tPtr
, 2);
2382 tPtr
->lastClickTime
= event
->xbutton
.time
;
2384 } else if(event
->xbutton
.time
- tPtr
->lastClickTime
2385 < WINGsConfiguration
.doubleClickDelay
) {
2386 autoSelectText(tPtr
, 3);
2390 if (!tPtr
->flags
.focused
) {
2391 WMSetFocusToWidget(tPtr
);
2392 tPtr
->flags
.focused
= True
;
2395 if (tPtr
->flags
.ownsSelection
)
2396 releaseSelection(tPtr
);
2398 tPtr
->lastClickTime
= event
->xbutton
.time
;
2399 cursorToTextPosition(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2403 if (event
->xbutton
.button
2404 == WINGsConfiguration
.mouseWheelDown
) {
2405 WMScrollText(tPtr
, 16);
2409 if (event
->xbutton
.button
2410 == WINGsConfiguration
.mouseWheelUp
) {
2411 WMScrollText(tPtr
, -16);
2415 if (event
->xbutton
.button
== Button2
) {
2419 if (!tPtr
->flags
.editable
) {
2425 if (!WMRequestSelection(tPtr
->view
, XA_PRIMARY
, XA_STRING
,
2426 event
->xbutton
.time
, pasteText
, NULL
)) {
2430 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
2436 (tPtr
->parser
) (tPtr
, (void *) text
);
2438 insertTextInteractively(tPtr
, text
, n
);
2442 NOTIFY(tPtr
, didChange
, WMTextDidChangeNotification
,
2443 (void*)WMInsertTextEvent
);
2447 tPtr
->flags
.waitingForSelection
= True
;
2456 if (tPtr
->flags
.pointerGrabbed
) {
2457 tPtr
->flags
.pointerGrabbed
= False
;
2458 XUngrabPointer(dpy
, CurrentTime
);
2462 if (tPtr
->flags
.waitingForSelection
)
2470 handleEvents(XEvent
*event
, void *data
)
2472 Text
*tPtr
= (Text
*)data
;
2474 switch(event
->type
) {
2477 if (event
->xexpose
.count
!=0)
2481 if (!(W_VIEW(tPtr
->hS
))->flags
.realized
)
2482 WMRealizeWidget(tPtr
->hS
);
2486 if (!(W_VIEW(tPtr
->vS
))->flags
.realized
)
2487 WMRealizeWidget(tPtr
->vS
);
2491 if (!(W_VIEW(tPtr
->ruler
))->flags
.realized
)
2492 WMRealizeWidget(tPtr
->ruler
);
2497 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2503 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))
2506 tPtr
->flags
.focused
= True
;
2508 if (tPtr
->flags
.editable
&& !tPtr
->timerID
) {
2509 tPtr
->timerID
= WMAddTimerHandler(12+0*CURSOR_BLINK_ON_DELAY
,
2517 tPtr
->flags
.focused
= False
;
2520 if (tPtr
->timerID
) {
2521 WMDeleteTimerHandler(tPtr
->timerID
);
2522 tPtr
->timerID
= NULL
;
2531 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
2533 WMEmptyArray(tPtr
->gfxItems
);
2536 WMDeleteTimerHandler(tPtr
->timerID
);
2538 WMReleaseFont(tPtr
->dFont
);
2539 WMReleaseColor(tPtr
->dColor
);
2540 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
, CurrentTime
);
2541 WMRemoveNotificationObserver(tPtr
);
2552 insertPlainText(Text
*tPtr
, char *text
)
2559 mark
= strchr(start
, '\n');
2561 tb
= WMCreateTextBlockWithText(tPtr
,
2563 tPtr
->dColor
, tPtr
->flags
.first
, (int)(mark
-start
));
2565 tPtr
->flags
.first
= True
;
2567 if (start
&& strlen(start
)) {
2568 tb
= WMCreateTextBlockWithText(tPtr
, start
, tPtr
->dFont
,
2569 tPtr
->dColor
, tPtr
->flags
.first
, strlen(start
));
2571 tPtr
->flags
.first
= False
;
2575 if (tPtr
->flags
.prepend
)
2576 WMPrependTextBlock(tPtr
, tb
);
2578 WMAppendTextBlock(tPtr
, tb
);
2586 rulerMoveCallBack(WMWidget
*w
, void *self
)
2588 Text
*tPtr
= (Text
*)self
;
2591 if (W_CLASS(tPtr
) != WC_Text
)
2599 rulerReleaseCallBack(WMWidget
*w
, void *self
)
2601 Text
*tPtr
= (Text
*)self
;
2604 if (W_CLASS(tPtr
) != WC_Text
)
2613 draggingEntered(WMView
*self
, WMDraggingInfo
*info
)
2615 printf("draggingEntered\n");
2616 return WDOperationCopy
;
2621 draggingUpdated(WMView
*self
, WMDraggingInfo
*info
)
2623 return WDOperationCopy
;
2628 draggingExited(WMView
*self
, WMDraggingInfo
*info
)
2630 printf("draggingExited\n");
2634 prepareForDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2636 printf("prepareForDragOperation\n");
2644 receivedData(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
2645 void *cdata
, WMData
*data
)
2647 badbadbad
= wstrdup((char *)WMDataBytes(data
));
2651 /* when it's done in WINGs, remove this */
2653 Bool
requestDroppedData(WMView
*view
, WMDraggingInfo
*info
, char *type
)
2655 WMScreen
*scr
= W_VIEW_SCREEN(view
);
2657 if (!WMRequestSelection(scr
->dragInfo
.destView
,
2658 scr
->xdndSelectionAtom
,
2659 XInternAtom(scr
->display
, type
, False
),
2660 scr
->dragInfo
.timestamp
,
2661 receivedData
, &scr
->dragInfo
)) {
2662 wwarning("could not request data for dropped data");
2669 ev
.type
= ClientMessage
;
2670 ev
.xclient
.message_type
= scr
->xdndFinishedAtom
;
2671 ev
.xclient
.format
= 32;
2672 ev
.xclient
.window
= info
->destinationWindow
;
2673 ev
.xclient
.data
.l
[0] = 0;
2674 ev
.xclient
.data
.l
[1] = 0;
2675 ev
.xclient
.data
.l
[2] = 0;
2676 ev
.xclient
.data
.l
[3] = 0;
2677 ev
.xclient
.data
.l
[4] = 0;
2679 XSendEvent(scr
->display
, info
->sourceWindow
, False
, 0, &ev
);
2680 XFlush(scr
->display
);
2686 performDragOperation(WMView
*self
, WMDraggingInfo
*info
, WMData
*data
)
2689 WMText
*tPtr
= (WMText
*)self
->self
;
2694 requestDroppedData(tPtr
->view
, info
, "application/X-color");
2695 color
= WMCreateNamedColor(W_VIEW_SCREEN(self
), badbadbad
, True
);
2697 WMSetTextSelectionColor(tPtr
, color
);
2698 WMReleaseColor(color
);
2707 concludeDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2709 printf("concludeDragOperation\n");
2713 static WMDragDestinationProcs _DragDestinationProcs
= {
2717 prepareForDragOperation
,
2718 performDragOperation
,
2719 concludeDragOperation
2724 getStream(WMText
*tPtr
, int sel
, int array
)
2726 TextBlock
*tb
= NULL
;
2728 unsigned long where
= 0;
2733 if (!(tb
= tPtr
->firstTextBlock
))
2737 (tPtr
->writer
) (tPtr
, (void *) text
);
2741 tb
= tPtr
->firstTextBlock
;
2744 if (!tb
->graphic
|| (tb
->graphic
&& !tPtr
->flags
.monoFont
)) {
2746 if (!sel
|| (tb
->graphic
&& tb
->selected
)) {
2748 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
)
2749 && tb
!= tPtr
->firstTextBlock
) {
2750 text
= wrealloc(text
, where
+1);
2751 text
[where
++] = '\n';
2757 if(tb
->graphic
&& array
) {
2758 text
= wrealloc(text
, where
+4);
2759 text
[where
++] = 0xFA;
2760 text
[where
++] = (tb
->used
>>8)&0x0ff;
2761 text
[where
++] = tb
->used
&0x0ff;
2762 text
[where
++] = tb
->allocated
; /* extra info */
2764 text
= wrealloc(text
, where
+tb
->used
);
2765 memcpy(&text
[where
], tb
->text
, tb
->used
);
2769 } else if (sel
&& tb
->selected
) {
2771 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
)
2772 && tb
!= tPtr
->firstTextBlock
) {
2773 text
= wrealloc(text
, where
+1);
2774 text
[where
++] = '\n';
2780 text
= wrealloc(text
, where
+(tb
->s_end
- tb
->s_begin
));
2781 memcpy(&text
[where
], &tb
->text
[tb
->s_begin
],
2782 tb
->s_end
- tb
->s_begin
);
2783 where
+= tb
->s_end
- tb
->s_begin
;
2788 _gSnext
:tb
= tb
->next
;
2791 /* +1 for the end of string, let's be nice */
2792 text
= wrealloc(text
, where
+1);
2799 releaseStreamObjects(void *data
)
2806 getStreamObjects(WMText
*tPtr
, int sel
)
2808 WMArray
*array
= WMCreateArrayWithDestructor(4, releaseStreamObjects
);
2812 char *start
, *fa
, *desc
;
2814 stream
= getStream(tPtr
, sel
, 1);
2821 fa
= strchr(start
, 0xFA);
2823 if((int)(fa
- start
)>0) {
2825 desc
[(int)(fa
- start
)] = 0;
2826 data
= WMCreateDataWithBytes((void *)desc
, (int)(fa
- start
));
2827 WMSetDataFormat(data
, TYPETEXT
);
2828 WMAddToArray(array
, (void *) data
);
2831 len
= *(fa
+1)*0xff + *(fa
+2);
2832 data
= WMCreateDataWithBytes((void *)(fa
+4), len
);
2833 WMSetDataFormat(data
, *(fa
+3));
2834 WMAddToArray(array
, (void *) data
);
2835 start
= fa
+ len
+ 4;
2838 if (start
&& strlen(start
)) {
2839 data
= WMCreateDataWithBytes((void *)start
, strlen(start
));
2840 WMSetDataFormat(data
, TYPETEXT
);
2841 WMAddToArray(array
, (void *) data
);
2854 WMCreateTextForDocumentType(WMWidget
*parent
,
2855 WMAction
*parser
, WMAction
*writer
)
2857 Text
*tPtr
= wmalloc(sizeof(Text
));
2859 printf("could not create text widget\n");
2864 memset(tPtr
, 0, sizeof(Text
));
2865 tPtr
->widgetClass
= WC_Text
;
2866 tPtr
->view
= W_CreateView(W_VIEW(parent
));
2868 perror("could not create text's view\n");
2872 tPtr
->view
->self
= tPtr
;
2873 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->textCursor
;
2874 tPtr
->view
->attribFlags
|= CWOverrideRedirect
| CWCursor
;
2875 W_ResizeView(tPtr
->view
, 250, 200);
2877 tPtr
->dColor
= WMWhiteColor(tPtr
->view
->screen
);
2878 tPtr
->bgGC
= WMColorGC(tPtr
->dColor
);
2879 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->dColor
);
2880 WMReleaseColor(tPtr
->dColor
);
2882 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
2883 tPtr
->fgGC
= WMColorGC(tPtr
->dColor
);
2889 tPtr
->dFont
= WMRetainFont(WMSystemFontOfSize(tPtr
->view
->screen
, 12));
2891 tPtr
->view
->delegate
= &_TextViewDelegate
;
2893 tPtr
->delegate
= NULL
;
2896 tPtr
->timerID
= NULL
;
2899 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
2900 |EnterWindowMask
|LeaveWindowMask
|FocusChangeMask
,
2901 handleEvents
, tPtr
);
2903 WMCreateEventHandler(tPtr
->view
, ButtonReleaseMask
|ButtonPressMask
2904 |KeyReleaseMask
|KeyPressMask
|Button1MotionMask
,
2905 handleActionEvents
, tPtr
);
2907 WMAddNotificationObserver(ownershipObserver
, tPtr
,
2908 "_lostOwnership", tPtr
);
2911 char *types
[2] = {"application/X-color", NULL
};
2912 WMSetViewDragDestinationProcs(tPtr
->view
, &_DragDestinationProcs
);
2913 WMRegisterViewForDraggedTypes(tPtr
->view
, types
);
2916 WMAddNotificationObserver(fontChanged
, tPtr
,
2917 "WMFontPanelDidChangeNotification", tPtr
);
2919 tPtr
->firstTextBlock
= NULL
;
2920 tPtr
->lastTextBlock
= NULL
;
2921 tPtr
->currentTextBlock
= NULL
;
2924 tPtr
->gfxItems
= WMCreateArray(4);
2926 tPtr
->parser
= parser
;
2927 tPtr
->writer
= writer
;
2929 tPtr
->sel
.x
= tPtr
->sel
.y
= 2;
2930 tPtr
->sel
.w
= tPtr
->sel
.h
= 0;
2932 tPtr
->clicked
.x
= tPtr
->clicked
.y
= 2;
2934 tPtr
->visible
.x
= tPtr
->visible
.y
= 2;
2935 tPtr
->visible
.h
= tPtr
->view
->size
.height
;
2936 tPtr
->visible
.w
= tPtr
->view
->size
.width
- 4;
2938 tPtr
->cursor
.x
= -23;
2941 tPtr
->docHeight
= 0;
2942 tPtr
->dBulletPix
= WMCreatePixmapFromXPMData(tPtr
->view
->screen
,
2944 tPtr
->db
= (Pixmap
) NULL
;
2946 tPtr
->margins
= WMGetRulerMargins(NULL
);
2947 tPtr
->margins
->right
= tPtr
->visible
.w
;
2950 tPtr
->flags
.rulerShown
= False
;
2951 tPtr
->flags
.monoFont
= False
;
2952 tPtr
->flags
.focused
= False
;
2953 tPtr
->flags
.editable
= True
;
2954 tPtr
->flags
.ownsSelection
= False
;
2955 tPtr
->flags
.pointerGrabbed
= False
;
2956 tPtr
->flags
.extendSelection
= False
;
2957 tPtr
->flags
.frozen
= False
;
2958 tPtr
->flags
.cursorShown
= True
;
2959 tPtr
->flags
.acceptsGraphic
= False
;
2960 tPtr
->flags
.horizOnDemand
= False
;
2961 tPtr
->flags
.needsLayOut
= False
;
2962 tPtr
->flags
.ignoreNewLine
= False
;
2963 tPtr
->flags
.indentNewLine
= False
;
2964 tPtr
->flags
.laidOut
= False
;
2965 tPtr
->flags
.waitingForSelection
= False
;
2966 tPtr
->flags
.prepend
= False
;
2967 tPtr
->flags
.isOverGraphic
= False
;
2968 tPtr
->flags
.relief
= WRSunken
;
2969 tPtr
->flags
.isOverGraphic
= 0;
2970 tPtr
->flags
.alignment
= WALeft
;
2971 tPtr
->flags
.first
= True
;
2977 WMPrependTextStream(WMText
*tPtr
, char *text
)
2979 CHECK_CLASS(tPtr
, WC_Text
);
2982 if(tPtr
->flags
.ownsSelection
)
2983 releaseSelection(tPtr
);
2986 updateScrollers(tPtr
);
2991 tPtr
->flags
.prepend
= True
;
2992 if (text
&& tPtr
->parser
)
2993 (tPtr
->parser
) (tPtr
, (void *) text
);
2995 insertPlainText(tPtr
, text
);
2997 tPtr
->flags
.needsLayOut
= True
;
3003 WMAppendTextStream(WMText
*tPtr
, char *text
)
3005 CHECK_CLASS(tPtr
, WC_Text
);
3008 if(tPtr
->flags
.ownsSelection
)
3009 releaseSelection(tPtr
);
3012 updateScrollers(tPtr
);
3017 tPtr
->flags
.prepend
= False
;
3018 if (text
&& tPtr
->parser
)
3019 (tPtr
->parser
) (tPtr
, (void *) text
);
3021 insertPlainText(tPtr
, text
);
3023 tPtr
->flags
.needsLayOut
= True
;
3024 if(tPtr
->currentTextBlock
)
3025 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
3032 WMGetTextStream(WMText
*tPtr
)
3034 CHECK_CLASS(tPtr
, WC_Text
);
3035 return getStream(tPtr
, 0, 0);
3039 WMGetTextSelectedStream(WMText
*tPtr
)
3041 CHECK_CLASS(tPtr
, WC_Text
);
3042 return getStream(tPtr
, 1, 0);
3046 WMGetTextObjects(WMText
*tPtr
)
3048 CHECK_CLASS(tPtr
, WC_Text
);
3049 return getStreamObjects(tPtr
, 0);
3053 WMGetTextSelectedObjects(WMText
*tPtr
)
3055 CHECK_CLASS(tPtr
, WC_Text
);
3056 return getStreamObjects(tPtr
, 1);
3061 WMSetTextDelegate(WMText
*tPtr
, WMTextDelegate
*delegate
)
3063 CHECK_CLASS(tPtr
, WC_Text
);
3065 tPtr
->delegate
= delegate
;
3070 WMCreateTextBlockWithObject(WMText
*tPtr
, WMWidget
*w
,
3071 char *description
, WMColor
*color
,
3072 unsigned short first
, unsigned short extraInfo
)
3076 if (!w
|| !description
|| !color
)
3079 tb
= wmalloc(sizeof(TextBlock
));
3083 tb
->text
= wstrdup(description
);
3084 tb
->used
= strlen(description
);
3087 tb
->color
= WMRetainColor(color
);
3088 tb
->marginN
= newMargin(tPtr
, NULL
);
3089 tb
->allocated
= extraInfo
;
3094 tb
->underlined
= False
;
3095 tb
->selected
= False
;
3097 tb
->sections
= NULL
;
3107 WMCreateTextBlockWithPixmap(WMText
*tPtr
, WMPixmap
*p
,
3108 char *description
, WMColor
*color
,
3109 unsigned short first
, unsigned short extraInfo
)
3113 if (!p
|| !description
|| !color
)
3116 tb
= wmalloc(sizeof(TextBlock
));
3120 tb
->text
= wstrdup(description
);
3121 tb
->used
= strlen(description
);
3123 tb
->d
.pixmap
= WMRetainPixmap(p
);
3124 tb
->color
= WMRetainColor(color
);
3125 tb
->marginN
= newMargin(tPtr
, NULL
);
3126 tb
->allocated
= extraInfo
;
3131 tb
->underlined
= False
;
3132 tb
->selected
= False
;
3134 tb
->sections
= NULL
;
3143 WMCreateTextBlockWithText(WMText
*tPtr
, char *text
, WMFont
*font
, WMColor
*color
,
3144 unsigned short first
, unsigned short len
)
3148 if (!font
|| !color
)
3151 tb
= wmalloc(sizeof(TextBlock
));
3155 tb
->allocated
= reqBlockSize(len
);
3156 tb
->text
= (char *)wmalloc(tb
->allocated
);
3157 memset(tb
->text
, 0, tb
->allocated
);
3159 if (len
< 1|| !text
|| (*text
== '\n' && len
==1 )) {
3164 memcpy(tb
->text
, text
, len
);
3168 tb
->text
[tb
->used
] = 0;
3170 tb
->d
.font
= WMRetainFont(font
);
3171 tb
->color
= WMRetainColor(color
);
3172 tb
->marginN
= newMargin(tPtr
, NULL
);
3175 tb
->graphic
= False
;
3176 tb
->underlined
= False
;
3177 tb
->selected
= False
;
3179 tb
->sections
= NULL
;
3187 WMSetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int first
,
3188 unsigned int kanji
, unsigned int underlined
, int script
,
3189 WMRulerMargins
*margins
)
3191 TextBlock
*tb
= (TextBlock
*) vtb
;
3197 tb
->underlined
= underlined
;
3198 tb
->script
= script
;
3199 tb
->marginN
= newMargin(tPtr
, margins
);
3203 WMGetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int *first
,
3204 unsigned int *kanji
, unsigned int *underlined
, int *script
,
3205 WMRulerMargins
*margins
)
3207 TextBlock
*tb
= (TextBlock
*) vtb
;
3211 if (first
) *first
= tb
->first
;
3212 if (kanji
) *kanji
= tb
->kanji
;
3213 if (underlined
) *underlined
= tb
->underlined
;
3214 if (script
) *script
= tb
->script
;
3215 if (margins
) margins
= &tPtr
->margins
[tb
->marginN
];
3221 WMPrependTextBlock(WMText
*tPtr
, void *vtb
)
3223 TextBlock
*tb
= (TextBlock
*)vtb
;
3230 WMWidget
*w
= tb
->d
.widget
;
3231 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
3232 handleWidgetPress
, tb
);
3233 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
3234 (W_VIEW(w
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3235 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3238 WMAddToArray(tPtr
->gfxItems
, (void *)tb
);
3240 } else tPtr
->tpos
= tb
->used
;
3242 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
3243 tb
->next
= tb
->prior
= NULL
;
3245 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
3246 = tPtr
->currentTextBlock
= tb
;
3251 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
3254 tb
->next
= tPtr
->currentTextBlock
;
3255 tb
->prior
= tPtr
->currentTextBlock
->prior
;
3256 if (tPtr
->currentTextBlock
->prior
)
3257 tPtr
->currentTextBlock
->prior
->next
= tb
;
3259 tPtr
->currentTextBlock
->prior
= tb
;
3261 tPtr
->firstTextBlock
= tb
;
3263 tPtr
->currentTextBlock
= tb
;
3268 WMAppendTextBlock(WMText
*tPtr
, void *vtb
)
3270 TextBlock
*tb
= (TextBlock
*)vtb
;
3277 WMWidget
*w
= tb
->d
.widget
;
3278 WMCreateEventHandler(W_VIEW(w
), ButtonPressMask
,
3279 handleWidgetPress
, tb
);
3280 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
3281 (W_VIEW(w
))->attribs
.cursor
=
3282 tPtr
->view
->screen
->defaultCursor
;
3283 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3286 WMAddToArray(tPtr
->gfxItems
, (void *)tb
);
3288 } else tPtr
->tpos
= tb
->used
;
3290 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
3291 tb
->next
= tb
->prior
= NULL
;
3293 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
3294 = tPtr
->currentTextBlock
= tb
;
3299 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
3302 tb
->next
= tPtr
->currentTextBlock
->next
;
3303 tb
->prior
= tPtr
->currentTextBlock
;
3304 if (tPtr
->currentTextBlock
->next
)
3305 tPtr
->currentTextBlock
->next
->prior
= tb
;
3307 tPtr
->currentTextBlock
->next
= tb
;
3310 tPtr
->lastTextBlock
= tb
;
3312 tPtr
->currentTextBlock
= tb
;
3316 WMRemoveTextBlock(WMText
*tPtr
)
3318 TextBlock
*tb
= NULL
;
3320 if (!tPtr
|| !tPtr
->firstTextBlock
|| !tPtr
->lastTextBlock
3321 || !tPtr
->currentTextBlock
) {
3322 printf("cannot remove non existent TextBlock!\b");
3326 tb
= tPtr
->currentTextBlock
;
3328 WMRemoveFromArray(tPtr
->gfxItems
, (void *)tb
);
3331 WMDeleteEventHandler(W_VIEW(tb
->d
.widget
), ButtonPressMask
,
3332 handleWidgetPress
, tb
);
3333 WMUnmapWidget(tb
->d
.widget
);
3337 if (tPtr
->currentTextBlock
== tPtr
->firstTextBlock
) {
3338 if (tPtr
->currentTextBlock
->next
)
3339 tPtr
->currentTextBlock
->next
->prior
= NULL
;
3341 tPtr
->firstTextBlock
= tPtr
->currentTextBlock
->next
;
3342 tPtr
->currentTextBlock
= tPtr
->firstTextBlock
;
3344 } else if (tPtr
->currentTextBlock
== tPtr
->lastTextBlock
) {
3345 tPtr
->currentTextBlock
->prior
->next
= NULL
;
3346 tPtr
->lastTextBlock
= tPtr
->currentTextBlock
->prior
;
3347 tPtr
->currentTextBlock
= tPtr
->lastTextBlock
;
3349 tPtr
->currentTextBlock
->prior
->next
= tPtr
->currentTextBlock
->next
;
3350 tPtr
->currentTextBlock
->next
->prior
= tPtr
->currentTextBlock
->prior
;
3351 tPtr
->currentTextBlock
= tPtr
->currentTextBlock
->next
;
3358 WMDestroyTextBlock(WMText
*tPtr
, void *vtb
)
3360 TextBlock
*tb
= (TextBlock
*)vtb
;
3366 /* naturally, there's a danger to destroying
3367 widgets whose action brings us here:
3368 ie. press a button to destroy it... need to
3369 find a safer way. till then... this stays commented out */
3370 /* WMDestroyWidget(tb->d.widget);
3371 wfree(tb->d.widget); */
3372 tb
->d
.widget
= NULL
;
3374 WMReleasePixmap(tb
->d
.pixmap
);
3375 tb
->d
.pixmap
= NULL
;
3378 WMReleaseFont(tb
->d
.font
);
3381 WMReleaseColor(tb
->color
);
3382 if (tb
->sections
&& tb
->nsections
> 0)
3383 wfree(tb
->sections
);
3392 WMSetTextForegroundColor(WMText
*tPtr
, WMColor
*color
)
3398 tPtr
->fgGC
= WMColorGC(color
);
3400 tPtr
->fgGC
= WMColorGC(WMBlackColor(tPtr
->view
->screen
));
3406 WMSetTextBackgroundColor(WMText
*tPtr
, WMColor
*color
)
3412 tPtr
->bgGC
= WMColorGC(color
);
3413 W_SetViewBackgroundColor(tPtr
->view
, color
);
3415 tPtr
->bgGC
= WMColorGC(WMWhiteColor(tPtr
->view
->screen
));
3416 W_SetViewBackgroundColor(tPtr
->view
,
3417 WMWhiteColor(tPtr
->view
->screen
));
3424 WMSetTextRelief(WMText
*tPtr
, WMReliefType relief
)
3428 tPtr
->flags
.relief
= relief
;
3429 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3433 WMSetTextHasHorizontalScroller(WMText
*tPtr
, Bool shouldhave
)
3438 if (shouldhave
&& !tPtr
->hS
) {
3439 tPtr
->hS
= WMCreateScroller(tPtr
);
3440 (W_VIEW(tPtr
->hS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3441 (W_VIEW(tPtr
->hS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3442 WMSetScrollerArrowsPosition(tPtr
->hS
, WSAMinEnd
);
3443 WMSetScrollerAction(tPtr
->hS
, scrollersCallBack
, tPtr
);
3444 WMMapWidget(tPtr
->hS
);
3445 } else if (!shouldhave
&& tPtr
->hS
) {
3446 WMUnmapWidget(tPtr
->hS
);
3447 WMDestroyWidget(tPtr
->hS
);
3453 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3458 WMSetTextHasRuler(WMText
*tPtr
, Bool shouldhave
)
3463 if(shouldhave
&& !tPtr
->ruler
) {
3464 tPtr
->ruler
= WMCreateRuler(tPtr
);
3465 (W_VIEW(tPtr
->ruler
))->attribs
.cursor
=
3466 tPtr
->view
->screen
->defaultCursor
;
3467 (W_VIEW(tPtr
->ruler
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3468 WMSetRulerReleaseAction(tPtr
->ruler
, rulerReleaseCallBack
, tPtr
);
3469 WMSetRulerMoveAction(tPtr
->ruler
, rulerMoveCallBack
, tPtr
);
3470 } else if(!shouldhave
&& tPtr
->ruler
) {
3471 WMShowTextRuler(tPtr
, False
);
3472 WMDestroyWidget(tPtr
->ruler
);
3475 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3479 WMShowTextRuler(WMText
*tPtr
, Bool show
)
3486 if(tPtr
->flags
.monoFont
)
3489 tPtr
->flags
.rulerShown
= show
;
3491 WMMapWidget(tPtr
->ruler
);
3493 WMUnmapWidget(tPtr
->ruler
);
3496 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3500 WMGetTextRulerShown(WMText
*tPtr
)
3508 return tPtr
->flags
.rulerShown
;
3513 WMSetTextHasVerticalScroller(WMText
*tPtr
, Bool shouldhave
)
3518 if (shouldhave
&& !tPtr
->vS
) {
3519 tPtr
->vS
= WMCreateScroller(tPtr
);
3520 (W_VIEW(tPtr
->vS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3521 (W_VIEW(tPtr
->vS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3522 WMSetScrollerArrowsPosition(tPtr
->vS
, WSAMaxEnd
);
3523 WMSetScrollerAction(tPtr
->vS
, scrollersCallBack
, tPtr
);
3524 WMMapWidget(tPtr
->vS
);
3525 } else if (!shouldhave
&& tPtr
->vS
) {
3526 WMUnmapWidget(tPtr
->vS
);
3527 WMDestroyWidget(tPtr
->vS
);
3533 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3539 WMScrollText(WMText
*tPtr
, int amount
)
3544 if (amount
== 0 || !tPtr
->view
->flags
.realized
)
3548 if (tPtr
->vpos
> 0) {
3549 if (tPtr
->vpos
> abs(amount
)) tPtr
->vpos
+= amount
;
3553 int limit
= tPtr
->docHeight
- tPtr
->visible
.h
;
3554 if (tPtr
->vpos
< limit
) {
3555 if (tPtr
->vpos
< limit
-amount
) tPtr
->vpos
+= amount
;
3556 else tPtr
->vpos
= limit
;
3560 if (scroll
&& tPtr
->vpos
!= tPtr
->prevVpos
) {
3561 updateScrollers(tPtr
);
3564 tPtr
->prevVpos
= tPtr
->vpos
;
3569 WMPageText(WMText
*tPtr
, Bool direction
)
3571 if (!tPtr
) return False
;
3572 if (!tPtr
->view
->flags
.realized
) return False
;
3574 return WMScrollText(tPtr
, direction
?tPtr
->visible
.h
:-tPtr
->visible
.h
);
3578 WMSetTextEditable(WMText
*tPtr
, Bool editable
)
3582 tPtr
->flags
.editable
= editable
;
3586 WMGetTextEditable(WMText
*tPtr
)
3590 return tPtr
->flags
.editable
;
3594 WMSetTextIndentNewLines(WMText
*tPtr
, Bool indent
)
3598 tPtr
->flags
.indentNewLine
= indent
;
3602 WMSetTextIgnoresNewline(WMText
*tPtr
, Bool ignore
)
3606 // tPtr->flags.ignoreNewLine = ignore;
3610 WMGetTextIgnoresNewline(WMText
*tPtr
)
3614 return tPtr
->flags
.ignoreNewLine
;
3618 WMSetTextUsesMonoFont(WMText
*tPtr
, Bool mono
)
3624 if(tPtr
->flags
.rulerShown
)
3625 WMShowTextRuler(tPtr
, False
);
3626 if(tPtr
->flags
.alignment
!= WALeft
)
3627 tPtr
->flags
.alignment
= WALeft
;
3630 tPtr
->flags
.monoFont
= mono
;
3631 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3635 WMGetTextUsesMonoFont(WMText
*tPtr
)
3639 return tPtr
->flags
.monoFont
;
3644 WMSetTextDefaultFont(WMText
*tPtr
, WMFont
*font
)
3649 WMReleaseFont(tPtr
->dFont
);
3651 tPtr
->dFont
= WMRetainFont(font
);
3653 tPtr
->dFont
= WMRetainFont(WMSystemFontOfSize(tPtr
->view
->screen
, 12));
3657 WMGetTextDefaultFont(WMText
*tPtr
)
3662 return WMRetainFont(tPtr
->dFont
);
3666 WMSetTextDefaultColor(WMText
*tPtr
, WMColor
*color
)
3671 WMReleaseColor(tPtr
->dColor
);
3673 tPtr
->dColor
= WMRetainColor(color
);
3675 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
3679 WMGetTextDefaultColor(WMText
*tPtr
)
3684 return WMRetainColor(tPtr
->dColor
);
3688 WMSetTextAlignment(WMText
*tPtr
, WMAlignment alignment
)
3692 if(tPtr
->flags
.monoFont
)
3693 tPtr
->flags
.alignment
= WALeft
;
3695 tPtr
->flags
.alignment
= alignment
;
3700 WMGetTextInsertType(WMText
*tPtr
)
3704 return tPtr
->flags
.prepend
;
3709 WMSetTextSelectionColor(WMText
*tPtr
, WMColor
*color
)
3711 if (!tPtr
|| !color
)
3714 setSelectionProperty(tPtr
, NULL
, color
, -1);
3718 WMSetTextSelectionFont(WMText
*tPtr
, WMFont
*font
)
3723 setSelectionProperty(tPtr
, font
, NULL
, -1) ;
3727 WMSetTextSelectionUnderlined(WMText
*tPtr
, int underlined
)
3729 if (!tPtr
|| (underlined
!=0 && underlined
!=1))
3732 setSelectionProperty(tPtr
, NULL
, NULL
, underlined
);
3739 WMFreezeText(WMText
*tPtr
)
3744 tPtr
->flags
.frozen
= True
;
3749 WMThawText(WMText
*tPtr
)
3754 tPtr
->flags
.frozen
= False
;
3756 if(tPtr
->flags
.monoFont
) {
3757 int j
, c
= WMGetArrayItemCount(tPtr
->gfxItems
);
3760 /* make sure to unmap widgets no matter where they are */
3761 /* they'll be later remapped if needed by paintText */
3762 for(j
=0; j
<c
; j
++) {
3763 if ((tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
))) {
3764 if (tb
->object
&& ((W_VIEW(tb
->d
.widget
))->flags
.mapped
))
3765 WMUnmapWidget(tb
->d
.widget
);
3771 tPtr
->flags
.laidOut
= False
;
3772 layOutDocument(tPtr
);
3773 updateScrollers(tPtr
);
3775 tPtr
->flags
.needsLayOut
= False
;
3781 mystrrstr(char *haystack
, char *needle
, unsigned short len
, char *end
,
3786 if(!haystack
|| !needle
)
3789 for (ptr
= haystack
-2; ptr
> end
; ptr
--) {
3791 if (*ptr
== *needle
&& !strncmp(ptr
, needle
, len
))
3794 if (tolower(*ptr
) == tolower(*needle
) &&
3795 strncasecmp(ptr
, needle
, len
))
3805 WMFindInTextStream(WMText
*tPtr
, char *needle
, Bool direction
,
3812 if (!tPtr
|| !needle
)
3815 if (! (tb
= tPtr
->currentTextBlock
)) {
3816 if (! (tb
= ( (direction
> 0) ?
3817 tPtr
->firstTextBlock
: tPtr
->lastTextBlock
) ) ){
3821 /* if(tb != ((direction>0) ?tPtr->firstTextBlock : tPtr->lastTextBlock))
3822 tb = (direction>0) ? tb->next : tb->prior; */
3823 if(tb
!= tPtr
->lastTextBlock
)
3831 if(pos
+1 < tb
->used
)
3834 if(tb
->used
- pos
> 0 && pos
> 0) {
3835 char tmp
= tb
->text
[tb
->used
];
3836 tb
->text
[tb
->used
] = 0;
3838 output(&tb
->text
[pos
], tb
->used
- pos
);
3840 mark
= strstr(&tb
->text
[pos
], needle
);
3842 mark
= mystrrstr(&tb
->text
[pos
], needle
,
3843 strlen(needle
), tb
->text
, caseSensitive
);
3845 tb
->text
[tb
->used
] = tmp
;
3852 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
3854 tPtr
->tpos
= (int)(mark
- tb
->text
);
3855 tPtr
->currentTextBlock
= tb
;
3856 updateCursorPosition(tPtr
);
3857 tPtr
->sel
.y
= tPtr
->cursor
.y
+5;
3858 tPtr
->sel
.h
= tPtr
->cursor
.h
-10;
3859 tPtr
->sel
.x
= tPtr
->cursor
.x
+1;
3860 tPtr
->sel
.w
= WMIN(WMWidthOfString(font
,
3861 &tb
->text
[tPtr
->tpos
], strlen(needle
)),
3862 tPtr
->docWidth
- tPtr
->sel
.x
);
3863 tPtr
->flags
.ownsSelection
= True
;
3870 tb
= (direction
>0) ? tb
->next
: tb
->prior
;