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 GC bgGC
; /* the background GC to draw with */
110 GC fgGC
; /* the foreground GC to draw with */
111 GC stippledGC
; /* the GC to overlay selected graphics with */
112 Pixmap db
; /* the buffer on which to draw */
113 WMPixmap
*bgPixmap
; /* the background pixmap */
115 myRect visible
; /* the actual rectangle that can be drawn into */
116 myRect cursor
; /* the position and (height) of cursor */
117 myRect sel
; /* the selection rectangle */
119 WMPoint clicked
; /* where in the _document_ was clicked */
121 unsigned short tpos
; /* the position in the currentTextBlock */
122 unsigned short docWidth
; /* the width of the entire document */
123 unsigned int docHeight
; /* the height of the entire document */
125 TextBlock
*firstTextBlock
;
126 TextBlock
*lastTextBlock
;
127 TextBlock
*currentTextBlock
;
129 WMArray
*gfxItems
; /* a nice array of graphic items */
132 WMHandlerID timerID
; /* for nice twinky-winky */
137 WMTextDelegate
*delegate
;
140 WMRulerMargins
*margins
; /* an array of margins */
142 unsigned int nMargins
:7; /* the total number of margins in use */
144 unsigned int monoFont
:1; /* whether to ignore formats and graphic */
145 unsigned int focused
:1; /* whether this instance has input focus */
146 unsigned int editable
:1; /* "silly user, you can't edit me" */
147 unsigned int ownsSelection
:1; /* "I ownz the current selection!" */
148 unsigned int pointerGrabbed
:1;/* "heh, gib me pointer" */
149 unsigned int extendSelection
:1; /* shift-drag to select more regions */
151 unsigned int rulerShown
:1; /* whether the ruler is shown or not */
152 unsigned int frozen
:1; /* whether screen updates are to be made */
153 unsigned int cursorShown
:1; /* whether to show the cursor */
154 unsigned int acceptsGraphic
:1;/* accept graphic when dropped */
155 unsigned int horizOnDemand
:1;/* if a large image should appear*/
156 unsigned int needsLayOut
:1; /* in case of Append/Deletes */
157 unsigned int ignoreNewLine
:1;/* turn it into a ' ' in streams > 1 */
158 unsigned int indentNewLine
:1;/* add " " for a newline typed */
159 unsigned int laidOut
:1; /* have the TextBlocks all been laid out */
160 unsigned int waitingForSelection
:1; /* I don't wanna wait in vain... */
161 unsigned int prepend
:1; /* prepend=1, append=0 (for parsers) */
162 WMAlignment alignment
:2; /* the alignment for text */
163 WMReliefType relief
:3; /* the relief to display with */
164 unsigned int isOverGraphic
:2;/* the mouse is over a graphic */
165 unsigned int first
:1; /* for plain text parsing, newline? */
166 /* unsigned int RESERVED:1; */
171 #define NOTIFY(T,C,N,A) {\
172 WMNotification *notif = WMCreateNotification(N,T,A);\
173 if ((T)->delegate && (T)->delegate->C)\
174 (*(T)->delegate->C)((T)->delegate,notif);\
175 WMPostNotification(notif);\
176 WMReleaseNotification(notif);}
182 /* just to print blocks of text not terminated by \0 */
184 output(char *ptr
, int len
)
191 /* printf(" s is [%s] (%d)\n", s, strlen(s)); */
199 #define CURSOR_BLINK_ON_DELAY 600
200 #define CURSOR_BLINK_OFF_DELAY 400
204 #define STIPPLE_WIDTH 8
205 #define STIPPLE_HEIGHT 8
206 static unsigned char STIPPLE_BITS
[] = {
207 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa
212 static char *default_bullet
[] = {
214 " c None s None", ". c black",
215 "X c white", "o c #808080",
224 static void handleEvents(XEvent
*event
, void *data
);
225 static void layOutDocument(Text
*tPtr
);
226 static void updateScrollers(Text
*tPtr
);
230 getMarginNumber(Text
*tPtr
, WMRulerMargins
*margins
)
234 for(i
=0; i
< tPtr
->nMargins
; i
++) {
236 if(WMIsMarginEqualToMargin(&tPtr
->margins
[i
], margins
))
246 newMargin(Text
*tPtr
, WMRulerMargins
*margins
)
251 tPtr
->margins
[0].retainCount
++;
255 n
= getMarginNumber(tPtr
, margins
);
259 if(tPtr
->nMargins
>= 127) {
260 n
= tPtr
->nMargins
-1;
264 tPtr
->margins
= wrealloc(tPtr
->margins
,
265 (++tPtr
->nMargins
)*sizeof(WMRulerMargins
));
267 n
= tPtr
->nMargins
-1;
268 tPtr
->margins
[n
].left
= margins
->left
;
269 tPtr
->margins
[n
].first
= margins
->first
;
270 tPtr
->margins
[n
].body
= margins
->body
;
271 tPtr
->margins
[n
].right
= margins
->right
;
272 /* for each tab... */
273 tPtr
->margins
[n
].retainCount
= 1;
275 tPtr
->margins
[n
].retainCount
++;
282 sectionWasSelected(Text
*tPtr
, TextBlock
*tb
, XRectangle
*rect
, int s
)
284 unsigned short i
, w
, lw
, selected
= False
, extend
= False
;
288 /* if selection rectangle completely encloses the section */
289 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
) ) {
293 sel
.w
= tPtr
->visible
.w
;
294 selected
= extend
= True
;
296 /* or if it starts on a line and then goes further down */
297 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
298 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
299 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
300 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
301 >= tPtr
->visible
.y
+ tPtr
->sel
.y
) ) {
302 sel
.x
= WMAX(tPtr
->sel
.x
, tPtr
->clicked
.x
);
303 sel
.w
= tPtr
->visible
.w
;
304 selected
= extend
= True
;
306 /* or if it begins before a line, but ends on it */
307 } else if ((tb
->sections
[s
]._y
>= tPtr
->visible
.y
+ tPtr
->sel
.y
)
308 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
309 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
)
310 && (tb
->sections
[s
]._y
311 <= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
313 if (1||tPtr
->sel
.x
+ tPtr
->sel
.w
> tPtr
->clicked
.x
)
314 sel
.w
= tPtr
->sel
.x
+ tPtr
->sel
.w
;
321 /* or if the selection rectangle lies entirely within a line */
322 } else if ((tb
->sections
[s
]._y
<= tPtr
->visible
.y
+ tPtr
->sel
.y
)
323 && (tPtr
->sel
.w
>= 2)
324 && (tb
->sections
[s
]._y
+ tb
->sections
[s
].h
325 >= tPtr
->visible
.y
+ tPtr
->sel
.y
+ tPtr
->sel
.h
) ) {
334 /* if not within (modified) selection rectangle */
335 if ( tb
->sections
[s
].x
> sel
.x
+ sel
.w
336 || tb
->sections
[s
].x
+ tb
->sections
[s
].w
< sel
.x
)
340 if ( tb
->sections
[s
].x
+ tb
->sections
[s
].w
<= sel
.x
+ sel
.w
341 && tb
->sections
[s
].x
>= sel
.x
) {
342 rect
->width
= tb
->sections
[s
].w
;
343 rect
->x
= tb
->sections
[s
].x
;
348 i
= tb
->sections
[s
].begin
;
351 if (0&& tb
->sections
[s
].x
>= sel
.x
) {
352 tb
->s_begin
= tb
->sections
[s
].begin
;
356 while (++i
<= tb
->sections
[s
].end
) {
358 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
361 if (lw
+ tb
->sections
[s
].x
>= sel
.x
362 || i
== tb
->sections
[s
].end
) {
365 tb
->s_begin
= (tb
->selected
? WMIN(tb
->s_begin
, i
) : i
);
370 if (i
> tb
->sections
[s
].end
) {
371 printf("WasSelected: (i > tb->sections[s].end) \n");
375 _selEnd
: rect
->x
= tb
->sections
[s
].x
+ lw
;
377 while(++i
<= tb
->sections
[s
].end
) {
379 w
= WMWidthOfString(tb
->d
.font
, &(tb
->text
[i
-1]), 1);
382 if (lw
+ rect
->x
>= sel
.x
+ sel
.w
383 || i
== tb
->sections
[s
].end
) {
385 if (i
!= tb
->sections
[s
].end
) {
391 if (tb
->sections
[s
].last
&& sel
.x
+ sel
.w
392 >= tb
->sections
[s
].x
+ tb
->sections
[s
].w
394 rect
->width
+= (tPtr
->visible
.w
- rect
->x
- lw
);
397 tb
->s_end
= (tb
->selected
? WMAX(tb
->s_end
, i
) : i
);
406 rect
->y
= tb
->sections
[s
]._y
- tPtr
->vpos
;
407 rect
->height
= tb
->sections
[s
].h
;
408 if(tb
->graphic
) { printf("DEBUG: graphic s%d h%d\n", s
,tb
->sections
[s
].h
);}
415 setSelectionProperty(WMText
*tPtr
, WMFont
*font
, WMColor
*color
, int underlined
)
420 tb
= tPtr
->firstTextBlock
;
421 if (!tb
|| !tPtr
->flags
.ownsSelection
)
424 if(font
&& (!color
|| underlined
==-1))
428 if (tPtr
->flags
.monoFont
|| tb
->selected
) {
430 if (tPtr
->flags
.monoFont
|| (tb
->s_end
- tb
->s_begin
== tb
->used
)
435 WMReleaseFont(tb
->d
.font
);
436 tb
->d
.font
= WMRetainFont(font
);
438 } else if(underlined
!=-1) {
439 tb
->underlined
= underlined
;
441 WMReleaseColor(tb
->color
);
442 tb
->color
= WMRetainColor(color
);
445 } else if (tb
->s_end
<= tb
->used
&& tb
->s_begin
< tb
->s_end
) {
447 TextBlock
*midtb
, *otb
= tb
;
449 if(underlined
!= -1) {
450 midtb
= (TextBlock
*) WMCreateTextBlockWithText(tPtr
,
451 &(tb
->text
[tb
->s_begin
]), tb
->d
.font
, tb
->color
,
452 False
, (tb
->s_end
- tb
->s_begin
));
454 midtb
= (TextBlock
*) WMCreateTextBlockWithText(tPtr
,
455 &(tb
->text
[tb
->s_begin
]),
456 (isFont
?font
:tb
->d
.font
),
457 (isFont
?tb
->color
:color
),
458 False
, (tb
->s_end
- tb
->s_begin
));
463 if(underlined
!= -1) {
464 midtb
->underlined
= underlined
;
466 midtb
->underlined
= otb
->underlined
;
469 midtb
->selected
= !True
;
471 midtb
->s_end
= midtb
->used
;
472 tPtr
->currentTextBlock
= tb
;
473 WMAppendTextBlock(tPtr
, midtb
);
474 tb
= tPtr
->currentTextBlock
;
477 if (otb
->used
- otb
->s_end
> 0) {
480 WMCreateTextBlockWithText(tPtr
,
481 &(otb
->text
[otb
->s_end
]), otb
->d
.font
, otb
->color
,
482 False
, otb
->used
- otb
->s_end
);
485 ntb
->underlined
= otb
->underlined
;
486 ntb
->selected
= False
;
487 WMAppendTextBlock(tPtr
, ntb
);
488 tb
= tPtr
->currentTextBlock
;
493 tPtr
->currentTextBlock
= midtb
;
496 otb
->selected
= False
;
497 otb
->used
= otb
->s_begin
;
504 tPtr
->flags
.needsLayOut
= True
;
507 /* in case the size changed... */
508 if(isFont
&& tPtr
->currentTextBlock
) {
509 TextBlock
*tb
= tPtr
->currentTextBlock
;
511 printf("%d %d %d\n", tPtr
->sel
.y
, tPtr
->sel
.h
, tPtr
->sel
.w
);
512 tPtr
->sel
.y
= 3 + tb
->sections
[0]._y
;
513 tPtr
->sel
.h
= tb
->sections
[tb
->nsections
-1]._y
- tb
->sections
[0]._y
;
514 tPtr
->sel
.w
= tb
->sections
[tb
->nsections
-1].w
;
515 if(tb
->sections
[tb
->nsections
-1]._y
!= tb
->sections
[0]._y
) {
518 printf("%d %d %d\n\n\n", tPtr
->sel
.y
, tPtr
->sel
.h
, tPtr
->sel
.w
);
525 removeSelection(Text
*tPtr
)
527 TextBlock
*tb
= NULL
;
530 if (!(tb
= tPtr
->firstTextBlock
))
535 if(!first
&& !tb
->graphic
) {
536 WMReleaseFont(tPtr
->dFont
);
537 tPtr
->dFont
= WMRetainFont(tb
->d
.font
);
541 if ( (tb
->s_end
- tb
->s_begin
== tb
->used
) || tb
->graphic
) {
542 tPtr
->currentTextBlock
= tb
;
545 } else if(tb
->prior
) {
546 if(tb
->prior
->graphic
)
549 tPtr
->tpos
= tb
->prior
->used
;
550 } else tPtr
->tpos
= 0;
552 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
553 tb
= tPtr
->currentTextBlock
;
556 } else if (tb
->s_end
<= tb
->used
) {
557 memmove(&(tb
->text
[tb
->s_begin
]),
558 &(tb
->text
[tb
->s_end
]), tb
->used
- tb
->s_end
);
559 tb
->used
-= (tb
->s_end
- tb
->s_begin
);
560 tb
->selected
= False
;
561 tPtr
->tpos
= tb
->s_begin
;
572 getFirstNonGraphicBlockFor(TextBlock
*tb
, short dir
)
574 TextBlock
*hold
= tb
;
582 tb
= (dir
? tb
->next
: tb
->prior
);
590 tb
= (dir
? tb
->prior
: tb
->next
);
602 updateStartForCurrentTextBlock(Text
*tPtr
, int x
, int y
, int *dir
,
605 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
606 tb
= getFirstNonGraphicBlockFor(tb
, *dir
);
611 tPtr
->currentTextBlock
=
612 (dir
? tPtr
->lastTextBlock
: tPtr
->firstTextBlock
);
620 layOutDocument(tPtr
);
624 *dir
= !(y
<= tb
->sections
[0].y
);
626 if ( ( y
<= tb
->sections
[0]._y
+ tb
->sections
[0].h
)
627 && (y
>= tb
->sections
[0]._y
) ) {
628 /* if it's on the same line */
629 if(x
< tb
->sections
[0].x
)
633 if ( ( y
<= tb
->sections
[tb
->nsections
-1]._y
634 + tb
->sections
[tb
->nsections
-1].h
)
635 && (y
>= tb
->sections
[tb
->nsections
-1]._y
) ) {
636 /* if it's on the same line */
637 if(x
> tb
->sections
[tb
->nsections
-1].x
)
647 paintText(Text
*tPtr
)
653 int len
, y
, c
, s
, done
=False
, prev_y
=-23, dir
/* 1 = down */;
654 WMScreen
*scr
= tPtr
->view
->screen
;
655 Display
*dpy
= tPtr
->view
->screen
->display
;
656 Window win
= tPtr
->view
->window
;
659 if (!tPtr
->view
->flags
.realized
|| !tPtr
->db
|| tPtr
->flags
.frozen
)
663 XFillRectangle(dpy
, tPtr
->db
, tPtr
->bgGC
,
664 0, 0, tPtr
->visible
.w
, tPtr
->visible
.h
);
666 if (tPtr
->bgPixmap
) {
667 WMDrawPixmap(tPtr
->bgPixmap
, tPtr
->db
,
668 (tPtr
->visible
.w
-tPtr
->visible
.x
-tPtr
->bgPixmap
->width
)/2,
669 (tPtr
->visible
.h
-tPtr
->visible
.y
-tPtr
->bgPixmap
->height
)/2);
672 if (! (tb
= tPtr
->currentTextBlock
)) {
673 if (! (tb
= tPtr
->firstTextBlock
)) {
678 if (tPtr
->flags
.ownsSelection
) {
679 color
= WMGrayColor(scr
);
680 greyGC
= WMColorGC(color
);
681 WMReleaseColor(color
);
688 /* first, which direction? Don't waste time looking all over,
689 since the parts to be drawn will most likely be near what
690 was previously drawn */
691 if(!updateStartForCurrentTextBlock(tPtr
, 0, tPtr
->vpos
, &dir
, tb
))
696 if (tb
->graphic
&& tPtr
->flags
.monoFont
)
700 if(tPtr
->vpos
<= tb
->sections
[tb
->nsections
-1]._y
701 + tb
->sections
[tb
->nsections
-1].h
)
704 if(tPtr
->vpos
>= tb
->sections
[tb
->nsections
-1]._y
705 + tb
->sections
[tb
->nsections
-1].h
)
722 /* first, place all text that can be viewed */
723 while (!done
&& tb
) {
731 tb
->selected
= False
;
733 for(s
=0; s
<tb
->nsections
&& !done
; s
++) {
735 if (tb
->sections
[s
]._y
> tPtr
->vpos
+ tPtr
->visible
.h
) {
740 if ( tb
->sections
[s
].y
+ tb
->sections
[s
].h
< tPtr
->vpos
)
743 if (tPtr
->flags
.monoFont
) {
748 gc
= WMColorGC(tb
->color
);
751 if (tPtr
->flags
.ownsSelection
) {
754 if ( sectionWasSelected(tPtr
, tb
, &rect
, s
)) {
756 XFillRectangle(dpy
, tPtr
->db
, greyGC
,
757 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
761 prev_y
= tb
->sections
[s
]._y
;
763 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
764 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
765 y
= tb
->sections
[s
].y
- tPtr
->vpos
;
766 WMDrawString(scr
, tPtr
->db
, gc
, font
,
767 tb
->sections
[s
].x
- tPtr
->hpos
, y
, text
, len
);
769 if (!tPtr
->flags
.monoFont
&& tb
->underlined
) {
770 XDrawLine(dpy
, tPtr
->db
, gc
,
771 tb
->sections
[s
].x
- tPtr
->hpos
,
773 tb
->sections
[s
].x
+ tb
->sections
[s
].w
- tPtr
->hpos
,
779 tb
= (!done
? tb
->next
: NULL
);
783 /* now , show all graphic items that can be viewed */
784 c
= WMGetArrayItemCount(tPtr
->gfxItems
);
785 if (c
> 0 && !tPtr
->flags
.monoFont
) {
789 tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
);
791 /* if it's not viewable, and mapped, unmap it */
792 if (tb
->sections
[0]._y
+ tb
->sections
[0].h
<= tPtr
->vpos
793 || tb
->sections
[0]._y
>= tPtr
->vpos
+ tPtr
->visible
.h
) {
796 if ((W_VIEW(tb
->d
.widget
))->flags
.mapped
) {
797 WMUnmapWidget(tb
->d
.widget
);
801 /* if it's viewable, and not mapped, map it */
803 W_View
*view
= W_VIEW(tb
->d
.widget
);
805 if (!view
->flags
.realized
)
806 WMRealizeWidget(tb
->d
.widget
);
807 if(!view
->flags
.mapped
) {
808 XMapWindow(view
->screen
->display
, view
->window
);
809 XFlush(view
->screen
->display
);
810 view
->flags
.mapped
= 1;
815 WMMoveWidget(tb
->d
.widget
,
816 tb
->sections
[0].x
+ tPtr
->visible
.x
- tPtr
->hpos
,
817 tb
->sections
[0].y
+ tPtr
->visible
.y
- tPtr
->vpos
);
818 h
= WMWidgetHeight(tb
->d
.widget
) + 1;
821 WMDrawPixmap(tb
->d
.pixmap
, tPtr
->db
,
822 tb
->sections
[0].x
- tPtr
->hpos
,
823 tb
->sections
[0].y
- tPtr
->vpos
);
824 h
= tb
->d
.pixmap
->height
+ 1;
828 if (tPtr
->flags
.ownsSelection
) {
831 if ( sectionWasSelected(tPtr
, tb
, &rect
, 0)) {
832 Drawable d
= (0&&tb
->object
?
833 (WMWidgetView(tb
->d
.widget
))->window
: tPtr
->db
);
836 XFillRectangle(dpy
, d
, tPtr
->stippledGC
,
837 /*XFillRectangle(dpy, tPtr->db, tPtr->stippledGC,*/
838 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
842 if (!tPtr
->flags
.monoFont
&& tb
->underlined
) {
843 XDrawLine(dpy
, tPtr
->db
, WMColorGC(tb
->color
),
844 tb
->sections
[0].x
- tPtr
->hpos
,
845 tb
->sections
[0].y
+ h
- tPtr
->vpos
,
846 tb
->sections
[0].x
+ tb
->sections
[0].w
- tPtr
->hpos
,
847 tb
->sections
[0].y
+ h
- tPtr
->vpos
);
855 if (tPtr
->flags
.editable
&& tPtr
->flags
.cursorShown
856 && tPtr
->cursor
.x
!= -23 && tPtr
->flags
.focused
) {
857 int y
= tPtr
->cursor
.y
- tPtr
->vpos
;
858 XDrawLine(dpy
, tPtr
->db
, tPtr
->fgGC
,
860 tPtr
->cursor
.x
, y
+ tPtr
->cursor
.h
);
863 XCopyArea(dpy
, tPtr
->db
, win
, tPtr
->bgGC
, 0, 0,
864 tPtr
->visible
.w
, tPtr
->visible
.h
,
865 tPtr
->visible
.x
, tPtr
->visible
.y
);
867 W_DrawRelief(scr
, win
, 0, 0,
868 tPtr
->view
->size
.width
, tPtr
->view
->size
.height
,
871 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)
872 XDrawLine(dpy
, win
, tPtr
->fgGC
,
873 2, 42, tPtr
->view
->size
.width
-4, 42);
878 mouseOverObject(Text
*tPtr
, int x
, int y
)
883 x
-= tPtr
->visible
.x
;
885 y
-= tPtr
->visible
.y
;
888 if(tPtr
->flags
.ownsSelection
) {
891 && tPtr
->sel
.x
+ tPtr
->sel
.w
>= x
892 && tPtr
->sel
.y
+ tPtr
->sel
.h
>= y
) {
893 tPtr
->flags
.isOverGraphic
= 1;
900 int j
, c
= WMGetArrayItemCount(tPtr
->gfxItems
);
903 tPtr
->flags
.isOverGraphic
= 0;
907 tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
);
909 if(!tb
|| !tb
->sections
) {
910 tPtr
->flags
.isOverGraphic
= 0;
915 if(tb
->sections
[0].x
<= x
916 && tb
->sections
[0].y
<= y
917 && tb
->sections
[0].x
+ tb
->sections
[0].w
>= x
918 && tb
->sections
[0].y
+ tb
->d
.pixmap
->height
>= y
) {
919 tPtr
->flags
.isOverGraphic
= 3;
930 tPtr
->flags
.isOverGraphic
= 0;
933 tPtr
->view
->attribs
.cursor
= (result
?
934 tPtr
->view
->screen
->defaultCursor
935 : tPtr
->view
->screen
->textCursor
);
937 XSetWindowAttributes attribs
;
938 attribs
.cursor
= tPtr
->view
->attribs
.cursor
;
939 XChangeWindowAttributes(tPtr
->view
->screen
->display
,
940 tPtr
->view
->window
, CWCursor
,
948 blinkCursor(void *data
)
950 Text
*tPtr
= (Text
*)data
;
952 if (tPtr
->flags
.cursorShown
) {
953 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY
,
956 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
,
960 tPtr
->flags
.cursorShown
= !tPtr
->flags
.cursorShown
;
965 updateCursorPosition(Text
*tPtr
)
967 TextBlock
*tb
= NULL
;
970 if(tPtr
->flags
.needsLayOut
)
971 layOutDocument(tPtr
);
973 if (! (tb
= tPtr
->currentTextBlock
)) {
974 if (! (tb
= tPtr
->firstTextBlock
)) {
975 WMFont
*font
= tPtr
->dFont
;
977 tPtr
->cursor
.h
= font
->height
+ abs(font
->height
-font
->y
);
988 y
= tb
->sections
[0].y
;
989 h
= tb
->sections
[0].h
;
990 x
= tb
->sections
[0].x
;
992 } else if(tb
->graphic
) {
993 y
= tb
->sections
[0].y
;
994 h
= tb
->sections
[0].h
;
995 x
= tb
->sections
[0].x
;
997 x
+= tb
->sections
[0].w
;
1000 if(tPtr
->tpos
> tb
->used
)
1001 tPtr
->tpos
= tb
->used
;
1003 for(s
=0; s
<tb
->nsections
-1; s
++) {
1005 if(tPtr
->tpos
>= tb
->sections
[s
].begin
1006 && tPtr
->tpos
<= tb
->sections
[s
].end
)
1010 y
= tb
->sections
[s
]._y
;
1011 h
= tb
->sections
[s
].h
;
1012 x
= tb
->sections
[s
].x
+ WMWidthOfString(
1013 (tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
),
1014 &tb
->text
[tb
->sections
[s
].begin
],
1015 tPtr
->tpos
- tb
->sections
[s
].begin
);
1023 /* scroll the bars if the cursor is not visible */
1024 if(tPtr
->flags
.editable
&& tPtr
->cursor
.x
!= -23) {
1025 if(tPtr
->cursor
.y
+tPtr
->cursor
.h
1026 > tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
) {
1028 (tPtr
->cursor
.y
+tPtr
->cursor
.h
+10
1029 - (tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
));
1030 } else if(tPtr
->cursor
.y
< tPtr
->vpos
+tPtr
->visible
.y
) {
1031 tPtr
->vpos
-= (tPtr
->vpos
+tPtr
->visible
.y
-tPtr
->cursor
.y
);
1036 updateScrollers(tPtr
);
1041 cursorToTextPosition(Text
*tPtr
, int x
, int y
)
1043 TextBlock
*tb
= NULL
;
1044 int done
=False
, s
, pos
, len
, _w
, _y
, dir
=1; /* 1 == "down" */
1047 if(tPtr
->flags
.needsLayOut
)
1048 layOutDocument(tPtr
);
1050 y
+= (tPtr
->vpos
- tPtr
->visible
.y
);
1054 x
-= (tPtr
->visible
.x
- 2);
1058 /* clicked is relative to document, not window... */
1059 tPtr
->clicked
.x
= x
;
1060 tPtr
->clicked
.y
= y
;
1062 if (! (tb
= tPtr
->currentTextBlock
)) {
1063 if (! (tb
= tPtr
->firstTextBlock
)) {
1064 WMFont
*font
= tPtr
->dFont
;
1066 tPtr
->cursor
.h
= font
->height
+ abs(font
->height
-font
->y
);
1073 /* first, which direction? Most likely, newly clicked
1074 position will be close to previous */
1075 if(!updateStartForCurrentTextBlock(tPtr
, x
, y
, &dir
, tb
))
1079 s
= (dir
? 0 : tb
->nsections
-1);
1080 if ( y
>= tb
->sections
[s
]._y
1081 && y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) {
1085 /* get the first (or last) section of the TextBlock that
1086 lies about the vertical click point */
1088 while (!done
&& tb
) {
1090 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1091 if( (dir
?tb
->next
:tb
->prior
))
1092 tb
= (dir
?tb
->next
:tb
->prior
);
1096 s
= (dir
? 0 : tb
->nsections
-1);
1097 while (!done
&& (dir
? (s
<tb
->nsections
) : (s
>=0) )) {
1099 if ( (dir
? (y
<= tb
->sections
[s
]._y
+ tb
->sections
[s
].h
) :
1100 ( y
>= tb
->sections
[s
]._y
) ) ) {
1108 if ( (dir
? tb
->next
: tb
->prior
)) {
1109 tb
= (dir
? tb
->next
: tb
->prior
);
1112 break; /* goto _doneH; */
1118 if (s
<0 || s
>=tb
->nsections
) {
1119 s
= (dir
? tb
->nsections
-1 : 0);
1123 /* we have the line, which TextBlock on that line is it? */
1124 pos
= (dir
?0:tb
->sections
[s
].begin
);
1125 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1126 TextBlock
*hold
= tb
;
1127 tb
= getFirstNonGraphicBlockFor(hold
, dir
);
1141 _y
= tb
->sections
[s
]._y
;
1145 if (tPtr
->flags
.monoFont
&& tb
->graphic
) {
1146 tb
= (dir
? tb
->next
: tb
->prior
);
1153 _w
= WMWidgetWidth(tb
->d
.widget
)-5;
1155 _w
= tb
->d
.pixmap
->width
-5;
1157 if (tb
->sections
[0].x
+ _w
>= x
)
1160 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
1161 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
1162 _w
= WMWidthOfString(tb
->d
.font
, text
, len
);
1163 if (tb
->sections
[s
].x
+ _w
>= x
)
1168 if (tb
->sections
[s
].x
<= x
)
1172 if ((dir
? tb
->next
: tb
->prior
)) {
1173 TextBlock
*nxt
= (dir
? tb
->next
: tb
->prior
);
1174 if (tPtr
->flags
.monoFont
&& nxt
->graphic
) {
1175 nxt
= getFirstNonGraphicBlockFor(nxt
, dir
);
1177 pos
= (dir
?0:tb
->sections
[s
].begin
);
1178 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
1183 if (_y
!= nxt
->sections
[dir
?0:nxt
->nsections
-1]._y
) {
1184 /* this must be the last/first on this line. stop */
1185 pos
= (dir
? tb
->sections
[s
].end
: 0);
1186 tPtr
->cursor
.x
= tb
->sections
[s
].x
;
1190 tPtr
->cursor
.x
+= WMWidgetWidth(tb
->d
.widget
);
1192 tPtr
->cursor
.x
+= tb
->d
.pixmap
->width
;
1193 } else if (pos
> tb
->sections
[s
].begin
) {
1195 WMWidthOfString(tb
->d
.font
,
1196 &(tb
->text
[tb
->sections
[s
].begin
]),
1197 pos
- tb
->sections
[s
].begin
);
1204 if ( (dir
? tb
->next
: tb
->prior
)) {
1205 tb
= (dir
? tb
->next
: tb
->prior
);
1212 s
= (dir
? 0 : tb
->nsections
-1);
1215 /* we have said TextBlock, now where within it? */
1218 int gw
= (tb
->object
?
1219 WMWidgetWidth(tb
->d
.widget
) : tb
->d
.pixmap
->width
);
1221 tPtr
->cursor
.x
= tb
->sections
[0].x
;
1223 if(x
> tPtr
->cursor
.x
+ gw
/2) {
1225 tPtr
->cursor
.x
+= gw
;
1227 printf("first %d\n", tb
->first
);
1229 if(tb
->prior
->graphic
) pos
= 1;
1230 else pos
= tb
->prior
->used
;
1240 WMFont
*f
= tb
->d
.font
;
1241 len
= tb
->sections
[s
].end
- tb
->sections
[s
].begin
;
1242 text
= &(tb
->text
[tb
->sections
[s
].begin
]);
1244 _w
= x
- tb
->sections
[s
].x
;
1247 while (pos
<len
&& WMWidthOfString(f
, text
, pos
+1) < _w
)
1250 tPtr
->cursor
.x
= tb
->sections
[s
].x
+
1251 (pos
? WMWidthOfString(f
, text
, pos
) : 0);
1253 pos
+= tb
->sections
[s
].begin
;
1259 tPtr
->tpos
= (pos
<=1)? pos
: 0;
1261 tPtr
->tpos
= (pos
<tb
->used
)? pos
: tb
->used
;
1265 printf("...for this app will surely crash :-)\n");
1267 tPtr
->currentTextBlock
= tb
;
1268 tPtr
->cursor
.h
= tb
->sections
[s
].h
;
1269 tPtr
->cursor
.y
= tb
->sections
[s
]._y
;
1271 /* scroll the bars if the cursor is not visible */
1272 if(tPtr
->flags
.editable
&& tPtr
->cursor
.x
!= -23) {
1273 if(tPtr
->cursor
.y
+tPtr
->cursor
.h
1274 > tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
) {
1276 (tPtr
->cursor
.y
+tPtr
->cursor
.h
+10
1277 - (tPtr
->vpos
+tPtr
->visible
.y
+tPtr
->visible
.h
));
1278 updateScrollers(tPtr
);
1279 } else if(tPtr
->cursor
.y
< tPtr
->vpos
+tPtr
->visible
.y
) {
1280 tPtr
->vpos
-= (tPtr
->vpos
+tPtr
->visible
.y
-tPtr
->cursor
.y
);
1281 updateScrollers(tPtr
);
1290 updateScrollers(Text
*tPtr
)
1293 if (tPtr
->flags
.frozen
)
1297 if (tPtr
->docHeight
<= tPtr
->visible
.h
) {
1298 WMSetScrollerParameters(tPtr
->vS
, 0, 1);
1301 float hmax
= (float)(tPtr
->docHeight
);
1302 WMSetScrollerParameters(tPtr
->vS
,
1303 ((float)tPtr
->vpos
)/(hmax
- (float)tPtr
->visible
.h
),
1304 (float)tPtr
->visible
.h
/hmax
);
1306 } else tPtr
->vpos
= 0;
1309 if (tPtr
->docWidth
<= tPtr
->visible
.w
) {
1310 WMSetScrollerParameters(tPtr
->hS
, 0, 1);
1313 float wmax
= (float)(tPtr
->docWidth
);
1314 WMSetScrollerParameters(tPtr
->hS
,
1315 ((float)tPtr
->hpos
)/(wmax
- (float)tPtr
->visible
.w
),
1316 (float)tPtr
->visible
.w
/wmax
);
1318 } else tPtr
->hpos
= 0;
1322 scrollersCallBack(WMWidget
*w
, void *self
)
1324 Text
*tPtr
= (Text
*)self
;
1325 Bool scroll
= False
;
1328 if (!tPtr
->view
->flags
.realized
|| tPtr
->flags
.frozen
)
1331 if (w
== tPtr
->vS
) {
1333 height
= tPtr
->visible
.h
;
1335 which
= WMGetScrollerHitPart(tPtr
->vS
);
1338 case WSDecrementLine
:
1339 if (tPtr
->vpos
> 0) {
1340 if (tPtr
->vpos
>16) tPtr
->vpos
-=16;
1346 case WSIncrementLine
: {
1347 int limit
= tPtr
->docHeight
- height
;
1348 if (tPtr
->vpos
< limit
) {
1349 if (tPtr
->vpos
<limit
-16) tPtr
->vpos
+=16;
1350 else tPtr
->vpos
=limit
;
1356 case WSDecrementPage
:
1357 if(((int)tPtr
->vpos
- (int)height
) >= 0)
1358 tPtr
->vpos
-= height
;
1365 case WSIncrementPage
:
1366 tPtr
->vpos
+= height
;
1367 if (tPtr
->vpos
> (tPtr
->docHeight
- height
))
1368 tPtr
->vpos
= tPtr
->docHeight
- height
;
1374 tPtr
->vpos
= WMGetScrollerValue(tPtr
->vS
)
1375 * (float)(tPtr
->docHeight
- height
);
1383 scroll
= (tPtr
->vpos
!= tPtr
->prevVpos
);
1384 tPtr
->prevVpos
= tPtr
->vpos
;
1388 if (w
== tPtr
->hS
) {
1389 int width
= tPtr
->visible
.w
;
1391 which
= WMGetScrollerHitPart(tPtr
->hS
);
1394 case WSDecrementLine
:
1395 if (tPtr
->hpos
> 0) {
1396 if (tPtr
->hpos
>16) tPtr
->hpos
-=16;
1401 case WSIncrementLine
: {
1402 int limit
= tPtr
->docWidth
- width
;
1403 if (tPtr
->hpos
< limit
) {
1404 if (tPtr
->hpos
<limit
-16) tPtr
->hpos
+=16;
1405 else tPtr
->hpos
=limit
;
1410 case WSDecrementPage
:
1411 if(((int)tPtr
->hpos
- (int)width
) >= 0)
1412 tPtr
->hpos
-= width
;
1419 case WSIncrementPage
:
1420 tPtr
->hpos
+= width
;
1421 if (tPtr
->hpos
> (tPtr
->docWidth
- width
))
1422 tPtr
->hpos
= tPtr
->docWidth
- width
;
1428 tPtr
->hpos
= WMGetScrollerValue(tPtr
->hS
)
1429 * (float)(tPtr
->docWidth
- width
);
1437 scroll
= (tPtr
->hpos
!= tPtr
->prevHpos
);
1438 tPtr
->prevHpos
= tPtr
->hpos
;
1442 updateScrollers(tPtr
);
1451 unsigned short begin
, end
; /* what part of the text block */
1456 layOutLine(Text
*tPtr
, myLineItems
*items
, int nitems
, int x
, int y
)
1458 int i
, j
=0, lw
= 0, line_height
=0, max_d
=0, len
, n
;
1461 TextBlock
*tb
, *tbsame
=NULL
;
1463 if(!items
|| nitems
== 0)
1466 for(i
=0; i
<nitems
; i
++) {
1470 if (!tPtr
->flags
.monoFont
) {
1472 WMWidget
*wdt
= tb
->d
.widget
;
1473 line_height
= WMAX(line_height
, WMWidgetHeight(wdt
));
1474 if (tPtr
->flags
.alignment
!= WALeft
)
1475 lw
+= WMWidgetWidth(wdt
);
1477 line_height
= WMAX(line_height
,
1478 tb
->d
.pixmap
->height
+ max_d
);
1479 if (tPtr
->flags
.alignment
!= WALeft
)
1480 lw
+= tb
->d
.pixmap
->width
;
1485 font
= (tPtr
->flags
.monoFont
)?tPtr
->dFont
: tb
->d
.font
;
1486 max_d
= WMAX(max_d
, abs(font
->height
-font
->y
));
1487 line_height
= WMAX(line_height
, font
->height
+ max_d
);
1488 text
= &(tb
->text
[items
[i
].begin
]);
1489 len
= items
[i
].end
- items
[i
].begin
;
1490 if (tPtr
->flags
.alignment
!= WALeft
)
1491 lw
+= WMWidthOfString(font
, text
, len
);
1495 if (tPtr
->flags
.alignment
== WARight
) {
1496 j
= tPtr
->visible
.w
- lw
;
1497 } else if (tPtr
->flags
.alignment
== WACenter
) {
1498 j
= (int) ((float)(tPtr
->visible
.w
- lw
))/2.0;
1501 for(i
=0; i
<nitems
; i
++) {
1504 if (tbsame
== tb
) { /* extend it, since it's on same line */
1505 tb
->sections
[tb
->nsections
-1].end
= items
[i
].end
;
1506 n
= tb
->nsections
-1;
1508 tb
->sections
= wrealloc(tb
->sections
,
1509 (++tb
->nsections
)*sizeof(Section
));
1510 n
= tb
->nsections
-1;
1511 tb
->sections
[n
]._y
= y
+ max_d
;
1512 tb
->sections
[n
].max_d
= max_d
;
1513 tb
->sections
[n
].x
= x
+j
;
1514 tb
->sections
[n
].h
= line_height
;
1515 tb
->sections
[n
].begin
= items
[i
].begin
;
1516 tb
->sections
[n
].end
= items
[i
].end
;
1519 tb
->sections
[n
].last
= (i
+1 == nitems
);
1522 if (!tPtr
->flags
.monoFont
) {
1524 WMWidget
*wdt
= tb
->d
.widget
;
1525 tb
->sections
[n
].y
= max_d
+ y
1526 + line_height
- WMWidgetHeight(wdt
);
1527 tb
->sections
[n
].w
= WMWidgetWidth(wdt
);
1529 tb
->sections
[n
].y
= y
+ line_height
1530 + max_d
- tb
->d
.pixmap
->height
;
1531 tb
->sections
[n
].w
= tb
->d
.pixmap
->width
;
1533 x
+= tb
->sections
[n
].w
;
1536 font
= (tPtr
->flags
.monoFont
)? tPtr
->dFont
: tb
->d
.font
;
1537 len
= items
[i
].end
- items
[i
].begin
;
1538 text
= &(tb
->text
[items
[i
].begin
]);
1540 tb
->sections
[n
].y
= y
+line_height
-font
->y
;
1542 WMWidthOfString(font
,
1543 &(tb
->text
[tb
->sections
[n
].begin
]),
1544 tb
->sections
[n
].end
- tb
->sections
[n
].begin
);
1546 x
+= WMWidthOfString(font
, text
, len
);
1558 layOutDocument(Text
*tPtr
)
1561 myLineItems
*items
= NULL
;
1562 unsigned int itemsSize
=0, nitems
=0, begin
, end
;
1564 unsigned int x
, y
=0, lw
= 0, width
=0, bmargin
;
1565 char *start
=NULL
, *mark
=NULL
;
1567 if ( tPtr
->flags
.frozen
|| (!(tb
= tPtr
->firstTextBlock
)) )
1570 assert(tPtr
->visible
.w
> 20);
1572 tPtr
->docWidth
= tPtr
->visible
.w
;
1573 x
= tPtr
->margins
[tb
->marginN
].first
;
1574 bmargin
= tPtr
->margins
[tb
->marginN
].body
;
1576 /* only partial layOut needed: re-Lay only affected textblocks */
1577 if (tPtr
->flags
.laidOut
) {
1578 tb
= tPtr
->currentTextBlock
;
1580 /* search backwards for textblocks on same line */
1582 if (!tb
->sections
|| tb
->nsections
<1) {
1583 tb
= tPtr
->firstTextBlock
;
1584 tPtr
->flags
.laidOut
= False
;
1589 if(!tb
->prior
->sections
|| tb
->prior
->nsections
<1) {
1590 tb
= tPtr
->firstTextBlock
;
1591 tPtr
->flags
.laidOut
= False
;
1596 if (tb
->sections
[0]._y
!=
1597 tb
->prior
->sections
[tb
->prior
->nsections
-1]._y
) {
1603 if(tb
->prior
&& tb
->prior
->sections
&& tb
->prior
->nsections
>0) {
1604 y
= tb
->prior
->sections
[tb
->prior
->nsections
-1]._y
+
1605 tb
->prior
->sections
[tb
->prior
->nsections
-1].h
-
1606 tb
->prior
->sections
[tb
->prior
->nsections
-1].max_d
;
1615 if (tb
->sections
&& tb
->nsections
>0) {
1616 wfree(tb
->sections
);
1617 tb
->sections
= NULL
;
1621 if (tb
->first
&& tb
->blank
&& tb
->next
&& !tb
->next
->first
) {
1622 TextBlock
*next
= tb
->next
;
1623 tPtr
->currentTextBlock
= tb
;
1624 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1630 if (tb
->first
&& tb
!= tPtr
->firstTextBlock
) {
1631 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1632 x
= tPtr
->margins
[tb
->marginN
].first
;
1633 bmargin
= tPtr
->margins
[tb
->marginN
].body
;
1639 if (!tPtr
->flags
.monoFont
) {
1641 width
= WMWidgetWidth(tb
->d
.widget
);
1643 width
= tb
->d
.pixmap
->width
;
1645 if (width
> tPtr
->docWidth
)
1646 tPtr
->docWidth
= width
;
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
= 0;
1663 items
[nitems
].end
= 0;
1667 } else if ((start
= tb
->text
)) {
1669 font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
1672 mark
= strchr(start
, ' ');
1674 end
+= (int)(mark
-start
)+1;
1677 end
+= strlen(start
);
1684 if (end
-begin
> 0) {
1686 width
= WMWidthOfString(font
,
1687 &tb
->text
[begin
], end
-begin
);
1689 /* if it won't fit, char wrap it */
1690 if (width
>= tPtr
->visible
.w
) {
1691 char *t
= &tb
->text
[begin
];
1692 int l
=end
-begin
, i
=0;
1694 width
= WMWidthOfString(font
, t
, ++i
);
1695 } while (width
< tPtr
->visible
.w
&& i
< l
);
1698 start
= &tb
->text
[end
];
1704 if (lw
>= tPtr
->visible
.w
- x
) {
1705 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1711 if(nitems
+ 1 > itemsSize
) {
1712 items
= wrealloc(items
,
1713 (++itemsSize
)*sizeof(myLineItems
));
1716 items
[nitems
].tb
= tb
;
1717 items
[nitems
].begin
= begin
;
1718 items
[nitems
].end
= end
;
1726 /* not yet fully ready. but is already VERY FAST for a 3Mbyte file ;-) */
1727 if(0&&tPtr
->flags
.laidOut
1728 && tb
->next
&& tb
->next
->sections
&& tb
->next
->nsections
>0
1729 && (tPtr
->vpos
+ tPtr
->visible
.h
1730 < tb
->next
->sections
[0]._y
)) {
1731 if(tPtr
->lastTextBlock
->sections
1732 && tPtr
->lastTextBlock
->nsections
> 0 ) {
1733 TextBlock
*ltb
= tPtr
->lastTextBlock
;
1734 int ly
= ltb
->sections
[ltb
->nsections
-1]._y
;
1735 int lh
= ltb
->sections
[ltb
->nsections
-1].h
;
1738 lh
+= 1 + tPtr
->visible
.y
+ ltb
->sections
[ltb
->nsections
-1].max_d
;
1739 printf("it's %d\n", tPtr
->visible
.y
+ ltb
->sections
[ltb
->nsections
-1].max_d
);
1741 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1743 sd
= tPtr
->docHeight
-y
;
1745 printf("dif %d-%d: %d\n", ss
, sd
, ss
-sd
);
1746 y
+= tb
->next
->sections
[0]._y
-y
;
1748 printf("nitems%d\n", nitems
);
1750 y
= tPtr
->docHeight
+ss
-sd
;
1754 tPtr
->flags
.laidOut
= False
;
1763 y
+= layOutLine(tPtr
, items
, nitems
, x
, y
);
1765 if (tPtr
->docHeight
!= y
+10) {
1766 tPtr
->docHeight
= y
+10;
1767 updateScrollers(tPtr
);
1770 if(tPtr
->docWidth
> tPtr
->visible
.w
&& !tPtr
->hS
) {
1773 tPtr
->flags
.horizOnDemand
= True
;
1774 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, True
);
1775 event
.type
= Expose
;
1776 handleEvents(&event
, (void *)tPtr
);
1778 } else if(tPtr
->docWidth
<= tPtr
->visible
.w
1779 && tPtr
->hS
&& tPtr
->flags
.horizOnDemand
) {
1780 tPtr
->flags
.horizOnDemand
= False
;
1781 WMSetTextHasHorizontalScroller((WMText
*)tPtr
, False
);
1784 tPtr
->flags
.laidOut
= True
;
1786 if(items
&& itemsSize
> 0)
1793 textDidResize(W_ViewDelegate
*self
, WMView
*view
)
1795 Text
*tPtr
= (Text
*)view
->self
;
1796 unsigned short w
= tPtr
->view
->size
.width
;
1797 unsigned short h
= tPtr
->view
->size
.height
;
1798 unsigned short rh
= 0, vw
= 0, rel
;
1800 rel
= (tPtr
->flags
.relief
== WRFlat
);
1802 if (tPtr
->ruler
&& tPtr
->flags
.rulerShown
) {
1803 WMMoveWidget(tPtr
->ruler
, 2, 2);
1804 WMResizeWidget(tPtr
->ruler
, w
- 4, 40);
1809 WMMoveWidget(tPtr
->vS
, 1 - (rel
?1:0), rh
+ 1 - (rel
?1:0));
1810 WMResizeWidget(tPtr
->vS
, 20, h
- rh
- 2 + (rel
?2:0));
1812 WMSetRulerOffset(tPtr
->ruler
,22);
1813 } else WMSetRulerOffset(tPtr
->ruler
, 2);
1817 WMMoveWidget(tPtr
->hS
, vw
, h
- 21);
1818 WMResizeWidget(tPtr
->hS
, w
- vw
- 1, 20);
1820 WMMoveWidget(tPtr
->hS
, vw
+1, h
- 21);
1821 WMResizeWidget(tPtr
->hS
, w
- vw
- 2, 20);
1825 tPtr
->visible
.x
= (tPtr
->vS
)?24:4;
1826 tPtr
->visible
.y
= (tPtr
->ruler
&& tPtr
->flags
.rulerShown
)?43:3;
1827 tPtr
->visible
.w
= tPtr
->view
->size
.width
- tPtr
->visible
.x
- 8;
1828 tPtr
->visible
.h
= tPtr
->view
->size
.height
- tPtr
->visible
.y
;
1829 tPtr
->visible
.h
-= (tPtr
->hS
)?20:0;
1830 tPtr
->margins
[0].right
= tPtr
->visible
.w
;
1832 if (tPtr
->view
->flags
.realized
) {
1835 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
1836 tPtr
->db
= (Pixmap
) NULL
;
1839 if (tPtr
->visible
.w
< 40)
1840 tPtr
->visible
.w
= 40;
1841 if (tPtr
->visible
.h
< 20)
1842 tPtr
->visible
.h
= 20;
1845 tPtr
->db
= XCreatePixmap(tPtr
->view
->screen
->display
,
1846 tPtr
->view
->window
, tPtr
->visible
.w
,
1847 tPtr
->visible
.h
, tPtr
->view
->screen
->depth
);
1854 W_ViewDelegate _TextViewDelegate
=
1862 #define TEXT_BUFFER_INCR 8
1863 #define reqBlockSize(requested) (requested + TEXT_BUFFER_INCR)
1866 clearText(Text
*tPtr
)
1868 tPtr
->vpos
= tPtr
->hpos
= 0;
1869 tPtr
->docHeight
= tPtr
->docWidth
= 0;
1870 tPtr
->cursor
.x
= -23;
1872 if (!tPtr
->firstTextBlock
)
1875 while (tPtr
->currentTextBlock
)
1876 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1878 tPtr
->firstTextBlock
= NULL
;
1879 tPtr
->currentTextBlock
= NULL
;
1880 tPtr
->lastTextBlock
= NULL
;
1881 WMEmptyArray(tPtr
->gfxItems
);
1884 /* possibly remove a single character from the currentTextBlock,
1885 or if there's a selection, remove it...
1886 note that Delete and Backspace are treated differently */
1888 deleteTextInteractively(Text
*tPtr
, KeySym ksym
)
1891 Bool back
= (Bool
) (ksym
== XK_BackSpace
);
1892 Bool done
= 1, wasFirst
= 0;
1894 if (!tPtr
->flags
.editable
)
1897 if ( !(tb
= tPtr
->currentTextBlock
) )
1900 if (tPtr
->flags
.ownsSelection
) {
1901 if(removeSelection(tPtr
))
1902 layOutDocument(tPtr
);
1906 wasFirst
= tb
->first
;
1907 if (back
&& tPtr
->tpos
< 1) {
1909 if(tb
->prior
->blank
) {
1910 tPtr
->currentTextBlock
= tb
->prior
;
1911 WMRemoveTextBlock(tPtr
);
1912 tPtr
->currentTextBlock
= tb
;
1914 layOutDocument(tPtr
);
1918 TextBlock
*prior
= tb
->prior
;
1919 tPtr
->currentTextBlock
= tb
;
1920 WMRemoveTextBlock(tPtr
);
1929 tPtr
->tpos
= tb
->used
;
1931 tPtr
->currentTextBlock
= tb
;
1935 tb
->next
->first
= False
;
1936 layOutDocument(tPtr
);
1943 if ( (tb
->used
> 0) && ((back
?tPtr
->tpos
> 0:1))
1944 && (tPtr
->tpos
<= tb
->used
) && !tb
->graphic
) {
1947 memmove(&(tb
->text
[tPtr
->tpos
]),
1948 &(tb
->text
[tPtr
->tpos
+ 1]), tb
->used
- tPtr
->tpos
);
1953 /* if there are no characters left to back over in the textblock,
1954 but it still has characters to the right of the cursor: */
1955 if ( (back
? (tPtr
->tpos
== 0 && !done
) : ( tPtr
->tpos
>= tb
->used
))
1958 /* no more chars, and it's marked as blank? */
1960 TextBlock
*sibling
= (back
? tb
->prior
: tb
->next
);
1962 if(tb
->used
== 0 || tb
->graphic
)
1963 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1966 tPtr
->currentTextBlock
= sibling
;
1968 tPtr
->tpos
= (back
? 1 : 0);
1970 tPtr
->tpos
= (back
? sibling
->used
: 0);
1972 /* no more chars, so mark it as blank */
1973 } else if(tb
->used
== 0) {
1975 } else if(tb
->graphic
) {
1976 Bool hasNext
= (Bool
)(tb
->next
);
1978 WMDestroyTextBlock(tPtr
, WMRemoveTextBlock(tPtr
));
1981 } else if(tPtr
->currentTextBlock
) {
1982 tPtr
->tpos
= (tPtr
->currentTextBlock
->graphic
?
1983 1 : tPtr
->currentTextBlock
->used
);
1985 } else printf("DEBUG: unaccounted for... catch this!\n");
1988 layOutDocument(tPtr
);
1993 insertTextInteractively(Text
*tPtr
, char *text
, int len
)
1996 char *newline
= NULL
;
1998 if (!tPtr
->flags
.editable
) {
2002 if (len
< 1 || !text
)
2006 if(tPtr
->flags
.ignoreNewLine
&& *text
== '\n' && len
== 1)
2010 if (tPtr
->flags
.ownsSelection
)
2011 removeSelection(tPtr
);
2014 if (tPtr
->flags
.ignoreNewLine
) {
2016 for(i
=0; i
<len
; i
++) {
2017 if (text
[i
] == '\n')
2022 tb
= tPtr
->currentTextBlock
;
2023 if (!tb
|| tb
->graphic
) {
2025 WMAppendTextStream(tPtr
, text
);
2026 layOutDocument(tPtr
);
2030 if ((newline
= strchr(text
, '\n'))) {
2031 int nlen
= (int)(newline
-text
);
2032 int s
= tb
->used
- tPtr
->tpos
;
2034 if (!tb
->blank
&& nlen
>0) {
2039 memcpy(save
, &tb
->text
[tPtr
->tpos
], s
);
2040 tb
->used
-= (tb
->used
- tPtr
->tpos
);
2042 insertTextInteractively(tPtr
, text
, nlen
);
2044 WMAppendTextStream(tPtr
, newline
);
2046 insertTextInteractively(tPtr
, save
, s
);
2050 if (tPtr
->tpos
>0 && tPtr
->tpos
< tb
->used
2051 && !tb
->graphic
&& tb
->text
) {
2053 unsigned short savePos
= tPtr
->tpos
;
2054 void *ntb
= WMCreateTextBlockWithText(
2055 tPtr
, &tb
->text
[tPtr
->tpos
],
2056 tb
->d
.font
, tb
->color
, True
, tb
->used
- tPtr
->tpos
);
2058 if(tb
->sections
[0].end
== tPtr
->tpos
)
2059 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
2060 NULL
, tb
->d
.font
, tb
->color
, True
, 0));
2063 WMAppendTextBlock(tPtr
, ntb
);
2066 } else if (tPtr
->tpos
== tb
->used
) {
2067 if(tPtr
->flags
.indentNewLine
) {
2068 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
2069 " ", tb
->d
.font
, tb
->color
, True
, 4));
2072 WMAppendTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
2073 NULL
, tb
->d
.font
, tb
->color
, True
, 0));
2076 } else if (tPtr
->tpos
== 0) {
2077 if(tPtr
->flags
.indentNewLine
) {
2078 WMPrependTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
2079 " ", tb
->d
.font
, tb
->color
, True
, 4));
2081 WMPrependTextBlock(tPtr
, WMCreateTextBlockWithText(tPtr
,
2082 NULL
, tb
->d
.font
, tb
->color
, True
, 0));
2085 if(tPtr
->currentTextBlock
->next
)
2086 tPtr
->currentTextBlock
= tPtr
->currentTextBlock
->next
;
2090 if (tb
->used
+ len
>= tb
->allocated
) {
2091 tb
->allocated
= reqBlockSize(tb
->used
+len
);
2092 tb
->text
= wrealloc(tb
->text
, tb
->allocated
);
2096 memcpy(tb
->text
, text
, len
);
2099 tb
->text
[tb
->used
] = 0;
2103 memmove(&(tb
->text
[tPtr
->tpos
+len
]), &tb
->text
[tPtr
->tpos
],
2104 tb
->used
-tPtr
->tpos
+1);
2105 memmove(&tb
->text
[tPtr
->tpos
], text
, len
);
2108 tb
->text
[tb
->used
] = 0;
2113 layOutDocument(tPtr
);
2118 selectRegion(Text
*tPtr
, int x
, int y
)
2124 y
+= (tPtr
->flags
.rulerShown
? 40: 0);
2127 y
-= 10; /* the original offset */
2129 x
-= tPtr
->visible
.x
-2;
2133 tPtr
->sel
.x
= WMAX(0, WMIN(tPtr
->clicked
.x
, x
));
2134 tPtr
->sel
.w
= abs(tPtr
->clicked
.x
- x
);
2135 tPtr
->sel
.y
= WMAX(0, WMIN(tPtr
->clicked
.y
, y
));
2136 tPtr
->sel
.h
= abs(tPtr
->clicked
.y
- y
);
2138 tPtr
->flags
.ownsSelection
= True
;
2144 releaseSelection(Text
*tPtr
)
2146 TextBlock
*tb
= tPtr
->firstTextBlock
;
2149 tb
->selected
= False
;
2152 tPtr
->flags
.ownsSelection
= False
;
2153 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
,
2161 requestHandler(WMView
*view
, Atom selection
, Atom target
, void *cdata
,
2164 Text
*tPtr
= view
->self
;
2165 Display
*dpy
= tPtr
->view
->screen
->display
;
2167 Atom TEXT
= XInternAtom(dpy
, "TEXT", False
);
2168 Atom COMPOUND_TEXT
= XInternAtom(dpy
, "COMPOUND_TEXT", False
);
2169 WMData
*data
= NULL
;
2172 if (target
== XA_STRING
|| target
== TEXT
|| target
== COMPOUND_TEXT
) {
2173 char *text
= WMGetTextSelectedStream(tPtr
);
2176 data
= WMCreateDataWithBytes(text
, strlen(text
));
2177 WMSetDataFormat(data
, TYPETEXT
);
2181 } else printf("didn't get it\n");
2183 _TARGETS
= XInternAtom(dpy
, "TARGETS", False
);
2184 if (target
== _TARGETS
) {
2187 ptr
= wmalloc(4 * sizeof(Atom
));
2191 ptr
[3] = COMPOUND_TEXT
;
2193 data
= WMCreateDataWithBytes(ptr
, 4*4);
2194 WMSetDataFormat(data
, 32);
2205 lostHandler(WMView
*view
, Atom selection
, void *cdata
)
2207 releaseSelection((WMText
*)view
->self
);
2211 static WMSelectionProcs selectionHandler
= {
2212 requestHandler
, lostHandler
, NULL
2217 ownershipObserver(void *observerData
, WMNotification
*notification
)
2219 if (observerData
!= WMGetNotificationClientData(notification
))
2220 lostHandler(WMWidgetView(observerData
), XA_PRIMARY
, NULL
);
2225 autoSelectText(Text
*tPtr
, int clicks
)
2229 char *mark
= NULL
, behind
, ahead
;
2231 if(!(tb
= tPtr
->currentTextBlock
))
2237 switch(tb
->text
[tPtr
->tpos
]) {
2240 case '<': case '>': behind = '<'; ahead = '>'; break;
2241 case '{': case '}': behind = '{'; ahead = '}'; break;
2242 case '[': case ']': behind = '['; ahead = ']'; break;
2244 default: behind
= ahead
= ' ';
2247 tPtr
->sel
.y
= tPtr
->cursor
.y
+5;
2248 tPtr
->sel
.h
= 6;/*tPtr->cursor.h-10;*/
2251 tPtr
->sel
.x
= tb
->sections
[0].x
;
2252 tPtr
->sel
.w
= tb
->sections
[0].w
;
2254 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
2257 while(start
> 0 && tb
->text
[start
-1] != behind
)
2261 if(tPtr
->tpos
> start
){
2262 x
-= WMWidthOfString(font
, &tb
->text
[start
],
2263 tPtr
->tpos
- start
);
2265 tPtr
->sel
.x
= (x
<0?0:x
)+1;
2267 if((mark
= strchr(&tb
->text
[start
], ahead
))) {
2268 tPtr
->sel
.w
= WMWidthOfString(font
, &tb
->text
[start
],
2269 (int)(mark
- &tb
->text
[start
]));
2270 } else if(tb
->used
> start
) {
2271 tPtr
->sel
.w
= WMWidthOfString(font
, &tb
->text
[start
],
2276 } else if(clicks
== 3) {
2277 TextBlock
*cur
= tb
;
2279 while(tb
&& !tb
->first
) {
2282 tPtr
->sel
.y
= tb
->sections
[0]._y
;
2285 while(tb
->next
&& !tb
->next
->first
) {
2288 tPtr
->sel
.h
= tb
->sections
[tb
->nsections
-1]._y
2292 tPtr
->sel
.w
= tPtr
->docWidth
;
2293 tPtr
->clicked
.x
= 0; /* only for now, fix sel. code */
2296 if (!tPtr
->flags
.ownsSelection
) {
2297 WMCreateSelectionHandler(tPtr
->view
,
2298 XA_PRIMARY
, tPtr
->lastClickTime
, &selectionHandler
, NULL
);
2299 tPtr
->flags
.ownsSelection
= True
;
2307 fontChanged(void *observerData
, WMNotification
*notification
)
2309 WMText
*tPtr
= (WMText
*) observerData
;
2310 WMFont
*font
= (WMFont
*)WMGetNotificationClientData(notification
);
2311 printf("fontChanged\n");
2316 if (tPtr
->flags
.ownsSelection
)
2317 WMSetTextSelectionFont(tPtr
, font
);
2322 handleTextKeyPress(Text
*tPtr
, XEvent
*event
)
2326 int control_pressed
= False
;
2327 TextBlock
*tb
= NULL
;
2329 if (((XKeyEvent
*) event
)->state
& ControlMask
)
2330 control_pressed
= True
;
2331 buffer
[XLookupString(&event
->xkey
, buffer
, 63, &ksym
, NULL
)] = 0;
2336 if((tPtr
->currentTextBlock
= tPtr
->firstTextBlock
))
2338 updateCursorPosition(tPtr
);
2343 if((tPtr
->currentTextBlock
= tPtr
->lastTextBlock
)) {
2344 if(tPtr
->currentTextBlock
->graphic
)
2347 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
2349 updateCursorPosition(tPtr
);
2354 if(!(tb
= tPtr
->currentTextBlock
))
2360 L_imaGFX
: if(tb
->prior
) {
2361 tPtr
->currentTextBlock
= tb
->prior
;
2362 if(tPtr
->currentTextBlock
->graphic
)
2365 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
2367 if(!tb
->first
&& tPtr
->tpos
> 0)
2369 } else tPtr
->tpos
= 0;
2370 } else tPtr
->tpos
--;
2371 updateCursorPosition(tPtr
);
2376 if(!(tb
= tPtr
->currentTextBlock
))
2380 if(tPtr
->tpos
== tb
->used
) {
2381 R_imaGFX
: if(tb
->next
) {
2382 tPtr
->currentTextBlock
= tb
->next
;
2384 if(!tb
->next
->first
&& tb
->next
->used
>0)
2390 tPtr
->tpos
= tb
->used
;
2392 } else tPtr
->tpos
++;
2393 updateCursorPosition(tPtr
);
2398 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
2399 tPtr
->clicked
.y
+ tPtr
->cursor
.h
- tPtr
->vpos
);
2404 cursorToTextPosition(tPtr
, tPtr
->cursor
.x
+ tPtr
->visible
.x
,
2405 tPtr
->visible
.y
+ tPtr
->cursor
.y
- tPtr
->vpos
- 3);
2414 deleteTextInteractively(tPtr
, ksym
);
2415 updateCursorPosition(tPtr
);
2421 control_pressed
= True
;
2425 insertTextInteractively(tPtr
, " ", 4);
2426 updateCursorPosition(tPtr
);
2433 if (*buffer
!= 0 && !control_pressed
) {
2434 insertTextInteractively(tPtr
, buffer
, strlen(buffer
));
2435 updateCursorPosition(tPtr
);
2438 } else if (control_pressed
&& ksym
==XK_r
) {
2439 Bool i
= !tPtr
->flags
.rulerShown
;
2440 WMShowTextRuler(tPtr
, i
);
2441 tPtr
->flags
.rulerShown
= i
;
2443 else if (control_pressed
&& *buffer
== '\a')
2444 XBell(tPtr
->view
->screen
->display
, 0);
2446 WMRelayToNextResponder(tPtr
->view
, event
);
2449 if (!control_pressed
&& tPtr
->flags
.ownsSelection
)
2450 releaseSelection(tPtr
);
2455 pasteText(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
2456 void *cdata
, WMData
*data
)
2458 Text
*tPtr
= (Text
*)view
->self
;
2461 tPtr
->flags
.waitingForSelection
= 0;
2464 text
= (char*)WMDataBytes(data
);
2467 (tPtr
->parser
) (tPtr
, (void *) text
);
2468 layOutDocument(tPtr
);
2469 } else insertTextInteractively(tPtr
, text
, strlen(text
));
2470 updateCursorPosition(tPtr
);
2476 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
2481 (tPtr
->parser
) (tPtr
, (void *) text
);
2482 layOutDocument(tPtr
);
2483 } else insertTextInteractively(tPtr
, text
, n
);
2484 updateCursorPosition(tPtr
);
2496 handleActionEvents(XEvent
*event
, void *data
)
2498 Text
*tPtr
= (Text
*)data
;
2499 Display
*dpy
= event
->xany
.display
;
2503 switch (event
->type
) {
2505 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2506 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2507 tPtr
->flags
.extendSelection
= True
;
2511 if (tPtr
->flags
.focused
) {
2512 XGrabPointer(dpy
, W_VIEW(tPtr
)->window
, False
,
2513 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
2514 GrabModeAsync
, GrabModeAsync
, None
,
2515 tPtr
->view
->screen
->invisibleCursor
, CurrentTime
);
2516 tPtr
->flags
.pointerGrabbed
= True
;
2517 handleTextKeyPress(tPtr
, event
);
2522 ksym
= XLookupKeysym((XKeyEvent
*)event
, 0);
2523 if (ksym
== XK_Shift_R
|| ksym
== XK_Shift_L
) {
2524 tPtr
->flags
.extendSelection
= False
;
2526 /* end modify flag so selection can be extended */
2533 if (tPtr
->flags
.pointerGrabbed
) {
2534 tPtr
->flags
.pointerGrabbed
= False
;
2535 XUngrabPointer(dpy
, CurrentTime
);
2538 if(tPtr
->flags
.waitingForSelection
)
2541 if ((event
->xmotion
.state
& Button1Mask
)) {
2542 TextBlock
*tb
= tPtr
->currentTextBlock
;
2544 if(tb
&& tPtr
->flags
.isOverGraphic
&&
2545 tb
->graphic
&& !tb
->object
) {
2547 WMPixmap
*pixmap
= tb
->d
.pixmap
;
2548 char *types
[2] = {"application/X-image", NULL
};
2553 WMDragImageFromView(tPtr
->view
, pixmap
, types
,
2554 wmkpoint(event
->xmotion
.x_root
, event
->xmotion
.y_root
),
2559 if (!tPtr
->flags
.ownsSelection
) {
2560 WMCreateSelectionHandler(tPtr
->view
,
2561 XA_PRIMARY
, event
->xbutton
.time
,
2562 &selectionHandler
, NULL
);
2563 tPtr
->flags
.ownsSelection
= True
;
2566 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2570 mouseOverObject(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2576 if (tPtr
->flags
.pointerGrabbed
) {
2577 tPtr
->flags
.pointerGrabbed
= False
;
2578 XUngrabPointer(dpy
, CurrentTime
);
2582 if (tPtr
->flags
.waitingForSelection
)
2585 if (tPtr
->flags
.extendSelection
&& tPtr
->flags
.ownsSelection
) {
2586 selectRegion(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2590 if (tPtr
->flags
.ownsSelection
)
2591 releaseSelection(tPtr
);
2594 if (event
->xbutton
.button
== Button1
) {
2596 if(WMIsDoubleClick(event
)) {
2597 TextBlock
*tb
= tPtr
->currentTextBlock
;
2599 tPtr
->lastClickTime
= event
->xbutton
.time
;
2600 if(tb
&& tb
->graphic
&& !tb
->object
) {
2601 if(tPtr
->delegate
&& tPtr
->delegate
->didDoubleClickOnPicture
) {
2604 desc
= wmalloc(tb
->used
+1);
2605 memcpy(desc
, tb
->text
, tb
->used
);
2607 (*tPtr
->delegate
->didDoubleClickOnPicture
)(tPtr
->delegate
, desc
);
2611 autoSelectText(tPtr
, 2);
2614 } else if(event
->xbutton
.time
- tPtr
->lastClickTime
2615 < WINGsConfiguration
.doubleClickDelay
) {
2616 tPtr
->lastClickTime
= event
->xbutton
.time
;
2617 autoSelectText(tPtr
, 3);
2621 if (!tPtr
->flags
.focused
) {
2622 WMSetFocusToWidget(tPtr
);
2623 tPtr
->flags
.focused
= True
;
2626 tPtr
->lastClickTime
= event
->xbutton
.time
;
2627 cursorToTextPosition(tPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
2631 if (event
->xbutton
.button
2632 == WINGsConfiguration
.mouseWheelDown
) {
2633 WMScrollText(tPtr
, 16);
2637 if (event
->xbutton
.button
2638 == WINGsConfiguration
.mouseWheelUp
) {
2639 WMScrollText(tPtr
, -16);
2643 if (event
->xbutton
.button
== Button2
) {
2647 if (!tPtr
->flags
.editable
) {
2652 if (!WMRequestSelection(tPtr
->view
, XA_PRIMARY
, XA_STRING
,
2653 event
->xbutton
.time
, pasteText
, NULL
)) {
2655 text
= XFetchBuffer(tPtr
->view
->screen
->display
, &n
, 0);
2656 tPtr
->flags
.waitingForSelection
= 0;
2662 (tPtr
->parser
) (tPtr
, (void *) text
);
2663 layOutDocument(tPtr
);
2666 insertTextInteractively(tPtr
, text
, n
);
2670 NOTIFY(tPtr
, didChange
, WMTextDidChangeNotification
,
2671 (void*)WMInsertTextEvent
);
2673 updateCursorPosition(tPtr
);
2677 tPtr
->flags
.waitingForSelection
= True
;
2685 if (tPtr
->flags
.pointerGrabbed
) {
2686 tPtr
->flags
.pointerGrabbed
= False
;
2687 XUngrabPointer(dpy
, CurrentTime
);
2691 if (tPtr
->flags
.waitingForSelection
)
2699 handleEvents(XEvent
*event
, void *data
)
2701 Text
*tPtr
= (Text
*)data
;
2703 switch(event
->type
) {
2706 if (event
->xexpose
.count
!=0)
2710 if (!(W_VIEW(tPtr
->hS
))->flags
.realized
)
2711 WMRealizeWidget(tPtr
->hS
);
2715 if (!(W_VIEW(tPtr
->vS
))->flags
.realized
)
2716 WMRealizeWidget(tPtr
->vS
);
2720 if (!(W_VIEW(tPtr
->ruler
))->flags
.realized
)
2721 WMRealizeWidget(tPtr
->ruler
);
2726 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
2732 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))
2735 tPtr
->flags
.focused
= True
;
2737 if (tPtr
->flags
.editable
&& !tPtr
->timerID
) {
2738 tPtr
->timerID
= WMAddTimerHandler(12+0*CURSOR_BLINK_ON_DELAY
,
2746 tPtr
->flags
.focused
= False
;
2749 if (tPtr
->timerID
) {
2750 WMDeleteTimerHandler(tPtr
->timerID
);
2751 tPtr
->timerID
= NULL
;
2760 XFreePixmap(tPtr
->view
->screen
->display
, tPtr
->db
);
2762 WMEmptyArray(tPtr
->gfxItems
);
2765 WMDeleteTimerHandler(tPtr
->timerID
);
2767 WMReleaseFont(tPtr
->dFont
);
2768 WMReleaseColor(tPtr
->dColor
);
2769 WMDeleteSelectionHandler(tPtr
->view
, XA_PRIMARY
, CurrentTime
);
2770 WMRemoveNotificationObserver(tPtr
);
2781 insertPlainText(Text
*tPtr
, char *text
)
2788 mark
= strchr(start
, '\n');
2790 tb
= WMCreateTextBlockWithText(tPtr
,
2792 tPtr
->dColor
, tPtr
->flags
.first
, (int)(mark
-start
));
2794 tPtr
->flags
.first
= True
;
2796 if (start
&& strlen(start
)) {
2797 tb
= WMCreateTextBlockWithText(tPtr
, start
, tPtr
->dFont
,
2798 tPtr
->dColor
, tPtr
->flags
.first
, strlen(start
));
2800 tPtr
->flags
.first
= False
;
2804 if (tPtr
->flags
.prepend
)
2805 WMPrependTextBlock(tPtr
, tb
);
2807 WMAppendTextBlock(tPtr
, tb
);
2813 rulerMoveCallBack(WMWidget
*w
, void *self
)
2815 Text
*tPtr
= (Text
*)self
;
2819 if (W_CLASS(tPtr
) != WC_Text
)
2827 rulerReleaseCallBack(WMWidget
*w
, void *self
)
2829 Text
*tPtr
= (Text
*)self
;
2833 if (W_CLASS(tPtr
) != WC_Text
)
2841 draggingSourceOperation(WMView
*self
, Bool local
)
2843 return WDOperationCopy
;
2847 fetchDragData(WMView
*self
, char *type
)
2849 TextBlock
*tb
= ((WMText
*)self
->self
)->currentTextBlock
;
2856 printf("type is [%s]\n", type
);
2857 desc
= wmalloc(tb
->used
+1);
2858 memcpy(desc
, tb
->text
, tb
->used
);
2860 data
= WMCreateDataWithBytes(desc
, strlen(desc
)+1);
2868 static WMDragSourceProcs _DragSourceProcs
= {
2869 draggingSourceOperation
,
2877 draggingEntered(WMView
*self
, WMDraggingInfo
*info
)
2879 printf("draggingEntered\n");
2880 return WDOperationCopy
;
2885 draggingUpdated(WMView
*self
, WMDraggingInfo
*info
)
2887 return WDOperationCopy
;
2892 draggingExited(WMView
*self
, WMDraggingInfo
*info
)
2894 printf("draggingExited\n");
2898 prepareForDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2900 printf("prepareForDragOperation\n");
2908 receivedData(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
2909 void *cdata
, WMData
*data
)
2911 badbadbad
= wstrdup((char *)WMDataBytes(data
));
2915 /* when it's done in WINGs, remove this */
2918 requestDroppedData(WMView
*view
, WMDraggingInfo
*info
, char *type
)
2920 WMScreen
*scr
= W_VIEW_SCREEN(view
);
2922 if (!WMRequestSelection(scr
->dragInfo
.destView
,
2923 scr
->xdndSelectionAtom
,
2924 XInternAtom(scr
->display
, type
, False
),
2925 scr
->dragInfo
.timestamp
,
2926 receivedData
, &scr
->dragInfo
)) {
2927 wwarning("could not request data for dropped data");
2933 ev
.type
= ClientMessage
;
2934 ev
.xclient
.message_type
= scr
->xdndFinishedAtom
;
2935 ev
.xclient
.format
= 32;
2936 ev
.xclient
.window
= info
->destinationWindow
;
2937 ev
.xclient
.data
.l
[0] = 0;
2938 ev
.xclient
.data
.l
[1] = 0;
2939 ev
.xclient
.data
.l
[2] = 0;
2940 ev
.xclient
.data
.l
[3] = 0;
2941 ev
.xclient
.data
.l
[4] = 0;
2943 XSendEvent(scr
->display
, info
->sourceWindow
, False
, 0, &ev
);
2944 XFlush(scr
->display
);
2950 performDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2953 WMText
*tPtr
= (WMText
*)self
->self
;
2958 requestDroppedData(tPtr
->view
, info
, "application/X-color");
2959 color
= WMCreateNamedColor(W_VIEW_SCREEN(self
), badbadbad
, True
);
2961 WMSetTextSelectionColor(tPtr
, color
);
2962 WMReleaseColor(color
);
2971 concludeDragOperation(WMView
*self
, WMDraggingInfo
*info
)
2973 printf("concludeDragOperation\n");
2977 static WMDragDestinationProcs _DragDestinationProcs
= {
2981 prepareForDragOperation
,
2982 performDragOperation
,
2983 concludeDragOperation
2988 getStream(WMText
*tPtr
, int sel
, int array
)
2990 TextBlock
*tb
= NULL
;
2992 unsigned long where
= 0;
2997 if (!(tb
= tPtr
->firstTextBlock
))
3001 (tPtr
->writer
) (tPtr
, (void *) text
);
3005 tb
= tPtr
->firstTextBlock
;
3008 if (!tb
->graphic
|| (tb
->graphic
&& !tPtr
->flags
.monoFont
)) {
3010 if (!sel
|| (tb
->graphic
&& tb
->selected
)) {
3012 if (!tPtr
->flags
.ignoreNewLine
&& (tb
->first
|| tb
->blank
)
3013 && tb
!= tPtr
->firstTextBlock
) {
3014 text
= wrealloc(text
, where
+1);
3015 text
[where
++] = '\n';
3021 if(tb
->graphic
&& array
) {
3022 text
= wrealloc(text
, where
+4);
3023 text
[where
++] = 0xFA;
3024 text
[where
++] = (tb
->used
>>8)&0x0ff;
3025 text
[where
++] = tb
->used
&0x0ff;
3026 text
[where
++] = tb
->allocated
; /* extra info */
3028 text
= wrealloc(text
, where
+tb
->used
);
3029 memcpy(&text
[where
], tb
->text
, tb
->used
);
3033 } else if (sel
&& tb
->selected
) {
3035 if (!tPtr
->flags
.ignoreNewLine
&& tb
->blank
) {
3036 text
= wrealloc(text
, where
+1);
3037 text
[where
++] = '\n';
3043 text
= wrealloc(text
, where
+(tb
->s_end
- tb
->s_begin
));
3044 memcpy(&text
[where
], &tb
->text
[tb
->s_begin
],
3045 tb
->s_end
- tb
->s_begin
);
3046 where
+= tb
->s_end
- tb
->s_begin
;
3051 _gSnext
:tb
= tb
->next
;
3054 /* +1 for the end of string, let's be nice */
3055 text
= wrealloc(text
, where
+1);
3062 releaseStreamObjects(void *data
)
3069 getStreamObjects(WMText
*tPtr
, int sel
)
3071 WMArray
*array
= WMCreateArrayWithDestructor(4, releaseStreamObjects
);
3075 char *start
, *fa
, *desc
;
3077 stream
= getStream(tPtr
, sel
, 1);
3084 fa
= strchr(start
, 0xFA);
3086 if((int)(fa
- start
)>0) {
3088 desc
[(int)(fa
- start
)] = 0;
3089 data
= WMCreateDataWithBytes((void *)desc
, (int)(fa
- start
));
3090 WMSetDataFormat(data
, TYPETEXT
);
3091 WMAddToArray(array
, (void *) data
);
3094 len
= *(fa
+1)*0xff + *(fa
+2);
3095 data
= WMCreateDataWithBytes((void *)(fa
+4), len
);
3096 WMSetDataFormat(data
, *(fa
+3));
3097 WMAddToArray(array
, (void *) data
);
3098 start
= fa
+ len
+ 4;
3101 if (start
&& strlen(start
)) {
3102 data
= WMCreateDataWithBytes((void *)start
, strlen(start
));
3103 WMSetDataFormat(data
, TYPETEXT
);
3104 WMAddToArray(array
, (void *) data
);
3116 WMCreateTextForDocumentType(WMWidget
*parent
, WMAction
*parser
, WMAction
*writer
)
3123 tPtr
= wmalloc(sizeof(Text
));
3124 memset(tPtr
, 0, sizeof(Text
));
3125 tPtr
->widgetClass
= WC_Text
;
3126 tPtr
->view
= W_CreateView(W_VIEW(parent
));
3128 perror("could not create text's view\n");
3133 dpy
= tPtr
->view
->screen
->display
;
3134 scr
= tPtr
->view
->screen
;
3136 tPtr
->view
->self
= tPtr
;
3137 tPtr
->view
->attribs
.cursor
= scr
->textCursor
;
3138 tPtr
->view
->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3139 W_ResizeView(tPtr
->view
, 250, 200);
3141 tPtr
->dColor
= WMWhiteColor(scr
);
3142 tPtr
->bgGC
= WMColorGC(tPtr
->dColor
);
3143 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->dColor
);
3144 WMReleaseColor(tPtr
->dColor
);
3146 tPtr
->dColor
= WMBlackColor(scr
);
3147 tPtr
->fgGC
= WMColorGC(tPtr
->dColor
);
3149 gcv
.graphics_exposures
= False
;
3150 gcv
.foreground
= W_PIXEL(scr
->gray
);
3151 gcv
.background
= W_PIXEL(scr
->darkGray
);
3152 gcv
.fill_style
= FillStippled
;
3153 /* why not use scr->stipple here? */
3154 gcv
.stipple
= XCreateBitmapFromData(dpy
, W_DRAWABLE(scr
),
3155 STIPPLE_BITS
, STIPPLE_WIDTH
, STIPPLE_HEIGHT
);
3156 tPtr
->stippledGC
= XCreateGC(dpy
, W_DRAWABLE(scr
),
3157 GCForeground
|GCBackground
|GCStipple
3158 |GCFillStyle
|GCGraphicsExposures
, &gcv
);
3164 tPtr
->dFont
= WMRetainFont(WMSystemFontOfSize(scr
, 12));
3166 tPtr
->view
->delegate
= &_TextViewDelegate
;
3168 tPtr
->delegate
= NULL
;
3171 tPtr
->timerID
= NULL
;
3174 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
3175 |EnterWindowMask
|LeaveWindowMask
|FocusChangeMask
,
3176 handleEvents
, tPtr
);
3178 WMCreateEventHandler(tPtr
->view
, ButtonReleaseMask
|ButtonPressMask
3179 |KeyReleaseMask
|KeyPressMask
|Button1MotionMask
,
3180 handleActionEvents
, tPtr
);
3182 WMAddNotificationObserver(ownershipObserver
, tPtr
,
3183 WMSelectionOwnerDidChangeNotification
,
3186 WMSetViewDragSourceProcs(tPtr
->view
, &_DragSourceProcs
);
3187 WMSetViewDragDestinationProcs(tPtr
->view
, &_DragDestinationProcs
);
3191 char *types
[3] = {"application/X-color", "application/X-image", NULL
};
3192 WMRegisterViewForDraggedTypes(tPtr
->view
, types
);
3195 /*WMAddNotificationObserver(fontChanged, tPtr,
3196 WMFontPanelDidChangeNotification, tPtr);*/
3198 tPtr
->firstTextBlock
= NULL
;
3199 tPtr
->lastTextBlock
= NULL
;
3200 tPtr
->currentTextBlock
= NULL
;
3203 tPtr
->gfxItems
= WMCreateArray(4);
3205 tPtr
->parser
= parser
;
3206 tPtr
->writer
= writer
;
3208 tPtr
->sel
.x
= tPtr
->sel
.y
= 2;
3209 tPtr
->sel
.w
= tPtr
->sel
.h
= 0;
3211 tPtr
->clicked
.x
= tPtr
->clicked
.y
= 2;
3213 tPtr
->visible
.x
= tPtr
->visible
.y
= 2;
3214 tPtr
->visible
.h
= tPtr
->view
->size
.height
;
3215 tPtr
->visible
.w
= tPtr
->view
->size
.width
- 4;
3217 tPtr
->cursor
.x
= -23;
3220 tPtr
->docHeight
= 0;
3221 tPtr
->dBulletPix
= WMCreatePixmapFromXPMData(tPtr
->view
->screen
,
3223 tPtr
->db
= (Pixmap
) NULL
;
3224 tPtr
->bgPixmap
= NULL
;
3226 tPtr
->margins
= WMGetRulerMargins(NULL
);
3227 tPtr
->margins
->right
= tPtr
->visible
.w
;
3230 tPtr
->flags
.rulerShown
= False
;
3231 tPtr
->flags
.monoFont
= False
;
3232 tPtr
->flags
.focused
= False
;
3233 tPtr
->flags
.editable
= True
;
3234 tPtr
->flags
.ownsSelection
= False
;
3235 tPtr
->flags
.pointerGrabbed
= False
;
3236 tPtr
->flags
.extendSelection
= False
;
3237 tPtr
->flags
.frozen
= False
;
3238 tPtr
->flags
.cursorShown
= True
;
3239 tPtr
->flags
.acceptsGraphic
= False
;
3240 tPtr
->flags
.horizOnDemand
= False
;
3241 tPtr
->flags
.needsLayOut
= False
;
3242 tPtr
->flags
.ignoreNewLine
= False
;
3243 tPtr
->flags
.indentNewLine
= False
;
3244 tPtr
->flags
.laidOut
= False
;
3245 tPtr
->flags
.ownsSelection
= False
;
3246 tPtr
->flags
.waitingForSelection
= False
;
3247 tPtr
->flags
.prepend
= False
;
3248 tPtr
->flags
.isOverGraphic
= False
;
3249 tPtr
->flags
.relief
= WRSunken
;
3250 tPtr
->flags
.isOverGraphic
= 0;
3251 tPtr
->flags
.alignment
= WALeft
;
3252 tPtr
->flags
.first
= True
;
3258 WMPrependTextStream(WMText
*tPtr
, char *text
)
3260 CHECK_CLASS(tPtr
, WC_Text
);
3263 if (tPtr
->flags
.ownsSelection
)
3264 releaseSelection(tPtr
);
3266 updateScrollers(tPtr
);
3270 tPtr
->flags
.prepend
= True
;
3271 if (text
&& tPtr
->parser
)
3272 (tPtr
->parser
) (tPtr
, (void *) text
);
3274 insertPlainText(tPtr
, text
);
3276 tPtr
->flags
.needsLayOut
= True
;
3278 if(!tPtr
->flags
.frozen
) {
3279 layOutDocument(tPtr
);
3285 WMAppendTextStream(WMText
*tPtr
, char *text
)
3287 CHECK_CLASS(tPtr
, WC_Text
);
3290 if (tPtr
->flags
.ownsSelection
)
3291 releaseSelection(tPtr
);
3293 updateScrollers(tPtr
);
3297 tPtr
->flags
.prepend
= False
;
3298 if (text
&& tPtr
->parser
)
3299 (tPtr
->parser
) (tPtr
, (void *) text
);
3301 insertPlainText(tPtr
, text
);
3303 tPtr
->flags
.needsLayOut
= True
;
3304 if(tPtr
->currentTextBlock
) {
3305 if(tPtr
->currentTextBlock
->graphic
)
3308 tPtr
->tpos
= tPtr
->currentTextBlock
->used
;
3311 if(!tPtr
->flags
.frozen
) {
3312 layOutDocument(tPtr
);
3318 WMGetTextStream(WMText
*tPtr
)
3320 CHECK_CLASS(tPtr
, WC_Text
);
3321 return getStream(tPtr
, 0, 0);
3325 WMGetTextSelectedStream(WMText
*tPtr
)
3327 CHECK_CLASS(tPtr
, WC_Text
);
3328 return getStream(tPtr
, 1, 0);
3332 WMGetTextObjects(WMText
*tPtr
)
3334 CHECK_CLASS(tPtr
, WC_Text
);
3335 return getStreamObjects(tPtr
, 0);
3339 WMGetTextSelectedObjects(WMText
*tPtr
)
3341 CHECK_CLASS(tPtr
, WC_Text
);
3342 return getStreamObjects(tPtr
, 1);
3347 WMSetTextDelegate(WMText
*tPtr
, WMTextDelegate
*delegate
)
3349 CHECK_CLASS(tPtr
, WC_Text
);
3351 tPtr
->delegate
= delegate
;
3356 WMCreateTextBlockWithObject(WMText
*tPtr
, WMWidget
*w
,
3357 char *description
, WMColor
*color
,
3358 unsigned short first
, unsigned short extraInfo
)
3362 if (!w
|| !description
|| !color
)
3365 tb
= wmalloc(sizeof(TextBlock
));
3369 tb
->text
= wstrdup(description
);
3370 tb
->used
= strlen(description
);
3373 tb
->color
= WMRetainColor(color
);
3374 tb
->marginN
= newMargin(tPtr
, NULL
);
3375 tb
->allocated
= extraInfo
;
3380 tb
->underlined
= False
;
3381 tb
->selected
= False
;
3383 tb
->sections
= NULL
;
3393 WMCreateTextBlockWithPixmap(WMText
*tPtr
, WMPixmap
*p
,
3394 char *description
, WMColor
*color
,
3395 unsigned short first
, unsigned short extraInfo
)
3399 if (!p
|| !description
|| !color
)
3402 tb
= wmalloc(sizeof(TextBlock
));
3406 tb
->text
= wstrdup(description
);
3407 tb
->used
= strlen(description
);
3409 tb
->d
.pixmap
= WMRetainPixmap(p
);
3410 tb
->color
= WMRetainColor(color
);
3411 tb
->marginN
= newMargin(tPtr
, NULL
);
3412 tb
->allocated
= extraInfo
;
3417 tb
->underlined
= False
;
3418 tb
->selected
= False
;
3420 tb
->sections
= NULL
;
3430 WMCreateTextBlockWithText(WMText
*tPtr
, char *text
, WMFont
*font
, WMColor
*color
,
3431 unsigned short first
, unsigned short len
)
3435 if (!font
|| !color
)
3438 tb
= wmalloc(sizeof(TextBlock
));
3442 tb
->allocated
= reqBlockSize(len
);
3443 tb
->text
= (char *)wmalloc(tb
->allocated
);
3444 memset(tb
->text
, 0, tb
->allocated
);
3446 if (len
< 1|| !text
|| (*text
== '\n' && len
==1 )) {
3451 memcpy(tb
->text
, text
, len
);
3455 tb
->text
[tb
->used
] = 0;
3457 tb
->d
.font
= WMRetainFont(font
);
3458 tb
->color
= WMRetainColor(color
);
3459 tb
->marginN
= newMargin(tPtr
, NULL
);
3462 tb
->graphic
= False
;
3463 tb
->underlined
= False
;
3464 tb
->selected
= False
;
3466 tb
->sections
= NULL
;
3474 WMSetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int first
,
3475 unsigned int kanji
, unsigned int underlined
, int script
,
3476 WMRulerMargins
*margins
)
3478 TextBlock
*tb
= (TextBlock
*) vtb
;
3484 tb
->underlined
= underlined
;
3485 tb
->script
= script
;
3486 tb
->marginN
= newMargin(tPtr
, margins
);
3490 WMGetTextBlockProperties(WMText
*tPtr
, void *vtb
, unsigned int *first
,
3491 unsigned int *kanji
, unsigned int *underlined
, int *script
,
3492 WMRulerMargins
*margins
)
3494 TextBlock
*tb
= (TextBlock
*) vtb
;
3498 if (first
) *first
= tb
->first
;
3499 if (kanji
) *kanji
= tb
->kanji
;
3500 if (underlined
) *underlined
= tb
->underlined
;
3501 if (script
) *script
= tb
->script
;
3502 if (margins
) margins
= &tPtr
->margins
[tb
->marginN
];
3508 WMPrependTextBlock(WMText
*tPtr
, void *vtb
)
3510 TextBlock
*tb
= (TextBlock
*)vtb
;
3517 WMWidget
*w
= tb
->d
.widget
;
3518 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
3519 (W_VIEW(w
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3520 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3523 WMAddToArray(tPtr
->gfxItems
, (void *)tb
);
3527 tPtr
->tpos
= tb
->used
;
3530 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
3531 tb
->next
= tb
->prior
= NULL
;
3533 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
3534 = tPtr
->currentTextBlock
= tb
;
3539 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
3542 tb
->next
= tPtr
->currentTextBlock
;
3543 tb
->prior
= tPtr
->currentTextBlock
->prior
;
3544 if (tPtr
->currentTextBlock
->prior
)
3545 tPtr
->currentTextBlock
->prior
->next
= tb
;
3547 tPtr
->currentTextBlock
->prior
= tb
;
3549 tPtr
->firstTextBlock
= tb
;
3551 tPtr
->currentTextBlock
= tb
;
3556 WMAppendTextBlock(WMText
*tPtr
, void *vtb
)
3558 TextBlock
*tb
= (TextBlock
*)vtb
;
3565 WMWidget
*w
= tb
->d
.widget
;
3566 if (W_CLASS(w
) != WC_TextField
&& W_CLASS(w
) != WC_Text
) {
3567 (W_VIEW(w
))->attribs
.cursor
=
3568 tPtr
->view
->screen
->defaultCursor
;
3569 (W_VIEW(w
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3572 WMAddToArray(tPtr
->gfxItems
, (void *)tb
);
3576 tPtr
->tpos
= tb
->used
;
3580 if (!tPtr
->lastTextBlock
|| !tPtr
->firstTextBlock
) {
3581 tb
->next
= tb
->prior
= NULL
;
3583 tPtr
->lastTextBlock
= tPtr
->firstTextBlock
3584 = tPtr
->currentTextBlock
= tb
;
3589 tb
->marginN
= tPtr
->currentTextBlock
->marginN
;
3592 tb
->next
= tPtr
->currentTextBlock
->next
;
3593 tb
->prior
= tPtr
->currentTextBlock
;
3594 if (tPtr
->currentTextBlock
->next
)
3595 tPtr
->currentTextBlock
->next
->prior
= tb
;
3597 tPtr
->currentTextBlock
->next
= tb
;
3600 tPtr
->lastTextBlock
= tb
;
3602 tPtr
->currentTextBlock
= tb
;
3607 WMRemoveTextBlock(WMText
*tPtr
)
3609 TextBlock
*tb
= NULL
;
3611 if (!tPtr
|| !tPtr
->firstTextBlock
|| !tPtr
->lastTextBlock
3612 || !tPtr
->currentTextBlock
) {
3616 tb
= tPtr
->currentTextBlock
;
3618 WMRemoveFromArray(tPtr
->gfxItems
, (void *)tb
);
3621 WMUnmapWidget(tb
->d
.widget
);
3625 if (tPtr
->currentTextBlock
== tPtr
->firstTextBlock
) {
3626 if (tPtr
->currentTextBlock
->next
)
3627 tPtr
->currentTextBlock
->next
->prior
= NULL
;
3629 tPtr
->firstTextBlock
= tPtr
->currentTextBlock
->next
;
3630 tPtr
->currentTextBlock
= tPtr
->firstTextBlock
;
3632 } else if (tPtr
->currentTextBlock
== tPtr
->lastTextBlock
) {
3633 tPtr
->currentTextBlock
->prior
->next
= NULL
;
3634 tPtr
->lastTextBlock
= tPtr
->currentTextBlock
->prior
;
3635 tPtr
->currentTextBlock
= tPtr
->lastTextBlock
;
3637 tPtr
->currentTextBlock
->prior
->next
= tPtr
->currentTextBlock
->next
;
3638 tPtr
->currentTextBlock
->next
->prior
= tPtr
->currentTextBlock
->prior
;
3639 tPtr
->currentTextBlock
= tPtr
->currentTextBlock
->next
;
3648 destroyWidget(WMWidget
*widget
)
3650 WMDestroyWidget(widget
);
3651 // -- never do this -- wfree(widget);
3657 WMDestroyTextBlock(WMText
*tPtr
, void *vtb
)
3659 TextBlock
*tb
= (TextBlock
*)vtb
;
3665 /* naturally, there's a danger to destroying widgets whose action
3666 * brings us here: ie. press a button to destroy it...
3667 * need to find a safer way. till then... this stays commented out */
3668 /* 5 months later... destroy it 10 seconds after now which should
3669 * be enough time for the widget's action to be completed... :-) */
3670 /* This is a bad assumption. Just destroy the widget here.
3671 // if the caller needs it, it can protect it with W_RetainView()
3672 //WMAddTimerHandler(10000, destroyWidget, (void *)tb->d.widget);*/
3673 WMDestroyWidget(tb
->d
.widget
);
3675 WMReleasePixmap(tb
->d
.pixmap
);
3678 WMReleaseFont(tb
->d
.font
);
3681 WMReleaseColor(tb
->color
);
3682 /* isn't this going to memleak if nsections==0? if (tb->sections && tb->nsections > 0) */
3684 wfree(tb
->sections
);
3691 WMSetTextForegroundColor(WMText
*tPtr
, WMColor
*color
)
3697 tPtr
->fgGC
= WMColorGC(color
);
3699 WMColor
*color
= WMBlackColor(tPtr
->view
->screen
);
3700 tPtr
->fgGC
= WMColorGC(color
);
3701 WMReleaseColor(color
);
3708 WMSetTextBackgroundColor(WMText
*tPtr
, WMColor
*color
)
3714 tPtr
->bgGC
= WMColorGC(color
);
3715 W_SetViewBackgroundColor(tPtr
->view
, color
);
3717 tPtr
->bgGC
= WMColorGC(WMWhiteColor(tPtr
->view
->screen
));
3718 W_SetViewBackgroundColor(tPtr
->view
,
3719 WMWhiteColor(tPtr
->view
->screen
));
3725 void WMSetTextBackgroundPixmap(WMText
*tPtr
, WMPixmap
*pixmap
)
3731 WMReleasePixmap(tPtr
->bgPixmap
);
3734 tPtr
->bgPixmap
= WMRetainPixmap(pixmap
);
3736 tPtr
->bgPixmap
= NULL
;
3740 WMSetTextRelief(WMText
*tPtr
, WMReliefType relief
)
3744 tPtr
->flags
.relief
= relief
;
3745 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3749 WMSetTextHasHorizontalScroller(WMText
*tPtr
, Bool shouldhave
)
3754 if (shouldhave
&& !tPtr
->hS
) {
3755 tPtr
->hS
= WMCreateScroller(tPtr
);
3756 (W_VIEW(tPtr
->hS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3757 (W_VIEW(tPtr
->hS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3758 WMSetScrollerArrowsPosition(tPtr
->hS
, WSAMinEnd
);
3759 WMSetScrollerAction(tPtr
->hS
, scrollersCallBack
, tPtr
);
3760 WMMapWidget(tPtr
->hS
);
3761 } else if (!shouldhave
&& tPtr
->hS
) {
3762 WMUnmapWidget(tPtr
->hS
);
3763 WMDestroyWidget(tPtr
->hS
);
3769 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3774 WMSetTextHasRuler(WMText
*tPtr
, Bool shouldhave
)
3779 if(shouldhave
&& !tPtr
->ruler
) {
3780 tPtr
->ruler
= WMCreateRuler(tPtr
);
3781 (W_VIEW(tPtr
->ruler
))->attribs
.cursor
=
3782 tPtr
->view
->screen
->defaultCursor
;
3783 (W_VIEW(tPtr
->ruler
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3784 WMSetRulerReleaseAction(tPtr
->ruler
, rulerReleaseCallBack
, tPtr
);
3785 WMSetRulerMoveAction(tPtr
->ruler
, rulerMoveCallBack
, tPtr
);
3786 } else if(!shouldhave
&& tPtr
->ruler
) {
3787 WMShowTextRuler(tPtr
, False
);
3788 WMDestroyWidget(tPtr
->ruler
);
3791 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3795 WMShowTextRuler(WMText
*tPtr
, Bool show
)
3802 if(tPtr
->flags
.monoFont
)
3805 tPtr
->flags
.rulerShown
= show
;
3807 WMMapWidget(tPtr
->ruler
);
3809 WMUnmapWidget(tPtr
->ruler
);
3812 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3816 WMGetTextRulerShown(WMText
*tPtr
)
3824 return tPtr
->flags
.rulerShown
;
3829 WMSetTextHasVerticalScroller(WMText
*tPtr
, Bool shouldhave
)
3834 if (shouldhave
&& !tPtr
->vS
) {
3835 tPtr
->vS
= WMCreateScroller(tPtr
);
3836 (W_VIEW(tPtr
->vS
))->attribs
.cursor
= tPtr
->view
->screen
->defaultCursor
;
3837 (W_VIEW(tPtr
->vS
))->attribFlags
|= CWOverrideRedirect
| CWCursor
;
3838 WMSetScrollerArrowsPosition(tPtr
->vS
, WSAMaxEnd
);
3839 WMSetScrollerAction(tPtr
->vS
, scrollersCallBack
, tPtr
);
3840 WMMapWidget(tPtr
->vS
);
3841 } else if (!shouldhave
&& tPtr
->vS
) {
3842 WMUnmapWidget(tPtr
->vS
);
3843 WMDestroyWidget(tPtr
->vS
);
3849 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3855 WMScrollText(WMText
*tPtr
, int amount
)
3860 if (amount
== 0 || !tPtr
->view
->flags
.realized
)
3864 if (tPtr
->vpos
> 0) {
3865 if (tPtr
->vpos
> abs(amount
)) tPtr
->vpos
+= amount
;
3870 int limit
= tPtr
->docHeight
- tPtr
->visible
.h
;
3871 if (tPtr
->vpos
< limit
) {
3872 if (tPtr
->vpos
< limit
-amount
) tPtr
->vpos
+= amount
;
3873 else tPtr
->vpos
= limit
;
3878 if (scroll
&& tPtr
->vpos
!= tPtr
->prevVpos
) {
3879 updateScrollers(tPtr
);
3882 tPtr
->prevVpos
= tPtr
->vpos
;
3887 WMPageText(WMText
*tPtr
, Bool direction
)
3889 if (!tPtr
) return False
;
3890 if (!tPtr
->view
->flags
.realized
) return False
;
3892 return WMScrollText(tPtr
, direction
?tPtr
->visible
.h
:-tPtr
->visible
.h
);
3896 WMSetTextEditable(WMText
*tPtr
, Bool editable
)
3900 tPtr
->flags
.editable
= editable
;
3904 WMGetTextEditable(WMText
*tPtr
)
3908 return tPtr
->flags
.editable
;
3912 WMSetTextIndentNewLines(WMText
*tPtr
, Bool indent
)
3916 tPtr
->flags
.indentNewLine
= indent
;
3920 WMSetTextIgnoresNewline(WMText
*tPtr
, Bool ignore
)
3924 tPtr
->flags
.ignoreNewLine
= ignore
;
3928 WMGetTextIgnoresNewline(WMText
*tPtr
)
3932 return tPtr
->flags
.ignoreNewLine
;
3936 WMSetTextUsesMonoFont(WMText
*tPtr
, Bool mono
)
3942 if(tPtr
->flags
.rulerShown
)
3943 WMShowTextRuler(tPtr
, False
);
3944 if(tPtr
->flags
.alignment
!= WALeft
)
3945 tPtr
->flags
.alignment
= WALeft
;
3948 tPtr
->flags
.monoFont
= mono
;
3949 textDidResize(tPtr
->view
->delegate
, tPtr
->view
);
3953 WMGetTextUsesMonoFont(WMText
*tPtr
)
3957 return tPtr
->flags
.monoFont
;
3962 WMSetTextDefaultFont(WMText
*tPtr
, WMFont
*font
)
3967 WMReleaseFont(tPtr
->dFont
);
3969 tPtr
->dFont
= WMRetainFont(font
);
3971 tPtr
->dFont
= WMRetainFont(WMSystemFontOfSize(tPtr
->view
->screen
, 12));
3975 WMGetTextDefaultFont(WMText
*tPtr
)
3980 return WMRetainFont(tPtr
->dFont
);
3984 WMSetTextDefaultColor(WMText
*tPtr
, WMColor
*color
)
3989 WMReleaseColor(tPtr
->dColor
);
3991 tPtr
->dColor
= WMRetainColor(color
);
3993 tPtr
->dColor
= WMBlackColor(tPtr
->view
->screen
);
3997 WMGetTextDefaultColor(WMText
*tPtr
)
4002 return WMRetainColor(tPtr
->dColor
);
4006 WMSetTextAlignment(WMText
*tPtr
, WMAlignment alignment
)
4010 if(tPtr
->flags
.monoFont
)
4011 tPtr
->flags
.alignment
= WALeft
;
4013 tPtr
->flags
.alignment
= alignment
;
4018 WMGetTextInsertType(WMText
*tPtr
)
4022 return tPtr
->flags
.prepend
;
4027 WMSetTextSelectionColor(WMText
*tPtr
, WMColor
*color
)
4029 if (!tPtr
|| !color
)
4032 setSelectionProperty(tPtr
, NULL
, color
, -1);
4036 WMGetTextSelectionColor(WMText
*tPtr
)
4043 tb
= tPtr
->currentTextBlock
;
4045 if (!tb
|| !tPtr
->flags
.ownsSelection
)
4056 WMSetTextSelectionFont(WMText
*tPtr
, WMFont
*font
)
4061 setSelectionProperty(tPtr
, font
, NULL
, -1) ;
4065 WMGetTextSelectionFont(WMText
*tPtr
)
4072 tb
= tPtr
->currentTextBlock
;
4074 if (!tb
|| !tPtr
->flags
.ownsSelection
)
4081 tb
= getFirstNonGraphicBlockFor(tb
, 1);
4085 return (tb
->selected
? tb
->d
.font
: NULL
);
4090 WMSetTextSelectionUnderlined(WMText
*tPtr
, int underlined
)
4092 if (!tPtr
|| (underlined
!=0 && underlined
!=1))
4095 setSelectionProperty(tPtr
, NULL
, NULL
, underlined
);
4100 WMGetTextSelectionUnderlined(WMText
*tPtr
)
4107 tb
= tPtr
->currentTextBlock
;
4109 if (!tb
|| !tPtr
->flags
.ownsSelection
)
4115 return tb
->underlined
;
4120 WMFreezeText(WMText
*tPtr
)
4125 tPtr
->flags
.frozen
= True
;
4130 WMThawText(WMText
*tPtr
)
4135 tPtr
->flags
.frozen
= False
;
4137 if(tPtr
->flags
.monoFont
) {
4138 int j
, c
= WMGetArrayItemCount(tPtr
->gfxItems
);
4141 /* make sure to unmap widgets no matter where they are */
4142 /* they'll be later remapped if needed by paintText */
4143 for(j
=0; j
<c
; j
++) {
4144 if ((tb
= (TextBlock
*) WMGetFromArray(tPtr
->gfxItems
, j
))) {
4145 if (tb
->object
&& ((W_VIEW(tb
->d
.widget
))->flags
.mapped
))
4146 WMUnmapWidget(tb
->d
.widget
);
4152 tPtr
->flags
.laidOut
= False
;
4153 layOutDocument(tPtr
);
4154 updateScrollers(tPtr
);
4156 tPtr
->flags
.needsLayOut
= False
;
4160 /* find first occurence of a string */
4162 mystrstr(char *haystack
, char *needle
, unsigned short len
, char *end
,
4167 if(!haystack
|| !needle
|| !end
)
4170 for (ptr
= haystack
; ptr
< end
; ptr
++) {
4172 if (*ptr
== *needle
&& !strncmp(ptr
, needle
, len
))
4176 if (tolower(*ptr
) == tolower(*needle
) &&
4177 !strncasecmp(ptr
, needle
, len
))
4185 /* find last occurence of a string */
4187 mystrrstr(char *haystack
, char *needle
, unsigned short len
, char *end
,
4192 if(!haystack
|| !needle
|| !end
)
4195 for (ptr
= haystack
-2; ptr
> end
; ptr
--) {
4197 if (*ptr
== *needle
&& !strncmp(ptr
, needle
, len
))
4200 if (tolower(*ptr
) == tolower(*needle
) &&
4201 !strncasecmp(ptr
, needle
, len
))
4211 WMFindInTextStream(WMText
*tPtr
, char *needle
, Bool direction
,
4218 if (!tPtr
|| !needle
)
4222 if (! (tb
= tPtr
->currentTextBlock
)) {
4223 if (! (tb
= ( (direction
> 0) ?
4224 tPtr
->firstTextBlock
: tPtr
->lastTextBlock
) ) ){
4228 /* if(tb != ((direction>0) ?tPtr->firstTextBlock : tPtr->lastTextBlock))
4229 tb = (direction>0) ? tb->next : tb->prior; */
4230 if(tb
!= tPtr
->lastTextBlock
)
4234 tb
= tPtr
->currentTextBlock
;
4242 if(pos
+1 < tb
->used
)
4245 if(tb
->used
- pos
> 0 && pos
> 0) {
4246 mark
= mystrstr(&tb
->text
[pos
], needle
,
4247 strlen(needle
), &tb
->text
[tb
->used
], caseSensitive
);
4260 mark
= mystrrstr(&tb
->text
[pos
], needle
,
4261 strlen(needle
), tb
->text
, caseSensitive
);
4273 WMFont
*font
= tPtr
->flags
.monoFont
?tPtr
->dFont
:tb
->d
.font
;
4275 tPtr
->tpos
= (int)(mark
- tb
->text
);
4276 tPtr
->currentTextBlock
= tb
;
4277 updateCursorPosition(tPtr
);
4278 tPtr
->sel
.y
= tPtr
->cursor
.y
+5;
4279 tPtr
->sel
.h
= tPtr
->cursor
.h
-10;
4280 tPtr
->sel
.x
= tPtr
->cursor
.x
+1;
4281 tPtr
->sel
.w
= WMIN(WMWidthOfString(font
,
4282 &tb
->text
[tPtr
->tpos
], strlen(needle
)),
4283 tPtr
->docWidth
- tPtr
->sel
.x
);
4284 tPtr
->flags
.ownsSelection
= True
;
4291 tb
= (direction
>0) ? tb
->next
: tb
->prior
;
4293 pos
= (direction
>0) ? 0 : tb
->used
;
4302 WMReplaceTextSelection(WMText
*tPtr
, char *replacement
)
4307 if (!tPtr
->flags
.ownsSelection
)
4310 removeSelection(tPtr
);
4313 insertTextInteractively(tPtr
, replacement
, strlen(replacement
));
4314 updateCursorPosition(tPtr
);