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)
1737 textDidResize(W_ViewDelegate
*self
, WMView
*view
)
1739 Text
*tPtr
= (Text
*)view
->self
;
1740 unsigned short w
= tPtr
->view
->size
.width
;
1741 unsigned short h
= tPtr
->view
->size
.height
;
1742 unsigned short rh
= 0, vw
= 0, rel
;
1744 rel
= (tPtr
->flags
.relief
== WRFlat
);
1746 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
) {
1747 WMMoveWidget(tPtr
->ruler
, 2, 2);
1748 WMResizeWidget(tPtr
->ruler
, w
- 4, 40);
1753 WMMoveWidget(tPtr
->vS
, 1 - (rel
?1:0), rh
+ 1 - (rel
?1:0));
1754 WMResizeWidget(tPtr
->vS
, 20, h
- rh
- 2 + (rel
?2:0));
1756 WMSetRulerOffset(tPtr
->ruler
,22);
1757 } else WMSetRulerOffset(tPtr
->ruler
, 2);
1761 WMMoveWidget(tPtr
->hS
, vw
, h
- 21);
1762 WMResizeWidget(tPtr
->hS
, w
- vw
- 1, 20);
1764 WMMoveWidget(tPtr
->hS
, vw
+1, h
- 21);
1765 WMResizeWidget(tPtr
->hS
, w
- vw
- 2, 20);
1769 tPtr
->visible
.x
= (tPtr
->vS
)?24:4;
1770 tPtr
->visible
.y
= (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)?43:3;
1771 tPtr
->visible
.w
= tPtr
->view
->size
.width
- tPtr
->visible
.x
- 8;
1772 tPtr
->visible
.h
= tPtr
->view
->size
.height
- tPtr
->visible
.y
;
1773 tPtr
->visible
.h
-= (tPtr
->hS
)?20:0;
1774 tPtr
->margins
[0].right
= tPtr
->visible
.w
;
1776 if (tPtr
->view
->flags
.realized
) {
1779 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
1780 tPtr
->db
= (Pixmap
) NULL
;
1783 if (tPtr
->visible
.w
< 40)
1784 tPtr
->visible
.w
= 40;
1785 if (tPtr
->visible
.h
< 20)
1786 tPtr
->visible
.h
= 20;
1789 tPtr
->db
= XCreatePixmap(tPtr
->view
->screen
->display
,
1790 tPtr
->view
->window
, tPtr
->visible
.w
,
1791 tPtr
->visible
.h
, tPtr
->view
->screen
->depth
);
1798 W_ViewDelegate _TextViewDelegate
=
1806 /* nice, divisble-by-16 blocks */
1807 static inline unsigned short
1808 reqBlockSize(unsigned short requested
)
1810 return requested
+ 16 - (requested
%16);
1815 clearText(Text
*tPtr
)
1817 tPtr
->vpos
= tPtr
->hpos
= 0;
1818 tPtr
->docHeight
= tPtr
->docWidth
= 0;
1819 tPtr
->cursor
.x
= -23;
1821 if (!tPtr
->firstTextBlock
)
1824 while (tPtr
->currentTextBlock
)
1825 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1827 tPtr
->firstTextBlock
= NULL
;
1828 tPtr
->currentTextBlock
= NULL
;
1829 tPtr
->lastTextBlock
= NULL
;
1830 WMEmptyArray(tPtr
->gfxItems
);
1834 deleteTextInteractively(Text
*tPtr
, KeySym ksym
)
1837 Bool back
= (Bool
) (ksym
== XK_BackSpace
);
1841 if (!tPtr
->flags
.editable
) {
1842 XBell(tPtr
->view
->screen
->display
, 0);
1846 if ( !(tb
= tPtr
->currentTextBlock
) )
1849 if (tPtr
->flags
.ownsSelection
) {
1850 if(removeSelection(tPtr
))
1851 layOutDocument(tPtr
);
1855 wasFirst
= tb
->first
;
1856 if (back
&& tPtr
->tpos
< 1) {
1858 if(tb
->prior
->blank
) {
1859 tPtr
->currentTextBlock
= tb
->prior
;
1860 WMRemoveTextBlock(tPtr
);
1861 tPtr
->currentTextBlock
= tb
;
1863 layOutDocument(tPtr
);
1867 TextBlock
*prior
= tb
->prior
;
1868 tPtr
->currentTextBlock
= tb
;
1869 WMRemoveTextBlock(tPtr
);
1875 tPtr
->tpos
= tb
->used
;
1876 tPtr
->currentTextBlock
= tb
;
1880 tb
->next
->first
= False
;
1881 layOutDocument(tPtr
);
1888 if ( (tb
->used
> 0) && ((back
?tPtr
->tpos
> 0:1))
1889 && (tPtr
->tpos
<= tb
->used
) && !tb
->graphic
) {
1892 memmove(&(tb
->text
[tPtr
->tpos
]),
1893 &(tb
->text
[tPtr
->tpos
+ 1]), tb
->used
- tPtr
->tpos
);
1898 if ( (back
? (tPtr
->tpos
< 1 && !done
) : ( tPtr
->tpos
>= tb
->used
))
1901 TextBlock
*sibling
= (back
? tb
->prior
: tb
->next
);
1903 if(tb
->used
== 0 || tb
->graphic
)
1904 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1907 tPtr
->currentTextBlock
= sibling
;
1908 tPtr
->tpos
= (back
? sibling
->used
: 0);
1912 layOutDocument(tPtr
);
1917 insertTextInteractively(Text
*tPtr
, char *text
, int len
)
1920 char *newline
= NULL
;
1922 if (!tPtr
->flags
.editable
) {
1923 XBell(tPtr
->view
->screen
->display
, 0);
1927 if (len
< 1 || !text
)
1931 if(tPtr
->flags
.ignoreNewLine
&& *text
== '\n' && len
== 1)
1935 if (tPtr
->flags
.ownsSelection
)
1936 removeSelection(tPtr
);
1939 if (tPtr
->flags
.ignoreNewLine
) {
1941 for(i
=0; i
<len
; i
++) {
1942 if (text
[i
] == '\n')
1947 tb
= tPtr
->currentTextBlock
;
1948 if (!tb
|| tb
->graphic
) {
1950 WMAppendTextStream(tPtr
, text
);
1951 layOutDocument(tPtr
);
1955 if ((newline
= strchr(text
, '\n'))) {
1956 int nlen
= (int)(newline
-text
);
1957 int s
= tb
->used
- tPtr
->tpos
;
1959 if (!tb
->blank
&& nlen
>0) {
1961 memcpy(save
, &tb
->text
[tPtr
->tpos
], s
);
1962 tb
->used
-= (tb
->used
- tPtr
->tpos
);
1964 insertTextInteractively(tPtr
, text
, nlen
);
1966 WMAppendTextStream(tPtr
, newline
);
1968 insertTextInteractively(tPtr
, save
, s
);
1971 if (tPtr
->tpos
>0 && tPtr
->tpos
< tb
->used
1972 && !tb
->graphic
&& tb
->text
) {
1974 void *ntb
= WMCreateTextBlockWithText(
1975 tPtr
, &tb
->text
[tPtr
->tpos
],
1976 tb
->d
.font
, tb
->color
, True
, tb
->used
- tPtr
->tpos
);
1977 tb
->used
= tPtr
->tpos
;
1978 WMAppendTextBlock(tPtr
, ntb
);
1981 } else if (tPtr
->tpos
== tb
->used
|| tPtr
->tpos
== 0) {
1982 if(tPtr
->flags
.indentNewLine
) {
1983 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
1984 " ", tb
->d
.font
, tb
->color
, True
, 4));
1987 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
1988 NULL
, tb
->d
.font
, tb
->color
, True
, 0));
1995 if (tb
->used
+ len
>= tb
->allocated
) {
1996 tb
->allocated
= reqBlockSize(tb
->used
+len
);
1997 tb
->text
= wrealloc(tb
->text
, tb
->allocated
);
2001 memcpy(tb
->text
, text
, len
);
2004 tb
->text
[tb
->used
] = 0;
2008 memmove(&(tb
->text
[tPtr
->tpos
+len
]), &tb
->text
[tPtr
->tpos
],
2009 tb
->used
-tPtr
->tpos
+1);
2010 memmove(&tb
->text
[tPtr
->tpos
], text
, len
);
2013 tb
->text
[tb
->used
] = 0;
2018 layOutDocument(tPtr
);
2023 selectRegion(Text
*tPtr
, int x
, int y
)
2029 y
+= (tPtr
->flags
.rulerShown
? 40: 0);
2032 y
-= 10; /* the original offset */
2034 x
-= tPtr
->visible
.x
-2;
2038 tPtr
->sel
.x
= WMAX(0, WMIN(tPtr
->clicked
.x
, x
));
2039 tPtr
->sel
.w
= abs(tPtr
->clicked
.x
- x
);
2040 tPtr
->sel
.y
= WMAX(0, WMIN(tPtr
->clicked
.y
, y
));
2041 tPtr
->sel
.h
= abs(tPtr
->clicked
.y
- y
);
2043 tPtr
->flags
.ownsSelection
= True
;
2049 releaseSelection(Text
*tPtr
)
2051 TextBlock
*tb
= tPtr
->firstTextBlock
;
2054 tb
->selected
= False
;
2057 tPtr
->flags
.ownsSelection
= False
;
2058 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
,
2066 requestHandler(WMView
*view
, Atom selection
, Atom target
, void *cdata
,
2069 Text
*tPtr
= view
->self
;
2070 Display
*dpy
= tPtr
->view
->screen
->display
;
2072 Atom TEXT
= XInternAtom(dpy
, "TEXT", False
);
2073 Atom COMPOUND_TEXT
= XInternAtom(dpy
, "COMPOUND_TEXT", False
);
2074 WMData
*data
= NULL
;
2077 if (target
== XA_STRING
|| target
== TEXT
|| target
== COMPOUND_TEXT
) {
2078 char *text
= WMGetTextSelectedStream(tPtr
);
2081 data
= WMCreateDataWithBytes(text
, strlen(text
));
2082 WMSetDataFormat(data
, TYPETEXT
);
2086 } else printf("didn't get it\n");
2088 _TARGETS
= XInternAtom(dpy
, "TARGETS", False
);
2089 if (target
== _TARGETS
) {
2092 ptr
= wmalloc(4 * sizeof(Atom
));
2096 ptr
[3] = COMPOUND_TEXT
;
2098 data
= WMCreateDataWithBytes(ptr
, 4*4);
2099 WMSetDataFormat(data
, 32);
2109 lostHandler(WMView
*view
, Atom selection
, void *cdata
)
2111 releaseSelection((WMText
*)view
->self
);
2114 static WMSelectionProcs selectionHandler
= {
2115 requestHandler
, lostHandler
, NULL
2120 ownershipObserver(void *observerData
, WMNotification
*notification
)
2122 if (observerData
!= WMGetNotificationClientData(notification
))
2123 lostHandler(WMWidgetView(observerData
), XA_PRIMARY
, NULL
);
2127 autoSelectText(Text
*tPtr
, int clicks
)
2131 char *mark
= NULL
, behind
, ahead
;
2133 if(!(tb
= tPtr
->currentTextBlock
))
2139 switch(tb
->text
[tPtr
->tpos
]) {
2142 case '<': case '>': behind = '<'; ahead = '>'; break;
2143 case '{': case '}': behind = '{'; ahead = '}'; break;
2144 case '[': case ']': behind = '['; ahead = ']'; break;
2146 default: behind
= ahead
= ' ';
2149 tPtr
->sel
.y
= tPtr
->cursor
.y
+5;
2150 tPtr
->sel
.h
= 6;/*tPtr->cursor.h-10;*/
2153 tPtr
->sel
.x
= tb
->sections
[0].x
;
2154 tPtr
->sel
.w
= tb
->sections
[0].w
;
2156 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
2159 while(start
> 0 && tb
->text
[start
-1] != behind
)
2163 if(tPtr
->tpos
> start
){
2164 x
-= WMWidthOfString(font
, &tb
->text
[start
],
2165 tPtr
->tpos
- start
);
2167 tPtr
->sel
.x
= (x
<0?0:x
)+1;
2169 if((mark
= strchr(&tb
->text
[start
], ahead
))) {
2170 tPtr
->sel
.w
= WMWidthOfString(font
, &tb
->text
[start
],
2171 (int)(mark
- &tb
->text
[start
]));
2172 } else if(tb
->used
> start
) {
2173 tPtr
->sel
.w
= WMWidthOfString(font
, &tb
->text
[start
],
2178 } else if(clicks
== 3) {
2179 TextBlock
*cur
= tb
;
2181 while(tb
&& !tb
->first
) {
2184 tPtr
->sel
.y
= tb
->sections
[0]._y
;
2187 while(tb
->next
&& !tb
->next
->first
) {
2190 tPtr
->sel
.h
= tb
->sections
[tb
->nsections
-1]._y
2194 tPtr
->sel
.w
= tPtr
->docWidth
;
2195 tPtr
->clicked
.x
= 0; /* only for now, fix sel. code */
2198 if (!tPtr
->flags
.ownsSelection
) {
2199 WMCreateSelectionHandler(tPtr
->view
,
2200 XA_PRIMARY
, tPtr
->lastClickTime
, &selectionHandler
, NULL
);
2201 tPtr
->flags
.ownsSelection
= True
;
2209 fontChanged(void *observerData
, WMNotification
*notification
)
2211 WMText
*tPtr
= (WMText
*) observerData
;
2212 WMFont
*font
= (WMFont
*)WMGetNotificationClientData(notification
);
2213 printf("fontChanged\n");
2218 if (tPtr
->flags
.ownsSelection
)
2219 WMSetTextSelectionFont(tPtr
, font
);
2224 handleTextKeyPress(Text
*tPtr
, XEvent
*event
)
2228 int control_pressed
= False
;
2229 TextBlock
*tb
= NULL
;
2231 if (((XKeyEvent
*) event
)->state
& ControlMask
)
2232 control_pressed
= True
;
2233 buffer
[XLookupString(&event
->xkey
, buffer
, 1, &ksym
, NULL
)] = 0;
2238 if(!(tb
= tPtr
->currentTextBlock
))
2244 L_imaGFX
: if(tb
->prior
) {
2245 tPtr
->currentTextBlock
= tb
->prior
;
2246 tPtr
->tpos
= tPtr
->currentTextBlock
->used
-1;
2247 } else tPtr
->tpos
= 0;
2248 } else tPtr
->tpos
--;
2249 updateCursorPosition(tPtr
);
2254 if(!(tb
= tPtr
->currentTextBlock
))
2258 if(tPtr
->tpos
== tb
->used
) {
2259 R_imaGFX
: if(tb
->next
) {
2260 tPtr
->currentTextBlock
= tb
->next
;
2262 } else tPtr
->tpos
= tb
->used
;
2263 } else tPtr
->tpos
++;
2264 updateCursorPosition(tPtr
);
2269 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
2270 tPtr
->clicked
.y
+ tPtr
->cursor
.h
- tPtr
->vpos
);
2275 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
2276 tPtr
->visible
.y
+ tPtr
->cursor
.y
- tPtr
->vpos
- 3);
2285 deleteTextInteractively(tPtr
, ksym
);
2286 updateCursorPosition(tPtr
);
2292 control_pressed
= True
;
2296 insertTextInteractively(tPtr
, " ", 4);
2297 updateCursorPosition(tPtr
);
2304 if (buffer
[0] != 0 && !control_pressed
) {
2305 insertTextInteractively(tPtr
, buffer
, 1);
2306 updateCursorPosition(tPtr
);
2309 } else if (control_pressed
&& ksym
==XK_r
) {
2310 Bool i
= !tPtr
->flags
.rulerShown
;
2311 WMShowTextRuler(tPtr
, i
);
2312 tPtr
->flags
.rulerShown
= i
;
2314 else if (control_pressed
&& buffer
[0] == '\a')
2315 XBell(tPtr
->view
->screen
->display
, 0);
2318 if (!control_pressed
&& tPtr
->flags
.ownsSelection
)
2319 releaseSelection(tPtr
);
2324 pasteText(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
2325 void *cdata
, WMData
*data
)
2327 Text
*tPtr
= (Text
*)view
->self
;
2330 tPtr
->flags
.waitingForSelection
= 0;
2333 text
= (char*)WMDataBytes(data
);
2336 (tPtr
->parser
) (tPtr
, (void *) text
);
2337 layOutDocument(tPtr
);
2338 } else insertTextInteractively(tPtr
, text
, strlen(text
));
2339 updateCursorPosition(tPtr
);
2345 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
2350 (tPtr
->parser
) (tPtr
, (void *) text
);
2351 layOutDocument(tPtr
);
2352 } else insertTextInteractively(tPtr
, text
, n
);
2353 updateCursorPosition(tPtr
);
2365 handleActionEvents(XEvent
*event
, void *data
)
2367 Text
*tPtr
= (Text
*)data
;
2368 Display
*dpy
= event
->xany
.display
;
2372 switch (event
->type
) {
2374 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2375 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2376 tPtr
->flags
.extendSelection
= True
;
2380 if (tPtr
->flags
.focused
) {
2381 XGrabPointer(dpy
, W_VIEW(tPtr
)->window
, False
,
2382 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
2383 GrabModeAsync
, GrabModeAsync
, None
,
2384 tPtr
->view
->screen
->invisibleCursor
, CurrentTime
);
2385 tPtr
->flags
.pointerGrabbed
= True
;
2386 handleTextKeyPress(tPtr
, event
);
2391 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2392 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2393 tPtr
->flags
.extendSelection
= False
;
2395 /* end modify flag so selection can be extended */
2402 if (tPtr
->flags
.pointerGrabbed
) {
2403 tPtr
->flags
.pointerGrabbed
= False
;
2404 XUngrabPointer(dpy
, CurrentTime
);
2407 if(tPtr
->flags
.waitingForSelection
)
2410 if ((event
->xmotion
.state
& Button1Mask
)) {
2411 TextBlock
*tb
= tPtr
->currentTextBlock
;
2413 if(tPtr
->flags
.isOverGraphic
&& tb
&& tb
->graphic
&& !tb
->object
) {
2415 WMPixmap
*pixmap
= tb
->d
.pixmap
;
2416 char *types
[2] = {"application/X-image", NULL
};
2421 WMDragImageFromView(tPtr
->view
, pixmap
, types
,
2422 wmkpoint(event
->xmotion
.x_root
, event
->xmotion
.y_root
),
2427 if (!tPtr
->flags
.ownsSelection
) {
2428 WMCreateSelectionHandler(tPtr
->view
,
2429 XA_PRIMARY
, event
->xbutton
.time
,
2430 &selectionHandler
, NULL
);
2431 tPtr
->flags
.ownsSelection
= True
;
2434 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2438 mouseOverObject(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2444 if (tPtr
->flags
.pointerGrabbed
) {
2445 tPtr
->flags
.pointerGrabbed
= False
;
2446 XUngrabPointer(dpy
, CurrentTime
);
2450 if (tPtr
->flags
.waitingForSelection
)
2453 if (tPtr
->flags
.extendSelection
) {
2454 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2458 if (tPtr
->flags
.ownsSelection
)
2459 releaseSelection(tPtr
);
2462 if (event
->xbutton
.button
== Button1
) {
2464 if(WMIsDoubleClick(event
)) {
2465 TextBlock
*tb
= tPtr
->currentTextBlock
;
2467 tPtr
->lastClickTime
= event
->xbutton
.time
;
2468 if(tb
&& tb
->graphic
&& !tb
->object
) {
2469 char desc
[tb
->used
+1];
2470 memcpy(desc
, tb
->text
, tb
->used
);
2472 if(tPtr
->delegate
) {
2473 if(tPtr
->delegate
->didDoubleClickOnPicture
)
2474 (*tPtr
->delegate
->didDoubleClickOnPicture
)
2475 (tPtr
->delegate
, desc
);
2478 autoSelectText(tPtr
, 2);
2481 } else if(event
->xbutton
.time
- tPtr
->lastClickTime
2482 < WINGsConfiguration
.doubleClickDelay
) {
2483 tPtr
->lastClickTime
= event
->xbutton
.time
;
2484 autoSelectText(tPtr
, 3);
2488 if (!tPtr
->flags
.focused
) {
2489 WMSetFocusToWidget(tPtr
);
2490 tPtr
->flags
.focused
= True
;
2493 tPtr
->lastClickTime
= event
->xbutton
.time
;
2494 cursorToTextPosition(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2498 if (event
->xbutton
.button
2499 == WINGsConfiguration
.mouseWheelDown
) {
2500 WMScrollText(tPtr
, 16);
2504 if (event
->xbutton
.button
2505 == WINGsConfiguration
.mouseWheelUp
) {
2506 WMScrollText(tPtr
, -16);
2510 if (event
->xbutton
.button
== Button2
) {
2514 if (!tPtr
->flags
.editable
) {
2519 if (!WMRequestSelection(tPtr
->view
, XA_PRIMARY
, XA_STRING
,
2520 event
->xbutton
.time
, pasteText
, NULL
)) {
2522 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
2523 tPtr
->flags
.waitingForSelection
= 0;
2529 (tPtr
->parser
) (tPtr
, (void *) text
);
2530 layOutDocument(tPtr
);
2533 insertTextInteractively(tPtr
, text
, n
);
2537 NOTIFY(tPtr
, didChange
, WMTextDidChangeNotification
,
2538 (void*)WMInsertTextEvent
);
2540 updateCursorPosition(tPtr
);
2544 tPtr
->flags
.waitingForSelection
= True
;
2552 if (tPtr
->flags
.pointerGrabbed
) {
2553 tPtr
->flags
.pointerGrabbed
= False
;
2554 XUngrabPointer(dpy
, CurrentTime
);
2558 if (tPtr
->flags
.waitingForSelection
)
2566 handleEvents(XEvent
*event
, void *data
)
2568 Text
*tPtr
= (Text
*)data
;
2570 switch(event
->type
) {
2573 if (event
->xexpose
.count
!=0)
2577 if (!(W_VIEW(tPtr
->hS
))->flags
.realized
)
2578 WMRealizeWidget(tPtr
->hS
);
2582 if (!(W_VIEW(tPtr
->vS
))->flags
.realized
)
2583 WMRealizeWidget(tPtr
->vS
);
2587 if (!(W_VIEW(tPtr
->ruler
))->flags
.realized
)
2588 WMRealizeWidget(tPtr
->ruler
);
2593 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2599 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))
2602 tPtr
->flags
.focused
= True
;
2604 if (tPtr
->flags
.editable
&& !tPtr
->timerID
) {
2605 tPtr
->timerID
= WMAddTimerHandler(12+0*CURSOR_BLINK_ON_DELAY
,
2613 tPtr
->flags
.focused
= False
;
2616 if (tPtr
->timerID
) {
2617 WMDeleteTimerHandler(tPtr
->timerID
);
2618 tPtr
->timerID
= NULL
;
2627 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
2629 WMEmptyArray(tPtr
->gfxItems
);
2632 WMDeleteTimerHandler(tPtr
->timerID
);
2634 WMReleaseFont(tPtr
->dFont
);
2635 WMReleaseColor(tPtr
->dColor
);
2636 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
, CurrentTime
);
2637 WMRemoveNotificationObserver(tPtr
);
2648 insertPlainText(Text
*tPtr
, char *text
)
2655 mark
= strchr(start
, '\n');
2657 tb
= WMCreateTextBlockWithText(tPtr
,
2659 tPtr
->dColor
, tPtr
->flags
.first
, (int)(mark
-start
));
2661 tPtr
->flags
.first
= True
;
2663 if (start
&& strlen(start
)) {
2664 tb
= WMCreateTextBlockWithText(tPtr
, start
, tPtr
->dFont
,
2665 tPtr
->dColor
, tPtr
->flags
.first
, strlen(start
));
2667 tPtr
->flags
.first
= False
;
2671 if (tPtr
->flags
.prepend
)
2672 WMPrependTextBlock(tPtr
, tb
);
2674 WMAppendTextBlock(tPtr
, tb
);
2682 rulerMoveCallBack(WMWidget
*w
, void *self
)
2684 Text
*tPtr
= (Text
*)self
;
2687 if (W_CLASS(tPtr
) != WC_Text
)
2695 rulerReleaseCallBack(WMWidget
*w
, void *self
)
2697 Text
*tPtr
= (Text
*)self
;
2700 if (W_CLASS(tPtr
) != WC_Text
)
2708 draggingSourceOperation(WMView
*self
, Bool local
)
2710 return WDOperationCopy
;
2714 fetchDragData(WMView
*self
, char *type
)
2716 TextBlock
*tb
= ((WMText
*)self
->self
)->currentTextBlock
;
2723 printf("type is [%s]\n", type
);
2724 desc
= wmalloc(tb
->used
+1);
2725 memcpy(desc
, tb
->text
, tb
->used
);
2727 data
= WMCreateDataWithBytes(desc
, strlen(desc
)+1);
2735 static WMDragSourceProcs _DragSourceProcs
= {
2736 draggingSourceOperation
,
2744 draggingEntered(WMView
*self
, WMDraggingInfo
*info
)
2746 printf("draggingEntered\n");
2747 return WDOperationCopy
;
2752 draggingUpdated(WMView
*self
, WMDraggingInfo
*info
)
2754 return WDOperationCopy
;
2759 draggingExited(WMView
*self
, WMDraggingInfo
*info
)
2761 printf("draggingExited\n");
2765 prepareForDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2767 printf("prepareForDragOperation\n");
2775 receivedData(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
2776 void *cdata
, WMData
*data
)
2778 badbadbad
= wstrdup((char *)WMDataBytes(data
));
2782 /* when it's done in WINGs, remove this */
2784 Bool
requestDroppedData(WMView
*view
, WMDraggingInfo
*info
, char *type
)
2786 WMScreen
*scr
= W_VIEW_SCREEN(view
);
2788 if (!WMRequestSelection(scr
->dragInfo
.destView
,
2789 scr
->xdndSelectionAtom
,
2790 XInternAtom(scr
->display
, type
, False
),
2791 scr
->dragInfo
.timestamp
,
2792 receivedData
, &scr
->dragInfo
)) {
2793 wwarning("could not request data for dropped data");
2800 ev
.type
= ClientMessage
;
2801 ev
.xclient
.message_type
= scr
->xdndFinishedAtom
;
2802 ev
.xclient
.format
= 32;
2803 ev
.xclient
.window
= info
->destinationWindow
;
2804 ev
.xclient
.data
.l
[0] = 0;
2805 ev
.xclient
.data
.l
[1] = 0;
2806 ev
.xclient
.data
.l
[2] = 0;
2807 ev
.xclient
.data
.l
[3] = 0;
2808 ev
.xclient
.data
.l
[4] = 0;
2810 XSendEvent(scr
->display
, info
->sourceWindow
, False
, 0, &ev
);
2811 XFlush(scr
->display
);
2817 performDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2820 WMText
*tPtr
= (WMText
*)self
->self
;
2825 requestDroppedData(tPtr
->view
, info
, "application/X-color");
2826 color
= WMCreateNamedColor(W_VIEW_SCREEN(self
), badbadbad
, True
);
2828 WMSetTextSelectionColor(tPtr
, color
);
2829 WMReleaseColor(color
);
2838 concludeDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2840 printf("concludeDragOperation\n");
2844 static WMDragDestinationProcs _DragDestinationProcs
= {
2848 prepareForDragOperation
,
2849 performDragOperation
,
2850 concludeDragOperation
2855 getStream(WMText
*tPtr
, int sel
, int array
)
2857 TextBlock
*tb
= NULL
;
2859 unsigned long where
= 0;
2864 if (!(tb
= tPtr
->firstTextBlock
))
2868 (tPtr
->writer
) (tPtr
, (void *) text
);
2872 tb
= tPtr
->firstTextBlock
;
2875 if (!tb
->graphic
|| (tb
->graphic
&& !tPtr
->flags
.monoFont
)) {
2877 if (!sel
|| (tb
->graphic
&& tb
->selected
)) {
2879 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
)
2880 && tb
!= tPtr
->firstTextBlock
) {
2881 text
= wrealloc(text
, where
+1);
2882 text
[where
++] = '\n';
2888 if(tb
->graphic
&& array
) {
2889 text
= wrealloc(text
, where
+4);
2890 text
[where
++] = 0xFA;
2891 text
[where
++] = (tb
->used
>>8)&0x0ff;
2892 text
[where
++] = tb
->used
&0x0ff;
2893 text
[where
++] = tb
->allocated
; /* extra info */
2895 text
= wrealloc(text
, where
+tb
->used
);
2896 memcpy(&text
[where
], tb
->text
, tb
->used
);
2900 } else if (sel
&& tb
->selected
) {
2902 if (!tPtr
->flags
.ignoreNewLine
&& tb
->blank
) {
2903 text
= wrealloc(text
, where
+1);
2904 text
[where
++] = '\n';
2910 text
= wrealloc(text
, where
+(tb
->s_end
- tb
->s_begin
));
2911 memcpy(&text
[where
], &tb
->text
[tb
->s_begin
],
2912 tb
->s_end
- tb
->s_begin
);
2913 where
+= tb
->s_end
- tb
->s_begin
;
2918 _gSnext
:tb
= tb
->next
;
2921 /* +1 for the end of string, let's be nice */
2922 text
= wrealloc(text
, where
+1);
2929 releaseStreamObjects(void *data
)
2936 getStreamObjects(WMText
*tPtr
, int sel
)
2938 WMArray
*array
= WMCreateArrayWithDestructor(4, releaseStreamObjects
);
2942 char *start
, *fa
, *desc
;
2944 stream
= getStream(tPtr
, sel
, 1);
2951 fa
= strchr(start
, 0xFA);
2953 if((int)(fa
- start
)>0) {
2955 desc
[(int)(fa
- start
)] = 0;
2956 data
= WMCreateDataWithBytes((void *)desc
, (int)(fa
- start
));
2957 WMSetDataFormat(data
, TYPETEXT
);
2958 WMAddToArray(array
, (void *) data
);
2961 len
= *(fa
+1)*0xff + *(fa
+2);
2962 data
= WMCreateDataWithBytes((void *)(fa
+4), len
);
2963 WMSetDataFormat(data
, *(fa
+3));
2964 WMAddToArray(array
, (void *) data
);
2965 start
= fa
+ len
+ 4;
2968 if (start
&& strlen(start
)) {
2969 data
= WMCreateDataWithBytes((void *)start
, strlen(start
));
2970 WMSetDataFormat(data
, TYPETEXT
);
2971 WMAddToArray(array
, (void *) data
);
2983 WMCreateTextForDocumentType(WMWidget
*parent
,
2984 WMAction
*parser
, WMAction
*writer
)
2986 Text
*tPtr
= wmalloc(sizeof(Text
));
2988 printf("could not create text widget\n");
2993 memset(tPtr
, 0, sizeof(Text
));
2994 tPtr
->widgetClass
= WC_Text
;
2995 tPtr
->view
= W_CreateView(W_VIEW(parent
));
2997 perror("could not create text's view\n");
3001 tPtr
->view
->self
= tPtr
;
3002 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->textCursor
;
3003 tPtr
->view
->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3004 W_ResizeView(tPtr
->view
, 250, 200);
3006 tPtr
->dColor
= WMWhiteColor(tPtr
->view
->screen
);
3007 tPtr
->bgGC
= WMColorGC(tPtr
->dColor
);
3008 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->dColor
);
3009 WMReleaseColor(tPtr
->dColor
);
3011 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
3012 tPtr
->fgGC
= WMColorGC(tPtr
->dColor
);
3018 tPtr
->dFont
= WMRetainFont(WMSystemFontOfSize(tPtr
->view
->screen
, 12));
3020 tPtr
->view
->delegate
= &_TextViewDelegate
;
3022 tPtr
->delegate
= NULL
;
3025 tPtr
->timerID
= NULL
;
3028 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
3029 |EnterWindowMask
|LeaveWindowMask
|FocusChangeMask
,
3030 handleEvents
, tPtr
);
3032 WMCreateEventHandler(tPtr
->view
, ButtonReleaseMask
|ButtonPressMask
3033 |KeyReleaseMask
|KeyPressMask
|Button1MotionMask
,
3034 handleActionEvents
, tPtr
);
3036 WMAddNotificationObserver(ownershipObserver
, tPtr
,
3037 "_lostOwnership", tPtr
);
3039 WMSetViewDragSourceProcs(tPtr
->view
, &_DragSourceProcs
);
3040 WMSetViewDragDestinationProcs(tPtr
->view
, &_DragDestinationProcs
);
3044 char *types
[3] = {"application/X-color", "application/X-image", NULL
};
3045 WMRegisterViewForDraggedTypes(tPtr
->view
, types
);
3048 WMAddNotificationObserver(fontChanged
, tPtr
,
3049 "WMFontPanelDidChangeNotification", tPtr
);
3051 tPtr
->firstTextBlock
= NULL
;
3052 tPtr
->lastTextBlock
= NULL
;
3053 tPtr
->currentTextBlock
= NULL
;
3056 tPtr
->gfxItems
= WMCreateArray(4);
3058 tPtr
->parser
= parser
;
3059 tPtr
->writer
= writer
;
3061 tPtr
->sel
.x
= tPtr
->sel
.y
= 2;
3062 tPtr
->sel
.w
= tPtr
->sel
.h
= 0;
3064 tPtr
->clicked
.x
= tPtr
->clicked
.y
= 2;
3066 tPtr
->visible
.x
= tPtr
->visible
.y
= 2;
3067 tPtr
->visible
.h
= tPtr
->view
->size
.height
;
3068 tPtr
->visible
.w
= tPtr
->view
->size
.width
- 4;
3070 tPtr
->cursor
.x
= -23;
3073 tPtr
->docHeight
= 0;
3074 tPtr
->dBulletPix
= WMCreatePixmapFromXPMData(tPtr
->view
->screen
,
3076 tPtr
->db
= (Pixmap
) NULL
;
3077 tPtr
->bgPixmap
= NULL
;
3079 tPtr
->margins
= WMGetRulerMargins(NULL
);
3080 tPtr
->margins
->right
= tPtr
->visible
.w
;
3083 tPtr
->flags
.rulerShown
= False
;
3084 tPtr
->flags
.monoFont
= False
;
3085 tPtr
->flags
.focused
= False
;
3086 tPtr
->flags
.editable
= True
;
3087 tPtr
->flags
.ownsSelection
= False
;
3088 tPtr
->flags
.pointerGrabbed
= False
;
3089 tPtr
->flags
.extendSelection
= False
;
3090 tPtr
->flags
.frozen
= False
;
3091 tPtr
->flags
.cursorShown
= True
;
3092 tPtr
->flags
.acceptsGraphic
= False
;
3093 tPtr
->flags
.horizOnDemand
= False
;
3094 tPtr
->flags
.needsLayOut
= False
;
3095 tPtr
->flags
.ignoreNewLine
= False
;
3096 tPtr
->flags
.indentNewLine
= False
;
3097 tPtr
->flags
.laidOut
= False
;
3098 tPtr
->flags
.waitingForSelection
= False
;
3099 tPtr
->flags
.prepend
= False
;
3100 tPtr
->flags
.isOverGraphic
= False
;
3101 tPtr
->flags
.relief
= WRSunken
;
3102 tPtr
->flags
.isOverGraphic
= 0;
3103 tPtr
->flags
.alignment
= WALeft
;
3104 tPtr
->flags
.first
= True
;
3110 WMPrependTextStream(WMText
*tPtr
, char *text
)
3112 CHECK_CLASS(tPtr
, WC_Text
);
3115 if (tPtr
->flags
.ownsSelection
)
3116 releaseSelection(tPtr
);
3118 updateScrollers(tPtr
);
3122 tPtr
->flags
.prepend
= True
;
3123 if (text
&& tPtr
->parser
)
3124 (tPtr
->parser
) (tPtr
, (void *) text
);
3126 insertPlainText(tPtr
, text
);
3128 tPtr
->flags
.needsLayOut
= True
;
3130 if(!tPtr
->flags
.frozen
) {
3131 layOutDocument(tPtr
);
3137 WMAppendTextStream(WMText
*tPtr
, char *text
)
3139 CHECK_CLASS(tPtr
, WC_Text
);
3142 if (tPtr
->flags
.ownsSelection
)
3143 releaseSelection(tPtr
);
3145 updateScrollers(tPtr
);
3149 tPtr
->flags
.prepend
= False
;
3150 if (text
&& tPtr
->parser
)
3151 (tPtr
->parser
) (tPtr
, (void *) text
);
3153 insertPlainText(tPtr
, text
);
3155 tPtr
->flags
.needsLayOut
= True
;
3156 if(tPtr
->currentTextBlock
)
3157 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
3159 if(!tPtr
->flags
.frozen
) {
3160 layOutDocument(tPtr
);
3166 WMGetTextStream(WMText
*tPtr
)
3168 CHECK_CLASS(tPtr
, WC_Text
);
3169 return getStream(tPtr
, 0, 0);
3173 WMGetTextSelectedStream(WMText
*tPtr
)
3175 CHECK_CLASS(tPtr
, WC_Text
);
3176 return getStream(tPtr
, 1, 0);
3180 WMGetTextObjects(WMText
*tPtr
)
3182 CHECK_CLASS(tPtr
, WC_Text
);
3183 return getStreamObjects(tPtr
, 0);
3187 WMGetTextSelectedObjects(WMText
*tPtr
)
3189 CHECK_CLASS(tPtr
, WC_Text
);
3190 return getStreamObjects(tPtr
, 1);
3195 WMSetTextDelegate(WMText
*tPtr
, WMTextDelegate
*delegate
)
3197 CHECK_CLASS(tPtr
, WC_Text
);
3199 tPtr
->delegate
= delegate
;
3204 WMCreateTextBlockWithObject(WMText
*tPtr
, WMWidget
*w
,
3205 char *description
, WMColor
*color
,
3206 unsigned short first
, unsigned short extraInfo
)
3210 if (!w
|| !description
|| !color
)
3213 tb
= wmalloc(sizeof(TextBlock
));
3217 tb
->text
= wstrdup(description
);
3218 tb
->used
= strlen(description
);
3221 tb
->color
= WMRetainColor(color
);
3222 tb
->marginN
= newMargin(tPtr
, NULL
);
3223 tb
->allocated
= extraInfo
;
3228 tb
->underlined
= False
;
3229 tb
->selected
= False
;
3231 tb
->sections
= NULL
;
3241 WMCreateTextBlockWithPixmap(WMText
*tPtr
, WMPixmap
*p
,
3242 char *description
, WMColor
*color
,
3243 unsigned short first
, unsigned short extraInfo
)
3247 if (!p
|| !description
|| !color
)
3250 tb
= wmalloc(sizeof(TextBlock
));
3254 tb
->text
= wstrdup(description
);
3255 tb
->used
= strlen(description
);
3257 tb
->d
.pixmap
= WMRetainPixmap(p
);
3258 tb
->color
= WMRetainColor(color
);
3259 tb
->marginN
= newMargin(tPtr
, NULL
);
3260 tb
->allocated
= extraInfo
;
3265 tb
->underlined
= False
;
3266 tb
->selected
= False
;
3268 tb
->sections
= NULL
;
3277 WMCreateTextBlockWithText(WMText
*tPtr
, char *text
, WMFont
*font
, WMColor
*color
,
3278 unsigned short first
, unsigned short len
)
3282 if (!font
|| !color
)
3285 tb
= wmalloc(sizeof(TextBlock
));
3289 tb
->allocated
= reqBlockSize(len
);
3290 tb
->text
= (char *)wmalloc(tb
->allocated
);
3291 memset(tb
->text
, 0, tb
->allocated
);
3293 if (len
< 1|| !text
|| (*text
== '\n' && len
==1 )) {
3298 memcpy(tb
->text
, text
, len
);
3302 tb
->text
[tb
->used
] = 0;
3304 tb
->d
.font
= WMRetainFont(font
);
3305 tb
->color
= WMRetainColor(color
);
3306 tb
->marginN
= newMargin(tPtr
, NULL
);
3309 tb
->graphic
= False
;
3310 tb
->underlined
= False
;
3311 tb
->selected
= False
;
3313 tb
->sections
= NULL
;
3321 WMSetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int first
,
3322 unsigned int kanji
, unsigned int underlined
, int script
,
3323 WMRulerMargins
*margins
)
3325 TextBlock
*tb
= (TextBlock
*) vtb
;
3331 tb
->underlined
= underlined
;
3332 tb
->script
= script
;
3333 tb
->marginN
= newMargin(tPtr
, margins
);
3337 WMGetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int *first
,
3338 unsigned int *kanji
, unsigned int *underlined
, int *script
,
3339 WMRulerMargins
*margins
)
3341 TextBlock
*tb
= (TextBlock
*) vtb
;
3345 if (first
) *first
= tb
->first
;
3346 if (kanji
) *kanji
= tb
->kanji
;
3347 if (underlined
) *underlined
= tb
->underlined
;
3348 if (script
) *script
= tb
->script
;
3349 if (margins
) margins
= &tPtr
->margins
[tb
->marginN
];
3355 WMPrependTextBlock(WMText
*tPtr
, void *vtb
)
3357 TextBlock
*tb
= (TextBlock
*)vtb
;
3364 WMWidget
*w
= tb
->d
.widget
;
3365 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
3366 (W_VIEW(w
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3367 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3370 WMAddToArray(tPtr
->gfxItems
, (void *)tb
);
3372 } else tPtr
->tpos
= tb
->used
;
3374 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
3375 tb
->next
= tb
->prior
= NULL
;
3377 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
3378 = tPtr
->currentTextBlock
= tb
;
3383 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
3386 tb
->next
= tPtr
->currentTextBlock
;
3387 tb
->prior
= tPtr
->currentTextBlock
->prior
;
3388 if (tPtr
->currentTextBlock
->prior
)
3389 tPtr
->currentTextBlock
->prior
->next
= tb
;
3391 tPtr
->currentTextBlock
->prior
= tb
;
3393 tPtr
->firstTextBlock
= tb
;
3395 tPtr
->currentTextBlock
= tb
;
3400 WMAppendTextBlock(WMText
*tPtr
, void *vtb
)
3402 TextBlock
*tb
= (TextBlock
*)vtb
;
3409 WMWidget
*w
= tb
->d
.widget
;
3410 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
3411 (W_VIEW(w
))->attribs
.cursor
=
3412 tPtr
->view
->screen
->defaultCursor
;
3413 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3416 WMAddToArray(tPtr
->gfxItems
, (void *)tb
);
3418 } else tPtr
->tpos
= tb
->used
;
3420 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
3421 tb
->next
= tb
->prior
= NULL
;
3423 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
3424 = tPtr
->currentTextBlock
= tb
;
3429 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
3432 tb
->next
= tPtr
->currentTextBlock
->next
;
3433 tb
->prior
= tPtr
->currentTextBlock
;
3434 if (tPtr
->currentTextBlock
->next
)
3435 tPtr
->currentTextBlock
->next
->prior
= tb
;
3437 tPtr
->currentTextBlock
->next
= tb
;
3440 tPtr
->lastTextBlock
= tb
;
3442 tPtr
->currentTextBlock
= tb
;
3446 WMRemoveTextBlock(WMText
*tPtr
)
3448 TextBlock
*tb
= NULL
;
3450 if (!tPtr
|| !tPtr
->firstTextBlock
|| !tPtr
->lastTextBlock
3451 || !tPtr
->currentTextBlock
) {
3452 printf("cannot remove non existent TextBlock!\b");
3456 tb
= tPtr
->currentTextBlock
;
3458 WMRemoveFromArray(tPtr
->gfxItems
, (void *)tb
);
3461 WMUnmapWidget(tb
->d
.widget
);
3465 if (tPtr
->currentTextBlock
== tPtr
->firstTextBlock
) {
3466 if (tPtr
->currentTextBlock
->next
)
3467 tPtr
->currentTextBlock
->next
->prior
= NULL
;
3469 tPtr
->firstTextBlock
= tPtr
->currentTextBlock
->next
;
3470 tPtr
->currentTextBlock
= tPtr
->firstTextBlock
;
3472 } else if (tPtr
->currentTextBlock
== tPtr
->lastTextBlock
) {
3473 tPtr
->currentTextBlock
->prior
->next
= NULL
;
3474 tPtr
->lastTextBlock
= tPtr
->currentTextBlock
->prior
;
3475 tPtr
->currentTextBlock
= tPtr
->lastTextBlock
;
3477 tPtr
->currentTextBlock
->prior
->next
= tPtr
->currentTextBlock
->next
;
3478 tPtr
->currentTextBlock
->next
->prior
= tPtr
->currentTextBlock
->prior
;
3479 tPtr
->currentTextBlock
= tPtr
->currentTextBlock
->next
;
3486 WMDestroyTextBlock(WMText
*tPtr
, void *vtb
)
3488 TextBlock
*tb
= (TextBlock
*)vtb
;
3494 /* naturally, there's a danger to destroying
3495 widgets whose action brings us here:
3496 ie. press a button to destroy it... need to
3497 find a safer way. till then... this stays commented out */
3498 /* WMDestroyWidget(tb->d.widget);
3499 wfree(tb->d.widget); */
3500 tb
->d
.widget
= NULL
;
3502 WMReleasePixmap(tb
->d
.pixmap
);
3503 tb
->d
.pixmap
= NULL
;
3506 WMReleaseFont(tb
->d
.font
);
3509 WMReleaseColor(tb
->color
);
3510 if (tb
->sections
&& tb
->nsections
> 0)
3511 wfree(tb
->sections
);
3520 WMSetTextForegroundColor(WMText
*tPtr
, WMColor
*color
)
3526 tPtr
->fgGC
= WMColorGC(color
);
3528 tPtr
->fgGC
= WMColorGC(WMBlackColor(tPtr
->view
->screen
));
3534 WMSetTextBackgroundColor(WMText
*tPtr
, WMColor
*color
)
3540 tPtr
->bgGC
= WMColorGC(color
);
3541 W_SetViewBackgroundColor(tPtr
->view
, color
);
3543 tPtr
->bgGC
= WMColorGC(WMWhiteColor(tPtr
->view
->screen
));
3544 W_SetViewBackgroundColor(tPtr
->view
,
3545 WMWhiteColor(tPtr
->view
->screen
));
3551 void WMSetTextBackgroundPixmap(WMText
*tPtr
, WMPixmap
*pixmap
)
3557 WMReleasePixmap(tPtr
->bgPixmap
);
3560 tPtr
->bgPixmap
= WMRetainPixmap(pixmap
);
3562 tPtr
->bgPixmap
= NULL
;
3566 WMSetTextRelief(WMText
*tPtr
, WMReliefType relief
)
3570 tPtr
->flags
.relief
= relief
;
3571 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3575 WMSetTextHasHorizontalScroller(WMText
*tPtr
, Bool shouldhave
)
3580 if (shouldhave
&& !tPtr
->hS
) {
3581 tPtr
->hS
= WMCreateScroller(tPtr
);
3582 (W_VIEW(tPtr
->hS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3583 (W_VIEW(tPtr
->hS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3584 WMSetScrollerArrowsPosition(tPtr
->hS
, WSAMinEnd
);
3585 WMSetScrollerAction(tPtr
->hS
, scrollersCallBack
, tPtr
);
3586 WMMapWidget(tPtr
->hS
);
3587 } else if (!shouldhave
&& tPtr
->hS
) {
3588 WMUnmapWidget(tPtr
->hS
);
3589 WMDestroyWidget(tPtr
->hS
);
3595 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3600 WMSetTextHasRuler(WMText
*tPtr
, Bool shouldhave
)
3605 if(shouldhave
&& !tPtr
->ruler
) {
3606 tPtr
->ruler
= WMCreateRuler(tPtr
);
3607 (W_VIEW(tPtr
->ruler
))->attribs
.cursor
=
3608 tPtr
->view
->screen
->defaultCursor
;
3609 (W_VIEW(tPtr
->ruler
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3610 WMSetRulerReleaseAction(tPtr
->ruler
, rulerReleaseCallBack
, tPtr
);
3611 WMSetRulerMoveAction(tPtr
->ruler
, rulerMoveCallBack
, tPtr
);
3612 } else if(!shouldhave
&& tPtr
->ruler
) {
3613 WMShowTextRuler(tPtr
, False
);
3614 WMDestroyWidget(tPtr
->ruler
);
3617 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3621 WMShowTextRuler(WMText
*tPtr
, Bool show
)
3628 if(tPtr
->flags
.monoFont
)
3631 tPtr
->flags
.rulerShown
= show
;
3633 WMMapWidget(tPtr
->ruler
);
3635 WMUnmapWidget(tPtr
->ruler
);
3638 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3642 WMGetTextRulerShown(WMText
*tPtr
)
3650 return tPtr
->flags
.rulerShown
;
3655 WMSetTextHasVerticalScroller(WMText
*tPtr
, Bool shouldhave
)
3660 if (shouldhave
&& !tPtr
->vS
) {
3661 tPtr
->vS
= WMCreateScroller(tPtr
);
3662 (W_VIEW(tPtr
->vS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3663 (W_VIEW(tPtr
->vS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3664 WMSetScrollerArrowsPosition(tPtr
->vS
, WSAMaxEnd
);
3665 WMSetScrollerAction(tPtr
->vS
, scrollersCallBack
, tPtr
);
3666 WMMapWidget(tPtr
->vS
);
3667 } else if (!shouldhave
&& tPtr
->vS
) {
3668 WMUnmapWidget(tPtr
->vS
);
3669 WMDestroyWidget(tPtr
->vS
);
3675 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3681 WMScrollText(WMText
*tPtr
, int amount
)
3686 if (amount
== 0 || !tPtr
->view
->flags
.realized
)
3690 if (tPtr
->vpos
> 0) {
3691 if (tPtr
->vpos
> abs(amount
)) tPtr
->vpos
+= amount
;
3695 int limit
= tPtr
->docHeight
- tPtr
->visible
.h
;
3696 if (tPtr
->vpos
< limit
) {
3697 if (tPtr
->vpos
< limit
-amount
) tPtr
->vpos
+= amount
;
3698 else tPtr
->vpos
= limit
;
3702 if (scroll
&& tPtr
->vpos
!= tPtr
->prevVpos
) {
3703 updateScrollers(tPtr
);
3706 tPtr
->prevVpos
= tPtr
->vpos
;
3711 WMPageText(WMText
*tPtr
, Bool direction
)
3713 if (!tPtr
) return False
;
3714 if (!tPtr
->view
->flags
.realized
) return False
;
3716 return WMScrollText(tPtr
, direction
?tPtr
->visible
.h
:-tPtr
->visible
.h
);
3720 WMSetTextEditable(WMText
*tPtr
, Bool editable
)
3724 tPtr
->flags
.editable
= editable
;
3728 WMGetTextEditable(WMText
*tPtr
)
3732 return tPtr
->flags
.editable
;
3736 WMSetTextIndentNewLines(WMText
*tPtr
, Bool indent
)
3740 tPtr
->flags
.indentNewLine
= indent
;
3744 WMSetTextIgnoresNewline(WMText
*tPtr
, Bool ignore
)
3748 tPtr
->flags
.ignoreNewLine
= ignore
;
3752 WMGetTextIgnoresNewline(WMText
*tPtr
)
3756 return tPtr
->flags
.ignoreNewLine
;
3760 WMSetTextUsesMonoFont(WMText
*tPtr
, Bool mono
)
3766 if(tPtr
->flags
.rulerShown
)
3767 WMShowTextRuler(tPtr
, False
);
3768 if(tPtr
->flags
.alignment
!= WALeft
)
3769 tPtr
->flags
.alignment
= WALeft
;
3772 tPtr
->flags
.monoFont
= mono
;
3773 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3777 WMGetTextUsesMonoFont(WMText
*tPtr
)
3781 return tPtr
->flags
.monoFont
;
3786 WMSetTextDefaultFont(WMText
*tPtr
, WMFont
*font
)
3791 WMReleaseFont(tPtr
->dFont
);
3793 tPtr
->dFont
= WMRetainFont(font
);
3795 tPtr
->dFont
= WMRetainFont(WMSystemFontOfSize(tPtr
->view
->screen
, 12));
3799 WMGetTextDefaultFont(WMText
*tPtr
)
3804 return WMRetainFont(tPtr
->dFont
);
3808 WMSetTextDefaultColor(WMText
*tPtr
, WMColor
*color
)
3813 WMReleaseColor(tPtr
->dColor
);
3815 tPtr
->dColor
= WMRetainColor(color
);
3817 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
3821 WMGetTextDefaultColor(WMText
*tPtr
)
3826 return WMRetainColor(tPtr
->dColor
);
3830 WMSetTextAlignment(WMText
*tPtr
, WMAlignment alignment
)
3834 if(tPtr
->flags
.monoFont
)
3835 tPtr
->flags
.alignment
= WALeft
;
3837 tPtr
->flags
.alignment
= alignment
;
3842 WMGetTextInsertType(WMText
*tPtr
)
3846 return tPtr
->flags
.prepend
;
3851 WMSetTextSelectionColor(WMText
*tPtr
, WMColor
*color
)
3853 if (!tPtr
|| !color
)
3856 setSelectionProperty(tPtr
, NULL
, color
, -1);
3860 WMGetTextSelectionColor(WMText
*tPtr
)
3867 tb
= tPtr
->currentTextBlock
;
3869 if (!tb
|| !tPtr
->flags
.ownsSelection
)
3880 WMSetTextSelectionFont(WMText
*tPtr
, WMFont
*font
)
3885 setSelectionProperty(tPtr
, font
, NULL
, -1) ;
3889 WMGetTextSelectionFont(WMText
*tPtr
)
3896 tb
= tPtr
->currentTextBlock
;
3898 if (!tb
|| !tPtr
->flags
.ownsSelection
)
3905 tb
= getFirstNonGraphicBlockFor(tb
, 1);
3909 return (tb
->selected
? tb
->d
.font
: NULL
);
3914 WMSetTextSelectionUnderlined(WMText
*tPtr
, int underlined
)
3916 if (!tPtr
|| (underlined
!=0 && underlined
!=1))
3919 setSelectionProperty(tPtr
, NULL
, NULL
, underlined
);
3924 WMGetTextSelectionUnderlined(WMText
*tPtr
)
3931 tb
= tPtr
->currentTextBlock
;
3933 if (!tb
|| !tPtr
->flags
.ownsSelection
)
3939 return tb
->underlined
;
3944 WMFreezeText(WMText
*tPtr
)
3949 tPtr
->flags
.frozen
= True
;
3954 WMThawText(WMText
*tPtr
)
3959 tPtr
->flags
.frozen
= False
;
3961 if(tPtr
->flags
.monoFont
) {
3962 int j
, c
= WMGetArrayItemCount(tPtr
->gfxItems
);
3965 /* make sure to unmap widgets no matter where they are */
3966 /* they'll be later remapped if needed by paintText */
3967 for(j
=0; j
<c
; j
++) {
3968 if ((tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
))) {
3969 if (tb
->object
&& ((W_VIEW(tb
->d
.widget
))->flags
.mapped
))
3970 WMUnmapWidget(tb
->d
.widget
);
3976 tPtr
->flags
.laidOut
= False
;
3977 layOutDocument(tPtr
);
3978 updateScrollers(tPtr
);
3980 tPtr
->flags
.needsLayOut
= False
;
3984 /* find first occurence of a string */
3986 mystrstr(char *haystack
, char *needle
, unsigned short len
, char *end
,
3991 if(!haystack
|| !needle
|| !end
)
3994 for (ptr
= haystack
; ptr
< end
; ptr
++) {
3996 if (*ptr
== *needle
&& !strncmp(ptr
, needle
, len
))
4000 if (tolower(*ptr
) == tolower(*needle
) &&
4001 !strncasecmp(ptr
, needle
, len
))
4009 /* find last occurence of a string */
4011 mystrrstr(char *haystack
, char *needle
, unsigned short len
, char *end
,
4016 if(!haystack
|| !needle
|| !end
)
4019 for (ptr
= haystack
-2; ptr
> end
; ptr
--) {
4021 if (*ptr
== *needle
&& !strncmp(ptr
, needle
, len
))
4024 if (tolower(*ptr
) == tolower(*needle
) &&
4025 !strncasecmp(ptr
, needle
, len
))
4035 WMFindInTextStream(WMText
*tPtr
, char *needle
, Bool direction
,
4042 if (!tPtr
|| !needle
)
4046 if (! (tb
= tPtr
->currentTextBlock
)) {
4047 if (! (tb
= ( (direction
> 0) ?
4048 tPtr
->firstTextBlock
: tPtr
->lastTextBlock
) ) ){
4052 /* if(tb != ((direction>0) ?tPtr->firstTextBlock : tPtr->lastTextBlock))
4053 tb = (direction>0) ? tb->next : tb->prior; */
4054 if(tb
!= tPtr
->lastTextBlock
)
4058 tb
= tPtr
->currentTextBlock
;
4066 if(pos
+1 < tb
->used
)
4069 if(tb
->used
- pos
> 0 && pos
> 0) {
4070 mark
= mystrstr(&tb
->text
[pos
], needle
,
4071 strlen(needle
), &tb
->text
[tb
->used
], caseSensitive
);
4084 mark
= mystrrstr(&tb
->text
[pos
], needle
,
4085 strlen(needle
), tb
->text
, caseSensitive
);
4097 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
4099 tPtr
->tpos
= (int)(mark
- tb
->text
);
4100 tPtr
->currentTextBlock
= tb
;
4101 updateCursorPosition(tPtr
);
4102 tPtr
->sel
.y
= tPtr
->cursor
.y
+5;
4103 tPtr
->sel
.h
= tPtr
->cursor
.h
-10;
4104 tPtr
->sel
.x
= tPtr
->cursor
.x
+1;
4105 tPtr
->sel
.w
= WMIN(WMWidthOfString(font
,
4106 &tb
->text
[tPtr
->tpos
], strlen(needle
)),
4107 tPtr
->docWidth
- tPtr
->sel
.x
);
4108 tPtr
->flags
.ownsSelection
= True
;
4115 tb
= (direction
>0) ? tb
->next
: tb
->prior
;
4117 pos
= (direction
>0) ? 0 : tb
->used
;
4126 WMReplaceTextSelection(WMText
*tPtr
, char *replacement
)
4131 if (!tPtr
->flags
.ownsSelection
)
4134 removeSelection(tPtr
);
4137 insertTextInteractively(tPtr
, replacement
, strlen(replacement
));
4138 updateCursorPosition(tPtr
);