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 #include "DXStrings.h"
14 #include "Application.h"
15 #include "SetDecoratorTextDialog.h"
16 #include "LabelDecorator.h"
17 #include "Network.h"
18 #include <Xm/RowColumn.h>
19 #include <Xm/PushB.h>
20 #include <Xm/PushBG.h>
21 #include <Xm/Form.h>
22 #include <Xm/SeparatoG.h>
23 #include <Xm/Text.h>
24 #include <Xm/DrawingA.h>
25 #include <Xm/DialogS.h>
26 #include <Xm/ArrowB.h>
27 #include <Xm/Label.h>
28
29 #include <ctype.h> // for ispunct
30
31 #define ORIG_MINWIDTH 620
32 #define ARROW_RIGHTMOST_POS 60
33
34 boolean SetDecoratorTextDialog::ClassInitialized = FALSE;
35
36 String SetDecoratorTextDialog::DefaultResources[] =
37 {
38 "*dialogTitle: Control Panel comment...\n",
39 "*justifyOM.labelString: Justification:",
40 "*justifyOM.sensitive: False",
41 "*colorOM.labelString: Text Color:",
42 "*fontOM.labelString: Font:",
43 "*editorText.columns: 40",
44 "*XmPushButtonGadget.traversalOn: False",
45 "*XmPushButton.traversalOn: False",
46 "*arrowLabel.marginWidth: 0",
47 "*arrowLabel.marginHeight: 0",
48 "*arrowLabel.marginTop: 0",
49 "*arrowLabel.marginLeft: 0",
50 "*arrowLabel.marginRight: 0",
51 "*arrowLabel.marginBottom: 0",
52
53 "*okButton.labelString: OK",
54 "*applyButton.labelString: Apply",
55 "*restoreButton.labelString: Restore",
56 "*reformatButton.labelString: Reformat",
57 "*cancelButton.labelString: Cancel",
58 "*okButton.width: 80",
59 "*applyButton.width: 80",
60 "*restoreButton.width: 80",
61 "*cancelButton.width: 80",
62 "*reformatButton.width: 80",
63
64 // If the user defines osfActivate (normally to be the return key) in the
65 // virtual bindings (usually in ~/.motifbind), then the text widget doesn't handle
66 // the return key properly. The return key triggers the widget's activate()
67 // method rather than the self-insert() or insert-string() methods.
68 // (Caution: If the translation is split into 2 lines, it breaks.)
69 // - Martin
70 "*editorText.translations: #override None<Key>osfActivate: insert-string(\"\\n\")",
71
72 NULL
73 };
74
75
76 #define DIRTY_COLORS 1
77 #define DIRTY_JUSTIFY 2
78 #define DIRTY_TEXT 4
79 #define DIRTY_FONT 8
80
SetDecoratorTextDialog(Widget parent,boolean,LabelDecorator * dec,const char * name)81 SetDecoratorTextDialog::SetDecoratorTextDialog(Widget parent, boolean ,
82 LabelDecorator *dec, const char* name) :
83 Dialog(name, parent)
84 {
85 this->decorator = dec;
86 this->dirty = DIRTY_COLORS | DIRTY_JUSTIFY | DIRTY_TEXT | DIRTY_FONT;
87 }
88
SetDecoratorTextDialog(Widget parent,boolean,LabelDecorator * dec)89 SetDecoratorTextDialog::SetDecoratorTextDialog(Widget parent,
90 boolean , LabelDecorator *dec) :
91 Dialog("LabelAttributes",parent)
92 {
93 this->decorator = dec;
94 this->dirty = DIRTY_COLORS | DIRTY_JUSTIFY | DIRTY_TEXT | DIRTY_FONT;
95
96 if (!SetDecoratorTextDialog::ClassInitialized) {
97 SetDecoratorTextDialog::ClassInitialized = TRUE;
98 this->installDefaultResources(theApplication->getRootWidget());
99 }
100 }
101
~SetDecoratorTextDialog()102 SetDecoratorTextDialog::~SetDecoratorTextDialog()
103 {
104 }
105
106 //
107 // Install the proper values whenever the dialog box is put onto the screen.
108 //
109 void
post()110 SetDecoratorTextDialog::post()
111 {
112 this->Dialog::post();
113 this->restoreCallback (this);
114 }
115
116 //
117 //
118 boolean
restoreCallback(Dialog *)119 SetDecoratorTextDialog::restoreCallback (Dialog * )
120 {
121 //
122 // text
123 //
124 if (this->dirty & DIRTY_TEXT) {
125 const char* cp = "";
126 if (this->decorator) cp = this->decorator->getLabelValue();
127 //XtRemoveCallback (this->editorText, XmNmodifyVerifyCallback, (XtCallbackProc)
128 // SetDecoratorTextDialog_DirtyTextCB, (XtPointer)this);
129 XmTextSetString (this->editorText, (char*)cp);
130 //XtAddCallback (this->editorText, XmNmodifyVerifyCallback, (XtCallbackProc)
131 // SetDecoratorTextDialog_DirtyTextCB, (XtPointer)this);
132 this->dirty&= ~DIRTY_TEXT;
133 }
134
135 //
136 // alignment
137 //
138 if (this->dirty & DIRTY_JUSTIFY) {
139 int i,nkids;
140 Widget *kids;
141 const char *align;
142 char *cp;
143 boolean isset = FALSE;
144 if (this->decorator) isset = this->decorator->isResourceSet (XmNalignment);
145 if (isset) {
146 align = this->decorator->getResourceString(XmNalignment);
147 } else {
148 align = NULL;
149 }
150 XtVaGetValues (this->justifyPulldown,
151 XmNnumChildren, &nkids, XmNchildren, &kids, NULL);
152 ASSERT (nkids > 0);
153 if ((align) && (align[0])) {
154 for (i=0; i<nkids; i++) {
155 XtVaGetValues (kids[i], XmNuserData, &cp, NULL);
156 if (!strcmp(cp, align)) break;
157 }
158 if (i==nkids) i = nkids - 1;
159 } else {
160 i = nkids - 1;
161 }
162
163 Widget choice = kids[i];
164 XtVaSetValues (this->justifyOM, XmNmenuHistory, kids[i], NULL);
165 this->dirty&= ~DIRTY_JUSTIFY;
166
167 //
168 // If justification is set to left, then enable the reformat button and
169 // disable wordwrap.
170 //
171 ASSERT(choice);
172 XtVaGetValues (choice, XmNuserData, &align, NULL);
173 boolean enab = (strcmp (align, "XmALIGNMENT_BEGINNING") == 0);
174 XtSetSensitive (this->reformat, enab);
175 }
176
177 //
178 // color
179 // The default will be kept in kids[nkids-1]
180 //
181 if (this->dirty & DIRTY_COLORS) {
182 int i,nkids;
183 Widget *kids;
184 char *cp;
185 const char *color;
186 boolean isset = FALSE;
187 if (this->decorator) isset = this->decorator->isResourceSet (XmNforeground);
188 if (isset) {
189 color = this->decorator->getResourceString(XmNforeground);
190 } else {
191 color = NULL;
192 }
193 XtVaGetValues (this->colorPulldown,
194 XmNnumChildren, &nkids, XmNchildren, &kids, NULL);
195 ASSERT (nkids > 0);
196 if ((color) && (color[0])) {
197 for (i=0; i<nkids; i++) {
198 XtVaGetValues (kids[i], XmNuserData, &cp, NULL);
199 if (!strcmp(cp, color)) break;
200 }
201 if (i==nkids) i = nkids - 1;
202 } else {
203 i = nkids - 1;
204 }
205
206 XtVaSetValues (this->colorOM, XmNmenuHistory, kids[i], NULL);
207 this->dirty&= ~DIRTY_COLORS;
208 }
209
210
211 //
212 // font
213 // The default will be kept in kids[nkids-1]
214 //
215 if (this->dirty & DIRTY_FONT) {
216 int i,nkids;
217 Widget *kids;
218 char *cp;
219 const char *font_name = NUL(char*);
220 if (this->decorator) font_name = this->decorator->getFont();
221 XtVaGetValues (this->fontPulldown,
222 XmNnumChildren, &nkids, XmNchildren, &kids, NULL);
223 ASSERT (nkids > 0);
224 if ((font_name) && (font_name[0])) {
225 for (i=0; i<nkids; i++) {
226 XtVaGetValues (kids[i], XmNuserData, &cp, NULL);
227 if (!strcmp(cp, font_name)) break;
228 }
229 if (i==nkids) i = nkids - 1;
230 } else {
231 i = nkids - 1;
232 }
233
234 XtVaSetValues (this->fontOM, XmNmenuHistory, kids[i], NULL);
235 this->dirty&= ~DIRTY_FONT;
236 }
237
238 return TRUE;
239 }
240
241 boolean
okCallback(Dialog *)242 SetDecoratorTextDialog::okCallback (Dialog* )
243 {
244
245 if (this->dirty) {
246 this->decorator->getNetwork()->setFileDirty();
247 }
248
249 if (this->dirty & DIRTY_TEXT) {
250 char *s = XmTextGetString (this->editorText);
251 this->decorator->setLabel(s);
252 XtFree(s);
253 this->dirty&= ~DIRTY_TEXT;
254 this->decorator->postTextGrowthWork();
255 }
256
257 Widget choice;
258 if (this->dirty & DIRTY_JUSTIFY) {
259 char *align;
260 XtVaGetValues (this->justifyOM, XmNmenuHistory, &choice, NULL);
261 ASSERT(choice);
262 XtVaGetValues (choice, XmNuserData, &align, NULL);
263 this->decorator->setResource (XmNalignment, align);
264
265 if (!strcmp(XtName(choice), DEFAULT_SETTING))
266 this->decorator->setResource(XmNalignment, NUL(const char *));
267
268 this->dirty&= ~DIRTY_JUSTIFY;
269 }
270
271 if (this->dirty & DIRTY_COLORS) {
272 char *color;
273 XtVaGetValues (this->colorOM, XmNmenuHistory, &choice, NULL);
274 ASSERT(choice);
275 XtVaGetValues (choice, XmNuserData, &color, NULL);
276 this->decorator->setResource (XmNforeground, color);
277
278 if (!strcmp(XtName(choice), DEFAULT_SETTING))
279 this->decorator->setResource (XmNforeground, NUL(const char *));
280
281 this->dirty&= ~DIRTY_COLORS;
282 }
283
284
285 if (this->dirty & DIRTY_FONT) {
286 char *font_name;
287 XtVaGetValues (this->fontOM, XmNmenuHistory, &choice, NULL);
288 ASSERT(choice);
289 XtVaGetValues (choice, XmNuserData, &font_name, NULL);
290 if (!strcmp(XtName(choice), DEFAULT_SETTING)) {
291 this->decorator->setFont (NUL(const char *));
292 } else {
293 this->decorator->setFont (font_name);
294 }
295 this->dirty&= ~DIRTY_FONT;
296 }
297
298 return TRUE;
299 }
300
301 Widget
createDialog(Widget parent)302 SetDecoratorTextDialog::createDialog(Widget parent)
303 {
304 int n = 0;
305 Widget form;
306 Arg args[20];
307
308 n = 0;
309 XtSetArg (args[n], XmNautoUnmanage, False); n++;
310 XtSetArg (args[n], XmNwidth, ORIG_MINWIDTH); n++;
311 XtSetArg (args[n], XmNminWidth, /*290*/ORIG_MINWIDTH); n++;
312 form = this->CreateMainForm (parent, this->name, args, n);
313 this->negotiated = FALSE;
314
315 n = 0;
316 XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
317 XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
318 XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
319 XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
320 XtSetArg (args[n], XmNrows, 6); n++;
321 XtSetArg (args[n], XmNcolumns, 40); n++;
322 XtSetArg (args[n], XmNbottomOffset, 130); n++;
323 XtSetArg (args[n], XmNtopOffset, 10); n++;
324 XtSetArg (args[n], XmNleftOffset, 6); n++;
325 XtSetArg (args[n], XmNrightOffset, ARROW_RIGHTMOST_POS); n++;
326 XtSetArg (args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
327 XtSetArg (args[n], XmNwordWrap, False); n++;
328 XtSetArg (args[n], XmNscrollHorizontal, False); n++;
329 XtSetArg (args[n], XmNmappedWhenManaged, False); n++;
330 this->editor_magic = XmCreateScrolledText (form, "editorText", args, n);
331 XtManageChild (this->editor_magic);
332
333 n = 0;
334 XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
335 XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
336 XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
337 XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
338 XtSetArg (args[n], XmNrows, 6); n++;
339 XtSetArg (args[n], XmNcolumns, 40); n++;
340 XtSetArg (args[n], XmNbottomOffset, 130); n++;
341 XtSetArg (args[n], XmNtopOffset, 10); n++;
342 XtSetArg (args[n], XmNleftOffset, 6); n++;
343 XtSetArg (args[n], XmNrightOffset, 6); n++;
344 XtSetArg (args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
345 XtSetArg (args[n], XmNwordWrap, False); n++;
346 XtSetArg (args[n], XmNscrollHorizontal, False); n++;
347 this->editorText = XmCreateScrolledText (form, "editorText", args, n);
348 XtManageChild (this->editorText);
349 XtAddCallback (this->editorText, XmNmodifyVerifyCallback, (XtCallbackProc)
350 SetDecoratorTextDialog_DirtyTextCB, (XtPointer)this);
351
352
353 n = 0;
354 XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
355 XtSetArg (args[n], XmNtopWidget, XtParent(this->editorText)); n++;
356 XtSetArg (args[n], XmNtopOffset, 30); n++;
357 XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
358 XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
359 Widget sep1 = XmCreateSeparatorGadget (form, "separator", args, n);
360 XtManageChild (sep1);
361
362 //
363 // Add an arrow button for resizing the text.
364 //
365 n = 0;
366 XtSetArg (args[n], XmNarrowDirection, XmARROW_UP); n++;
367 XtSetArg (args[n], XmNshadowThickness, 0); n++;
368 XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
369 XtSetArg (args[n], XmNbottomWidget, sep1); n++;
370 XtSetArg (args[n], XmNbottomOffset, 2); n++;
371 XtSetArg (args[n], XmNleftAttachment, XmATTACH_NONE); n++;
372 XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
373 XtSetArg (args[n], XmNrightOffset, ARROW_RIGHTMOST_POS); n++;
374 this->resize_arrow = XmCreateArrowButton (form, "resizeArrow", args, n);
375 XtManageChild (this->resize_arrow);
376 XtAddEventHandler (this->resize_arrow, Button1MotionMask, False,
377 (XtEventHandler)SetDecoratorTextDialog_ArrowMotionEH, (XtPointer)this);
378 XtAddCallback (this->resize_arrow, XmNarmCallback, (XtCallbackProc)
379 SetDecoratorTextDialog_StartPosCB, (XtPointer)this);
380 //XtAddCallback (this->resize_arrow, XmNactivateCallback, (XtCallbackProc)
381 // SetDecoratorTextDialog_EndPosCB, (XtPointer)this);
382 XtAddCallback (this->resize_arrow, XmNdisarmCallback, (XtCallbackProc)
383 SetDecoratorTextDialog_EndPosCB, (XtPointer)this);
384
385 XmString xmstr = XmStringCreateLtoR ("margin\nposition", "small_bold");
386 n = 0;
387 XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
388 XtSetArg (args[n], XmNbottomWidget, sep1); n++;
389 XtSetArg (args[n], XmNbottomOffset, 0); n++;
390 XtSetArg (args[n], XmNleftAttachment, XmATTACH_NONE); n++;
391 XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
392 XtSetArg (args[n], XmNrightOffset, 4); n++;
393 XtSetArg (args[n], XmNlabelString, xmstr); n++;
394 XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
395 this->resize_arrow_label = XmCreateLabel (form, "arrowLabel", args, n);
396 XmStringFree(xmstr);
397 XtManageChild (this->resize_arrow_label);
398
399
400 n = 0;
401 XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
402 XtSetArg (args[n], XmNtopWidget, sep1); n++;
403 XtSetArg (args[n], XmNtopOffset, 10); n++;
404 XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
405 XtSetArg (args[n], XmNleftOffset, 6); n++;
406 XtSetArg (args[n], XmNsubMenuId, this->createColorMenu(form)); n++;
407 this->colorOM = XmCreateOptionMenu (form, "colorOM", args, n);
408 XtManageChild (this->colorOM);
409
410 n = 0;
411 XtSetArg (args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
412 XtSetArg (args[n], XmNtopWidget, this->colorOM); n++;
413 XtSetArg (args[n], XmNtopOffset, 0); n++;
414 XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
415 XtSetArg (args[n], XmNleftWidget, this->colorOM); n++;
416 XtSetArg (args[n], XmNleftOffset, 10); n++;
417 //XtSetArg (args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
418 //XtSetArg (args[n], XmNrightWidget, this->justifyOM); n++;
419 //XtSetArg (args[n], XmNrightOffset, 10); n++;
420 XtSetArg (args[n], XmNsubMenuId, this->createFontMenu(form)); n++;
421 this->fontOM = XmCreateOptionMenu (form, "fontOM", args, n);
422 XtManageChild (this->fontOM);
423
424 n = 0;
425 XtSetArg (args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
426 XtSetArg (args[n], XmNtopWidget, this->colorOM); n++;
427 XtSetArg (args[n], XmNtopOffset, 0); n++;
428 XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
429 XtSetArg (args[n], XmNrightOffset, 6); n++;
430 XtSetArg (args[n], XmNsubMenuId, this->createJustifyMenu(form)); n++;
431 this->justifyOM = XmCreateOptionMenu (form, "justifyOM", args, n);
432 XtManageChild (this->justifyOM);
433
434 n = 0;
435 XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
436 XtSetArg (args[n], XmNtopWidget, colorOM); n++;
437 XtSetArg (args[n], XmNtopOffset, 10); n++;
438 XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
439 XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
440 Widget sep2 = XmCreateSeparatorGadget (form, "separator", args, n);
441 XtManageChild (sep2);
442
443 n = 0;
444 XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
445 XtSetArg (args[n], XmNtopWidget, sep2); n++;
446 XtSetArg (args[n], XmNtopOffset, 2); n++;
447 XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
448 XtSetArg (args[n], XmNleftOffset, 2); n++;
449 XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
450 XtSetArg (args[n], XmNrightOffset, 2); n++;
451 XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
452 XtSetArg (args[n], XmNbottomOffset, 2); n++;
453 Widget button_form = XmCreateForm (form, "bForm", args, n);
454 XtManageChild (button_form);
455
456 n = 0;
457 XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
458 XtSetArg (args[n], XmNtopOffset, 12); n++;
459 XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
460 XtSetArg (args[n], XmNleftOffset, 12); n++;
461 this->ok = XmCreatePushButton (button_form, "okButton", args, n);
462 XtManageChild (this->ok);
463
464 n = 0;
465 XtSetArg (args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
466 XtSetArg (args[n], XmNtopWidget, this->ok); n++;
467 XtSetArg (args[n], XmNtopOffset, 0); n++;
468 XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
469 XtSetArg (args[n], XmNleftWidget, this->ok); n++;
470 XtSetArg (args[n], XmNleftOffset, 10); n++;
471 this->apply = XmCreatePushButton (button_form, "applyButton", args, n);
472 XtManageChild (this->apply);
473 XtAddCallback (this->apply, XmNactivateCallback, (XtCallbackProc)
474 SetDecoratorTextDialog_ApplyCB, (XtPointer)this);
475
476 n = 0;
477 XtSetArg (args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
478 XtSetArg (args[n], XmNtopWidget, this->ok); n++;
479 XtSetArg (args[n], XmNtopOffset, 0); n++;
480 XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
481 XtSetArg (args[n], XmNrightOffset, 12); n++;
482 this->cancel = XmCreatePushButton (button_form, "cancelButton", args, n);
483 XtManageChild (this->cancel);
484
485 n = 0;
486 XtSetArg (args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
487 XtSetArg (args[n], XmNtopWidget, this->cancel); n++;
488 XtSetArg (args[n], XmNtopOffset, 0); n++;
489 XtSetArg (args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
490 XtSetArg (args[n], XmNrightWidget, this->cancel); n++;
491 XtSetArg (args[n], XmNrightOffset, 10); n++;
492 this->restore = XmCreatePushButton (button_form, "restoreButton", args, n);
493 XtManageChild (this->restore);
494 XtAddCallback (this->restore, XmNactivateCallback, (XtCallbackProc)
495 SetDecoratorTextDialog_RestoreCB, (XtPointer)this);
496
497 n = 0;
498 XtSetArg (args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
499 XtSetArg (args[n], XmNtopWidget, this->cancel); n++;
500 XtSetArg (args[n], XmNtopOffset, 0); n++;
501 XtSetArg (args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
502 XtSetArg (args[n], XmNrightWidget, this->restore); n++;
503 XtSetArg (args[n], XmNrightOffset, 10); n++;
504 this->reformat = XmCreatePushButton (button_form, "reformatButton", args, n);
505 XtManageChild (this->reformat);
506 XtAddCallback (this->reformat, XmNactivateCallback, (XtCallbackProc)
507 SetDecoratorTextDialog_ReformatCB, (XtPointer)this);
508
509 return form;
510 }
511
512 //
513 // Things inside SHOW_IT_NOW ifdefs will set the corresponding resource value
514 // into the button so that the user sees it without having to set the value
515 // into the decorator. These things are turned off right now because turning
516 // them on affects widget size which makes the option menus unequal in size.
517 //
518 Widget
createColorMenu(Widget parent)519 SetDecoratorTextDialog::createColorMenu(Widget parent)
520 {
521 Widget button;
522 const char **btn_names = this->decorator->getSupportedColorNames();
523 const char **color_values = this->decorator->getSupportedColorValues();
524
525 Arg args[9];
526 int i,n;
527
528 n = 0;
529 this->colorPulldown = XmCreatePulldownMenu (parent, "pulldownMenu", args, n);
530
531 # if SHOW_IT_NOW
532 Pixel fg;
533 XrmValue from, toinout;
534 # endif
535
536 i = 0;
537 while (btn_names[i]) {
538 char *color_value, *btn_name;
539 btn_name = new char[1+strlen(btn_names[i])];
540 strcpy (btn_name, btn_names[i]);
541 color_value = new char[1+strlen(color_values[i])];
542 strcpy (color_value, color_values[i]);
543
544 # if SHOW_IT_NOW
545 from.addr = color_values[i];
546 from.size = 1+strlen(from.addr);
547 toinout.addr = (XPointer)&fg;
548 toinout.size = sizeof(Pixel);
549 XtConvertAndStore(parent, XmRString, &from, XmRPixel, &toinout);
550 # endif
551
552 XmString xmstr = XmStringCreateLtoR (btn_name, "bold");
553
554 n = 0;
555 # if SHOW_IT_NOW
556 XtSetArg (args[n], XmNforeground, fg); n++;
557 # endif
558 XtSetArg (args[n], XmNuserData, color_values[i]); n++;
559 XtSetArg (args[n], XmNlabelString, xmstr); n++;
560 # if SHOW_IT_NOW
561 button = XmCreatePushButton (this->colorPulldown, btn_name, args, n);
562 # else
563 button = XmCreatePushButtonGadget (this->colorPulldown, btn_name, args, n);
564 # endif
565 XtManageChild (button);
566 XtAddCallback (button, XmNactivateCallback, (XtCallbackProc)
567 SetDecoratorTextDialog_DirtyColorsCB, (XtPointer)this);
568
569 XmStringFree(xmstr);
570 delete color_value;
571 delete btn_name;
572
573 i++;
574 }
575
576 return this->colorPulldown;
577 }
578
579
580 Widget
createFontMenu(Widget parent)581 SetDecoratorTextDialog::createFontMenu(Widget parent)
582 {
583 Widget button;
584 Arg args[9];
585 int i,n;
586 #if defined(aviion) || defined(hp700)
587 static
588 #endif
589 char *btn_names[] = {
590 "bold 12 point", "bold 14 point", "bold 18 point", "bold 24 point",
591 "italic 12 point", "italic 14 point", "italic 18 point", "italic 24 point",
592 "medium 12 point", "medium 14 point", "medium 18 point", "medium 24 point",
593 DEFAULT_SETTING
594 };
595
596 // These names must match those used for fontList in IMBApplication.C
597 #if defined(aviion) || defined(hp700)
598 static
599 #endif
600 char *font_names[] = {
601 "small_bold", "bold", "big_bold", "huge_bold",
602 "small_oblique", "oblique", "big_oblique", "huge_oblique",
603 "small_normal", "normal", "big_normal", "huge_normal",
604 XmSTRING_DEFAULT_CHARSET
605 };
606
607 n = 0;
608 this->fontPulldown = XmCreatePulldownMenu (parent, "pulldownMenu", args, n);
609
610 for (i=0; i<XtNumber(btn_names); i++) {
611 # if SHOW_IT_NOW
612 XmString xmstr = XmStringCreateLtoR (btn_names[i], font_names[i]);
613 # endif
614
615 n = 0;
616 XtSetArg (args[n], XmNuserData, font_names[i]); n++;
617 # if SHOW_IT_NOW
618 XtSetArg (args[n], XmNlabelString, xmstr); n++;
619 # endif
620 button = XmCreatePushButton (this->fontPulldown, btn_names[i], args, n);
621 XtManageChild (button);
622 XtAddCallback (button, XmNactivateCallback, (XtCallbackProc)
623 SetDecoratorTextDialog_DirtyFontCB, (XtPointer)this);
624
625 # if SHOW_IT_NOW
626 XmStringFree(xmstr);
627 # endif
628 }
629
630 return this->fontPulldown;
631 }
632
633 Widget
createJustifyMenu(Widget parent)634 SetDecoratorTextDialog::createJustifyMenu (Widget parent)
635 {
636 Widget button;
637 Arg args[9];
638 int i,n;
639
640 #if defined(aviion) || defined(hp700)
641 static
642 #endif
643 char *btn_names[] = {
644 "Left", "Center", "Right",
645 DEFAULT_SETTING
646 };
647
648
649 static char *align_names[4];
650 align_names[0] = "XmALIGNMENT_BEGINNING";
651 align_names[1] = "XmALIGNMENT_CENTER";
652 align_names[2] = "XmALIGNMENT_END";
653 align_names[3] = (char*)this->defaultJustifySetting();
654
655 n = 0;
656 this->justifyPulldown = XmCreatePulldownMenu (parent, "pulldownMenu", args, n);
657
658 for (i=0; i<XtNumber(btn_names); i++) {
659 n = 0;
660 XtSetArg (args[n], XmNuserData, align_names[i]); n++;
661 button = XmCreatePushButtonGadget (this->justifyPulldown, btn_names[i], args, n);
662 XtManageChild (button);
663 XtAddCallback (button, XmNactivateCallback, (XtCallbackProc)
664 SetDecoratorTextDialog_DirtyJustifyCB, (XtPointer)this);
665 }
666
667 return this->justifyPulldown;
668 }
669
670 const char*
defaultJustifySetting()671 SetDecoratorTextDialog::defaultJustifySetting()
672 {
673 static char* def = "XmALIGNMENT_CENTER";
674 return def;
675 }
676
677 extern "C" {
678
679 void
SetDecoratorTextDialog_DirtyColorsCB(Widget,XtPointer cdata,XtPointer)680 SetDecoratorTextDialog_DirtyColorsCB (Widget , XtPointer cdata, XtPointer)
681 {
682 SetDecoratorTextDialog *sdt = (SetDecoratorTextDialog *)cdata;
683
684 ASSERT(sdt);
685 sdt->dirty|= DIRTY_COLORS;
686 }
687
688
689 void
SetDecoratorTextDialog_DirtyJustifyCB(Widget,XtPointer cdata,XtPointer)690 SetDecoratorTextDialog_DirtyJustifyCB (Widget , XtPointer cdata, XtPointer)
691 {
692 SetDecoratorTextDialog *sdt = (SetDecoratorTextDialog *)cdata;
693
694 ASSERT(sdt);
695 sdt->dirty|= DIRTY_JUSTIFY;
696 //
697 // ...a workaround for a bug in libXm in aix 3.2.5. If you
698 // set XmNalignment on anything of the XmLabel variety, the text won't
699 // move. But if you set other resources, then the text will move.
700 //
701 #if defined(ibm6000)
702 sdt->dirty|= DIRTY_TEXT;
703 #endif
704
705
706 //
707 // If justification is set to left, then enable the reformat button
708 //
709 Widget choice;
710 char *align;
711 XtVaGetValues (sdt->justifyOM, XmNmenuHistory, &choice, NULL);
712 ASSERT(choice);
713 XtVaGetValues (choice, XmNuserData, &align, NULL);
714 boolean enab = (strcmp (align, "XmALIGNMENT_BEGINNING") == 0);
715 XtSetSensitive (sdt->reformat, enab);
716
717 XtVaSetValues (sdt->resize_arrow, XmNmappedWhenManaged, (Boolean)enab, NULL);
718 XtVaSetValues (sdt->resize_arrow_label, XmNmappedWhenManaged, (Boolean)enab, NULL);
719 }
720
721 void
SetDecoratorTextDialog_DirtyTextCB(Widget w,XtPointer cdata,XtPointer cbs)722 SetDecoratorTextDialog_DirtyTextCB (Widget w, XtPointer cdata, XtPointer cbs)
723 {
724 SetDecoratorTextDialog *sdt = (SetDecoratorTextDialog *)cdata;
725 XmTextVerifyCallbackStruct *tvcs = (XmTextVerifyCallbackStruct*)cbs;
726 XmTextBlockRec *tb = tvcs->text;
727 boolean enable_it, disable_it;
728
729 ASSERT(sdt);
730 sdt->dirty|= DIRTY_TEXT;
731
732 enable_it = disable_it = FALSE;
733 boolean isSensitive = XtIsSensitive(sdt->justifyOM);
734
735 //
736 // If you're inserting a newline and the menu is insensitive...
737 // you're done and you can just turn on the menu.
738 //
739 if ((tb->length) && (tb->ptr) && (!isSensitive) &&
740 (strchr(tb->ptr, (int)'\n')) &&
741 (tvcs->startPos >= tvcs->currInsert)) {
742 enable_it = True;
743
744 //
745 // else if you're erasing a chunk and the menu is sensitive, then
746 // count the lines exclusive of the erased chunk.
747 // The chars between startPos and endPos are going away.
748 //
749 } else if ((tb->length==0) && (isSensitive)) {
750 char *cp = XmTextGetString (w);
751 int i,len = ((cp&&cp[0])?strlen(cp):0);
752 int lines = 0;
753
754 for (i=0; i<len; i++) {
755 if ((i<tvcs->startPos) || (i>=tvcs->endPos))
756 if (cp[i] == '\n') lines++;
757 if (lines>=1) break;
758 }
759
760 if (lines<1) disable_it = TRUE;
761 XtFree(cp);
762
763 //
764 // else you're replacing a chunk and you must count lines exclusive
765 // of the erasure and inclusive of the insertion.
766 //
767 } else if (isSensitive) {
768 char *cp = XmTextGetString (w);
769 int i,len = ((cp&&cp[0])?strlen(cp):0);
770 int lines = 0;
771
772 for (i=0; i<len; i++) {
773 if ((i<tvcs->startPos) || (i>=tvcs->endPos))
774 if (cp[i] == '\n') lines++;
775 }
776
777 for (i=0; i<tb->length; i++) {
778 if (tb->ptr[i] == '\n') lines++;
779 if (lines>=1) break;
780 }
781
782 if (lines<1) disable_it = TRUE;
783 XtFree(cp);
784 }
785
786 ASSERT (!(enable_it && disable_it));
787 if (enable_it) {
788 XtSetSensitive (sdt->justifyOM, True);
789
790 //
791 // If justification is set to left, then enable the reformat button
792 //
793 Widget choice;
794 char *align;
795 XtVaGetValues (sdt->justifyOM, XmNmenuHistory, &choice, NULL);
796 ASSERT(choice);
797 XtVaGetValues (choice, XmNuserData, &align, NULL);
798 boolean enab = (strcmp (align, "XmALIGNMENT_BEGINNING") == 0);
799 XtSetSensitive (sdt->reformat, enab);
800 } else if (disable_it) {
801 int nkids;
802 Widget *kids;
803 XtVaGetValues (sdt->justifyPulldown,
804 XmNnumChildren, &nkids, XmNchildren, &kids, NULL);
805 ASSERT (nkids > 0);
806
807 XtVaSetValues (sdt->justifyOM, XmNmenuHistory, kids[nkids-1], NULL);
808 sdt->dirty|= DIRTY_JUSTIFY;
809 XtSetSensitive (sdt->justifyOM, False);
810 XtSetSensitive (sdt->reformat, False);
811 }
812
813 tvcs->doit = True;
814 }
815
816 void
SetDecoratorTextDialog_DirtyFontCB(Widget,XtPointer cdata,XtPointer)817 SetDecoratorTextDialog_DirtyFontCB (Widget , XtPointer cdata, XtPointer)
818 {
819 SetDecoratorTextDialog *sdt = (SetDecoratorTextDialog *)cdata;
820
821 ASSERT(sdt);
822 sdt->dirty|= DIRTY_FONT;
823 }
824
825
826 void
SetDecoratorTextDialog_ApplyCB(Widget,XtPointer cdata,XtPointer)827 SetDecoratorTextDialog_ApplyCB (Widget , XtPointer cdata, XtPointer)
828 {
829 SetDecoratorTextDialog *sdt = (SetDecoratorTextDialog *)cdata;
830
831 ASSERT(sdt);
832 sdt->okCallback (sdt);
833 }
834
835 void
SetDecoratorTextDialog_RestoreCB(Widget,XtPointer cdata,XtPointer)836 SetDecoratorTextDialog_RestoreCB (Widget , XtPointer cdata, XtPointer)
837 {
838 SetDecoratorTextDialog *sdt = (SetDecoratorTextDialog *)cdata;
839
840 ASSERT(sdt);
841 sdt->restoreCallback (sdt);
842 }
843
844
845 void
SetDecoratorTextDialog_ReformatCB(Widget,XtPointer cdata,XtPointer)846 SetDecoratorTextDialog_ReformatCB (Widget , XtPointer cdata, XtPointer)
847 {
848 SetDecoratorTextDialog *sdt = (SetDecoratorTextDialog *)cdata;
849
850 ASSERT(sdt);
851 sdt->reformatCallback (sdt);
852 }
853
854
855 void
SetDecoratorTextDialog_ArrowMotionEH(Widget w,XtPointer cdata,XEvent * xev,Boolean * keep_going)856 SetDecoratorTextDialog_ArrowMotionEH
857 (Widget w, XtPointer cdata, XEvent *xev, Boolean *keep_going)
858 {
859 SetDecoratorTextDialog *sdt = (SetDecoratorTextDialog *)cdata;
860
861 ASSERT(sdt);
862 *keep_going = True;
863
864 if (!xev) return ;
865 if (xev->type != MotionNotify) return ;
866 XMotionEvent* xmo = (XMotionEvent*)xev;
867
868 int diff = sdt->initial_xpos - xmo->x_root;
869 int newofs = sdt->start_pos + diff;
870 if ((newofs > 500) && (sdt->start_pos >= 500)) return ;
871 if ((newofs < ARROW_RIGHTMOST_POS) && (sdt->start_pos <= ARROW_RIGHTMOST_POS)) return ;
872 if (newofs < ARROW_RIGHTMOST_POS) {
873 sdt->start_pos = ARROW_RIGHTMOST_POS;
874 sdt->initial_xpos = xmo->x_root - (ARROW_RIGHTMOST_POS-newofs);
875 } else if (newofs > 500) {
876 sdt->start_pos = 500;
877 sdt->initial_xpos = xmo->x_root - (500-newofs);
878 } else {
879 sdt->initial_xpos = xmo->x_root;
880 sdt->start_pos = newofs;
881 }
882
883 XtVaSetValues (sdt->resize_arrow, XmNrightOffset, sdt->start_pos, NULL);
884 }
885
886
887 void
SetDecoratorTextDialog_StartPosCB(Widget,XtPointer cdata,XtPointer cbs)888 SetDecoratorTextDialog_StartPosCB(Widget , XtPointer cdata, XtPointer cbs)
889 {
890 SetDecoratorTextDialog *sdt = (SetDecoratorTextDialog *)cdata;
891 XmArrowButtonCallbackStruct *abcs = (XmArrowButtonCallbackStruct*)cbs;
892 XEvent *xev = abcs->event;
893
894 if (!xev) return ;
895 if (xev->type != ButtonPress) return ;
896 XButtonEvent* xbe = (XButtonEvent*)xev;
897 sdt->initial_xpos = xbe->x_root;
898
899 ASSERT(sdt);
900 XtVaGetValues (sdt->resize_arrow, XmNrightOffset, &sdt->start_pos, NULL);
901 XtVaSetValues (sdt->getRootWidget(), XmNresizePolicy, XmRESIZE_NONE, NULL);
902 }
903
904
905 void
SetDecoratorTextDialog_EndPosCB(Widget,XtPointer cdata,XtPointer)906 SetDecoratorTextDialog_EndPosCB(Widget , XtPointer cdata, XtPointer)
907 {
908 SetDecoratorTextDialog *sdt = (SetDecoratorTextDialog *)cdata;
909
910 ASSERT(sdt);
911 XtVaSetValues (XtParent(sdt->editor_magic), XmNrightOffset, sdt->start_pos, NULL);
912 sdt->reformatCallback(sdt);
913 }
914
915
916 } // extern C
917
918
919 //
920 // Install the default resources for this class.
921 //
installDefaultResources(Widget baseWidget)922 void SetDecoratorTextDialog::installDefaultResources(Widget baseWidget)
923 {
924 this->setDefaultResources(baseWidget, SetDecoratorTextDialog::DefaultResources);
925 this->Dialog::installDefaultResources( baseWidget);
926 }
927
928
929 //
930 // Connect the dialog to a new decorator. Update the displayed values.
931 //
setDecorator(LabelDecorator * new_lab)932 void SetDecoratorTextDialog::setDecorator(LabelDecorator* new_lab)
933 {
934 this->decorator = new_lab;
935 this->dirty = DIRTY_COLORS | DIRTY_JUSTIFY | DIRTY_TEXT | DIRTY_FONT;
936 this->restoreCallback(this);
937
938 if (!this->decorator) {
939 XtSetSensitive (this->ok, False);
940 XtSetSensitive (this->restore, False);
941 XtSetSensitive (this->apply, False);
942 } else {
943 XtSetSensitive (this->ok, True);
944 XtSetSensitive (this->restore, True);
945 XtSetSensitive (this->apply, True);
946 }
947 }
948
949 //
950 // 1) Make a copy of the text.
951 // 2) Replace all instances of a WhiteSpace which contain only 1 '\n', with one space
952 // 3) loop over new buffer jumping ahead XmNcolumns chars each time and then
953 // back up until work boundary where you insert a '\n'.
954 // - When backing up, look for only a space. This is the normal case. If there is
955 // no space, then settle for ispunct()==1 while scanning ahead.
956 //
957 // This doesn't account for variable width fonts. The value in XmNcolumns is just
958 // an estimate of the number of chars we can accommodate. There is in fact no such
959 // number. In order to do this correctly, we would have to count the pixels used
960 // by each char on the line. Motif supplies a mechanism for that sort of behavior.
961 // It's what you get when you set XmNwordWrap==True. Unfortunately, there isn't
962 // any way to query for the results of Motif's wordwrapping. If there were, then
963 // we would use that instead.
964 //
965 #define IsSpace(q) ((q==' ')||(q=='\t')||(q=='\n'))
reformatCallback(SetDecoratorTextDialog *)966 boolean SetDecoratorTextDialog::reformatCallback(SetDecoratorTextDialog*)
967 {
968 short cols;
969
970 char *spare = XmTextGetString (this->editorText);
971 XtVaGetValues (this->editor_magic, XmNcolumns, &cols, NULL);
972
973 cols+= (cols>>2);
974 if (!spare)
975 return FALSE;
976 int len = strlen(spare);
977 if (!len) {
978 XtFree(spare);
979 return FALSE;
980 }
981
982 //
983 // compress whitespace converting \n to ' '
984 //
985 char* no_extra_space = new char[1+len];
986 int i;
987 boolean was_space = TRUE;
988 boolean was_newline = FALSE;
989 int nxt = 0;
990 for (i=0; i<len; i++) {
991 if (IsSpace(spare[i])) {
992 if (was_space == FALSE) {
993 no_extra_space[nxt++] = ' ';
994 } else if (was_newline) {
995 if (spare[i] == '\n') {
996 no_extra_space[nxt-1] = '\n';
997 no_extra_space[nxt++] = '\n';
998 }
999 } else {
1000 }
1001 was_newline = (spare[i] == '\n');
1002 was_space = TRUE;
1003 } else {
1004 no_extra_space[nxt++] = spare[i];
1005 was_space = FALSE;
1006 was_newline = FALSE;
1007 }
1008 }
1009 no_extra_space[nxt] = '\0';
1010 XtFree(spare);
1011 spare = no_extra_space;
1012
1013 //
1014 // adding back the \n
1015 //
1016 len = nxt;
1017 no_extra_space = new char[nxt<<1];
1018
1019 nxt = 0;
1020 int copied_in_row = 0;
1021 int most_recent_space = 0;
1022 for (i=0; i<len; i++) {
1023 if (copied_in_row == 0) most_recent_space = -1;
1024 boolean line_break = (copied_in_row == cols);
1025 if (line_break) {
1026 //
1027 // How far away is the next space?
1028 //
1029 # define HOW_FAR_TO_LOOK 8
1030 int to_next_space = HOW_FAR_TO_LOOK+1;
1031 int regress = most_recent_space-nxt;
1032 # define PREFER_BACKWARDS -(HOW_FAR_TO_LOOK+4)
1033 if (regress <= PREFER_BACKWARDS) {
1034 int k = i;
1035 while ((spare[k]) &&
1036 (to_next_space<HOW_FAR_TO_LOOK) &&
1037 (IsSpace(spare[k]) == FALSE)) {
1038 k++;
1039 to_next_space++;
1040 }
1041 }
1042
1043 if ((to_next_space < HOW_FAR_TO_LOOK) &&
1044 (most_recent_space > 0) && (regress <= PREFER_BACKWARDS)) {
1045 } else if (most_recent_space > 0) {
1046 //
1047 // If we can regress to a space then do
1048 //
1049 nxt = most_recent_space;
1050 i+= regress;
1051 }
1052 # undef HOW_FAR_TO_LOOK
1053 # undef PREFER_BACKWARDS
1054
1055 //
1056 // This handles the case of... we've regressed or we must move ahead
1057 //
1058 while ((spare[i]) &&
1059 (IsSpace(spare[i]) == FALSE) &&
1060 (ispunct((int)spare[i]) == 0)) {
1061 no_extra_space[nxt++] = spare[i++];
1062 }
1063
1064 no_extra_space[nxt++] = '\n';
1065 if ((spare[i] != '\n') && (spare[i] != ' ')) {
1066 no_extra_space[nxt++] = spare[i];
1067 }
1068 copied_in_row = 0;
1069 } else {
1070 if ((spare[i] == ' ') || (spare[i] == '\t'))
1071 most_recent_space = nxt;
1072 no_extra_space[nxt++] = spare[i];
1073 if (spare[i] == '\n')
1074 copied_in_row = 0;
1075 else
1076 copied_in_row++;
1077 }
1078 }
1079 no_extra_space[nxt] = '\0';
1080 delete spare;
1081
1082 //
1083 // Prepare for kerning
1084 //
1085 this->kern_lines = NULL;
1086 this->kern_lengths = NULL;
1087 this->line_count = 0;
1088
1089 boolean default_justification = FALSE;
1090 Widget choice;
1091 XtVaGetValues (this->justifyOM, XmNmenuHistory, &choice, NULL);
1092 ASSERT(choice);
1093
1094 if (!strcmp(XtName(choice), DEFAULT_SETTING))
1095 default_justification = TRUE;
1096
1097 if (default_justification) {
1098 //
1099 // Use the font in our menu for calculating padding.
1100 //
1101 char *font_name;
1102 Widget choice;
1103 XtVaGetValues (this->fontOM, XmNmenuHistory, &choice, NULL);
1104 ASSERT(choice);
1105 XtVaGetValues (choice, XmNuserData, &font_name, NULL);
1106 spare = this->kern(no_extra_space, font_name);
1107 } else {
1108 spare = no_extra_space;
1109 }
1110
1111 XmTextSetString(this->editorText, spare);
1112 delete spare;
1113
1114 if (this->line_count>1) {
1115 for (i=0; i<this->line_count; i++)
1116 delete this->kern_lines[i];
1117 delete this->kern_lines;
1118 delete this->kern_lengths;
1119 this->kern_lines = NULL;
1120 this->kern_lengths = NULL;
1121 this->line_count = 0;
1122 }
1123
1124 return TRUE;
1125 }
1126
1127
kern(char * src,char * font)1128 char* SetDecoratorTextDialog::kern(char* src, char* font)
1129 {
1130 int i;
1131
1132 if ((!src) || (!src[0])) return src;
1133
1134 XmFontList xmfl = this->decorator->getFontList();
1135
1136 //
1137 // Chop the input into individual lines and measure each one.
1138 //
1139 XmString str1 = XmStringCreateLtoR (src, font);
1140 boolean retVal = this->measureLines(str1, font);
1141 int max_pixel_len = XmStringWidth (xmfl, str1);
1142 XmStringFree(str1);
1143 if (!retVal) return src;
1144
1145
1146 //
1147 // Find the size of a ' ' character.
1148 //
1149 XmString s1 = XmStringCreateLtoR ("H i", font);
1150 XmString s2 = XmStringCreateLtoR ("H i", font);
1151 Dimension w1 = XmStringWidth (xmfl, s1);
1152 Dimension w2 = XmStringWidth (xmfl, s2);
1153 XmStringFree(s1);
1154 XmStringFree(s2);
1155 int size_of_1_space = w2 - w1;
1156 if (size_of_1_space < 1) return src;
1157
1158
1159 //
1160 // If the maximum number of extra spaces required is greater than
1161 // threshold then skip the line. If the line requires more than half
1162 // its length in padding, then skip the line.
1163 //
1164 float threshhold = max_pixel_len * 0.25;
1165
1166 //
1167 // Pad each line appropriately.
1168 //
1169 for (i=0; i<this->line_count; i++) {
1170 int pixel_diff = max_pixel_len - this->kern_lengths[i];
1171 if (pixel_diff == 0) continue;
1172 if (pixel_diff > threshhold) continue;
1173 if (pixel_diff > (this->kern_lengths[i]>>1)) continue;
1174 int needed_spaces = pixel_diff / size_of_1_space;
1175 this->kern_lines[i] =
1176 SetDecoratorTextDialog::Pad (this->kern_lines[i], needed_spaces, 2);
1177 }
1178
1179 //
1180 // reconnect the lines
1181 //
1182 int totlen = 0;
1183 for (i=0; i<this->line_count; i++)
1184 totlen+= strlen(this->kern_lines[i]);
1185 char* newsrc = new char[totlen+1];
1186
1187 totlen = 0;
1188 for (i=0; i<this->line_count; i++) {
1189 int len = strlen(this->kern_lines[i]);
1190 strcpy (&newsrc[totlen], this->kern_lines[i]);
1191 totlen+= len;
1192 newsrc[totlen] = '\0';
1193 }
1194
1195 delete src;
1196 return newsrc;
1197 }
1198
1199 char*
Pad(char * src,int pad,int every_nth)1200 SetDecoratorTextDialog::Pad(char* src, int pad, int every_nth)
1201 {
1202 static char sep_chars[] = {
1203 ',', '?', ';', '!', '@', '#', '*',
1204 '$', '&', '+', '{', '}', '[', ']',
1205 '|', '=', ' ', '\0'
1206 };
1207
1208 ASSERT (src);
1209 if (pad == 0) return src;
1210 ASSERT (pad > 0);
1211 int pads_added = 0;
1212 int len = strlen(src);
1213 char* newsrc = new char[len+1+pad];
1214 int space_cnt = 1;
1215
1216 boolean just_added = FALSE;
1217 int nxt = 0;
1218 int i;
1219 for (i=0; i<len; i++) {
1220 newsrc[nxt++] = src[i];
1221 if (pads_added < pad) {
1222 boolean is_separator = FALSE;
1223 if ((just_added == FALSE) && (every_nth)) {
1224 if (space_cnt == every_nth) {
1225 is_separator = (src[i]==' ');
1226 space_cnt = 1;
1227 } else
1228 space_cnt++;
1229 } else if (just_added == FALSE) {
1230 int j = 0;
1231 while ((is_separator == FALSE) && (sep_chars[j]))
1232 is_separator = (src[i] == sep_chars[j++]);
1233 }
1234
1235 if (is_separator) {
1236 newsrc[nxt++] = ' ';
1237 pads_added++;
1238 just_added = TRUE;
1239 } else
1240 just_added = FALSE;
1241 }
1242 }
1243 newsrc[nxt] = '\0';
1244
1245 delete src;
1246 int remaining = pad - pads_added;
1247 if (pads_added == 0)
1248 return newsrc;
1249 else
1250 return SetDecoratorTextDialog::Pad(newsrc, remaining, (every_nth?every_nth-1:0));
1251 }
1252
1253 //
1254 // null-terminated char * -- the XmNlabelStinrg
1255 //
measureLines(XmString srcString,char * font)1256 boolean SetDecoratorTextDialog::measureLines(XmString srcString, char* font)
1257 {
1258 XmStringContext cxt;
1259 char *text, *tag;
1260 XmStringDirection dir;
1261 int i;
1262
1263 if (!srcString) return FALSE;
1264 this->line_count = XmStringLineCount(srcString);
1265 if (this->line_count<=1)
1266 return FALSE;
1267
1268 if (!XmStringInitContext (&cxt, srcString)) {
1269 XtWarning ("Can't convert compound string.");
1270 return FALSE;
1271 }
1272
1273 this->kern_lines = new String[this->line_count];
1274 this->kern_lengths = new int[this->line_count];
1275 int next_kern_line = 0;
1276 for (i=0; i<this->line_count; i++) {
1277 this->kern_lengths[i] = 0;
1278 this->kern_lines[i] = NUL(String);
1279 }
1280
1281 int os = 0;
1282 unsigned short ukl = 0;
1283 unsigned char* ukv = 0;
1284 XmStringComponentType uktag = 0;
1285 char* label_buf = NUL(char*);
1286 tag = NUL(char*);
1287 while (1) {
1288 int len;
1289 XmStringComponentType retVal =
1290 XmStringGetNextComponent (cxt, &text, &tag, &dir, &uktag, &ukl, &ukv);
1291 if (retVal == XmSTRING_COMPONENT_END) break;
1292 switch (retVal) {
1293 case XmSTRING_COMPONENT_TEXT:
1294 case XmSTRING_COMPONENT_LOCALE_TEXT:
1295 ASSERT (next_kern_line < this->line_count);
1296 len = strlen(text);
1297 label_buf = this->kern_lines[next_kern_line++] =
1298 new char[len+2];
1299 strcpy (&label_buf[os], text);
1300 os+= len;
1301 XtFree(text),text = NUL(char*);
1302 break;
1303 case XmSTRING_COMPONENT_SEPARATOR:
1304 ASSERT (next_kern_line <= this->line_count);
1305 if (!label_buf) {
1306 label_buf = this->kern_lines[next_kern_line++] =
1307 new char[8];
1308 }
1309 label_buf[os++] = '\n';
1310 label_buf[os] = '\0';
1311 os = 0;
1312 label_buf = NUL(char*);
1313 break;
1314 default:
1315 if (tag) XtFree(tag),tag=NUL(char*);
1316 break;
1317 }
1318 }
1319 XmStringFreeContext(cxt);
1320
1321 XmFontList xmfl = this->decorator->getFontList();
1322
1323 for (i=0; i<this->line_count; i++) {
1324 if (this->kern_lines[i] == NUL(char*)) {
1325 this->kern_lines[i] = new char[2];
1326 this->kern_lines[i][0]= '\0';
1327 }
1328
1329 XmString xmstr = XmStringCreateLtoR (this->kern_lines[i], font);
1330 this->kern_lengths[i] = XmStringWidth (xmfl, xmstr);
1331 XmStringFree(xmstr);
1332 }
1333 return TRUE;
1334 }
1335
1336