2 /* WINGs WMText: multi-line/font/color/graphic text widget, by Nwanua. */
7 #include <X11/keysym.h>
13 * - selection code... selects can be funny if it crosses over. use rect?
14 * - also inspect behaviour for WACenter and WARight
15 * - what if a widget grabs the click... howto say: "pressed me"?
16 * note that WMCreateEventHandler takes one data, but need widget & tPtr
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 */
112 WMPixmap
*bgPixmap
; /* the background pixmap */
114 myRect visible
; /* the actual rectangle that can be drawn into */
115 myRect cursor
; /* the position and (height) of cursor */
116 myRect sel
; /* the selection rectangle */
118 WMPoint clicked
; /* where in the _document_ was clicked */
120 unsigned short tpos
; /* the position in the currentTextBlock */
121 unsigned short docWidth
; /* the width of the entire document */
122 unsigned int docHeight
; /* the height of the entire document */
124 TextBlock
*firstTextBlock
;
125 TextBlock
*lastTextBlock
;
126 TextBlock
*currentTextBlock
;
128 WMArray
*gfxItems
; /* a nice array of graphic items */
131 WMHandlerID timerID
; /* for nice twinky-winky */
136 WMTextDelegate
*delegate
;
139 WMRulerMargins
*margins
; /* an array of margins */
141 unsigned int nMargins
:7; /* the total number of margins in use */
143 unsigned int monoFont
:1; /* whether to ignore formats and graphic */
144 unsigned int focused
:1; /* whether this instance has input focus */
145 unsigned int editable
:1; /* "silly user, you can't edit me" */
146 unsigned int ownsSelection
:1; /* "I ownz the current selection!" */
147 unsigned int pointerGrabbed
:1;/* "heh, gib me pointer" */
148 unsigned int extendSelection
:1; /* shift-drag to select more regions */
150 unsigned int rulerShown
:1; /* whether the ruler is shown or not */
151 unsigned int frozen
:1; /* whether screen updates are to be made */
152 unsigned int cursorShown
:1; /* whether to show the cursor */
153 unsigned int acceptsGraphic
:1;/* accept graphic when dropped */
154 unsigned int horizOnDemand
:1;/* if a large image should appear*/
155 unsigned int needsLayOut
:1; /* in case of Append/Deletes */
156 unsigned int ignoreNewLine
:1;/* turn it into a ' ' in streams > 1 */
157 unsigned int indentNewLine
:1;/* add " " for a newline typed */
158 unsigned int laidOut
:1; /* have the TextBlocks all been laid out */
159 unsigned int waitingForSelection
:1; /* I don't wanna wait in vain... */
160 unsigned int prepend
:1; /* prepend=1, append=0 (for parsers) */
161 WMAlignment alignment
:2; /* the alignment for text */
162 WMReliefType relief
:3; /* the relief to display with */
163 unsigned int isOverGraphic
:2;/* the mouse is over a graphic */
164 unsigned int first
:1; /* for plain text parsing, newline? */
165 /* unsigned int RESERVED:1; */
170 #define NOTIFY(T,C,N,A) { WMNotification *notif = WMCreateNotification(N,T,A);\
171 if ((T)->delegate && (T)->delegate->C)\
172 (*(T)->delegate->C)((T)->delegate,notif);\
173 WMPostNotification(notif);\
174 WMReleaseNotification(notif);}
180 output(char *ptr
, int len
)
185 /* printf(" s is [%s] (%d)\n", s, strlen(s)); */
191 #define CURSOR_BLINK_ON_DELAY 600
192 #define CURSOR_BLINK_OFF_DELAY 400
195 static char *default_bullet
[] = {
197 " c None s None", ". c black",
198 "X c white", "o c #808080",
206 static void handleEvents(XEvent
*event
, void *data
);
207 static void layOutDocument(Text
*tPtr
);
208 static void updateScrollers(Text
*tPtr
);
212 getMarginNumber(Text
*tPtr
, WMRulerMargins
*margins
)
216 for(i
=0; i
< tPtr
->nMargins
; i
++) {
218 if(WMIsMarginEqualToMargin(&tPtr
->margins
[i
], margins
))
228 newMargin(Text
*tPtr
, WMRulerMargins
*margins
)
233 tPtr
->margins
[0].retainCount
++;
237 n
= getMarginNumber(tPtr
, margins
);
241 if(tPtr
->nMargins
>= 127) {
242 n
= tPtr
->nMargins
-1;
246 tPtr
->margins
= wrealloc(tPtr
->margins
,
247 (++tPtr
->nMargins
)*sizeof(WMRulerMargins
));
249 n
= tPtr
->nMargins
-1;
250 tPtr
->margins
[n
].left
= margins
->left
;
251 tPtr
->margins
[n
].first
= margins
->first
;
252 tPtr
->margins
[n
].body
= margins
->body
;
253 tPtr
->margins
[n
].right
= margins
->right
;
254 /* for each tab... */
255 tPtr
->margins
[n
].retainCount
= 1;
257 tPtr
->margins
[n
].retainCount
++;
264 sectionWasSelected(Text
*tPtr
, TextBlock
*tb
, XRectangle
*rect
, int s
)
266 unsigned short i
, w
, lw
, selected
= False
, extend
= False
;
270 /* if selection rectangle completely encloses the section */
271 if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
272 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
273 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
275 sel
.w
= tPtr
->visible
.w
;
276 selected
= extend
= True
;
278 /* or if it starts on a line and then goes further down */
279 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
280 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
281 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
282 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
283 >= tPtr
->visible
.y
+ tPtr
->sel
.y
) ) {
284 sel
.x
= WMAX(tPtr
->sel
.x
, tPtr
->clicked
.x
);
285 sel
.w
= tPtr
->visible
.w
;
286 selected
= extend
= True
;
288 /* or if it begins before a line, but ends on it */
289 } else if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
290 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
291 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
292 && (tb
->sections
[s
]._y
293 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
295 if (1||tPtr
->sel
.x
+ tPtr
->sel
.w
> tPtr
->clicked
.x
)
296 sel
.w
= tPtr
->sel
.x
+ tPtr
->sel
.w
;
303 /* or if the selection rectangle lies entirely within a line */
304 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
305 && (tPtr
->sel
.w
>= 2)
306 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
307 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
316 /* if not within (modified) selection rectangle */
317 if ( tb
->sections
[s
].x
> sel
.x
+ sel
.w
318 || tb
->sections
[s
].x
+ tb
->sections
[s
].w
< sel
.x
)
322 if ( tb
->sections
[s
].x
+ tb
->sections
[s
].w
<= sel
.x
+ sel
.w
323 && tb
->sections
[s
].x
>= sel
.x
) {
324 rect
->width
= tb
->sections
[s
].w
;
325 rect
->x
= tb
->sections
[s
].x
;
330 i
= tb
->sections
[s
].begin
;
333 if (0&& tb
->sections
[s
].x
>= sel
.x
) {
334 tb
->s_begin
= tb
->sections
[s
].begin
;
338 while (++i
<= tb
->sections
[s
].end
) {
340 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
343 if (lw
+ tb
->sections
[s
].x
>= sel
.x
344 || i
== tb
->sections
[s
].end
) {
347 tb
->s_begin
= (tb
->selected
? WMIN(tb
->s_begin
, i
) : i
);
352 if (i
> tb
->sections
[s
].end
) {
353 printf("WasSelected: (i > tb->sections[s].end) \n");
357 _selEnd
: rect
->x
= tb
->sections
[s
].x
+ lw
;
359 while(++i
<= tb
->sections
[s
].end
) {
361 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
364 if (lw
+ rect
->x
>= sel
.x
+ sel
.w
365 || i
== tb
->sections
[s
].end
) {
367 if (i
!= tb
->sections
[s
].end
) {
373 if (tb
->sections
[s
].last
&& sel
.x
+ sel
.w
374 >= tb
->sections
[s
].x
+ tb
->sections
[s
].w
376 rect
->width
+= (tPtr
->visible
.w
- rect
->x
- lw
);
379 tb
->s_end
= (tb
->selected
? WMAX(tb
->s_end
, i
) : i
);
385 rect
->y
= tb
->sections
[s
]._y
- tPtr
->vpos
;
386 rect
->height
= tb
->sections
[s
].h
;
387 if(tb
->graphic
) { printf("graphic s%d h%d\n", s
,tb
->sections
[s
].h
);}
394 setSelectionProperty(WMText
*tPtr
, WMFont
*font
, WMColor
*color
, int underlined
)
399 tb
= tPtr
->firstTextBlock
;
400 if (!tb
|| !tPtr
->flags
.ownsSelection
)
403 if(font
&& (!color
|| underlined
==-1))
407 if (tPtr
->flags
.monoFont
|| tb
->selected
) {
409 if (tPtr
->flags
.monoFont
|| (tb
->s_end
- tb
->s_begin
== tb
->used
)
414 WMReleaseFont(tb
->d
.font
);
415 tb
->d
.font
= WMRetainFont(font
);
417 } else if(underlined
!=-1) {
418 tb
->underlined
= underlined
;
420 WMReleaseColor(tb
->color
);
421 tb
->color
= WMRetainColor(color
);
424 } else if (tb
->s_end
<= tb
->used
&& tb
->s_begin
< tb
->s_end
) {
426 TextBlock
*midtb
, *otb
= tb
;
428 if(underlined
!= -1) {
429 midtb
= (TextBlock
*) WMCreateTextBlockWithText(tPtr
,
430 &(tb
->text
[tb
->s_begin
]), tb
->d
.font
, tb
->color
,
431 False
, (tb
->s_end
- tb
->s_begin
));
433 midtb
= (TextBlock
*) WMCreateTextBlockWithText(tPtr
,
434 &(tb
->text
[tb
->s_begin
]),
435 (isFont
?font
:tb
->d
.font
),
436 (isFont
?tb
->color
:color
),
437 False
, (tb
->s_end
- tb
->s_begin
));
442 if(underlined
!= -1) {
443 midtb
->underlined
= underlined
;
445 midtb
->underlined
= otb
->underlined
;
448 midtb
->selected
= !True
;
450 midtb
->s_end
= midtb
->used
;
451 tPtr
->currentTextBlock
= tb
;
452 WMAppendTextBlock(tPtr
, midtb
);
453 tb
= tPtr
->currentTextBlock
;
456 if (otb
->used
- otb
->s_end
> 0) {
459 WMCreateTextBlockWithText(tPtr
,
460 &(otb
->text
[otb
->s_end
]), otb
->d
.font
, otb
->color
,
461 False
, otb
->used
- otb
->s_end
);
464 ntb
->underlined
= otb
->underlined
;
465 ntb
->selected
= False
;
466 WMAppendTextBlock(tPtr
, ntb
);
467 tb
= tPtr
->currentTextBlock
;
472 tPtr
->currentTextBlock
= midtb
;
475 otb
->selected
= False
;
476 otb
->used
= otb
->s_begin
;
483 tPtr
->flags
.needsLayOut
= True
;
486 /* in case the size changed... */
487 if(isFont
&& tPtr
->currentTextBlock
) {
488 TextBlock
*tb
= tPtr
->currentTextBlock
;
490 printf("%d %d %d\n", tPtr
->sel
.y
, tPtr
->sel
.h
, tPtr
->sel
.w
);
491 tPtr
->sel
.y
= 3 + tb
->sections
[0]._y
;
492 tPtr
->sel
.h
= tb
->sections
[tb
->nsections
-1]._y
- tb
->sections
[0]._y
;
493 tPtr
->sel
.w
= tb
->sections
[tb
->nsections
-1].w
;
494 if(tb
->sections
[tb
->nsections
-1]._y
!= tb
->sections
[0]._y
) {
497 printf("%d %d %d\n\n\n", tPtr
->sel
.y
, tPtr
->sel
.h
, tPtr
->sel
.w
);
504 removeSelection(Text
*tPtr
)
506 TextBlock
*tb
= NULL
;
509 if (!(tb
= tPtr
->firstTextBlock
))
514 if(!first
&& !tb
->graphic
) {
515 WMReleaseFont(tPtr
->dFont
);
516 tPtr
->dFont
= WMRetainFont(tb
->d
.font
);
520 if ( (tb
->s_end
- tb
->s_begin
== tb
->used
) || tb
->graphic
) {
521 tPtr
->currentTextBlock
= tb
;
522 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
523 tb
= tPtr
->currentTextBlock
;
528 } else if (tb
->s_end
<= tb
->used
) {
529 memmove(&(tb
->text
[tb
->s_begin
]),
530 &(tb
->text
[tb
->s_end
]), tb
->used
- tb
->s_end
);
531 tb
->used
-= (tb
->s_end
- tb
->s_begin
);
532 tb
->selected
= False
;
533 tPtr
->tpos
= tb
->s_begin
;
544 getFirstNonGraphicBlockFor(TextBlock
*tb
, short dir
)
546 TextBlock
*hold
= tb
;
554 tb
= (dir
? tb
->next
: tb
->prior
);
562 tb
= (dir
? tb
->prior
: tb
->next
);
574 updateStartForCurrentTextBlock(Text
*tPtr
, int x
, int y
, int *dir
,
577 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
578 tb
= getFirstNonGraphicBlockFor(tb
, *dir
);
583 tPtr
->currentTextBlock
=
584 (dir
? tPtr
->lastTextBlock
: tPtr
->firstTextBlock
);
592 layOutDocument(tPtr
);
596 *dir
= !(y
<= tb
->sections
[0].y
);
598 if ( ( y
<= tb
->sections
[0]._y
+ tb
->sections
[0].h
)
599 && (y
>= tb
->sections
[0]._y
) ) {
600 /* if it's on the same line */
601 if(x
< tb
->sections
[0].x
)
605 if ( ( y
<= tb
->sections
[tb
->nsections
-1]._y
606 + tb
->sections
[tb
->nsections
-1].h
)
607 && (y
>= tb
->sections
[tb
->nsections
-1]._y
) ) {
608 /* if it's on the same line */
609 if(x
> tb
->sections
[tb
->nsections
-1].x
)
619 paintText(Text
*tPtr
)
625 int len
, y
, c
, s
, done
=False
, prev_y
=-23, dir
/* 1 = down */;
626 WMScreen
*scr
= tPtr
->view
->screen
;
627 Display
*dpy
= tPtr
->view
->screen
->display
;
628 Window win
= tPtr
->view
->window
;
630 if (!tPtr
->view
->flags
.realized
|| !tPtr
->db
|| tPtr
->flags
.frozen
)
633 XFillRectangle(dpy
, tPtr
->db
, tPtr
->bgGC
,
634 0, 0, tPtr
->visible
.w
, tPtr
->visible
.h
);
636 if (tPtr
->bgPixmap
) {
637 WMDrawPixmap(tPtr
->bgPixmap
, tPtr
->db
,
638 (tPtr
->visible
.w
-tPtr
->visible
.x
-tPtr
->bgPixmap
->width
)/2,
639 (tPtr
->visible
.h
-tPtr
->visible
.y
-tPtr
->bgPixmap
->height
)/2);
642 if (! (tb
= tPtr
->currentTextBlock
)) {
643 if (! (tb
= tPtr
->firstTextBlock
)) {
648 if (tPtr
->flags
.ownsSelection
)
649 greyGC
= WMColorGC(WMGrayColor(scr
));
655 /* first, which direction? Don't waste time looking all over,
656 since the parts to be drawn will most likely be near what
657 was previously drawn */
658 if(!updateStartForCurrentTextBlock(tPtr
, 0, tPtr
->vpos
, &dir
, tb
))
663 if (tb
->graphic
&& tPtr
->flags
.monoFont
)
667 if(tPtr
->vpos
<= tb
->sections
[tb
->nsections
-1]._y
668 + tb
->sections
[tb
->nsections
-1].h
)
671 if(tPtr
->vpos
>= tb
->sections
[tb
->nsections
-1]._y
672 + tb
->sections
[tb
->nsections
-1].h
)
689 /* first, place all text that can be viewed */
690 while (!done
&& tb
) {
692 /* paragraph diagnostic
693 if(tb->blank) {tb->text[0] = 'F'; } */
700 tb
->selected
= False
;
702 for(s
=0; s
<tb
->nsections
&& !done
; s
++) {
704 if (tb
->sections
[s
]._y
> tPtr
->vpos
+ tPtr
->visible
.h
) {
709 if ( tb
->sections
[s
].y
+ tb
->sections
[s
].h
< tPtr
->vpos
)
712 if (tPtr
->flags
.monoFont
) {
717 gc
= WMColorGC(tb
->color
);
720 if (tPtr
->flags
.ownsSelection
) {
723 if ( sectionWasSelected(tPtr
, tb
, &rect
, s
)) {
725 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
726 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
730 prev_y
= tb
->sections
[s
]._y
;
732 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
733 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
734 y
= tb
->sections
[s
].y
- tPtr
->vpos
;
735 WMDrawString(scr
, tPtr
->db
, gc
, font
,
736 tb
->sections
[s
].x
- tPtr
->hpos
, y
, text
, len
);
738 if (!tPtr
->flags
.monoFont
&& tb
->underlined
) {
739 XDrawLine(dpy
, tPtr
->db
, gc
,
740 tb
->sections
[s
].x
- tPtr
->hpos
,
742 tb
->sections
[s
].x
+ tb
->sections
[s
].w
- tPtr
->hpos
,
748 tb
= (!done
? tb
->next
: NULL
);
752 /* now , show all graphic items that can be viewed */
753 c
= WMGetArrayItemCount(tPtr
->gfxItems
);
754 if (c
> 0 && !tPtr
->flags
.monoFont
) {
758 tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
);
760 /* if it's not viewable, and mapped, unmap it */
761 if (tb
->sections
[0]._y
+ tb
->sections
[0].h
<= tPtr
->vpos
762 || tb
->sections
[0]._y
>= tPtr
->vpos
+ tPtr
->visible
.h
) {
765 if ((W_VIEW(tb
->d
.widget
))->flags
.mapped
) {
766 WMUnmapWidget(tb
->d
.widget
);
770 /* if it's viewable, and not mapped, map it */
772 W_View
*view
= W_VIEW(tb
->d
.widget
);
774 if (!view
->flags
.realized
)
775 WMRealizeWidget(tb
->d
.widget
);
776 if(!view
->flags
.mapped
) {
777 XMapWindow(view
->screen
->display
, view
->window
);
778 XFlush(view
->screen
->display
);
779 view
->flags
.mapped
= 1;
783 if (tPtr
->flags
.ownsSelection
) {
786 if ( sectionWasSelected(tPtr
, tb
, &rect
, 0)) {
788 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
789 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
794 WMMoveWidget(tb
->d
.widget
,
795 tb
->sections
[0].x
+ tPtr
->visible
.x
- tPtr
->hpos
,
796 tb
->sections
[0].y
+ tPtr
->visible
.y
- tPtr
->vpos
);
797 h
= WMWidgetHeight(tb
->d
.widget
) + 1;
800 WMDrawPixmap(tb
->d
.pixmap
, tPtr
->db
,
801 tb
->sections
[0].x
- tPtr
->hpos
,
802 tb
->sections
[0].y
- tPtr
->vpos
);
803 h
= tb
->d
.pixmap
->height
+ 1;
807 if (!tPtr
->flags
.monoFont
&& tb
->underlined
) {
808 XDrawLine(dpy
, tPtr
->db
, WMColorGC(tb
->color
),
809 tb
->sections
[0].x
- tPtr
->hpos
,
810 tb
->sections
[0].y
+ h
- tPtr
->vpos
,
811 tb
->sections
[0].x
+ tb
->sections
[0].w
- tPtr
->hpos
,
812 tb
->sections
[0].y
+ h
- tPtr
->vpos
);
817 if (tPtr
->flags
.editable
&& tPtr
->flags
.cursorShown
818 && tPtr
->cursor
.x
!= -23 && tPtr
->flags
.focused
) {
819 int y
= tPtr
->cursor
.y
- tPtr
->vpos
;
820 XDrawLine(dpy
, tPtr
->db
, tPtr
->fgGC
,
822 tPtr
->cursor
.x
, y
+ tPtr
->cursor
.h
);
825 XCopyArea(dpy
, tPtr
->db
, win
, tPtr
->bgGC
, 0, 0,
826 tPtr
->visible
.w
, tPtr
->visible
.h
,
827 tPtr
->visible
.x
, tPtr
->visible
.y
);
829 W_DrawRelief(scr
, win
, 0, 0,
830 tPtr
->view
->size
.width
, tPtr
->view
->size
.height
,
833 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)
834 XDrawLine(dpy
, win
, tPtr
->fgGC
,
835 2, 42, tPtr
->view
->size
.width
-4, 42);
840 mouseOverObject(Text
*tPtr
, int x
, int y
)
845 x
-= tPtr
->visible
.x
;
847 y
-= tPtr
->visible
.y
;
850 if(tPtr
->flags
.ownsSelection
) {
853 && tPtr
->sel
.x
+ tPtr
->sel
.w
>= x
854 && tPtr
->sel
.y
+ tPtr
->sel
.h
>= y
) {
855 tPtr
->flags
.isOverGraphic
= 1;
862 int j
, c
= WMGetArrayItemCount(tPtr
->gfxItems
);
865 tPtr
->flags
.isOverGraphic
= 0;
869 tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
);
871 if(!tb
|| !tb
->sections
) {
872 tPtr
->flags
.isOverGraphic
= 0;
877 if(tb
->sections
[0].x
<= x
878 && tb
->sections
[0].y
<= y
879 && tb
->sections
[0].x
+ tb
->sections
[0].w
>= x
880 && tb
->sections
[0].y
+ tb
->d
.pixmap
->height
>= y
) {
881 tPtr
->flags
.isOverGraphic
= 3;
892 tPtr
->flags
.isOverGraphic
= 0;
895 tPtr
->view
->attribs
.cursor
= (result
?
896 tPtr
->view
->screen
->defaultCursor
897 : tPtr
->view
->screen
->textCursor
);
899 XSetWindowAttributes attribs
;
900 attribs
.cursor
= tPtr
->view
->attribs
.cursor
;
901 XChangeWindowAttributes(tPtr
->view
->screen
->display
,
902 tPtr
->view
->window
, CWCursor
,
910 blinkCursor(void *data
)
912 Text
*tPtr
= (Text
*)data
;
914 if (tPtr
->flags
.cursorShown
) {
915 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY
,
918 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
,
922 tPtr
->flags
.cursorShown
= !tPtr
->flags
.cursorShown
;
927 updateCursorPosition(Text
*tPtr
)
929 TextBlock
*tb
= NULL
;
932 if(tPtr
->flags
.needsLayOut
)
933 layOutDocument(tPtr
);
935 if (! (tb
= tPtr
->currentTextBlock
)) {
936 if (! (tb
= tPtr
->firstTextBlock
)) {
938 tPtr
->cursor
.h
= tPtr
->dFont
->height
;
948 y
= tb
->sections
[0].y
;
949 h
= tb
->sections
[0].h
;
950 x
= tb
->sections
[0].x
;
952 } else if(tb
->graphic
) {
953 y
= tb
->sections
[0].y
;
954 h
= tb
->sections
[0].h
;
955 x
= tb
->sections
[0].x
;
958 if(tPtr
->tpos
> tb
->used
)
959 tPtr
->tpos
= tb
->used
;
961 for(s
=0; s
<tb
->nsections
-1; s
++) {
963 if(tPtr
->tpos
>= tb
->sections
[s
].begin
964 && tPtr
->tpos
<= tb
->sections
[s
].end
)
968 y
= tb
->sections
[s
]._y
;
969 h
= tb
->sections
[s
].h
;
970 x
= tb
->sections
[s
].x
+ WMWidthOfString(
971 (tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
),
972 &tb
->text
[tb
->sections
[s
].begin
],
973 tPtr
->tpos
- tb
->sections
[s
].begin
);
981 /* scroll the bars if the cursor is not visible */
982 if(tPtr
->flags
.editable
&& tPtr
->cursor
.x
!= -23) {
983 if(tPtr
->cursor
.y
+tPtr
->cursor
.h
984 > tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
) {
986 (tPtr
->cursor
.y
+tPtr
->cursor
.h
+10
987 - (tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
));
988 } else if(tPtr
->cursor
.y
< tPtr
->vpos
+tPtr
->visible
.y
) {
989 tPtr
->vpos
-= (tPtr
->vpos
+tPtr
->visible
.y
-tPtr
->cursor
.y
);
994 updateScrollers(tPtr
);
999 cursorToTextPosition(Text
*tPtr
, int x
, int y
)
1001 TextBlock
*tb
= NULL
;
1002 int done
=False
, s
, pos
, len
, _w
, _y
, dir
=1; /* 1 == "down" */
1005 if(tPtr
->flags
.needsLayOut
)
1006 layOutDocument(tPtr
);
1008 y
+= (tPtr
->vpos
- tPtr
->visible
.y
);
1012 x
-= (tPtr
->visible
.x
- 2);
1016 /* clicked is relative to document, not window... */
1017 tPtr
->clicked
.x
= x
;
1018 tPtr
->clicked
.y
= y
;
1020 if (! (tb
= tPtr
->currentTextBlock
)) {
1021 if (! (tb
= tPtr
->firstTextBlock
)) {
1023 tPtr
->cursor
.h
= tPtr
->dFont
->height
;
1030 /* first, which direction? Most likely, newly clicked
1031 position will be close to previous */
1032 if(!updateStartForCurrentTextBlock(tPtr
, x
, y
, &dir
, tb
))
1036 s
= (dir
? 0 : tb
->nsections
-1);
1037 if ( y
>= tb
->sections
[s
]._y
1038 && y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) {
1042 /* get the first (or last) section of the TextBlock that
1043 lies about the vertical click point */
1045 while (!done
&& tb
) {
1047 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1048 if( (dir
?tb
->next
:tb
->prior
))
1049 tb
= (dir
?tb
->next
:tb
->prior
);
1053 s
= (dir
? 0 : tb
->nsections
-1);
1054 while (!done
&& (dir
? (s
<tb
->nsections
) : (s
>=0) )) {
1056 if ( (dir
? (y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) :
1057 ( y
>= tb
->sections
[s
]._y
) ) ) {
1065 if ( (dir
? tb
->next
: tb
->prior
)) {
1066 tb
= (dir
? tb
->next
: tb
->prior
);
1069 break; /* goto _doneH; */
1075 if (s
<0 || s
>=tb
->nsections
) {
1076 s
= (dir
? tb
->nsections
-1 : 0);
1080 /* we have the line, which TextBlock on that line is it? */
1081 pos
= (dir
?0:tb
->sections
[s
].begin
);
1082 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1083 TextBlock
*hold
= tb
;
1084 tb
= getFirstNonGraphicBlockFor(hold
, dir
);
1098 _y
= tb
->sections
[s
]._y
;
1102 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1103 tb
= (dir
? tb
->next
: tb
->prior
);
1110 _w
= WMWidgetWidth(tb
->d
.widget
)-5;
1112 _w
= tb
->d
.pixmap
->width
-5;
1114 if (tb
->sections
[0].x
+ _w
>= x
)
1117 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
1118 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
1119 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
1120 if (tb
->sections
[s
].x
+ _w
>= x
)
1125 if (tb
->sections
[s
].x
<= x
)
1129 if ((dir
? tb
->next
: tb
->prior
)) {
1130 TextBlock
*nxt
= (dir
? tb
->next
: tb
->prior
);
1131 if (tPtr
->flags
.monoFont
&& nxt
->graphic
) {
1132 nxt
= getFirstNonGraphicBlockFor(nxt
, dir
);
1134 pos
= (dir
?0:tb
->sections
[s
].begin
);
1135 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
1140 if (_y
!= nxt
->sections
[dir
?0:nxt
->nsections
-1]._y
) {
1141 /* this must be the last/first on this line. stop */
1142 pos
= (dir
? tb
->sections
[s
].end
: 0);
1143 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
1147 tPtr
->cursor
.x
+= WMWidgetWidth(tb
->d
.widget
);
1149 tPtr
->cursor
.x
+= tb
->d
.pixmap
->width
;
1150 } else if (pos
> tb
->sections
[s
].begin
) {
1152 WMWidthOfString(tb
->d
.font
,
1153 &(tb
->text
[tb
->sections
[s
].begin
]),
1154 pos
- tb
->sections
[s
].begin
);
1161 if ( (dir
? tb
->next
: tb
->prior
)) {
1162 tb
= (dir
? tb
->next
: tb
->prior
);
1169 s
= (dir
? 0 : tb
->nsections
-1);
1172 /* we have said TextBlock, now where within it? */
1175 int gw
= (tb
->object
?
1176 WMWidgetWidth(tb
->d
.widget
) : tb
->d
.pixmap
->width
);
1178 tPtr
->cursor
.x
= tb
->sections
[0].x
;
1180 if(x
> tPtr
->cursor
.x
+ gw
/2) {
1182 printf("here x%d: %d\n", x
, tPtr
->cursor
.x
+ gw
/2);
1183 tPtr
->cursor
.x
+= gw
;
1190 WMFont
*f
= tb
->d
.font
;
1191 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
1192 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
1194 _w
= x
- tb
->sections
[s
].x
;
1197 while (pos
<len
&& WMWidthOfString(f
, text
, pos
+1) < _w
)
1200 tPtr
->cursor
.x
= tb
->sections
[s
].x
+
1201 (pos
? WMWidthOfString(f
, text
, pos
) : 0);
1203 pos
+= tb
->sections
[s
].begin
;
1208 tPtr
->tpos
= (pos
<tb
->used
)? pos
: tb
->used
;
1211 printf("...for this app will surely crash :-)\n");
1213 tPtr
->currentTextBlock
= tb
;
1214 tPtr
->cursor
.h
= tb
->sections
[s
].h
;
1215 tPtr
->cursor
.y
= tb
->sections
[s
]._y
;
1217 /* scroll the bars if the cursor is not visible */
1218 if(tPtr
->flags
.editable
&& tPtr
->cursor
.x
!= -23) {
1219 if(tPtr
->cursor
.y
+tPtr
->cursor
.h
1220 > tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
) {
1222 (tPtr
->cursor
.y
+tPtr
->cursor
.h
+10
1223 - (tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
));
1224 updateScrollers(tPtr
);
1225 } else if(tPtr
->cursor
.y
< tPtr
->vpos
+tPtr
->visible
.y
) {
1226 tPtr
->vpos
-= (tPtr
->vpos
+tPtr
->visible
.y
-tPtr
->cursor
.y
);
1227 updateScrollers(tPtr
);
1236 updateScrollers(Text
*tPtr
)
1239 if (tPtr
->flags
.frozen
)
1243 if (tPtr
->docHeight
< tPtr
->visible
.h
) {
1244 WMSetScrollerParameters(tPtr
->vS
, 0, 1);
1247 float hmax
= (float)(tPtr
->docHeight
);
1248 WMSetScrollerParameters(tPtr
->vS
,
1249 ((float)tPtr
->vpos
)/(hmax
- (float)tPtr
->visible
.h
),
1250 (float)tPtr
->visible
.h
/hmax
);
1252 } else tPtr
->vpos
= 0;
1255 if (tPtr
->docWidth
< tPtr
->visible
.w
) {
1256 WMSetScrollerParameters(tPtr
->hS
, 0, 1);
1259 float wmax
= (float)(tPtr
->docWidth
);
1260 WMSetScrollerParameters(tPtr
->hS
,
1261 ((float)tPtr
->hpos
)/(wmax
- (float)tPtr
->visible
.w
),
1262 (float)tPtr
->visible
.w
/wmax
);
1264 } else tPtr
->hpos
= 0;
1268 scrollersCallBack(WMWidget
*w
, void *self
)
1270 Text
*tPtr
= (Text
*)self
;
1271 Bool scroll
= False
;
1274 if (!tPtr
->view
->flags
.realized
|| tPtr
->flags
.frozen
)
1277 if (w
== tPtr
->vS
) {
1279 height
= tPtr
->visible
.h
;
1281 which
= WMGetScrollerHitPart(tPtr
->vS
);
1284 case WSDecrementLine
:
1285 if (tPtr
->vpos
> 0) {
1286 if (tPtr
->vpos
>16) tPtr
->vpos
-=16;
1292 case WSIncrementLine
: {
1293 int limit
= tPtr
->docHeight
- height
;
1294 if (tPtr
->vpos
< limit
) {
1295 if (tPtr
->vpos
<limit
-16) tPtr
->vpos
+=16;
1296 else tPtr
->vpos
=limit
;
1302 case WSDecrementPage
:
1303 if(((int)tPtr
->vpos
- (int)height
) >= 0)
1304 tPtr
->vpos
-= height
;
1311 case WSIncrementPage
:
1312 tPtr
->vpos
+= height
;
1313 if (tPtr
->vpos
> (tPtr
->docHeight
- height
))
1314 tPtr
->vpos
= tPtr
->docHeight
- height
;
1320 tPtr
->vpos
= WMGetScrollerValue(tPtr
->vS
)
1321 * (float)(tPtr
->docHeight
- height
);
1329 scroll
= (tPtr
->vpos
!= tPtr
->prevVpos
);
1330 tPtr
->prevVpos
= tPtr
->vpos
;
1334 if (w
== tPtr
->hS
) {
1335 int width
= tPtr
->visible
.w
;
1337 which
= WMGetScrollerHitPart(tPtr
->hS
);
1340 case WSDecrementLine
:
1341 if (tPtr
->hpos
> 0) {
1342 if (tPtr
->hpos
>16) tPtr
->hpos
-=16;
1347 case WSIncrementLine
: {
1348 int limit
= tPtr
->docWidth
- width
;
1349 if (tPtr
->hpos
< limit
) {
1350 if (tPtr
->hpos
<limit
-16) tPtr
->hpos
+=16;
1351 else tPtr
->hpos
=limit
;
1355 case WSDecrementPage
:
1356 if(((int)tPtr
->hpos
- (int)width
) >= 0)
1357 tPtr
->hpos
-= width
;
1364 case WSIncrementPage
:
1365 tPtr
->hpos
+= width
;
1366 if (tPtr
->hpos
> (tPtr
->docWidth
- width
))
1367 tPtr
->hpos
= tPtr
->docWidth
- width
;
1373 tPtr
->hpos
= WMGetScrollerValue(tPtr
->hS
)
1374 * (float)(tPtr
->docWidth
- width
);
1382 scroll
= (tPtr
->hpos
!= tPtr
->prevHpos
);
1383 tPtr
->prevHpos
= tPtr
->hpos
;
1387 updateScrollers(tPtr
);
1396 unsigned short begin
, end
; /* what part of the text block */
1401 layOutLine(Text
*tPtr
, myLineItems
*items
, int nitems
, int x
, int y
)
1403 int i
, j
=0, lw
= 0, line_height
=0, max_d
=0, len
, n
;
1406 TextBlock
*tb
, *tbsame
=NULL
;
1408 if(!items
|| nitems
== 0)
1411 for(i
=0; i
<nitems
; i
++) {
1415 if (!tPtr
->flags
.monoFont
) {
1417 WMWidget
*wdt
= tb
->d
.widget
;
1418 line_height
= WMAX(line_height
, WMWidgetHeight(wdt
));
1419 if (tPtr
->flags
.alignment
!= WALeft
)
1420 lw
+= WMWidgetWidth(wdt
);
1422 line_height
= WMAX(line_height
,
1423 tb
->d
.pixmap
->height
+ max_d
);
1424 if (tPtr
->flags
.alignment
!= WALeft
)
1425 lw
+= tb
->d
.pixmap
->width
;
1430 font
= (tPtr
->flags
.monoFont
)?tPtr
->dFont
: tb
->d
.font
;
1431 max_d
= WMAX(max_d
, abs(font
->height
-font
->y
));
1432 line_height
= WMAX(line_height
, font
->height
+ max_d
);
1433 text
= &(tb
->text
[items
[i
].begin
]);
1434 len
= items
[i
].end
- items
[i
].begin
;
1435 if (tPtr
->flags
.alignment
!= WALeft
)
1436 lw
+= WMWidthOfString(font
, text
, len
);
1440 if (tPtr
->flags
.alignment
== WARight
) {
1441 j
= tPtr
->visible
.w
- lw
;
1442 } else if (tPtr
->flags
.alignment
== WACenter
) {
1443 j
= (int) ((float)(tPtr
->visible
.w
- lw
))/2.0;
1446 for(i
=0; i
<nitems
; i
++) {
1449 if (tbsame
== tb
) { /* extend it, since it's on same line */
1450 tb
->sections
[tb
->nsections
-1].end
= items
[i
].end
;
1451 n
= tb
->nsections
-1;
1453 tb
->sections
= wrealloc(tb
->sections
,
1454 (++tb
->nsections
)*sizeof(Section
));
1455 n
= tb
->nsections
-1;
1456 tb
->sections
[n
]._y
= y
+ max_d
;
1457 tb
->sections
[n
].max_d
= max_d
;
1458 tb
->sections
[n
].x
= x
+j
;
1459 tb
->sections
[n
].h
= line_height
;
1460 tb
->sections
[n
].begin
= items
[i
].begin
;
1461 tb
->sections
[n
].end
= items
[i
].end
;
1464 tb
->sections
[n
].last
= (i
+1 == nitems
);
1467 if (!tPtr
->flags
.monoFont
) {
1469 WMWidget
*wdt
= tb
->d
.widget
;
1470 tb
->sections
[n
].y
= max_d
+ y
1471 + line_height
- WMWidgetHeight(wdt
);
1472 tb
->sections
[n
].w
= WMWidgetWidth(wdt
);
1474 tb
->sections
[n
].y
= y
+ line_height
1475 + max_d
- tb
->d
.pixmap
->height
;
1476 tb
->sections
[n
].w
= tb
->d
.pixmap
->width
;
1478 x
+= tb
->sections
[n
].w
;
1481 font
= (tPtr
->flags
.monoFont
)? tPtr
->dFont
: tb
->d
.font
;
1482 len
= items
[i
].end
- items
[i
].begin
;
1483 text
= &(tb
->text
[items
[i
].begin
]);
1485 tb
->sections
[n
].y
= y
+line_height
-font
->y
;
1487 WMWidthOfString(font
,
1488 &(tb
->text
[tb
->sections
[n
].begin
]),
1489 tb
->sections
[n
].end
- tb
->sections
[n
].begin
);
1491 x
+= WMWidthOfString(font
, text
, len
);
1503 layOutDocument(Text
*tPtr
)
1506 myLineItems
*items
= NULL
;
1507 unsigned int itemsSize
=0, nitems
=0, begin
, end
;
1509 unsigned int x
, y
=0, lw
= 0, width
=0, bmargin
;
1510 char *start
=NULL
, *mark
=NULL
;
1512 if ( tPtr
->flags
.frozen
|| (!(tb
= tPtr
->firstTextBlock
)) )
1515 assert(tPtr
->visible
.w
> 20);
1517 tPtr
->docWidth
= tPtr
->visible
.w
;
1518 x
= tPtr
->margins
[tb
->marginN
].first
;
1519 bmargin
= tPtr
->margins
[tb
->marginN
].body
;
1521 /* only partial layOut needed: re-Lay only affected textblocks */
1522 if (tPtr
->flags
.laidOut
) {
1523 tb
= tPtr
->currentTextBlock
;
1525 /* search backwards for textblocks on same line */
1527 if (!tb
->sections
|| tb
->nsections
<1) {
1528 tb
= tPtr
->firstTextBlock
;
1529 tPtr
->flags
.laidOut
= False
;
1534 if(!tb
->prior
->sections
|| tb
->prior
->nsections
<1) {
1535 tb
= tPtr
->firstTextBlock
;
1536 tPtr
->flags
.laidOut
= False
;
1541 if (tb
->sections
[0]._y
!=
1542 tb
->prior
->sections
[tb
->prior
->nsections
-1]._y
) {
1548 if(tb
->prior
&& tb
->prior
->sections
&& tb
->prior
->nsections
>0) {
1549 y
= tb
->prior
->sections
[tb
->prior
->nsections
-1]._y
+
1550 tb
->prior
->sections
[tb
->prior
->nsections
-1].h
-
1551 tb
->prior
->sections
[tb
->prior
->nsections
-1].max_d
;
1560 if (tb
->sections
&& tb
->nsections
>0) {
1561 wfree(tb
->sections
);
1562 tb
->sections
= NULL
;
1566 if (tb
->blank
&& tb
->next
&& !tb
->next
->first
) {
1567 TextBlock
*next
= tb
->next
;
1568 tPtr
->currentTextBlock
= tb
;
1569 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1575 if (tb
->first
&& tb
!= tPtr
->firstTextBlock
) {
1576 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1577 x
= tPtr
->margins
[tb
->marginN
].first
;
1578 bmargin
= tPtr
->margins
[tb
->marginN
].body
;
1584 if (!tPtr
->flags
.monoFont
) {
1586 width
= WMWidgetWidth(tb
->d
.widget
);
1588 width
= tb
->d
.pixmap
->width
;
1590 if (width
> tPtr
->docWidth
)
1591 tPtr
->docWidth
= width
;
1594 if (lw
>= tPtr
->visible
.w
- x
) {
1595 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1601 if(nitems
+ 1> itemsSize
) {
1602 items
= wrealloc(items
,
1603 (++itemsSize
)*sizeof(myLineItems
));
1606 items
[nitems
].tb
= tb
;
1607 items
[nitems
].begin
= 0;
1608 items
[nitems
].end
= 0;
1612 } else if ((start
= tb
->text
)) {
1614 font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
1617 mark
= strchr(start
, ' ');
1619 end
+= (int)(mark
-start
)+1;
1622 end
+= strlen(start
);
1629 if (end
-begin
> 0) {
1631 width
= WMWidthOfString(font
,
1632 &tb
->text
[begin
], end
-begin
);
1634 /* if it won't fit, char wrap it */
1635 if (width
>= tPtr
->visible
.w
) {
1636 char *t
= &tb
->text
[begin
];
1637 int l
=end
-begin
, i
=0;
1639 width
= WMWidthOfString(font
, t
, ++i
);
1640 } while (width
< tPtr
->visible
.w
&& i
< l
);
1643 start
= &tb
->text
[end
];
1649 if (lw
>= tPtr
->visible
.w
- x
) {
1650 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1656 if(nitems
+ 1 > itemsSize
) {
1657 items
= wrealloc(items
,
1658 (++itemsSize
)*sizeof(myLineItems
));
1661 items
[nitems
].tb
= tb
;
1662 items
[nitems
].begin
= begin
;
1663 items
[nitems
].end
= end
;
1671 /* not yet fully ready. but is already VERY FAST for a 3Mbyte file ;-) */
1672 if(0&&tPtr
->flags
.laidOut
1673 && tb
->next
&& tb
->next
->sections
&& tb
->next
->nsections
>0
1674 && (tPtr
->vpos
+ tPtr
->visible
.h
1675 < tb
->next
->sections
[0]._y
)) {
1676 if(tPtr
->lastTextBlock
->sections
1677 && tPtr
->lastTextBlock
->nsections
> 0 ) {
1678 TextBlock
*ltb
= tPtr
->lastTextBlock
;
1679 int ly
= ltb
->sections
[ltb
->nsections
-1]._y
;
1680 int lh
= ltb
->sections
[ltb
->nsections
-1].h
;
1683 lh
+= 1 + tPtr
->visible
.y
+ ltb
->sections
[ltb
->nsections
-1].max_d
;
1684 printf("it's %d\n", tPtr
->visible
.y
+ ltb
->sections
[ltb
->nsections
-1].max_d
);
1686 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1688 sd
= tPtr
->docHeight
-y
;
1690 printf("dif %d-%d: %d\n", ss
, sd
, ss
-sd
);
1691 y
+= tb
->next
->sections
[0]._y
-y
;
1693 printf("nitems%d\n", nitems
);
1695 y
= tPtr
->docHeight
+ss
-sd
;
1699 tPtr
->flags
.laidOut
= False
;
1708 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1710 if (tPtr
->docHeight
!= y
+10) {
1711 tPtr
->docHeight
= y
+10;
1712 updateScrollers(tPtr
);
1715 if(tPtr
->docWidth
> tPtr
->visible
.w
&& !tPtr
->hS
) {
1718 tPtr
->flags
.horizOnDemand
= True
;
1719 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, True
);
1720 event
.type
= Expose
;
1721 handleEvents(&event
, (void *)tPtr
);
1723 } else if(tPtr
->docWidth
<= tPtr
->visible
.w
1724 && tPtr
->hS
&& tPtr
->flags
.horizOnDemand
) {
1725 tPtr
->flags
.horizOnDemand
= False
;
1726 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, False
);
1729 tPtr
->flags
.laidOut
= True
;
1731 if(items
&& itemsSize
> 0)
1734 if (W_VIEW_REALIZED(tPtr
->view
) && W_VIEW_MAPPED(tPtr
->view
))
1740 textDidResize(W_ViewDelegate
*self
, WMView
*view
)
1742 Text
*tPtr
= (Text
*)view
->self
;
1743 unsigned short w
= tPtr
->view
->size
.width
;
1744 unsigned short h
= tPtr
->view
->size
.height
;
1745 unsigned short rh
= 0, vw
= 0, rel
;
1747 rel
= (tPtr
->flags
.relief
== WRFlat
);
1749 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
) {
1750 WMMoveWidget(tPtr
->ruler
, 2, 2);
1751 WMResizeWidget(tPtr
->ruler
, w
- 4, 40);
1756 WMMoveWidget(tPtr
->vS
, 1 - (rel
?1:0), rh
+ 1 - (rel
?1:0));
1757 WMResizeWidget(tPtr
->vS
, 20, h
- rh
- 2 + (rel
?2:0));
1759 WMSetRulerOffset(tPtr
->ruler
,22);
1760 } else WMSetRulerOffset(tPtr
->ruler
, 2);
1764 WMMoveWidget(tPtr
->hS
, vw
, h
- 21);
1765 WMResizeWidget(tPtr
->hS
, w
- vw
- 1, 20);
1767 WMMoveWidget(tPtr
->hS
, vw
+1, h
- 21);
1768 WMResizeWidget(tPtr
->hS
, w
- vw
- 2, 20);
1772 tPtr
->visible
.x
= (tPtr
->vS
)?24:4;
1773 tPtr
->visible
.y
= (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)?43:3;
1774 tPtr
->visible
.w
= tPtr
->view
->size
.width
- tPtr
->visible
.x
- 8;
1775 tPtr
->visible
.h
= tPtr
->view
->size
.height
- tPtr
->visible
.y
;
1776 tPtr
->visible
.h
-= (tPtr
->hS
)?20:0;
1777 tPtr
->margins
[0].right
= tPtr
->visible
.w
;
1779 if (tPtr
->view
->flags
.realized
) {
1782 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
1783 tPtr
->db
= (Pixmap
) NULL
;
1786 if (tPtr
->visible
.w
< 40)
1787 tPtr
->visible
.w
= 40;
1788 if (tPtr
->visible
.h
< 20)
1789 tPtr
->visible
.h
= 20;
1792 tPtr
->db
= XCreatePixmap(tPtr
->view
->screen
->display
,
1793 tPtr
->view
->window
, tPtr
->visible
.w
,
1794 tPtr
->visible
.h
, tPtr
->view
->screen
->depth
);
1801 W_ViewDelegate _TextViewDelegate
=
1809 /* nice, divisble-by-16 blocks */
1810 static inline unsigned short
1811 reqBlockSize(unsigned short requested
)
1813 return requested
+ 16 - (requested
%16);
1818 clearText(Text
*tPtr
)
1820 tPtr
->vpos
= tPtr
->hpos
= 0;
1821 tPtr
->docHeight
= tPtr
->docWidth
= 0;
1822 tPtr
->cursor
.x
= -23;
1824 if (!tPtr
->firstTextBlock
)
1827 while (tPtr
->currentTextBlock
)
1828 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1830 tPtr
->firstTextBlock
= NULL
;
1831 tPtr
->currentTextBlock
= NULL
;
1832 tPtr
->lastTextBlock
= NULL
;
1833 WMEmptyArray(tPtr
->gfxItems
);
1837 deleteTextInteractively(Text
*tPtr
, KeySym ksym
)
1840 Bool back
= (Bool
) (ksym
== XK_BackSpace
);
1844 if (!tPtr
->flags
.editable
) {
1845 XBell(tPtr
->view
->screen
->display
, 0);
1849 if ( !(tb
= tPtr
->currentTextBlock
) )
1852 if (tPtr
->flags
.ownsSelection
) {
1853 if(removeSelection(tPtr
))
1854 layOutDocument(tPtr
);
1858 wasFirst
= tb
->first
;
1859 if (back
&& tPtr
->tpos
< 1) {
1861 if(tb
->prior
->blank
) {
1862 tPtr
->currentTextBlock
= tb
->prior
;
1863 WMRemoveTextBlock(tPtr
);
1864 tPtr
->currentTextBlock
= tb
;
1866 layOutDocument(tPtr
);
1870 TextBlock
*prior
= tb
->prior
;
1871 tPtr
->currentTextBlock
= tb
;
1872 WMRemoveTextBlock(tPtr
);
1878 tPtr
->tpos
= tb
->used
;
1879 tPtr
->currentTextBlock
= tb
;
1883 tb
->next
->first
= False
;
1884 layOutDocument(tPtr
);
1891 if ( (tb
->used
> 0) && ((back
?tPtr
->tpos
> 0:1))
1892 && (tPtr
->tpos
<= tb
->used
) && !tb
->graphic
) {
1895 memmove(&(tb
->text
[tPtr
->tpos
]),
1896 &(tb
->text
[tPtr
->tpos
+ 1]), tb
->used
- tPtr
->tpos
);
1901 if ( (back
? (tPtr
->tpos
< 1 && !done
) : ( tPtr
->tpos
>= tb
->used
))
1904 TextBlock
*sibling
= (back
? tb
->prior
: tb
->next
);
1906 if(tb
->used
== 0 || tb
->graphic
)
1907 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1910 tPtr
->currentTextBlock
= sibling
;
1911 tPtr
->tpos
= (back
? sibling
->used
: 0);
1915 layOutDocument(tPtr
);
1920 insertTextInteractively(Text
*tPtr
, char *text
, int len
)
1923 char *newline
= NULL
;
1925 if (!tPtr
->flags
.editable
) {
1926 XBell(tPtr
->view
->screen
->display
, 0);
1930 if (len
< 1 || !text
)
1934 if(tPtr
->flags
.ignoreNewLine
&& *text
== '\n' && len
== 1)
1938 if (tPtr
->flags
.ownsSelection
)
1939 removeSelection(tPtr
);
1942 if (tPtr
->flags
.ignoreNewLine
) {
1944 for(i
=0; i
<len
; i
++) {
1945 if (text
[i
] == '\n')
1950 tb
= tPtr
->currentTextBlock
;
1951 if (!tb
|| tb
->graphic
) {
1953 WMAppendTextStream(tPtr
, text
);
1954 layOutDocument(tPtr
);
1958 if ((newline
= strchr(text
, '\n'))) {
1959 int nlen
= (int)(newline
-text
);
1960 int s
= tb
->used
- tPtr
->tpos
;
1962 if (!tb
->blank
&& nlen
>0) {
1964 memcpy(save
, &tb
->text
[tPtr
->tpos
], s
);
1965 tb
->used
-= (tb
->used
- tPtr
->tpos
);
1967 insertTextInteractively(tPtr
, text
, nlen
);
1969 WMAppendTextStream(tPtr
, newline
);
1971 insertTextInteractively(tPtr
, save
, s
);
1974 if (tPtr
->tpos
>0 && tPtr
->tpos
< tb
->used
1975 && !tb
->graphic
&& tb
->text
) {
1977 void *ntb
= WMCreateTextBlockWithText(
1978 tPtr
, &tb
->text
[tPtr
->tpos
],
1979 tb
->d
.font
, tb
->color
, True
, tb
->used
- tPtr
->tpos
);
1980 tb
->used
= tPtr
->tpos
;
1981 WMAppendTextBlock(tPtr
, ntb
);
1984 } else if (tPtr
->tpos
== tb
->used
|| tPtr
->tpos
== 0) {
1985 if(tPtr
->flags
.indentNewLine
) {
1986 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
1987 " ", tb
->d
.font
, tb
->color
, True
, 4));
1990 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
1991 NULL
, tb
->d
.font
, tb
->color
, True
, 0));
1998 if (tb
->used
+ len
>= tb
->allocated
) {
1999 tb
->allocated
= reqBlockSize(tb
->used
+len
);
2000 tb
->text
= wrealloc(tb
->text
, tb
->allocated
);
2004 memcpy(tb
->text
, text
, len
);
2007 tb
->text
[tb
->used
] = 0;
2011 memmove(&(tb
->text
[tPtr
->tpos
+len
]), &tb
->text
[tPtr
->tpos
],
2012 tb
->used
-tPtr
->tpos
+1);
2013 memmove(&tb
->text
[tPtr
->tpos
], text
, len
);
2016 tb
->text
[tb
->used
] = 0;
2021 layOutDocument(tPtr
);
2026 selectRegion(Text
*tPtr
, int x
, int y
)
2032 y
+= (tPtr
->flags
.rulerShown
? 40: 0);
2035 y
-= 10; /* the original offset */
2037 x
-= tPtr
->visible
.x
-2;
2041 tPtr
->sel
.x
= WMAX(0, WMIN(tPtr
->clicked
.x
, x
));
2042 tPtr
->sel
.w
= abs(tPtr
->clicked
.x
- x
);
2043 tPtr
->sel
.y
= WMAX(0, WMIN(tPtr
->clicked
.y
, y
));
2044 tPtr
->sel
.h
= abs(tPtr
->clicked
.y
- y
);
2046 tPtr
->flags
.ownsSelection
= True
;
2052 releaseSelection(Text
*tPtr
)
2054 TextBlock
*tb
= tPtr
->firstTextBlock
;
2057 tb
->selected
= False
;
2060 tPtr
->flags
.ownsSelection
= False
;
2061 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
,
2069 requestHandler(WMView
*view
, Atom selection
, Atom target
, void *cdata
,
2072 Text
*tPtr
= view
->self
;
2073 Display
*dpy
= tPtr
->view
->screen
->display
;
2075 Atom TEXT
= XInternAtom(dpy
, "TEXT", False
);
2076 Atom COMPOUND_TEXT
= XInternAtom(dpy
, "COMPOUND_TEXT", False
);
2077 WMData
*data
= NULL
;
2080 if (target
== XA_STRING
|| target
== TEXT
|| target
== COMPOUND_TEXT
) {
2081 char *text
= WMGetTextSelectedStream(tPtr
);
2084 data
= WMCreateDataWithBytes(text
, strlen(text
));
2085 WMSetDataFormat(data
, TYPETEXT
);
2089 } else printf("didn't get it\n");
2091 _TARGETS
= XInternAtom(dpy
, "TARGETS", False
);
2092 if (target
== _TARGETS
) {
2095 ptr
= wmalloc(4 * sizeof(Atom
));
2099 ptr
[3] = COMPOUND_TEXT
;
2101 data
= WMCreateDataWithBytes(ptr
, 4*4);
2102 WMSetDataFormat(data
, 32);
2112 lostHandler(WMView
*view
, Atom selection
, void *cdata
)
2114 releaseSelection((WMText
*)view
->self
);
2117 static WMSelectionProcs selectionHandler
= {
2118 requestHandler
, lostHandler
, NULL
2123 ownershipObserver(void *observerData
, WMNotification
*notification
)
2125 if (observerData
!= WMGetNotificationClientData(notification
))
2126 lostHandler(WMWidgetView(observerData
), XA_PRIMARY
, NULL
);
2130 autoSelectText(Text
*tPtr
, int clicks
)
2134 char *mark
= NULL
, behind
, ahead
;
2136 if(!(tb
= tPtr
->currentTextBlock
))
2142 switch(tb
->text
[tPtr
->tpos
]) {
2145 case '<': case '>': behind = '<'; ahead = '>'; break;
2146 case '{': case '}': behind = '{'; ahead = '}'; break;
2147 case '[': case ']': behind = '['; ahead = ']'; break;
2149 default: behind
= ahead
= ' ';
2152 tPtr
->sel
.y
= tPtr
->cursor
.y
+5;
2153 tPtr
->sel
.h
= 6;/*tPtr->cursor.h-10;*/
2156 tPtr
->sel
.x
= tb
->sections
[0].x
;
2157 tPtr
->sel
.w
= tb
->sections
[0].w
;
2159 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
2162 while(start
> 0 && tb
->text
[start
-1] != behind
)
2166 if(tPtr
->tpos
> start
){
2167 x
-= WMWidthOfString(font
, &tb
->text
[start
],
2168 tPtr
->tpos
- start
);
2170 tPtr
->sel
.x
= (x
<0?0:x
)+1;
2172 if((mark
= strchr(&tb
->text
[start
], ahead
))) {
2173 tPtr
->sel
.w
= WMWidthOfString(font
, &tb
->text
[start
],
2174 (int)(mark
- &tb
->text
[start
]));
2175 } else if(tb
->used
> start
) {
2176 tPtr
->sel
.w
= WMWidthOfString(font
, &tb
->text
[start
],
2181 } else if(clicks
== 3) {
2182 TextBlock
*cur
= tb
;
2184 while(tb
&& !tb
->first
) {
2187 tPtr
->sel
.y
= tb
->sections
[0]._y
;
2190 while(tb
->next
&& !tb
->next
->first
) {
2193 tPtr
->sel
.h
= tb
->sections
[tb
->nsections
-1]._y
2197 tPtr
->sel
.w
= tPtr
->docWidth
;
2198 tPtr
->clicked
.x
= 0; /* only for now, fix sel. code */
2201 if (!tPtr
->flags
.ownsSelection
) {
2202 WMCreateSelectionHandler(tPtr
->view
,
2203 XA_PRIMARY
, tPtr
->lastClickTime
, &selectionHandler
, NULL
);
2204 tPtr
->flags
.ownsSelection
= True
;
2212 fontChanged(void *observerData
, WMNotification
*notification
)
2214 WMText
*tPtr
= (WMText
*) observerData
;
2215 WMFont
*font
= (WMFont
*)WMGetNotificationClientData(notification
);
2216 printf("fontChanged\n");
2221 if (tPtr
->flags
.ownsSelection
)
2222 WMSetTextSelectionFont(tPtr
, font
);
2227 handleTextKeyPress(Text
*tPtr
, XEvent
*event
)
2231 int control_pressed
= False
;
2232 TextBlock
*tb
= NULL
;
2234 if (((XKeyEvent
*) event
)->state
& ControlMask
)
2235 control_pressed
= True
;
2236 buffer
[XLookupString(&event
->xkey
, buffer
, 1, &ksym
, NULL
)] = 0;
2241 if(!(tb
= tPtr
->currentTextBlock
))
2247 L_imaGFX
: if(tb
->prior
) {
2248 tPtr
->currentTextBlock
= tb
->prior
;
2249 tPtr
->tpos
= tPtr
->currentTextBlock
->used
-1;
2250 } else tPtr
->tpos
= 0;
2251 } else tPtr
->tpos
--;
2252 updateCursorPosition(tPtr
);
2257 if(!(tb
= tPtr
->currentTextBlock
))
2261 if(tPtr
->tpos
== tb
->used
) {
2262 R_imaGFX
: if(tb
->next
) {
2263 tPtr
->currentTextBlock
= tb
->next
;
2265 } else tPtr
->tpos
= tb
->used
;
2266 } else tPtr
->tpos
++;
2267 updateCursorPosition(tPtr
);
2272 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
2273 tPtr
->clicked
.y
+ tPtr
->cursor
.h
- tPtr
->vpos
);
2278 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
2279 tPtr
->visible
.y
+ tPtr
->cursor
.y
- tPtr
->vpos
- 3);
2288 deleteTextInteractively(tPtr
, ksym
);
2289 updateCursorPosition(tPtr
);
2295 control_pressed
= True
;
2299 insertTextInteractively(tPtr
, " ", 4);
2300 updateCursorPosition(tPtr
);
2307 if (buffer
[0] != 0 && !control_pressed
) {
2308 insertTextInteractively(tPtr
, buffer
, 1);
2309 updateCursorPosition(tPtr
);
2312 } else if (control_pressed
&& ksym
==XK_r
) {
2313 Bool i
= !tPtr
->flags
.rulerShown
;
2314 WMShowTextRuler(tPtr
, i
);
2315 tPtr
->flags
.rulerShown
= i
;
2317 else if (control_pressed
&& buffer
[0] == '\a')
2318 XBell(tPtr
->view
->screen
->display
, 0);
2321 if (!control_pressed
&& tPtr
->flags
.ownsSelection
)
2322 releaseSelection(tPtr
);
2327 pasteText(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
2328 void *cdata
, WMData
*data
)
2330 Text
*tPtr
= (Text
*)view
->self
;
2333 tPtr
->flags
.waitingForSelection
= 0;
2336 text
= (char*)WMDataBytes(data
);
2339 (tPtr
->parser
) (tPtr
, (void *) text
);
2340 layOutDocument(tPtr
);
2341 } else insertTextInteractively(tPtr
, text
, strlen(text
));
2342 updateCursorPosition(tPtr
);
2348 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
2353 (tPtr
->parser
) (tPtr
, (void *) text
);
2354 layOutDocument(tPtr
);
2355 } else insertTextInteractively(tPtr
, text
, n
);
2356 updateCursorPosition(tPtr
);
2368 handleActionEvents(XEvent
*event
, void *data
)
2370 Text
*tPtr
= (Text
*)data
;
2371 Display
*dpy
= event
->xany
.display
;
2375 switch (event
->type
) {
2377 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2378 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2379 tPtr
->flags
.extendSelection
= True
;
2383 if (tPtr
->flags
.focused
) {
2384 XGrabPointer(dpy
, W_VIEW(tPtr
)->window
, False
,
2385 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
2386 GrabModeAsync
, GrabModeAsync
, None
,
2387 tPtr
->view
->screen
->invisibleCursor
, CurrentTime
);
2388 tPtr
->flags
.pointerGrabbed
= True
;
2389 handleTextKeyPress(tPtr
, event
);
2394 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2395 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2396 tPtr
->flags
.extendSelection
= False
;
2398 /* end modify flag so selection can be extended */
2405 if (tPtr
->flags
.pointerGrabbed
) {
2406 tPtr
->flags
.pointerGrabbed
= False
;
2407 XUngrabPointer(dpy
, CurrentTime
);
2410 if(tPtr
->flags
.waitingForSelection
)
2413 if ((event
->xmotion
.state
& Button1Mask
)) {
2414 TextBlock
*tb
= tPtr
->currentTextBlock
;
2416 if(tPtr
->flags
.isOverGraphic
&& tb
&& tb
->graphic
&& !tb
->object
) {
2418 WMPixmap
*pixmap
= tb
->d
.pixmap
;
2419 char *types
[2] = {"application/X-image", NULL
};
2424 WMDragImageFromView(tPtr
->view
, pixmap
, types
,
2425 wmkpoint(event
->xmotion
.x_root
, event
->xmotion
.y_root
),
2430 if (!tPtr
->flags
.ownsSelection
) {
2431 WMCreateSelectionHandler(tPtr
->view
,
2432 XA_PRIMARY
, event
->xbutton
.time
,
2433 &selectionHandler
, NULL
);
2434 tPtr
->flags
.ownsSelection
= True
;
2437 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2441 mouseOverObject(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2447 if (tPtr
->flags
.pointerGrabbed
) {
2448 tPtr
->flags
.pointerGrabbed
= False
;
2449 XUngrabPointer(dpy
, CurrentTime
);
2453 if (tPtr
->flags
.waitingForSelection
)
2456 if (tPtr
->flags
.extendSelection
) {
2457 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2461 if (tPtr
->flags
.ownsSelection
)
2462 releaseSelection(tPtr
);
2465 if (event
->xbutton
.button
== Button1
) {
2467 if(WMIsDoubleClick(event
)) {
2468 TextBlock
*tb
= tPtr
->currentTextBlock
;
2470 tPtr
->lastClickTime
= event
->xbutton
.time
;
2471 if(tb
&& tb
->graphic
&& !tb
->object
) {
2472 char desc
[tb
->used
+1];
2473 memcpy(desc
, tb
->text
, tb
->used
);
2475 if(tPtr
->delegate
) {
2476 if(tPtr
->delegate
->didDoubleClickOnPicture
)
2477 (*tPtr
->delegate
->didDoubleClickOnPicture
)
2478 (tPtr
->delegate
, desc
);
2481 autoSelectText(tPtr
, 2);
2484 } else if(event
->xbutton
.time
- tPtr
->lastClickTime
2485 < WINGsConfiguration
.doubleClickDelay
) {
2486 tPtr
->lastClickTime
= event
->xbutton
.time
;
2487 autoSelectText(tPtr
, 3);
2491 if (!tPtr
->flags
.focused
) {
2492 WMSetFocusToWidget(tPtr
);
2493 tPtr
->flags
.focused
= True
;
2496 tPtr
->lastClickTime
= event
->xbutton
.time
;
2497 cursorToTextPosition(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2501 if (event
->xbutton
.button
2502 == WINGsConfiguration
.mouseWheelDown
) {
2503 WMScrollText(tPtr
, 16);
2507 if (event
->xbutton
.button
2508 == WINGsConfiguration
.mouseWheelUp
) {
2509 WMScrollText(tPtr
, -16);
2513 if (event
->xbutton
.button
== Button2
) {
2517 if (!tPtr
->flags
.editable
) {
2522 if (!WMRequestSelection(tPtr
->view
, XA_PRIMARY
, XA_STRING
,
2523 event
->xbutton
.time
, pasteText
, NULL
)) {
2525 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
2526 tPtr
->flags
.waitingForSelection
= 0;
2532 (tPtr
->parser
) (tPtr
, (void *) text
);
2533 layOutDocument(tPtr
);
2536 insertTextInteractively(tPtr
, text
, n
);
2540 NOTIFY(tPtr
, didChange
, WMTextDidChangeNotification
,
2541 (void*)WMInsertTextEvent
);
2543 updateCursorPosition(tPtr
);
2547 tPtr
->flags
.waitingForSelection
= True
;
2555 if (tPtr
->flags
.pointerGrabbed
) {
2556 tPtr
->flags
.pointerGrabbed
= False
;
2557 XUngrabPointer(dpy
, CurrentTime
);
2561 if (tPtr
->flags
.waitingForSelection
)
2569 handleEvents(XEvent
*event
, void *data
)
2571 Text
*tPtr
= (Text
*)data
;
2573 switch(event
->type
) {
2576 if (event
->xexpose
.count
!=0)
2580 if (!(W_VIEW(tPtr
->hS
))->flags
.realized
)
2581 WMRealizeWidget(tPtr
->hS
);
2585 if (!(W_VIEW(tPtr
->vS
))->flags
.realized
)
2586 WMRealizeWidget(tPtr
->vS
);
2590 if (!(W_VIEW(tPtr
->ruler
))->flags
.realized
)
2591 WMRealizeWidget(tPtr
->ruler
);
2596 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2602 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))
2605 tPtr
->flags
.focused
= True
;
2607 if (tPtr
->flags
.editable
&& !tPtr
->timerID
) {
2608 tPtr
->timerID
= WMAddTimerHandler(12+0*CURSOR_BLINK_ON_DELAY
,
2616 tPtr
->flags
.focused
= False
;
2619 if (tPtr
->timerID
) {
2620 WMDeleteTimerHandler(tPtr
->timerID
);
2621 tPtr
->timerID
= NULL
;
2630 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
2632 WMEmptyArray(tPtr
->gfxItems
);
2635 WMDeleteTimerHandler(tPtr
->timerID
);
2637 WMReleaseFont(tPtr
->dFont
);
2638 WMReleaseColor(tPtr
->dColor
);
2639 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
, CurrentTime
);
2640 WMRemoveNotificationObserver(tPtr
);
2651 insertPlainText(Text
*tPtr
, char *text
)
2658 mark
= strchr(start
, '\n');
2660 tb
= WMCreateTextBlockWithText(tPtr
,
2662 tPtr
->dColor
, tPtr
->flags
.first
, (int)(mark
-start
));
2664 tPtr
->flags
.first
= True
;
2666 if (start
&& strlen(start
)) {
2667 tb
= WMCreateTextBlockWithText(tPtr
, start
, tPtr
->dFont
,
2668 tPtr
->dColor
, tPtr
->flags
.first
, strlen(start
));
2670 tPtr
->flags
.first
= False
;
2674 if (tPtr
->flags
.prepend
)
2675 WMPrependTextBlock(tPtr
, tb
);
2677 WMAppendTextBlock(tPtr
, tb
);
2683 rulerMoveCallBack(WMWidget
*w
, void *self
)
2685 Text
*tPtr
= (Text
*)self
;
2689 if (W_CLASS(tPtr
) != WC_Text
)
2697 rulerReleaseCallBack(WMWidget
*w
, void *self
)
2699 Text
*tPtr
= (Text
*)self
;
2703 if (W_CLASS(tPtr
) != WC_Text
)
2711 draggingSourceOperation(WMView
*self
, Bool local
)
2713 return WDOperationCopy
;
2717 fetchDragData(WMView
*self
, char *type
)
2719 TextBlock
*tb
= ((WMText
*)self
->self
)->currentTextBlock
;
2726 printf("type is [%s]\n", type
);
2727 desc
= wmalloc(tb
->used
+1);
2728 memcpy(desc
, tb
->text
, tb
->used
);
2730 data
= WMCreateDataWithBytes(desc
, strlen(desc
)+1);
2738 static WMDragSourceProcs _DragSourceProcs
= {
2739 draggingSourceOperation
,
2747 draggingEntered(WMView
*self
, WMDraggingInfo
*info
)
2749 printf("draggingEntered\n");
2750 return WDOperationCopy
;
2755 draggingUpdated(WMView
*self
, WMDraggingInfo
*info
)
2757 return WDOperationCopy
;
2762 draggingExited(WMView
*self
, WMDraggingInfo
*info
)
2764 printf("draggingExited\n");
2768 prepareForDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2770 printf("prepareForDragOperation\n");
2778 receivedData(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
2779 void *cdata
, WMData
*data
)
2781 badbadbad
= wstrdup((char *)WMDataBytes(data
));
2785 /* when it's done in WINGs, remove this */
2788 requestDroppedData(WMView
*view
, WMDraggingInfo
*info
, char *type
)
2790 WMScreen
*scr
= W_VIEW_SCREEN(view
);
2792 if (!WMRequestSelection(scr
->dragInfo
.destView
,
2793 scr
->xdndSelectionAtom
,
2794 XInternAtom(scr
->display
, type
, False
),
2795 scr
->dragInfo
.timestamp
,
2796 receivedData
, &scr
->dragInfo
)) {
2797 wwarning("could not request data for dropped data");
2803 ev
.type
= ClientMessage
;
2804 ev
.xclient
.message_type
= scr
->xdndFinishedAtom
;
2805 ev
.xclient
.format
= 32;
2806 ev
.xclient
.window
= info
->destinationWindow
;
2807 ev
.xclient
.data
.l
[0] = 0;
2808 ev
.xclient
.data
.l
[1] = 0;
2809 ev
.xclient
.data
.l
[2] = 0;
2810 ev
.xclient
.data
.l
[3] = 0;
2811 ev
.xclient
.data
.l
[4] = 0;
2813 XSendEvent(scr
->display
, info
->sourceWindow
, False
, 0, &ev
);
2814 XFlush(scr
->display
);
2820 performDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2823 WMText
*tPtr
= (WMText
*)self
->self
;
2828 requestDroppedData(tPtr
->view
, info
, "application/X-color");
2829 color
= WMCreateNamedColor(W_VIEW_SCREEN(self
), badbadbad
, True
);
2831 WMSetTextSelectionColor(tPtr
, color
);
2832 WMReleaseColor(color
);
2841 concludeDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2843 printf("concludeDragOperation\n");
2847 static WMDragDestinationProcs _DragDestinationProcs
= {
2851 prepareForDragOperation
,
2852 performDragOperation
,
2853 concludeDragOperation
2858 getStream(WMText
*tPtr
, int sel
, int array
)
2860 TextBlock
*tb
= NULL
;
2862 unsigned long where
= 0;
2867 if (!(tb
= tPtr
->firstTextBlock
))
2871 (tPtr
->writer
) (tPtr
, (void *) text
);
2875 tb
= tPtr
->firstTextBlock
;
2878 if (!tb
->graphic
|| (tb
->graphic
&& !tPtr
->flags
.monoFont
)) {
2880 if (!sel
|| (tb
->graphic
&& tb
->selected
)) {
2882 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
)
2883 && tb
!= tPtr
->firstTextBlock
) {
2884 text
= wrealloc(text
, where
+1);
2885 text
[where
++] = '\n';
2891 if(tb
->graphic
&& array
) {
2892 text
= wrealloc(text
, where
+4);
2893 text
[where
++] = 0xFA;
2894 text
[where
++] = (tb
->used
>>8)&0x0ff;
2895 text
[where
++] = tb
->used
&0x0ff;
2896 text
[where
++] = tb
->allocated
; /* extra info */
2898 text
= wrealloc(text
, where
+tb
->used
);
2899 memcpy(&text
[where
], tb
->text
, tb
->used
);
2903 } else if (sel
&& tb
->selected
) {
2905 if (!tPtr
->flags
.ignoreNewLine
&& tb
->blank
) {
2906 text
= wrealloc(text
, where
+1);
2907 text
[where
++] = '\n';
2913 text
= wrealloc(text
, where
+(tb
->s_end
- tb
->s_begin
));
2914 memcpy(&text
[where
], &tb
->text
[tb
->s_begin
],
2915 tb
->s_end
- tb
->s_begin
);
2916 where
+= tb
->s_end
- tb
->s_begin
;
2921 _gSnext
:tb
= tb
->next
;
2924 /* +1 for the end of string, let's be nice */
2925 text
= wrealloc(text
, where
+1);
2932 releaseStreamObjects(void *data
)
2939 getStreamObjects(WMText
*tPtr
, int sel
)
2941 WMArray
*array
= WMCreateArrayWithDestructor(4, releaseStreamObjects
);
2945 char *start
, *fa
, *desc
;
2947 stream
= getStream(tPtr
, sel
, 1);
2954 fa
= strchr(start
, 0xFA);
2956 if((int)(fa
- start
)>0) {
2958 desc
[(int)(fa
- start
)] = 0;
2959 data
= WMCreateDataWithBytes((void *)desc
, (int)(fa
- start
));
2960 WMSetDataFormat(data
, TYPETEXT
);
2961 WMAddToArray(array
, (void *) data
);
2964 len
= *(fa
+1)*0xff + *(fa
+2);
2965 data
= WMCreateDataWithBytes((void *)(fa
+4), len
);
2966 WMSetDataFormat(data
, *(fa
+3));
2967 WMAddToArray(array
, (void *) data
);
2968 start
= fa
+ len
+ 4;
2971 if (start
&& strlen(start
)) {
2972 data
= WMCreateDataWithBytes((void *)start
, strlen(start
));
2973 WMSetDataFormat(data
, TYPETEXT
);
2974 WMAddToArray(array
, (void *) data
);
2986 WMCreateTextForDocumentType(WMWidget
*parent
, WMAction
*parser
, WMAction
*writer
)
2990 tPtr
= wmalloc(sizeof(Text
));
2991 memset(tPtr
, 0, sizeof(Text
));
2992 tPtr
->widgetClass
= WC_Text
;
2993 tPtr
->view
= W_CreateView(W_VIEW(parent
));
2995 perror("could not create text's view\n");
2999 tPtr
->view
->self
= tPtr
;
3000 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->textCursor
;
3001 tPtr
->view
->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3002 W_ResizeView(tPtr
->view
, 250, 200);
3004 tPtr
->dColor
= WMWhiteColor(tPtr
->view
->screen
);
3005 tPtr
->bgGC
= WMColorGC(tPtr
->dColor
);
3006 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->dColor
);
3007 WMReleaseColor(tPtr
->dColor
);
3009 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
3010 tPtr
->fgGC
= WMColorGC(tPtr
->dColor
);
3016 tPtr
->dFont
= WMRetainFont(WMSystemFontOfSize(tPtr
->view
->screen
, 12));
3018 tPtr
->view
->delegate
= &_TextViewDelegate
;
3020 tPtr
->delegate
= NULL
;
3023 tPtr
->timerID
= NULL
;
3026 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
3027 |EnterWindowMask
|LeaveWindowMask
|FocusChangeMask
,
3028 handleEvents
, tPtr
);
3030 WMCreateEventHandler(tPtr
->view
, ButtonReleaseMask
|ButtonPressMask
3031 |KeyReleaseMask
|KeyPressMask
|Button1MotionMask
,
3032 handleActionEvents
, tPtr
);
3034 WMAddNotificationObserver(ownershipObserver
, tPtr
,
3035 "_lostOwnership", tPtr
);
3037 WMSetViewDragSourceProcs(tPtr
->view
, &_DragSourceProcs
);
3038 WMSetViewDragDestinationProcs(tPtr
->view
, &_DragDestinationProcs
);
3042 char *types
[3] = {"application/X-color", "application/X-image", NULL
};
3043 WMRegisterViewForDraggedTypes(tPtr
->view
, types
);
3046 WMAddNotificationObserver(fontChanged
, tPtr
,
3047 "WMFontPanelDidChangeNotification", tPtr
);
3049 tPtr
->firstTextBlock
= NULL
;
3050 tPtr
->lastTextBlock
= NULL
;
3051 tPtr
->currentTextBlock
= NULL
;
3054 tPtr
->gfxItems
= WMCreateArray(4);
3056 tPtr
->parser
= parser
;
3057 tPtr
->writer
= writer
;
3059 tPtr
->sel
.x
= tPtr
->sel
.y
= 2;
3060 tPtr
->sel
.w
= tPtr
->sel
.h
= 0;
3062 tPtr
->clicked
.x
= tPtr
->clicked
.y
= 2;
3064 tPtr
->visible
.x
= tPtr
->visible
.y
= 2;
3065 tPtr
->visible
.h
= tPtr
->view
->size
.height
;
3066 tPtr
->visible
.w
= tPtr
->view
->size
.width
- 4;
3068 tPtr
->cursor
.x
= -23;
3071 tPtr
->docHeight
= 0;
3072 tPtr
->dBulletPix
= WMCreatePixmapFromXPMData(tPtr
->view
->screen
,
3074 tPtr
->db
= (Pixmap
) NULL
;
3075 tPtr
->bgPixmap
= NULL
;
3077 tPtr
->margins
= WMGetRulerMargins(NULL
);
3078 tPtr
->margins
->right
= tPtr
->visible
.w
;
3081 tPtr
->flags
.rulerShown
= False
;
3082 tPtr
->flags
.monoFont
= False
;
3083 tPtr
->flags
.focused
= False
;
3084 tPtr
->flags
.editable
= True
;
3085 tPtr
->flags
.ownsSelection
= False
;
3086 tPtr
->flags
.pointerGrabbed
= False
;
3087 tPtr
->flags
.extendSelection
= False
;
3088 tPtr
->flags
.frozen
= False
;
3089 tPtr
->flags
.cursorShown
= True
;
3090 tPtr
->flags
.acceptsGraphic
= False
;
3091 tPtr
->flags
.horizOnDemand
= False
;
3092 tPtr
->flags
.needsLayOut
= False
;
3093 tPtr
->flags
.ignoreNewLine
= False
;
3094 tPtr
->flags
.indentNewLine
= False
;
3095 tPtr
->flags
.laidOut
= False
;
3096 tPtr
->flags
.waitingForSelection
= False
;
3097 tPtr
->flags
.prepend
= False
;
3098 tPtr
->flags
.isOverGraphic
= False
;
3099 tPtr
->flags
.relief
= WRSunken
;
3100 tPtr
->flags
.isOverGraphic
= 0;
3101 tPtr
->flags
.alignment
= WALeft
;
3102 tPtr
->flags
.first
= True
;
3108 WMPrependTextStream(WMText
*tPtr
, char *text
)
3110 CHECK_CLASS(tPtr
, WC_Text
);
3113 if (tPtr
->flags
.ownsSelection
)
3114 releaseSelection(tPtr
);
3116 updateScrollers(tPtr
);
3120 tPtr
->flags
.prepend
= True
;
3121 if (text
&& tPtr
->parser
)
3122 (tPtr
->parser
) (tPtr
, (void *) text
);
3124 insertPlainText(tPtr
, text
);
3126 tPtr
->flags
.needsLayOut
= True
;
3128 if(!tPtr
->flags
.frozen
) {
3129 layOutDocument(tPtr
);
3135 WMAppendTextStream(WMText
*tPtr
, char *text
)
3137 CHECK_CLASS(tPtr
, WC_Text
);
3140 if (tPtr
->flags
.ownsSelection
)
3141 releaseSelection(tPtr
);
3143 updateScrollers(tPtr
);
3147 tPtr
->flags
.prepend
= False
;
3148 if (text
&& tPtr
->parser
)
3149 (tPtr
->parser
) (tPtr
, (void *) text
);
3151 insertPlainText(tPtr
, text
);
3153 tPtr
->flags
.needsLayOut
= True
;
3154 if(tPtr
->currentTextBlock
)
3155 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
3157 if(!tPtr
->flags
.frozen
) {
3158 layOutDocument(tPtr
);
3164 WMGetTextStream(WMText
*tPtr
)
3166 CHECK_CLASS(tPtr
, WC_Text
);
3167 return getStream(tPtr
, 0, 0);
3171 WMGetTextSelectedStream(WMText
*tPtr
)
3173 CHECK_CLASS(tPtr
, WC_Text
);
3174 return getStream(tPtr
, 1, 0);
3178 WMGetTextObjects(WMText
*tPtr
)
3180 CHECK_CLASS(tPtr
, WC_Text
);
3181 return getStreamObjects(tPtr
, 0);
3185 WMGetTextSelectedObjects(WMText
*tPtr
)
3187 CHECK_CLASS(tPtr
, WC_Text
);
3188 return getStreamObjects(tPtr
, 1);
3193 WMSetTextDelegate(WMText
*tPtr
, WMTextDelegate
*delegate
)
3195 CHECK_CLASS(tPtr
, WC_Text
);
3197 tPtr
->delegate
= delegate
;
3202 WMCreateTextBlockWithObject(WMText
*tPtr
, WMWidget
*w
,
3203 char *description
, WMColor
*color
,
3204 unsigned short first
, unsigned short extraInfo
)
3208 if (!w
|| !description
|| !color
)
3211 tb
= wmalloc(sizeof(TextBlock
));
3215 tb
->text
= wstrdup(description
);
3216 tb
->used
= strlen(description
);
3219 tb
->color
= WMRetainColor(color
);
3220 tb
->marginN
= newMargin(tPtr
, NULL
);
3221 tb
->allocated
= extraInfo
;
3226 tb
->underlined
= False
;
3227 tb
->selected
= False
;
3229 tb
->sections
= NULL
;
3239 WMCreateTextBlockWithPixmap(WMText
*tPtr
, WMPixmap
*p
,
3240 char *description
, WMColor
*color
,
3241 unsigned short first
, unsigned short extraInfo
)
3245 if (!p
|| !description
|| !color
)
3248 tb
= wmalloc(sizeof(TextBlock
));
3252 tb
->text
= wstrdup(description
);
3253 tb
->used
= strlen(description
);
3255 tb
->d
.pixmap
= WMRetainPixmap(p
);
3256 tb
->color
= WMRetainColor(color
);
3257 tb
->marginN
= newMargin(tPtr
, NULL
);
3258 tb
->allocated
= extraInfo
;
3263 tb
->underlined
= False
;
3264 tb
->selected
= False
;
3266 tb
->sections
= NULL
;
3276 WMCreateTextBlockWithText(WMText
*tPtr
, char *text
, WMFont
*font
, WMColor
*color
,
3277 unsigned short first
, unsigned short len
)
3281 if (!font
|| !color
)
3284 tb
= wmalloc(sizeof(TextBlock
));
3288 tb
->allocated
= reqBlockSize(len
);
3289 tb
->text
= (char *)wmalloc(tb
->allocated
);
3290 memset(tb
->text
, 0, tb
->allocated
);
3292 if (len
< 1|| !text
|| (*text
== '\n' && len
==1 )) {
3297 memcpy(tb
->text
, text
, len
);
3301 tb
->text
[tb
->used
] = 0;
3303 tb
->d
.font
= WMRetainFont(font
);
3304 tb
->color
= WMRetainColor(color
);
3305 tb
->marginN
= newMargin(tPtr
, NULL
);
3308 tb
->graphic
= False
;
3309 tb
->underlined
= False
;
3310 tb
->selected
= False
;
3312 tb
->sections
= NULL
;
3320 WMSetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int first
,
3321 unsigned int kanji
, unsigned int underlined
, int script
,
3322 WMRulerMargins
*margins
)
3324 TextBlock
*tb
= (TextBlock
*) vtb
;
3330 tb
->underlined
= underlined
;
3331 tb
->script
= script
;
3332 tb
->marginN
= newMargin(tPtr
, margins
);
3336 WMGetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int *first
,
3337 unsigned int *kanji
, unsigned int *underlined
, int *script
,
3338 WMRulerMargins
*margins
)
3340 TextBlock
*tb
= (TextBlock
*) vtb
;
3344 if (first
) *first
= tb
->first
;
3345 if (kanji
) *kanji
= tb
->kanji
;
3346 if (underlined
) *underlined
= tb
->underlined
;
3347 if (script
) *script
= tb
->script
;
3348 if (margins
) margins
= &tPtr
->margins
[tb
->marginN
];
3354 WMPrependTextBlock(WMText
*tPtr
, void *vtb
)
3356 TextBlock
*tb
= (TextBlock
*)vtb
;
3363 WMWidget
*w
= tb
->d
.widget
;
3364 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
3365 (W_VIEW(w
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3366 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3369 WMAddToArray(tPtr
->gfxItems
, (void *)tb
);
3371 } else tPtr
->tpos
= tb
->used
;
3373 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
3374 tb
->next
= tb
->prior
= NULL
;
3376 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
3377 = tPtr
->currentTextBlock
= tb
;
3382 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
3385 tb
->next
= tPtr
->currentTextBlock
;
3386 tb
->prior
= tPtr
->currentTextBlock
->prior
;
3387 if (tPtr
->currentTextBlock
->prior
)
3388 tPtr
->currentTextBlock
->prior
->next
= tb
;
3390 tPtr
->currentTextBlock
->prior
= tb
;
3392 tPtr
->firstTextBlock
= tb
;
3394 tPtr
->currentTextBlock
= tb
;
3399 WMAppendTextBlock(WMText
*tPtr
, void *vtb
)
3401 TextBlock
*tb
= (TextBlock
*)vtb
;
3408 WMWidget
*w
= tb
->d
.widget
;
3409 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
3410 (W_VIEW(w
))->attribs
.cursor
=
3411 tPtr
->view
->screen
->defaultCursor
;
3412 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3415 WMAddToArray(tPtr
->gfxItems
, (void *)tb
);
3417 } else tPtr
->tpos
= tb
->used
;
3419 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
3420 tb
->next
= tb
->prior
= NULL
;
3422 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
3423 = tPtr
->currentTextBlock
= tb
;
3428 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
3431 tb
->next
= tPtr
->currentTextBlock
->next
;
3432 tb
->prior
= tPtr
->currentTextBlock
;
3433 if (tPtr
->currentTextBlock
->next
)
3434 tPtr
->currentTextBlock
->next
->prior
= tb
;
3436 tPtr
->currentTextBlock
->next
= tb
;
3439 tPtr
->lastTextBlock
= tb
;
3441 tPtr
->currentTextBlock
= tb
;
3445 WMRemoveTextBlock(WMText
*tPtr
)
3447 TextBlock
*tb
= NULL
;
3449 if (!tPtr
|| !tPtr
->firstTextBlock
|| !tPtr
->lastTextBlock
3450 || !tPtr
->currentTextBlock
) {
3451 /* printf("cannot remove non existent TextBlock!\n"); */
3455 tb
= tPtr
->currentTextBlock
;
3457 WMRemoveFromArray(tPtr
->gfxItems
, (void *)tb
);
3460 WMUnmapWidget(tb
->d
.widget
);
3464 if (tPtr
->currentTextBlock
== tPtr
->firstTextBlock
) {
3465 if (tPtr
->currentTextBlock
->next
)
3466 tPtr
->currentTextBlock
->next
->prior
= NULL
;
3468 tPtr
->firstTextBlock
= tPtr
->currentTextBlock
->next
;
3469 tPtr
->currentTextBlock
= tPtr
->firstTextBlock
;
3471 } else if (tPtr
->currentTextBlock
== tPtr
->lastTextBlock
) {
3472 tPtr
->currentTextBlock
->prior
->next
= NULL
;
3473 tPtr
->lastTextBlock
= tPtr
->currentTextBlock
->prior
;
3474 tPtr
->currentTextBlock
= tPtr
->lastTextBlock
;
3476 tPtr
->currentTextBlock
->prior
->next
= tPtr
->currentTextBlock
->next
;
3477 tPtr
->currentTextBlock
->next
->prior
= tPtr
->currentTextBlock
->prior
;
3478 tPtr
->currentTextBlock
= tPtr
->currentTextBlock
->next
;
3485 WMDestroyTextBlock(WMText
*tPtr
, void *vtb
)
3487 TextBlock
*tb
= (TextBlock
*)vtb
;
3493 /* naturally, there's a danger to destroying
3494 widgets whose action brings us here:
3495 ie. press a button to destroy it... need to
3496 find a safer way. till then... this stays commented out */
3497 /* WMDestroyWidget(tb->d.widget);
3498 wfree(tb->d.widget); */
3499 tb
->d
.widget
= NULL
;
3501 WMReleasePixmap(tb
->d
.pixmap
);
3502 tb
->d
.pixmap
= NULL
;
3505 WMReleaseFont(tb
->d
.font
);
3508 WMReleaseColor(tb
->color
);
3509 if (tb
->sections
&& tb
->nsections
> 0)
3510 wfree(tb
->sections
);
3519 WMSetTextForegroundColor(WMText
*tPtr
, WMColor
*color
)
3525 tPtr
->fgGC
= WMColorGC(color
);
3527 tPtr
->fgGC
= WMColorGC(WMBlackColor(tPtr
->view
->screen
));
3533 WMSetTextBackgroundColor(WMText
*tPtr
, WMColor
*color
)
3539 tPtr
->bgGC
= WMColorGC(color
);
3540 W_SetViewBackgroundColor(tPtr
->view
, color
);
3542 tPtr
->bgGC
= WMColorGC(WMWhiteColor(tPtr
->view
->screen
));
3543 W_SetViewBackgroundColor(tPtr
->view
,
3544 WMWhiteColor(tPtr
->view
->screen
));
3550 void WMSetTextBackgroundPixmap(WMText
*tPtr
, WMPixmap
*pixmap
)
3556 WMReleasePixmap(tPtr
->bgPixmap
);
3559 tPtr
->bgPixmap
= WMRetainPixmap(pixmap
);
3561 tPtr
->bgPixmap
= NULL
;
3565 WMSetTextRelief(WMText
*tPtr
, WMReliefType relief
)
3569 tPtr
->flags
.relief
= relief
;
3570 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3574 WMSetTextHasHorizontalScroller(WMText
*tPtr
, Bool shouldhave
)
3579 if (shouldhave
&& !tPtr
->hS
) {
3580 tPtr
->hS
= WMCreateScroller(tPtr
);
3581 (W_VIEW(tPtr
->hS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3582 (W_VIEW(tPtr
->hS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3583 WMSetScrollerArrowsPosition(tPtr
->hS
, WSAMinEnd
);
3584 WMSetScrollerAction(tPtr
->hS
, scrollersCallBack
, tPtr
);
3585 WMMapWidget(tPtr
->hS
);
3586 } else if (!shouldhave
&& tPtr
->hS
) {
3587 WMUnmapWidget(tPtr
->hS
);
3588 WMDestroyWidget(tPtr
->hS
);
3594 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3599 WMSetTextHasRuler(WMText
*tPtr
, Bool shouldhave
)
3604 if(shouldhave
&& !tPtr
->ruler
) {
3605 tPtr
->ruler
= WMCreateRuler(tPtr
);
3606 (W_VIEW(tPtr
->ruler
))->attribs
.cursor
=
3607 tPtr
->view
->screen
->defaultCursor
;
3608 (W_VIEW(tPtr
->ruler
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3609 WMSetRulerReleaseAction(tPtr
->ruler
, rulerReleaseCallBack
, tPtr
);
3610 WMSetRulerMoveAction(tPtr
->ruler
, rulerMoveCallBack
, tPtr
);
3611 } else if(!shouldhave
&& tPtr
->ruler
) {
3612 WMShowTextRuler(tPtr
, False
);
3613 WMDestroyWidget(tPtr
->ruler
);
3616 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3620 WMShowTextRuler(WMText
*tPtr
, Bool show
)
3627 if(tPtr
->flags
.monoFont
)
3630 tPtr
->flags
.rulerShown
= show
;
3632 WMMapWidget(tPtr
->ruler
);
3634 WMUnmapWidget(tPtr
->ruler
);
3637 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3641 WMGetTextRulerShown(WMText
*tPtr
)
3649 return tPtr
->flags
.rulerShown
;
3654 WMSetTextHasVerticalScroller(WMText
*tPtr
, Bool shouldhave
)
3659 if (shouldhave
&& !tPtr
->vS
) {
3660 tPtr
->vS
= WMCreateScroller(tPtr
);
3661 (W_VIEW(tPtr
->vS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3662 (W_VIEW(tPtr
->vS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3663 WMSetScrollerArrowsPosition(tPtr
->vS
, WSAMaxEnd
);
3664 WMSetScrollerAction(tPtr
->vS
, scrollersCallBack
, tPtr
);
3665 WMMapWidget(tPtr
->vS
);
3666 } else if (!shouldhave
&& tPtr
->vS
) {
3667 WMUnmapWidget(tPtr
->vS
);
3668 WMDestroyWidget(tPtr
->vS
);
3674 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3680 WMScrollText(WMText
*tPtr
, int amount
)
3685 if (amount
== 0 || !tPtr
->view
->flags
.realized
)
3689 if (tPtr
->vpos
> 0) {
3690 if (tPtr
->vpos
> abs(amount
)) tPtr
->vpos
+= amount
;
3694 int limit
= tPtr
->docHeight
- tPtr
->visible
.h
;
3695 if (tPtr
->vpos
< limit
) {
3696 if (tPtr
->vpos
< limit
-amount
) tPtr
->vpos
+= amount
;
3697 else tPtr
->vpos
= limit
;
3701 if (scroll
&& tPtr
->vpos
!= tPtr
->prevVpos
) {
3702 updateScrollers(tPtr
);
3705 tPtr
->prevVpos
= tPtr
->vpos
;
3710 WMPageText(WMText
*tPtr
, Bool direction
)
3712 if (!tPtr
) return False
;
3713 if (!tPtr
->view
->flags
.realized
) return False
;
3715 return WMScrollText(tPtr
, direction
?tPtr
->visible
.h
:-tPtr
->visible
.h
);
3719 WMSetTextEditable(WMText
*tPtr
, Bool editable
)
3723 tPtr
->flags
.editable
= editable
;
3727 WMGetTextEditable(WMText
*tPtr
)
3731 return tPtr
->flags
.editable
;
3735 WMSetTextIndentNewLines(WMText
*tPtr
, Bool indent
)
3739 tPtr
->flags
.indentNewLine
= indent
;
3743 WMSetTextIgnoresNewline(WMText
*tPtr
, Bool ignore
)
3747 tPtr
->flags
.ignoreNewLine
= ignore
;
3751 WMGetTextIgnoresNewline(WMText
*tPtr
)
3755 return tPtr
->flags
.ignoreNewLine
;
3759 WMSetTextUsesMonoFont(WMText
*tPtr
, Bool mono
)
3765 if(tPtr
->flags
.rulerShown
)
3766 WMShowTextRuler(tPtr
, False
);
3767 if(tPtr
->flags
.alignment
!= WALeft
)
3768 tPtr
->flags
.alignment
= WALeft
;
3771 tPtr
->flags
.monoFont
= mono
;
3772 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3776 WMGetTextUsesMonoFont(WMText
*tPtr
)
3780 return tPtr
->flags
.monoFont
;
3785 WMSetTextDefaultFont(WMText
*tPtr
, WMFont
*font
)
3790 WMReleaseFont(tPtr
->dFont
);
3792 tPtr
->dFont
= WMRetainFont(font
);
3794 tPtr
->dFont
= WMRetainFont(WMSystemFontOfSize(tPtr
->view
->screen
, 12));
3798 WMGetTextDefaultFont(WMText
*tPtr
)
3803 return WMRetainFont(tPtr
->dFont
);
3807 WMSetTextDefaultColor(WMText
*tPtr
, WMColor
*color
)
3812 WMReleaseColor(tPtr
->dColor
);
3814 tPtr
->dColor
= WMRetainColor(color
);
3816 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
3820 WMGetTextDefaultColor(WMText
*tPtr
)
3825 return WMRetainColor(tPtr
->dColor
);
3829 WMSetTextAlignment(WMText
*tPtr
, WMAlignment alignment
)
3833 if(tPtr
->flags
.monoFont
)
3834 tPtr
->flags
.alignment
= WALeft
;
3836 tPtr
->flags
.alignment
= alignment
;
3841 WMGetTextInsertType(WMText
*tPtr
)
3845 return tPtr
->flags
.prepend
;
3850 WMSetTextSelectionColor(WMText
*tPtr
, WMColor
*color
)
3852 if (!tPtr
|| !color
)
3855 setSelectionProperty(tPtr
, NULL
, color
, -1);
3859 WMGetTextSelectionColor(WMText
*tPtr
)
3866 tb
= tPtr
->currentTextBlock
;
3868 if (!tb
|| !tPtr
->flags
.ownsSelection
)
3879 WMSetTextSelectionFont(WMText
*tPtr
, WMFont
*font
)
3884 setSelectionProperty(tPtr
, font
, NULL
, -1) ;
3888 WMGetTextSelectionFont(WMText
*tPtr
)
3895 tb
= tPtr
->currentTextBlock
;
3897 if (!tb
|| !tPtr
->flags
.ownsSelection
)
3904 tb
= getFirstNonGraphicBlockFor(tb
, 1);
3908 return (tb
->selected
? tb
->d
.font
: NULL
);
3913 WMSetTextSelectionUnderlined(WMText
*tPtr
, int underlined
)
3915 if (!tPtr
|| (underlined
!=0 && underlined
!=1))
3918 setSelectionProperty(tPtr
, NULL
, NULL
, underlined
);
3923 WMGetTextSelectionUnderlined(WMText
*tPtr
)
3930 tb
= tPtr
->currentTextBlock
;
3932 if (!tb
|| !tPtr
->flags
.ownsSelection
)
3938 return tb
->underlined
;
3943 WMFreezeText(WMText
*tPtr
)
3948 tPtr
->flags
.frozen
= True
;
3953 WMThawText(WMText
*tPtr
)
3958 tPtr
->flags
.frozen
= False
;
3960 if(tPtr
->flags
.monoFont
) {
3961 int j
, c
= WMGetArrayItemCount(tPtr
->gfxItems
);
3964 /* make sure to unmap widgets no matter where they are */
3965 /* they'll be later remapped if needed by paintText */
3966 for(j
=0; j
<c
; j
++) {
3967 if ((tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
))) {
3968 if (tb
->object
&& ((W_VIEW(tb
->d
.widget
))->flags
.mapped
))
3969 WMUnmapWidget(tb
->d
.widget
);
3975 tPtr
->flags
.laidOut
= False
;
3976 layOutDocument(tPtr
);
3977 updateScrollers(tPtr
);
3979 tPtr
->flags
.needsLayOut
= False
;
3983 /* find first occurence of a string */
3985 mystrstr(char *haystack
, char *needle
, unsigned short len
, char *end
,
3990 if(!haystack
|| !needle
|| !end
)
3993 for (ptr
= haystack
; ptr
< end
; ptr
++) {
3995 if (*ptr
== *needle
&& !strncmp(ptr
, needle
, len
))
3999 if (tolower(*ptr
) == tolower(*needle
) &&
4000 !strncasecmp(ptr
, needle
, len
))
4008 /* find last occurence of a string */
4010 mystrrstr(char *haystack
, char *needle
, unsigned short len
, char *end
,
4015 if(!haystack
|| !needle
|| !end
)
4018 for (ptr
= haystack
-2; ptr
> end
; ptr
--) {
4020 if (*ptr
== *needle
&& !strncmp(ptr
, needle
, len
))
4023 if (tolower(*ptr
) == tolower(*needle
) &&
4024 !strncasecmp(ptr
, needle
, len
))
4034 WMFindInTextStream(WMText
*tPtr
, char *needle
, Bool direction
,
4041 if (!tPtr
|| !needle
)
4045 if (! (tb
= tPtr
->currentTextBlock
)) {
4046 if (! (tb
= ( (direction
> 0) ?
4047 tPtr
->firstTextBlock
: tPtr
->lastTextBlock
) ) ){
4051 /* if(tb != ((direction>0) ?tPtr->firstTextBlock : tPtr->lastTextBlock))
4052 tb = (direction>0) ? tb->next : tb->prior; */
4053 if(tb
!= tPtr
->lastTextBlock
)
4057 tb
= tPtr
->currentTextBlock
;
4065 if(pos
+1 < tb
->used
)
4068 if(tb
->used
- pos
> 0 && pos
> 0) {
4069 mark
= mystrstr(&tb
->text
[pos
], needle
,
4070 strlen(needle
), &tb
->text
[tb
->used
], caseSensitive
);
4083 mark
= mystrrstr(&tb
->text
[pos
], needle
,
4084 strlen(needle
), tb
->text
, caseSensitive
);
4096 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
4098 tPtr
->tpos
= (int)(mark
- tb
->text
);
4099 tPtr
->currentTextBlock
= tb
;
4100 updateCursorPosition(tPtr
);
4101 tPtr
->sel
.y
= tPtr
->cursor
.y
+5;
4102 tPtr
->sel
.h
= tPtr
->cursor
.h
-10;
4103 tPtr
->sel
.x
= tPtr
->cursor
.x
+1;
4104 tPtr
->sel
.w
= WMIN(WMWidthOfString(font
,
4105 &tb
->text
[tPtr
->tpos
], strlen(needle
)),
4106 tPtr
->docWidth
- tPtr
->sel
.x
);
4107 tPtr
->flags
.ownsSelection
= True
;
4114 tb
= (direction
>0) ? tb
->next
: tb
->prior
;
4116 pos
= (direction
>0) ? 0 : tb
->used
;
4125 WMReplaceTextSelection(WMText
*tPtr
, char *replacement
)
4130 if (!tPtr
->flags
.ownsSelection
)
4133 removeSelection(tPtr
);
4136 insertTextInteractively(tPtr
, replacement
, strlen(replacement
));
4137 updateCursorPosition(tPtr
);