home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / xpaint-247 / graphic.c < prev    next >
C/C++ Source or Header  |  1997-01-03  |  62KB  |  2,499 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1992, 1993, David Koblas (koblas@netcom.com)           | */
  3. /* | Copyright 1995, 1996 Torsten Martinsen (bullestock@dk-online.dk)  | */
  4. /* |                                       | */
  5. /* | Permission to use, copy, modify, and to distribute this software  | */
  6. /* | and its documentation for any purpose is hereby granted without   | */
  7. /* | fee, provided that the above copyright notice appear in all       | */
  8. /* | copies and that both that copyright notice and this permission    | */
  9. /* | notice appear in supporting documentation.     There is no           | */
  10. /* | representations about the suitability of this software for           | */
  11. /* | any purpose.  this software is provided "as is" without express   | */
  12. /* | or implied warranty.                           | */
  13. /* |                                       | */
  14. /* +-------------------------------------------------------------------+ */
  15.  
  16. /* $Id: graphic.c,v 1.21 1996/09/27 06:17:31 torsten Exp $ */
  17.  
  18. #include <X11/Intrinsic.h>
  19. #include <X11/Shell.h>
  20. #include <X11/StringDefs.h>
  21. #ifndef VMS
  22. #include <X11/Xaw/Form.h>
  23. #include <X11/Xaw/Viewport.h>
  24. #include <X11/Xaw/Box.h>
  25. #include <X11/Xaw/Label.h>
  26. #include <X11/Xaw/Toggle.h>
  27. #include <X11/Xaw/SmeBSB.h>
  28. #include <X11/Xaw/Paned.h>
  29. #else
  30. #include <X11Xaw/Form.h>
  31. #include <X11Xaw/Viewport.h>
  32. #include <X11Xaw/Box.h>
  33. #include <X11Xaw/Label.h>
  34. #include <X11Xaw/Toggle.h>
  35. #include <X11Xaw/SmeBSB.h>
  36. #include <X11Xaw/Paned.h>
  37. #endif
  38. #ifdef HAVE_COLTOG
  39. #include "ColToggle.h"
  40. #endif
  41. #include <stdio.h>
  42. #include <math.h>
  43. #include <limits.h>
  44.  
  45. #ifndef M_PI
  46. #define M_PI        3.14159265358979323846
  47. #endif
  48.  
  49. #ifndef NOSTDHDRS
  50. #include <stdlib.h>
  51. #include <unistd.h>
  52. #endif
  53.  
  54. /*
  55.  * Undefine this if you want the Lookup button to be
  56.  * inside the palette area (not recommended)
  57.  */
  58. #define LOOKUP_OUTSIDE
  59.  
  60. #include "Paint.h"
  61. #include "PaintP.h"
  62.  
  63. #include "xpaint.h"
  64. #include "palette.h"
  65. #include "misc.h"
  66. #include "menu.h"
  67. #include "text.h"
  68. #include "graphic.h"
  69. #include "image.h"
  70. #include "cutCopyPaste.h"
  71. #include "operation.h"
  72. #include "rc.h"
  73. #include "protocol.h"
  74. #include "color.h"
  75. #include "ops.h"
  76.  
  77. #include "rw/rwTable.h"
  78.  
  79. /* Global data */
  80. struct imageprocessinfo ImgProcessInfo =
  81. {
  82.     7,                /* oilArea        */
  83.     20,                /* noiseDelta        */
  84.     2,                /* spreadDistance    */
  85.     4,                /* pixelizeXSize    */
  86.     4,                /* pixelizeYSize    */
  87.     3,                /* despeckleMask    */
  88.     3,                /* smoothMaskSize    */
  89.     20,                /* tilt            */
  90.     50,                /* solarizeThreshold    */
  91.     99,                /* contrastW        */
  92.     2,                /* contrastB        */
  93.     16,                /* quantizeColors      */
  94.     0, 0, 0, 0
  95. };
  96.  
  97. #define PATTERN(name)       \
  98.     (char *)CONCAT(name,_bits), CONCAT(name,_width), CONCAT(name,_height)
  99.  
  100. struct paintWindows {
  101.     Widget paint;
  102.     struct paintWindows *next;
  103.     void *ldata;
  104.     Boolean done;
  105. };
  106.  
  107. typedef struct {
  108.     Widget paint;
  109.     Palette *map;
  110.     Widget primaryBox, secondaryBox;
  111.     Widget primaryList, secondaryList;
  112.     Widget first, second;
  113. } LocalInfo;
  114.  
  115. /*
  116.  *  Forward references
  117.  */
  118. static void makePaletteArea(LocalInfo *, RCInfo *);
  119. static void editPatternCB(Widget, Widget);
  120. static void deletePatternCB(Widget, Widget);
  121.  
  122. /*
  123.  *  Begin menus
  124.  */
  125.  
  126. static PaintMenuItem fileMenu[] =
  127. {
  128. #define SAVE_ITEM 0
  129.     MI_SIMPLE("save"),
  130. #define SAVEAS_ITEM 1
  131.     MI_SIMPLE("saveas"),
  132. #define SAVER_ITEM 2
  133.     MI_SIMPLE("saveregion"),
  134. #define SAVE_CONFIG 3
  135.     MI_SIMPLE("saveconfig"),
  136. #define LOAD_CONFIG 4
  137.     MI_SIMPLE("loadconfig"),
  138. #define REVERT_ITEM 5
  139.     MI_SIMPLE("revert"),
  140. #define CLOSE_ITEM 6
  141.     MI_SIMPLE("close"),
  142. };
  143.  
  144. static PaintMenuItem editMenu[] =
  145. {
  146. #define UNDO_ITEM    0
  147.     MI_SIMPLE("undo"),
  148. #define REDO_ITEM    1
  149.     MI_SIMPLE("redo"),
  150.     MI_SEPERATOR(),
  151. #define CUT_ITEM    3
  152.     MI_SIMPLE("cut"),
  153. #define COPY_ITEM    4
  154.     MI_SIMPLE("copy"),
  155. #define PASTE_ITEM    5
  156.     MI_SIMPLE("paste"),
  157. #define CLEAR_ITEM    6
  158.     MI_SIMPLE("clear"),
  159.     MI_SEPERATOR(),
  160. #define DUP_ITEM    8
  161.     MI_SIMPLE("dup"),
  162. #define SELECT_ALL_ITEM    9
  163.     MI_SIMPLE("all"),
  164. #if 0
  165.     {"lock", NULL, NULL, MF_NONE, 0, NULL},
  166.     {"unlock", NULL, NULL, MF_NONE, 0, NULL},
  167. #endif
  168. };
  169.  
  170. static PaintMenuItem rotateMenu[] =
  171. {
  172.     MI_SEPERATOR(),
  173.     MI_SIMPLE("rotate1"),
  174.     MI_SIMPLE("rotate2"),
  175.     MI_SIMPLE("rotate3"),
  176.     MI_SIMPLE("rotate4"),
  177.     MI_SIMPLE("rotate5"),
  178. };
  179.  
  180. static PaintMenuItem regionMenu[] =
  181. {
  182. #define RG_FLIPX_ITEM    0
  183.     MI_SIMPLE("flipX"),
  184. #define RG_FLIPY_ITEM    1
  185.     MI_SIMPLE("flipY"),
  186.     MI_SEPERATOR(),
  187. #define RG_ROTATETO    3
  188.     MI_RIGHT("rotateTo", XtNumber(rotateMenu), rotateMenu),
  189. #define RG_ROTATE    4
  190.     MI_SIMPLE("rotate"),
  191.     MI_SEPERATOR(),        /* 5 */
  192. #define RG_CROP        6
  193.     MI_SIMPLE("crop"),
  194.     MI_SEPERATOR(),        /* 7 */
  195. #ifdef FEATURE_TILT
  196. #define RG_TILT        8
  197.     MI_SIMPLE("tilt"),
  198.     MI_SEPERATOR(),        /* 9 */
  199. #define RG_RESET    10
  200. #else
  201. #define RG_RESET    8
  202. #endif
  203.     MI_SIMPLE("reset"),
  204. };
  205.  
  206. static PaintMenuItem filterMenu[] =
  207. {
  208. #define RG_LAST_ITEM    0
  209.     MI_SIMPLE("last"),
  210.     MI_SEPERATOR(),        /* 1 */
  211. #define RG_INVERT_ITEM    2
  212.     MI_SIMPLE("invert"),
  213. #define RG_SHARPEN_ITEM    3
  214.     MI_SIMPLE("sharpen"),
  215.   /* remove noise */
  216.     MI_SEPERATOR(),        /* 4 */
  217. #define RG_SMOOTH_ITEM    5
  218.     MI_SIMPLE("smooth"),
  219. #define RG_DIRFILT_ITEM 6
  220.     MI_SIMPLE("dirfilt"),
  221. #define RG_DESPECKLE_ITEM 7
  222.     MI_SIMPLE("despeckle"),
  223.     MI_SEPERATOR(),        /* 8 */
  224. #define RG_EDGE_ITEM    9
  225.     MI_SIMPLE("edge"),
  226. #define RG_EMBOSE_ITEM    10
  227.     MI_SIMPLE("emboss"),
  228. #define RG_OIL_ITEM    11
  229.     MI_SIMPLE("oil"),
  230. #define RG_NOISE_ITEM    12
  231.     MI_SIMPLE("noise"),
  232. #define RG_SPREAD_ITEM    13
  233.     MI_SIMPLE("spread"),
  234. #define RG_PIXELIZE_ITEM  14
  235.     MI_SIMPLE("pixelize"),
  236.   /* special fx */
  237. #define RG_BLEND_ITEM    15
  238.     MI_SIMPLE("blend"),
  239. #define RG_SOLARIZE_ITEM 16
  240.     MI_SIMPLE("solarize"),
  241.   /* colour manipulation */
  242.     MI_SEPERATOR(),        /* 17 */
  243. #define RG_CONTRAST_ITEM 18
  244.     MI_SIMPLE("contrast"),
  245. #define RG_QUANTIZE_ITEM 19
  246.     MI_SIMPLE("quantize"),
  247. #define RG_TOGREY_ITEM 20
  248.     MI_SIMPLE("togrey"),
  249. };
  250.  
  251. static PaintMenuItem otherMenu[] =
  252. {
  253. #define    FAT_ITEM    0
  254.     MI_SIMPLE("fatbits"),
  255. #define    GRID_ITEM    1
  256.     MI_FLAG("grid", MF_CHECK),
  257. #define    SNAP_ITEM    2
  258.     MI_FLAG("snap", MF_CHECK),
  259. #define    CHSNAP_ITEM    3
  260.     MI_SIMPLE("snapSpacing"),
  261.     MI_SEPERATOR(),        /* 4 */
  262. #define EDIT_BACKGROUND    5
  263.     MI_SIMPLE("background"),
  264.     MI_SEPERATOR(),        /* 6 */
  265. #define    CHSIZE_ITEM    7
  266.     MI_SIMPLE("size"),
  267. #define UNDOSZ_ITEM    8
  268.     MI_SIMPLE("undosize"),
  269. #define    AUTOCROP_ITEM    9
  270.     MI_SIMPLE("autocrop"),
  271. #define    CHZOOM_ITEM    10
  272.     MI_SIMPLE("zoom"),
  273. };
  274.  
  275. static PaintMenuItem helpMenu[] =
  276. {
  277.     MI_SIMPLECB("help", HelpDialog, "canvas"),
  278. };
  279.  
  280. static PaintMenuBar menuBar[] =
  281. {
  282.     {None, "file", XtNumber(fileMenu), fileMenu},
  283.     {None, "edit", XtNumber(editMenu), editMenu},
  284.     {None, "region", XtNumber(regionMenu), regionMenu},
  285.     {None, "filter", XtNumber(filterMenu), filterMenu},
  286.     {None, "other", XtNumber(otherMenu), otherMenu},
  287.     {None, "help", XtNumber(helpMenu), helpMenu},
  288. };
  289.  
  290. static PaintMenuItem paletteMenu[] =
  291. {
  292.     MI_SEPERATOR(),
  293.     MI_SIMPLECB("edit", editPatternCB, NULL),
  294.     MI_SIMPLECB("remove", deletePatternCB, NULL),
  295.     MI_SEPERATOR(),
  296.     MI_SIMPLECB("help", HelpDialog, "canvas.patBox"),
  297. };
  298.  
  299.  
  300. /*
  301.  *  End of menus
  302.  */
  303.  
  304. static struct paintWindows *head = NULL;
  305.  
  306. void
  307. GraphicRemove(Widget paint, XtPointer junk, XtPointer junk2)
  308. {
  309.     struct paintWindows *cur = head, **prev = &head;
  310.  
  311.     while (cur != NULL && cur->paint != paint) {
  312.     prev = &cur->next;
  313.     cur = cur->next;
  314.     }
  315.  
  316.     if (cur == NULL)
  317.     return;
  318.  
  319.     *prev = cur->next;
  320.  
  321.     if (cur->done)
  322.     CurrentOp->remove(cur->paint, cur->ldata);
  323.     XtFree((XtPointer) cur);
  324. }
  325.  
  326. static void
  327. destroyCallback(Widget paint, XtPointer data, XtPointer junk2)
  328. {
  329.     LocalInfo *info = (LocalInfo *) data;
  330.     Colormap cmap;
  331.     Palette *map;
  332.  
  333.     XtVaGetValues(paint, XtNcolormap, &cmap, NULL);
  334.  
  335.     if ((map = PaletteFind(paint, cmap)) != NULL)
  336.     PaletteDelete(map);
  337.     XtFree((XtPointer) info);
  338. }
  339.  
  340. static void
  341. realize(Widget paint, XtPointer ldataArg, XEvent * event, Boolean * junk)
  342. {
  343.     struct paintWindows *cur = (struct paintWindows *) ldataArg;
  344.  
  345.     if (event->type == MapNotify) {
  346.     XtRemoveEventHandler(paint, StructureNotifyMask, False, realize, ldataArg);
  347.     if (CurrentOp != NULL && CurrentOp->add != NULL)
  348.         cur->ldata = CurrentOp->add(paint);
  349.     cur->done = True;
  350.     }
  351. }
  352.  
  353. void
  354. GraphicAdd(Widget paint)
  355. {
  356.     struct paintWindows *new = XtNew(struct paintWindows);
  357.  
  358.     new->next = head;
  359.     head = new;
  360.     new->paint = paint;
  361.     new->ldata = NULL;
  362.     new->done = False;
  363.  
  364.     if (XtIsRealized(paint)) {
  365.     if (CurrentOp != NULL && CurrentOp->add != NULL)
  366.         new->ldata = CurrentOp->add(paint);
  367.     new->done = True;
  368.     } else
  369.     XtAddEventHandler(paint, StructureNotifyMask, False,
  370.               realize, (XtPointer) new);
  371.  
  372.     XtAddCallback(paint, XtNdestroyCallback, GraphicRemove, NULL);
  373. }
  374.  
  375.  
  376. void
  377. GraphicAll(GraphicAllProc func, void *data)
  378. {
  379.     struct paintWindows *cur;
  380.  
  381.     for (cur = head; cur != NULL; cur = cur->next) {
  382.     if (!cur->done)
  383.         continue;
  384.     func(cur->paint, data);
  385.     }
  386. }
  387.  
  388. void
  389. GraphicSetOp(void (*stop) (Widget, void *), void *(*start) (Widget))
  390. {
  391.     struct paintWindows *cur;
  392.  
  393.     for (cur = head; cur != NULL; cur = cur->next) {
  394.     if (stop != NULL)
  395.         stop(cur->paint, cur->ldata);
  396.     if (start != NULL)
  397.         cur->ldata = start(cur->paint);
  398.     }
  399. }
  400.  
  401. void *
  402. GraphicGetData(Widget w)
  403. {
  404.     struct paintWindows *cur;
  405.  
  406.     for (cur = head; cur != NULL; cur = cur->next)
  407.     if (cur->paint == w)
  408.         return cur->ldata;
  409.     return NULL;
  410. }
  411.  
  412. /*
  413.  *  Pattern creation and changing, utilities.
  414.  */
  415. #define PAT_MIN_WH    24
  416.  
  417. static int pattern_min_wh = 0;
  418.  
  419. typedef struct {
  420.     Widget paint;
  421.     Widget widget, widget2;
  422.     int width, height;
  423.     Pixmap pixmap, shownPixmap;
  424.     Pixel pixel;
  425.     LocalInfo *li;
  426. } PatternInfo;
  427.  
  428. static void
  429. patternUpdate(PatternInfo * info, Boolean isFirst)
  430. {
  431.     char *w_fr, *w_fg, *w_pat;
  432.  
  433.     if (isFirst) {
  434.     w_fr = XtNfillRule;
  435.     w_fg = XtNforeground;
  436.     w_pat = XtNpattern;
  437.     } else {
  438.     w_fr = XtNlineFillRule;
  439.     w_fg = XtNlineForeground;
  440.     w_pat = XtNlinePattern;
  441.     }
  442.  
  443.     if (info->pixmap == None) {
  444.     XtVaSetValues(info->paint, w_fg, info->pixel,
  445.               w_fr, FillSolid,
  446.               NULL);
  447.     } else {
  448.     XtVaSetValues(info->paint, w_pat, info->pixmap,
  449.               w_fr, FillTiled,
  450.               NULL);
  451.     }
  452. }
  453.  
  454. static void
  455. setPatternCallback(Widget icon, PatternInfo * info, XtPointer junk2)
  456. {
  457.     Widget rg;
  458.     Boolean state;
  459.  
  460.     XtVaGetValues(icon, XtNstate, &state, XtNradioGroup, &rg, NULL);
  461.  
  462.     if (state == False)
  463.     return;
  464.  
  465.     if (rg == info->li->primaryList || info->li->primaryList == icon)
  466.     patternUpdate(info, True);
  467.     else
  468.     patternUpdate(info, False);
  469. }
  470.  
  471. static void
  472. freePatternInfo(Widget icon, PatternInfo * info)
  473. {
  474.     if (info->pixmap != info->shownPixmap)
  475.     XFreePixmap(XtDisplay(icon), info->shownPixmap);
  476.     if (info->pixmap != None)
  477.     XFreePixmap(XtDisplay(icon), info->pixmap);
  478.  
  479.     XtFree((XtPointer) info);
  480. }
  481.  
  482. static void
  483. installPatternPixmap(PatternInfo * info, Pixmap pix)
  484. {
  485.     XtPointer curPrimary, curSecondary;
  486.  
  487.     curPrimary = XawToggleGetCurrent(info->li->primaryList);
  488.     curSecondary = XawToggleGetCurrent(info->li->secondaryList);
  489.  
  490.     if (curPrimary == (XtPointer) info)
  491.     XawToggleUnsetCurrent(info->li->primaryList);
  492.     if (curSecondary == (XtPointer) info)
  493.     XawToggleUnsetCurrent(info->li->secondaryList);
  494.  
  495.     XtVaSetValues(info->widget, XtNbitmap, pix, NULL);
  496.     XtVaSetValues(info->widget2, XtNbitmap, pix, NULL);
  497.  
  498.     if (curPrimary == (XtPointer) info)
  499.     XawToggleSetCurrent(info->li->primaryList, curPrimary);
  500.     if (curSecondary == (XtPointer) info)
  501.     XawToggleSetCurrent(info->li->secondaryList, curSecondary);
  502. }
  503.  
  504. static void
  505. editSolidOk(Widget paint, PatternInfo * info, XColor * col)
  506. {
  507.     LocalInfo *l = info->li;
  508.  
  509.     StateShellBusy(paint, False);
  510.  
  511.     if (col == NULL)
  512.     return;
  513.  
  514.     if (!PaletteSetPixel(l->map, info->pixel, col)) {
  515.     /*
  516.      *  This will fail for because we are on a static screen
  517.      *   if it is a TrueColor screen change the "icon"
  518.      */
  519.     if (!l->map->isMapped) {
  520.         /*
  521.          *    TrueColor
  522.          */
  523.         Pixel p = PaletteAlloc(l->map, col);
  524.         Display *dpy = XtDisplay(paint);
  525.         GC gc = XCreateGC(dpy, XtWindow(paint), 0, 0);
  526.         Pixmap pix;
  527.         int depth;
  528.  
  529.         XtVaGetValues(info->widget, XtNdepth, &depth, NULL);
  530.  
  531.         pix = XCreatePixmap(dpy, DefaultRootWindow(dpy),
  532.                 pattern_min_wh, pattern_min_wh, depth);
  533.         XSetForeground(dpy, gc, p);
  534.         XFillRectangle(dpy, pix, gc, 0, 0, pattern_min_wh, pattern_min_wh);
  535.  
  536.         info->pixel = p;
  537.         installPatternPixmap(info, pix);
  538.  
  539.         XFreePixmap(dpy, info->shownPixmap);
  540.         info->shownPixmap = pix;
  541.  
  542.         XFreeGC(dpy, gc);
  543.     }
  544.     }
  545. }
  546.  
  547. static void
  548. editPatternAction(Widget w, XEvent * event)
  549. {
  550.     PatternInfo *info;
  551.  
  552.     XtVaGetValues(w, XtNradioData, &info, NULL);
  553.  
  554.     if (info->pixmap == None) {
  555.     LocalInfo *l = (LocalInfo *) info->li;
  556.  
  557. #ifndef VMS
  558.     if (!l->map->readonly || !l->map->isMapped) {
  559. #else
  560.     if (!l->map->Readonly || !l->map->isMapped) {
  561. #endif
  562.         StateShellBusy(l->paint, True);
  563.  
  564.         ColorEditor(l->paint, info->pixel, l->map, True,
  565.             (XtCallbackProc) editSolidOk, (XtPointer) info);
  566.     }
  567.     } else {
  568.     void PatternEdit(Widget, Pixmap, Widget);
  569.  
  570.     PatternEdit(info->paint, info->pixmap, w);
  571.     }
  572. }
  573.  
  574. static void
  575. deletePatternCB(Widget mb, Widget w)
  576. {
  577.     LocalInfo *li;
  578.     PatternInfo *info, *ainfo;
  579.     Widget parent;
  580.     WidgetList children;
  581.     int nchild;
  582.     Boolean setFirst = False;
  583.     Boolean actPrimary = False, actSecondary = False;
  584.  
  585.     XtVaGetValues(w, XtNradioData, &info, NULL);
  586.  
  587.     /*
  588.      *    Check to see if it is active
  589.      */
  590.     ainfo = (PatternInfo *) XawToggleGetCurrent(info->widget);
  591.     if (info == ainfo) {
  592.     XawToggleUnsetCurrent(info->widget);
  593.     actPrimary = True;
  594.     }
  595.     ainfo = (PatternInfo *) XawToggleGetCurrent(info->widget2);
  596.     if (info == ainfo) {
  597.     XawToggleUnsetCurrent(info->widget2);
  598.     actSecondary = True;
  599.     }
  600.     /*    
  601.      *    Make sure there are enough widgets
  602.      */
  603.     XtVaGetValues(parent = XtParent(info->widget),
  604.           XtNnumChildren, &nchild,
  605.           XtNchildren, &children,
  606.           NULL);
  607.     if (nchild == 1) {
  608.     Notice(w, "You must have at least one entry");
  609.     return;
  610.     }
  611.     li = info->li;
  612.     if (info->widget == li->primaryList)
  613.     setFirst = True;
  614.  
  615.     XtDestroyWidget(info->widget);
  616.     XtDestroyWidget(info->widget2);
  617.  
  618.     if (setFirst) {
  619.     XtVaGetValues(parent, XtNchildren, &children, NULL);
  620.     if (children[0] == info->widget)
  621.         li->primaryList = children[1];
  622.     else
  623.         li->primaryList = children[0];
  624.     XtVaGetValues(li->primaryList, XtNradioData, &info, NULL);
  625.     li->secondaryList = info->widget2;
  626.     }
  627.     if (actPrimary) {
  628.     XtVaGetValues(li->primaryList, XtNradioData, &info, NULL);
  629.     XawToggleSetCurrent(li->primaryList, (XtPointer) info);
  630.     }
  631.     if (actSecondary) {
  632.     XtVaGetValues(li->secondaryList, XtNradioData, &info, NULL);
  633.     XawToggleSetCurrent(li->secondaryList, (XtPointer) info);
  634.     }
  635. }
  636.  
  637. static void
  638. editPatternCB(Widget mb, Widget w)
  639. {
  640.     editPatternAction(w, NULL);
  641. }
  642.  
  643.  
  644. /*
  645.  *   Special trick so that during creation of the pattern box
  646.  *    initialization can happen
  647.  */
  648. static LocalInfo *hiddenLocalInfo;
  649.  
  650. Widget
  651. AddPattern(Widget group, Widget paint, Pixmap pix, Pixel pxl)
  652. {
  653.     static XtTranslations trans = None;
  654.     static GC gc = None;
  655.     static Boolean added = False;
  656.     Widget parent, iconA, iconB, box;
  657.     PatternInfo *info = XtNew(PatternInfo);
  658.     Display *dpy = XtDisplay(group);
  659.     int depth;
  660.     char *nm = "pattern";
  661.     char *str;
  662.     XrmValue val;
  663.     
  664.     if (pattern_min_wh == 0)
  665.     if ((XrmGetResource(XtDatabase(XtDisplay(paint)), "Xpaint.patternsize",
  666.                 "XPaint", &str, &val) != 1) ||
  667.         (sscanf((char *) val.addr, "%d", &pattern_min_wh) != 1) ||
  668.         (pattern_min_wh < 4) || (pattern_min_wh > 64))
  669.         pattern_min_wh = PAT_MIN_WH;
  670.     
  671.     if (!added) {
  672.     static XtActionsRec v =
  673.     {"editPattern", (XtActionProc) editPatternAction};
  674.     XtAppAddActions(XtWidgetToApplicationContext(paint), &v, 1);
  675.     added = True;
  676.     }
  677.     if (trans == None)
  678.     trans = XtParseTranslationTable
  679.         ("<BtnDown>,<BtnUp>: set() notify()\n<BtnDown>(2): editPattern()");
  680.  
  681.     if (XtClass(group) == toggleWidgetClass) {
  682.     PatternInfo *tpi;
  683.  
  684.     parent = XtParent(group);
  685.     XtVaGetValues(group, XtNradioData, &tpi, NULL);
  686.     info->li = tpi->li;
  687. #ifdef HAVE_COLTOG
  688.     } else if (XtClass(group) == colToggleWidgetClass) {
  689.     PatternInfo *tpi;
  690.  
  691.     parent = XtParent(group);
  692.     XtVaGetValues(group, XtNradioData, &tpi, NULL);
  693.     info->li = tpi->li;
  694. #endif
  695.     } else {
  696.     parent = group;
  697.     group = None;
  698.     info->li = hiddenLocalInfo;
  699.     }
  700.  
  701.     box = parent;
  702.  
  703.     info->paint = paint;
  704.  
  705.     if (pix != None) {
  706.     GetPixmapWHD(dpy, pix, &info->width, &info->height, &depth);
  707.     info->pixmap = pix;
  708.     if (info->width == 1 && info->height == 1) {
  709.         XImage *xim = XGetImage(XtDisplay(paint), pix, 0, 0, 1, 1,
  710.                     AllPlanes, ZPixmap);
  711.         info->pixel = XGetPixel(xim, 0, 0);
  712.         XDestroyImage(xim);
  713.  
  714.         info->pixmap = None;
  715.         pix = None;
  716.     }
  717.     } else {
  718.     info->pixel = pxl;
  719.     info->pixmap = None;
  720.     XtVaGetValues(parent, XtNdepth, &depth, NULL);
  721.     }
  722.     if (info->pixmap == None)
  723.     nm = "solid";
  724.  
  725.     if (info->pixmap == None) {
  726.     /* XXX Getting a read only GC, and writing to it */
  727.     if (gc == None)
  728.         gc = XtGetGC(paint, 0, 0);
  729.  
  730.     pix = XCreatePixmap(dpy, DefaultRootWindow(dpy),
  731.                 pattern_min_wh, pattern_min_wh, depth);
  732.     XSetForeground(dpy, gc, info->pixel);
  733.     XFillRectangle(dpy, pix, gc, 0, 0, pattern_min_wh, pattern_min_wh);
  734.     } else if (info->width < pattern_min_wh || info->height < pattern_min_wh) {
  735.     int nw = (info->width < pattern_min_wh) ? pattern_min_wh : info->width;
  736.     int nh = (info->height < pattern_min_wh) ? pattern_min_wh : info->height;
  737.     int x, y;
  738.  
  739.     if (gc == None)
  740.         gc = XtGetGC(paint, 0, 0);
  741.  
  742.     pix = XCreatePixmap(dpy, DefaultRootWindow(dpy), nw, nh, depth);
  743.  
  744.     for (y = 0; y < nh; y += info->height)
  745.         for (x = 0; x < nw; x += info->width)
  746.         XCopyArea(dpy, info->pixmap, pix, gc,
  747.               0, 0, info->width, info->height, x, y);
  748.     }
  749. #ifdef HAVE_COLTOG
  750.     if (info->pixmap == None) {
  751.     iconA = XtVaCreateManagedWidget(nm, colToggleWidgetClass,
  752.                     info->li->primaryBox,
  753.                     XtNforeground, info->pixel,
  754.                     XtNradioGroup, info->li->primaryList,
  755.                     XtNtranslations, trans,
  756.                     XtNradioData, info,
  757.                     XtNisSolid, True,
  758.                     NULL);
  759.     iconB = XtVaCreateManagedWidget(nm, colToggleWidgetClass,
  760.                     info->li->secondaryBox,
  761.                     XtNforeground, info->pixel,
  762.                   XtNradioGroup, info->li->secondaryList,
  763.                     XtNtranslations, trans,
  764.                     XtNradioData, info,
  765.                     XtNisSolid, True,
  766.                     NULL);
  767.     } else {
  768. #endif
  769.     iconA = XtVaCreateManagedWidget(nm, toggleWidgetClass,
  770.                     info->li->primaryBox,
  771.                     XtNbitmap, pix,
  772.                     XtNradioGroup, info->li->primaryList,
  773.                     XtNtranslations, trans,
  774.                     XtNradioData, info,
  775.                     NULL);
  776.     iconB = XtVaCreateManagedWidget(nm, toggleWidgetClass,
  777.                     info->li->secondaryBox,
  778.                     XtNbitmap, pix,
  779.                   XtNradioGroup, info->li->secondaryList,
  780.                     XtNtranslations, trans,
  781.                     XtNradioData, info,
  782.                     NULL);
  783. #ifdef HAVE_COLTOG
  784.     }
  785. #endif
  786.  
  787.     if (info->li->primaryList == None)
  788.     info->li->primaryList = iconA;
  789.     if (info->li->secondaryList == None)
  790.     info->li->secondaryList = iconB;
  791.  
  792.     XtAddCallback(iconA, XtNcallback, (XtCallbackProc) setPatternCallback,
  793.           (XtPointer) info);
  794.     XtAddCallback(iconB, XtNcallback, (XtCallbackProc) setPatternCallback,
  795.           (XtPointer) info);
  796.  
  797.     paletteMenu[1].data = (void *) iconA;
  798.     paletteMenu[2].data = (void *) iconA;
  799.     MenuPopupCreate(iconA, XtNumber(paletteMenu), paletteMenu);
  800.     paletteMenu[1].data = (void *) iconB;
  801.     paletteMenu[2].data = (void *) iconB;
  802.     MenuPopupCreate(iconB, XtNumber(paletteMenu), paletteMenu);
  803.  
  804.     info->widget = iconA;
  805.     info->widget2 = iconB;
  806.  
  807.     info->shownPixmap = pix;
  808.     XtAddCallback(iconA, XtNdestroyCallback, (XtCallbackProc) freePatternInfo,
  809.           (XtPointer) info);
  810.  
  811.     return iconA;
  812. }
  813.  
  814. Widget
  815. AddPatternInfo(void *piArg, Pixmap pix, Pixel pxl)
  816. {
  817.     PatternInfo *pi = (PatternInfo *) piArg;
  818.  
  819.     return AddPattern(pi->widget, pi->paint, pix, pxl);
  820. }
  821.  
  822. void
  823. ChangePattern(void *iArg, Pixmap pix)
  824. {
  825.     PatternInfo *info = (PatternInfo *) iArg;
  826.     int depth;
  827.     Display *dpy = XtDisplay(info->paint);
  828.     Pixmap pfree1 = None, pfree2 = None;
  829.  
  830.     GetPixmapWHD(dpy, pix, &info->width, &info->height, &depth);
  831.  
  832.     if (info->pixmap != info->shownPixmap)
  833.     pfree1 = info->shownPixmap;
  834.     if (info->pixmap != None)
  835.     pfree2 = info->pixmap;
  836.  
  837.     info->pixmap = pix;
  838.  
  839.     if (info->width < pattern_min_wh || info->height < pattern_min_wh) {
  840.     int nw = (info->width < pattern_min_wh) ? pattern_min_wh : info->width;
  841.     int nh = (info->height < pattern_min_wh) ? pattern_min_wh : info->height;
  842.     int x, y;
  843.     GC gc = XtGetGC(info->paint, 0, 0);
  844.  
  845.     pix = XCreatePixmap(dpy, DefaultRootWindow(dpy), nw, nh, depth);
  846.  
  847.     for (y = 0; y < nh; y += info->height)
  848.         for (x = 0; x < nw; x += info->width)
  849.         XCopyArea(dpy, info->pixmap, pix, gc,
  850.               0, 0, info->width, info->height, x, y);
  851.     XtReleaseGC(info->paint, gc);
  852.     }
  853.     installPatternPixmap(info, pix);
  854.  
  855.     info->shownPixmap = pix;
  856.  
  857.     if (pfree1 != None)
  858.     XFreePixmap(dpy, pfree1);
  859.     if (pfree2 != None)
  860.     XFreePixmap(dpy, pfree2);
  861. }
  862.  
  863. /*
  864.  *  Save configuration 
  865.  */
  866. static void
  867. saveConfigOkCallback(Widget il, LocalInfo * info, char *file)
  868. {
  869.     Widget parent = XtParent(info->primaryList);
  870.     WidgetList children;
  871.     int nchildren;
  872.     int i;
  873.     FILE *fd;
  874.     Colormap cmap;
  875.  
  876.     XtVaGetValues(parent, XtNchildren, &children,
  877.           XtNnumChildren, &nchildren, NULL);
  878.     XtVaGetValues(GetShell(parent), XtNcolormap, &cmap, NULL);
  879.  
  880.     if (nchildren == 0) {
  881.     Notice(parent, "No information to save");
  882.     return;
  883.     }
  884.     StateSetBusyWatch(True);
  885.  
  886.     if ((fd = fopen(file, "w")) == NULL) {
  887.     Notice(parent, "Unable to open file '%s' for writing", file);
  888.     return;
  889.     }
  890.     fprintf(fd, "reset\n\n");
  891.  
  892.     for (i = 0; i < nchildren; i++) {
  893.     PatternInfo *pi;
  894.  
  895.     pi = NULL;
  896.     XtVaGetValues(children[i], XtNradioData, &pi, NULL);
  897.  
  898.     if (pi == NULL)
  899.         continue;
  900.  
  901.     if (pi->pixmap == None) {
  902.         XColor col;
  903.         int r, g, b;
  904.  
  905.         col.pixel = pi->pixel;
  906.         col.flags = DoRed | DoGreen | DoBlue;
  907.         XQueryColor(XtDisplay(parent), cmap, &col);
  908.         r = (col.red >> 8) & 0xff;
  909.         g = (col.green >> 8) & 0xff;
  910.         b = (col.blue >> 8) & 0xff;
  911.         fprintf(fd, "solid #%02x%02x%02x\n", r, g, b);
  912.     } else {
  913.         Image *image;
  914.  
  915.         fprintf(fd, "pattern BeginData\n");
  916.         image = PixmapToImage(info->paint, pi->pixmap, cmap);
  917.         WriteAsciiPNMfd(fd, image);
  918.         ImageDelete(image);
  919.         fprintf(fd, "\nEndData\n");
  920.     }
  921.     }
  922.  
  923.     fclose(fd);
  924.  
  925.     StateSetBusyWatch(False);
  926. }
  927.  
  928. static void
  929. saveConfigCallback(Widget w, LocalInfo * info, XtPointer junk)
  930. {
  931.     GetFileName(info->paint, 2, ".XPaintrc",
  932.         (XtCallbackProc) saveConfigOkCallback, (XtPointer) info);
  933. }
  934.  
  935. static void
  936. loadConfigOkCallback(Widget il, LocalInfo * info, char *file)
  937. {
  938.     RCInfo *rcInfo = ReadRC(file);
  939.  
  940.     if (rcInfo == NULL) {
  941.     Notice(info->paint, "Unable to open file %s", file);
  942.     return;
  943.     }
  944.     makePaletteArea(info, rcInfo);
  945.  
  946.     FreeRC(rcInfo);
  947. }
  948.  
  949. static void
  950. loadConfigCallback(Widget w, LocalInfo * info, XtPointer junk)
  951. {
  952.     GetFileName(info->paint, 3, ".XPaintrc",
  953.         (XtCallbackProc) loadConfigOkCallback, (XtPointer) info);
  954. }
  955.  
  956. /*
  957.  *  Pattern edit/add callback
  958.  */
  959. static void
  960. addSolidOk(Widget w, LocalInfo * info, XColor * col)
  961. {
  962.     StateShellBusy(w, False);
  963.  
  964.     if (col != NULL) {
  965.     Pixel pix = PaletteAlloc(info->map, col);
  966.  
  967.     AddPattern(info->primaryList, info->paint, None, pix);
  968.     }
  969. }
  970.  
  971. static void
  972. addSolidCallback(Widget w, XtPointer wlArg, XtPointer junk)
  973. {
  974.     LocalInfo *info = (LocalInfo *) wlArg;
  975.     Widget paint = info->paint;
  976.     Pixel bg;
  977.  
  978.     StateShellBusy(paint, True);
  979.  
  980.     XtVaGetValues(paint, XtNbackground, &bg, NULL);
  981.  
  982.     ColorEditor(paint, bg, info->map, False,
  983.         (XtCallbackProc) addSolidOk, (XtPointer) info);
  984. }
  985.  
  986. static void
  987. addPatternCallback(Widget w, XtPointer wlArg, XtPointer junk)
  988. {
  989.     void PatternEdit(Widget, Pixmap, Widget);
  990.     LocalInfo *info = (LocalInfo *) wlArg;
  991.  
  992.     PatternEdit(info->paint, None, info->primaryList);
  993. }
  994.  
  995. static void
  996. lookupPatternCallback(Widget w, XtPointer infoArg, XtPointer junk2)
  997. {
  998.     LocalInfo *info = (LocalInfo *) infoArg;
  999.     int nchildren, i;
  1000.     WidgetList children;
  1001.     Widget icon, list;
  1002.     Colormap cmap;
  1003.     Pixel p;
  1004.     PatternInfo *pi;
  1005.  
  1006.     DoGrabPixel(w, &p, &cmap);
  1007.  
  1008.     if (cmap != info->map->cmap) {
  1009.     XColor col;
  1010.  
  1011.     col.pixel = p;
  1012.     col.flags = DoRed | DoGreen | DoBlue;
  1013.     XQueryColor(XtDisplay(w), cmap, &col);
  1014.     if (!PaletteLookupColor(info->map, &col, &p))
  1015.         p = PaletteAlloc(info->map, &col);
  1016.     }
  1017. #ifndef LOOKUP_OUTSIDE
  1018.     if (XtParent(w) == info->primaryBox)
  1019.     list = info->primaryList;
  1020.     else
  1021.     list = info->secondaryList;
  1022. #else
  1023.     if (XtNameToWidget(XtParent(w), "viewport2.patternRack") == info->primaryBox)
  1024.     list = info->primaryList;
  1025.     else
  1026.     list = info->secondaryList;
  1027. #endif
  1028.  
  1029.     XtVaGetValues(XtParent(list),
  1030.           XtNnumChildren, &nchildren,
  1031.           XtNchildren, &children,
  1032.           NULL);
  1033.  
  1034.     for (i = 0; i < nchildren; i++) {
  1035.     pi = NULL;
  1036.     XtVaGetValues(children[i], XtNradioData, &pi, NULL);
  1037.     if (pi == NULL || pi->pixmap != None)
  1038.         continue;
  1039.  
  1040.     if (pi->pixel == p) {
  1041.         XawToggleSetCurrent(list, (XtPointer) pi);
  1042.         return;
  1043.     }
  1044.     }
  1045.  
  1046.     icon = AddPattern(info->primaryList, info->paint, None, p);
  1047.     XtVaGetValues(icon, XtNradioData, &pi, NULL);
  1048.     XawToggleSetCurrent(list, (XtPointer) pi);
  1049. }
  1050.  
  1051. /*
  1052.  *  Convert RC file information into the pattern box info
  1053.  */
  1054. static void
  1055. makePaletteArea(LocalInfo * info, RCInfo * rcInfo)
  1056. {
  1057.     Widget firstIcon, icon;
  1058.     Widget pattern = info->secondaryBox;
  1059.     XColor col, rgb;
  1060.     int i, j;
  1061.  
  1062.     /*
  1063.      *    Allocate the color entries
  1064.      */
  1065.     rcInfo->colorFlags = (Boolean *) XtCalloc(sizeof(Boolean),
  1066.                           rcInfo->ncolors);
  1067.     rcInfo->colorPixels = (Pixel *) XtCalloc(sizeof(Pixel),
  1068.                          rcInfo->ncolors);
  1069.     for (i = 0; i < rcInfo->ncolors; i++)
  1070.     rcInfo->colorFlags[i] = False;
  1071.  
  1072.     for (i = 0; i < rcInfo->ncolors; i++) {
  1073.     if (XLookupColor(XtDisplay(info->paint), info->map->cmap,
  1074.              rcInfo->colors[i], &col, &rgb) ||
  1075.         XParseColor(XtDisplay(info->paint), info->map->cmap,
  1076.             rcInfo->colors[i], &col)) {
  1077.         rcInfo->colorPixels[i] = PaletteAlloc(info->map, &col);
  1078.         rcInfo->colorFlags[i] = True;
  1079.         for (j = 0; j < i; j++)
  1080.         if (rcInfo->colorPixels[i] == rcInfo->colorPixels[j])
  1081.             rcInfo->colorFlags[i] = False;
  1082.     }
  1083.     }
  1084.  
  1085.     /*
  1086.      *    Sneaky pass to AddPattern()
  1087.      */
  1088.     hiddenLocalInfo = info;
  1089.  
  1090.     firstIcon = pattern;
  1091.  
  1092.     for (i = 0; i < rcInfo->ncolors; i++) {
  1093.     if (!rcInfo->colorFlags[i])
  1094.         continue;
  1095.  
  1096.     icon = AddPattern(firstIcon, info->paint, None, rcInfo->colorPixels[i]);
  1097.  
  1098.     if (firstIcon == pattern)
  1099.         firstIcon = icon;
  1100.     }
  1101.  
  1102.     for (i = 0; i < rcInfo->nimages; i++) {
  1103.     Pixmap pix;
  1104.  
  1105.     rcInfo->images[i]->refCount++;
  1106.     pix = None;
  1107.     ImageToPixmapCmap(rcInfo->images[i], info->paint, &pix, info->map->cmap);
  1108.  
  1109.     icon = AddPattern(firstIcon, info->paint, pix, 0);
  1110.  
  1111.     if (firstIcon == pattern)
  1112.         firstIcon = icon;
  1113.     }
  1114. }
  1115.  
  1116. /*
  1117.  *  First level menu callbacks.
  1118.  */
  1119.  
  1120. static void
  1121. closeOkCallback(Widget shell, XtPointer junk, XtPointer junk2)
  1122. {
  1123.     XtDestroyWidget(shell);
  1124. }
  1125.  
  1126. static void
  1127. genericCancelCallback(Widget shell, XtPointer junk, XtPointer junk2)
  1128. {
  1129. }
  1130.  
  1131. static void
  1132. closeCallback(Widget w, XtPointer paintArg, XtPointer junk2)
  1133. {
  1134.     Widget paint = (Widget) paintArg;
  1135.     Boolean flg;
  1136.     XtVaGetValues(paint, XtNdirty, &flg, NULL);
  1137.  
  1138.     if (flg)
  1139.     AlertBox(GetShell(paint), "Unsaved changes!\nDo you really wish to close?",
  1140.          closeOkCallback, genericCancelCallback, NULL);
  1141.     else
  1142.     XtDestroyWidget(GetShell(paint));
  1143. }
  1144.  
  1145. /*
  1146.  * Reload the image from the last saved file.
  1147.  */
  1148.  
  1149. /*
  1150.  * We need to use a work procedure, otherwise X gets confused.
  1151.  * Simplify a bit by assuming that there will never be more than
  1152.  * one revert process going on at any one time.
  1153.  */
  1154. static XtWorkProcId workProcId;
  1155. static int workProcDone;
  1156.  
  1157. static Boolean
  1158. workProc(XtPointer w)
  1159. {
  1160.     if (workProcDone)
  1161.     return True;
  1162.  
  1163.     /* this is a kluge, but it is necessary */
  1164.     workProcDone = 1;
  1165.  
  1166.     XtRemoveWorkProc(workProcId);
  1167.  
  1168.     XtDestroyWidget(GetShell((Widget) w));
  1169.     return True;
  1170. }
  1171.  
  1172.  
  1173. static void
  1174. doRevert(Widget w)
  1175. {
  1176.     void *v;
  1177.     char *file;
  1178.     Widget paint, top;
  1179.     int zoom, snap;
  1180.     Boolean snapon;
  1181.     Pixel background;
  1182.     WidgetList wlist;
  1183.  
  1184.  
  1185.     XtVaGetValues(w,
  1186.           XtNzoom, &zoom, XtNsnap, &snap, XtNsnapOn, &snapon,
  1187.           XtNbackground, &background, XtNmenuwidgets, &wlist,
  1188.           XtNfilename, &file,
  1189.           NULL);
  1190.     if ((file == NULL) || (*file == 0))
  1191.     return;
  1192.  
  1193.     StateSetBusy(True);
  1194.  
  1195.     top = GetToplevel(w);
  1196.     workProcDone = 0;
  1197.     workProcId = XtAppAddWorkProc(Global.appContext, workProc, (XtPointer) w);
  1198.  
  1199.     if ((v = ReadMagic(file)) != NULL)
  1200.     paint = GraphicOpenFileZoom(top, file, v, zoom);
  1201.     else {
  1202.     StateSetBusy(False);
  1203.     Notice(top, "Unable to open input file \"%s\"\n    %s",
  1204.            file, RWGetMsg());
  1205.     return;
  1206.     }
  1207.  
  1208.     XtVaSetValues(paint, XtNsnapOn, snapon, XtNsnap, snap,
  1209.           XtNbackground, background, XtNdirty, False, NULL);
  1210.  
  1211.     XtVaGetValues(paint, XtNmenuwidgets, &wlist, NULL);
  1212.     MenuCheckItem(wlist[2], snapon);
  1213.  
  1214.     StateSetBusy(False);
  1215. }
  1216.  
  1217. static void
  1218. revertOkCallback(Widget shell, XtPointer arg, XtPointer junk2)
  1219. {
  1220.     doRevert((Widget) arg);
  1221. }
  1222.  
  1223. static void
  1224. revertCallback(Widget w, XtPointer paintArg, XtPointer junk2)
  1225. {
  1226.     Widget paint = (Widget) paintArg;
  1227.     Boolean flg;
  1228.  
  1229.     XtVaGetValues(paint, XtNdirty, &flg, NULL);
  1230.     if (flg)
  1231.     AlertBox(GetShell(paint), "Unsaved changes!\nDo you really wish to revert?",
  1232.          revertOkCallback, genericCancelCallback, paint);
  1233. }
  1234.  
  1235. /*
  1236.  * Pop up the fatbits window.
  1237.  */
  1238. static void
  1239. fatCallback(Widget w, XtPointer paint, XtPointer junk2)
  1240. {
  1241.     FatbitsEdit((Widget) paint);
  1242. }
  1243.  
  1244. /*
  1245.  * Toggle the 'grid' menu item.
  1246.  */
  1247. static void
  1248. gridCallback(Widget w, XtPointer paintArg, XtPointer junk2)
  1249. {
  1250.     Widget paint = (Widget) paintArg;
  1251.     Boolean v;
  1252.  
  1253.     XtVaGetValues(paint, XtNgrid, &v, NULL);
  1254.     v = !v;
  1255.     XtVaSetValues(paint, XtNgrid, v, NULL);
  1256.  
  1257.     MenuCheckItem(w, v);
  1258. }
  1259.  
  1260. /*
  1261.  * Toggle the 'snap' menu item.
  1262.  */
  1263. static void
  1264. snapCallback(Widget w, XtPointer paintArg, XtPointer junk2)
  1265. {
  1266.     Widget paint = (Widget) paintArg;
  1267.     Boolean v;
  1268.  
  1269.     XtVaGetValues(paint, XtNsnapOn, &v, NULL);
  1270.     v = !v;
  1271.     XtVaSetValues(paint, XtNsnapOn, v, NULL);
  1272.  
  1273.     MenuCheckItem(w, v);
  1274. }
  1275.  
  1276. /*
  1277.  *  Callbacks for setting snap spacing.
  1278.  */
  1279. static int snapSpacing = 10;
  1280.  
  1281. static void
  1282. changeSnapOkCallback(Widget paint, void *junk, XtPointer infoArg)
  1283. {
  1284.     TextPromptInfo *info = (TextPromptInfo *) infoArg;
  1285.     int v = atoi(info->prompts[0].rstr);
  1286.  
  1287.     if (v < 1 || v > 100) {
  1288.     Notice(paint, "Bad snap spacing.\nShould be between 2 and 100");
  1289.     return;
  1290.     }
  1291.     snapSpacing = v;
  1292.     XtVaSetValues(paint, XtNsnap, v, NULL);
  1293. }
  1294.  
  1295. static void
  1296. changeSnapCallback(Widget w, XtPointer paintArg, XtPointer junk2)
  1297. {
  1298.     Widget paint = (Widget) paintArg;
  1299.     static TextPromptInfo info;
  1300.     static struct textPromptInfo value[1];
  1301.     static char buf[10];
  1302.  
  1303.     sprintf(buf, "%d", snapSpacing);
  1304.  
  1305.     value[0].prompt = "Spacing:";
  1306.     value[0].str = buf;
  1307.     value[0].len = 4;
  1308.     info.prompts = value;
  1309.     info.title = "Enter desired snap spacing";
  1310.     info.nprompt = 1;
  1311.  
  1312.     TextPrompt(paint, "linewidth", &info, changeSnapOkCallback, NULL, NULL);
  1313. }
  1314.  
  1315. /*
  1316.  *  Callback for changing the image size.
  1317.  */
  1318. static void
  1319. sizeCallback(Widget w, XtPointer paintArg, XtPointer junk2)
  1320. {
  1321.     Widget paint = (Widget) paintArg;
  1322.  
  1323.     SizeSelect(GetShell(paint), paint, NULL);
  1324. }
  1325.  
  1326. static void
  1327. sureCallback(Widget w, XtPointer argArg, XtPointer junk)
  1328. {
  1329.     AutoCrop((Widget) argArg);
  1330. }
  1331.  
  1332. static void
  1333. undosizeOkCallback(Widget paint, void * junk, XtPointer infoArg)
  1334. {
  1335.     TextPromptInfo *info = (TextPromptInfo *) infoArg;
  1336.     int n = atoi(info->prompts[0].rstr);
  1337.  
  1338.     if (n < 0 || n > 20) {
  1339.     Notice(paint, "Bad number of undo levels.\nShould be between 0 and 20");
  1340.     return;
  1341.     }
  1342.     XtVaSetValues(paint, XtNundoSize, n, NULL);
  1343. }
  1344.  
  1345. static void
  1346. undosizeCallback(Widget w, XtPointer paintArg, XtPointer junk2)
  1347. {
  1348.     Widget paint = (Widget) paintArg;
  1349.     static TextPromptInfo info;
  1350.     static struct textPromptInfo value[1];
  1351.     static char buf[5];
  1352.     int undosize;
  1353.  
  1354.     XtVaGetValues(paint, XtNundoSize, &undosize, NULL);
  1355.     sprintf(buf, "%d", undosize);
  1356.  
  1357.     value[0].prompt = "Levels (0-20):";
  1358.     value[0].str = buf;
  1359.     value[0].len = 3;
  1360.     info.prompts = value;
  1361.     info.title = "Number of undo levels";
  1362.     info.nprompt = 1;
  1363.  
  1364.     TextPrompt(paint, "undolevels", &info, undosizeOkCallback, NULL, NULL);
  1365. }
  1366.  
  1367.  
  1368. static void
  1369. autocropCallback(Widget w, XtPointer paintArg, XtPointer junk2)
  1370. {
  1371.     AlertBox(GetShell(paintArg),
  1372.        "Autocrop\n\nWarning: this operation cannot be undone\nContinue?",
  1373.          sureCallback, genericCancelCallback, paintArg);
  1374. }
  1375.  
  1376. /*
  1377.  * Callback functions for changing zoom
  1378.  */
  1379. static void
  1380. zoomAddChild(Widget paint, int zoom)
  1381. {
  1382.     Cardinal nc;
  1383.     Widget t, box = XtParent(paint);
  1384.     WidgetList children;
  1385.     int dw, dh;
  1386.  
  1387.     /*
  1388.      *    1 child == just paint widget
  1389.      *    2 children paint widget + normal size view
  1390.      */
  1391.     XtVaGetValues(box, XtNchildren, &children, XtNnumChildren, &nc, NULL);
  1392.     XtVaGetValues(paint, XtNdrawWidth, &dw, XtNdrawHeight, &dh, NULL);
  1393.     if (nc == 1 && zoom > 1 && dw < 256 && dh < 256) {
  1394.     /*
  1395.      * Add child
  1396.      */
  1397.     t = XtVaCreateManagedWidget("norm", paintWidgetClass, box,
  1398.                     XtNpaint, paint,
  1399.                     XtNzoom, 1,
  1400.                     NULL);
  1401.     GraphicAdd(t);
  1402.     } else if (nc != 1 && zoom <= 1) {
  1403.     /*
  1404.      * Remove child
  1405.      */
  1406.     t = children[(children[0] == paint) ? 1 : 0];
  1407.     XtDestroyWidget(t);
  1408.     }
  1409. }
  1410.  
  1411. static void
  1412. zoomOkCallback(Widget w, XtPointer paintArg, XtPointer infoArg)
  1413. {
  1414.     Widget paint = (Widget) paintArg;
  1415.     TextPromptInfo *info = (TextPromptInfo *) infoArg;
  1416.     int zoom = atoi(info->prompts[0].rstr);
  1417.  
  1418.     if (zoom < 1) {
  1419.     Notice(paint, "Invalid zoom");
  1420.     } else {
  1421.     XtVaSetValues(paint, XtNzoom, zoom, NULL);
  1422.     zoomAddChild(paint, zoom);
  1423.     if ((CurrentOp->add == BrushAdd) ||
  1424.         (CurrentOp->add == EraseAdd) ||
  1425.         (CurrentOp->add == SmearAdd))
  1426.         if (zoom > 1) {
  1427.         SetCrossHairCursor(paint);
  1428.         FatCursorAddZoom(zoom, paint);
  1429.         } else
  1430.         FatCursorRemoveZoom(paint);
  1431.     FatbitsUpdate(paint, zoom);
  1432.     }
  1433. }
  1434.  
  1435. void
  1436. zoomCallback(Widget w, XtPointer paintArg, XtPointer junk2)
  1437. {
  1438.     static TextPromptInfo info;
  1439.     static struct textPromptInfo values[2];
  1440.     char buf[80];
  1441.     int zoom;
  1442.     Widget paint = (Widget) paintArg;
  1443.  
  1444.     info.nprompt = 1;
  1445.     info.prompts = values;
  1446.     info.title = "Change zoom factor for image";
  1447.     values[0].prompt = "Zoom: ";
  1448.     values[0].len = 4;
  1449.     values[0].str = buf;
  1450.  
  1451.     XtVaGetValues(paint, XtNzoom, &zoom, NULL);
  1452.     sprintf(buf, "%d", (int) zoom);
  1453.  
  1454.     TextPrompt(GetShell(paint), "zoomselect", &info,
  1455.            zoomOkCallback, NULL, paint);
  1456. }
  1457.  
  1458. /*
  1459.  * Callback functions for Region menu
  1460.  */
  1461. static void
  1462. rotateTo(Widget w, XtPointer paintArg, XtPointer junk2)
  1463. {
  1464.     Widget paint = (Widget) paintArg;
  1465.     float t;
  1466.     pwMatrix m;
  1467.     String lbl;
  1468.  
  1469.     XtVaGetValues(w, XtNlabel, &lbl, NULL);
  1470.     t = atof(lbl);
  1471.     if (t == 0.0)
  1472.     return;
  1473.  
  1474.     t *= M_PI / 180.0;
  1475.  
  1476.     m[0][0] = cos(t);
  1477.     m[0][1] = -sin(t);
  1478.     m[1][0] = sin(t);
  1479.     m[1][1] = cos(t);
  1480.     PwRegionAppendMatrix(paint, m);
  1481. }
  1482.  
  1483. static int rotateAngle = 0;
  1484.  
  1485. static void
  1486. rotateOkCallback(Widget paint, void *junk, XtPointer infoArg)
  1487. {
  1488.     TextPromptInfo *info = (TextPromptInfo *) infoArg;
  1489.     float t = atof(info->prompts[0].rstr) * M_PI / 180.0;
  1490.     pwMatrix m;
  1491.  
  1492.     m[0][0] = cos(t);
  1493.     m[0][1] = -sin(t);
  1494.     m[1][0] = sin(t);
  1495.     m[1][1] = cos(t);
  1496.     PwRegionAppendMatrix(paint, m);
  1497.     rotateAngle = (int) t;
  1498. }
  1499.  
  1500. static void
  1501. rotate(Widget w, XtPointer paintArg, XtPointer junk2)
  1502. {
  1503.     Widget paint = (Widget) paintArg;
  1504.     static TextPromptInfo info;
  1505.     static struct textPromptInfo value[1];
  1506.     static char buf[10];
  1507.  
  1508.     sprintf(buf, "%d", rotateAngle);
  1509.  
  1510.     value[0].prompt = "Angle (in Degrees):";
  1511.     value[0].str = buf;
  1512.     value[0].len = 4;
  1513.     info.prompts = value;
  1514.     info.title = "Enter desired rotation";
  1515.     info.nprompt = 1;
  1516.  
  1517.     TextPrompt(paint, "rotation", &info, rotateOkCallback, NULL, NULL);
  1518. }
  1519.  
  1520. static void
  1521. resetMat(Widget w, XtPointer paintArg, XtPointer junk2)
  1522. {
  1523.     PwRegionReset((Widget) paintArg, True);
  1524. }
  1525.  
  1526. static void
  1527. cropToRegionOkCallback(Widget w, PaintWidget paint, XtPointer infoArg)
  1528. {
  1529.     RegionCrop(paint);
  1530. }
  1531.  
  1532. static void
  1533. cropToRegion(Widget w, XtPointer paintArg, XtPointer junk2)
  1534. {
  1535.     Widget paint = (Widget) paintArg;
  1536.  
  1537.     AlertBox(GetShell(paint),
  1538.     "Are you sure you want to crop the\nimage to the size of the region?",
  1539.          (XtCallbackProc) cropToRegionOkCallback,
  1540.          genericCancelCallback, paint);
  1541. }
  1542.  
  1543. #ifdef FEATURE_TILT
  1544. static void
  1545. tiltRegionOkCallback(Widget paint, void *junk, XtPointer infoArg)
  1546. {
  1547.     TextPromptInfo *info = (TextPromptInfo *) infoArg;
  1548.  
  1549.     ImgProcessInfo.tiltX1 = atoi(info->prompts[0].rstr);
  1550.     ImgProcessInfo.tiltY1 = atoi(info->prompts[1].rstr);
  1551.     ImgProcessInfo.tiltX2 = atoi(info->prompts[2].rstr);
  1552.     ImgProcessInfo.tiltY2 = atoi(info->prompts[3].rstr);
  1553.     StdRegionTilt(paint, paint, NULL);
  1554. }
  1555.  
  1556. static void
  1557. tiltRegion(Widget w, XtPointer paintArg, XtPointer junk2)
  1558. {
  1559.     Widget paint = (Widget) paintArg;
  1560.     static TextPromptInfo info;
  1561.     static struct textPromptInfo value[4];
  1562.     static char buf1[10], buf2[10], buf3[10], buf4[10];
  1563.  
  1564.     sprintf(buf1, "%d", ImgProcessInfo.tiltX1);
  1565.     sprintf(buf2, "%d", ImgProcessInfo.tiltY1);
  1566.     sprintf(buf3, "%d", ImgProcessInfo.tiltX2);
  1567.     sprintf(buf4, "%d", ImgProcessInfo.tiltY2);
  1568.  
  1569.     value[0].prompt = "X1:";
  1570.     value[0].str = buf1;
  1571.     value[0].len = 4;
  1572.     value[1].prompt = "Y1:";
  1573.     value[1].str = buf2;
  1574.     value[1].len = 4;
  1575.     value[2].prompt = "X2:";
  1576.     value[2].str = buf3;
  1577.     value[2].len = 4;
  1578.     value[3].prompt = "Y2:";
  1579.     value[3].str = buf4;
  1580.     value[3].len = 4;
  1581.     info.prompts = value;
  1582.     info.title = "Enter points";
  1583.     info.nprompt = 4;
  1584.  
  1585.     TextPrompt(paint, "tilt", &info, tiltRegionOkCallback, NULL, NULL);
  1586. }
  1587.  
  1588. #endif
  1589.  
  1590.  
  1591. /*
  1592.  * Callback functions for Filter menu
  1593.  */
  1594.  
  1595. static void
  1596. oilPaintOkCallback(Widget paint, void *junk, XtPointer infoArg)
  1597. {
  1598.     TextPromptInfo *info = (TextPromptInfo *) infoArg;
  1599.     int t;
  1600.  
  1601.     t = atoi(info->prompts[0].rstr);
  1602.     if ((t < 3) || ((t & 1) == 0)) {
  1603.     Notice(paint, "Invalid mask size");
  1604.     return;
  1605.     }
  1606.     ImgProcessInfo.oilArea = t;
  1607.     StdRegionOilPaint(paint, paint, NULL);
  1608. }
  1609.  
  1610. static void
  1611. oilPaint(Widget w, XtPointer paintArg, XtPointer junk2)
  1612. {
  1613.     Widget paint = (Widget) paintArg;
  1614.     static TextPromptInfo info;
  1615.     static struct textPromptInfo value[1];
  1616.     static char buf[10];
  1617.  
  1618.  
  1619.     sprintf(buf, "%d", ImgProcessInfo.oilArea);
  1620.  
  1621.     info.prompts = value;
  1622.     info.title = "Enter mask size for oil paint effect";
  1623.     info.nprompt = 1;
  1624.     value[0].prompt = "(must be odd):";
  1625.     value[0].str = buf;
  1626.     value[0].len = 3;
  1627.  
  1628.     TextPrompt(paint, "mask", &info, oilPaintOkCallback, NULL, NULL);
  1629. }
  1630.  
  1631. static void
  1632. SmoothOkCallback(Widget paint, void *junk, XtPointer infoArg)
  1633. {
  1634.     TextPromptInfo *info = (TextPromptInfo *) infoArg;
  1635.     int t;
  1636.  
  1637.     t = atoi(info->prompts[0].rstr);
  1638.     if ((t < 3) || ((t & 1) == 0)) {
  1639.     Notice(paint, "Invalid mask size");
  1640.     return;
  1641.     }
  1642.     ImgProcessInfo.smoothMaskSize = t;
  1643.     StdRegionSmooth(paint, paint, NULL);
  1644. }
  1645.  
  1646. static void
  1647. doSmooth(Widget w, XtPointer paintArg, XtPointer junk2)
  1648. {
  1649.     Widget paint = (Widget) paintArg;
  1650.     static TextPromptInfo info;
  1651.     static struct textPromptInfo value[1];
  1652.     static char buf[10];
  1653.  
  1654.  
  1655.     sprintf(buf, "%d", ImgProcessInfo.smoothMaskSize);
  1656.  
  1657.     info.prompts = value;
  1658.     info.title = "Enter mask size for smoothing effect";
  1659.     info.nprompt = 1;
  1660.     value[0].prompt = "(must be odd):";
  1661.     value[0].str = buf;
  1662.     value[0].len = 3;
  1663.  
  1664.     TextPrompt(paint, "mask", &info, SmoothOkCallback, NULL, NULL);
  1665. }
  1666.  
  1667. static void
  1668. addNoiseOkCallback(Widget paint, void *junk, XtPointer infoArg)
  1669. {
  1670.     TextPromptInfo *info = (TextPromptInfo *) infoArg;
  1671.     int t;
  1672.  
  1673.     t = atoi(info->prompts[0].rstr);
  1674.     if (t < 1) {
  1675.     Notice(paint, "Invalid noise variance");
  1676.     return;
  1677.     }
  1678.     ImgProcessInfo.noiseDelta = t;
  1679.     StdRegionAddNoise(paint, paint, NULL);
  1680. }
  1681.  
  1682. static void
  1683. addNoise(Widget w, XtPointer paintArg, XtPointer junk2)
  1684. {
  1685.     Widget paint = (Widget) paintArg;
  1686.     static TextPromptInfo info;
  1687.     static struct textPromptInfo value[1];
  1688.     static char buf[10];
  1689.  
  1690.  
  1691.     sprintf(buf, "%d", ImgProcessInfo.noiseDelta);
  1692.  
  1693.     value[0].prompt = "(0-255):";
  1694.     value[0].str = buf;
  1695.     value[0].len = 3;
  1696.     info.prompts = value;
  1697.     info.title = "Enter desired noise variance";
  1698.     info.nprompt = 1;
  1699.  
  1700.     TextPrompt(paint, "delta", &info, addNoiseOkCallback, NULL, NULL);
  1701. }
  1702.  
  1703. static void
  1704. doSpreadOkCallback(Widget paint, void *junk, XtPointer infoArg)
  1705. {
  1706.     TextPromptInfo *info = (TextPromptInfo *) infoArg;
  1707.     int t;
  1708.  
  1709.     t = atoi(info->prompts[0].rstr);
  1710.     if (t < 1) {
  1711.     Notice(paint, "Invalid spread distance");
  1712.     return;
  1713.     }
  1714.     ImgProcessInfo.spreadDistance = t;
  1715.     StdRegionSpread(paint, paint, NULL);
  1716. }
  1717.  
  1718. static void
  1719. doSpread(Widget w, XtPointer paintArg, XtPointer junk2)
  1720. {
  1721.     Widget paint = (Widget) paintArg;
  1722.     static TextPromptInfo info;
  1723.     static struct textPromptInfo value[1];
  1724.     static char buf1[10];
  1725.  
  1726.  
  1727.     sprintf(buf1, "%d", ImgProcessInfo.spreadDistance);
  1728.  
  1729.     value[0].prompt = "Distance (pixels):";
  1730.     value[0].str = buf1;
  1731.     value[0].len = 3;
  1732.     info.prompts = value;
  1733.     info.title = "Enter the desired spread distance";
  1734.     info.nprompt = 1;
  1735.  
  1736.     TextPrompt(paint, "distance", &info, doSpreadOkCallback, NULL, NULL);
  1737. }
  1738.  
  1739. static void
  1740. doPixelizeOkCallback(Widget paint, void *junk, XtPointer infoArg)
  1741. {
  1742.     TextPromptInfo *info = (TextPromptInfo *) infoArg;
  1743.     char *s = info->prompts[0].rstr;
  1744.     int e = 0, tx, ty;
  1745.  
  1746.  
  1747.     if (strchr(s, 'x')) {
  1748.     if (sscanf(s, "%d x %d", &tx, &ty) != 2)
  1749.         ++e;
  1750.     } else {
  1751.     if (sscanf(s, "%d", &tx) != 1)
  1752.         ++e;
  1753.     ty = tx;
  1754.     }
  1755.  
  1756.     if (e || (tx < 1) || (ty < 1)) {
  1757.     Notice(paint, "Invalid pixel size");
  1758.     return;
  1759.     }
  1760.     ImgProcessInfo.pixelizeXSize = tx;
  1761.     ImgProcessInfo.pixelizeYSize = ty;
  1762.     StdRegionPixelize(paint, paint, NULL);
  1763. }
  1764.  
  1765. static void
  1766. doPixelize(Widget w, XtPointer paintArg, XtPointer junk2)
  1767. {
  1768.     Widget paint = (Widget) paintArg;
  1769.     static TextPromptInfo info;
  1770.     static struct textPromptInfo value[1];
  1771.     static char buf[10];
  1772.  
  1773.  
  1774.     if (ImgProcessInfo.pixelizeXSize != ImgProcessInfo.pixelizeYSize)
  1775.     sprintf(buf, "%dx%d", ImgProcessInfo.pixelizeXSize,
  1776.         ImgProcessInfo.pixelizeYSize);
  1777.     else
  1778.     sprintf(buf, "%d", ImgProcessInfo.pixelizeXSize);
  1779.  
  1780.     value[0].prompt = "(w x h, or single number):";
  1781.     value[0].str = buf;
  1782.     value[0].len = 3;
  1783.     info.prompts = value;
  1784.     info.title = "Enter desired megapixel size";
  1785.     info.nprompt = 1;
  1786.  
  1787.     TextPrompt(paint, "size", &info, doPixelizeOkCallback, NULL, NULL);
  1788. }
  1789.  
  1790. static void
  1791. despeckleOkCallback(Widget paint, void *junk, XtPointer infoArg)
  1792. {
  1793.     TextPromptInfo *info = (TextPromptInfo *) infoArg;
  1794.     int t;
  1795.  
  1796.     t = atoi(info->prompts[0].rstr);
  1797.     if ((t < 3) || ((t & 1) == 0)) {
  1798.     Notice(paint, "Invalid mask size");
  1799.     return;
  1800.     }
  1801.     ImgProcessInfo.despeckleMask = t;
  1802.     StdRegionDespeckle(paint, paint, NULL);
  1803. }
  1804.  
  1805. static void
  1806. doDespeckle(Widget w, XtPointer paintArg, XtPointer junk2)
  1807. {
  1808.     Widget paint = (Widget) paintArg;
  1809.     static TextPromptInfo info;
  1810.     static struct textPromptInfo value[1];
  1811.     static char buf[10];
  1812.  
  1813.  
  1814.     sprintf(buf, "%d", ImgProcessInfo.despeckleMask);
  1815.  
  1816.     info.prompts = value;
  1817.     info.title = "Enter mask size for despeckle filter";
  1818.     info.nprompt = 1;
  1819.     value[0].prompt = "(must be odd):";
  1820.     value[0].str = buf;
  1821.     value[0].len = 3;
  1822.  
  1823.     TextPrompt(paint, "despeckle", &info, despeckleOkCallback, NULL, NULL);
  1824. }
  1825.  
  1826. static void
  1827. contrastOkCallback(Widget paint, void *junk, XtPointer infoArg)
  1828. {
  1829.     TextPromptInfo *info = (TextPromptInfo *) infoArg;
  1830.     int t1, t2;
  1831.  
  1832.     t1 = atoi(info->prompts[0].rstr);
  1833.     if ((t1 < 0) || (t1 > 100)) {
  1834.     Notice(paint, "Invalid white level");
  1835.     return;
  1836.     }
  1837.     t2 = atoi(info->prompts[1].rstr);
  1838.     if ((t2 < 0) || (t2 > 100)) {
  1839.     Notice(paint, "Invalid black level");
  1840.     return;
  1841.     }
  1842.     ImgProcessInfo.contrastB = t1;
  1843.     ImgProcessInfo.contrastW = t2;
  1844.     StdRegionNormContrast(paint, paint, NULL);
  1845. }
  1846.  
  1847.  
  1848. static void
  1849. doContrast(Widget w, XtPointer paintArg, XtPointer junk2)
  1850. {
  1851.     Widget paint = (Widget) paintArg;
  1852.     static TextPromptInfo info;
  1853.     static struct textPromptInfo value[2];
  1854.     static char buf1[10], buf2[10];
  1855.  
  1856.  
  1857.     sprintf(buf1, "%d", ImgProcessInfo.contrastB);
  1858.     sprintf(buf2, "%d", ImgProcessInfo.contrastW);
  1859.  
  1860.     info.prompts = value;
  1861.     info.title = "Enter levels for contrast adjustment";
  1862.     info.nprompt = 2;
  1863.     value[0].prompt = "Black level (%):";
  1864.     value[0].str = buf1;
  1865.     value[0].len = 3;
  1866.     value[1].prompt = "White level (%):";
  1867.     value[1].str = buf2;
  1868.     value[1].len = 3;
  1869.     TextPrompt(paint, "contrast", &info, contrastOkCallback, NULL, NULL);
  1870. }
  1871.  
  1872. static void
  1873. solarizeOkCallback(Widget paint, void *junk, XtPointer infoArg)
  1874. {
  1875.     TextPromptInfo *info = (TextPromptInfo *) infoArg;
  1876.     int t;
  1877.  
  1878.     t = atoi(info->prompts[0].rstr);
  1879.     if ((t < 1) || (t > 99)) {
  1880.     Notice(paint, "Invalid solarization threshold");
  1881.     return;
  1882.     }
  1883.     ImgProcessInfo.solarizeThreshold = t;
  1884.     StdRegionSolarize(paint, paint, NULL);
  1885. }
  1886.  
  1887. static void
  1888. doSolarize(Widget w, XtPointer paintArg, XtPointer junk2)
  1889. {
  1890.     Widget paint = (Widget) paintArg;
  1891.     static TextPromptInfo info;
  1892.     static struct textPromptInfo value[1];
  1893.     static char buf[10];
  1894.  
  1895.  
  1896.     sprintf(buf, "%d", ImgProcessInfo.solarizeThreshold);
  1897.  
  1898.     info.prompts = value;
  1899.     info.title = "Enter threshold for solarize filter";
  1900.     info.nprompt = 1;
  1901.     value[0].prompt = "(%):";
  1902.     value[0].str = buf;
  1903.     value[0].len = 3;
  1904.  
  1905.     TextPrompt(paint, "mask", &info, solarizeOkCallback, NULL, NULL);
  1906. }
  1907.  
  1908. static void
  1909. quantizeOkCallback(Widget paint, void *junk, XtPointer infoArg)
  1910. {
  1911.     TextPromptInfo *info = (TextPromptInfo *) infoArg;
  1912.     int t;
  1913.  
  1914.     t = atoi(info->prompts[0].rstr);
  1915.     if ((t < 2) || (t > 256)) {
  1916.     Notice(paint, "Invalid number of colors");
  1917.     return;
  1918.     }
  1919.     ImgProcessInfo.quantizeColors = t;
  1920.     StdRegionQuantize(paint, paint, NULL);
  1921. }
  1922.  
  1923. static void
  1924. doQuantize(Widget w, XtPointer paintArg, XtPointer junk2)
  1925. {
  1926.     Widget paint = (Widget) paintArg;
  1927.     static TextPromptInfo info;
  1928.     static struct textPromptInfo value[1];
  1929.     static char buf[10];
  1930.  
  1931.  
  1932.     sprintf(buf, "%d", ImgProcessInfo.quantizeColors);
  1933.  
  1934.     info.prompts = value;
  1935.     info.title = "Enter desired number of colors";
  1936.     info.nprompt = 1;
  1937.     value[0].prompt = "(2-256):";
  1938.     value[0].str = buf;
  1939.     value[0].len = 3;
  1940.  
  1941.     TextPrompt(paint, "mask", &info, quantizeOkCallback, NULL, NULL);
  1942. }
  1943.  
  1944. static void
  1945. doLast(Widget w, XtPointer paintArg, XtPointer junk2)
  1946. {
  1947.     Widget paint = (Widget) paintArg;
  1948.  
  1949.     StdLastImgProcess(paint);
  1950. }
  1951.  
  1952. static void
  1953. prCallback(Widget paint, Widget w, Boolean flag)
  1954. {
  1955.     XtVaSetValues(w, XtNsensitive, flag, NULL);
  1956. }
  1957.  
  1958. void
  1959. EnableRevert(Widget paint)
  1960. {
  1961.     WidgetList wlist;
  1962.  
  1963.     XtVaGetValues(paint, XtNmenuwidgets, &wlist, NULL);
  1964.     XtVaSetValues(wlist[0], XtNsensitive, 1, NULL);
  1965. }
  1966.  
  1967. void
  1968. EnableLast(Widget paint)
  1969. {
  1970.     WidgetList wlist;
  1971.  
  1972.     XtVaGetValues(paint, XtNmenuwidgets, &wlist, NULL);
  1973.     XtVaSetValues(wlist[1], XtNsensitive, 1, NULL);
  1974. }
  1975.  
  1976. /*
  1977.  *  Background changer
  1978.  */
  1979. static void
  1980. changeBgOk(Widget w, Palette * map, XColor * col)
  1981. {
  1982.     StateShellBusy(w, False);
  1983.  
  1984.     if (col != NULL) {
  1985.     Pixel pix = PaletteAlloc(map, col);
  1986.     XtVaSetValues(w, XtNbackground, pix, NULL);
  1987.     }
  1988. }
  1989.  
  1990. static void
  1991. changeBackground(Widget w, XtPointer paintArg, XtPointer junk2)
  1992. {
  1993.     Widget paint = (Widget) paintArg;
  1994.     Colormap cmap;
  1995.     Pixel bg;
  1996.     Palette *map;
  1997.  
  1998.     StateShellBusy(paint, True);
  1999.  
  2000.     XtVaGetValues(GetShell(paint), XtNcolormap, &cmap, NULL);
  2001.     XtVaGetValues(paint, XtNbackground, &bg, NULL);
  2002.     map = PaletteFind(paint, cmap);
  2003.  
  2004.     ColorEditor(paint, bg, map,
  2005.         False, (XtCallbackProc) changeBgOk, (XtPointer) map);
  2006. }
  2007.  
  2008. static void
  2009. selectColorRange(Widget w, XtPointer wlArg, XtPointer junk)
  2010. {
  2011.     LocalInfo *info = (LocalInfo *) wlArg;
  2012.     Widget paint = info->paint;
  2013.  
  2014.     ChromaDialog(paint, info->map);
  2015. }
  2016.  
  2017.  
  2018. /*
  2019.  *  Start of graphic window creation routines
  2020.  */
  2021.  
  2022. Widget
  2023. makeGraphicShell(Widget wid)
  2024. {
  2025.     Arg args[2];
  2026.     int nargs = 0;
  2027.     Widget shell;
  2028.  
  2029.     XtSetArg(args[nargs], XtNtitle, DEFAULT_TITLE);
  2030.     nargs++;
  2031.     XtSetArg(args[nargs], XtNiconName, DEFAULT_TITLE);
  2032.     nargs++;
  2033.  
  2034.     shell = XtAppCreateShell("Canvas", "Canvas",
  2035.            topLevelShellWidgetClass, XtDisplay(GetToplevel(wid)),
  2036.                  args, nargs);
  2037.  
  2038.     return shell;
  2039. }
  2040.  
  2041. static Widget
  2042. mkPatternArea(Widget parent, Widget left, char *name,
  2043.           Widget * pform, LocalInfo * info)
  2044. {
  2045.     Widget form, label, pattern, vport, lookup;
  2046.  
  2047.     form = XtVaCreateManagedWidget("patternRackForm",
  2048.                    formWidgetClass, parent,
  2049.                    XtNborderWidth, 0,
  2050.                    XtNfromHoriz, left,
  2051.                    XtNleft, XtChainLeft,
  2052.                    XtNright, XtChainLeft,
  2053.                    NULL);
  2054.     if (pform != NULL)
  2055.     *pform = form;
  2056.     label = XtVaCreateManagedWidget(name, labelWidgetClass, form,
  2057.                     XtNborderWidth, 0,
  2058.                     NULL);
  2059. #ifdef LOOKUP_OUTSIDE
  2060.     lookup = XtVaCreateManagedWidget("lookup",
  2061.                      commandWidgetClass, form,
  2062.                      XtNfromHoriz, label,
  2063.                      NULL);
  2064. #else
  2065.     lookup = label;
  2066. #endif
  2067.  
  2068.     vport = XtVaCreateManagedWidget("viewport2",
  2069.                     viewportWidgetClass, form,
  2070.                     XtNallowVert, True,
  2071.                     XtNuseBottom, True,
  2072.                     XtNuseRight, True,
  2073.                     XtNfromVert, lookup,
  2074.                     NULL);
  2075.     pattern = XtVaCreateWidget("patternRack",
  2076.                    boxWidgetClass, vport,
  2077.                    NULL);
  2078. #ifndef LOOKUP_OUTSIDE
  2079.     lookup = XtVaCreateManagedWidget("lookup",
  2080.                      commandWidgetClass, pattern,
  2081.                      NULL);
  2082. #endif
  2083.  
  2084.     XtAddCallback(lookup, XtNcallback, lookupPatternCallback, (XtPointer) info);
  2085.  
  2086.     return pattern;
  2087. }
  2088.  
  2089. #define ADDCALLBACK(menu, item, pw, func) \
  2090.   XtAddCallback(menu[item].widget, XtNcallback, (XtCallbackProc) func, \
  2091.         (XtPointer) pw);
  2092.  
  2093. /*
  2094.  * This assumes that you either
  2095.  *  - specify a pixmap, in which case width and height are taken from that, or
  2096.  *  - specify width and height, in which case the pixmap is not needed.
  2097.  * Returns the created PaintWidget.
  2098.  */
  2099. Widget
  2100. graphicCreate(Widget shell, int width, int height, int zoom,
  2101.           Pixmap pix, Colormap cmap)
  2102. {
  2103.     Widget form, viewport, pattern, bar;
  2104.     Widget pane, pane1, pform;
  2105.     Widget paint;
  2106.     Widget add, edit;
  2107.     WidgetList child, wlist;
  2108.     int nchild;
  2109.     RCInfo *rcInfo;
  2110.     Palette *map;
  2111.     int i;
  2112.     int depth;
  2113.     LocalInfo *info = XtNew(LocalInfo);
  2114.     PatternInfo *pData;
  2115.  
  2116.     /*
  2117.      *    Menu Bar
  2118.      */
  2119.     if (cmap == None) {
  2120.     map = PaletteCreate(shell);
  2121.     cmap = map->cmap;
  2122.     } else {
  2123.     map = PaletteFind(shell, cmap);
  2124.     }
  2125.     depth = map->depth;
  2126.     XtVaSetValues(shell, XtNcolormap, cmap, NULL);
  2127.  
  2128.     PaletteAddUser(map, shell);
  2129.  
  2130.     info->map = map;
  2131.  
  2132.     pane = XtVaCreateManagedWidget("pane",
  2133.                    panedWidgetClass, shell,
  2134.                    NULL);
  2135.     rcInfo = ReadDefaultRC();
  2136.  
  2137.     /*
  2138.      *    Menu area
  2139.      */
  2140.     form = XtVaCreateManagedWidget("form1",
  2141.                    formWidgetClass, pane,
  2142.                    NULL);
  2143.     bar = MenuBarCreate(form, XtNumber(menuBar), menuBar);
  2144.     XtVaSetValues(form, XtNshowGrip, False, NULL);
  2145.  
  2146.     /*
  2147.      *    Drawing Area
  2148.      */
  2149.     viewport = XtVaCreateWidget("viewport",
  2150.                 viewportWidgetClass, pane,
  2151.                 XtNfromVert, bar,
  2152.                 XtNallowVert, True,
  2153.                 XtNallowHoriz, True,
  2154.                 XtNuseBottom, True,
  2155.                 XtNuseRight, True,
  2156.                 XtNtop, XtChainTop,
  2157.                 NULL);
  2158.  
  2159.     /*
  2160.      *    Custom Drawing Widget here
  2161.      */
  2162.     pane1 = XtVaCreateWidget("paintBox",
  2163.                  boxWidgetClass, viewport,
  2164.               XtNbackgroundPixmap, GetBackgroundPixmap(viewport),
  2165.                  NULL);
  2166.     /*
  2167.      *    Try and do something nice for the user
  2168.      */
  2169.     if (pix != None)
  2170.     GetPixmapWHD(XtDisplay(pane1), pix, &width, &height, NULL);
  2171.     if (zoom == -1 && width <= 64 && height <= 64)
  2172.     zoom = 6;
  2173.  
  2174.     paint = XtVaCreateManagedWidget("paint",
  2175.                     paintWidgetClass, pane1,
  2176.                     XtNdrawWidth, width,
  2177.                     XtNdrawHeight, height,
  2178.                     XtNzoom, zoom,
  2179.                     XtNpixmap, pix,
  2180.                     XtNcolormap, cmap,
  2181.                     XtNallowResize, True,
  2182.                     XtNshowGrip, False,
  2183.                     XtNundoSize, 4,
  2184.                     NULL);
  2185.     XtSetKeyboardFocus(pane, paint);
  2186.  
  2187.     zoomAddChild(paint, zoom);
  2188.  
  2189.     info->paint = paint;
  2190.     OperationSetPaint(paint);
  2191.     ccpAddStdPopup(paint);
  2192.  
  2193.     XtManageChild(pane1);
  2194.     XtManageChild(viewport);
  2195.  
  2196.     ADDCALLBACK(fileMenu, SAVE_CONFIG, info, saveConfigCallback);
  2197.     ADDCALLBACK(fileMenu, LOAD_CONFIG, info, loadConfigCallback);
  2198.  
  2199.     ccpAddUndo(editMenu[UNDO_ITEM].widget, paint);
  2200.     ccpAddRedo(editMenu[REDO_ITEM].widget, paint);
  2201.     ccpAddCut(editMenu[CUT_ITEM].widget, paint);
  2202.     ccpAddCopy(editMenu[COPY_ITEM].widget, paint);
  2203.     ccpAddPaste(editMenu[PASTE_ITEM].widget, paint);
  2204.     ccpAddClear(editMenu[CLEAR_ITEM].widget, paint);
  2205.     ccpAddDuplicate(editMenu[DUP_ITEM].widget, paint);
  2206.  
  2207.     ADDCALLBACK(editMenu, SELECT_ALL_ITEM, paint, StdSelectAllCallback);
  2208.     ADDCALLBACK(fileMenu, SAVEAS_ITEM, paint, StdSaveAsFile);
  2209.     ADDCALLBACK(fileMenu, SAVE_ITEM, paint, StdSaveFile);
  2210.  
  2211.     ccpAddSaveRegion(fileMenu[SAVER_ITEM].widget, paint);
  2212.  
  2213.     ADDCALLBACK(fileMenu, REVERT_ITEM, paint, revertCallback);
  2214.     prCallback(paint, fileMenu[REVERT_ITEM].widget, False);
  2215.  
  2216.     ADDCALLBACK(fileMenu, CLOSE_ITEM, paint, closeCallback);
  2217.     ADDCALLBACK(otherMenu, GRID_ITEM, paint, gridCallback);
  2218.     ADDCALLBACK(otherMenu, SNAP_ITEM, paint, snapCallback);
  2219.     ADDCALLBACK(otherMenu, CHSNAP_ITEM, paint, changeSnapCallback);
  2220.     ADDCALLBACK(otherMenu, FAT_ITEM, paint, fatCallback);
  2221.     ADDCALLBACK(otherMenu, CHSIZE_ITEM, paint, sizeCallback);
  2222.     ADDCALLBACK(otherMenu, UNDOSZ_ITEM, paint, undosizeCallback);
  2223.     ADDCALLBACK(otherMenu, AUTOCROP_ITEM, paint, autocropCallback);
  2224.     ADDCALLBACK(otherMenu, CHZOOM_ITEM, paint, zoomCallback);
  2225.     ADDCALLBACK(otherMenu, EDIT_BACKGROUND, paint, changeBackground);
  2226.  
  2227.     ADDCALLBACK(regionMenu, RG_FLIPX_ITEM, paint, StdRegionFlipX);
  2228.     ADDCALLBACK(regionMenu, RG_FLIPY_ITEM, paint, StdRegionFlipY);
  2229.     ADDCALLBACK(filterMenu, RG_INVERT_ITEM, paint, StdRegionInvert);
  2230.     ADDCALLBACK(filterMenu, RG_SHARPEN_ITEM, paint, StdRegionSharpen);
  2231.     ADDCALLBACK(filterMenu, RG_EDGE_ITEM, paint, StdRegionEdge);
  2232.     ADDCALLBACK(filterMenu, RG_EMBOSE_ITEM, paint, StdRegionEmbose);
  2233.     ADDCALLBACK(filterMenu, RG_BLEND_ITEM, paint, StdRegionBlend);
  2234.  
  2235.     for (i = 0; i < XtNumber(rotateMenu); i++) {
  2236.     if (rotateMenu[i].name[0] == '\0')
  2237.         continue;
  2238.  
  2239.     ADDCALLBACK(rotateMenu, i, paint, rotateTo);
  2240.     XtAddCallback(paint, XtNregionCallback, (XtCallbackProc) prCallback,
  2241.               (XtPointer) rotateMenu[i].widget);
  2242.     prCallback(paint, rotateMenu[i].widget, False);
  2243.     }
  2244.  
  2245.     ADDCALLBACK(regionMenu, RG_ROTATE, paint, rotate);
  2246.     XtAddCallback(paint, XtNregionCallback, (XtCallbackProc) prCallback,
  2247.           (XtPointer) regionMenu[RG_ROTATE].widget);
  2248.     prCallback(paint, regionMenu[RG_ROTATE].widget, False);
  2249.  
  2250.     ADDCALLBACK(filterMenu, RG_SMOOTH_ITEM, paint, doSmooth);
  2251.     ADDCALLBACK(filterMenu, RG_OIL_ITEM, paint, oilPaint);
  2252.     ADDCALLBACK(filterMenu, RG_NOISE_ITEM, paint, addNoise);
  2253.     ADDCALLBACK(filterMenu, RG_SPREAD_ITEM, paint, doSpread);
  2254.     ADDCALLBACK(filterMenu, RG_PIXELIZE_ITEM, paint, doPixelize);
  2255.     ADDCALLBACK(filterMenu, RG_DESPECKLE_ITEM, paint, doDespeckle);
  2256.     ADDCALLBACK(filterMenu, RG_CONTRAST_ITEM, paint, doContrast);
  2257.     ADDCALLBACK(filterMenu, RG_SOLARIZE_ITEM, paint, doSolarize);
  2258.     ADDCALLBACK(filterMenu, RG_QUANTIZE_ITEM, paint, doQuantize);
  2259.     ADDCALLBACK(filterMenu, RG_TOGREY_ITEM, paint, StdRegionGrey);
  2260.     ADDCALLBACK(filterMenu, RG_DIRFILT_ITEM, paint, StdRegionDirFilt);
  2261.     ADDCALLBACK(filterMenu, RG_LAST_ITEM, paint, doLast);
  2262.     prCallback(paint, filterMenu[RG_LAST_ITEM].widget, False);
  2263.  
  2264.     ADDCALLBACK(regionMenu, RG_CROP, paint, cropToRegion);
  2265.     XtAddCallback(paint, XtNregionCallback, (XtCallbackProc) prCallback,
  2266.           (XtPointer) regionMenu[RG_CROP].widget);
  2267.     prCallback(paint, regionMenu[RG_CROP].widget, False);
  2268.  
  2269. #ifdef FEATURE_TILT
  2270.     ADDCALLBACK(regionMenu, RG_TILT, paint, tiltRegion);
  2271. #endif
  2272.     ADDCALLBACK(regionMenu, RG_RESET, paint, resetMat);
  2273.  
  2274.     XtAddCallback(paint, XtNregionCallback, (XtCallbackProc) prCallback,
  2275.           (XtPointer) regionMenu[RG_RESET].widget);
  2276.     prCallback(paint, regionMenu[RG_RESET].widget, False);
  2277.  
  2278.     /* Store menu widgets for later reference */
  2279.     wlist = (WidgetList) XtMalloc(NMENUWIDGETS * sizeof(Widget));
  2280.     wlist[0] = fileMenu[REVERT_ITEM].widget;
  2281.     wlist[1] = filterMenu[RG_LAST_ITEM].widget;
  2282.     wlist[2] = otherMenu[SNAP_ITEM].widget;
  2283.     XtVaSetValues(paint, XtNmenuwidgets, wlist, NULL);
  2284.  
  2285.     form = XtVaCreateManagedWidget("form2",
  2286.                    formWidgetClass, pane,
  2287.                    XtNskipAdjust, True,
  2288.                    NULL);
  2289.  
  2290.     pattern = mkPatternArea(form, None, "primary", &pform, info);
  2291.     info->primaryBox = pattern;
  2292.  
  2293.     pattern = mkPatternArea(form, pform, "secondary", &pform, info);
  2294.     info->secondaryBox = pattern;
  2295.  
  2296.     info->primaryList = None;
  2297.     info->secondaryList = None;
  2298.  
  2299.     /*
  2300.      *    Now construct the palette area and set the
  2301.      *      primary and secondary selections correctly
  2302.      */
  2303.  
  2304.     makePaletteArea(info, rcInfo);
  2305.  
  2306.     XtVaGetValues(info->primaryBox, XtNchildren, &child,
  2307.           XtNnumChildren, &nchild,
  2308.           NULL);
  2309.     XtVaGetValues(child[0], XtNradioData, &pData, NULL);
  2310.     XawToggleSetCurrent(info->primaryList, (XtPointer) pData);
  2311.  
  2312.     XtVaGetValues(info->secondaryBox, XtNchildren, &child,
  2313.           XtNnumChildren, &nchild,
  2314.           NULL);
  2315.     if (nchild == 1)
  2316.     XtVaGetValues(child[0], XtNradioData, &pData, NULL);
  2317.     else
  2318.     XtVaGetValues(child[1], XtNradioData, &pData, NULL);
  2319.     XawToggleSetCurrent(info->secondaryList, (XtPointer) pData);
  2320.  
  2321.     XtManageChild(info->primaryBox);
  2322.     XtManageChild(info->secondaryBox);
  2323.  
  2324.     /*
  2325.      *    A few buttons for help...
  2326.      */
  2327.     add = XtVaCreateManagedWidget("addPattern",
  2328.                   commandWidgetClass, form,
  2329.                   XtNfromHoriz, pform,
  2330.                   XtNfromVert, None,
  2331.                   XtNleft, XtChainRight,
  2332.                   XtNright, XtChainRight,
  2333.                   XtNtop, XtChainTop,
  2334.                   XtNbottom, XtChainTop,
  2335.                   NULL);
  2336.     /*
  2337.      *    If we are on a small static colormap, we shouldn't be able to do an add
  2338.      */
  2339.     edit = XtVaCreateManagedWidget("addSolid",
  2340.                    commandWidgetClass, form,
  2341.                    XtNfromHoriz, pform,
  2342.                    XtNfromVert, add,
  2343.                    XtNleft, XtChainRight,
  2344.                    XtNright, XtChainRight,
  2345.                    XtNtop, XtChainTop,
  2346.                    XtNbottom, XtChainTop,
  2347.                    NULL);
  2348.  
  2349.     if (edit != None)
  2350.     XtAddCallback(edit, XtNcallback, addSolidCallback, (XtPointer) info);
  2351.     XtAddCallback(add, XtNcallback, addPatternCallback, (XtPointer) info);
  2352.     XtAddCallback(paint, XtNdestroyCallback, destroyCallback, (XtPointer) info);
  2353.  
  2354.     edit = XtVaCreateManagedWidget("selectRange",
  2355.                    commandWidgetClass, form,
  2356.                    XtNfromHoriz, pform,
  2357.                    XtNfromVert, edit,
  2358.                    XtNleft, XtChainRight,
  2359.                    XtNright, XtChainRight,
  2360.                    XtNtop, XtChainTop,
  2361.                    XtNbottom, XtChainTop,
  2362.                    NULL);
  2363.  
  2364.     XtAddCallback(edit, XtNcallback, selectColorRange, (XtPointer) info);
  2365.  
  2366.     AddDestroyCallback(shell,
  2367.                (DestroyCallbackFunc) closeCallback, (void *) paint);
  2368.     SetIconImage(shell);
  2369.  
  2370.     XtRealizeWidget(shell);
  2371.     GraphicAdd(paint);
  2372.     return paint;
  2373. }
  2374.  
  2375. typedef struct cwi_s {
  2376.     Widget paint;
  2377.     void *id;
  2378.     struct cwi_s *next;
  2379. } CanvasWriteInfo;
  2380.  
  2381. static CanvasWriteInfo *cwiHead = NULL;
  2382.  
  2383. static void
  2384. removeCWI(Widget w, CanvasWriteInfo * ci, XtPointer junk)
  2385. {
  2386.     CanvasWriteInfo *cur = cwiHead, **pp = &cwiHead;
  2387.  
  2388.     while (cur != NULL && cur != ci) {
  2389.     pp = &cur->next;
  2390.     cur = cur->next;
  2391.     }
  2392.  
  2393.     if (cur == NULL)
  2394.     return;
  2395.     *pp = cur->next;
  2396.     XtFree((XtPointer) ci);
  2397. }
  2398.  
  2399. void *
  2400. GraphicGetReaderId(Widget paint)
  2401. {
  2402.     CanvasWriteInfo *cur;
  2403.  
  2404.     paint = GetShell(paint);
  2405.  
  2406.     for (cur = cwiHead; cur != NULL && cur->paint != paint; cur = cur->next);
  2407.  
  2408.     if (cur == NULL)
  2409.     return NULL;
  2410.  
  2411.     return cur->id;
  2412. }
  2413.  
  2414. Widget
  2415. GraphicOpenFileZoom(Widget w, char *file, XtPointer imageArg, int zoom)
  2416. {
  2417.     Image *image = (Image *) imageArg;
  2418.     Colormap cmap;
  2419.     Pixmap pix;
  2420.     Widget shell = makeGraphicShell(w);
  2421.     CanvasWriteInfo *ci = XtNew(CanvasWriteInfo);
  2422.     PaintWidget paint;
  2423.  
  2424.     ci->next = cwiHead;
  2425.     cwiHead = ci;
  2426.     ci->paint = shell;
  2427.     ci->id = GetFileNameGetLastId();
  2428.  
  2429.     XtAddCallback(shell, XtNdestroyCallback,
  2430.           (XtCallbackProc) removeCWI, (XtPointer) ci);
  2431.  
  2432.     if (ImageToPixmap(image, shell, &pix, &cmap)) {
  2433.     /*
  2434.      * If mask != None, set the mask region color to the BG color of the Canvas
  2435.      */
  2436.     if ((paint = (PaintWidget)
  2437.          graphicCreate(shell, 0, 0, zoom, pix, cmap)) != None) {
  2438.         char *cp = strrchr(file, '/');
  2439.         if (cp == NULL)
  2440.         cp = file;
  2441.         else
  2442.         cp++;
  2443.  
  2444.         XtVaSetValues(shell, XtNiconName, cp, XtNtitle, file, NULL);
  2445.         cp = xmalloc(strlen(file) + 1);
  2446.         strcpy(cp, file);
  2447.         paint->paint.filename = cp;
  2448.         EnableRevert((Widget) paint);
  2449.         return (Widget) paint;
  2450.     } else {
  2451.         XtDestroyWidget(shell);
  2452.     }
  2453.     } else {
  2454.     Notice(w, "Unable to create paint window with image");
  2455.     XtDestroyWidget(shell);
  2456.     }
  2457.     return NULL;
  2458. }
  2459.  
  2460. void
  2461. GraphicOpenFile(Widget w, XtPointer fileArg, XtPointer imageArg)
  2462. {
  2463.     GraphicOpenFileZoom(w, (char *) fileArg, imageArg, -1);
  2464. }
  2465.  
  2466. static void
  2467. doCreate(Widget wid, int width, int height, int zoom)
  2468. {
  2469.     graphicCreate(makeGraphicShell(wid), width, height, zoom, None, None);
  2470. }
  2471.  
  2472. /*
  2473.  * 0: Create new (blank) canvas
  2474.  * 1: Open a file
  2475.  * 2: Create new (blank) canvas, querying for size
  2476.  */
  2477. void
  2478. #ifndef VMS
  2479. GraphicCreate(Widget wid, int value)
  2480. #else
  2481. Graphic_Create(Widget wid, int value)
  2482. #endif
  2483. {
  2484.     int width, height;
  2485.  
  2486.     switch (value) {
  2487.     case 0:
  2488.     GetDefaultWH(&width, &height);
  2489.     graphicCreate(makeGraphicShell(wid), width, height, -1, None, None);
  2490.     break;
  2491.     case 1:
  2492.     GetFileName(GetToplevel(wid), 0, NULL, GraphicOpenFile, NULL);
  2493.     break;
  2494.     case 2:
  2495.     SizeSelect(wid, None, doCreate);
  2496.     break;
  2497.     }
  2498. }
  2499.