1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8
9 #include <dxconfig.h>
10 #include "../base/defines.h"
11
12
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #if defined (HAVE_CTYPE_H)
17 #include <ctype.h>
18 #endif
19 #if defined (HAVE_TYPES_H)
20 #include <types.h>
21 #endif
22 #include <X11/IntrinsicP.h>
23 #include <Xm/Xm.h>
24 #include <Xm/MessageB.h>
25
26
27 #include "MultiTextP.h"
28
29 #if defined(intelnt)
30 /* winuser.h defines ScrollWindow which conflicts with code in this file */
31 #define ScrollWindow _ScrollWindow
32 #endif
33
34 #define CR 13
35 #define TAB 9
36 #define BACKSPACE 8
37 #define SPACE 32
38 #define CTRL_C 3
39
40 #define DEFAULT_WORD_SPACING 1
41 #define DEFAULT_LINE_SPACING 0
42 #define DEFAULT_FONT_NAME "fixed"
43 #define MAX_BUFF_SIZE 32767
44 #define MAX_STR_LEN 1024
45
46 #define UP 0
47 #define DOWN 1
48 #define LEFT 2
49 #define RIGHT 3
50
51 #define TOP 1
52 #define BOTTOM 2
53 #define ON TRUE
54 #define OFF FALSE
55
56 #ifndef ABS
57 #define ABS(a) (((a) > 0) ? (a) : -(a))
58 #endif
59
60 #define STRCMP(a,b) ((a) ? ((b) ? strcmp(a,b) : strcmp(a,"")) : \
61 ((b) ? strcmp("",b) : 0))
62
63 /*
64 * Forward declaration of methods:
65 */
66 static void ClassInitialize();
67
68 static void Initialize(Widget, Widget, ArgList, Cardinal*);
69
70 static void Destroy(Widget);
71
72 static void Redisplay(Widget, XEvent*, Region);
73
74 static void Resize(Widget);
75
76 static Boolean SetValues();
77
78 /*
79 * Private routines used by the XmMultiTextWidget.
80 */
81 static char* NewString(char*);
82
83 static XtGeometryResult ChangeHeight(XmMultiTextWidget,
84 Dimension);
85
86 static void GetBoundingBox(XmMultiTextWidget,
87 char*,
88 XFontStruct*,
89 XCharStruct*,
90 int);
91
92 static void ShiftFollowingLines(LineList, int);
93
94 static Boolean PtInLine (int x, int y, LineList lp);
95 static Boolean PtInWord (int x, int y, WordList wp, LineList lp);
96 static Boolean SameLinks (WordList wp1, WordList wp2);
97 static void SetCurrentFont (XmMultiTextWidget w, WordList wp,
98 XFontStruct *font);
99 static void SetCurrentColor (XmMultiTextWidget w, WordList wp,
100 unsigned long color);
101 static void DisplayImage (XmMultiTextWidget w, WordList wp);
102 static void DisplayWord (XmMultiTextWidget w, WordList wp);
103 static void DisplaySelectedWord (XmMultiTextWidget w, WordList wp);
104 static void DisplayDeselectedWord (XmMultiTextWidget w, WordList wp);
105 static void DrawLinkMarking (XmMultiTextWidget w, WordList wp);
106 static void CalculateSpacing (Widget w, WordList wp, int *spaceBefore,
107 int *spaceAfter);
108 static void DrawWord (XmMultiTextWidget w, WordList wp,
109 Boolean selected);
110 static void DrawLine (XmMultiTextWidget w, LineList lp);
111 static void ResizeTheLine (XmMultiTextWidget w, LineList lp,
112 WordList theWord);
113 static void FreeCharRecord (XmMultiTextWidget w, CharList cp);
114 static void FreeWordRecord (XmMultiTextWidget w, WordList wp);
115 static void FreeLineRecord (XmMultiTextWidget w, LineList lp);
116 static int NextTab (XmMultiTextWidget w, int *tabWidth,
117 int indent);
118 static unsigned long Color (XmMultiTextWidget w, char *name);
119 static XFontStruct *NamedFont (XmMultiTextWidget w, char *name);
120 static LineList NewLine (XmMultiTextWidget w, int indent, int yposn,
121 int lineSpacing);
122 static Boolean StuffWordOntoCurrentLine (XmMultiTextWidget w, LineList lp, WordList wp,
123 int neededWidth, Boolean firstWordOfLine,
124 Boolean isTab, Boolean prevWordIsTab);
125 static int GetNeededWidth (XmMultiTextWidget w, WordList wPtr, int indent,
126 Boolean *firstWordOfLine, Boolean *isTab,
127 Boolean *prevWordIsTab);
128 static unsigned short StoreWord (XmMultiTextWidget w, WordList wordPtr,
129 int indent);
130 static unsigned int AppendWordToTopLine (XmMultiTextWidget cw, WordList wordPtr,
131 int indent);
132 static void PositionCursor (XmMultiTextWidget cw, int x, int y,
133 LineList *lp, int *actualX);
134 static void UpdateCursor (XmMultiTextWidget cw, LineList lp, int x,
135 int actualX, int actualY);
136 static void MakeCursorPixmaps (XmMultiTextWidget cw);
137 static void BlinkCursor (XmMultiTextWidget cw);
138 static void TurnOnCursor (XmMultiTextWidget cw);
139 static void TurnOffCursor (XmMultiTextWidget cw);
140
141
142 /* actions */
143 static void MoveTo(Widget, XEvent*, String*, Cardinal*);
144 static void BtnMoveTo (Widget, XEvent*, String*, Cardinal*);
145 static void BtnMoveNew (Widget, XEvent*, String*, Cardinal*);
146 static void BtnRelease (Widget, XEvent*, String*, Cardinal*);
147
148 static void KeyPush (Widget, XEvent*, String*, Cardinal*);
149 static void NewLineCR (Widget, XEvent*, String*, Cardinal*);
150 static void InsertSpace (Widget, XEvent*, String*, Cardinal*);
151 static void MoveUp (Widget, XEvent*, String*, Cardinal*);
152 static void MoveDown (Widget, XEvent*, String*, Cardinal*);
153 static void MoveLeft (Widget, XEvent*, String*, Cardinal*);
154 static void MoveRight (Widget, XEvent*, String*, Cardinal*);
155 static void Enter (Widget, XEvent*, String*, Cardinal*);
156 static void Leave (Widget, XEvent*, String*, Cardinal*);
157 static void InFocus (Widget, XEvent*, String*, Cardinal*);
158 static void OutFocus (Widget, XEvent*, String*, Cardinal*);
159 static void DeleteLine (Widget w, XKeyPressedEvent *event, String *argv, Cardinal *argc);
160 static void OpenLineTop (Widget, XEvent*, String*, Cardinal*);
161 static void AddWordTop (Widget, XEvent*, String*, Cardinal*);
162 static void Dummy (Widget, XEvent*, String*, Cardinal*);
163
164 #ifndef NODPS
165 extern void ShowScale (Widget, XEvent*, String*, Cardinal*);
166 #endif
167 static void Refresh (Widget, XEvent*, String*, Cardinal*);
168 static void Cut (Widget, XEvent*, String*, Cardinal*);
169
170
171 /*
172 * Event handler?
173 */
174 static void ChangeFocus (Widget, XEvent*, String*, Cardinal*);
175
176
177 /* Public routines defined external in public header file. */
178 void XmMultiTextClearText (Widget w);
179 int XmMultiTextGetPosition (Widget w);
180 int XmMultiTextGetCursorPosition (Widget w);
181 void XmMultiTextQueryCursor (Widget w, int *lineNumber, int *y);
182 void XmMultiTextDeselectAll (Widget w);
183 void XmMultiTextSetTabStops (Widget w, int tabList[], int tabCount);
184 LinkInfoPtr XmMultiTextMakeLinkRecord (Widget w, LinkType linkType, LinkPosition linkPosition,
185 char *linkData);
186 void XmMultiTextAppendNewLine (Widget w, char *theWord, char *fontName, int indent);
187 unsigned short XmMultiTextAppendWord (Widget w, char *theWord, char *fontName,
188 char *colorName,
189 int indent, LinkInfoPtr linkInfo);
190 unsigned short XmMultiTextAppendWordTop (Widget w, char *theWord, char *fontName,
191 char *colorName, int indent, LinkInfoPtr linkInfo);
192 void XmMultiTextOpenLineTop (Widget w, int indent);
193 int XmMultiTextDeleteLineTop (Widget w, int linesToDelete);
194 void XmMultiTextDeleteLineBottom (Widget w);
195 int XmMultiTextLongestLineLength (Widget w);
196 unsigned short XmMultiTextAppendImage (Widget w, char *theWord, char *fontName,
197 char *colorName,
198 int indent, Pixmap image, unsigned int width,
199 unsigned int height, LinkInfoPtr linkInfo);
200 unsigned short XmMultiTextAppendWidget (Widget w, char *theWord, char *fontName,
201 char *colorName,
202 int indent, Widget newW);
203 unsigned short XmMultiTextAppendDPS (Widget w, char *theWord, char *fontName,
204 char *colorName,
205 int indent, char *dpsFileName, unsigned int width,
206 unsigned int height, LinkInfoPtr linkInfo);
207 Boolean XmMultiTextAppendChar (Widget w, char str);
208 Boolean XmMultiTextAppendLine (Widget w, char *str);
209
210 static XtResource resources[] =
211 {
212 {
213 XmNdpsCapable,
214 XmCDPSCapable,
215 XmRBoolean,
216 sizeof(Boolean),
217 offset(multiText.dpsCapable),
218 XmRImmediate,
219 (XtPointer)TRUE
220 },
221 {
222 XmNwordWrap,
223 XmCWordWrap,
224 XmRBoolean,
225 sizeof(Boolean),
226 offset(multiText.wordWrap),
227 XmRImmediate,
228 (XtPointer)TRUE
229 },
230 {
231 XmNmarginWidth,
232 XmCMarginWidth,
233 XmRInt,
234 sizeof(int),
235 offset(multiText.marginWidth),
236 XmRImmediate,
237 (XtPointer)10
238 },
239 {
240 XmNmarginHeight,
241 XmCMarginHeight,
242 XmRInt,
243 sizeof(int),
244 offset(multiText.marginHeight),
245 XmRImmediate,
246 (XtPointer)10
247 },
248 {
249 XmNwaitCursorCount,
250 XmCWaitCursorCount,
251 XmRInt,
252 sizeof(int),
253 offset(multiText.waitCursorCount),
254 XmRImmediate,
255 (XtPointer)1
256 },
257 {
258 XmNblinkRate,
259 XmCBlinkRate,
260 XmRInt,
261 sizeof(int),
262 offset(multiText.blinkRate),
263 XmRImmediate,
264 (XtPointer)250
265 },
266 {
267 XmNshowCursor,
268 XmCShowCursor,
269 XmRBoolean,
270 sizeof(Boolean),
271 offset(multiText.showCursor),
272 XmRImmediate,
273 (XtPointer)TRUE
274 },
275 {
276 XmNfocusSensitive,
277 XmCFocusSensitive,
278 XmRBoolean,
279 sizeof(Boolean),
280 offset(multiText.focusSensitive),
281 XmRImmediate,
282 (XtPointer)FALSE
283 },
284 {
285 XmNcursorColor,
286 XmCForeground,
287 XmRPixel,
288 sizeof(Pixel),
289 offset(multiText.cursorColor),
290 XmRString,
291 "yellow"
292 },
293 {
294 XmNscaleDPSpercent,
295 XmCScaleDPSpercent,
296 XmRInt,
297 sizeof(int),
298 offset(multiText.scaleDPSpercent),
299 XmRImmediate,
300 (XtPointer)100
301 },
302 {
303 XmNsmartSpacing,
304 XmCSmartSpacing, XmRBoolean,
305 sizeof(Boolean),
306 offset(multiText.smartSpacing),
307 XmRImmediate,
308 (XtPointer)TRUE
309 },
310 {
311 XmNsmoothScroll,
312 XmCSmoothScroll,
313 XmRBoolean,
314 sizeof(Boolean),
315 offset(multiText.smoothScroll),
316 XmRImmediate,
317 (XtPointer)FALSE
318 },
319 {
320 XmNexposeOnly,
321 XmCExposeOnly,
322 XmRBoolean,
323 sizeof(Boolean),
324 offset(multiText.exposeOnly),
325 XmRImmediate,
326 (XtPointer)FALSE
327 },
328 {
329 XmNlinkCallback, XmCCallback, XmRCallback,
330 sizeof(XtCallbackList), offset(multiText.linkCallback),
331 XmRImmediate, (XtPointer) NULL
332 },
333 {
334 XmNselectCallback,
335 XmCCallback,
336 XmRCallback,
337 sizeof(XtCallbackList),
338 offset(multiText.selectCallback),
339 XmRImmediate,
340 (XtPointer)NULL
341 }
342 };
343
344
345 /*
346 * Default Translation Table:
347 * This table maps event sequences into action names.
348 */
349 #ifndef NODPS
350 static char defaultTranslations[] =
351 "Ctrl Shift<Btn1Down>: ShowScale() \n\
352 <Btn1Motion>: BtnMoveTo() \n\
353 <Btn1Up>: BtnRelease() \n\
354 <Btn1Down>: MoveTo() \n\
355 <Key>BackSpace: Cut() \n\
356 <Key>Up: MoveUp() \n\
357 <Key>Down: MoveDown() \n\
358 <Key>Left: MoveLeft() \n\
359 <Key>Right: MoveRight() \n\
360 <Key>Delete: Dummy() \n\
361 <Key>Return: NewLineCR() \n\
362 <FocusIn>: InFocus() \n\
363 <FocusOut>: OutFocus() \n\
364 <Key>F1: DeleteLine(1) \n\
365 <Key>F2: DeleteLine(2) \n\
366 <Key>F3: OpenLineTop() \n\
367 <Key>F5: AddWordTop()";
368 #else
369 static char defaultTranslations[] =
370 "<Btn1Motion>: BtnMoveTo() \n\
371 <Btn1Up>: BtnRelease() \n\
372 <Btn1Down>: MoveTo() \n\
373 <Key>BackSpace: Cut() \n\
374 <Key>Up: MoveUp() \n\
375 <Key>Down: MoveDown() \n\
376 <Key>Left: MoveLeft() \n\
377 <Key>Right: MoveRight() \n\
378 <Key>Delete: Dummy() \n\
379 <Key>Return: NewLineCR() \n\
380 <FocusIn>: InFocus() \n\
381 <FocusOut>: OutFocus() \n\
382 <Key>F1: DeleteLine(1) \n\
383 <Key>F2: DeleteLine(2) \n\
384 <Key>F3: OpenLineTop() \n\
385 <Key>F5: AddWordTop()";
386 #endif
387
388
389 /*=======================================================*
390 | Actions Table |
391 | the action table maps string action names into actual |
392 | action functions. |
393 *=======================================================*/
394
395 static XtActionsRec actions[] = {
396 {"MoveTo", MoveTo },
397 {"BtnMoveTo", BtnMoveTo },
398 {"BtnMoveNew", BtnMoveNew },
399 {"BtnRelease", BtnRelease },
400 {"Refresh", Refresh },
401 {"Cut", Cut },
402 {"KeyPush", KeyPush },
403 {"NewLineCR", NewLineCR },
404 {"InsertSpace", InsertSpace },
405 #ifndef NODPS
406 {"ShowScale", ShowScale },
407 #endif
408 {"MoveUp", MoveUp },
409 {"MoveDown", MoveDown },
410 {"MoveLeft", MoveLeft },
411 {"MoveRight", MoveRight },
412 {"Enter", Enter },
413 {"Leave", Leave },
414 {"InFocus", InFocus },
415 {"OutFocus", OutFocus },
416 {"DeleteLine", (XtActionProc)DeleteLine },
417 {"Dummy", Dummy },
418 {"OpenLineTop", OpenLineTop },
419 {"AddWordTop", AddWordTop },
420 };
421
422
423
424 /* The MultiText class record definition */
425
426 XmMultiTextClassRec xmMultiTextClassRec =
427 {
428 /*
429 * Core class part:
430 */
431 {
432 (WidgetClass)&xmDrawingAreaClassRec,
433 /* superclass */
434 "XmMultiText", /* class_name */
435 sizeof(XmMultiTextRec), /* widget_size */
436 ClassInitialize, /* class_initialize */
437 NULL, /* class_part_initialize */
438 FALSE, /* class_inited */
439 Initialize, /* initialize */
440 NULL, /* initialize_hook */
441 XtInheritRealize, /* realize */
442 actions, /* actions */
443 XtNumber(actions), /* num_actions */
444 resources, /* resources */
445 XtNumber(resources), /* num_resources */
446 NULLQUARK, /* xrm_class */
447 TRUE, /* compress_motion */
448 TRUE, /* compress_exposure */
449 TRUE, /* compress_enterleave */
450 FALSE, /* visible_interest */
451 Destroy, /* destroy */
452 Resize, /* resize */
453 Redisplay, /* expose */
454 (XtSetValuesFunc)SetValues, /* set_values */
455 NULL, /* set_values_hook */
456 XtInheritSetValuesAlmost, /* set_values_almost */
457 NULL, /* get_values_hook */
458 NULL, /* accept_focus */
459 XtVersion, /* version */
460 NULL, /* callback private */
461 defaultTranslations, /* tm_table */
462 XtInheritQueryGeometry, /* query_geometry */
463 NULL, /* display_accelerator */
464 NULL /* extension */
465 },
466
467 /*
468 * Compositie class part:
469 */
470 {
471 XtInheritGeometryManager, /* Geometry Manager */
472 XtInheritChangeManaged, /* Change Managed */
473 XtInheritInsertChild, /* Insert Child */
474 XtInheritDeleteChild, /* Delete Child */
475 NULL /* extension */
476 },
477
478 /*
479 * Constraint class part:
480 */
481 {
482 NULL, /* resources */
483 0, /* num resources */
484 0, /* constraint record */
485 NULL, /* initialize */
486 NULL, /* destroy */
487 NULL, /* set values */
488 NULL /* extension */
489 },
490
491 /*
492 * Manager class part:
493 */
494 {
495 NULL, /* default_translations */
496 NULL, /* get_resources */
497 0, /* num_get_resources */
498 NULL, /* get_cont_resources */
499 0, /* num_get_cont_resources */
500 (XmParentProcessProc)NULL, /* parent_process */
501 NULL /* extension */
502 },
503
504 /*
505 * DrawingArea class part:
506 */
507 {
508 NULL /* dummy field */
509 },
510
511
512 {
513 NULL /* extension */
514 },
515 };
516
517
518 WidgetClass xmMultiTextWidgetClass = (WidgetClass)&xmMultiTextClassRec;
519
520
521
522 /*======================================================================*
523 | XmMultiText Widget Methods |
524 | -------------------------- |
525 | These are private to XmMultiText and can't be accessed by the |
526 | application programmer directly. |
527 *======================================================================*/
528
529 /*
530 * This routine creates an XFontStruct and a GC. Both of these are put
531 * into the instance record of the MultiTextWidget.
532 */
533 static void
GetTextGC(XmMultiTextWidget cw)534 GetTextGC(XmMultiTextWidget cw)
535 {
536 XtGCMask mask;
537 XGCValues values;
538 XFontStruct* font;
539
540 mask =
541 GCForeground |
542 GCBackground |
543 GCFont |
544 GCGraphicsExposures |
545 GCSubwindowMode;
546
547 font = XLoadQueryFont(XtDisplay(cw), "fixed");
548
549 values.font = font->fid;
550 values.foreground = cw->manager.foreground;
551 values.background = cw->core.background_pixel;
552 values.graphics_exposures = False;
553 values.subwindow_mode = ClipByChildren;
554
555 cw->multiText.textGC =
556 XCreateGC(XtDisplay(cw),
557 XRootWindowOfScreen(XtScreen(cw)),
558 mask,
559 &values);
560
561 values.foreground = cw->multiText.cursorColor;
562 cw->multiText.cursorGC =
563 XCreateGC(XtDisplay(cw),
564 XRootWindowOfScreen(XtScreen(cw)),
565 mask,
566 &values);
567
568 XFreeFont(XtDisplay(cw), font);
569 }
570
571
572
573 /*
574 * Only draws the lines that are effected by the refreshed area.
575 */
576 static void
DoRedrawText(XmMultiTextWidget cw,int y,int height)577 DoRedrawText(XmMultiTextWidget cw,
578 int y,
579 int height)
580 {
581 LineList lp = cw->multiText.firstLine;
582 int y1;
583 int y2;
584 int ey1;
585 int ey2;
586
587
588 if (cw->multiText.drawing)
589 return;
590
591 cw->multiText.drawing = TRUE;
592
593 ey1 = y;
594 ey2 = y + height;
595
596
597 while (lp != NULL)
598 {
599 y1 = lp->y;
600 y2 = lp->y + lp->bbox.ascent + lp->bbox.descent;
601
602 if (!(((ey1 < y1) && (ey2 < y1)) || ((y1 < ey1) && (y2 < ey1))))
603 {
604 DrawLine(cw, lp);
605 }
606
607 lp = lp->next;
608 }
609
610 cw->multiText.drawing = FALSE;
611 }
612
613
614
615 static void
StringToFloatConverter(XrmValue * args,Cardinal * nargs,XrmValue * fromVal,XrmValue * toVal)616 StringToFloatConverter(XrmValue* args,
617 Cardinal* nargs,
618 XrmValue* fromVal,
619 XrmValue* toVal)
620 {
621 static float result;
622
623 /*
624 * Make sure the number of args is correct.
625 */
626 if (*nargs != 0)
627 {
628 XtWarning("String to Float conversion needs no arguments");
629 }
630
631 /*
632 * Convert the string in the fromVal to a floating pt.
633 */
634 if (sscanf((char*)fromVal->addr, "%f", &result) == 1)
635 {
636 /*
637 * Make the toVal point to the result.
638 */
639 toVal->size = sizeof(float);
640 toVal->addr = (void *)&result;
641 }
642 }
643
644
645
646 static void
ClassInitialize(WidgetClass wc)647 ClassInitialize(WidgetClass wc)
648 {
649 #ifdef intelnt /* Exceed on WINDOWS NT has _XmRegisterConverters() */
650 _XmRegisterConverters();
651 #else
652 XmRegisterConverters();
653 #endif
654 XtAddConverter(XmRString, XmRFloat, StringToFloatConverter, NULL, 0);
655 }
656
657
658
659 /*
660 * The instance record of each widget must be initialized at run time.
661 * This method is invoked when a new widget is created.
662 * 'newWidget' is the real widget, 'request' is a copy. 'request' contains
663 * the original resource values. 'newWidget' may have been modified by other
664 * initialize routines of superclasses. All changes are made to 'newWidget'.
665 */
Initialize(Widget reqWidget,Widget newWidgetWidget,ArgList arg,Cardinal * argc)666 static void Initialize(Widget reqWidget,
667 Widget newWidgetWidget,
668 ArgList arg,
669 Cardinal* argc)
670 {
671 XmMultiTextWidget req = (XmMultiTextWidget)reqWidget;
672 XmMultiTextWidget newWidget = (XmMultiTextWidget)newWidgetWidget;
673 int i;
674 char buf[MAX_STR_LEN];
675
676
677 #ifndef NODPS
678
679 int firstEvent;
680 int firstError;
681 int majorOpCode;
682 if (!XQueryExtension(XtDisplay(req),
683 DPSNAME,
684 &majorOpCode,
685 &firstEvent,
686 &firstError))
687 {
688 WarningDialog(newWidget, MSG7);
689 }
690
691 #endif
692
693 newWidget->manager.traversal_on = True;
694
695 newWidget->multiText.firstLine = NULL;
696 newWidget->multiText.currentLine = NULL;
697 newWidget->multiText.lastLine = NULL;
698
699 newWidget->multiText.drawing = FALSE;
700 newWidget->multiText.selecting = FALSE;
701
702 newWidget->multiText.actualX = 0;
703 newWidget->multiText.cursorX = 0;
704 newWidget->multiText.cursorY = 0;
705 newWidget->multiText.oldX = 0;
706 newWidget->multiText.oldY = 0;
707 newWidget->multiText.cursorFg = None;
708 newWidget->multiText.cursorBg = None;
709 newWidget->multiText.blinkState = FALSE;
710 newWidget->multiText.cursorAvailable = TRUE;
711 newWidget->multiText.blinkTimeOutID = 0;
712
713 newWidget->multiText.wordSpacing = DEFAULT_WORD_SPACING;
714
715 newWidget->multiText.currentFontID = 0;
716 newWidget->multiText.currentColor = 0;
717 newWidget->multiText.lastColorName = NewString("");
718 newWidget->multiText.numFonts = 0;
719 newWidget->multiText.fontCache = NULL;
720 newWidget->multiText.showCursor = req->multiText.showCursor;
721 if (newWidget->multiText.showCursor)
722 {
723 TurnOnCursor(newWidget);
724 }
725 else
726 {
727 TurnOffCursor(newWidget);
728 }
729
730 for (i = 0; i < MAX_TAB_COUNT; i++) newWidget->multiText.tabs[i] = 0;
731 newWidget->multiText.tabCount = 0;
732
733 newWidget->multiText.waitCursorIndex = 1;
734
735 if ((newWidget->multiText.waitCursorCount < 1) ||
736 (newWidget->multiText.waitCursorCount > CURSOR_COUNT))
737 {
738 sprintf (buf, MSG1, CURSOR_COUNT);
739 XtWarning(buf);
740 newWidget->multiText.waitCursorCount = 1;
741 }
742
743 if (newWidget->multiText.scaleDPSpercent <= 0)
744 {
745 XtWarning(MSG2);
746 newWidget->multiText.scaleDPSpercent = 1;
747 }
748
749 GetTextGC(newWidget);
750
751 XtAddEventHandler((Widget)newWidget, FocusChangeMask, FALSE, (XtEventHandler)ChangeFocus, (Opaque)NULL);
752 XtAddEventHandler((Widget)newWidget, EnterWindowMask, FALSE, (XtEventHandler)Enter, (Opaque)NULL);
753 XtAddEventHandler((Widget)newWidget, LeaveWindowMask, FALSE, (XtEventHandler)Leave, (Opaque)NULL);
754 }
755
756
757
758 /*---------------------------================---------------------------*
759 | Redisplay method |
760 | This is where the widget gets redrawn when an Expose event occurs. |
761 | Note that this routine can't be called 'Expose' since X.h defined |
762 | 'Expose' as 12. |
763 | w - defines the widget instance to be redisplayed. |
764 | event - defines a pointer to an Expose event. |
765 | region - is the region to be redrawn. If compress_exposures is true |
766 | then the region is the sum of rectangles reported on all |
767 | expose events, and the event parameter contains the bounding|
768 | box of the region. Otherwise, region is NULL. |
769 *---------------------------================---------------------------*/
Redisplay(Widget w,XEvent * event,Region region)770 static void Redisplay (Widget w, XEvent *event, Region region)
771 {
772 XmMultiTextWidget cw = (XmMultiTextWidget)w;
773 XExposeEvent *expose = (XExposeEvent*)event;
774
775 if (XtIsRealized((Widget)cw))
776 {
777 DoRedrawText(cw, expose->y, expose->height);
778
779 if ((cw->multiText.cursorFg == None) && cw->multiText.cursorAvailable)
780 {
781 if (cw->multiText.blinkTimeOutID != 0)
782 {
783 XtRemoveTimeOut(cw->multiText.blinkTimeOutID);
784 cw->multiText.blinkTimeOutID = 0;
785 }
786 BlinkCursor(cw);
787 }
788 }
789 }
790
791
792 /*---------------------------================---------------------------*
793 | SetValues method |
794 | This method allows a widget to be notified when one of its resources |
795 | is set or changed. This can be called when a widget is initialized |
796 | by the resource manager, or when an application sets a resource with |
797 | XtSetValues(). The SetValues methods are chained and called from |
798 | superclass to subclass order. |
799 | current - the previous, unaltered state of the widget. |
800 | request - the values requested for the widget. |
801 | newWidget - the state of the widget after all superclass's SetValues |
802 | methods were called. All changes must be made to newWidget. |
803 | SetValues returns a Boolean value specifying whether or not the |
804 | widget needs to be redrawn. If TRUE, the Intrinsics causes an Expose |
805 | event to be generated for the entire window. |
806 | Note that SetValues must not perform any graphics operations on the |
807 | widget's window unless the widget is realized. |
808 *---------------------------================---------------------------*/
SetValues(XmMultiTextWidget current,XmMultiTextWidget request,XmMultiTextWidget newWidget)809 static Boolean SetValues (XmMultiTextWidget current, XmMultiTextWidget request,
810 XmMultiTextWidget newWidget)
811 {
812 Boolean redraw = FALSE;
813 char buf[MAX_STR_LEN];
814
815 if (current->multiText.waitCursorCount != newWidget->multiText.waitCursorCount)
816 if ((newWidget->multiText.waitCursorCount < 1) || (newWidget->multiText.waitCursorCount > CURSOR_COUNT))
817 {
818 sprintf(buf, MSG1, CURSOR_COUNT);
819 XtWarning(buf);
820 newWidget->multiText.waitCursorCount = 1;
821 }
822
823 /* there really isn't any way to screw-up the values of the MultiTextWidget, yet... */
824 /* however, it is possible to cause a redraw by changing the wordwrap value. */
825
826 if (current->multiText.wordWrap != newWidget->multiText.wordWrap)
827 redraw = TRUE;
828
829 /* check that the DPSscaling percentage is correct. */
830 if (newWidget->multiText.scaleDPSpercent <= 0)
831 {
832 XtWarning(MSG2);
833 newWidget->multiText.scaleDPSpercent = 1;
834 }
835
836 /* check if there's a change in the showCursor state. */
837 if (current->multiText.showCursor != newWidget->multiText.showCursor)
838 {
839 if (newWidget->multiText.showCursor)
840 TurnOnCursor(newWidget);
841 else
842 TurnOffCursor(newWidget);
843 }
844
845 /* should add checking for margins here... */
846
847 return redraw;
848 }
849
850
851 /*----------------------------==============----------------------------*
852 | Destroy method |
853 | The Destroy method is invoked when a widget is destroyed. Chaining |
854 | is in reverse order from other chaining; the widget's method is |
855 | called first followed by its superclass's Destroy method. |
856 *----------------------------==============----------------------------*/
Destroy(Widget w)857 static void Destroy (Widget w)
858 {
859 XmMultiTextWidget cw = (XmMultiTextWidget)w;
860 int i;
861
862 /* free the font cache. */
863 for (i=0; i<cw->multiText.numFonts; i++ )
864 {
865 XFreeFont(XtDisplay(cw), cw->multiText.fontCache[i].font);
866 #ifdef COMMENT
867 XtFree(cw->multiText.fontCache[i].font);
868 #endif
869 XtFree(cw->multiText.fontCache[i].name);
870 }
871 XtFree((char*)cw->multiText.fontCache);
872 XtFree(cw->multiText.lastColorName);
873
874 if (cw->multiText.textGC) XFreeGC(XtDisplay(cw), cw->multiText.textGC);
875 if (cw->multiText.cursorGC) XFreeGC(XtDisplay(cw), cw->multiText.cursorGC);
876 if (cw->multiText.blinkTimeOutID != 0) XtRemoveTimeOut(cw->multiText.blinkTimeOutID);
877 }
878
879
880 /*-----------------------------=============----------------------------*
881 | Resize method |
882 | The Resize method is invoked when the widget's window is reconfigured|
883 | in any way. Since the X server generates an Expose event if the |
884 | contents of a window are corrupted, the Resize method only updates |
885 | the data needed to allow the Redisplay method to redraw the widget |
886 | correctly. |
887 *-----------------------------=============----------------------------*/
Resize(Widget w)888 static void Resize (Widget w)
889 {
890 XmMultiTextWidget cw = (XmMultiTextWidget)w;
891 if (cw->multiText.smoothScroll)
892 {
893 XRectangle recs[1];
894
895 recs[0].x = cw->multiText.marginWidth;
896 recs[0].y = cw->multiText.marginHeight;
897 recs[0].width = cw->core.width;
898 recs[0].height = cw->core.height;
899
900 XSetClipRectangles(XtDisplay(cw), cw->multiText.textGC, 0, 0, recs, 1, Unsorted);
901 }
902 }
903
904
905
906
907
908 /*======================================================================*
909 | XmMultiText Widget Action Procedures |
910 | ------------------------------------ |
911 | The(se) routine(s) are defined at the beginning of the file in the |
912 | list of actions. |
913 *======================================================================*/
914
915
916 /*----------------------------------------------------------------------*
917 | PtInWord |
918 *----------------------------------------------------------------------*/
PtInWord(int x,int y,WordList wp,LineList lp)919 static Boolean PtInWord (int x, int y, WordList wp, LineList lp)
920 {
921 if ((x >= lp->x + wp->x) && (x < lp->x + wp->x + wp->bbox.width))
922 return TRUE;
923 else
924
925 /* now for a bit more complex - if this is a link then the bounding box */
926 /* is different depending if there is a link behind or after this word. */
927 /* in this case, we must account for the spacing between words as well */
928 /* as the actual word itself. - yuk! */
929 if (wp->linkInfo != NULL)
930 {
931 int x1 = lp->x + wp->x;
932 int x2 = lp->x + wp->x + wp->bbox.width;
933
934 if ((wp->prev != NULL) && (wp->prev->linkInfo != NULL))
935 x1 -= wp->spacing;
936
937 if ((wp->next != NULL) && (wp->next->linkInfo != NULL))
938 x2 += wp->spacing;
939
940 /* now let's see if it's in the new larger bounding box. */
941 if ((x >= x1) && (x < x2))
942 return TRUE;
943 else
944 return FALSE;
945 }
946
947 else
948 return FALSE;
949 }
950
951
952
953 /*----------------------------------------------------------------------*
954 | HighlightWord |
955 *----------------------------------------------------------------------*/
HighlightWord(XmMultiTextWidget cw,LineList lp,WordList wp,int x2,int y2)956 static void HighlightWord (XmMultiTextWidget cw, LineList lp, WordList wp, int x2, int y2)
957 {
958 int x1 = cw->multiText.startX;
959 int y1 = cw->multiText.startY;
960 int wpx1 = wp->x + lp->x;
961 int wpy1 = lp->y;
962 int wpx2 = wp->x + lp->x + wp->bbox.width;
963 int wpy2 = lp->y + lp->bbox.ascent + lp->bbox.descent;
964 Boolean startAfter, startBefore, endAfter, endBefore, startInside, endInside;
965
966
967 startAfter = (((x1 > wpx2) && (y1 >= wpy1)) || (y1 > wpy2));
968 startBefore = (((x1 < wpx1) && (y1 <= wpy2)) || (y1 < wpy1));
969 endAfter = (((x2 > wpx2) && (y2 > wpy1)) || (y2 > wpy2));
970 endBefore = (((x2 < wpx1) && (y2 < wpy2)) || (y2 <= wpy1));
971 startInside = ((wpx1 < x1) && (x1 <= wpx2) && (wpy1 < y1) && (y1 <= wpy2));
972 endInside = ((wpx1 < x2) && (x2 <= wpx2) && (wpy1 < y2) && (y2 <= wpy2));
973
974 if ((startBefore && endAfter) || (startAfter && endBefore) || startInside || endInside)
975 {
976 if (!wp->selected)
977 {
978 DrawWord(cw, wp, TRUE);
979 wp->selected = TRUE;
980 }
981 }
982 else
983 if (wp->selected)
984 {
985 DrawWord(cw, wp, FALSE);
986 wp->selected = FALSE;
987 }
988 }
989
990
991 /*----------------------------------------------------------------------*
992 | BtnMoveTo |
993 | This gets call when the mouse button is pressed while the mouse is |
994 | moved. |
995 *----------------------------------------------------------------------*/
BtnMoveTo(Widget w,XEvent * event,String * params,Cardinal * numParams)996 static void BtnMoveTo (Widget w, XEvent* event, String* params, Cardinal* numParams)
997 {
998 XmMultiTextWidget cw = (XmMultiTextWidget) w;
999 LineList lp;
1000 WordList wp;
1001
1002
1003 if (cw->multiText.selecting) /* selecting turns on when button is pressed. Off on release. */
1004 {
1005 /* go through each word and highlight if in region and unhighlight if not. */
1006 for (lp = cw->multiText.firstLine; lp != NULL; lp = lp->next)
1007 for (wp = lp->firstWord; wp != NULL; wp = wp->next)
1008 HighlightWord(cw, lp, wp, event->xbutton.x, event->xbutton.y);
1009 }
1010 }
1011
1012
1013
1014 /*----------------------------------------------------------------------*
1015 | BtnMoveNew |
1016 | This gets call when the mouse button is pressed while the mouse is |
1017 | moved. |
1018 | This routine highlights the lines in the region - first find the line|
1019 | that the pointer is currently in, then find what line the selection |
1020 | started in. Highlight all lines between these line but not including|
1021 | these. Finally highlight the region corresponding to what should be |
1022 | selected for each of the lines containing the start or end points of |
1023 | the selection region. |
1024 *----------------------------------------------------------------------*/
BtnMoveNew(Widget w,XEvent * event,String * params,Cardinal * numParams)1025 static void BtnMoveNew (Widget w, XEvent* event, String* params, Cardinal* numParams)
1026 {
1027 XmMultiTextWidget cw = (XmMultiTextWidget) w;
1028 LineList lp, lp1, lp2;
1029 int y1, y2;
1030
1031 /* find the line containing the starting point (the lowest of the y positions). */
1032 y1 = MIN(cw->multiText.startY, event->xbutton.y);
1033 y2 = MAX(cw->multiText.startY, event->xbutton.y);
1034
1035 for (lp1 = cw->multiText.firstLine;
1036 (lp1 != NULL) && !((lp1->y <= y1) && (y1 <= lp1->y + lp1->bbox.ascent + lp1->bbox.descent));
1037 lp1 = lp1->next)
1038 /* move lp1 to start of selection region. */ ;
1039
1040
1041 /* now lp1 points to the line where the selection region is starting in. */
1042 /* find the line where the selection ends. */
1043
1044 for (lp2 = lp1;
1045 (lp2 != NULL) && !((lp2->y <= y2) && (y2 <= lp2->y + lp2->bbox.ascent + lp2->bbox.descent));
1046 lp2 = lp2->next)
1047 /* lp2 points to where the selection ends. */;
1048
1049
1050 /* highlight each line between lp1 and lp2. */
1051 for (lp = lp1; lp != lp2; lp = lp->next)
1052 /* highlight each line... TBA */ ;
1053 }
1054
1055
1056
1057 /*----------------------------------------------------------------------*
1058 | StuffOntoClipboard |
1059 *----------------------------------------------------------------------*/
ToClipboard(XmMultiTextWidget cw,char * data)1060 void ToClipboard (XmMultiTextWidget cw, char *data)
1061 {
1062 long clipID = 0;
1063 int status;
1064 XmString clipLabel;
1065 char buf[32];
1066 static int cnt;
1067
1068
1069 sprintf(buf, "%s-%d", data, ++cnt);
1070 clipLabel = XmStringCreate(data, XmSTRING_DEFAULT_CHARSET);
1071
1072 do
1073 status = XmClipboardStartCopy(XtDisplay(cw), XtWindow(cw),
1074 clipLabel, CurrentTime, NULL, NULL, &clipID);
1075 while (status == ClipboardLocked);
1076 XmStringFree(clipLabel);
1077
1078 do
1079 status = XmClipboardCopy(XtDisplay(cw), XtWindow(cw),
1080 clipID, "STRING", buf, (long)strlen(buf)+1, cnt, NULL);
1081 while (status == ClipboardLocked);
1082
1083 do
1084 status = XmClipboardEndCopy(XtDisplay(cw), XtWindow(cw), clipID);
1085 while (status == ClipboardLocked);
1086 }
1087
1088
1089
1090 /*----------------------------------------------------------------------*
1091 | BtnRelease |
1092 *----------------------------------------------------------------------*/
BtnRelease(Widget w,XEvent * event,String * params,Cardinal * numParams)1093 static void BtnRelease (Widget w, XEvent* event, String* params, Cardinal* numParams)
1094 {
1095 XmMultiTextWidget cw = (XmMultiTextWidget) w;
1096 static char mondoBuffer[MAX_BUFF_SIZE], *space = " ", *cr = "\n";
1097 LineList lp;
1098 WordList wp;
1099 XmMultiTextSelectCallbackStruct callValue;
1100 Boolean foundSomething, textIsSelected = FALSE;
1101
1102
1103 if (cw->multiText.selecting)
1104 {
1105 cw->multiText.selecting = FALSE;
1106
1107 strcpy(mondoBuffer,"");
1108
1109 /* grab the selected text. */
1110 foundSomething = FALSE;
1111 for (lp = cw->multiText.firstLine; lp != NULL; lp = lp->next)
1112 {
1113 foundSomething = FALSE;
1114 for (wp = lp->firstWord; wp != NULL; wp = wp->next)
1115 if (wp->selected)
1116 {
1117 foundSomething = textIsSelected = TRUE;
1118 strcat(mondoBuffer, wp->chars);
1119 if (cw->multiText.smartSpacing) strcat(mondoBuffer, space);
1120 }
1121 else
1122 foundSomething = FALSE;
1123 if (foundSomething) strcat(mondoBuffer, cr);
1124 }
1125
1126 /* Check if the selection callback exists. */
1127 callValue.reason = XmCR_SELECT;
1128 callValue.event = event;
1129 callValue.data = NewString(mondoBuffer);
1130
1131 if (XtHasCallbacks((Widget)cw, XmNselectCallback) == XtCallbackHasSome)
1132 {
1133 XFlush(XtDisplay(w));
1134 XtCallCallbacks((Widget)cw, XmNselectCallback, &callValue);
1135 }
1136 XtFree(callValue.data);
1137 }
1138
1139 /*
1140 if (textIsSelected) ToClipboard(cw, mondoBuffer);
1141 */
1142
1143 cw->multiText.textIsSelected = textIsSelected;
1144 }
1145
1146
1147
1148
1149
1150 /*----------------------------------------------------------------------*
1151 | Refresh |
1152 | causes a complete redraw of the text widget. |
1153 *----------------------------------------------------------------------*/
Refresh(Widget w,XEvent * event,String * params,Cardinal * numParams)1154 static void Refresh (Widget w, XEvent* event, String* params, Cardinal* numParams)
1155 {
1156 XmMultiTextWidget cw = (XmMultiTextWidget) w;
1157 LineList lp = cw->multiText.firstLine;
1158
1159
1160 XmMultiTextClearText((Widget)cw);
1161
1162 while (lp != NULL)
1163 {
1164 DrawLine(cw, lp);
1165 lp = lp->next;
1166 }
1167 }
1168
1169
1170
1171 /*----------------------------------------------------------------------*
1172 | DeleteLineFromWidget |
1173 *----------------------------------------------------------------------*/
DeleteLineFromWidget(XmMultiTextWidget cw,LineList * lpp)1174 void DeleteLineFromWidget (XmMultiTextWidget cw, LineList *lpp)
1175 {
1176 LineList temp;
1177
1178
1179 if (*lpp == NULL) return;
1180
1181 if ((*lpp)->prev == NULL)
1182 cw->multiText.firstLine = NULL;
1183 else
1184 (*lpp)->prev->next = (*lpp)->next;
1185
1186 if ((*lpp)->next == NULL)
1187 cw->multiText.lastLine = (*lpp)->prev;
1188 else
1189 (*lpp)->next->prev = (*lpp)->prev;
1190
1191
1192 if ((*lpp)->prev == NULL)
1193 temp = (*lpp)->next;
1194 else
1195 temp = (*lpp)->prev;
1196
1197 FreeLineRecord(cw, *lpp);
1198
1199 *lpp = temp;
1200 }
1201
1202
1203
1204
1205 /*----------------------------------------------------------------------*
1206 | LineTooLong |
1207 | A line is too long if it has more than one word AND doesn't fit into |
1208 | the widget AND the last word is allowed to be wrapped. |
1209 *----------------------------------------------------------------------*/
LineTooLong(XmMultiTextWidget cw,LineList lp)1210 Boolean LineTooLong (XmMultiTextWidget cw, LineList lp)
1211 {
1212 /* if the line is null or empty, return false. */
1213 if ((lp == NULL) || (lp->lastWord == NULL))
1214 return (FALSE);
1215
1216 /* if the line is too long and the last word is 'wrappable', then return true. */
1217 if (((lp->x + lp->bbox.width) > (cw->core.width - cw->multiText.marginWidth)) &&
1218 (lp->lastWord->wordWrapping && cw->multiText.wordWrap))
1219 return (TRUE);
1220 else
1221 return (FALSE);
1222 }
1223
1224
1225 /*----------------------------------------------------------------------*
1226 | WrapLastWordToNextLine |
1227 | this routine assumes that the last word is allowed to be wrapped. In |
1228 | other words - it just performs the wrapping and does what it's told. |
1229 *----------------------------------------------------------------------*/
WrapLastWordToNextLine(XmMultiTextWidget cw,LineList lp)1230 void WrapLastWordToNextLine (XmMultiTextWidget cw, LineList lp)
1231 {
1232 int dx;
1233 WordList wp;
1234
1235
1236 /* let's do some simple checking - these errors should never occur... */
1237 if ((lp == NULL) || (lp->lastWord == NULL) || (lp->lastWord == lp->firstWord))
1238 return;
1239
1240 wp = lp->lastWord;
1241 lp->lastWord = wp->prev;
1242 dx = lp->bbox.width - lp->lastWord->x + lp->lastWord->bbox.width;
1243 lp->bbox.width -= dx;
1244 lp->remaining += dx;
1245 lp->wordCount --;
1246
1247
1248 /* if this is the last line, then open a new line after this one. */
1249
1250 /*********
1251 if (lp->next == NULL) OpenNewLine();
1252 *********/
1253
1254 wp->y = lp->next->bbox.ascent - wp->bbox.ascent;
1255 wp->tabCount = 0;
1256 wp->spaceCount = 0;
1257 wp->linePtr = lp->next;
1258
1259 /* now shift horizontally all words in the line. */
1260 /*****
1261 if the a word's tabcount is < next word's tabcount, then the next char is a tab.
1262 do the same for the number of spaces...
1263 *****/
1264
1265 /* now adjust the ascent or descent of the line if necessary */
1266
1267 }
1268
1269
1270
1271 /*----------------------------------------------------------------------*
1272 | Reflow |
1273 | reflows all lines after the lineIndex so each line fits correctly |
1274 | into the newly sized window. |
1275 *----------------------------------------------------------------------*/
Reflow(XmMultiTextWidget cw,LineList reflp)1276 void Reflow (XmMultiTextWidget cw, LineList reflp)
1277 {
1278 LineList lp;
1279
1280
1281 /* start reflowing after the current line unless lp is set to NULL. */
1282 /* in that case, reflow all lines. */
1283 if (reflp == NULL)
1284 lp = cw->multiText.firstLine;
1285 else
1286 lp = reflp->next;
1287
1288 for (; lp != NULL; lp = lp->next)
1289 {
1290 while (LineTooLong(cw, lp))
1291 WrapLastWordToNextLine(cw, lp);
1292 }
1293 }
1294
1295
1296
1297 /*----------------------------------------------------------------------*
1298 | ShiftFollowingLines2 |
1299 *----------------------------------------------------------------------*/
ShiftFollowingLines2(XmMultiTextWidget cw,LineList indexLine)1300 void ShiftFollowingLines2 (XmMultiTextWidget cw, LineList indexLine)
1301 {
1302 LineList lp, startLine;
1303
1304 if (indexLine == NULL)
1305 startLine = cw->multiText.firstLine;
1306 else
1307 startLine = indexLine;
1308 if (startLine == NULL) return;
1309
1310 for (lp = startLine; (lp != NULL) && (lp->next != NULL); lp = lp->next)
1311 {
1312 lp->next->y = lp->y + lp->bbox.ascent + lp->bbox.descent + lp->lineSpacing;
1313 }
1314 }
1315
1316
1317 /*----------------------------------------------------------------------*
1318 | DeleteWordFromLine |
1319 *----------------------------------------------------------------------*/
DeleteWordFromLine(XmMultiTextWidget cw,WordList wp)1320 void DeleteWordFromLine (XmMultiTextWidget cw, WordList wp)
1321 {
1322 if (wp == NULL) return;
1323
1324
1325 if (wp->prev == NULL)
1326 wp->linePtr->firstWord = wp->next;
1327 else
1328 wp->prev->next = wp->next;
1329
1330 if (wp->next == NULL)
1331 wp->linePtr->lastWord = wp->prev;
1332 else
1333 wp->next->prev = wp->prev;
1334
1335 wp->linePtr->wordCount --;
1336 wp->linePtr->remaining += wp->bbox.width;
1337
1338 FreeWordRecord(cw, wp);
1339 }
1340
1341
1342
1343 /*----------------------------------------------------------------------*
1344 | Cut |
1345 *----------------------------------------------------------------------*/
1346 static void
Cut(Widget w,XEvent * event,String * params,Cardinal * numParams)1347 Cut (Widget w, XEvent* event, String* params, Cardinal* numParams)
1348 {
1349 XmMultiTextWidget cw = (XmMultiTextWidget) w;
1350 LineList lp;
1351 WordList wp;
1352
1353
1354 /* go through all text and find the selected text. */
1355 /* this should probably not keep checking after the first chunk of selected text. */
1356 /* however, future versions may allow multiple selections. */
1357
1358 for (lp = cw->multiText.firstLine; lp != NULL; lp = lp->next)
1359 for (wp = lp->firstWord; wp != NULL; wp = wp->next)
1360 if (wp->selected)
1361 DeleteWordFromLine(cw, wp);
1362
1363 Reflow(cw, NULL);
1364 }
1365
1366
1367
1368
1369 /*----------------------------------------------------------------------*
1370 | GetWholeLink |
1371 *----------------------------------------------------------------------*/
GetWholeLink(Widget w,WordList wp)1372 static char *GetWholeLink (Widget w, WordList wp)
1373 {
1374 WordList wpStart, wpTemp;
1375 char *buf = "\0";
1376 int len = 0;;
1377
1378 if (!wp->linkInfo) return(buf);
1379
1380 wpStart = wp;
1381 while ((wpStart->prev != NULL) && (SameLinks(wpStart->prev, wp)))
1382 wpStart = wpStart->prev;
1383
1384
1385 /* scan forward in the line till the end of the line or the end of the line. */
1386 /* buf first find out how long this string is going to be. */
1387
1388 wpTemp = wpStart;
1389 while ((wpTemp != NULL) && (SameLinks(wpTemp, wp)))
1390 {
1391 len += strlen(wpTemp->chars) + 1;
1392 wpTemp = wpTemp->next;
1393 }
1394 buf = (char *) XtMalloc(sizeof(char) * len + 1);
1395 strcpy(buf, "");
1396
1397 while ((wpStart != NULL) && (SameLinks(wpStart, wp)))
1398 {
1399 if (strlen(buf))
1400 sprintf(buf,"%s %s", buf, wpStart->chars);
1401 else
1402 strcpy(buf, wpStart->chars);
1403 wpStart = wpStart->next;
1404 }
1405
1406 return(buf);
1407 }
1408
1409
1410
1411 /*----------------------------------------------------------------------*
1412 | DeselectAll |
1413 *----------------------------------------------------------------------*/
DeselectAll(XmMultiTextWidget cw)1414 static void DeselectAll (XmMultiTextWidget cw)
1415 {
1416 LineList lp;
1417 WordList wp;
1418
1419 for (lp = cw->multiText.firstLine; lp != NULL; lp = lp->next)
1420 for (wp = lp->firstWord; wp != NULL; wp = wp->next)
1421 if (wp->selected)
1422 {
1423 DrawWord(cw, wp, !wp->selected);
1424 wp->selected = FALSE;
1425 }
1426
1427 cw->multiText.textIsSelected = FALSE;
1428 }
1429
1430
1431
1432 /*-----------------------=======================------------------------*
1433 | MoveTo action procedure |
1434 | This routine is invoked (default case) on a Btn1Down event occurs in |
1435 | the widget's window. It then positions the cursor at the new |
1436 | location. Well, actually it does all sorts of things - none of which|
1437 | is permanent, so I really won't go into a full description here, yet.|
1438 *-----------------------=======================------------------------*/
MoveTo(Widget w,XEvent * event,String * params,Cardinal * numParams)1439 static void MoveTo (Widget w,
1440 XEvent* event,
1441 String* params,
1442 Cardinal* numParams)
1443 {
1444 XmMultiTextWidget cw = (XmMultiTextWidget) w;
1445 LineList lp = cw->multiText.firstLine;
1446 LineList clp;
1447 int actualX;
1448 WordList wp;
1449 Boolean foundLine = FALSE;
1450 Boolean foundWord = FALSE;
1451 XmMultiTextLinkCallbackStruct callValue;
1452
1453
1454 /* First scan all the lines until correct line is found. */
1455 while ((lp != NULL) && !foundLine)
1456 {
1457 foundLine = PtInLine(event->xbutton.x, event->xbutton.y, lp);
1458 if (!foundLine) lp = lp->next;
1459 }
1460
1461
1462 /* Now scan the words to find the word in this line */
1463 if (foundLine)
1464 {
1465 wp = lp->firstWord;
1466
1467 while ((wp != NULL) && !foundWord)
1468 {
1469 foundWord = PtInWord(event->xbutton.x, event->xbutton.y, wp, lp);
1470 if (!foundWord) wp = wp->next;
1471 }
1472
1473 /* Check if this is a Link. If so, setup the callback. */
1474 if ((foundWord) && (wp->linkInfo != NULL) && (wp->linkInfo->linkType != NOOP))
1475 {
1476 callValue.reason = XmCR_LINK;
1477 callValue.event = event;
1478 callValue.type = wp->linkInfo->linkType;
1479 callValue.posn = NewString(wp->linkInfo->linkPosn);
1480 callValue.data = NewString(wp->linkInfo->linkData);
1481 callValue.word = GetWholeLink(w, wp);
1482
1483 if (XtHasCallbacks((Widget)cw, XmNlinkCallback) == XtCallbackHasSome)
1484 {
1485 XFlush(XtDisplay(w));
1486 XtCallCallbacks((Widget)cw, XmNlinkCallback, &callValue);
1487 XtFree(callValue.posn); XtFree(callValue.data); XtFree(callValue.word);
1488 return;
1489 }
1490 XtFree(callValue.posn); XtFree(callValue.data); XtFree(callValue.word);
1491 }
1492 else
1493 DeselectAll((XmMultiTextWidget)cw);
1494
1495 PositionCursor(cw, event->xbutton.x, event->xbutton.y, &clp, &actualX);
1496 UpdateCursor(cw, clp, event->xbutton.x, actualX, clp->y + clp->bbox.ascent);
1497 }
1498 else
1499 DeselectAll((XmMultiTextWidget)cw);
1500
1501
1502 /* now check for selections... */
1503 cw->multiText.selecting = TRUE;
1504
1505 /* set the widgets selection points. */
1506 cw->multiText.startX = event->xbutton.x;
1507 cw->multiText.startY = event->xbutton.y;
1508
1509 /* that's all the setup that's necessary - actions take care of the rest. */
1510 }
1511
1512
1513
1514
1515 /*----------------------------------------------------------------------*
1516 | ChangeFocus |
1517 *----------------------------------------------------------------------*/
ChangeFocus(Widget w,XEvent * event,String * params,Cardinal * numParams)1518 static void ChangeFocus(Widget w, XEvent* event, String* params, Cardinal* numParams)
1519 {
1520
1521 }
1522
1523
1524
1525 /*----------------------------------------------------------------------*
1526 | Enter |
1527 *----------------------------------------------------------------------*/
Enter(Widget w,XEvent * event,String * params,Cardinal * numParams)1528 static void Enter (Widget w, XEvent* event, String* params, Cardinal* numParams)
1529 {
1530
1531 }
1532
1533
1534
1535 /*----------------------------------------------------------------------*
1536 | Leave |
1537 *----------------------------------------------------------------------*/
Leave(Widget w,XEvent * event,String * params,Cardinal * numParams)1538 static void Leave (Widget w, XEvent* event, String* params, Cardinal* numParams)
1539 {
1540
1541 }
1542
1543
1544
1545 /*----------------------------------------------------------------------*
1546 | InFocus |
1547 *----------------------------------------------------------------------*/
InFocus(Widget w,XEvent * event,String * params,Cardinal * numParams)1548 static void InFocus (Widget w, XEvent* event, String* params, Cardinal* numParams)
1549 {
1550
1551 }
1552
1553
1554
1555 /*----------------------------------------------------------------------*
1556 | OutFocus |
1557 *----------------------------------------------------------------------*/
OutFocus(Widget w,XEvent * event,String * params,Cardinal * numParams)1558 static void OutFocus (Widget w, XEvent* event, String* params, Cardinal* numParams)
1559 {
1560
1561 }
1562
1563
1564
1565
1566 /*----------------------------------------------------------------------*
1567 | DeleteLine |
1568 *----------------------------------------------------------------------*/
DeleteLine(Widget w,XKeyPressedEvent * event,String * argv,Cardinal * argc)1569 static void DeleteLine (Widget w, XKeyPressedEvent *event, String *argv, Cardinal *argc)
1570 {
1571 /* argv hold a single argument telling if the line should be deleted */
1572 /* from the TOP or the BOTTOM. */
1573
1574 switch (atoi(*argv))
1575 {
1576 case TOP:
1577 XmMultiTextDeleteLineTop(w, 1);
1578 break;
1579
1580 case BOTTOM:
1581 XmMultiTextDeleteLineBottom(w);
1582 break;
1583
1584 default: ;
1585 }
1586 }
1587
1588
1589
1590
1591 /*----------------------------------------------------------------------*
1592 | OpenLineTop |
1593 *----------------------------------------------------------------------*/
OpenLineTop(Widget w,XEvent * event,String * params,Cardinal * numParams)1594 static void OpenLineTop (Widget w, XEvent* event, String* params, Cardinal* numParams)
1595 {
1596 XmMultiTextOpenLineTop (w, 0);
1597 }
1598
1599
1600
1601
1602 /*----------------------------------------------------------------------*
1603 | AddWordTop |
1604 *----------------------------------------------------------------------*/
AddWordTop(Widget w,XEvent * event,String * params,Cardinal * numParams)1605 static void AddWordTop (Widget w, XEvent* event, String* params, Cardinal* numParams)
1606 {
1607 static int i=1;
1608 char *str="testing ";
1609
1610 sprintf(str, "testing%d", i++);
1611 XmMultiTextAppendWordTop (w, str, "hodges-24", "red", 0, NULL);
1612 }
1613
1614
1615
1616
1617 /*======================================================================*
1618 | Xmmultitext Widget Public Procedures |
1619 | ------------------------------------ |
1620 | The(se) routine(s) are defined at the beginning of the file in the |
1621 | list of actions. |
1622 *======================================================================*/
1623
1624
1625 /*-----------------------====================---------------------------*
1626 | XmMultiTextClearText |
1627 *-----------------------====================---------------------------*/
XmMultiTextClearText(Widget w)1628 void XmMultiTextClearText (Widget w)
1629 {
1630 XmMultiTextWidget cw = (XmMultiTextWidget) w;
1631 LineList lp, lpNext;
1632
1633 lp = cw->multiText.firstLine;
1634
1635 while (lp != NULL) {
1636 lpNext = lp->next;
1637 FreeLineRecord(cw, lp);
1638 XtFree((char*)lp);
1639 lp = lpNext;
1640 }
1641
1642 cw->multiText.firstLine = NULL;
1643 cw->multiText.currentLine = NULL;
1644 cw->multiText.lastLine = NULL;
1645
1646 /* clean up all the cursor stuff... */
1647 if (cw->multiText.cursorFg != None)
1648 {
1649 XFreePixmap(XtDisplay(cw), cw->multiText.cursorFg);
1650 XFreePixmap(XtDisplay(cw), cw->multiText.cursorBg);
1651 XFreePixmap(XtDisplay(cw), cw->multiText.cursorMask);
1652 }
1653 if (cw->multiText.blinkTimeOutID != 0) XtRemoveTimeOut(cw->multiText.blinkTimeOutID);
1654 cw->multiText.blinkTimeOutID = 0;
1655 cw->multiText.selecting = FALSE;
1656 cw->multiText.textIsSelected = FALSE;
1657 cw->multiText.cursorFg = None;
1658 cw->multiText.cursorBg = None;
1659 cw->multiText.cursorMask = None;
1660
1661 XClearArea(XtDisplay(cw), XtWindow(cw), 0, 0, 0, 0, TRUE);
1662
1663 XSync(XtDisplay(cw), False);
1664 ChangeHeight((XmMultiTextWidget)w, XtParent(w)->core.height);
1665 }
1666
1667
1668
1669 /*----------------------======================--------------------------*
1670 | XmMultiTextGetPosition |
1671 | Returns the last position of the data already entered. This tells |
1672 | where new data will be appended. |
1673 *----------------------======================--------------------------*/
XmMultiTextGetPosition(Widget w)1674 int XmMultiTextGetPosition (Widget w)
1675 {
1676 XmMultiTextWidget cw = (XmMultiTextWidget) w;
1677
1678
1679 if (cw->multiText.lastLine == NULL)
1680 return(0);
1681 else
1682 return(cw->multiText.lastLine->y);
1683 }
1684
1685
1686
1687 /*-------------------============================-----------------------*
1688 | XmMultiTextGetCursorPosition |
1689 | Returns the last position of the data already entered. This tells |
1690 | where new data will be appended. |
1691 *-------------------============================-----------------------*/
XmMultiTextGetCursorPosition(Widget w)1692 int XmMultiTextGetCursorPosition (Widget w)
1693 {
1694 XmMultiTextWidget cw = (XmMultiTextWidget) w;
1695
1696 return(cw->multiText.cursorY);
1697 }
1698
1699
1700
1701 /*-----------------------======================-------------------------*
1702 | XmMultiTextQueryCursor |
1703 *-----------------------======================-------------------------*/
XmMultiTextQueryCursor(Widget w,int * lineNumber,int * y)1704 void XmMultiTextQueryCursor (Widget w, int *lineNumber, int *y)
1705 {
1706 XmMultiTextWidget cw = (XmMultiTextWidget) w;
1707 LineList lp;
1708
1709 *lineNumber = 0;
1710
1711 for (lp = cw->multiText.firstLine; lp != NULL; lp = lp->next)
1712 {
1713 if (lp->y + lp->bbox.ascent + lp->bbox.descent > cw->multiText.cursorY)
1714 break;
1715 *lineNumber = *lineNumber + 1;
1716 }
1717
1718 if (lp == NULL)
1719 if (cw->multiText.lastLine != NULL)
1720 *y = cw->multiText.lastLine->y;
1721 else
1722 {
1723 *y = 0;
1724 *lineNumber = 0;
1725 }
1726 else
1727 *y = lp->y;
1728 }
1729
1730
1731
1732 /*-----------------------======================-------------------------*
1733 | XmMultiTextDeselectAll |
1734 *-----------------------======================-------------------------*/
XmMultiTextDeselectAll(Widget w)1735 void XmMultiTextDeselectAll (Widget w)
1736 {
1737 XmMultiTextWidget cw = (XmMultiTextWidget) w;
1738
1739 if (XtIsRealized((Widget)cw))
1740 DeselectAll(cw);
1741 }
1742
1743
1744
1745 /*----------------------======================--------------------------*
1746 | XmMultiTextSetTabStops |
1747 *----------------------======================--------------------------*/
XmMultiTextSetTabStops(Widget w,int tabList[],int tabCount)1748 void XmMultiTextSetTabStops (Widget w, int tabList[], int tabCount)
1749 {
1750 XmMultiTextWidget cw = (XmMultiTextWidget) w;
1751 int i;
1752
1753 /* enter the tabs into the widget. */
1754 for (i=0; i<tabCount; i++)
1755 cw->multiText.tabs[i] = tabList[i];
1756
1757 cw->multiText.tabCount = tabCount;
1758 }
1759
1760
1761
1762
1763 /*---------------------=========================------------------------*
1764 | XmMultiTextMakeLinkRecord |
1765 *---------------------=========================------------------------*/
XmMultiTextMakeLinkRecord(Widget w,LinkType linkType,char * linkPosn,char * linkData)1766 LinkInfoPtr XmMultiTextMakeLinkRecord (Widget w, LinkType linkType, char *linkPosn, char *linkData)
1767 {
1768 LinkInfoPtr li;
1769
1770 li = (LinkInfoPtr) XtMalloc(sizeof(struct LinkRec));
1771 if (li == NULL) XtError(MSG3);
1772 else
1773 {
1774 li->linkType = linkType;
1775 li->linkPosn = NewString(linkPosn);
1776 li->linkData = NewString(linkData);
1777 }
1778
1779 return(li);
1780 }
1781
1782
1783
1784 /*---------------------========================-------------------------*
1785 | XmMultiTextAppendNewLine |
1786 | (future version...) a new line should be treated as a word and should|
1787 | be assigned a font as any other word. This font should be used to |
1788 | determine the height of the new line. If a new word is inserted into |
1789 | the new line that is shorter, the line shouldn't shrink to match the |
1790 | new height until the font of the newline is changed. |
1791 *---------------------========================-------------------------*/
XmMultiTextAppendNewLine(Widget w,char * theWord,char * fontName,int indent)1792 void XmMultiTextAppendNewLine (Widget w, char *theWord, char *fontName, int indent)
1793 {
1794 XmMultiTextWidget cw = (XmMultiTextWidget) w;
1795 LineList lp;
1796 XFontStruct *font;
1797 int direction, fontAscent, fontDescent, yposn;
1798 XCharStruct boundingBox;
1799
1800
1801 /* Create a new line with the height of the current font. */
1802
1803 /* there are two cases, either the line before has some words in it, or it doesn't. */
1804 /* if there are words in the previous line, use its height to figure the new posn. */
1805 /* if there are no words, then calculate the new posn using the current font. */
1806
1807 /* Case 0 - No lines in widget yet. */
1808 if (cw->multiText.firstLine == NULL)
1809 {
1810 font = NamedFont(cw, fontName);
1811 if (!font)
1812 {
1813 return;
1814 }
1815 XTextExtents(font, theWord, strlen(theWord),
1816 &direction, &fontAscent, &fontDescent, &boundingBox);
1817 if (fontAscent != boundingBox.ascent) boundingBox.ascent = fontAscent;
1818 if (fontDescent != boundingBox.descent) boundingBox.descent = fontDescent;
1819 yposn = cw->multiText.marginHeight;
1820
1821 lp = NewLine(cw, indent, yposn, DEFAULT_LINE_SPACING);
1822 lp->bbox.ascent = fontAscent;
1823 lp->bbox.descent = fontDescent;
1824 cw->multiText.firstLine = lp;
1825 cw->multiText.lastLine = lp;
1826 }
1827 else
1828
1829
1830 /* Case 1 - Previous line has words in it already. */
1831 /* Use the previous word for height info - sorta logical, I guess. */
1832 if (cw->multiText.lastLine->firstWord != NULL)
1833 {
1834 yposn = cw->multiText.lastLine->y +
1835 cw->multiText.lastLine->bbox.ascent + cw->multiText.lastLine->bbox.descent +
1836 cw->multiText.lastLine->lineSpacing;
1837
1838 lp = NewLine(cw, indent, yposn, cw->multiText.lastLine->lineSpacing);
1839 cw->multiText.lastLine->next = lp;
1840 lp->prev = cw->multiText.lastLine;
1841 cw->multiText.lastLine = lp;
1842
1843 font = NamedFont(cw, fontName);
1844 if (!font)
1845 {
1846 return;
1847 }
1848 XTextExtents(font, theWord, strlen(theWord), &direction, &fontAscent, &fontDescent,
1849 &boundingBox);
1850 lp->bbox.ascent = fontAscent;
1851 lp->bbox.descent = fontDescent;
1852 }
1853
1854
1855 /* Case 2 - Previous line has no words in it - probably just a newline. */
1856 else
1857 {
1858 font = NamedFont(cw, fontName);
1859 if (!font)
1860 {
1861 return;
1862 }
1863 XTextExtents(font, theWord, strlen(theWord), &direction, &fontAscent, &fontDescent,
1864 &boundingBox);
1865 if (fontAscent != boundingBox.ascent) boundingBox.ascent = fontAscent;
1866 if (fontDescent != boundingBox.descent) boundingBox.descent = fontDescent;
1867 yposn = cw->multiText.lastLine->y +
1868 fontAscent + fontDescent +
1869 cw->multiText.lastLine->lineSpacing;
1870
1871 lp = NewLine(cw, indent, yposn, cw->multiText.lastLine->lineSpacing);
1872 lp->bbox.ascent = fontAscent;
1873 lp->bbox.descent = fontDescent;
1874 cw->multiText.lastLine->next = lp;
1875 lp->prev = cw->multiText.lastLine;
1876 cw->multiText.lastLine = lp;
1877 }
1878
1879 cw->multiText.currentLine = cw->multiText.lastLine; /* set this as the current line. */
1880 lp->newLine = TRUE; /* tag this newline as a 'hard' newline. */
1881 }
1882
1883
1884
1885
1886
1887 /*-----------------------=====================--------------------------*
1888 | XmMultiTextAppendWord |
1889 | This is called from the outside world. Words are appended to the |
1890 | current cursor position and have the following associated traits: |
1891 | Color, Font, Link. |
1892 | |
1893 | From here, the word will be appended as a single word into the data- |
1894 | structure of the XmMultiTextWidget. Any justification and other text |
1895 | handling is not done here. |
1896 | |
1897 | This routine calls the internal routine StoreWord which enters the |
1898 | new word structure to the current line. StoreWord returns status |
1899 | information depending on what occured when the new word was added to |
1900 | the line. |
1901 | A tab is entered as a complete word. The next word shouldn't add |
1902 | any wordspacing. |
1903 *-----------------------=====================--------------------------*/
XmMultiTextAppendWord(Widget w,char * theWord,char * fontName,char * colorName,int indent,LinkInfoPtr linkInfo)1904 unsigned short XmMultiTextAppendWord (Widget w, char *theWord, char *fontName, char *colorName,
1905 int indent, LinkInfoPtr linkInfo)
1906 {
1907 XmMultiTextWidget cw = (XmMultiTextWidget) w;
1908 WordList wordPtr;
1909 XFontStruct *font;
1910 XCharStruct boundingBox;
1911 unsigned short status;
1912
1913
1914 font = NamedFont (cw, fontName);
1915 if (!font)
1916 {
1917 return 0;
1918 }
1919
1920 /* get the bounding box for this word (or tab). */
1921 GetBoundingBox(cw, theWord, font, &boundingBox, indent);
1922
1923 /* build the word record to add to the widget. */
1924 wordPtr = (WordList) XtMalloc(sizeof(struct WordRec));
1925 if (wordPtr == NULL) XtError(MSG6);
1926 wordPtr->charList = NULL;
1927 wordPtr->bbox = boundingBox;
1928 wordPtr->x = 0;
1929 wordPtr->y = 0;
1930 wordPtr->length = strlen(theWord);
1931 wordPtr->chars = NewString(theWord);
1932 wordPtr->font = font;
1933 wordPtr->spacing = 0;
1934 wordPtr->color = Color (cw, colorName);
1935 wordPtr->linkInfo = linkInfo;
1936 wordPtr->bbox.attributes = 0;
1937 wordPtr->image = None;
1938 wordPtr->widget = NULL;
1939 wordPtr->selected = FALSE;
1940 wordPtr->linePtr = NULL;
1941 wordPtr->next = NULL;
1942 wordPtr->prev = NULL;
1943
1944 /* append the word structure on the widget's current line. */
1945 status = StoreWord(cw, wordPtr, indent);
1946
1947 return (status);
1948 }
1949
1950
1951 /*---------------------========================-------------------------*
1952 | XmMultiTextAppendWordTop |
1953 | This routine adds a single word to the first line in the MultiText |
1954 | widget. It requires that there is a first line. Additionally, word |
1955 | wrapping isn't yet supported and a warning is issued if the appended |
1956 | word is supposed to wrap. In any case, the word will be appended as |
1957 | though word wrapping is off. |
1958 | After the word is inserted, all lines after the current line must be |
1959 | updated to reflect the new height changes (if necessary). The prev |
1960 | pointer of the following line must also be changed. |
1961 *---------------------========================-------------------------*/
XmMultiTextAppendWordTop(Widget w,char * theWord,char * fontName,char * colorName,int indent,LinkInfoPtr linkInfo)1962 unsigned short XmMultiTextAppendWordTop (Widget w, char *theWord, char *fontName,
1963 char *colorName, int indent, LinkInfoPtr linkInfo)
1964 {
1965 XmMultiTextWidget cw = (XmMultiTextWidget) w;
1966 WordList wordPtr;
1967 XFontStruct *font;
1968 XCharStruct boundingBox;
1969 unsigned short status;
1970
1971
1972 /* this routine won't work if there is no top-line to append the new word. */
1973 /* maybe later, I'll automatically create a new line in this case. But for */
1974 /* now, just return and don't append the new word. */
1975 if (cw->multiText.firstLine == NULL) {
1976 XtWarning(MSG9);
1977 return(APPEND_ERROR);
1978 }
1979
1980
1981 font = NamedFont (cw, fontName);
1982 if (!font)
1983 {
1984 return 0;
1985 }
1986
1987 /* get the bounding box for this word (or tab). */
1988 GetBoundingBox(cw, theWord, font, &boundingBox, indent);
1989
1990 /* build the word record to add to the widget. */
1991 wordPtr = (WordList) XtMalloc(sizeof(struct WordRec));
1992 if (wordPtr == NULL) XtError(MSG6);
1993 wordPtr->charList = NULL;
1994 wordPtr->bbox = boundingBox;
1995 wordPtr->x = 0;
1996 wordPtr->y = 0;
1997 wordPtr->length = strlen(theWord);
1998 wordPtr->chars = NewString(theWord);
1999 wordPtr->font = font;
2000 wordPtr->spacing = 0;
2001 wordPtr->color = Color (cw, colorName);
2002 wordPtr->linkInfo = linkInfo;
2003 wordPtr->bbox.attributes = 0;
2004 wordPtr->image = None;
2005 wordPtr->widget = NULL;
2006 wordPtr->selected = FALSE;
2007 wordPtr->linePtr = NULL;
2008 wordPtr->next = NULL;
2009 wordPtr->prev = NULL;
2010
2011 /* append the word structure on the widget's first line. */
2012 status = AppendWordToTopLine(cw, wordPtr, indent);
2013
2014
2015 return (status);
2016 }
2017
2018
2019
2020 /*-------------------============================-----------------------*
2021 | XmMultiTextAppendOpenLineTop |
2022 | |
2023 | NOTE - THE NEW LINE IS EMPTY AND HAS NO ASCENT OR DESCENT. YOU MUST |
2024 | PUT SOMETHING INTO IT OR IT WILL NOT SHOW UP. |
2025 | |
2026 | (Future...) should handle cases with no lines in the widget yet. |
2027 *-------------------============================-----------------------*/
XmMultiTextOpenLineTop(Widget w,int indent)2028 void XmMultiTextOpenLineTop (Widget w, int indent)
2029 {
2030 XmMultiTextWidget cw = (XmMultiTextWidget) w;
2031 LineList lp;
2032
2033
2034
2035 lp = NewLine(cw, indent, cw->multiText.marginHeight, DEFAULT_LINE_SPACING);
2036
2037 if (lp != NULL)
2038 {
2039 lp->next = cw->multiText.firstLine;
2040 if (lp->next != NULL) lp->next->prev = lp;
2041 cw->multiText.firstLine = lp;
2042
2043 /* NOTE - THE ASCENT AND DESCENT OF THE LINE IS ZERO AT THIS POINT. */
2044 }
2045 }
2046
2047
2048
2049
2050 /*----------------------------------------------------------------------*
2051 | ScrollWindow |
2052 | Note that a negative dy value scrolls up and a positive scrolls down.|
2053 | This routine assumes that it is completely visible - ie must be a |
2054 | child of a scrolled window (its working area). In addition, the |
2055 | scrolledWindow must be in "applicationDefined" mode. |
2056 *----------------------------------------------------------------------*/
ScrollWindow(XmMultiTextWidget cw,int dy)2057 static void ScrollWindow (XmMultiTextWidget cw, int dy)
2058 {
2059 if (!cw->multiText.exposeOnly) TurnOffCursor(cw);
2060
2061 /* XFlush(XtDisplay(cw)); */
2062 /* XSync(XtDisplay(cw), False); */
2063
2064 if (dy > 0) /* SCROLL DOWN - shift the contents of the screen down. */
2065 {
2066 XCopyArea(XtDisplay(cw), XtWindow(cw), XtWindow(cw), cw->multiText.textGC,
2067 0, cw->multiText.marginHeight,
2068 cw->core.width, cw->core.height - 2*cw->multiText.marginHeight - dy,
2069 0, cw->multiText.marginHeight + dy);
2070
2071 /* draw the lines that fit into the uncovered region. */
2072 XClearArea(XtDisplay(cw), XtWindow(cw),
2073 0, 0,
2074 cw->core.width, cw->multiText.marginHeight + dy, FALSE);
2075 DoRedrawText(cw, cw->multiText.marginHeight-dy, 2*dy);
2076 }
2077 else
2078
2079 if (dy < 0) /* SCROLL UP - shift the contents of the screen up. */
2080 {
2081 XCopyArea(XtDisplay(cw), XtWindow(cw), XtWindow(cw), cw->multiText.textGC,
2082 0, cw->multiText.marginHeight + (-dy),
2083 cw->core.width, cw->core.height - 2*cw->multiText.marginHeight - (-dy),
2084 0, cw->multiText.marginHeight);
2085
2086 XClearArea(XtDisplay(cw), XtWindow(cw),
2087 0, cw->core.height - cw->multiText.marginHeight - (-dy),
2088 cw->core.width, (-dy), FALSE);
2089 DoRedrawText(cw, cw->core.height - cw->multiText.marginHeight - (-dy), (-dy));
2090 }
2091
2092 if (!cw->multiText.exposeOnly) TurnOnCursor(cw);
2093 }
2094
2095
2096
2097 /*---------------------========================-------------------------*
2098 | XmMultiTextDeleteLineTop |
2099 *---------------------========================-------------------------*/
XmMultiTextDeleteLineTop(Widget w,int linesToDelete)2100 int XmMultiTextDeleteLineTop (Widget w, int linesToDelete)
2101 {
2102 XmMultiTextWidget cw = (XmMultiTextWidget) w;
2103 int dy, i;
2104 LineList lp = cw->multiText.firstLine;
2105
2106
2107 if ((cw->multiText.firstLine == NULL) || (linesToDelete <= 0)) return (0);
2108
2109 for (i=0; (i<linesToDelete) && (lp != NULL); i++)
2110 {
2111 lp = cw->multiText.firstLine;
2112
2113 cw->multiText.firstLine = lp->next;
2114 if (lp->next != NULL) lp->next->prev = NULL;
2115
2116 /* find how much to shift all the lines... note, line's know about the margin height. */
2117 dy = cw->multiText.marginHeight - cw->multiText.firstLine->y;
2118
2119 ShiftFollowingLines (lp, dy);
2120
2121 if (cw->multiText.currentLine == lp)
2122 if (cw->multiText.firstLine->wordCount > 0)
2123 UpdateCursor(cw, cw->multiText.firstLine,
2124 cw->multiText.firstLine->x + cw->multiText.firstLine->firstWord->x,
2125 cw->multiText.firstLine->x + cw->multiText.firstLine->firstWord->x,
2126 cw->multiText.firstLine->y + cw->multiText.firstLine->bbox.ascent);
2127 else
2128 UpdateCursor(cw, cw->multiText.firstLine,
2129 cw->multiText.firstLine->x,
2130 cw->multiText.firstLine->x,
2131 cw->multiText.firstLine->y + cw->multiText.firstLine->bbox.ascent);
2132 else
2133 cw->multiText.cursorY += dy;
2134
2135 if (!cw->multiText.exposeOnly)
2136 if (cw->multiText.smoothScroll) ScrollWindow(cw, dy);
2137
2138 /* if you want to automatically update the widget's height, add that here... */
2139 /*
2140 XtSetArg(args[0], XmNheight, cw->core.height + dy);
2141 XtSetValues(cw, args, 1);
2142 */
2143
2144 /* now free the memory held by the line (lp). */
2145 FreeLineRecord (cw, lp);
2146 }
2147
2148 if (!cw->multiText.exposeOnly)
2149 if (!cw->multiText.smoothScroll)
2150 XClearArea(XtDisplay(cw), XtWindow(cw), 0, 0, 0, 0, TRUE);
2151
2152 return(i);
2153 }
2154
2155
2156
2157 /*-------------------===========================------------------------*
2158 | XmMultiTextDeleteLineBottom |
2159 *-------------------===========================------------------------*/
XmMultiTextDeleteLineBottom(Widget w)2160 void XmMultiTextDeleteLineBottom (Widget w)
2161 {
2162 XmMultiTextWidget cw = (XmMultiTextWidget) w;
2163 LineList lp = cw->multiText.firstLine;
2164
2165
2166 lp = cw->multiText.lastLine;
2167 if (lp != NULL)
2168 {
2169 cw->multiText.lastLine = lp->prev;
2170 if (lp->prev != NULL) lp->prev->next = NULL;
2171
2172 /* if you want to automatically update the widget's height, add that here... */
2173 /*
2174 dy = lp->bbox.ascent + lp->bbox.descent + lp->lineSpacing;
2175 XtSetArg(args[0], XmNheight, cw->core.height - dy);
2176 XtSetValues(cw, args, 1);
2177 */
2178
2179 /* now free the memory held by the line (lp). */
2180 FreeLineRecord (cw, lp);
2181 }
2182 }
2183
2184
2185
2186
2187 /*------------------============================------------------------*
2188 | XmMultiTextLongestLineLength |
2189 *------------------============================------------------------*/
XmMultiTextLongestLineLength(Widget w)2190 int XmMultiTextLongestLineLength (Widget w)
2191 {
2192 XmMultiTextWidget cw = (XmMultiTextWidget) w;
2193 LineList lp;
2194 int widestWidth = 0;
2195
2196 for (lp = cw->multiText.firstLine; lp != NULL; lp = lp->next)
2197 if (widestWidth < (lp->x + lp->bbox.width) )
2198 widestWidth = lp->x + lp->bbox.width;
2199
2200 return (widestWidth);
2201 }
2202
2203
2204
2205
2206
2207 /*-----------------------======================-------------------------*
2208 | XmMultiTextAppendImage |
2209 *-----------------------======================-------------------------*/
XmMultiTextAppendImage(Widget w,char * theWord,char * fontName,char * colorName,int indent,Pixmap image,unsigned int width,unsigned int height,LinkInfoPtr linkInfo)2210 unsigned short XmMultiTextAppendImage (Widget w, char *theWord, char *fontName, char *colorName,
2211 int indent, Pixmap image, unsigned int width,
2212 unsigned int height, LinkInfoPtr linkInfo)
2213 {
2214 XmMultiTextWidget cw = (XmMultiTextWidget) w;
2215 WordList wordPtr;
2216 XFontStruct *font;
2217 XCharStruct boundingBox;
2218
2219 font = NamedFont (cw, fontName);
2220 if (!font)
2221 {
2222 return 0;
2223 }
2224
2225 /* get the bounding box for this word (or tab). */
2226 GetBoundingBox(cw, theWord, font, &boundingBox, indent);
2227
2228 /* build the word record to add to the widget. */
2229 wordPtr = (WordList) XtMalloc(sizeof(struct WordRec));
2230 if (wordPtr == NULL) XtError(MSG6);
2231 wordPtr->charList = NULL;
2232 wordPtr->x = 0;
2233 wordPtr->y = 0;
2234 wordPtr->length = strlen(theWord); /* doesn't really make sense for images... */
2235 wordPtr->chars = NewString(theWord); /* 'theWord' is value returned if selected. */
2236 wordPtr->font = font;
2237 wordPtr->spacing = 0;
2238 wordPtr->color = Color (cw, colorName);
2239 wordPtr->linkInfo = linkInfo;
2240 wordPtr->selected = FALSE;
2241 wordPtr->linePtr = NULL;
2242 wordPtr->next = NULL;
2243 wordPtr->prev = NULL;
2244
2245 /* now setup the image information. */
2246 wordPtr->image = image;
2247 wordPtr->widget = NULL;
2248 wordPtr->bbox.lbearing = 0;
2249 wordPtr->bbox.rbearing = width;
2250 wordPtr->bbox.width = width;
2251 wordPtr->bbox.ascent = (height+1) / 2;
2252 wordPtr->bbox.descent = height / 2;
2253 wordPtr->bbox.attributes = 0;
2254
2255
2256 /* append the word structure on the widget's current line. */
2257 StoreWord(cw, wordPtr, indent);
2258
2259 return (1);
2260 }
2261
2262
2263
2264 /*-----------------------=======================------------------------*
2265 | XmMultiTextAppendWidget |
2266 *-----------------------=======================------------------------*/
XmMultiTextAppendWidget(Widget w,char * theWord,char * fontName,char * colorName,int indent,Widget newW)2267 unsigned short XmMultiTextAppendWidget (Widget w, char *theWord, char *fontName, char *colorName,
2268 int indent, Widget newW)
2269 {
2270 XmMultiTextWidget cw = (XmMultiTextWidget) w;
2271 WordList wordPtr;
2272 XFontStruct *font;
2273 XCharStruct boundingBox;
2274 unsigned short status;
2275 int n, width, height;
2276 Arg args[5];
2277 int xoffset; /* line's indent + margin width */
2278 int yposn; /* top of current line */
2279
2280
2281 font = NamedFont (cw, fontName);
2282 if (!font)
2283 {
2284 return 0;
2285 }
2286
2287 /* get the bounding box for this word (or tab). */
2288 GetBoundingBox(cw, theWord, font, &boundingBox, indent);
2289
2290 /* build the word record to add to the widget. */
2291 wordPtr = (WordList) XtMalloc(sizeof(struct WordRec));
2292 if (wordPtr == NULL) XtError(MSG6);
2293 wordPtr->charList = NULL;
2294 wordPtr->x = 0;
2295 wordPtr->y = 0;
2296 wordPtr->length = strlen(theWord); /* doesn't really make sense for widgets... */
2297 wordPtr->chars = NewString(theWord); /* 'theWord' is value returned if selected. */
2298 wordPtr->font = font;
2299 wordPtr->spacing = 0;
2300 wordPtr->color = Color (cw, colorName);
2301 wordPtr->linkInfo = NULL; /* can't have a widget as a link... */
2302 wordPtr->selected = FALSE;
2303 wordPtr->linePtr = NULL;
2304 wordPtr->next = NULL;
2305 wordPtr->prev = NULL;
2306
2307 /* find the size of the widget */
2308 n = 0;
2309 XtSetArg(args[n], XmNwidth, &width); n++;
2310 XtSetArg(args[n], XmNheight, &height); n++;
2311 XtGetValues(newW, args, n);
2312
2313 /* now setup the image information. */
2314 wordPtr->image = None;
2315 wordPtr->widget = newW;
2316 wordPtr->bbox.lbearing = 0;
2317 wordPtr->bbox.rbearing = width;
2318 wordPtr->bbox.width = width;
2319 wordPtr->bbox.ascent = (height+1) / 2;
2320 wordPtr->bbox.descent = height / 2;
2321 wordPtr->bbox.attributes = 0;
2322
2323
2324 /* append the word structure on the widget's current line. */
2325 status = StoreWord(cw, wordPtr, indent);
2326
2327
2328 xoffset = wordPtr->linePtr->x;
2329 yposn = wordPtr->linePtr->y + wordPtr->linePtr->bbox.ascent;
2330
2331 XtMoveWidget(newW, xoffset + wordPtr->x, yposn - wordPtr->bbox.ascent);
2332 XtManageChild(newW);
2333
2334 return (status);
2335 }
2336
2337
2338
2339
2340 /*-----------------------====================---------------------------*
2341 | XmMultiTextAppendDPS |
2342 *-----------------------====================---------------------------*/
XmMultiTextAppendDPS(Widget w,char * theWord,char * fontName,char * colorName,int indent,char * dpsFileName,unsigned int width,unsigned int height,LinkInfoPtr linkInfo)2343 unsigned short XmMultiTextAppendDPS (Widget w, char *theWord, char *fontName, char *colorName,
2344 int indent, char *dpsFileName, unsigned int width,
2345 unsigned int height, LinkInfoPtr linkInfo)
2346 {
2347 unsigned short status;
2348
2349
2350 #ifdef NODPS
2351 /* if the systems doesn't support DPS then just replace it with a substitute string. */
2352 status = XmMultiTextAppendWord (w, "Graphics omitted from Online Documentation, please see the manual", fontName, colorName, indent, linkInfo);
2353
2354 #else
2355 {
2356 XmMultiTextWidget cw = (XmMultiTextWidget) w;
2357 Pixmap image;
2358
2359 if (cw->multiText.dpsCapable)
2360 {
2361 image = GetDPSImage(cw, dpsFileName, &width, &height);
2362 /* append the word structure on the widget's current line. */
2363 /* Note: 'theWord' is the value returned when an image is selected. */
2364 status = XmMultiTextAppendImage (w, theWord, fontName, colorName, indent,
2365 image, width, height, linkInfo);
2366 }
2367 else
2368 {
2369 /* if the systems doesn't support DPS then just replace it with a substitute string. */
2370 status = XmMultiTextAppendWord (w, "Graphics omitted from Online Documentation, please see the manual", fontName, colorName, indent, linkInfo);
2371 }
2372 }
2373 #endif
2374
2375 return (status != APPEND_ERROR);
2376 }
2377
2378
2379
2380 /*-----------------------=====================--------------------------*
2381 | XmMultiTextAppendLine |
2382 *-----------------------=====================--------------------------*/
XmMultiTextAppendLine(Widget w,char * str)2383 Boolean XmMultiTextAppendLine (Widget w, char *str)
2384 {
2385 return True;
2386 }
2387
2388
2389 /*-----------------------=====================--------------------------*
2390 | XmMultiTextAppendChar |
2391 | add a character to the current word. This will cause the current |
2392 | word to redisplay. Perhapse the best method is to just show the |
2393 | character unless the character has a different format than the other |
2394 | letters. How to manage that is still a mystery... |
2395 *-----------------------=====================--------------------------*/
XmMultiTextAppendChar(Widget w,char ch)2396 Boolean XmMultiTextAppendChar (Widget w, char ch)
2397 {
2398 XmMultiTextWidget cw = (XmMultiTextWidget) w;
2399 WordList wp;
2400 char *newWord;
2401
2402
2403 if ((cw->multiText.firstLine == NULL) || (cw->multiText.lastLine->firstWord == NULL))
2404 XtWarning("Sorry - this isn't supported yet.");
2405
2406 else
2407 {
2408 /* stuff this character onto the current word. */
2409 wp = cw->multiText.lastLine->lastWord;
2410 wp->length++;
2411 newWord = (char *) XtMalloc(sizeof(char) * wp->length + 2);
2412 if (newWord == NULL) XtError(MSG6);
2413 sprintf(newWord, "%s%c", wp->chars, ch);
2414 XtFree(wp->chars);
2415 wp->chars = newWord;
2416
2417 GetBoundingBox(cw, newWord, wp->font, &wp->bbox, cw->multiText.lastLine->indent);
2418
2419 XClearArea(XtDisplay(w), XtWindow(w),
2420 wp->x + cw->multiText.lastLine->x, wp->y + cw->multiText.lastLine->y,
2421 wp->bbox.width, wp->bbox.ascent + wp->bbox.descent, TRUE);
2422 }
2423
2424 return True;
2425 }
2426
2427
2428
2429
2430
2431 /*======================================================================*
2432 | XmMultiText Widget Support Procedures |
2433 | ------------------------------------- |
2434 *======================================================================*/
2435
2436 /*----------------------------------------------------------------------*
2437 | NewString |
2438 *----------------------------------------------------------------------*/
NewString(char * str)2439 static char *NewString(char *str)
2440 {
2441 char *retStr;
2442
2443 retStr = (char *) XtMalloc(sizeof(char) * (str ? strlen(str) : 0) + 1);
2444 if (retStr == NULL) XtError(MSG6);
2445
2446 if (str == NULL)
2447 retStr[0] = '\0';
2448 else
2449 strcpy(retStr, str);
2450
2451 return(retStr);
2452 }
2453
2454
2455 /*----------------------------------------------------------------------*
2456 | ChangeHeight |
2457 *----------------------------------------------------------------------*/
ChangeHeight(XmMultiTextWidget w,Dimension newHeight)2458 static XtGeometryResult ChangeHeight (XmMultiTextWidget w, Dimension newHeight)
2459 {
2460 XtWidgetGeometry request, replyReturn;
2461 XtGeometryResult result;
2462
2463 /* build the request */
2464 request.request_mode = CWHeight;
2465 request.height = newHeight;
2466
2467 result = XtMakeGeometryRequest((Widget)w, &request, &replyReturn);
2468
2469 return (result);
2470 }
2471
2472
2473
2474 /*----------------------------------------------------------------------*
2475 | GetBoundingBox |
2476 | sets the bounding box of the word. |
2477 *----------------------------------------------------------------------*/
GetBoundingBox(XmMultiTextWidget cw,char * theWord,XFontStruct * font,XCharStruct * boundingBox,int indent)2478 static void GetBoundingBox(XmMultiTextWidget cw, char *theWord, XFontStruct *font,
2479 XCharStruct *boundingBox, int indent)
2480 {
2481 int direction, fontAscent, fontDescent, tabWidth;
2482
2483 /* if the word is a tab, must build bbox from scratch. */
2484 if (theWord[0] == TAB)
2485 {
2486 /* calculate the bounding box depending on the current tab settings. */
2487 /*tabPos =*/ NextTab(cw, &tabWidth, indent);
2488 boundingBox->lbearing = 0;
2489 boundingBox->rbearing = tabWidth;
2490 boundingBox->width = tabWidth;
2491 boundingBox->ascent = 0;
2492 boundingBox->descent = 0;
2493 boundingBox->attributes = 0;
2494 }
2495 else
2496 {
2497 XTextExtents(font, theWord, strlen(theWord), &direction, &fontAscent, &fontDescent,
2498 boundingBox);
2499 boundingBox->ascent = fontAscent;
2500 boundingBox->descent = fontDescent; /* make sure bounding box uses font's ascent,descent */
2501 }
2502 }
2503
2504
2505 /*----------------------------------------------------------------------*
2506 | ShiftFollowingLines |
2507 *----------------------------------------------------------------------*/
ShiftFollowingLines(LineList lines,int dy)2508 static void ShiftFollowingLines (LineList lines, int dy)
2509 {
2510 LineList lp;
2511 WordList wp;
2512
2513
2514 for (lp = lines; lp != NULL; lp = lp->next)
2515 {
2516 /* it shouldn't be necessary to adjust any of the words in the line */
2517 /* since they are relative to the line's position. */
2518
2519 lp->y += dy;
2520
2521 /* if the line has widgets - these may need moving. */
2522 /* though it should probably be handled on redraw, it is faster */
2523 /* if I handle it here. That way the checking is done only once. */
2524
2525 /* Scan though all words in the line and check if it's a widget. */
2526 /* If so, move it vertically by dy. */
2527
2528 for (wp = lp->firstWord; wp != NULL; wp = wp->next)
2529 if (wp->widget != NULL)
2530 XtMoveWidget(wp->widget, wp->widget->core.x, dy + wp->widget->core.y);
2531 }
2532 }
2533
2534
2535
2536 /*----------------------------------------------------------------------*
2537 | PtInLine |
2538 *----------------------------------------------------------------------*/
PtInLine(int x,int y,LineList lp)2539 static Boolean PtInLine (int x, int y, LineList lp)
2540 {
2541 if (lp == NULL) return FALSE;
2542
2543 if ((y >= lp->y) && (y < lp->y + lp->bbox.ascent + lp->bbox.descent))
2544 return TRUE;
2545 else
2546 return FALSE;
2547 }
2548
2549
2550
2551 /*----------------------------------------------------------------------*
2552 | CalculateSpacing |
2553 *----------------------------------------------------------------------*/
CalculateSpacing(Widget w,WordList wp,int * spaceBefore,int * spaceAfter)2554 static void CalculateSpacing (Widget w, WordList wp, int *spaceBefore, int *spaceAfter)
2555 {
2556 *spaceBefore = 0; /* problems will occur if these aren't initialized. */
2557 *spaceAfter = 0;
2558
2559 if (wp->prev == NULL)
2560 *spaceBefore = 0;
2561 else
2562 *spaceBefore = (int)((wp->x - (wp->prev->x + wp->prev->bbox.width)) / 2);
2563
2564 if (wp->next == NULL)
2565 *spaceAfter = 0;
2566 else
2567 *spaceAfter = (int)((wp->next->x - (wp->x + wp->bbox.width)) / 2 + 1);
2568 }
2569
2570
2571
2572 /*----------------------------------------------------------------------*
2573 | SameLinks |
2574 | returns true if the links are the same, and false otherwise. |
2575 *----------------------------------------------------------------------*/
SameLinks(WordList wp1,WordList wp2)2576 static Boolean SameLinks (WordList wp1, WordList wp2)
2577 {
2578 if ((wp1 == NULL) || (wp2 == NULL)) return(FALSE);
2579 else
2580 if ((wp1->linkInfo == NULL) || ((wp2->linkInfo == NULL))) return (FALSE);
2581 else
2582 if (wp1->linkInfo->linkType != wp2->linkInfo->linkType) return(FALSE);
2583 else
2584 if (STRCMP(wp1->linkInfo->linkPosn, wp2->linkInfo->linkPosn)) return(FALSE);
2585 else
2586 return(!STRCMP(wp1->linkInfo->linkData, wp2->linkInfo->linkData));
2587 }
2588
2589
2590 /*----------------------------------------------------------------------*
2591 | SetCurrentFont |
2592 *----------------------------------------------------------------------*/
SetCurrentFont(XmMultiTextWidget w,WordList wp,XFontStruct * font)2593 static void SetCurrentFont (XmMultiTextWidget w, WordList wp, XFontStruct *font)
2594 {
2595 /* to speed things up - only set the font if needed. */
2596 if (wp->font->fid != w->multiText.currentFontID)
2597 {
2598 XSetFont(XtDisplay(w), w->multiText.textGC, wp->font->fid);
2599 w->multiText.currentFontID = wp->font->fid;
2600 }
2601 }
2602
2603
2604 /*----------------------------------------------------------------------*
2605 | SetCurrentColor |
2606 *----------------------------------------------------------------------*/
SetCurrentColor(XmMultiTextWidget w,WordList wp,unsigned long color)2607 static void SetCurrentColor (XmMultiTextWidget w, WordList wp, unsigned long color)
2608 {
2609 /* to speed things up - only set the color if needed. */
2610 if (wp->color != w->multiText.currentColor)
2611 {
2612 XSetForeground(XtDisplay(w), w->multiText.textGC, wp->color);
2613 w->multiText.currentColor = wp->color;
2614 }
2615 }
2616
2617
2618 /*----------------------------------------------------------------------*
2619 | DisplayImage |
2620 *----------------------------------------------------------------------*/
DisplayImage(XmMultiTextWidget w,WordList wp)2621 static void DisplayImage (XmMultiTextWidget w, WordList wp)
2622 {
2623 int xoffset = wp->linePtr->x; /* line's indent + margine width */
2624 int yposn = wp->linePtr->y + wp->linePtr->bbox.ascent; /* top of the current line. */
2625
2626
2627 XCopyArea(XtDisplay(w), wp->image, XtWindow(w), w->multiText.textGC,
2628 0, 0, wp->bbox.width, wp->bbox.ascent + wp->bbox.descent,
2629 xoffset + wp->x, yposn - wp->bbox.ascent);
2630 }
2631
2632
2633 /*----------------------------------------------------------------------*
2634 | DisplayWord |
2635 | (future...) to fix the problem of jaged selection, erase the full |
2636 | lineheight before drawing the string. |
2637 *----------------------------------------------------------------------*/
DisplayWord(XmMultiTextWidget w,WordList wp)2638 static void DisplayWord (XmMultiTextWidget w, WordList wp)
2639 {
2640 int xoffset = wp->linePtr->x; /* line's indent + margine width */
2641 int yposn = wp->linePtr->y + wp->linePtr->bbox.ascent; /* baseline position */
2642 /* X always draws strings at the */
2643 /* baseline, not upperleft corner*/
2644 SetCurrentFont(w, wp, wp->font);
2645 SetCurrentColor(w, wp, wp->color);
2646
2647 if (wp->image != None)
2648 DisplayImage (w, wp);
2649 else
2650 if (wp->widget != NULL)
2651 /* do nothing */;
2652 else
2653 XDrawString(XtDisplay(w), XtWindow(w), w->multiText.textGC, wp->x + xoffset,
2654 yposn, wp->chars, wp->length);
2655 }
2656
2657
2658
2659 /*----------------------------------------------------------------------*
2660 | DisplaySelectedWord |
2661 | (future...) to fix the problem of jaged selection, fill the full line|
2662 | height on selections, not only the word's bounding box. |
2663 | The selection region should eventually be the same as the fill rgn. |
2664 *----------------------------------------------------------------------*/
DisplaySelectedWord(XmMultiTextWidget w,WordList wp)2665 static void DisplaySelectedWord (XmMultiTextWidget w, WordList wp)
2666 {
2667 Pixel fg = wp->color;
2668 Pixel bg = w->core.background_pixel;
2669 int spaceBefore, spaceAfter;
2670 int xoffset = wp->linePtr->x; /* line's indent + margine width */
2671 int yposn = wp->linePtr->y + wp->linePtr->bbox.ascent; /* baseline position */
2672 /* X always draws strings at the */
2673 /* baseline, not upperleft corner*/
2674 SetCurrentFont(w, wp, wp->font);
2675 SetCurrentColor(w, wp, wp->color);
2676
2677 CalculateSpacing((Widget)w, wp, &spaceBefore, &spaceAfter);
2678
2679 /* clear the area first. */
2680 XClearArea(XtDisplay(w), XtWindow(w),
2681 xoffset + wp->x - spaceBefore, yposn - wp->bbox.ascent,
2682 wp->bbox.width + spaceBefore + spaceAfter,
2683 wp->bbox.ascent + wp->bbox.descent, FALSE);
2684
2685 if (wp->image != None)
2686 DisplayImage (w, wp);
2687 else
2688 if (wp->widget != NULL)
2689 /* do nothing */;
2690 else
2691 XDrawString(XtDisplay(w), XtWindow(w), w->multiText.textGC, wp->x + xoffset,
2692 yposn, wp->chars, wp->length);
2693
2694 /* draw an xor box at the mouse position */
2695 /* should use... ->primitive.foreground ^ ->core.background_pixel */
2696
2697 XSetForeground(XtDisplay(w), w->multiText.textGC, WhitePixelOfScreen(XtScreen(w)));
2698 XSetBackground(XtDisplay(w), w->multiText.textGC, BlackPixelOfScreen(XtScreen(w)));
2699 XSetFunction (XtDisplay(w), w->multiText.textGC, GXxor);
2700
2701 XFillRectangle(XtDisplay(w), XtWindow(w), w->multiText.textGC,
2702 xoffset + wp->x - spaceBefore,
2703 yposn - wp->bbox.ascent,
2704 wp->bbox.width + spaceBefore + spaceAfter,
2705 wp->bbox.ascent + wp->bbox.descent);
2706
2707 XSetFunction (XtDisplay(w), w->multiText.textGC, GXcopy);
2708 XSetForeground(XtDisplay(w), w->multiText.textGC, fg);
2709 XSetBackground(XtDisplay(w), w->multiText.textGC, bg);
2710 }
2711
2712
2713 /*----------------------------------------------------------------------*
2714 | DisplayDeselectedWord |
2715 | fix for selections goes here too... |
2716 *----------------------------------------------------------------------*/
DisplayDeselectedWord(XmMultiTextWidget w,WordList wp)2717 static void DisplayDeselectedWord (XmMultiTextWidget w, WordList wp)
2718 {
2719 int spaceBefore, spaceAfter;
2720 int xoffset = wp->linePtr->x; /* line's indent + margine width */
2721 int yposn = wp->linePtr->y + wp->linePtr->bbox.ascent; /* baseline position */
2722 /* X always draws strings at the */
2723 /* baseline, not upperleft corner*/
2724 SetCurrentFont(w, wp, wp->font);
2725 SetCurrentColor(w, wp, wp->color);
2726
2727 CalculateSpacing((Widget)w, wp, &spaceBefore, &spaceAfter);
2728
2729 XClearArea(XtDisplay(w), XtWindow(w),
2730 xoffset + wp->x - spaceBefore, yposn - wp->bbox.ascent,
2731 wp->bbox.width + spaceBefore + spaceAfter,
2732 wp->bbox.ascent + wp->bbox.descent, FALSE);
2733
2734 if (wp->image != None)
2735 DisplayImage (w, wp);
2736 else
2737 if (wp->widget != NULL)
2738 {
2739 XtUnmapWidget(wp->widget);
2740 XtMapWidget(wp->widget);
2741 }
2742 else
2743 XDrawString(XtDisplay(w), XtWindow(w), w->multiText.textGC, wp->x + xoffset,
2744 yposn, wp->chars, wp->length);
2745 }
2746
2747
2748
2749 /*----------------------------------------------------------------------*
2750 | DrawLinkMarking |
2751 | this routine draws the rectangle around a link. |
2752 *----------------------------------------------------------------------*/
DrawLinkMarking(XmMultiTextWidget w,WordList wp)2753 static void DrawLinkMarking (XmMultiTextWidget w, WordList wp)
2754 {
2755 int x[4], y[4];
2756 int xoffset = wp->linePtr->x; /* line's indent + margine width */
2757 int yposn = wp->linePtr->y + wp->linePtr->bbox.ascent; /* baseline position */
2758 /* X always draws strings at the */
2759 /* baseline, not upperleft corner*/
2760 /* don't close the box if the next word is the same link */
2761
2762 if (SameLinks(wp->next, wp))
2763 x[0] = xoffset + wp->next->x;
2764 else
2765 x[0] = xoffset + wp->x + wp->bbox.width;
2766
2767 y[0] = yposn - wp->linePtr->bbox.ascent -1;
2768 x[1] = xoffset + wp->x; y[1] = y[0];
2769 x[2] = x[1]; y[2] = yposn + wp->linePtr->bbox.descent;
2770 x[3] = x[0]; y[3] = y[2];
2771
2772 XDrawLine(XtDisplay(w), XtWindow(w), w->multiText.textGC, x[0], y[0], x[1], y[1]);
2773 XDrawLine(XtDisplay(w), XtWindow(w), w->multiText.textGC, x[2], y[2], x[3], y[3]);
2774 if (!SameLinks(wp->next, wp)) XDrawLine(XtDisplay(w), XtWindow(w), w->multiText.textGC,
2775 x[3], y[3], x[0], y[0]);
2776 if (!SameLinks(wp, wp->prev)) XDrawLine(XtDisplay(w), XtWindow(w), w->multiText.textGC,
2777 x[1], y[1], x[2], y[2]);
2778 }
2779
2780
2781
2782 /*----------------------------------------------------------------------*
2783 | DrawWord |
2784 | xoffset is the left edge of the line. yposn is the baseline of the |
2785 | line for this word. |
2786 | the boolean 'selected' tells if the word becomes selected or not. |
2787 | if it has the same value as the word's internal value, then don't |
2788 | change it; ie: if it is not selected and 'selected' is false, then |
2789 | don't bother clearing the word's bounding box before drawing it. |
2790 *----------------------------------------------------------------------*/
DrawWord(XmMultiTextWidget w,WordList wp,Boolean selected)2791 static void DrawWord (XmMultiTextWidget w, WordList wp, Boolean selected)
2792 {
2793
2794 /* this routine just calls the appropriate version of the drawing */
2795 /* routine depending on the type and style of the word. */
2796
2797 /* if this is a tab, return */
2798 if (wp->chars[0] == TAB) return;
2799
2800 /* if you don't want the image to be highlighted when selected, uncomment these lines. */
2801 /*
2802 if (wp->image != NULL) DisplayImage(w, wp);
2803 else
2804 */
2805
2806
2807 /* if the word isn't selected and isn't becomming selected, draw normally */
2808 if (!wp->selected && !selected) DisplayWord(w, wp);
2809 else
2810
2811 /* if the word isn't selected and it should become selected, draw it selected */
2812 if (!wp->selected && selected) DisplaySelectedWord(w, wp);
2813 else
2814
2815 /* if the word is selected and should become deselected, unselect it. */
2816 if (wp->selected && !selected) DisplayDeselectedWord(w, wp);
2817 else
2818
2819 /* and finally, if the word was selected and still is, draw it selected */
2820 if (wp->selected && selected) DisplaySelectedWord(w, wp);
2821 else
2822
2823 /* the above cases should cover all possibilities! */
2824 XtError("DrawWord: detected inconsistency");
2825
2826
2827 /* now handle links. Do whatever drawing is required */
2828 /* to show that this word is a link if needed. */
2829 if ((wp->linkInfo != NULL) && (wp->linkInfo->linkType != NOOP))
2830 DrawLinkMarking(w, wp);
2831 }
2832
2833
2834
2835 /*----------------------------------------------------------------------*
2836 | DrawLine |
2837 | call DrawWord for each word in the line. |
2838 *----------------------------------------------------------------------*/
DrawLine(XmMultiTextWidget w,LineList lp)2839 static void DrawLine (XmMultiTextWidget w, LineList lp)
2840 {
2841 WordList wp;
2842 int i;
2843
2844 if (lp != NULL)
2845 {
2846 wp = lp->firstWord;
2847
2848 for (i = 0; i < lp->wordCount; i++)
2849 {
2850 DrawWord(w, wp, wp->selected);
2851 wp = wp->next;
2852 }
2853 }
2854 }
2855
2856
2857
2858
2859 /*----------------------------------------------------------------------*
2860 | ResizeTheLine |
2861 | this routine will move each word in the line to the correct baseline |
2862 | position corresponding to its line. |
2863 | theWord is can be passed to this routine to enable a line to be re- |
2864 | sized before theWord is appended. If you just want to resize the |
2865 | line, pass theWord as NULL. |
2866 *----------------------------------------------------------------------*/
ResizeTheLine(XmMultiTextWidget w,LineList lp,WordList theWord)2867 static void ResizeTheLine (XmMultiTextWidget w, LineList lp, WordList theWord)
2868 {
2869 WordList wp;
2870 Dimension newHeight;
2871 int xoffset, yposn, maxAscent, maxDescent;
2872
2873
2874 if (lp == NULL) return;
2875 if (theWord == NULL) theWord = lp->firstWord;
2876 if (theWord == NULL)
2877 {
2878 lp->bbox.ascent = 0;
2879 lp->bbox.descent = 0;
2880 return;
2881 }
2882
2883
2884 /* know that theWord points to a valid word - may be first in line or new word. */
2885
2886 maxAscent = theWord->bbox.ascent;
2887 maxDescent = theWord->bbox.descent;
2888 for (wp = lp->firstWord; wp != NULL; wp = wp->next)
2889 {
2890 maxAscent = MAX(maxAscent, wp->bbox.ascent);
2891 maxDescent = MAX(maxDescent, wp->bbox.descent);
2892 }
2893 lp->bbox.ascent = maxAscent;
2894 lp->bbox.descent = maxDescent;
2895
2896
2897 wp = lp->firstWord;
2898 while (wp != NULL)
2899 {
2900 wp->y = lp->bbox.ascent - wp->bbox.ascent;
2901
2902 /* check if this is a widget, then move the widget. */
2903 if (wp->widget != NULL)
2904 {
2905 xoffset = wp->linePtr->x;
2906 yposn = wp->linePtr->y + wp->linePtr->bbox.ascent;
2907 XtMoveWidget(wp->widget, xoffset + wp->x, yposn - wp->bbox.ascent);
2908 }
2909
2910 wp = wp->next;
2911 }
2912
2913 /* if this line is below the bottom of the widget, then resize the widget to fit. */
2914 newHeight = lp->y + lp->bbox.ascent + lp->bbox.descent;
2915 if (w->core.height < newHeight + w->multiText.marginHeight)
2916 ChangeHeight(w, newHeight + (XtParent(w)->core.height/2));
2917 }
2918
2919
2920
2921
2922 /*----------------------------------------------------------------------*
2923 | FreeCharRecord |
2924 *----------------------------------------------------------------------*/
FreeCharRecord(XmMultiTextWidget w,CharList cp)2925 static void FreeCharRecord (XmMultiTextWidget w, CharList cp)
2926 {
2927 XtError("MultiText FreeCharRecord: charlist not initialized correctly");
2928 }
2929
2930
2931
2932 /*----------------------------------------------------------------------*
2933 | FreeWordRecord |
2934 *----------------------------------------------------------------------*/
FreeWordRecord(XmMultiTextWidget w,WordList wp)2935 static void FreeWordRecord (XmMultiTextWidget w, WordList wp)
2936 {
2937 CharList cp, cpNext;
2938
2939 cp = wp->charList;
2940
2941 while (cp != NULL) {
2942 cpNext = cp->next;
2943 FreeCharRecord(w, cp);
2944 XtFree((char*)cp);
2945 cp = cpNext;
2946 }
2947
2948 if (wp->image != None) XFreePixmap(XtDisplay(w), wp->image);
2949 if (wp->widget != NULL) XtDestroyWidget(wp->widget);
2950 if (wp->chars != NULL) XtFree(wp->chars);
2951 if (wp->linkInfo != NULL)
2952 {
2953 XtFree(wp->linkInfo->linkPosn);
2954 XtFree(wp->linkInfo->linkData);
2955 XtFree((char*)wp->linkInfo);
2956 }
2957 /* if (wp->font != NULL) XtFree(wp->font); - Don't even think of doing this! */
2958 }
2959
2960
2961
2962 /*----------------------------------------------------------------------*
2963 | FreeLineRecord |
2964 *----------------------------------------------------------------------*/
FreeLineRecord(XmMultiTextWidget w,LineList lp)2965 static void FreeLineRecord (XmMultiTextWidget w, LineList lp)
2966 {
2967 WordList wp, wpNext;
2968
2969 wp = lp->firstWord;
2970
2971 while (wp != NULL) {
2972 wpNext = wp->next;
2973 FreeWordRecord(w, wp);
2974 XtFree((char*)wp);
2975 wp = wpNext;
2976 }
2977 }
2978
2979
2980
2981 /*----------------------------------------------------------------------*
2982 | NextTab |
2983 *----------------------------------------------------------------------*/
NextTab(XmMultiTextWidget w,int * tabWidth,int indent)2984 static int NextTab (XmMultiTextWidget w, int *tabWidth, int indent)
2985 {
2986 int i, nextTabPos, currentPos;
2987
2988 /* first find out where we are. */
2989 if ((w->multiText.lastLine == NULL) || (w->multiText.lastLine->lastWord == NULL))
2990 currentPos = indent;
2991 else
2992 currentPos = w->multiText.lastLine->lastWord->x + w->multiText.lastLine->lastWord->bbox.width;
2993
2994 /* there are no tabs in this widget. nextTabPos is current posn. */
2995 if (w->multiText.tabCount == 0)
2996 {
2997 *tabWidth = 0;
2998 nextTabPos = currentPos;
2999 }
3000 else
3001 {
3002 /* must hunt for the correct tab... */
3003 for (i=0; ((currentPos > w->multiText.tabs[i]) && (i < w->multiText.tabCount)); i++);
3004
3005 /* if there was no tab after the current posn, ignore the tab. */
3006 if ((i == w->multiText.tabCount) && (currentPos > w->multiText.tabs[i]))
3007 nextTabPos = currentPos;
3008 else
3009 nextTabPos = w->multiText.tabs[i];
3010 *tabWidth = w->multiText.tabs[i] - currentPos;
3011 }
3012
3013 return (nextTabPos);
3014 }
3015
3016
3017 /*----------------------------------------------------------------------*
3018 | Color |
3019 | Note this will only lookup a new color if the name is different than |
3020 | the last one. |
3021 *----------------------------------------------------------------------*/
Color(XmMultiTextWidget w,char * name)3022 static unsigned long Color (XmMultiTextWidget w, char *name)
3023 {
3024 Colormap cmap;
3025
3026 if (STRCMP(w->multiText.lastColorName, name) != 0)
3027 {
3028 cmap = DefaultColormap(XtDisplay(w), XScreenNumberOfScreen(XtScreen(w)));
3029 w->multiText.color.pixel = (unsigned long)0;
3030 XParseColor(XtDisplay(w), cmap, name, &w->multiText.color);
3031 XAllocColor(XtDisplay(w), cmap, &w->multiText.color);
3032
3033 if (w->multiText.lastColorName != NULL) XtFree(w->multiText.lastColorName);
3034 w->multiText.lastColorName = NewString(name);
3035 }
3036
3037 return (w->multiText.color.pixel);
3038 }
3039
3040
3041 /*----------------------------------------------------------------------*
3042 | NamedFont |
3043 | Note this will only lookup a new font if the name is different than |
3044 | the last one. |
3045 *----------------------------------------------------------------------*/
NamedFont(XmMultiTextWidget w,char * name)3046 static XFontStruct *NamedFont (XmMultiTextWidget w, char *name)
3047 {
3048 int width;
3049 char buf[MAX_STR_LEN];
3050 int i=0;
3051
3052
3053 for (i = 0; i < w->multiText.numFonts; ++i)
3054 {
3055 if (STRCMP(w->multiText.fontCache[i].name, name) == 0)
3056 {
3057 if (w->multiText.smartSpacing)
3058 {
3059 width = XTextWidth(w->multiText.fontCache[i].font, " ", 1);
3060 if (width != 0) w->multiText.wordSpacing = width;
3061 }
3062 else
3063 w->multiText.wordSpacing = 0;
3064
3065 return(w->multiText.fontCache[i].font);
3066 }
3067 }
3068
3069 /* We didn't find the font, get the info and add it to our cache */
3070 w->multiText.numFonts++;
3071 w->multiText.fontCache =
3072 (XmMultiTextFontCache)XtRealloc((char *)w->multiText.fontCache,
3073 (i + 1) * sizeof (XmMultiTextFontCacheRec));
3074 w->multiText.fontCache[i].name = NewString(name);
3075 w->multiText.fontCache[i].font = XLoadQueryFont(XtDisplay(w), name);
3076 if (w->multiText.fontCache[i].font == NULL)
3077 {
3078 sprintf(buf, MSG4, name, DEFAULT_FONT_NAME);
3079 XtWarning(buf);
3080
3081 w->multiText.fontCache[i].font = XLoadQueryFont(XtDisplay(w), DEFAULT_FONT_NAME);
3082 if (w->multiText.fontCache[i].font == NULL)
3083 {
3084 sprintf(buf, MSG5, DEFAULT_FONT_NAME);
3085 XtWarning(buf);
3086 return NULL;
3087 }
3088 }
3089
3090 if (w->multiText.smartSpacing)
3091 {
3092 width = XTextWidth(w->multiText.fontCache[i].font, " ", 1);
3093 if (width != 0) w->multiText.wordSpacing = width;
3094 }
3095 else
3096 w->multiText.wordSpacing = 0;
3097
3098 return (w->multiText.fontCache[i].font);
3099 }
3100
3101
3102
3103 /*----------------------------------------------------------------------*
3104 | NewLine |
3105 *----------------------------------------------------------------------*/
NewLine(XmMultiTextWidget cw,int indent,int yposn,int lineSpacing)3106 static LineList NewLine (XmMultiTextWidget cw, int indent, int yposn, int lineSpacing)
3107 {
3108 LineList lp;
3109 Dimension newHeight;
3110
3111
3112 lp = (LineList) XtMalloc(sizeof(struct LineRec));
3113 if (lp == NULL) XtError(MSG6);
3114 else
3115 {
3116 lp->firstWord = NULL;
3117 lp->lastWord = NULL;
3118 lp->bbox.lbearing = 0;
3119 lp->bbox.rbearing = 0;
3120 lp->bbox.width = 0;
3121 lp->bbox.ascent = 0;
3122 lp->bbox.descent = 0;
3123 lp->bbox.attributes = 0;
3124 lp->x = indent + cw->multiText.marginWidth;
3125 lp->y = MAX(yposn, cw->multiText.marginHeight);
3126 lp->wordCount = 0;
3127 lp->indent = indent;
3128 lp->remaining = cw->core.width - 2*cw->multiText.marginWidth - indent;
3129 lp->lineSpacing = lineSpacing;
3130 lp->next = NULL;
3131 lp->prev = NULL; /* don't want to force the prev to be the last line just yet. */
3132
3133 /* if this line is below the bottom of the widget, the resize the widget to fit. */
3134 /* this is also done when an existing line is resized. */
3135 newHeight = (Dimension)(lp->y + lp->bbox.ascent + lp->bbox.descent);
3136 if (cw->core.height < newHeight + cw->multiText.marginHeight)
3137 ChangeHeight(cw, newHeight + (XtParent(cw)->core.height/RESIZE_FRACTION));
3138 }
3139
3140 return (lp);
3141 }
3142
3143
3144
3145 /*----------------------------------------------------------------------*
3146 | StuffWordOntoCurrentLine |
3147 | each word is stored at an x,y location which is relative to the line |
3148 | that contains this word. A word's x,y posn IS NOT the location in |
3149 | the multitext window! |
3150 | If any resizing of the line is needed, it will be handled here. The |
3151 | calling routine will be notified if any resizing was done so that |
3152 | any redrawing of the line can be performed. |
3153 *----------------------------------------------------------------------*/
StuffWordOntoCurrentLine(XmMultiTextWidget w,LineList lp,WordList wp,int neededWidth,Boolean firstWordOfLine,Boolean isTab,Boolean prevWordIsTab)3154 static Boolean StuffWordOntoCurrentLine (XmMultiTextWidget w, LineList lp, WordList wp,
3155 int neededWidth, Boolean firstWordOfLine, Boolean isTab,
3156 Boolean prevWordIsTab)
3157 {
3158 Boolean resizeLine = FALSE;
3159
3160 if (lp->firstWord == NULL)
3161 /* zero, not indent since word offset from lp and is already indented correctly. */
3162 wp->x = 0;
3163 else
3164 /* move current posn to the end of the last word (no spacing included - yet!) */
3165 wp->x = lp->lastWord->x + lp->lastWord->bbox.width;
3166
3167
3168 /* now add the spacing that should go before this word. */
3169 /* wordspacing is always the spacing used by the font of the previous word. */
3170 if (!isTab && !prevWordIsTab && (lp->firstWord != NULL))
3171 {
3172 wp->x += w->multiText.wordSpacing /* lp->wordSpacing */;
3173 wp->spacing = w->multiText.wordSpacing;
3174 }
3175
3176
3177 /* find out if resize is necessary. If so, resize the line. */
3178 if ((wp->bbox.ascent > lp->bbox.ascent) || (wp->bbox.descent > lp->bbox.descent)) {
3179 ResizeTheLine(w, lp, wp);
3180 resizeLine = TRUE;
3181 }
3182
3183
3184 /* append the wordStructure to the line's structure. */
3185 wp->prev = lp->lastWord; /* each word should know about the previous word. */
3186 if (lp->firstWord == NULL)
3187 lp->firstWord = wp;
3188 else
3189 lp->lastWord->next = wp;
3190 lp->lastWord = wp;
3191
3192 /* update the parameters of the line. */
3193 lp->bbox.width += neededWidth;
3194 lp->wordCount ++;
3195 lp->remaining -= neededWidth;
3196
3197 /* update the parameters of the word. */
3198 wp->y = lp->bbox.ascent - wp->bbox.ascent;
3199 wp->linePtr = lp;
3200
3201 return (resizeLine);
3202 }
3203
3204
3205
3206
3207 /*----------------------------------------------------------------------*
3208 | GetNeededWidth |
3209 *----------------------------------------------------------------------*/
GetNeededWidth(XmMultiTextWidget w,WordList wPtr,int indent,Boolean * firstWordOfLine,Boolean * isTab,Boolean * prevWordIsTab)3210 static int GetNeededWidth (XmMultiTextWidget w, WordList wPtr, int indent,
3211 Boolean *firstWordOfLine, Boolean *isTab, Boolean *prevWordIsTab)
3212 {
3213 int neededWidth;
3214
3215 /* lets start with the width of the word. */
3216 neededWidth = wPtr->bbox.width;
3217
3218 /* special handling for: first word, tabs, and words following tabs. */
3219 *firstWordOfLine = ((w->multiText.lastLine == NULL) ||
3220 (w->multiText.lastLine->lastWord == NULL));
3221 *isTab = (wPtr->chars[0] == TAB);
3222 *prevWordIsTab = ((w->multiText.lastLine != NULL) &&
3223 (w->multiText.lastLine->lastWord != NULL) &&
3224 (w->multiText.lastLine->lastWord->chars[0] == TAB));
3225
3226 /* if this isn't a tab, then add the indent to the amount that this word requires. */
3227 /* this is added since indented lines are just shifted - bounding boxes don't keep this info. */
3228 if (!isTab) neededWidth += indent;
3229
3230 if (!(*firstWordOfLine) && !(*prevWordIsTab) && !(*isTab))
3231 neededWidth += w->multiText.wordSpacing; /* spacing of current font is held by widget. */
3232
3233
3234 return(neededWidth);
3235 }
3236
3237
3238
3239 /*----------------------------------------------------------------------*
3240 | StoreWord |
3241 | This routine stores the new word into the current line. If this is |
3242 | the first word in the document, then create a new line before |
3243 | inserting it. Before appending the current word to the line, check |
3244 | to make sure that it will fit. The word's size is its bounding plus |
3245 | the size of the space between it and the previous word. |
3246 | Finally, if the word doesn't fit, print the previous full line and |
3247 | create a new line for the word. |
3248 *----------------------------------------------------------------------*/
StoreWord(XmMultiTextWidget w,WordList wordPtr,int indent)3249 static unsigned short StoreWord (XmMultiTextWidget w, WordList wordPtr, int indent)
3250 {
3251 LineList lp;
3252 Boolean resizeLine, firstWordOfLine, isTab, prevWordIsTab;
3253 unsigned short returnVal=0;
3254 int neededWidth, yposn;
3255
3256
3257 /* find the amount of space this word takes. This includes any indents and wordspacing. */
3258 /* this is used to determine if this word fits onto this line. (~Word width + indent) */
3259 neededWidth = GetNeededWidth(w, wordPtr, indent, &firstWordOfLine, &isTab, &prevWordIsTab);
3260
3261 /* case 1: no lines in the widget -> make a new one and add the word. */
3262 if (w->multiText.firstLine == NULL)
3263 {
3264 lp = NewLine(w, indent, 0, DEFAULT_LINE_SPACING);
3265 w->multiText.firstLine = lp;
3266 w->multiText.lastLine = lp;
3267 resizeLine = StuffWordOntoCurrentLine(w, lp, wordPtr, neededWidth,
3268 firstWordOfLine, isTab, prevWordIsTab);
3269 returnVal = APPEND_FIRST;
3270 }
3271 else
3272
3273 /* case 2: word doesn't fit on this line and wordwrapping is on. */
3274 if ((neededWidth > w->multiText.lastLine->remaining) && w->multiText.wordWrap)
3275 {
3276 yposn = w->multiText.lastLine->y + w->multiText.lastLine->bbox.ascent +
3277 w->multiText.lastLine->bbox.descent + w->multiText.lastLine->lineSpacing;
3278 lp = NewLine(w, indent, yposn, w->multiText.lastLine->lineSpacing);
3279 w->multiText.lastLine->next = lp;
3280 lp->prev = w->multiText.lastLine;
3281 resizeLine = StuffWordOntoCurrentLine(w, lp, wordPtr, neededWidth,
3282 firstWordOfLine, isTab,
3283 prevWordIsTab);
3284 w->multiText.lastLine = lp;
3285 returnVal = APPEND_FIRST;
3286 }
3287 else
3288
3289 /* case 3: word doesn't fit and wordwrapping is off. */
3290 if ((neededWidth > w->multiText.lastLine->remaining) && !w->multiText.wordWrap)
3291 {
3292 resizeLine = StuffWordOntoCurrentLine(w, w->multiText.lastLine, wordPtr, neededWidth,
3293 firstWordOfLine, isTab, prevWordIsTab);
3294 returnVal = APPEND_OK;
3295 if (resizeLine)
3296 returnVal = APPEND_RESIZE; /* this should probably be APPEND_CLIP_RESIZE... */
3297 else
3298 returnVal = APPEND_OK; /* this should probably be APPEND_CLIP... */
3299 }
3300 else
3301
3302 /* case 4: the word fits onto the current line. */
3303 if (neededWidth <= w->multiText.lastLine->remaining)
3304 {
3305 resizeLine = StuffWordOntoCurrentLine(w, w->multiText.lastLine, wordPtr, neededWidth,
3306 firstWordOfLine, isTab, prevWordIsTab);
3307 if (resizeLine)
3308 returnVal = APPEND_RESIZE;
3309 else
3310 returnVal = APPEND_OK;
3311 }
3312
3313
3314 /* set the current line to the one that was just appended to. */
3315 UpdateCursor(w, w->multiText.lastLine,
3316 w->multiText.lastLine->x + w->multiText.lastLine->lastWord->x +
3317 w->multiText.lastLine->lastWord->bbox.width,
3318 w->multiText.lastLine->x + w->multiText.lastLine->lastWord->x +
3319 w->multiText.lastLine->lastWord->bbox.width,
3320 w->multiText.lastLine->y + w->multiText.lastLine->bbox.ascent);
3321
3322 /* now draw what's necessary - Compile with -DREALTIME to see each word as it's appended. */
3323 #ifdef REALTIME
3324 if (XtIsRealized) DrawWord(w, wordPtr, FALSE);
3325 #endif
3326
3327
3328 return(returnVal);
3329 }
3330
3331
3332
3333
3334 /*----------------------------------------------------------------------*
3335 | AppendWordToTopLine |
3336 | This routine will append the given word to the first line in the |
3337 | widget. There must be a line to append to. In addition, the word is |
3338 | not allowed to wrap to the next line since this isn't supported. If |
3339 | wordWrapping is off - no problem; however, if it is ON then there is |
3340 | only a problem if the word is too long for the line. |
3341 | All resizing of the top line and all following lines is handled in |
3342 | this routine. |
3343 | THIS ~ASSUMES THAT THIS IS THE ONLY WORD OF THE LINE!!! SOME CLEANUP |
3344 | WILL BE NECESSARY FOR GENERAL CASES. |
3345 *----------------------------------------------------------------------*/
AppendWordToTopLine(XmMultiTextWidget cw,WordList wordPtr,int indent)3346 static unsigned int AppendWordToTopLine(XmMultiTextWidget cw, WordList wordPtr, int indent)
3347 {
3348 int maxAscent, maxDescent, dy;
3349 int textBottomY;
3350 LineList lp;
3351
3352
3353 /* this is redundant since this must be false if we are here... */
3354 if (cw->multiText.firstLine == NULL)
3355 {
3356 XtWarning(MSG9);
3357 return(APPEND_ERROR);
3358 }
3359
3360
3361 /* find the amount that all lines must be shifted down. */
3362 maxAscent = MAX(wordPtr->bbox.ascent, cw->multiText.firstLine->bbox.ascent);
3363 maxDescent = MAX(wordPtr->bbox.descent, cw->multiText.firstLine->bbox.descent);
3364 dy = (maxAscent + maxDescent) -
3365 (cw->multiText.firstLine->bbox.ascent + cw->multiText.firstLine->bbox.descent);
3366
3367 /* if the text is too large for the widget, then resize to fit. (Bottom of last line is below window. */
3368 textBottomY = cw->multiText.lastLine->y + cw->multiText.lastLine->bbox.ascent + cw->multiText.lastLine->bbox.descent;
3369
3370 if (cw->core.height - cw->multiText.marginHeight < dy + textBottomY)
3371 ChangeHeight(cw, dy + textBottomY + cw->multiText.marginHeight + (XtParent(cw)->core.height/2));
3372
3373 lp = cw->multiText.firstLine;
3374 if ((dy > 0) && (lp->next != NULL))
3375 ShiftFollowingLines(lp->next, dy);
3376
3377 /* now append the word and adjust the current line - all following lines are now correct. */
3378 /* note that this line isn't really the correct format; it's newline parameter may be wrong. */
3379 if (lp->wordCount == 0)
3380 {
3381 wordPtr->x = 0;
3382 lp->lastWord = lp->firstWord = wordPtr;
3383 }
3384 else
3385 {
3386 wordPtr->x = lp->lastWord->x + lp->lastWord->bbox.width; /* NOT GENERAL... */
3387 lp->lastWord->next = wordPtr;
3388 lp->lastWord = wordPtr;
3389 }
3390
3391 wordPtr->linePtr = cw->multiText.firstLine;
3392 lp->bbox.ascent = maxAscent;
3393 lp->bbox.descent = maxDescent;
3394 lp->wordCount++;
3395
3396
3397 /* now check if we have a word wrapping problem - in any case, don't wrap! */
3398 if ((lp->remaining < wordPtr->bbox.width) && (wordPtr->wordWrapping))
3399 XtWarning(MSG8);
3400
3401 /* currently, multiText isn't consistent with wordwrapping. Sometimes it uses */
3402 /* resource value and sometimes it uses the word's value. THIS WILL HAVE TO BE */
3403 /* FIXED! however, in the mean time - check both values. */
3404 if ((lp->remaining < wordPtr->bbox.width) && (cw->multiText.wordWrap))
3405 XtWarning(MSG8);
3406
3407 /* if, or if not wordwrapping, force the new word at the end of the first line. */
3408 lp->remaining -= wordPtr->bbox.width; /* NOT GENERAL... */
3409 lp->bbox.width += wordPtr->bbox.width; /* NOT GENERAL... */
3410
3411 TurnOffCursor(cw);
3412 cw->multiText.cursorY += dy;
3413 if (!cw->multiText.exposeOnly)
3414 if (dy > 0) ScrollWindow(cw, dy);
3415
3416 return APPEND_OK;
3417 }
3418
3419
3420 /*----------------------------------------------------------------------*
3421 | PositionCursor |
3422 | This routine returns the correct position for a cursor given x, y. |
3423 | Since the cursor position must be on a word boundry, the actual X |
3424 | position may be different from the cursor X position. The Y posn is |
3425 | always correct - or atleast it should be :-) |
3426 | Note - this routine DOES NOT change or move the cursor! |
3427 *----------------------------------------------------------------------*/
PositionCursor(XmMultiTextWidget cw,int x,int y,LineList * currentLine,int * actualX)3428 static void PositionCursor (XmMultiTextWidget cw, int x, int y, LineList *currentLine, int *actualX)
3429 {
3430 LineList lp;
3431 WordList wp, closestWord;
3432 int dx;
3433
3434
3435 if (cw->multiText.currentLine == NULL)
3436 {
3437 fprintf(stderr, "ERROR - NO-TEXT CASE Should not occur!\n");
3438 return;
3439 }
3440
3441
3442 /* find the line containing the new position. */
3443 /* for speed, check the immediate neighborhood (1 up or 1 down) first */
3444 if (PtInLine(x, y, cw->multiText.currentLine)) lp = cw->multiText.currentLine;
3445 else if (PtInLine(x, y, cw->multiText.currentLine->next)) lp = cw->multiText.currentLine->next;
3446 else if (PtInLine(x, y, cw->multiText.currentLine->prev)) lp = cw->multiText.currentLine->prev;
3447 else
3448
3449 /* else, find line containing the pt. */
3450 for (lp = cw->multiText.firstLine; lp != NULL; lp = lp->next)
3451 if (PtInLine(x, y, lp))
3452 break;
3453
3454 /* if not in any line, then ring bell - went off screen. */
3455 if (lp == NULL)
3456 {
3457 XBell(XtDisplay(cw), 0);
3458
3459 /* set cursor info to current positions. */
3460 *actualX = cw->multiText.actualX;
3461 *currentLine = cw->multiText.currentLine;
3462
3463 return;
3464 }
3465
3466
3467 /* now to find the horizontal location of the cursor. Either before, after, or middle of line. */
3468 if ((x <= lp->x) || (lp->lastWord == NULL))
3469 *actualX = lp->x;
3470
3471 else if (x >= (lp->x + lp->lastWord->x + lp->lastWord->bbox.width))
3472 *actualX = lp->x + lp->lastWord->x + lp->lastWord->bbox.width;
3473
3474 else
3475 {
3476 dx = lp->bbox.width;
3477 closestWord = lp->firstWord;
3478 for (wp = lp->firstWord; wp != NULL; wp = wp->next)
3479 if (dx > ABS((x - lp->x) - wp->x))
3480 {
3481 dx = ABS((x - lp->x) - wp->x);
3482 closestWord = wp;
3483 }
3484
3485 *actualX = lp->x + closestWord->x;
3486 }
3487
3488 *currentLine = lp;
3489 }
3490
3491
3492
3493 /*----------------------------------------------------------------------*
3494 | UpdateCursor |
3495 *----------------------------------------------------------------------*/
UpdateCursor(XmMultiTextWidget cw,LineList lp,int x,int actualX,int actualY)3496 static void UpdateCursor (XmMultiTextWidget cw, LineList lp, int x, int actualX, int actualY)
3497 {
3498 cw->multiText.cursorX = x;
3499 cw->multiText.cursorY = actualY;
3500 cw->multiText.actualX = actualX;
3501 cw->multiText.currentLine = lp;
3502 }
3503
3504
3505
3506 /*----------------------------------------------------------------------*
3507 | MoveUp |
3508 | Moving up dowsn't change the horizontally stored position. That way |
3509 | we always scroll back to the same position. |
3510 | Note, cursor is always at the baseline of the line. |
3511 *----------------------------------------------------------------------*/
MoveUp(Widget w,XEvent * event,String * params,Cardinal * numParams)3512 static void MoveUp (Widget w, XEvent* event, String* params, Cardinal* numParams)
3513 {
3514 XmMultiTextWidget cw = (XmMultiTextWidget) w;
3515 int actualX;
3516 int currentX = cw->multiText.cursorX;
3517 int currentY;
3518 LineList lp;
3519
3520
3521 if (cw->multiText.textIsSelected) DeselectAll(cw);
3522
3523 lp = cw->multiText.currentLine;
3524 if (lp->prev == NULL)
3525 {
3526 currentY = cw->multiText.cursorY;
3527 XBell(XtDisplay(cw), 0);
3528 }
3529 else
3530 currentY = lp->prev->y + lp->prev->bbox.ascent;
3531
3532 PositionCursor(cw, currentX, currentY, &lp, &actualX);
3533 UpdateCursor(cw, lp, currentX, actualX, currentY);
3534 }
3535
3536
3537 /*----------------------------------------------------------------------*
3538 | MoveDown |
3539 | Note, cursor is always at the baseline of the line. |
3540 *----------------------------------------------------------------------*/
MoveDown(Widget w,XEvent * event,String * params,Cardinal * numParams)3541 static void MoveDown (Widget w, XEvent* event, String* params, Cardinal* numParams)
3542 {
3543 XmMultiTextWidget cw = (XmMultiTextWidget) w;
3544 int actualX;
3545 int currentX = cw->multiText.cursorX;
3546 int currentY;
3547 LineList lp;
3548
3549
3550 if (cw->multiText.textIsSelected) DeselectAll(cw);
3551
3552 lp = cw->multiText.currentLine;
3553 if (lp->next == NULL)
3554 {
3555 currentY = cw->multiText.cursorY;
3556 XBell(XtDisplay(cw), 0);
3557 }
3558 else
3559 currentY = lp->next->y + lp->next->bbox.ascent;
3560
3561 PositionCursor(cw, currentX, currentY, &lp, &actualX);
3562 UpdateCursor(cw, lp, currentX, actualX, currentY);;
3563 }
3564
3565
3566
3567 /*----------------------------------------------------------------------*
3568 | ClosestPosition |
3569 | The closest position to a given location in a line can either be the |
3570 | left side of a word closest to the given position, or the end of the |
3571 | line. This routine is used to find where the cursor whould be placed |
3572 | given the reference position. |
3573 | ClosestWord is returned as the word containing the reference posi- |
3574 | tion. |
3575 *----------------------------------------------------------------------*/
ClosestPosition(XmMultiTextWidget cw,LineList lp,WordList * closestWord,int refPosn)3576 int ClosestPosition (XmMultiTextWidget cw, LineList lp,
3577 WordList *closestWord, int refPosn)
3578 {
3579 int dx, x=0;
3580 WordList wp;
3581
3582
3583 /* find the current word in this line. It's the word closest to the actual position. */
3584 dx = lp->bbox.width;
3585 *closestWord = lp->firstWord;
3586
3587 for (wp = lp->firstWord; wp != NULL; wp = wp->next)
3588 if (dx > ABS((cw->multiText.actualX - lp->x) - wp->x))
3589 {
3590 dx = ABS((cw->multiText.actualX - lp->x) - wp->x);
3591 *closestWord = wp;
3592 x = wp->x + lp->x;
3593 }
3594
3595 /* now check if the end of the line is closer than the closest word. */
3596 if (dx > ABS(lp->x + lp->bbox.width - cw->multiText.actualX))
3597 {
3598 *closestWord = NULL;
3599 x = lp->x + lp->bbox.width;
3600 }
3601
3602 return(x);
3603 }
3604
3605
3606
3607 /*----------------------------------------------------------------------*
3608 | MoveLeft |
3609 | Note, cursor is always at the baseline of the line. |
3610 *----------------------------------------------------------------------*/
MoveLeft(Widget w,XEvent * event,String * params,Cardinal * numParams)3611 static void MoveLeft (Widget w, XEvent* event, String* params, Cardinal* numParams)
3612 {
3613 XmMultiTextWidget cw = (XmMultiTextWidget) w;
3614 int actualX;
3615 int currentX;
3616 int currentY = cw->multiText.cursorY;
3617 LineList lp;
3618 WordList closestWord;
3619
3620
3621 if (cw->multiText.textIsSelected) DeselectAll(cw);
3622
3623 lp = cw->multiText.currentLine;
3624
3625 /* find the current word in this line. It's the word closest to the actual position. */
3626 ClosestPosition(cw, lp, &closestWord, cw->multiText.actualX);
3627
3628
3629 /* if closestWord is null, then the cursor is off the right side of the line. */
3630 /* unless there are no words in this line. */
3631
3632 if ((closestWord == NULL) && (lp->wordCount > 0)) /* move to the left side of the right-most word. */
3633 {
3634 if (lp->lastWord != NULL) /* go to the beginning of the last word. */
3635 currentX = actualX = lp->x + lp->lastWord->x;
3636 else
3637 currentX = actualX = lp->x;
3638 }
3639 else
3640 {
3641 if ((closestWord != NULL) && (closestWord->prev != NULL))
3642 currentX = actualX = lp->x + closestWord->prev->x;
3643
3644 /* should be here if we're in a line that has no words or this is the first line. */
3645 else
3646 {
3647 if (lp->prev != NULL)
3648 {
3649 lp = lp->prev; /* go to prev line. */
3650 currentX = actualX = lp->x + lp->bbox.width;
3651 currentY = lp->y + lp->bbox.ascent;
3652 }
3653 else
3654 {
3655 /* already at first line. */
3656 currentX = actualX = lp->x;
3657 XBell(XtDisplay(cw), 0);
3658 }
3659 }
3660 }
3661
3662 UpdateCursor(cw, lp, currentX, actualX, currentY);
3663 }
3664
3665
3666 /*----------------------------------------------------------------------*
3667 | MoveRight |
3668 | Note, cursor is always at the baseline of the line. |
3669 *----------------------------------------------------------------------*/
MoveRight(Widget w,XEvent * event,String * params,Cardinal * numParams)3670 static void MoveRight (Widget w, XEvent* event, String* params, Cardinal* numParams)
3671 {
3672 XmMultiTextWidget cw = (XmMultiTextWidget) w;
3673 int actualX;
3674 int currentX;
3675 int currentY = cw->multiText.cursorY;
3676 LineList lp;
3677 WordList closestWord;
3678
3679
3680 if (cw->multiText.textIsSelected) DeselectAll(cw);
3681
3682 lp = cw->multiText.currentLine;
3683
3684 ClosestPosition(cw, lp, &closestWord, cw->multiText.actualX);
3685 if (closestWord != NULL)
3686 {
3687 if (closestWord->next != NULL)
3688 currentX = actualX = closestWord->next->x + lp->x;
3689 else
3690 currentX = actualX = lp->x + lp->bbox.width;
3691 }
3692 else
3693 {
3694 /* scrolled past end of line - move to beginning of next line if there is one. */
3695 if (lp->next == NULL)
3696 {
3697 currentX = actualX = lp->x + lp->bbox.width;
3698 XBell(XtDisplay(w), 0);
3699 }
3700 else
3701 {
3702 lp = lp->next; /* go to next line. */
3703 currentX = actualX = lp->x;
3704 currentY = lp->y + lp->bbox.ascent;
3705 }
3706 }
3707
3708 UpdateCursor(cw, lp, currentX, actualX, currentY);
3709 }
3710
3711
3712 #define cursor_width 7
3713 #define cursor_height 5
3714 /*----------------------------------------------------------------------*
3715 | MakeCursorPixmaps |
3716 | this routine creates (or updates) the cursor's fg and bg pixmaps. |
3717 *----------------------------------------------------------------------*/
MakeCursorPixmaps(XmMultiTextWidget cw)3718 static void MakeCursorPixmaps (XmMultiTextWidget cw)
3719 {
3720 if (cw->multiText.cursorFg == None)
3721 {
3722 static char cursor_bits[] = {0x08, 0x1c, 0x3e, 0x7f, 0x77};
3723
3724 cw->multiText.cursorFg =
3725 XCreatePixmapFromBitmapData(XtDisplay(cw), XtWindow(cw),
3726 cursor_bits, cursor_width, cursor_height,
3727 cw->multiText.cursorColor,
3728 None,
3729 DefaultDepthOfScreen(XtScreen(cw)));
3730 cw->multiText.cursorMask =
3731 XCreatePixmapFromBitmapData(XtDisplay(cw), XtWindow(cw),
3732 cursor_bits, cursor_width, cursor_height,
3733 WhitePixelOfScreen(XtScreen(cw)),
3734 None,
3735 1);
3736 }
3737
3738 if (cw->multiText.cursorBg == None)
3739 cw->multiText.cursorBg = XCreatePixmap(XtDisplay(cw), XtWindow(cw),
3740 cursor_width, cursor_height,
3741 DefaultDepthOfScreen(XtScreen(cw)));
3742
3743 /* grab the region under the cursor and store it into the cursorBg field. */
3744 XCopyArea(XtDisplay(cw), XtWindow(cw), cw->multiText.cursorBg, cw->multiText.cursorGC,
3745 cw->multiText.actualX, cw->multiText.cursorY, cursor_width, cursor_height,
3746 0, 0);
3747 }
3748
3749
3750
3751 /*----------------------------------------------------------------------*
3752 | BlinkCursor |
3753 *----------------------------------------------------------------------*/
BlinkCursor(XmMultiTextWidget cw)3754 static void BlinkCursor (XmMultiTextWidget cw)
3755 {
3756 cw->multiText.blinkTimeOutID = 0;
3757
3758 if ((cw->multiText.showCursor) &&
3759 (XtIsRealized((Widget)cw) && !cw->multiText.textIsSelected && !cw->multiText.selecting))
3760 {
3761 /* this only gets called once. */
3762 if (cw->multiText.cursorFg == None)
3763 {
3764 MakeCursorPixmaps(cw);
3765 cw->multiText.oldX = cw->multiText.actualX;
3766 cw->multiText.oldY = cw->multiText.cursorY;
3767 }
3768
3769 XCopyArea(XtDisplay(cw), cw->multiText.cursorBg, XtWindow(cw), cw->multiText.cursorGC,
3770 0, 0, cursor_width, cursor_height,
3771 cw->multiText.oldX, cw->multiText.oldY);
3772
3773 if ((cw->multiText.oldX != cw->multiText.actualX) || (cw->multiText.oldY != cw->multiText.cursorY))
3774 {
3775 cw->multiText.blinkState = FALSE;
3776 MakeCursorPixmaps(cw);
3777 }
3778
3779 if (!cw->multiText.blinkState)
3780 {
3781 XSetClipMask (XtDisplay(cw), cw->multiText.cursorGC, cw->multiText.cursorMask);
3782 XSetClipOrigin(XtDisplay(cw), cw->multiText.cursorGC, cw->multiText.actualX, cw->multiText.cursorY);
3783
3784 XCopyArea(XtDisplay(cw), cw->multiText.cursorFg, XtWindow(cw), cw->multiText.cursorGC,
3785 0, 0, cursor_width, cursor_height,
3786 cw->multiText.actualX, cw->multiText.cursorY);
3787 XSetClipMask (XtDisplay(cw), cw->multiText.cursorGC, None);
3788
3789 cw->multiText.oldX = cw->multiText.actualX;
3790 cw->multiText.oldY = cw->multiText.cursorY;
3791 }
3792
3793 cw->multiText.blinkState = !cw->multiText.blinkState;
3794 }
3795
3796
3797 cw->multiText.blinkTimeOutID =
3798 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)cw), cw->multiText.blinkRate, (XtTimerCallbackProc)BlinkCursor, cw);
3799 }
3800
3801
3802
3803 /*----------------------------------------------------------------------*
3804 | TurnOffCursor |
3805 *----------------------------------------------------------------------*/
TurnOffCursor(XmMultiTextWidget cw)3806 static void TurnOffCursor (XmMultiTextWidget cw)
3807 {
3808 cw->multiText.cursorAvailable = FALSE;
3809
3810 if (cw->multiText.blinkTimeOutID != 0)
3811 {
3812 XtRemoveTimeOut(cw->multiText.blinkTimeOutID);
3813 cw->multiText.blinkTimeOutID = 0;
3814 }
3815
3816 if (cw->multiText.blinkState == ON)
3817 {
3818 BlinkCursor(cw);
3819 XtRemoveTimeOut(cw->multiText.blinkTimeOutID);
3820 cw->multiText.blinkTimeOutID = 0;
3821 }
3822
3823 /* clearout the pixmaps. */
3824 if (cw->multiText.cursorFg != None)
3825 {
3826 XFreePixmap(XtDisplay(cw), cw->multiText.cursorFg);
3827 XFreePixmap(XtDisplay(cw), cw->multiText.cursorBg);
3828 XFreePixmap(XtDisplay(cw), cw->multiText.cursorMask);
3829 }
3830 cw->multiText.cursorFg = None;
3831 cw->multiText.cursorBg = None;
3832 cw->multiText.cursorMask = None;
3833 }
3834
3835
3836
3837 /*----------------------------------------------------------------------*
3838 | TurnOnCursor |
3839 *----------------------------------------------------------------------*/
TurnOnCursor(XmMultiTextWidget cw)3840 static void TurnOnCursor (XmMultiTextWidget cw)
3841 {
3842 cw->multiText.cursorAvailable = TRUE;
3843 if (cw->multiText.blinkTimeOutID != 0)
3844 {
3845 XtRemoveTimeOut(cw->multiText.blinkTimeOutID);
3846 cw->multiText.blinkTimeOutID = 0;
3847 }
3848 BlinkCursor(cw);
3849 }
3850
3851
3852
3853 /*##########################################################################################*
3854 # O U T P U T R O U T I N E S F O R U S E R I N P U T #
3855 # ... future work... #
3856 *##########################################################################################*/
3857
3858
3859
3860 /*-----------------------========================-----------------------*
3861 | KeyPush action procedure |
3862 | This routine is active if the MultiText widget is editable. There |
3863 | is currently no checking for this case. |
3864 | |
3865 *-----------------------========================-----------------------*/
KeyPush(Widget w,XEvent * event,String * params,Cardinal * numParams)3866 static void KeyPush (Widget w, XEvent* event, String* params, Cardinal* numParams)
3867 {
3868 KeySym ks;
3869 char *str = " ";
3870
3871 XLookupString(&event->xkey, str, 1, &ks, NULL);
3872
3873 switch (*str)
3874 {
3875 case CR:
3876 printf("<CR>\n"); break;
3877 case TAB:
3878 printf("<TAB>"); break;
3879 case CTRL_C:
3880 printf("<CTRL_C>\n"); break;
3881 case SPACE:
3882 printf("<space>"); break;
3883 case BACKSPACE:
3884 printf("<backspace>"); break;
3885 default:
3886 if (isgraph(*str)) printf("%c", *str);
3887 }
3888
3889 /*
3890 XmMultiTextAppendChar(w, str[0]);
3891 */
3892 }
3893
3894
3895 /*-----------------------------=========--------------------------------*
3896 | NewLineCR |
3897 | |
3898 *-----------------------------=========--------------------------------*/
3899 static
NewLineCR(Widget w,XEvent * event,String * params,Cardinal * numParams)3900 void NewLineCR (Widget w, XEvent* event, String* params, Cardinal* numParams)
3901 {
3902 }
3903
3904
3905 /*----------------------------===========-------------------------------*
3906 | InsertSpace |
3907 | |
3908 *----------------------------===========-------------------------------*/
3909 static
InsertSpace(Widget w,XEvent * event,String * params,Cardinal * numParams)3910 void InsertSpace (Widget w, XEvent* event, String* params, Cardinal* numParams)
3911 {
3912 }
3913
3914
3915 /*------------------------------=====-----------------------------------*
3916 | Dummy |
3917 | |
3918 *------------------------------=====-----------------------------------*/
3919 static
Dummy(Widget w,XEvent * event,String * params,Cardinal * numParams)3920 void Dummy (Widget w, XEvent* event, String* params, Cardinal* numParams)
3921 {
3922 }
3923