2 /* WINGs WMText: multi-line/font/color/graphic text widget, by Nwanua. */
7 #include <X11/keysym.h>
13 * - verify what happens with XK_return in insertTextInt...
14 * - selection code... selects can be funny if it crosses over. use rect?
15 * - also inspect behaviour for WACenter and WARight
16 * - what if a widget grabs the click... howto say: "pressed me"?
17 * note that WMCreateEventHandler takes one data, but need widget & tPtr
18 * - FIX: graphix blocks MUST be skipped if monoFont even though they exist!
19 * - check if support for Horizontal Scroll is complete
20 * - 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 WMColor
*fgColor
; /* The current foreground color */
110 WMColor
*bgColor
; /* The background color */
112 GC stippledGC
; /* the GC to overlay selected graphics with */
113 Pixmap db
; /* the buffer on which to draw */
114 WMPixmap
*bgPixmap
; /* the background pixmap */
116 myRect visible
; /* the actual rectangle that can be drawn into */
117 myRect cursor
; /* the position and (height) of cursor */
118 myRect sel
; /* the selection rectangle */
120 WMPoint clicked
; /* where in the _document_ was clicked */
122 unsigned short tpos
; /* the position in the currentTextBlock */
123 unsigned short docWidth
; /* the width of the entire document */
124 unsigned int docHeight
; /* the height of the entire document */
126 TextBlock
*firstTextBlock
;
127 TextBlock
*lastTextBlock
;
128 TextBlock
*currentTextBlock
;
130 WMArray
*gfxItems
; /* a nice array of graphic items */
133 WMHandlerID timerID
; /* for nice twinky-winky */
138 WMTextDelegate
*delegate
;
141 WMRulerMargins
*margins
; /* an array of margins */
143 unsigned int nMargins
:7; /* the total number of margins in use */
145 unsigned int monoFont
:1; /* whether to ignore formats and graphic */
146 unsigned int focused
:1; /* whether this instance has input focus */
147 unsigned int editable
:1; /* "silly user, you can't edit me" */
148 unsigned int ownsSelection
:1; /* "I ownz the current selection!" */
149 unsigned int pointerGrabbed
:1;/* "heh, gib me pointer" */
150 unsigned int extendSelection
:1; /* shift-drag to select more regions */
152 unsigned int rulerShown
:1; /* whether the ruler is shown or not */
153 unsigned int frozen
:1; /* whether screen updates are to be made */
154 unsigned int cursorShown
:1; /* whether to show the cursor */
155 unsigned int acceptsGraphic
:1;/* accept graphic when dropped */
156 unsigned int horizOnDemand
:1;/* if a large image should appear*/
157 unsigned int needsLayOut
:1; /* in case of Append/Deletes */
158 unsigned int ignoreNewLine
:1;/* turn it into a ' ' in streams > 1 */
159 unsigned int indentNewLine
:1;/* add " " for a newline typed */
160 unsigned int laidOut
:1; /* have the TextBlocks all been laid out */
161 unsigned int waitingForSelection
:1; /* I don't wanna wait in vain... */
162 unsigned int prepend
:1; /* prepend=1, append=0 (for parsers) */
163 WMAlignment alignment
:2; /* the alignment for text */
164 WMReliefType relief
:3; /* the relief to display with */
165 unsigned int isOverGraphic
:2;/* the mouse is over a graphic */
166 unsigned int first
:1; /* for plain text parsing, newline? */
167 /* unsigned int RESERVED:1; */
170 WMArray
*xdndSourceTypes
;
171 WMArray
*xdndDestinationTypes
;
175 #define NOTIFY(T,C,N,A) {\
176 WMNotification *notif = WMCreateNotification(N,T,A);\
177 if ((T)->delegate && (T)->delegate->C)\
178 (*(T)->delegate->C)((T)->delegate,notif);\
179 WMPostNotification(notif);\
180 WMReleaseNotification(notif);}
186 /* just to print blocks of text not terminated by \0 */
188 output(char *ptr
, int len
)
195 /* printf(" s is [%s] (%d)\n", s, strlen(s)); */
203 #define CURSOR_BLINK_ON_DELAY 600
204 #define CURSOR_BLINK_OFF_DELAY 400
208 #define STIPPLE_WIDTH 8
209 #define STIPPLE_HEIGHT 8
210 static unsigned char STIPPLE_BITS
[] = {
211 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa
216 static char *default_bullet
[] = {
218 " c None s None", ". c black",
219 "X c white", "o c #808080",
228 static void handleEvents(XEvent
*event
, void *data
);
229 static void layOutDocument(Text
*tPtr
);
230 static void updateScrollers(Text
*tPtr
);
234 getMarginNumber(Text
*tPtr
, WMRulerMargins
*margins
)
238 for(i
=0; i
< tPtr
->nMargins
; i
++) {
240 if(WMIsMarginEqualToMargin(&tPtr
->margins
[i
], margins
))
250 newMargin(Text
*tPtr
, WMRulerMargins
*margins
)
255 tPtr
->margins
[0].retainCount
++;
259 n
= getMarginNumber(tPtr
, margins
);
263 if(tPtr
->nMargins
>= 127) {
264 n
= tPtr
->nMargins
-1;
268 tPtr
->margins
= wrealloc(tPtr
->margins
,
269 (++tPtr
->nMargins
)*sizeof(WMRulerMargins
));
271 n
= tPtr
->nMargins
-1;
272 tPtr
->margins
[n
].left
= margins
->left
;
273 tPtr
->margins
[n
].first
= margins
->first
;
274 tPtr
->margins
[n
].body
= margins
->body
;
275 tPtr
->margins
[n
].right
= margins
->right
;
276 /* for each tab... */
277 tPtr
->margins
[n
].retainCount
= 1;
279 tPtr
->margins
[n
].retainCount
++;
286 sectionWasSelected(Text
*tPtr
, TextBlock
*tb
, XRectangle
*rect
, int s
)
288 unsigned short i
, w
, lw
, selected
= False
, extend
= False
;
292 /* if selection rectangle completely encloses the section */
293 if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
294 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
295 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
297 sel
.w
= tPtr
->visible
.w
;
298 selected
= extend
= True
;
300 /* or if it starts on a line and then goes further down */
301 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
302 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
303 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
304 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
305 >= tPtr
->visible
.y
+ tPtr
->sel
.y
) ) {
306 sel
.x
= WMAX(tPtr
->sel
.x
, tPtr
->clicked
.x
);
307 sel
.w
= tPtr
->visible
.w
;
308 selected
= extend
= True
;
310 /* or if it begins before a line, but ends on it */
311 } else if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
312 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
313 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
314 && (tb
->sections
[s
]._y
315 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
317 if (1||tPtr
->sel
.x
+ tPtr
->sel
.w
> tPtr
->clicked
.x
)
318 sel
.w
= tPtr
->sel
.x
+ tPtr
->sel
.w
;
325 /* or if the selection rectangle lies entirely within a line */
326 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
327 && (tPtr
->sel
.w
>= 2)
328 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
329 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
338 /* if not within (modified) selection rectangle */
339 if ( tb
->sections
[s
].x
> sel
.x
+ sel
.w
340 || tb
->sections
[s
].x
+ tb
->sections
[s
].w
< sel
.x
)
344 if ( tb
->sections
[s
].x
+ tb
->sections
[s
].w
<= sel
.x
+ sel
.w
345 && tb
->sections
[s
].x
>= sel
.x
) {
346 rect
->width
= tb
->sections
[s
].w
;
347 rect
->x
= tb
->sections
[s
].x
;
352 i
= tb
->sections
[s
].begin
;
355 if (0&& tb
->sections
[s
].x
>= sel
.x
) {
356 tb
->s_begin
= tb
->sections
[s
].begin
;
360 while (++i
<= tb
->sections
[s
].end
) {
362 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
365 if (lw
+ tb
->sections
[s
].x
>= sel
.x
366 || i
== tb
->sections
[s
].end
) {
369 tb
->s_begin
= (tb
->selected
? WMIN(tb
->s_begin
, i
) : i
);
374 if (i
> tb
->sections
[s
].end
) {
375 printf("WasSelected: (i > tb->sections[s].end) \n");
379 _selEnd
: rect
->x
= tb
->sections
[s
].x
+ lw
;
381 while(++i
<= tb
->sections
[s
].end
) {
383 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
386 if (lw
+ rect
->x
>= sel
.x
+ sel
.w
387 || i
== tb
->sections
[s
].end
) {
389 if (i
!= tb
->sections
[s
].end
) {
395 if (tb
->sections
[s
].last
&& sel
.x
+ sel
.w
396 >= tb
->sections
[s
].x
+ tb
->sections
[s
].w
398 rect
->width
+= (tPtr
->visible
.w
- rect
->x
- lw
);
401 tb
->s_end
= (tb
->selected
? WMAX(tb
->s_end
, i
) : i
);
410 rect
->y
= tb
->sections
[s
]._y
- tPtr
->vpos
;
411 rect
->height
= tb
->sections
[s
].h
;
412 if(tb
->graphic
) { printf("DEBUG: graphic s%d h%d\n", s
,tb
->sections
[s
].h
);}
419 setSelectionProperty(WMText
*tPtr
, WMFont
*font
, WMColor
*color
, int underlined
)
424 tb
= tPtr
->firstTextBlock
;
425 if (!tb
|| !tPtr
->flags
.ownsSelection
)
428 if (font
&& (!color
|| underlined
==-1))
432 if (tPtr
->flags
.monoFont
|| tb
->selected
) {
434 if (tPtr
->flags
.monoFont
|| (tb
->s_end
- tb
->s_begin
== tb
->used
)
439 WMReleaseFont(tb
->d
.font
);
440 tb
->d
.font
= WMRetainFont(font
);
442 } else if(underlined
!=-1) {
443 tb
->underlined
= underlined
;
445 WMReleaseColor(tb
->color
);
446 tb
->color
= WMRetainColor(color
);
449 } else if (tb
->s_end
<= tb
->used
&& tb
->s_begin
< tb
->s_end
) {
451 TextBlock
*midtb
, *otb
= tb
;
453 if(underlined
!= -1) {
454 midtb
= (TextBlock
*) WMCreateTextBlockWithText(tPtr
,
455 &(tb
->text
[tb
->s_begin
]), tb
->d
.font
, tb
->color
,
456 False
, (tb
->s_end
- tb
->s_begin
));
458 midtb
= (TextBlock
*) WMCreateTextBlockWithText(tPtr
,
459 &(tb
->text
[tb
->s_begin
]),
460 (isFont
?font
:tb
->d
.font
),
461 (isFont
?tb
->color
:color
),
462 False
, (tb
->s_end
- tb
->s_begin
));
467 if(underlined
!= -1) {
468 midtb
->underlined
= underlined
;
470 midtb
->underlined
= otb
->underlined
;
473 midtb
->selected
= !True
;
475 midtb
->s_end
= midtb
->used
;
476 tPtr
->currentTextBlock
= tb
;
477 WMAppendTextBlock(tPtr
, midtb
);
478 tb
= tPtr
->currentTextBlock
;
481 if (otb
->used
- otb
->s_end
> 0) {
484 WMCreateTextBlockWithText(tPtr
,
485 &(otb
->text
[otb
->s_end
]), otb
->d
.font
, otb
->color
,
486 False
, otb
->used
- otb
->s_end
);
489 ntb
->underlined
= otb
->underlined
;
490 ntb
->selected
= False
;
491 WMAppendTextBlock(tPtr
, ntb
);
492 tb
= tPtr
->currentTextBlock
;
497 tPtr
->currentTextBlock
= midtb
;
500 otb
->selected
= False
;
501 otb
->used
= otb
->s_begin
;
508 tPtr
->flags
.needsLayOut
= True
;
511 /* in case the size changed... */
512 if(isFont
&& tPtr
->currentTextBlock
) {
513 TextBlock
*tb
= tPtr
->currentTextBlock
;
515 printf("%d %d %d\n", tPtr
->sel
.y
, tPtr
->sel
.h
, tPtr
->sel
.w
);
516 tPtr
->sel
.y
= 3 + tb
->sections
[0]._y
;
517 tPtr
->sel
.h
= tb
->sections
[tb
->nsections
-1]._y
- tb
->sections
[0]._y
;
518 tPtr
->sel
.w
= tb
->sections
[tb
->nsections
-1].w
;
519 if(tb
->sections
[tb
->nsections
-1]._y
!= tb
->sections
[0]._y
) {
522 printf("%d %d %d\n\n\n", tPtr
->sel
.y
, tPtr
->sel
.h
, tPtr
->sel
.w
);
529 removeSelection(Text
*tPtr
)
531 TextBlock
*tb
= NULL
;
534 if (!(tb
= tPtr
->firstTextBlock
))
539 if(!first
&& !tb
->graphic
) {
540 WMReleaseFont(tPtr
->dFont
);
541 tPtr
->dFont
= WMRetainFont(tb
->d
.font
);
545 if ( (tb
->s_end
- tb
->s_begin
== tb
->used
) || tb
->graphic
) {
546 tPtr
->currentTextBlock
= tb
;
549 } else if(tb
->prior
) {
550 if(tb
->prior
->graphic
)
553 tPtr
->tpos
= tb
->prior
->used
;
554 } else tPtr
->tpos
= 0;
556 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
557 tb
= tPtr
->currentTextBlock
;
560 } else if (tb
->s_end
<= tb
->used
) {
561 memmove(&(tb
->text
[tb
->s_begin
]),
562 &(tb
->text
[tb
->s_end
]), tb
->used
- tb
->s_end
);
563 tb
->used
-= (tb
->s_end
- tb
->s_begin
);
564 tb
->selected
= False
;
565 tPtr
->tpos
= tb
->s_begin
;
577 getFirstNonGraphicBlockFor(TextBlock
*tb
, short dir
)
579 TextBlock
*hold
= tb
;
587 tb
= (dir
? tb
->next
: tb
->prior
);
595 tb
= (dir
? tb
->prior
: tb
->next
);
607 updateStartForCurrentTextBlock(Text
*tPtr
, int x
, int y
, int *dir
,
610 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
611 tb
= getFirstNonGraphicBlockFor(tb
, *dir
);
616 tPtr
->currentTextBlock
=
617 (dir
? tPtr
->lastTextBlock
: tPtr
->firstTextBlock
);
625 layOutDocument(tPtr
);
629 *dir
= !(y
<= tb
->sections
[0].y
);
631 if ( ( y
<= tb
->sections
[0]._y
+ tb
->sections
[0].h
)
632 && (y
>= tb
->sections
[0]._y
) ) {
633 /* if it's on the same line */
634 if(x
< tb
->sections
[0].x
)
638 if ( ( y
<= tb
->sections
[tb
->nsections
-1]._y
639 + tb
->sections
[tb
->nsections
-1].h
)
640 && (y
>= tb
->sections
[tb
->nsections
-1]._y
) ) {
641 /* if it's on the same line */
642 if(x
> tb
->sections
[tb
->nsections
-1].x
)
652 paintText(Text
*tPtr
)
657 int len
, y
, c
, s
, done
=False
, prev_y
=-23, dir
/* 1 = down */;
658 WMScreen
*scr
= tPtr
->view
->screen
;
659 Display
*dpy
= tPtr
->view
->screen
->display
;
660 Window win
= tPtr
->view
->window
;
663 if (!tPtr
->view
->flags
.realized
|| !tPtr
->db
|| tPtr
->flags
.frozen
)
667 XFillRectangle(dpy
, tPtr
->db
, WMColorGC(tPtr
->bgColor
), 0, 0,
668 tPtr
->visible
.w
, tPtr
->visible
.h
);
670 if (tPtr
->bgPixmap
) {
671 WMDrawPixmap(tPtr
->bgPixmap
, tPtr
->db
,
672 (tPtr
->visible
.w
-tPtr
->visible
.x
-tPtr
->bgPixmap
->width
)/2,
673 (tPtr
->visible
.h
-tPtr
->visible
.y
-tPtr
->bgPixmap
->height
)/2);
676 if (! (tb
= tPtr
->currentTextBlock
)) {
677 if (! (tb
= tPtr
->firstTextBlock
)) {
686 /* first, which direction? Don't waste time looking all over,
687 since the parts to be drawn will most likely be near what
688 was previously drawn */
689 if(!updateStartForCurrentTextBlock(tPtr
, 0, tPtr
->vpos
, &dir
, tb
))
694 if (tb
->graphic
&& tPtr
->flags
.monoFont
)
698 if(tPtr
->vpos
<= tb
->sections
[tb
->nsections
-1]._y
699 + tb
->sections
[tb
->nsections
-1].h
)
702 if(tPtr
->vpos
>= tb
->sections
[tb
->nsections
-1]._y
703 + tb
->sections
[tb
->nsections
-1].h
)
720 /* first, place all text that can be viewed */
721 while (!done
&& tb
) {
727 tb
->selected
= False
;
729 for(s
=0; s
<tb
->nsections
&& !done
; s
++) {
731 if (tb
->sections
[s
]._y
> tPtr
->vpos
+ tPtr
->visible
.h
) {
736 if ( tb
->sections
[s
].y
+ tb
->sections
[s
].h
< tPtr
->vpos
)
739 if (tPtr
->flags
.monoFont
) {
741 color
= tPtr
->fgColor
;
747 if (tPtr
->flags
.ownsSelection
) {
750 if (sectionWasSelected(tPtr
, tb
, &rect
, s
)) {
752 XFillRectangle(dpy
, tPtr
->db
, WMColorGC(scr
->gray
),
753 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
757 prev_y
= tb
->sections
[s
]._y
;
759 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
760 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
761 y
= tb
->sections
[s
].y
- tPtr
->vpos
;
762 WMDrawString(scr
, tPtr
->db
, color
, font
,
763 tb
->sections
[s
].x
- tPtr
->hpos
, y
, text
, len
);
765 if (!tPtr
->flags
.monoFont
&& tb
->underlined
) {
766 XDrawLine(dpy
, tPtr
->db
, WMColorGC(color
),
767 tb
->sections
[s
].x
- tPtr
->hpos
,
769 tb
->sections
[s
].x
+ tb
->sections
[s
].w
- tPtr
->hpos
,
773 tb
= (!done
? tb
->next
: NULL
);
776 /* now , show all graphic items that can be viewed */
777 c
= WMGetArrayItemCount(tPtr
->gfxItems
);
778 if (c
> 0 && !tPtr
->flags
.monoFont
) {
782 tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
);
784 /* if it's not viewable, and mapped, unmap it */
785 if (tb
->sections
[0]._y
+ tb
->sections
[0].h
<= tPtr
->vpos
786 || tb
->sections
[0]._y
>= tPtr
->vpos
+ tPtr
->visible
.h
) {
789 if ((W_VIEW(tb
->d
.widget
))->flags
.mapped
) {
790 WMUnmapWidget(tb
->d
.widget
);
794 /* if it's viewable, and not mapped, map it */
796 W_View
*view
= W_VIEW(tb
->d
.widget
);
798 if (!view
->flags
.realized
)
799 WMRealizeWidget(tb
->d
.widget
);
800 if(!view
->flags
.mapped
) {
801 XMapWindow(view
->screen
->display
, view
->window
);
802 XFlush(view
->screen
->display
);
803 view
->flags
.mapped
= 1;
808 WMMoveWidget(tb
->d
.widget
,
809 tb
->sections
[0].x
+ tPtr
->visible
.x
- tPtr
->hpos
,
810 tb
->sections
[0].y
+ tPtr
->visible
.y
- tPtr
->vpos
);
811 h
= WMWidgetHeight(tb
->d
.widget
) + 1;
814 WMDrawPixmap(tb
->d
.pixmap
, tPtr
->db
,
815 tb
->sections
[0].x
- tPtr
->hpos
,
816 tb
->sections
[0].y
- tPtr
->vpos
);
817 h
= tb
->d
.pixmap
->height
+ 1;
821 if (tPtr
->flags
.ownsSelection
) {
824 if ( sectionWasSelected(tPtr
, tb
, &rect
, 0)) {
825 Drawable d
= (0&&tb
->object
?
826 (WMWidgetView(tb
->d
.widget
))->window
: tPtr
->db
);
829 XFillRectangle(dpy
, d
, tPtr
->stippledGC
,
830 /*XFillRectangle(dpy, tPtr->db, tPtr->stippledGC,*/
831 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
835 if (!tPtr
->flags
.monoFont
&& tb
->underlined
) {
836 XDrawLine(dpy
, tPtr
->db
, WMColorGC(tb
->color
),
837 tb
->sections
[0].x
- tPtr
->hpos
,
838 tb
->sections
[0].y
+ h
- tPtr
->vpos
,
839 tb
->sections
[0].x
+ tb
->sections
[0].w
- tPtr
->hpos
,
840 tb
->sections
[0].y
+ h
- tPtr
->vpos
);
848 if (tPtr
->flags
.editable
&& tPtr
->flags
.cursorShown
849 && tPtr
->cursor
.x
!= -23 && tPtr
->flags
.focused
) {
850 int y
= tPtr
->cursor
.y
- tPtr
->vpos
;
851 XDrawLine(dpy
, tPtr
->db
, WMColorGC(tPtr
->fgColor
),
853 tPtr
->cursor
.x
, y
+ tPtr
->cursor
.h
);
856 XCopyArea(dpy
, tPtr
->db
, win
, WMColorGC(tPtr
->bgColor
), 0, 0,
857 tPtr
->visible
.w
, tPtr
->visible
.h
,
858 tPtr
->visible
.x
, tPtr
->visible
.y
);
860 W_DrawRelief(scr
, win
, 0, 0,
861 tPtr
->view
->size
.width
, tPtr
->view
->size
.height
,
864 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)
865 XDrawLine(dpy
, win
, WMColorGC(tPtr
->fgColor
),
866 2, 42, tPtr
->view
->size
.width
-4, 42);
871 mouseOverObject(Text
*tPtr
, int x
, int y
)
876 x
-= tPtr
->visible
.x
;
878 y
-= tPtr
->visible
.y
;
881 if(tPtr
->flags
.ownsSelection
) {
884 && tPtr
->sel
.x
+ tPtr
->sel
.w
>= x
885 && tPtr
->sel
.y
+ tPtr
->sel
.h
>= y
) {
886 tPtr
->flags
.isOverGraphic
= 1;
893 int j
, c
= WMGetArrayItemCount(tPtr
->gfxItems
);
896 tPtr
->flags
.isOverGraphic
= 0;
900 tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
);
902 if(!tb
|| !tb
->sections
) {
903 tPtr
->flags
.isOverGraphic
= 0;
908 if(tb
->sections
[0].x
<= x
909 && tb
->sections
[0].y
<= y
910 && tb
->sections
[0].x
+ tb
->sections
[0].w
>= x
911 && tb
->sections
[0].y
+ tb
->d
.pixmap
->height
>= y
) {
912 tPtr
->flags
.isOverGraphic
= 3;
923 tPtr
->flags
.isOverGraphic
= 0;
926 tPtr
->view
->attribs
.cursor
= (result
?
927 tPtr
->view
->screen
->defaultCursor
928 : tPtr
->view
->screen
->textCursor
);
930 XSetWindowAttributes attribs
;
931 attribs
.cursor
= tPtr
->view
->attribs
.cursor
;
932 XChangeWindowAttributes(tPtr
->view
->screen
->display
,
933 tPtr
->view
->window
, CWCursor
,
941 blinkCursor(void *data
)
943 Text
*tPtr
= (Text
*)data
;
945 if (tPtr
->flags
.cursorShown
) {
946 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY
,
949 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
,
953 tPtr
->flags
.cursorShown
= !tPtr
->flags
.cursorShown
;
958 updateCursorPosition(Text
*tPtr
)
960 TextBlock
*tb
= NULL
;
963 if(tPtr
->flags
.needsLayOut
)
964 layOutDocument(tPtr
);
966 if (! (tb
= tPtr
->currentTextBlock
)) {
967 if (! (tb
= tPtr
->firstTextBlock
)) {
968 WMFont
*font
= tPtr
->dFont
;
970 tPtr
->cursor
.h
= font
->height
+ abs(font
->height
-font
->y
);
981 y
= tb
->sections
[0].y
;
982 h
= tb
->sections
[0].h
;
983 x
= tb
->sections
[0].x
;
985 } else if(tb
->graphic
) {
986 y
= tb
->sections
[0].y
;
987 h
= tb
->sections
[0].h
;
988 x
= tb
->sections
[0].x
;
990 x
+= tb
->sections
[0].w
;
993 if(tPtr
->tpos
> tb
->used
)
994 tPtr
->tpos
= tb
->used
;
996 for(s
=0; s
<tb
->nsections
-1; s
++) {
998 if(tPtr
->tpos
>= tb
->sections
[s
].begin
999 && tPtr
->tpos
<= tb
->sections
[s
].end
)
1003 y
= tb
->sections
[s
]._y
;
1004 h
= tb
->sections
[s
].h
;
1005 x
= tb
->sections
[s
].x
+ WMWidthOfString(
1006 (tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
),
1007 &tb
->text
[tb
->sections
[s
].begin
],
1008 tPtr
->tpos
- tb
->sections
[s
].begin
);
1016 /* scroll the bars if the cursor is not visible */
1017 if(tPtr
->flags
.editable
&& tPtr
->cursor
.x
!= -23) {
1018 if(tPtr
->cursor
.y
+tPtr
->cursor
.h
1019 > tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
) {
1021 (tPtr
->cursor
.y
+tPtr
->cursor
.h
+10
1022 - (tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
));
1023 } else if(tPtr
->cursor
.y
< tPtr
->vpos
+tPtr
->visible
.y
) {
1024 tPtr
->vpos
-= (tPtr
->vpos
+tPtr
->visible
.y
-tPtr
->cursor
.y
);
1029 updateScrollers(tPtr
);
1034 cursorToTextPosition(Text
*tPtr
, int x
, int y
)
1036 TextBlock
*tb
= NULL
;
1037 int done
=False
, s
, pos
, len
, _w
, _y
, dir
=1; /* 1 == "down" */
1040 if(tPtr
->flags
.needsLayOut
)
1041 layOutDocument(tPtr
);
1043 y
+= (tPtr
->vpos
- tPtr
->visible
.y
);
1047 x
-= (tPtr
->visible
.x
- 2);
1051 /* clicked is relative to document, not window... */
1052 tPtr
->clicked
.x
= x
;
1053 tPtr
->clicked
.y
= y
;
1055 if (! (tb
= tPtr
->currentTextBlock
)) {
1056 if (! (tb
= tPtr
->firstTextBlock
)) {
1057 WMFont
*font
= tPtr
->dFont
;
1059 tPtr
->cursor
.h
= font
->height
+ abs(font
->height
-font
->y
);
1066 /* first, which direction? Most likely, newly clicked
1067 position will be close to previous */
1068 if(!updateStartForCurrentTextBlock(tPtr
, x
, y
, &dir
, tb
))
1072 s
= (dir
? 0 : tb
->nsections
-1);
1073 if ( y
>= tb
->sections
[s
]._y
1074 && y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) {
1078 /* get the first (or last) section of the TextBlock that
1079 lies about the vertical click point */
1081 while (!done
&& tb
) {
1083 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1084 if( (dir
?tb
->next
:tb
->prior
))
1085 tb
= (dir
?tb
->next
:tb
->prior
);
1089 s
= (dir
? 0 : tb
->nsections
-1);
1090 while (!done
&& (dir
? (s
<tb
->nsections
) : (s
>=0) )) {
1092 if ( (dir
? (y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) :
1093 ( y
>= tb
->sections
[s
]._y
) ) ) {
1101 if ( (dir
? tb
->next
: tb
->prior
)) {
1102 tb
= (dir
? tb
->next
: tb
->prior
);
1105 break; /* goto _doneH; */
1111 if (s
<0 || s
>=tb
->nsections
) {
1112 s
= (dir
? tb
->nsections
-1 : 0);
1116 /* we have the line, which TextBlock on that line is it? */
1117 pos
= (dir
?0:tb
->sections
[s
].begin
);
1118 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1119 TextBlock
*hold
= tb
;
1120 tb
= getFirstNonGraphicBlockFor(hold
, dir
);
1134 _y
= tb
->sections
[s
]._y
;
1138 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1139 tb
= (dir
? tb
->next
: tb
->prior
);
1146 _w
= WMWidgetWidth(tb
->d
.widget
)-5;
1148 _w
= tb
->d
.pixmap
->width
-5;
1150 if (tb
->sections
[0].x
+ _w
>= x
)
1153 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
1154 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
1155 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
1156 if (tb
->sections
[s
].x
+ _w
>= x
)
1161 if (tb
->sections
[s
].x
<= x
)
1165 if ((dir
? tb
->next
: tb
->prior
)) {
1166 TextBlock
*nxt
= (dir
? tb
->next
: tb
->prior
);
1167 if (tPtr
->flags
.monoFont
&& nxt
->graphic
) {
1168 nxt
= getFirstNonGraphicBlockFor(nxt
, dir
);
1170 pos
= (dir
?0:tb
->sections
[s
].begin
);
1171 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
1176 if (_y
!= nxt
->sections
[dir
?0:nxt
->nsections
-1]._y
) {
1177 /* this must be the last/first on this line. stop */
1178 pos
= (dir
? tb
->sections
[s
].end
: 0);
1179 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
1183 tPtr
->cursor
.x
+= WMWidgetWidth(tb
->d
.widget
);
1185 tPtr
->cursor
.x
+= tb
->d
.pixmap
->width
;
1186 } else if (pos
> tb
->sections
[s
].begin
) {
1188 WMWidthOfString(tb
->d
.font
,
1189 &(tb
->text
[tb
->sections
[s
].begin
]),
1190 pos
- tb
->sections
[s
].begin
);
1197 if ( (dir
? tb
->next
: tb
->prior
)) {
1198 tb
= (dir
? tb
->next
: tb
->prior
);
1205 s
= (dir
? 0 : tb
->nsections
-1);
1208 /* we have said TextBlock, now where within it? */
1211 int gw
= (tb
->object
?
1212 WMWidgetWidth(tb
->d
.widget
) : tb
->d
.pixmap
->width
);
1214 tPtr
->cursor
.x
= tb
->sections
[0].x
;
1216 if(x
> tPtr
->cursor
.x
+ gw
/2) {
1218 tPtr
->cursor
.x
+= gw
;
1220 printf("first %d\n", tb
->first
);
1222 if(tb
->prior
->graphic
) pos
= 1;
1223 else pos
= tb
->prior
->used
;
1233 WMFont
*f
= tb
->d
.font
;
1234 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
1235 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
1237 _w
= x
- tb
->sections
[s
].x
;
1240 while (pos
<len
&& WMWidthOfString(f
, text
, pos
+1) < _w
)
1243 tPtr
->cursor
.x
= tb
->sections
[s
].x
+
1244 (pos
? WMWidthOfString(f
, text
, pos
) : 0);
1246 pos
+= tb
->sections
[s
].begin
;
1252 tPtr
->tpos
= (pos
<=1)? pos
: 0;
1254 tPtr
->tpos
= (pos
<tb
->used
)? pos
: tb
->used
;
1258 printf("...for this app will surely crash :-)\n");
1260 tPtr
->currentTextBlock
= tb
;
1261 tPtr
->cursor
.h
= tb
->sections
[s
].h
;
1262 tPtr
->cursor
.y
= tb
->sections
[s
]._y
;
1264 /* scroll the bars if the cursor is not visible */
1265 if(tPtr
->flags
.editable
&& tPtr
->cursor
.x
!= -23) {
1266 if(tPtr
->cursor
.y
+tPtr
->cursor
.h
1267 > tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
) {
1269 (tPtr
->cursor
.y
+tPtr
->cursor
.h
+10
1270 - (tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
));
1271 updateScrollers(tPtr
);
1272 } else if(tPtr
->cursor
.y
< tPtr
->vpos
+tPtr
->visible
.y
) {
1273 tPtr
->vpos
-= (tPtr
->vpos
+tPtr
->visible
.y
-tPtr
->cursor
.y
);
1274 updateScrollers(tPtr
);
1283 updateScrollers(Text
*tPtr
)
1286 if (tPtr
->flags
.frozen
)
1290 if (tPtr
->docHeight
<= tPtr
->visible
.h
) {
1291 WMSetScrollerParameters(tPtr
->vS
, 0, 1);
1294 float hmax
= (float)(tPtr
->docHeight
);
1295 WMSetScrollerParameters(tPtr
->vS
,
1296 ((float)tPtr
->vpos
)/(hmax
- (float)tPtr
->visible
.h
),
1297 (float)tPtr
->visible
.h
/hmax
);
1299 } else tPtr
->vpos
= 0;
1302 if (tPtr
->docWidth
<= tPtr
->visible
.w
) {
1303 WMSetScrollerParameters(tPtr
->hS
, 0, 1);
1306 float wmax
= (float)(tPtr
->docWidth
);
1307 WMSetScrollerParameters(tPtr
->hS
,
1308 ((float)tPtr
->hpos
)/(wmax
- (float)tPtr
->visible
.w
),
1309 (float)tPtr
->visible
.w
/wmax
);
1311 } else tPtr
->hpos
= 0;
1315 scrollersCallBack(WMWidget
*w
, void *self
)
1317 Text
*tPtr
= (Text
*)self
;
1318 Bool scroll
= False
;
1321 if (!tPtr
->view
->flags
.realized
|| tPtr
->flags
.frozen
)
1324 if (w
== tPtr
->vS
) {
1326 height
= tPtr
->visible
.h
;
1328 which
= WMGetScrollerHitPart(tPtr
->vS
);
1331 case WSDecrementLine
:
1332 if (tPtr
->vpos
> 0) {
1333 if (tPtr
->vpos
>16) tPtr
->vpos
-=16;
1339 case WSIncrementLine
: {
1340 int limit
= tPtr
->docHeight
- height
;
1341 if (tPtr
->vpos
< limit
) {
1342 if (tPtr
->vpos
<limit
-16) tPtr
->vpos
+=16;
1343 else tPtr
->vpos
=limit
;
1349 case WSDecrementPage
:
1350 if(((int)tPtr
->vpos
- (int)height
) >= 0)
1351 tPtr
->vpos
-= height
;
1358 case WSIncrementPage
:
1359 tPtr
->vpos
+= height
;
1360 if (tPtr
->vpos
> (tPtr
->docHeight
- height
))
1361 tPtr
->vpos
= tPtr
->docHeight
- height
;
1367 tPtr
->vpos
= WMGetScrollerValue(tPtr
->vS
)
1368 * (float)(tPtr
->docHeight
- height
);
1376 scroll
= (tPtr
->vpos
!= tPtr
->prevVpos
);
1377 tPtr
->prevVpos
= tPtr
->vpos
;
1381 if (w
== tPtr
->hS
) {
1382 int width
= tPtr
->visible
.w
;
1384 which
= WMGetScrollerHitPart(tPtr
->hS
);
1387 case WSDecrementLine
:
1388 if (tPtr
->hpos
> 0) {
1389 if (tPtr
->hpos
>16) tPtr
->hpos
-=16;
1394 case WSIncrementLine
: {
1395 int limit
= tPtr
->docWidth
- width
;
1396 if (tPtr
->hpos
< limit
) {
1397 if (tPtr
->hpos
<limit
-16) tPtr
->hpos
+=16;
1398 else tPtr
->hpos
=limit
;
1403 case WSDecrementPage
:
1404 if(((int)tPtr
->hpos
- (int)width
) >= 0)
1405 tPtr
->hpos
-= width
;
1412 case WSIncrementPage
:
1413 tPtr
->hpos
+= width
;
1414 if (tPtr
->hpos
> (tPtr
->docWidth
- width
))
1415 tPtr
->hpos
= tPtr
->docWidth
- width
;
1421 tPtr
->hpos
= WMGetScrollerValue(tPtr
->hS
)
1422 * (float)(tPtr
->docWidth
- width
);
1430 scroll
= (tPtr
->hpos
!= tPtr
->prevHpos
);
1431 tPtr
->prevHpos
= tPtr
->hpos
;
1435 updateScrollers(tPtr
);
1444 unsigned short begin
, end
; /* what part of the text block */
1449 layOutLine(Text
*tPtr
, myLineItems
*items
, int nitems
, int x
, int y
)
1451 int i
, j
=0, lw
= 0, line_height
=0, max_d
=0, len
, n
;
1454 TextBlock
*tb
, *tbsame
=NULL
;
1456 if(!items
|| nitems
== 0)
1459 for(i
=0; i
<nitems
; i
++) {
1463 if (!tPtr
->flags
.monoFont
) {
1465 WMWidget
*wdt
= tb
->d
.widget
;
1466 line_height
= WMAX(line_height
, WMWidgetHeight(wdt
));
1467 if (tPtr
->flags
.alignment
!= WALeft
)
1468 lw
+= WMWidgetWidth(wdt
);
1470 line_height
= WMAX(line_height
,
1471 tb
->d
.pixmap
->height
+ max_d
);
1472 if (tPtr
->flags
.alignment
!= WALeft
)
1473 lw
+= tb
->d
.pixmap
->width
;
1478 font
= (tPtr
->flags
.monoFont
)?tPtr
->dFont
: tb
->d
.font
;
1479 /*max_d = WMAX(max_d, abs(font->height-font->y));*/
1481 line_height
= WMAX(line_height
, font
->height
+ max_d
);
1482 text
= &(tb
->text
[items
[i
].begin
]);
1483 len
= items
[i
].end
- items
[i
].begin
;
1484 if (tPtr
->flags
.alignment
!= WALeft
)
1485 lw
+= WMWidthOfString(font
, text
, len
);
1489 if (tPtr
->flags
.alignment
== WARight
) {
1490 j
= tPtr
->visible
.w
- lw
;
1491 } else if (tPtr
->flags
.alignment
== WACenter
) {
1492 j
= (int) ((float)(tPtr
->visible
.w
- lw
))/2.0;
1495 for(i
=0; i
<nitems
; i
++) {
1498 if (tbsame
== tb
) { /* extend it, since it's on same line */
1499 tb
->sections
[tb
->nsections
-1].end
= items
[i
].end
;
1500 n
= tb
->nsections
-1;
1502 tb
->sections
= wrealloc(tb
->sections
,
1503 (++tb
->nsections
)*sizeof(Section
));
1504 n
= tb
->nsections
-1;
1505 tb
->sections
[n
]._y
= y
+ max_d
;
1506 tb
->sections
[n
].max_d
= max_d
;
1507 tb
->sections
[n
].x
= x
+j
;
1508 tb
->sections
[n
].h
= line_height
;
1509 tb
->sections
[n
].begin
= items
[i
].begin
;
1510 tb
->sections
[n
].end
= items
[i
].end
;
1513 tb
->sections
[n
].last
= (i
+1 == nitems
);
1516 if (!tPtr
->flags
.monoFont
) {
1518 WMWidget
*wdt
= tb
->d
.widget
;
1519 tb
->sections
[n
].y
= max_d
+ y
1520 + line_height
- WMWidgetHeight(wdt
);
1521 tb
->sections
[n
].w
= WMWidgetWidth(wdt
);
1523 tb
->sections
[n
].y
= y
+ line_height
1524 + max_d
- tb
->d
.pixmap
->height
;
1525 tb
->sections
[n
].w
= tb
->d
.pixmap
->width
;
1527 x
+= tb
->sections
[n
].w
;
1530 font
= (tPtr
->flags
.monoFont
)? tPtr
->dFont
: tb
->d
.font
;
1531 len
= items
[i
].end
- items
[i
].begin
;
1532 text
= &(tb
->text
[items
[i
].begin
]);
1534 tb
->sections
[n
].y
= y
+line_height
-font
->y
;
1536 WMWidthOfString(font
,
1537 &(tb
->text
[tb
->sections
[n
].begin
]),
1538 tb
->sections
[n
].end
- tb
->sections
[n
].begin
);
1540 x
+= WMWidthOfString(font
, text
, len
);
1552 layOutDocument(Text
*tPtr
)
1555 myLineItems
*items
= NULL
;
1556 unsigned int itemsSize
=0, nitems
=0, begin
, end
;
1558 unsigned int x
, y
=0, lw
= 0, width
=0, bmargin
;
1559 char *start
=NULL
, *mark
=NULL
;
1561 if ( tPtr
->flags
.frozen
|| (!(tb
= tPtr
->firstTextBlock
)) )
1564 assert(tPtr
->visible
.w
> 20);
1566 tPtr
->docWidth
= tPtr
->visible
.w
;
1567 x
= tPtr
->margins
[tb
->marginN
].first
;
1568 bmargin
= tPtr
->margins
[tb
->marginN
].body
;
1570 /* only partial layOut needed: re-Lay only affected textblocks */
1571 if (tPtr
->flags
.laidOut
) {
1572 tb
= tPtr
->currentTextBlock
;
1574 /* search backwards for textblocks on same line */
1576 if (!tb
->sections
|| tb
->nsections
<1) {
1577 tb
= tPtr
->firstTextBlock
;
1578 tPtr
->flags
.laidOut
= False
;
1583 if(!tb
->prior
->sections
|| tb
->prior
->nsections
<1) {
1584 tb
= tPtr
->firstTextBlock
;
1585 tPtr
->flags
.laidOut
= False
;
1590 if (tb
->sections
[0]._y
!=
1591 tb
->prior
->sections
[tb
->prior
->nsections
-1]._y
) {
1597 if(tb
->prior
&& tb
->prior
->sections
&& tb
->prior
->nsections
>0) {
1598 y
= tb
->prior
->sections
[tb
->prior
->nsections
-1]._y
+
1599 tb
->prior
->sections
[tb
->prior
->nsections
-1].h
-
1600 tb
->prior
->sections
[tb
->prior
->nsections
-1].max_d
;
1609 if (tb
->sections
&& tb
->nsections
>0) {
1610 wfree(tb
->sections
);
1611 tb
->sections
= NULL
;
1615 if (tb
->first
&& tb
->blank
&& tb
->next
&& !tb
->next
->first
) {
1616 TextBlock
*next
= tb
->next
;
1617 tPtr
->currentTextBlock
= tb
;
1618 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1624 if (tb
->first
&& tb
!= tPtr
->firstTextBlock
) {
1625 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1626 x
= tPtr
->margins
[tb
->marginN
].first
;
1627 bmargin
= tPtr
->margins
[tb
->marginN
].body
;
1633 if (!tPtr
->flags
.monoFont
) {
1635 width
= WMWidgetWidth(tb
->d
.widget
);
1637 width
= tb
->d
.pixmap
->width
;
1639 if (width
> tPtr
->docWidth
)
1640 tPtr
->docWidth
= width
;
1643 if (lw
>= tPtr
->visible
.w
- x
) {
1644 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1650 if(nitems
+ 1> itemsSize
) {
1651 items
= wrealloc(items
,
1652 (++itemsSize
)*sizeof(myLineItems
));
1655 items
[nitems
].tb
= tb
;
1656 items
[nitems
].begin
= 0;
1657 items
[nitems
].end
= 0;
1661 } else if ((start
= tb
->text
)) {
1663 font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
1666 mark
= strchr(start
, ' ');
1668 end
+= (int)(mark
-start
)+1;
1671 end
+= strlen(start
);
1678 if (end
-begin
> 0) {
1680 width
= WMWidthOfString(font
,
1681 &tb
->text
[begin
], end
-begin
);
1683 /* if it won't fit, char wrap it */
1684 if (width
>= tPtr
->visible
.w
) {
1685 char *t
= &tb
->text
[begin
];
1686 int l
=end
-begin
, i
=0;
1688 width
= WMWidthOfString(font
, t
, ++i
);
1689 } while (width
< tPtr
->visible
.w
&& i
< l
);
1692 start
= &tb
->text
[end
];
1698 if (lw
>= tPtr
->visible
.w
- x
) {
1699 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1705 if(nitems
+ 1 > itemsSize
) {
1706 items
= wrealloc(items
,
1707 (++itemsSize
)*sizeof(myLineItems
));
1710 items
[nitems
].tb
= tb
;
1711 items
[nitems
].begin
= begin
;
1712 items
[nitems
].end
= end
;
1720 /* not yet fully ready. but is already VERY FAST for a 3Mbyte file ;-) */
1721 if(0&&tPtr
->flags
.laidOut
1722 && tb
->next
&& tb
->next
->sections
&& tb
->next
->nsections
>0
1723 && (tPtr
->vpos
+ tPtr
->visible
.h
1724 < tb
->next
->sections
[0]._y
)) {
1725 if(tPtr
->lastTextBlock
->sections
1726 && tPtr
->lastTextBlock
->nsections
> 0 ) {
1727 TextBlock
*ltb
= tPtr
->lastTextBlock
;
1728 int ly
= ltb
->sections
[ltb
->nsections
-1]._y
;
1729 int lh
= ltb
->sections
[ltb
->nsections
-1].h
;
1732 lh
+= 1 + tPtr
->visible
.y
+ ltb
->sections
[ltb
->nsections
-1].max_d
;
1733 printf("it's %d\n", tPtr
->visible
.y
+ ltb
->sections
[ltb
->nsections
-1].max_d
);
1735 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1737 sd
= tPtr
->docHeight
-y
;
1739 printf("dif %d-%d: %d\n", ss
, sd
, ss
-sd
);
1740 y
+= tb
->next
->sections
[0]._y
-y
;
1742 printf("nitems%d\n", nitems
);
1744 y
= tPtr
->docHeight
+ss
-sd
;
1748 tPtr
->flags
.laidOut
= False
;
1757 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1759 if (tPtr
->docHeight
!= y
+10) {
1760 tPtr
->docHeight
= y
+10;
1761 updateScrollers(tPtr
);
1764 if(tPtr
->docWidth
> tPtr
->visible
.w
&& !tPtr
->hS
) {
1767 tPtr
->flags
.horizOnDemand
= True
;
1768 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, True
);
1769 event
.type
= Expose
;
1770 handleEvents(&event
, (void *)tPtr
);
1772 } else if(tPtr
->docWidth
<= tPtr
->visible
.w
1773 && tPtr
->hS
&& tPtr
->flags
.horizOnDemand
) {
1774 tPtr
->flags
.horizOnDemand
= False
;
1775 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, False
);
1778 tPtr
->flags
.laidOut
= True
;
1780 if(items
&& itemsSize
> 0)
1787 textDidResize(W_ViewDelegate
*self
, WMView
*view
)
1789 Text
*tPtr
= (Text
*)view
->self
;
1790 unsigned short w
= tPtr
->view
->size
.width
;
1791 unsigned short h
= tPtr
->view
->size
.height
;
1792 unsigned short rh
= 0, vw
= 0, rel
;
1794 rel
= (tPtr
->flags
.relief
== WRFlat
);
1796 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
) {
1797 WMMoveWidget(tPtr
->ruler
, 2, 2);
1798 WMResizeWidget(tPtr
->ruler
, w
- 4, 40);
1803 WMMoveWidget(tPtr
->vS
, 1 - (rel
?1:0), rh
+ 1 - (rel
?1:0));
1804 WMResizeWidget(tPtr
->vS
, 20, h
- rh
- 2 + (rel
?2:0));
1806 WMSetRulerOffset(tPtr
->ruler
,22);
1807 } else WMSetRulerOffset(tPtr
->ruler
, 2);
1811 WMMoveWidget(tPtr
->hS
, vw
, h
- 21);
1812 WMResizeWidget(tPtr
->hS
, w
- vw
- 1, 20);
1814 WMMoveWidget(tPtr
->hS
, vw
+1, h
- 21);
1815 WMResizeWidget(tPtr
->hS
, w
- vw
- 2, 20);
1819 tPtr
->visible
.x
= (tPtr
->vS
)?24:4;
1820 tPtr
->visible
.y
= (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)?43:3;
1821 tPtr
->visible
.w
= tPtr
->view
->size
.width
- tPtr
->visible
.x
- 8;
1822 tPtr
->visible
.h
= tPtr
->view
->size
.height
- tPtr
->visible
.y
;
1823 tPtr
->visible
.h
-= (tPtr
->hS
)?20:0;
1824 tPtr
->margins
[0].right
= tPtr
->visible
.w
;
1826 if (tPtr
->view
->flags
.realized
) {
1829 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
1830 tPtr
->db
= (Pixmap
) NULL
;
1833 if (tPtr
->visible
.w
< 40)
1834 tPtr
->visible
.w
= 40;
1835 if (tPtr
->visible
.h
< 20)
1836 tPtr
->visible
.h
= 20;
1839 tPtr
->db
= XCreatePixmap(tPtr
->view
->screen
->display
,
1840 tPtr
->view
->window
, tPtr
->visible
.w
,
1841 tPtr
->visible
.h
, tPtr
->view
->screen
->depth
);
1848 W_ViewDelegate _TextViewDelegate
=
1856 #define TEXT_BUFFER_INCR 8
1857 #define reqBlockSize(requested) (requested + TEXT_BUFFER_INCR)
1860 clearText(Text
*tPtr
)
1862 tPtr
->vpos
= tPtr
->hpos
= 0;
1863 tPtr
->docHeight
= tPtr
->docWidth
= 0;
1864 tPtr
->cursor
.x
= -23;
1866 if (!tPtr
->firstTextBlock
)
1869 while (tPtr
->currentTextBlock
)
1870 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1872 tPtr
->firstTextBlock
= NULL
;
1873 tPtr
->currentTextBlock
= NULL
;
1874 tPtr
->lastTextBlock
= NULL
;
1875 WMEmptyArray(tPtr
->gfxItems
);
1878 /* possibly remove a single character from the currentTextBlock,
1879 or if there's a selection, remove it...
1880 note that Delete and Backspace are treated differently */
1882 deleteTextInteractively(Text
*tPtr
, KeySym ksym
)
1885 Bool back
= (Bool
) (ksym
== XK_BackSpace
);
1886 Bool done
= 1, wasFirst
= 0;
1888 if (!tPtr
->flags
.editable
)
1891 if ( !(tb
= tPtr
->currentTextBlock
) )
1894 if (tPtr
->flags
.ownsSelection
) {
1895 if(removeSelection(tPtr
))
1896 layOutDocument(tPtr
);
1900 wasFirst
= tb
->first
;
1901 if (back
&& tPtr
->tpos
< 1) {
1903 if(tb
->prior
->blank
) {
1904 tPtr
->currentTextBlock
= tb
->prior
;
1905 WMRemoveTextBlock(tPtr
);
1906 tPtr
->currentTextBlock
= tb
;
1908 layOutDocument(tPtr
);
1912 TextBlock
*prior
= tb
->prior
;
1913 tPtr
->currentTextBlock
= tb
;
1914 WMRemoveTextBlock(tPtr
);
1923 tPtr
->tpos
= tb
->used
;
1925 tPtr
->currentTextBlock
= tb
;
1929 tb
->next
->first
= False
;
1930 layOutDocument(tPtr
);
1937 if ( (tb
->used
> 0) && ((back
?tPtr
->tpos
> 0:1))
1938 && (tPtr
->tpos
<= tb
->used
) && !tb
->graphic
) {
1941 memmove(&(tb
->text
[tPtr
->tpos
]),
1942 &(tb
->text
[tPtr
->tpos
+ 1]), tb
->used
- tPtr
->tpos
);
1947 /* if there are no characters left to back over in the textblock,
1948 but it still has characters to the right of the cursor: */
1949 if ( (back
? (tPtr
->tpos
== 0 && !done
) : ( tPtr
->tpos
>= tb
->used
))
1952 /* no more chars, and it's marked as blank? */
1954 TextBlock
*sibling
= (back
? tb
->prior
: tb
->next
);
1956 if(tb
->used
== 0 || tb
->graphic
)
1957 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1960 tPtr
->currentTextBlock
= sibling
;
1962 tPtr
->tpos
= (back
? 1 : 0);
1964 tPtr
->tpos
= (back
? sibling
->used
: 0);
1966 /* no more chars, so mark it as blank */
1967 } else if(tb
->used
== 0) {
1969 } else if(tb
->graphic
) {
1970 Bool hasNext
= (Bool
)(tb
->next
);
1972 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1975 } else if(tPtr
->currentTextBlock
) {
1976 tPtr
->tpos
= (tPtr
->currentTextBlock
->graphic
?
1977 1 : tPtr
->currentTextBlock
->used
);
1979 } else printf("DEBUG: unaccounted for... catch this!\n");
1982 layOutDocument(tPtr
);
1987 insertTextInteractively(Text
*tPtr
, char *text
, int len
)
1990 char *newline
= NULL
;
1992 if (!tPtr
->flags
.editable
) {
1996 if (len
< 1 || !text
)
2000 if(tPtr
->flags
.ignoreNewLine
&& *text
== '\n' && len
== 1)
2004 if (tPtr
->flags
.ownsSelection
)
2005 removeSelection(tPtr
);
2008 if (tPtr
->flags
.ignoreNewLine
) {
2010 for(i
=0; i
<len
; i
++) {
2011 if (text
[i
] == '\n')
2016 tb
= tPtr
->currentTextBlock
;
2017 if (!tb
|| tb
->graphic
) {
2019 WMAppendTextStream(tPtr
, text
);
2020 layOutDocument(tPtr
);
2024 if ((newline
= strchr(text
, '\n'))) {
2025 int nlen
= (int)(newline
-text
);
2026 int s
= tb
->used
- tPtr
->tpos
;
2028 if (!tb
->blank
&& nlen
>0) {
2033 memcpy(save
, &tb
->text
[tPtr
->tpos
], s
);
2034 tb
->used
-= (tb
->used
- tPtr
->tpos
);
2036 insertTextInteractively(tPtr
, text
, nlen
);
2038 WMAppendTextStream(tPtr
, newline
);
2040 insertTextInteractively(tPtr
, save
, s
);
2044 if (tPtr
->tpos
>0 && tPtr
->tpos
< tb
->used
2045 && !tb
->graphic
&& tb
->text
) {
2047 unsigned short savePos
= tPtr
->tpos
;
2048 void *ntb
= WMCreateTextBlockWithText(
2049 tPtr
, &tb
->text
[tPtr
->tpos
],
2050 tb
->d
.font
, tb
->color
, True
, tb
->used
- tPtr
->tpos
);
2052 if(tb
->sections
[0].end
== tPtr
->tpos
)
2053 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
2054 NULL
, tb
->d
.font
, tb
->color
, True
, 0));
2057 WMAppendTextBlock(tPtr
, ntb
);
2060 } else if (tPtr
->tpos
== tb
->used
) {
2061 if(tPtr
->flags
.indentNewLine
) {
2062 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
2063 " ", tb
->d
.font
, tb
->color
, True
, 4));
2066 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
2067 NULL
, tb
->d
.font
, tb
->color
, True
, 0));
2070 } else if (tPtr
->tpos
== 0) {
2071 if(tPtr
->flags
.indentNewLine
) {
2072 WMPrependTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
2073 " ", tb
->d
.font
, tb
->color
, True
, 4));
2075 WMPrependTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
2076 NULL
, tb
->d
.font
, tb
->color
, True
, 0));
2079 if(tPtr
->currentTextBlock
->next
)
2080 tPtr
->currentTextBlock
= tPtr
->currentTextBlock
->next
;
2084 if (tb
->used
+ len
>= tb
->allocated
) {
2085 tb
->allocated
= reqBlockSize(tb
->used
+len
);
2086 tb
->text
= wrealloc(tb
->text
, tb
->allocated
);
2090 memcpy(tb
->text
, text
, len
);
2093 tb
->text
[tb
->used
] = 0;
2097 memmove(&(tb
->text
[tPtr
->tpos
+len
]), &tb
->text
[tPtr
->tpos
],
2098 tb
->used
-tPtr
->tpos
+1);
2099 memmove(&tb
->text
[tPtr
->tpos
], text
, len
);
2102 tb
->text
[tb
->used
] = 0;
2107 layOutDocument(tPtr
);
2112 selectRegion(Text
*tPtr
, int x
, int y
)
2118 y
+= (tPtr
->flags
.rulerShown
? 40: 0);
2121 y
-= 10; /* the original offset */
2123 x
-= tPtr
->visible
.x
-2;
2127 tPtr
->sel
.x
= WMAX(0, WMIN(tPtr
->clicked
.x
, x
));
2128 tPtr
->sel
.w
= abs(tPtr
->clicked
.x
- x
);
2129 tPtr
->sel
.y
= WMAX(0, WMIN(tPtr
->clicked
.y
, y
));
2130 tPtr
->sel
.h
= abs(tPtr
->clicked
.y
- y
);
2132 tPtr
->flags
.ownsSelection
= True
;
2138 releaseSelection(Text
*tPtr
)
2140 TextBlock
*tb
= tPtr
->firstTextBlock
;
2143 tb
->selected
= False
;
2146 tPtr
->flags
.ownsSelection
= False
;
2147 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
,
2155 requestHandler(WMView
*view
, Atom selection
, Atom target
, void *cdata
,
2158 Text
*tPtr
= view
->self
;
2159 Display
*dpy
= tPtr
->view
->screen
->display
;
2161 Atom TEXT
= XInternAtom(dpy
, "TEXT", False
);
2162 Atom COMPOUND_TEXT
= XInternAtom(dpy
, "COMPOUND_TEXT", False
);
2163 WMData
*data
= NULL
;
2166 if (target
== XA_STRING
|| target
== TEXT
|| target
== COMPOUND_TEXT
) {
2167 char *text
= WMGetTextSelectedStream(tPtr
);
2170 data
= WMCreateDataWithBytes(text
, strlen(text
));
2171 WMSetDataFormat(data
, TYPETEXT
);
2175 } else printf("didn't get it\n");
2177 _TARGETS
= XInternAtom(dpy
, "TARGETS", False
);
2178 if (target
== _TARGETS
) {
2181 ptr
= wmalloc(4 * sizeof(Atom
));
2185 ptr
[3] = COMPOUND_TEXT
;
2187 data
= WMCreateDataWithBytes(ptr
, 4*4);
2188 WMSetDataFormat(data
, 32);
2199 lostHandler(WMView
*view
, Atom selection
, void *cdata
)
2201 releaseSelection((WMText
*)view
->self
);
2205 static WMSelectionProcs selectionHandler
= {
2206 requestHandler
, lostHandler
, NULL
2211 ownershipObserver(void *observerData
, WMNotification
*notification
)
2213 if (observerData
!= WMGetNotificationClientData(notification
))
2214 lostHandler(WMWidgetView(observerData
), XA_PRIMARY
, NULL
);
2219 autoSelectText(Text
*tPtr
, int clicks
)
2223 char *mark
= NULL
, behind
, ahead
;
2225 if(!(tb
= tPtr
->currentTextBlock
))
2231 switch(tb
->text
[tPtr
->tpos
]) {
2234 case '<': case '>': behind = '<'; ahead = '>'; break;
2235 case '{': case '}': behind = '{'; ahead = '}'; break;
2236 case '[': case ']': behind = '['; ahead = ']'; break;
2238 default: behind
= ahead
= ' ';
2241 tPtr
->sel
.y
= tPtr
->cursor
.y
+5;
2242 tPtr
->sel
.h
= 6;/*tPtr->cursor.h-10;*/
2245 tPtr
->sel
.x
= tb
->sections
[0].x
;
2246 tPtr
->sel
.w
= tb
->sections
[0].w
;
2248 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
2251 while(start
> 0 && tb
->text
[start
-1] != behind
)
2255 if(tPtr
->tpos
> start
){
2256 x
-= WMWidthOfString(font
, &tb
->text
[start
],
2257 tPtr
->tpos
- start
);
2259 tPtr
->sel
.x
= (x
<0?0:x
)+1;
2261 if((mark
= strchr(&tb
->text
[start
], ahead
))) {
2262 tPtr
->sel
.w
= WMWidthOfString(font
, &tb
->text
[start
],
2263 (int)(mark
- &tb
->text
[start
]));
2264 } else if(tb
->used
> start
) {
2265 tPtr
->sel
.w
= WMWidthOfString(font
, &tb
->text
[start
],
2270 } else if(clicks
== 3) {
2271 TextBlock
*cur
= tb
;
2273 while(tb
&& !tb
->first
) {
2276 tPtr
->sel
.y
= tb
->sections
[0]._y
;
2279 while(tb
->next
&& !tb
->next
->first
) {
2282 tPtr
->sel
.h
= tb
->sections
[tb
->nsections
-1]._y
2286 tPtr
->sel
.w
= tPtr
->docWidth
;
2287 tPtr
->clicked
.x
= 0; /* only for now, fix sel. code */
2290 if (!tPtr
->flags
.ownsSelection
) {
2291 WMCreateSelectionHandler(tPtr
->view
,
2292 XA_PRIMARY
, tPtr
->lastClickTime
, &selectionHandler
, NULL
);
2293 tPtr
->flags
.ownsSelection
= True
;
2301 fontChanged(void *observerData
, WMNotification
*notification
)
2303 WMText
*tPtr
= (WMText
*) observerData
;
2304 WMFont
*font
= (WMFont
*)WMGetNotificationClientData(notification
);
2305 printf("fontChanged\n");
2310 if (tPtr
->flags
.ownsSelection
)
2311 WMSetTextSelectionFont(tPtr
, font
);
2316 handleTextKeyPress(Text
*tPtr
, XEvent
*event
)
2320 int control_pressed
= False
;
2321 TextBlock
*tb
= NULL
;
2323 if (((XKeyEvent
*) event
)->state
& ControlMask
)
2324 control_pressed
= True
;
2325 buffer
[XLookupString(&event
->xkey
, buffer
, 63, &ksym
, NULL
)] = 0;
2330 if((tPtr
->currentTextBlock
= tPtr
->firstTextBlock
))
2332 updateCursorPosition(tPtr
);
2337 if((tPtr
->currentTextBlock
= tPtr
->lastTextBlock
)) {
2338 if(tPtr
->currentTextBlock
->graphic
)
2341 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
2343 updateCursorPosition(tPtr
);
2348 if(!(tb
= tPtr
->currentTextBlock
))
2356 tPtr
->currentTextBlock
= tb
->prior
;
2357 if(tPtr
->currentTextBlock
->graphic
)
2360 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
2362 if(!tb
->first
&& tPtr
->tpos
> 0)
2364 } else tPtr
->tpos
= 0;
2365 } else tPtr
->tpos
--;
2366 updateCursorPosition(tPtr
);
2371 if(!(tb
= tPtr
->currentTextBlock
))
2375 if(tPtr
->tpos
== tb
->used
) {
2378 tPtr
->currentTextBlock
= tb
->next
;
2380 if(!tb
->next
->first
&& tb
->next
->used
>0)
2386 tPtr
->tpos
= tb
->used
;
2388 } else tPtr
->tpos
++;
2389 updateCursorPosition(tPtr
);
2394 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
2395 tPtr
->clicked
.y
+ tPtr
->cursor
.h
- tPtr
->vpos
);
2400 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
2401 tPtr
->visible
.y
+ tPtr
->cursor
.y
- tPtr
->vpos
- 3);
2410 deleteTextInteractively(tPtr
, ksym
);
2411 updateCursorPosition(tPtr
);
2417 control_pressed
= True
;
2421 insertTextInteractively(tPtr
, " ", 4);
2422 updateCursorPosition(tPtr
);
2429 if (*buffer
!= 0 && !control_pressed
) {
2430 insertTextInteractively(tPtr
, buffer
, strlen(buffer
));
2431 updateCursorPosition(tPtr
);
2434 } else if (control_pressed
&& ksym
==XK_r
) {
2435 Bool i
= !tPtr
->flags
.rulerShown
;
2436 WMShowTextRuler(tPtr
, i
);
2437 tPtr
->flags
.rulerShown
= i
;
2438 } else if (control_pressed
&& *buffer
== '\a') {
2439 XBell(tPtr
->view
->screen
->display
, 0);
2441 WMRelayToNextResponder(tPtr
->view
, event
);
2445 if (!control_pressed
&& tPtr
->flags
.ownsSelection
) {
2446 releaseSelection(tPtr
);
2452 pasteText(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
2453 void *cdata
, WMData
*data
)
2455 Text
*tPtr
= (Text
*)view
->self
;
2458 tPtr
->flags
.waitingForSelection
= 0;
2461 text
= (char*)WMDataBytes(data
);
2464 (tPtr
->parser
) (tPtr
, (void *) text
);
2465 layOutDocument(tPtr
);
2466 } else insertTextInteractively(tPtr
, text
, strlen(text
));
2467 updateCursorPosition(tPtr
);
2473 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
2478 (tPtr
->parser
) (tPtr
, (void *) text
);
2479 layOutDocument(tPtr
);
2480 } else insertTextInteractively(tPtr
, text
, n
);
2481 updateCursorPosition(tPtr
);
2493 handleActionEvents(XEvent
*event
, void *data
)
2495 Text
*tPtr
= (Text
*)data
;
2496 Display
*dpy
= event
->xany
.display
;
2500 switch (event
->type
) {
2502 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2503 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2504 tPtr
->flags
.extendSelection
= True
;
2508 if (tPtr
->flags
.focused
) {
2509 XGrabPointer(dpy
, W_VIEW(tPtr
)->window
, False
,
2510 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
2511 GrabModeAsync
, GrabModeAsync
, None
,
2512 tPtr
->view
->screen
->invisibleCursor
, CurrentTime
);
2513 tPtr
->flags
.pointerGrabbed
= True
;
2514 handleTextKeyPress(tPtr
, event
);
2519 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2520 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2521 tPtr
->flags
.extendSelection
= False
;
2523 /* end modify flag so selection can be extended */
2530 if (tPtr
->flags
.pointerGrabbed
) {
2531 tPtr
->flags
.pointerGrabbed
= False
;
2532 XUngrabPointer(dpy
, CurrentTime
);
2535 if(tPtr
->flags
.waitingForSelection
)
2538 if ((event
->xmotion
.state
& Button1Mask
)) {
2540 if (WMIsDraggingFromView(tPtr
->view
)) {
2541 WMDragImageFromView(tPtr
->view
, event
);
2545 if (!tPtr
->flags
.ownsSelection
) {
2546 WMCreateSelectionHandler(tPtr
->view
,
2547 XA_PRIMARY
, event
->xbutton
.time
,
2548 &selectionHandler
, NULL
);
2549 tPtr
->flags
.ownsSelection
= True
;
2551 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2555 mouseOverObject(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2561 if (tPtr
->flags
.pointerGrabbed
) {
2562 tPtr
->flags
.pointerGrabbed
= False
;
2563 XUngrabPointer(dpy
, CurrentTime
);
2567 if (tPtr
->flags
.waitingForSelection
)
2570 if (tPtr
->flags
.extendSelection
&& tPtr
->flags
.ownsSelection
) {
2571 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2575 if (tPtr
->flags
.ownsSelection
)
2576 releaseSelection(tPtr
);
2579 if (event
->xbutton
.button
== Button1
) {
2580 TextBlock
*tb
= tPtr
->currentTextBlock
;
2582 if(WMIsDoubleClick(event
)) {
2584 tPtr
->lastClickTime
= event
->xbutton
.time
;
2585 if(tb
&& tb
->graphic
&& !tb
->object
) {
2586 if(tPtr
->delegate
&& tPtr
->delegate
->didDoubleClickOnPicture
) {
2589 desc
= wmalloc(tb
->used
+1);
2590 memcpy(desc
, tb
->text
, tb
->used
);
2592 (*tPtr
->delegate
->didDoubleClickOnPicture
)(tPtr
->delegate
, desc
);
2596 autoSelectText(tPtr
, 2);
2599 } else if (event
->xbutton
.time
- tPtr
->lastClickTime
2600 < WINGsConfiguration
.doubleClickDelay
) {
2601 tPtr
->lastClickTime
= event
->xbutton
.time
;
2602 autoSelectText(tPtr
, 3);
2606 if (!tPtr
->flags
.focused
) {
2607 WMSetFocusToWidget(tPtr
);
2608 tPtr
->flags
.focused
= True
;
2609 } else if (tb
&& tPtr
->flags
.isOverGraphic
&&
2610 tb
->graphic
&& !tb
->object
&& tb
->d
.pixmap
) {
2612 WMSetViewDragImage(tPtr
->view
, tb
->d
.pixmap
);
2613 WMDragImageFromView(tPtr
->view
, event
);
2617 tPtr
->lastClickTime
= event
->xbutton
.time
;
2618 cursorToTextPosition(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2622 if (event
->xbutton
.button
2623 == WINGsConfiguration
.mouseWheelDown
) {
2624 WMScrollText(tPtr
, 16);
2628 if (event
->xbutton
.button
2629 == WINGsConfiguration
.mouseWheelUp
) {
2630 WMScrollText(tPtr
, -16);
2634 if (event
->xbutton
.button
== Button2
) {
2638 if (!tPtr
->flags
.editable
) {
2643 if (!WMRequestSelection(tPtr
->view
, XA_PRIMARY
, XA_STRING
,
2644 event
->xbutton
.time
, pasteText
, NULL
)) {
2646 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
2647 tPtr
->flags
.waitingForSelection
= 0;
2653 (tPtr
->parser
) (tPtr
, (void *) text
);
2654 layOutDocument(tPtr
);
2657 insertTextInteractively(tPtr
, text
, n
);
2661 NOTIFY(tPtr
, didChange
, WMTextDidChangeNotification
,
2662 (void*)WMInsertTextEvent
);
2664 updateCursorPosition(tPtr
);
2668 tPtr
->flags
.waitingForSelection
= True
;
2676 if (tPtr
->flags
.pointerGrabbed
) {
2677 tPtr
->flags
.pointerGrabbed
= False
;
2678 XUngrabPointer(dpy
, CurrentTime
);
2682 if (tPtr
->flags
.waitingForSelection
)
2685 if (WMIsDraggingFromView(tPtr
->view
))
2686 WMDragImageFromView(tPtr
->view
, event
);
2693 handleEvents(XEvent
*event
, void *data
)
2695 Text
*tPtr
= (Text
*)data
;
2697 switch(event
->type
) {
2700 if (event
->xexpose
.count
!=0)
2704 if (!(W_VIEW(tPtr
->hS
))->flags
.realized
)
2705 WMRealizeWidget(tPtr
->hS
);
2709 if (!(W_VIEW(tPtr
->vS
))->flags
.realized
)
2710 WMRealizeWidget(tPtr
->vS
);
2714 if (!(W_VIEW(tPtr
->ruler
))->flags
.realized
)
2715 WMRealizeWidget(tPtr
->ruler
);
2720 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2726 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))
2729 tPtr
->flags
.focused
= True
;
2731 if (tPtr
->flags
.editable
&& !tPtr
->timerID
) {
2732 tPtr
->timerID
= WMAddTimerHandler(12+0*CURSOR_BLINK_ON_DELAY
,
2740 tPtr
->flags
.focused
= False
;
2743 if (tPtr
->timerID
) {
2744 WMDeleteTimerHandler(tPtr
->timerID
);
2745 tPtr
->timerID
= NULL
;
2754 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
2756 WMEmptyArray(tPtr
->gfxItems
);
2759 WMDeleteTimerHandler(tPtr
->timerID
);
2761 WMReleaseFont(tPtr
->dFont
);
2762 WMReleaseColor(tPtr
->dColor
);
2763 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
, CurrentTime
);
2764 WMRemoveNotificationObserver(tPtr
);
2766 WMFreeArray(tPtr
->xdndSourceTypes
);
2767 WMFreeArray(tPtr
->xdndDestinationTypes
);
2778 insertPlainText(Text
*tPtr
, char *text
)
2785 mark
= strchr(start
, '\n');
2787 tb
= WMCreateTextBlockWithText(tPtr
,
2789 tPtr
->dColor
, tPtr
->flags
.first
, (int)(mark
-start
));
2791 tPtr
->flags
.first
= True
;
2793 if (start
&& strlen(start
)) {
2794 tb
= WMCreateTextBlockWithText(tPtr
, start
, tPtr
->dFont
,
2795 tPtr
->dColor
, tPtr
->flags
.first
, strlen(start
));
2797 tPtr
->flags
.first
= False
;
2801 if (tPtr
->flags
.prepend
)
2802 WMPrependTextBlock(tPtr
, tb
);
2804 WMAppendTextBlock(tPtr
, tb
);
2810 rulerMoveCallBack(WMWidget
*w
, void *self
)
2812 Text
*tPtr
= (Text
*)self
;
2816 if (W_CLASS(tPtr
) != WC_Text
)
2824 rulerReleaseCallBack(WMWidget
*w
, void *self
)
2826 Text
*tPtr
= (Text
*)self
;
2830 if (W_CLASS(tPtr
) != WC_Text
)
2839 dropDataTypes(WMView
*self
)
2841 return ((Text
*)self
->self
)->xdndSourceTypes
;
2845 static WMDragOperationType
2846 wantedDropOperation(WMView
*self
)
2848 return WDOperationCopy
;
2853 acceptDropOperation(WMView
*self
, WMDragOperationType allowedOperation
)
2855 return (allowedOperation
== WDOperationCopy
);
2860 fetchDragData(WMView
*self
, char *type
)
2862 TextBlock
*tb
= ((WMText
*)self
->self
)->currentTextBlock
;
2866 if (strcmp(type
, "text/plain")) {
2870 desc
= wmalloc(tb
->used
+1);
2871 memcpy(desc
, tb
->text
, tb
->used
);
2873 data
= WMCreateDataWithBytes(desc
, strlen(desc
)+1);
2884 static WMDragSourceProcs _DragSourceProcs
= {
2886 wantedDropOperation
,
2888 acceptDropOperation
,
2896 requiredDataTypes(WMView
*self
, WMDragOperationType request
, WMArray
*sourceDataTypes
)
2898 return ((Text
*)self
->self
)->xdndDestinationTypes
;
2902 static WMDragOperationType
2903 allowedOperation(WMView
*self
, WMDragOperationType request
, WMArray
*sourceDataTypes
)
2905 return WDOperationCopy
;
2910 performDragOperation(WMView
*self
, WMArray
*dropData
, WMArray
*operations
,
2911 WMPoint
* dropLocation
)
2913 WMText
*tPtr
= (WMText
*)self
->self
;
2920 /* only one required type, implies only one drop data */
2922 /* get application/X-color if any */
2923 data
= (WMData
*)WMPopFromArray(dropData
);
2925 colorName
= (char*)WMDataBytes(data
);
2926 color
= WMCreateNamedColor(W_VIEW_SCREEN(self
), colorName
, True
);
2929 WMSetTextSelectionColor(tPtr
, color
);
2930 WMReleaseColor(color
);
2936 static WMDragDestinationProcs _DragDestinationProcs
= {
2941 performDragOperation
,
2947 getStream(WMText
*tPtr
, int sel
, int array
)
2949 TextBlock
*tb
= NULL
;
2951 unsigned long where
= 0;
2956 if (!(tb
= tPtr
->firstTextBlock
))
2960 (tPtr
->writer
) (tPtr
, (void *) text
);
2964 tb
= tPtr
->firstTextBlock
;
2967 if (!tb
->graphic
|| (tb
->graphic
&& !tPtr
->flags
.monoFont
)) {
2969 if (!sel
|| (tb
->graphic
&& tb
->selected
)) {
2971 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
)
2972 && tb
!= tPtr
->firstTextBlock
) {
2973 text
= wrealloc(text
, where
+1);
2974 text
[where
++] = '\n';
2980 if(tb
->graphic
&& array
) {
2981 text
= wrealloc(text
, where
+4);
2982 text
[where
++] = 0xFA;
2983 text
[where
++] = (tb
->used
>>8)&0x0ff;
2984 text
[where
++] = tb
->used
&0x0ff;
2985 text
[where
++] = tb
->allocated
; /* extra info */
2987 text
= wrealloc(text
, where
+tb
->used
);
2988 memcpy(&text
[where
], tb
->text
, tb
->used
);
2992 } else if (sel
&& tb
->selected
) {
2994 if (!tPtr
->flags
.ignoreNewLine
&& tb
->blank
) {
2995 text
= wrealloc(text
, where
+1);
2996 text
[where
++] = '\n';
3002 text
= wrealloc(text
, where
+(tb
->s_end
- tb
->s_begin
));
3003 memcpy(&text
[where
], &tb
->text
[tb
->s_begin
],
3004 tb
->s_end
- tb
->s_begin
);
3005 where
+= tb
->s_end
- tb
->s_begin
;
3010 _gSnext
:tb
= tb
->next
;
3013 /* +1 for the end of string, let's be nice */
3014 text
= wrealloc(text
, where
+1);
3021 releaseStreamObjects(void *data
)
3028 getStreamObjects(WMText
*tPtr
, int sel
)
3030 WMArray
*array
= WMCreateArrayWithDestructor(4, releaseStreamObjects
);
3034 char *start
, *fa
, *desc
;
3036 stream
= getStream(tPtr
, sel
, 1);
3043 fa
= strchr(start
, 0xFA);
3045 if((int)(fa
- start
)>0) {
3047 desc
[(int)(fa
- start
)] = 0;
3048 data
= WMCreateDataWithBytes((void *)desc
, (int)(fa
- start
));
3049 WMSetDataFormat(data
, TYPETEXT
);
3050 WMAddToArray(array
, (void *) data
);
3053 len
= *(fa
+1)*0xff + *(fa
+2);
3054 data
= WMCreateDataWithBytes((void *)(fa
+4), len
);
3055 WMSetDataFormat(data
, *(fa
+3));
3056 WMAddToArray(array
, (void *) data
);
3057 start
= fa
+ len
+ 4;
3060 if (start
&& strlen(start
)) {
3061 data
= WMCreateDataWithBytes((void *)start
, strlen(start
));
3062 WMSetDataFormat(data
, TYPETEXT
);
3063 WMAddToArray(array
, (void *) data
);
3074 #define XDND_TEXT_DATA_TYPE "text/plain"
3075 #define XDND_COLOR_DATA_TYPE "application/X-color"
3077 getXdndSourceTypeArray()
3079 WMArray
*types
= WMCreateArray(1);
3080 WMAddToArray(types
, XDND_TEXT_DATA_TYPE
);
3086 getXdndDestinationTypeArray()
3088 WMArray
*types
= WMCreateArray(1);
3089 WMAddToArray(types
, XDND_COLOR_DATA_TYPE
);
3095 WMCreateTextForDocumentType(WMWidget
*parent
, WMAction
*parser
, WMAction
*writer
)
3102 tPtr
= wmalloc(sizeof(Text
));
3103 memset(tPtr
, 0, sizeof(Text
));
3104 tPtr
->widgetClass
= WC_Text
;
3105 tPtr
->view
= W_CreateView(W_VIEW(parent
));
3107 perror("could not create text's view\n");
3112 dpy
= tPtr
->view
->screen
->display
;
3113 scr
= tPtr
->view
->screen
;
3115 tPtr
->view
->self
= tPtr
;
3116 tPtr
->view
->attribs
.cursor
= scr
->textCursor
;
3117 tPtr
->view
->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3118 W_ResizeView(tPtr
->view
, 250, 200);
3120 tPtr
->dColor
= WMBlackColor(scr
);
3121 tPtr
->fgColor
= WMBlackColor(scr
);
3122 tPtr
->bgColor
= WMWhiteColor(scr
);
3123 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->bgColor
);
3125 gcv
.graphics_exposures
= False
;
3126 gcv
.foreground
= W_PIXEL(scr
->gray
);
3127 gcv
.background
= W_PIXEL(scr
->darkGray
);
3128 gcv
.fill_style
= FillStippled
;
3129 /* why not use scr->stipple here? */
3130 gcv
.stipple
= XCreateBitmapFromData(dpy
, W_DRAWABLE(scr
), STIPPLE_BITS
,
3131 STIPPLE_WIDTH
, STIPPLE_HEIGHT
);
3132 tPtr
->stippledGC
= XCreateGC(dpy
, W_DRAWABLE(scr
),
3133 GCForeground
|GCBackground
|GCStipple
3134 |GCFillStyle
|GCGraphicsExposures
, &gcv
);
3140 tPtr
->dFont
= WMSystemFontOfSize(scr
, 12);
3142 tPtr
->view
->delegate
= &_TextViewDelegate
;
3144 tPtr
->delegate
= NULL
;
3147 tPtr
->timerID
= NULL
;
3150 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
3151 |EnterWindowMask
|LeaveWindowMask
|FocusChangeMask
,
3152 handleEvents
, tPtr
);
3154 WMCreateEventHandler(tPtr
->view
, ButtonReleaseMask
|ButtonPressMask
3155 |KeyReleaseMask
|KeyPressMask
|Button1MotionMask
,
3156 handleActionEvents
, tPtr
);
3158 WMAddNotificationObserver(ownershipObserver
, tPtr
,
3159 WMSelectionOwnerDidChangeNotification
,
3162 WMSetViewDragSourceProcs(tPtr
->view
, &_DragSourceProcs
);
3163 WMSetViewDragDestinationProcs(tPtr
->view
, &_DragDestinationProcs
);
3167 WMArray
*types
= WMCreateArray(2);
3168 WMAddToArray(types
, "application/X-color");
3169 WMAddToArray(types
, "application/X-image");
3170 WMRegisterViewForDraggedTypes(tPtr
->view
, types
);
3173 /*WMAddNotificationObserver(fontChanged, tPtr,
3174 WMFontPanelDidChangeNotification, tPtr);*/
3176 tPtr
->firstTextBlock
= NULL
;
3177 tPtr
->lastTextBlock
= NULL
;
3178 tPtr
->currentTextBlock
= NULL
;
3181 tPtr
->gfxItems
= WMCreateArray(4);
3183 tPtr
->parser
= parser
;
3184 tPtr
->writer
= writer
;
3186 tPtr
->sel
.x
= tPtr
->sel
.y
= 2;
3187 tPtr
->sel
.w
= tPtr
->sel
.h
= 0;
3189 tPtr
->clicked
.x
= tPtr
->clicked
.y
= 2;
3191 tPtr
->visible
.x
= tPtr
->visible
.y
= 2;
3192 tPtr
->visible
.h
= tPtr
->view
->size
.height
;
3193 tPtr
->visible
.w
= tPtr
->view
->size
.width
- 4;
3195 tPtr
->cursor
.x
= -23;
3198 tPtr
->docHeight
= 0;
3199 tPtr
->dBulletPix
= WMCreatePixmapFromXPMData(tPtr
->view
->screen
,
3201 tPtr
->db
= (Pixmap
) NULL
;
3202 tPtr
->bgPixmap
= NULL
;
3204 tPtr
->margins
= WMGetRulerMargins(NULL
);
3205 tPtr
->margins
->right
= tPtr
->visible
.w
;
3208 tPtr
->flags
.rulerShown
= False
;
3209 tPtr
->flags
.monoFont
= False
;
3210 tPtr
->flags
.focused
= False
;
3211 tPtr
->flags
.editable
= True
;
3212 tPtr
->flags
.ownsSelection
= False
;
3213 tPtr
->flags
.pointerGrabbed
= False
;
3214 tPtr
->flags
.extendSelection
= False
;
3215 tPtr
->flags
.frozen
= False
;
3216 tPtr
->flags
.cursorShown
= True
;
3217 tPtr
->flags
.acceptsGraphic
= False
;
3218 tPtr
->flags
.horizOnDemand
= False
;
3219 tPtr
->flags
.needsLayOut
= False
;
3220 tPtr
->flags
.ignoreNewLine
= False
;
3221 tPtr
->flags
.indentNewLine
= False
;
3222 tPtr
->flags
.laidOut
= False
;
3223 tPtr
->flags
.ownsSelection
= False
;
3224 tPtr
->flags
.waitingForSelection
= False
;
3225 tPtr
->flags
.prepend
= False
;
3226 tPtr
->flags
.isOverGraphic
= False
;
3227 tPtr
->flags
.relief
= WRSunken
;
3228 tPtr
->flags
.isOverGraphic
= 0;
3229 tPtr
->flags
.alignment
= WALeft
;
3230 tPtr
->flags
.first
= True
;
3232 tPtr
->xdndSourceTypes
= getXdndSourceTypeArray();
3233 tPtr
->xdndDestinationTypes
= getXdndDestinationTypeArray();
3239 WMPrependTextStream(WMText
*tPtr
, char *text
)
3241 CHECK_CLASS(tPtr
, WC_Text
);
3244 if (tPtr
->flags
.ownsSelection
)
3245 releaseSelection(tPtr
);
3247 updateScrollers(tPtr
);
3251 tPtr
->flags
.prepend
= True
;
3252 if (text
&& tPtr
->parser
)
3253 (tPtr
->parser
) (tPtr
, (void *) text
);
3255 insertPlainText(tPtr
, text
);
3257 tPtr
->flags
.needsLayOut
= True
;
3259 if(!tPtr
->flags
.frozen
) {
3260 layOutDocument(tPtr
);
3266 WMAppendTextStream(WMText
*tPtr
, char *text
)
3268 CHECK_CLASS(tPtr
, WC_Text
);
3271 if (tPtr
->flags
.ownsSelection
)
3272 releaseSelection(tPtr
);
3274 updateScrollers(tPtr
);
3278 tPtr
->flags
.prepend
= False
;
3279 if (text
&& tPtr
->parser
)
3280 (tPtr
->parser
) (tPtr
, (void *) text
);
3282 insertPlainText(tPtr
, text
);
3284 tPtr
->flags
.needsLayOut
= True
;
3285 if(tPtr
->currentTextBlock
) {
3286 if(tPtr
->currentTextBlock
->graphic
)
3289 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
3292 if(!tPtr
->flags
.frozen
) {
3293 layOutDocument(tPtr
);
3299 WMGetTextStream(WMText
*tPtr
)
3301 CHECK_CLASS(tPtr
, WC_Text
);
3303 return getStream(tPtr
, 0, 0);
3308 WMGetTextSelectedStream(WMText
*tPtr
)
3310 CHECK_CLASS(tPtr
, WC_Text
);
3312 return getStream(tPtr
, 1, 0);
3317 WMGetTextObjects(WMText
*tPtr
)
3319 CHECK_CLASS(tPtr
, WC_Text
);
3321 return getStreamObjects(tPtr
, 0);
3325 WMGetTextSelectedObjects(WMText
*tPtr
)
3327 CHECK_CLASS(tPtr
, WC_Text
);
3329 return getStreamObjects(tPtr
, 1);
3334 WMSetTextDelegate(WMText
*tPtr
, WMTextDelegate
*delegate
)
3336 CHECK_CLASS(tPtr
, WC_Text
);
3338 tPtr
->delegate
= delegate
;
3343 WMCreateTextBlockWithObject(WMText
*tPtr
, WMWidget
*w
,
3344 char *description
, WMColor
*color
,
3345 unsigned short first
, unsigned short extraInfo
)
3349 if (!w
|| !description
|| !color
)
3352 tb
= wmalloc(sizeof(TextBlock
));
3354 tb
->text
= wstrdup(description
);
3355 tb
->used
= strlen(description
);
3358 tb
->color
= WMRetainColor(color
);
3359 tb
->marginN
= newMargin(tPtr
, NULL
);
3360 tb
->allocated
= extraInfo
;
3365 tb
->underlined
= False
;
3366 tb
->selected
= False
;
3368 tb
->sections
= NULL
;
3378 WMCreateTextBlockWithPixmap(WMText
*tPtr
, WMPixmap
*p
,
3379 char *description
, WMColor
*color
,
3380 unsigned short first
, unsigned short extraInfo
)
3384 if (!p
|| !description
|| !color
)
3387 tb
= wmalloc(sizeof(TextBlock
));
3389 tb
->text
= wstrdup(description
);
3390 tb
->used
= strlen(description
);
3392 tb
->d
.pixmap
= WMRetainPixmap(p
);
3393 tb
->color
= WMRetainColor(color
);
3394 tb
->marginN
= newMargin(tPtr
, NULL
);
3395 tb
->allocated
= extraInfo
;
3400 tb
->underlined
= False
;
3401 tb
->selected
= False
;
3403 tb
->sections
= NULL
;
3413 WMCreateTextBlockWithText(WMText
*tPtr
, char *text
, WMFont
*font
, WMColor
*color
,
3414 unsigned short first
, unsigned short len
)
3418 if (!font
|| !color
)
3421 tb
= wmalloc(sizeof(TextBlock
));
3423 tb
->allocated
= reqBlockSize(len
);
3424 tb
->text
= (char *)wmalloc(tb
->allocated
);
3425 memset(tb
->text
, 0, tb
->allocated
);
3427 if (len
< 1|| !text
|| (*text
== '\n' && len
==1 )) {
3432 memcpy(tb
->text
, text
, len
);
3436 tb
->text
[tb
->used
] = 0;
3438 tb
->d
.font
= WMRetainFont(font
);
3439 tb
->color
= WMRetainColor(color
);
3440 tb
->marginN
= newMargin(tPtr
, NULL
);
3443 tb
->graphic
= False
;
3444 tb
->underlined
= False
;
3445 tb
->selected
= False
;
3447 tb
->sections
= NULL
;
3456 WMSetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int first
,
3457 unsigned int kanji
, unsigned int underlined
, int script
,
3458 WMRulerMargins
*margins
)
3460 TextBlock
*tb
= (TextBlock
*) vtb
;
3466 tb
->underlined
= underlined
;
3467 tb
->script
= script
;
3468 tb
->marginN
= newMargin(tPtr
, margins
);
3473 WMGetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int *first
,
3474 unsigned int *kanji
, unsigned int *underlined
, int *script
,
3475 WMRulerMargins
*margins
)
3477 TextBlock
*tb
= (TextBlock
*) vtb
;
3481 if (first
) *first
= tb
->first
;
3482 if (kanji
) *kanji
= tb
->kanji
;
3483 if (underlined
) *underlined
= tb
->underlined
;
3484 if (script
) *script
= tb
->script
;
3485 if (margins
) margins
= &tPtr
->margins
[tb
->marginN
];
3490 WMPrependTextBlock(WMText
*tPtr
, void *vtb
)
3492 TextBlock
*tb
= (TextBlock
*)vtb
;
3499 WMWidget
*w
= tb
->d
.widget
;
3500 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
3501 (W_VIEW(w
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3502 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3505 WMAddToArray(tPtr
->gfxItems
, (void *)tb
);
3509 tPtr
->tpos
= tb
->used
;
3512 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
3513 tb
->next
= tb
->prior
= NULL
;
3515 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
3516 = tPtr
->currentTextBlock
= tb
;
3521 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
3524 tb
->next
= tPtr
->currentTextBlock
;
3525 tb
->prior
= tPtr
->currentTextBlock
->prior
;
3526 if (tPtr
->currentTextBlock
->prior
)
3527 tPtr
->currentTextBlock
->prior
->next
= tb
;
3529 tPtr
->currentTextBlock
->prior
= tb
;
3531 tPtr
->firstTextBlock
= tb
;
3533 tPtr
->currentTextBlock
= tb
;
3538 WMAppendTextBlock(WMText
*tPtr
, void *vtb
)
3540 TextBlock
*tb
= (TextBlock
*)vtb
;
3547 WMWidget
*w
= tb
->d
.widget
;
3548 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
3549 (W_VIEW(w
))->attribs
.cursor
=
3550 tPtr
->view
->screen
->defaultCursor
;
3551 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3554 WMAddToArray(tPtr
->gfxItems
, (void *)tb
);
3558 tPtr
->tpos
= tb
->used
;
3562 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
3563 tb
->next
= tb
->prior
= NULL
;
3565 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
3566 = tPtr
->currentTextBlock
= tb
;
3571 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
3574 tb
->next
= tPtr
->currentTextBlock
->next
;
3575 tb
->prior
= tPtr
->currentTextBlock
;
3576 if (tPtr
->currentTextBlock
->next
)
3577 tPtr
->currentTextBlock
->next
->prior
= tb
;
3579 tPtr
->currentTextBlock
->next
= tb
;
3582 tPtr
->lastTextBlock
= tb
;
3584 tPtr
->currentTextBlock
= tb
;
3589 WMRemoveTextBlock(WMText
*tPtr
)
3591 TextBlock
*tb
= NULL
;
3593 if (!tPtr
->firstTextBlock
|| !tPtr
->lastTextBlock
||
3594 !tPtr
->currentTextBlock
) {
3598 tb
= tPtr
->currentTextBlock
;
3600 WMRemoveFromArray(tPtr
->gfxItems
, (void *)tb
);
3603 WMUnmapWidget(tb
->d
.widget
);
3607 if (tPtr
->currentTextBlock
== tPtr
->firstTextBlock
) {
3608 if (tPtr
->currentTextBlock
->next
)
3609 tPtr
->currentTextBlock
->next
->prior
= NULL
;
3611 tPtr
->firstTextBlock
= tPtr
->currentTextBlock
->next
;
3612 tPtr
->currentTextBlock
= tPtr
->firstTextBlock
;
3614 } else if (tPtr
->currentTextBlock
== tPtr
->lastTextBlock
) {
3615 tPtr
->currentTextBlock
->prior
->next
= NULL
;
3616 tPtr
->lastTextBlock
= tPtr
->currentTextBlock
->prior
;
3617 tPtr
->currentTextBlock
= tPtr
->lastTextBlock
;
3619 tPtr
->currentTextBlock
->prior
->next
= tPtr
->currentTextBlock
->next
;
3620 tPtr
->currentTextBlock
->next
->prior
= tPtr
->currentTextBlock
->prior
;
3621 tPtr
->currentTextBlock
= tPtr
->currentTextBlock
->next
;
3630 destroyWidget(WMWidget
*widget
)
3632 WMDestroyWidget(widget
);
3633 // -- never do this -- wfree(widget);
3639 WMDestroyTextBlock(WMText
*tPtr
, void *vtb
)
3641 TextBlock
*tb
= (TextBlock
*)vtb
;
3647 /* naturally, there's a danger to destroying widgets whose action
3648 * brings us here: ie. press a button to destroy it...
3649 * need to find a safer way. till then... this stays commented out */
3650 /* 5 months later... destroy it 10 seconds after now which should
3651 * be enough time for the widget's action to be completed... :-) */
3652 /* This is a bad assumption. Just destroy the widget here.
3653 * if the caller needs it, it can protect it with W_RetainView()
3654 * WMAddTimerHandler(10000, destroyWidget, (void *)tb->d.widget);*/
3655 WMDestroyWidget(tb
->d
.widget
);
3657 WMReleasePixmap(tb
->d
.pixmap
);
3660 WMReleaseFont(tb
->d
.font
);
3663 WMReleaseColor(tb
->color
);
3664 /* isn't this going to memleak if nsections==0? if (tb->sections && tb->nsections > 0) */
3666 wfree(tb
->sections
);
3673 WMSetTextForegroundColor(WMText
*tPtr
, WMColor
*color
)
3676 WMReleaseColor(tPtr
->fgColor
);
3678 tPtr
->fgColor
= WMRetainColor(color
? color
: tPtr
->view
->screen
->black
);
3685 WMSetTextBackgroundColor(WMText
*tPtr
, WMColor
*color
)
3688 WMReleaseColor(tPtr
->bgColor
);
3690 tPtr
->bgColor
= WMRetainColor(color
? color
: tPtr
->view
->screen
->white
);
3691 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->bgColor
);
3698 WMSetTextBackgroundPixmap(WMText
*tPtr
, WMPixmap
*pixmap
)
3701 WMReleasePixmap(tPtr
->bgPixmap
);
3704 tPtr
->bgPixmap
= WMRetainPixmap(pixmap
);
3706 tPtr
->bgPixmap
= NULL
;
3711 WMSetTextRelief(WMText
*tPtr
, WMReliefType relief
)
3713 tPtr
->flags
.relief
= relief
;
3714 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3719 WMSetTextHasHorizontalScroller(WMText
*tPtr
, Bool shouldhave
)
3721 if (shouldhave
&& !tPtr
->hS
) {
3722 tPtr
->hS
= WMCreateScroller(tPtr
);
3723 (W_VIEW(tPtr
->hS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3724 (W_VIEW(tPtr
->hS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3725 WMSetScrollerArrowsPosition(tPtr
->hS
, WSAMinEnd
);
3726 WMSetScrollerAction(tPtr
->hS
, scrollersCallBack
, tPtr
);
3727 WMMapWidget(tPtr
->hS
);
3728 } else if (!shouldhave
&& tPtr
->hS
) {
3729 WMUnmapWidget(tPtr
->hS
);
3730 WMDestroyWidget(tPtr
->hS
);
3736 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3741 WMSetTextHasRuler(WMText
*tPtr
, Bool shouldhave
)
3743 if(shouldhave
&& !tPtr
->ruler
) {
3744 tPtr
->ruler
= WMCreateRuler(tPtr
);
3745 (W_VIEW(tPtr
->ruler
))->attribs
.cursor
=
3746 tPtr
->view
->screen
->defaultCursor
;
3747 (W_VIEW(tPtr
->ruler
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3748 WMSetRulerReleaseAction(tPtr
->ruler
, rulerReleaseCallBack
, tPtr
);
3749 WMSetRulerMoveAction(tPtr
->ruler
, rulerMoveCallBack
, tPtr
);
3750 } else if(!shouldhave
&& tPtr
->ruler
) {
3751 WMShowTextRuler(tPtr
, False
);
3752 WMDestroyWidget(tPtr
->ruler
);
3755 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3759 WMShowTextRuler(WMText
*tPtr
, Bool show
)
3764 if(tPtr
->flags
.monoFont
)
3767 tPtr
->flags
.rulerShown
= show
;
3769 WMMapWidget(tPtr
->ruler
);
3771 WMUnmapWidget(tPtr
->ruler
);
3774 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3779 WMGetTextRulerShown(WMText
*tPtr
)
3784 return tPtr
->flags
.rulerShown
;
3789 WMSetTextHasVerticalScroller(WMText
*tPtr
, Bool shouldhave
)
3791 if (shouldhave
&& !tPtr
->vS
) {
3792 tPtr
->vS
= WMCreateScroller(tPtr
);
3793 (W_VIEW(tPtr
->vS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3794 (W_VIEW(tPtr
->vS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3795 WMSetScrollerArrowsPosition(tPtr
->vS
, WSAMaxEnd
);
3796 WMSetScrollerAction(tPtr
->vS
, scrollersCallBack
, tPtr
);
3797 WMMapWidget(tPtr
->vS
);
3798 } else if (!shouldhave
&& tPtr
->vS
) {
3799 WMUnmapWidget(tPtr
->vS
);
3800 WMDestroyWidget(tPtr
->vS
);
3806 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3811 WMScrollText(WMText
*tPtr
, int amount
)
3815 if (amount
== 0 || !tPtr
->view
->flags
.realized
)
3819 if (tPtr
->vpos
> 0) {
3820 if (tPtr
->vpos
> abs(amount
)) tPtr
->vpos
+= amount
;
3825 int limit
= tPtr
->docHeight
- tPtr
->visible
.h
;
3826 if (tPtr
->vpos
< limit
) {
3827 if (tPtr
->vpos
< limit
-amount
) tPtr
->vpos
+= amount
;
3828 else tPtr
->vpos
= limit
;
3833 if (scroll
&& tPtr
->vpos
!= tPtr
->prevVpos
) {
3834 updateScrollers(tPtr
);
3837 tPtr
->prevVpos
= tPtr
->vpos
;
3843 WMPageText(WMText
*tPtr
, Bool direction
)
3845 if (!tPtr
->view
->flags
.realized
)
3848 return WMScrollText(tPtr
, direction
?tPtr
->visible
.h
:-tPtr
->visible
.h
);
3853 WMSetTextEditable(WMText
*tPtr
, Bool editable
)
3855 tPtr
->flags
.editable
= editable
;
3860 WMGetTextEditable(WMText
*tPtr
)
3862 return tPtr
->flags
.editable
;
3866 WMSetTextIndentNewLines(WMText
*tPtr
, Bool indent
)
3868 tPtr
->flags
.indentNewLine
= indent
;
3872 WMSetTextIgnoresNewline(WMText
*tPtr
, Bool ignore
)
3874 tPtr
->flags
.ignoreNewLine
= ignore
;
3878 WMGetTextIgnoresNewline(WMText
*tPtr
)
3880 return tPtr
->flags
.ignoreNewLine
;
3884 WMSetTextUsesMonoFont(WMText
*tPtr
, Bool mono
)
3887 if(tPtr
->flags
.rulerShown
)
3888 WMShowTextRuler(tPtr
, False
);
3889 if(tPtr
->flags
.alignment
!= WALeft
)
3890 tPtr
->flags
.alignment
= WALeft
;
3893 tPtr
->flags
.monoFont
= mono
;
3894 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3898 WMGetTextUsesMonoFont(WMText
*tPtr
)
3900 return tPtr
->flags
.monoFont
;
3905 WMSetTextDefaultFont(WMText
*tPtr
, WMFont
*font
)
3908 WMReleaseFont(tPtr
->dFont
);
3911 tPtr
->dFont
= WMRetainFont(font
);
3913 tPtr
->dFont
= WMSystemFontOfSize(tPtr
->view
->screen
, 12);
3919 WMGetTextDefaultFont(WMText
*tPtr
)
3921 return WMRetainFont(tPtr
->dFont
);
3926 WMSetTextDefaultColor(WMText
*tPtr
, WMColor
*color
)
3929 WMReleaseColor(tPtr
->dColor
);
3932 tPtr
->dColor
= WMRetainColor(color
);
3934 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
3940 WMGetTextDefaultColor(WMText
*tPtr
)
3942 return tPtr
->dColor
;
3947 WMSetTextAlignment(WMText
*tPtr
, WMAlignment alignment
)
3949 if(tPtr
->flags
.monoFont
)
3950 tPtr
->flags
.alignment
= WALeft
;
3952 tPtr
->flags
.alignment
= alignment
;
3958 WMGetTextInsertType(WMText
*tPtr
)
3960 return tPtr
->flags
.prepend
;
3965 WMSetTextSelectionColor(WMText
*tPtr
, WMColor
*color
)
3967 setSelectionProperty(tPtr
, NULL
, color
, -1);
3972 WMGetTextSelectionColor(WMText
*tPtr
)
3976 tb
= tPtr
->currentTextBlock
;
3978 if (!tb
|| !tPtr
->flags
.ownsSelection
)
3989 WMSetTextSelectionFont(WMText
*tPtr
, WMFont
*font
)
3991 setSelectionProperty(tPtr
, font
, NULL
, -1) ;
3996 WMGetTextSelectionFont(WMText
*tPtr
)
4000 tb
= tPtr
->currentTextBlock
;
4002 if (!tb
|| !tPtr
->flags
.ownsSelection
)
4009 tb
= getFirstNonGraphicBlockFor(tb
, 1);
4013 return (tb
->selected
? tb
->d
.font
: NULL
);
4018 WMSetTextSelectionUnderlined(WMText
*tPtr
, int underlined
)
4021 if (underlined
!=0 && underlined
!=1)
4024 setSelectionProperty(tPtr
, NULL
, NULL
, underlined
);
4029 WMGetTextSelectionUnderlined(WMText
*tPtr
)
4033 tb
= tPtr
->currentTextBlock
;
4035 if (!tb
|| !tPtr
->flags
.ownsSelection
)
4041 return tb
->underlined
;
4046 WMFreezeText(WMText
*tPtr
)
4048 tPtr
->flags
.frozen
= True
;
4053 WMThawText(WMText
*tPtr
)
4055 tPtr
->flags
.frozen
= False
;
4057 if(tPtr
->flags
.monoFont
) {
4058 int j
, c
= WMGetArrayItemCount(tPtr
->gfxItems
);
4061 /* make sure to unmap widgets no matter where they are */
4062 /* they'll be later remapped if needed by paintText */
4063 for(j
=0; j
<c
; j
++) {
4064 if ((tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
))) {
4065 if (tb
->object
&& ((W_VIEW(tb
->d
.widget
))->flags
.mapped
))
4066 WMUnmapWidget(tb
->d
.widget
);
4072 tPtr
->flags
.laidOut
= False
;
4073 layOutDocument(tPtr
);
4074 updateScrollers(tPtr
);
4076 tPtr
->flags
.needsLayOut
= False
;
4080 /* find first occurence of a string */
4082 mystrstr(char *haystack
, char *needle
, unsigned short len
, char *end
,
4087 if(!haystack
|| !needle
|| !end
)
4090 for (ptr
= haystack
; ptr
< end
; ptr
++) {
4092 if (*ptr
== *needle
&& !strncmp(ptr
, needle
, len
))
4096 if (tolower(*ptr
) == tolower(*needle
) &&
4097 !strncasecmp(ptr
, needle
, len
))
4105 /* find last occurence of a string */
4107 mystrrstr(char *haystack
, char *needle
, unsigned short len
, char *end
,
4112 if(!haystack
|| !needle
|| !end
)
4115 for (ptr
= haystack
-2; ptr
> end
; ptr
--) {
4117 if (*ptr
== *needle
&& !strncmp(ptr
, needle
, len
))
4120 if (tolower(*ptr
) == tolower(*needle
) &&
4121 !strncasecmp(ptr
, needle
, len
))
4131 WMFindInTextStream(WMText
*tPtr
, char *needle
, Bool direction
,
4140 if (! (tb
= tPtr
->currentTextBlock
)) {
4141 if (! (tb
= ( (direction
> 0) ?
4142 tPtr
->firstTextBlock
: tPtr
->lastTextBlock
) ) ){
4146 /* if(tb != ((direction>0) ?tPtr->firstTextBlock : tPtr->lastTextBlock))
4147 tb = (direction>0) ? tb->next : tb->prior; */
4148 if(tb
!= tPtr
->lastTextBlock
)
4152 tb
= tPtr
->currentTextBlock
;
4160 if(pos
+1 < tb
->used
)
4163 if(tb
->used
- pos
> 0 && pos
> 0) {
4164 mark
= mystrstr(&tb
->text
[pos
], needle
,
4165 strlen(needle
), &tb
->text
[tb
->used
], caseSensitive
);
4178 mark
= mystrrstr(&tb
->text
[pos
], needle
,
4179 strlen(needle
), tb
->text
, caseSensitive
);
4191 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
4193 tPtr
->tpos
= (int)(mark
- tb
->text
);
4194 tPtr
->currentTextBlock
= tb
;
4195 updateCursorPosition(tPtr
);
4196 tPtr
->sel
.y
= tPtr
->cursor
.y
+5;
4197 tPtr
->sel
.h
= tPtr
->cursor
.h
-10;
4198 tPtr
->sel
.x
= tPtr
->cursor
.x
+1;
4199 tPtr
->sel
.w
= WMIN(WMWidthOfString(font
,
4200 &tb
->text
[tPtr
->tpos
], strlen(needle
)),
4201 tPtr
->docWidth
- tPtr
->sel
.x
);
4202 tPtr
->flags
.ownsSelection
= True
;
4209 tb
= (direction
>0) ? tb
->next
: tb
->prior
;
4211 pos
= (direction
>0) ? 0 : tb
->used
;
4220 WMReplaceTextSelection(WMText
*tPtr
, char *replacement
)
4222 if (!tPtr
->flags
.ownsSelection
)
4225 removeSelection(tPtr
);
4228 insertTextInteractively(tPtr
, replacement
, strlen(replacement
));
4229 updateCursorPosition(tPtr
);