home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / m / motifpg2.zip / ch04 / BitmapEdit.c < prev    next >
C/C++ Source or Header  |  1992-07-08  |  23KB  |  762 lines

  1. /*
  2.  * Copyright 1989, 1992 O'Reilly and Associates, Inc.
  3.  * See ../Copyright for complete rights and liability information.
  4.  */
  5.  
  6. /*
  7.  * BitmapEdit.c - bitmap editor widget.
  8.  */
  9.  
  10. #include <Xm/XmP.h>
  11. #include <X11/StringDefs.h>
  12.  
  13. #include <stdio.h>
  14.  
  15. #include "BitmapEdiP.h"
  16.  
  17. #define INTERNAL_WIDTH    2
  18. #define INTERNAL_HEIGHT 4
  19.  
  20. #define DEFAULT_PIXMAP_WIDTH    32  /* in cells */
  21. #define DEFAULT_PIXMAP_HEIGHT   32  /* in cells */
  22.  
  23. #define DEFAULT_CELL_SIZE   30  /* in pixels */
  24.  
  25. /* values for instance variable is_drawn */
  26. #define DRAWN 1
  27. #define UNDRAWN 0
  28.  
  29. /* modes for drawing */
  30. #define DRAW 1
  31. #define UNDRAW 0
  32.  
  33. #define MAXLINES 1000   /* max of horiz or vertical cells */
  34. #define SCROLLBARWIDTH 15
  35.  
  36. #define DEFAULTWIDTH 300  /* widget size when show_all is False */
  37.  
  38. #define offset(field) XtOffsetOf(BitmapEditRec, field)
  39.  
  40. static XtResource resources[] = {
  41. /* not needed in Motif - already defined by Primitive.
  42.  *    {
  43.  *   XtNforeground, 
  44.  *   XtCForeground, 
  45.  *   XtRPixel, 
  46.  *   sizeof(Pixel),
  47.  *   offset(bitmapEdit.foreground), 
  48.  *   XtRString, 
  49.  *   XtDefaultForeground
  50.  *    },
  51.  */
  52.      {
  53.     XtNtoggleCallback, 
  54.     XtCToggleCallback, 
  55.     XtRCallback, 
  56.     sizeof(XtPointer),
  57.     offset(bitmapEdit.callback), 
  58.     XtRCallback, 
  59.     NULL
  60.      },
  61.      {
  62.     XtNcellSizeInPixels, 
  63.     XtCCellSizeInPixels, 
  64.     XtRInt, sizeof(int),
  65.     offset(bitmapEdit.cell_size_in_pixels), 
  66.     XtRImmediate, 
  67.     (XtPointer)DEFAULT_CELL_SIZE
  68.      },
  69.      {
  70.     XtNpixmapWidthInCells, 
  71.     XtCPixmapWidthInCells, 
  72.     XtRDimension, 
  73.     sizeof(Dimension),
  74.     offset(bitmapEdit.pixmap_width_in_cells), 
  75.     XtRImmediate, 
  76.     (XtPointer)DEFAULT_PIXMAP_WIDTH
  77.      },
  78.      {
  79.     XtNpixmapHeightInCells, 
  80.     XtCPixmapHeightInCells, 
  81.     XtRDimension, 
  82.     sizeof(Dimension),
  83.     offset(bitmapEdit.pixmap_height_in_cells), 
  84.     XtRImmediate, 
  85.     (XtPointer)DEFAULT_PIXMAP_HEIGHT
  86.      },
  87.      {
  88.     XtNcurX, 
  89.     XtCCurX, 
  90.     XtRInt, 
  91.     sizeof(int),
  92.     offset(bitmapEdit.cur_x), 
  93.     XtRImmediate, 
  94.     (XtPointer) 0
  95.      },
  96.      {
  97.     XtNcurY, 
  98.     XtCCurY, 
  99.     XtRInt, 
  100.     sizeof(int),
  101.     offset(bitmapEdit.cur_y), 
  102.     XtRImmediate, 
  103.     (XtPointer) 0
  104.      },
  105.      {
  106.     XtNcellArray, 
  107.     XtCCellArray, 
  108.     XtRString, 
  109.     sizeof(String),
  110.     offset(bitmapEdit.cell), 
  111.     XtRImmediate, 
  112.     (XtPointer) 0
  113.      },
  114.      {
  115.     XtNshowEntireBitmap, 
  116.     XtCShowEntireBitmap, 
  117.     XtRBoolean, 
  118.     sizeof(Boolean),
  119.     offset(bitmapEdit.show_all), 
  120.     XtRImmediate, 
  121.     (XtPointer) TRUE
  122.      },
  123. };
  124.  
  125. /* Declaration of methods */
  126.  
  127. static void Initialize();
  128. static void Redisplay();
  129. static void Destroy();
  130. static void Resize();
  131. static Boolean SetValues();
  132. static XtGeometryResult QueryGeometry();
  133.  
  134. /* these Core methods not needed by BitmapEdit:
  135.  *
  136.  * static void ClassInitialize();
  137.  * static void Realize();
  138.  */
  139.  
  140. /* the following are private functions unique to BitmapEdit */
  141. static void DrawPixmaps(), DoCell(), ChangeCellSize();
  142.  
  143. /* the following are actions of BitmapEdit */
  144. static void DrawCell(), UndrawCell(), ToggleCell();
  145.  
  146. /* The following are public functions of BitmapEdit, declared extern
  147.  * in the public include file: */
  148. char *BitmapEditGetArray(); 
  149.  
  150. static char defaultTranslations[] =
  151.     "<Btn1Down>:    DrawCell()              \n\
  152.     <Btn2Down>:    UndrawCell()            \n\
  153.     <Btn3Down>:    ToggleCell()            \n\
  154.     <Btn1Motion>:  DrawCell()              \n\
  155.     <Btn2Motion>:  UndrawCell()            \n\
  156.     <Btn3Motion>:  ToggleCell()";
  157.  
  158. static XtActionsRec actions[] = {
  159.         {"DrawCell", DrawCell},
  160.         {"UndrawCell", UndrawCell},
  161.         {"ToggleCell", ToggleCell},
  162. };
  163.  
  164. /* definition in BitmapEdit.h */
  165. static BitmapEditPointInfo info;
  166.  
  167. BitmapEditClassRec bitmapEditClassRec = {
  168.     {
  169.     /* core_class fields */
  170.     /* superclass        */ (WidgetClass) &xmPrimitiveClassRec,
  171.     /* class_name        */ "BitmapEdit",
  172.     /* widget_size       */ sizeof(BitmapEditRec),
  173.     /* class_initialize      */ NULL,
  174.     /* class_part_initialize     */ NULL,
  175.     /* class_inited          */ FALSE,
  176.     /* initialize        */ Initialize,
  177.     /* initialize_hook       */ NULL,
  178.     /* realize           */ XtInheritRealize,
  179.     /* actions           */ actions,
  180.     /* num_actions       */ XtNumber(actions),
  181.     /* resources         */ resources,
  182.     /* num_resources         */ XtNumber(resources),
  183.     /* xrm_class         */ NULLQUARK,
  184.     /* compress_motion       */ TRUE,
  185.     /* compress_exposure     */ XtExposeCompressMultiple,
  186.     /* compress_enterleave   */ TRUE,
  187.     /* visible_interest      */ FALSE,
  188.     /* destroy           */ Destroy,
  189.     /* resize            */ Resize,
  190.     /* expose            */ Redisplay,
  191.     /* set_values        */ SetValues,
  192.     /* set_values_hook       */ NULL,
  193.     /* set_values_almost     */ XtInheritSetValuesAlmost,
  194.     /* get_values_hook       */ NULL,
  195.     /* accept_focus      */ NULL,
  196.     /* version           */ XtVersion,
  197.     /* callback_private      */ NULL,
  198.     /* tm_table          */ defaultTranslations,
  199.     /* query_geometry        */ QueryGeometry,
  200.     /* display_accelerator       */ XtInheritDisplayAccelerator,
  201.     /* extension                 */ NULL
  202.     },
  203.     {  /* Primitive class fields */
  204.     /* border_highlight   */        _XtInherit,       
  205.     /* border_unhighlight */        _XtInherit,    
  206.     /* translations       */        XtInheritTranslations,      
  207.     /* arm_and_activate   */        NULL,             
  208.     /* syn resources      */        NULL,           
  209.     /* num_syn_resources  */        0, 
  210.     /* extension          */        NULL,             
  211.     },
  212.     {
  213.     /* extension          */        0,
  214.     },
  215. };
  216.  
  217. WidgetClass bitmapEditWidgetClass = (WidgetClass) & bitmapEditClassRec;
  218.  
  219. static void
  220. GetDrawGC(w)
  221. Widget w;
  222. {
  223.     BitmapEditWidget cw = (BitmapEditWidget) w;
  224.     XGCValues values;
  225.     XtGCMask mask = GCForeground | GCBackground | GCDashOffset | 
  226.             GCDashList | GCLineStyle;
  227.  
  228.     /* 
  229.      * Setting foreground and background to 1 and 0 looks like a 
  230.      * kludge but isn't.  This GC is used for drawing
  231.      * into a pixmap of depth one.  Real colors are applied with a
  232.      * separate GC when the pixmap is copied into the window.
  233.      */
  234.     values.foreground = 1;
  235.     values.background = 0;
  236.     values.dashes = 1;
  237.     values.dash_offset = 0;
  238.     values.line_style = LineOnOffDash;
  239.  
  240.     cw->bitmapEdit.draw_gc = XCreateGC(XtDisplay(cw), 
  241.              cw->bitmapEdit.big_picture, mask, &values);
  242. }
  243.  
  244. static void
  245. GetUndrawGC(w)
  246. Widget w;
  247. {
  248.     BitmapEditWidget cw = (BitmapEditWidget) w;
  249.     XGCValues values;
  250.     XtGCMask mask = GCForeground | GCBackground;
  251.  
  252.     /* this looks like a kludge but isn't.  This GC is used for drawing
  253.      * into a pixmap of depth one.  Real colors are applied as the 
  254.      * pixmap is copied into the window.
  255.      */
  256.     values.foreground = 0;
  257.     values.background = 1;
  258.  
  259.     cw->bitmapEdit.undraw_gc = XCreateGC(XtDisplay(cw), 
  260.               cw->bitmapEdit.big_picture, mask, &values);
  261. }
  262.  
  263. static void
  264. GetCopyGC(w)
  265. Widget w;
  266. {
  267.     BitmapEditWidget cw = (BitmapEditWidget) w;
  268.     XGCValues values;
  269.     XtGCMask mask = GCForeground | GCBackground;
  270.  
  271.     values.foreground = cw->primitive.foreground;
  272.     values.background = cw->core.background_pixel;
  273.  
  274.     cw->bitmapEdit.copy_gc = XtGetGC(cw, mask, &values);
  275. }
  276.  
  277. /* ARGSUSED */
  278. static void
  279. Initialize(treq, tnew, args, num_args)
  280. Widget treq, tnew;
  281. ArgList args;
  282. Cardinal *num_args;
  283. {
  284.     BitmapEditWidget new = (BitmapEditWidget) tnew;
  285.     new->bitmapEdit.cur_x = 0;
  286.     new->bitmapEdit.cur_y = 0;
  287.  
  288.     /* 
  289.      *  Check instance values set by resources that may be invalid. 
  290.      */
  291.  
  292.     if ((new->bitmapEdit.pixmap_width_in_cells < 1) ||
  293.             (new->bitmapEdit.pixmap_height_in_cells < 1))  {
  294.         XtWarning("BitmapEdit: pixmapWidth and/or pixmapHeight is too small (using 10 x 10)."); 
  295.         new->bitmapEdit.pixmap_width_in_cells = 10;
  296.         new->bitmapEdit.pixmap_height_in_cells = 10;
  297.     }
  298.  
  299.     if (new->bitmapEdit.cell_size_in_pixels < 5) {
  300.         XtWarning("BitmapEdit: cellSize is too small (using 5)."); 
  301.         new->bitmapEdit.cell_size_in_pixels = 5;
  302.     }
  303.  
  304.     if ((new->bitmapEdit.cur_x < 0) ||  (new->bitmapEdit.cur_y < 0)) {
  305.         XtWarning("BitmapEdit: cur_x and cur_y must be non-negative (using 0, 0)."); 
  306.         new->bitmapEdit.cur_x = 0;
  307.         new->bitmapEdit.cur_y = 0;
  308.     }
  309.  
  310.     if (new->bitmapEdit.cell == NULL)
  311.         new->bitmapEdit.cell = XtCalloc( 
  312.                 new->bitmapEdit.pixmap_width_in_cells * 
  313.                 new->bitmapEdit.pixmap_height_in_cells, sizeof(char));
  314.     else
  315.         new->bitmapEdit.user_allocated = True;  /* user supplied cell array */
  316.  
  317.     new->bitmapEdit.pixmap_width_in_pixels = 
  318.            new->bitmapEdit.pixmap_width_in_cells * 
  319.            new->bitmapEdit.cell_size_in_pixels;
  320.  
  321.     new->bitmapEdit.pixmap_height_in_pixels = 
  322.            new->bitmapEdit.pixmap_height_in_cells * 
  323.            new->bitmapEdit.cell_size_in_pixels;
  324.  
  325.     /* 
  326.      * Motif Primitive sets width and height to provide enough room for
  327.      * the highlight and shadow around a widget.  BitmapEdit
  328.      * doesn't use these features.  A widget that did use these
  329.      * features would *add* its desired dimensions to those set
  330.      * by Primitive.  To use this widget with another widget set, remove
  331.      * the following two lines. 
  332.      */
  333.     new->core.width = 0;
  334.     new->core.height = 0;
  335.  
  336.     if (new->core.width == 0) {
  337.         if (new->bitmapEdit.show_all == False)
  338.             new->core.width = (new->bitmapEdit.pixmap_width_in_pixels 
  339.                     > DEFAULTWIDTH) ? DEFAULTWIDTH : 
  340.                     (new->bitmapEdit.pixmap_width_in_pixels);
  341.         else
  342.             new->core.width = new->bitmapEdit.pixmap_width_in_pixels;
  343.     }
  344.  
  345.     if (new->core.height == 0) {
  346.         if (new->bitmapEdit.show_all == False)
  347.             new->core.height = 
  348.                     (new->bitmapEdit.pixmap_height_in_pixels > 
  349.                     DEFAULTWIDTH) ? DEFAULTWIDTH : 
  350.                     (new->bitmapEdit.pixmap_height_in_pixels);
  351.         else
  352.             new->core.height = new->bitmapEdit.pixmap_height_in_pixels;
  353.     }
  354.  
  355.     /* tell Primitive not to allow tabbing to this widget */ 
  356.     XtVaSetValues(new,
  357.         XmNtraversalOn, False,
  358.         NULL);
  359.  
  360.     CreateBigPixmap(new);
  361.  
  362.     GetDrawGC(new);
  363.     GetUndrawGC(new);
  364.     GetCopyGC(new);
  365.  
  366.     DrawIntoBigPixmap(new);
  367. }
  368.  
  369. /* ARGSUSED */
  370. static void
  371. Redisplay(w, event)
  372. Widget w;
  373. XExposeEvent *event;
  374. {
  375.     BitmapEditWidget cw = (BitmapEditWidget) w;
  376.     register int x, y;
  377.     unsigned int width, height;
  378.     if (!XtIsRealized(cw))
  379.     return;
  380.  
  381.     if (event) {  /* called from btn-event or expose */
  382.         x = event->x;
  383.         y = event->y; 
  384.         width = event->width;
  385.         height =  event->height;
  386.     } 
  387.     else {        /* called because complete redraw */
  388.         x = 0;
  389.         y = 0; 
  390.         width = cw->bitmapEdit.pixmap_width_in_pixels;
  391.         height = cw->bitmapEdit.pixmap_height_in_pixels;
  392.     }
  393.  
  394.     if (DefaultDepthOfScreen(XtScreen(cw)) == 1)
  395.         XCopyArea(XtDisplay(cw), cw->bitmapEdit.big_picture, 
  396.                 XtWindow(cw), cw->bitmapEdit.copy_gc, x + 
  397.                 cw->bitmapEdit.cur_x, y + cw->bitmapEdit.cur_y, 
  398.                 width, height, x, y);
  399.     else
  400.         XCopyPlane(XtDisplay(cw), cw->bitmapEdit.big_picture, 
  401.                 XtWindow(cw), cw->bitmapEdit.copy_gc, x + 
  402.                 cw->bitmapEdit.cur_x, y + cw->bitmapEdit.cur_y, 
  403.                 width, height, x, y, 1);
  404. }
  405.  
  406. /* ARGSUSED */
  407. static Boolean
  408. SetValues(current, request, new, args, num_args)
  409. Widget current, request, new;
  410. ArgList args;
  411. Cardinal *num_args;
  412. {
  413.     BitmapEditWidget curcw = (BitmapEditWidget) current;
  414.     BitmapEditWidget newcw = (BitmapEditWidget) new;
  415.     Boolean do_redisplay = False;
  416.  
  417.     if (curcw->primitive.foreground != newcw->primitive.foreground) {
  418.         XtReleaseGC(curcw, curcw->bitmapEdit.copy_gc);
  419.         GetCopyGC(newcw);
  420.         do_redisplay = True;
  421.     }
  422.  
  423.     if ((curcw->bitmapEdit.cur_x != newcw->bitmapEdit.cur_x) || 
  424.             (curcw->bitmapEdit.cur_y != newcw->bitmapEdit.cur_y))
  425.         do_redisplay = True;
  426.  
  427.     if (curcw->bitmapEdit.cell_size_in_pixels != 
  428.             newcw->bitmapEdit.cell_size_in_pixels) {
  429.         ChangeCellSize(curcw, newcw->bitmapEdit.cell_size_in_pixels);
  430.         do_redisplay = True;
  431.     }
  432.  
  433.     if (curcw->bitmapEdit.pixmap_width_in_cells != 
  434.             newcw->bitmapEdit.pixmap_width_in_cells)  {
  435.         newcw->bitmapEdit.pixmap_width_in_cells = 
  436.                 curcw->bitmapEdit.pixmap_width_in_cells;
  437.         XtWarning("BitmapEdit: pixmap_width_in_cells cannot be set by XtSetValues.\n");
  438.     }
  439.  
  440.     if (curcw->bitmapEdit.pixmap_height_in_cells != 
  441.             newcw->bitmapEdit.pixmap_height_in_cells) {
  442.         newcw->bitmapEdit.pixmap_height_in_cells = 
  443.                 curcw->bitmapEdit.pixmap_height_in_cells;
  444.         XtWarning("BitmapEdit: pixmap_height_in_cells cannot be set by XtSetValues.\n");
  445.     }
  446.  
  447.     return do_redisplay;
  448. }
  449.  
  450.  
  451. static void
  452. Destroy(w)
  453. Widget w;
  454. {
  455.     BitmapEditWidget cw = (BitmapEditWidget) w;
  456.     if (cw->bitmapEdit.big_picture)
  457.         XFreePixmap(XtDisplay(cw), cw->bitmapEdit.big_picture);
  458.  
  459.     if (cw->bitmapEdit.draw_gc)
  460.         XFreeGC(XtDisplay(cw), cw->bitmapEdit.draw_gc);
  461.  
  462.     if (cw->bitmapEdit.undraw_gc)
  463.         XFreeGC(XtDisplay(cw), cw->bitmapEdit.undraw_gc);
  464.  
  465.     if (cw->bitmapEdit.copy_gc)
  466.         XFreeGC(XtDisplay(cw), cw->bitmapEdit.copy_gc);
  467.  
  468.     /* Free memory allocated with Calloc.  This was done
  469.      * only if application didn't supply cell array.
  470.      */
  471.     if (!cw->bitmapEdit.user_allocated)
  472.         XtFree(cw->bitmapEdit.cell);
  473. }
  474.  
  475. static void
  476. DrawCell(w, event)
  477. Widget w;
  478. XEvent *event;
  479. {
  480.     BitmapEditWidget cw = (BitmapEditWidget) w;
  481.     DrawPixmaps(cw->bitmapEdit.draw_gc, DRAW, cw, event);
  482. }
  483.  
  484. static void
  485. UndrawCell(w, event)
  486. Widget w;
  487. XEvent *event;
  488. {
  489.     BitmapEditWidget cw = (BitmapEditWidget) w;
  490.     DrawPixmaps(cw->bitmapEdit.undraw_gc, UNDRAW, cw, event);
  491. }
  492.  
  493. static void
  494. ToggleCell(w, event)
  495. Widget w;
  496. XEvent *event;
  497. {
  498.     BitmapEditWidget cw = (BitmapEditWidget) w;
  499.     static int oldx = -1, oldy = -1;
  500.     GC gc;
  501.     int mode;
  502.     int newx, newy;
  503.  
  504.     /* This is strictly correct, but doesn't
  505.      * seem to be necessary */
  506.     if (event->type == ButtonPress) {
  507.         newx = (cw->bitmapEdit.cur_x + ((XButtonEvent *)event)->x) / 
  508.         cw->bitmapEdit.cell_size_in_pixels;
  509.         newy = (cw->bitmapEdit.cur_y + ((XButtonEvent *)event)->y) / 
  510.         cw->bitmapEdit.cell_size_in_pixels;
  511.     }
  512.     else  {
  513.         newx = (cw->bitmapEdit.cur_x + ((XMotionEvent *)event)->x) / 
  514.         cw->bitmapEdit.cell_size_in_pixels;
  515.         newy = (cw->bitmapEdit.cur_y + ((XMotionEvent *)event)->y) / 
  516.         cw->bitmapEdit.cell_size_in_pixels;
  517.     }
  518.  
  519.  
  520.     if ((mode = cw->bitmapEdit.cell[newx + newy * cw->bitmapEdit.pixmap_width_in_cells]) == DRAWN) {
  521.         gc = cw->bitmapEdit.undraw_gc;
  522.         mode = UNDRAW;
  523.     }
  524.     else {
  525.         gc = cw->bitmapEdit.draw_gc;
  526.         mode = DRAW;
  527.     }
  528.  
  529.     if (oldx != newx || oldy != newy) {
  530.         oldx = newx;
  531.         oldy = newy;
  532.         DrawPixmaps(gc, mode, cw, event);
  533.     } 
  534. }
  535.  
  536. static void
  537. DrawPixmaps(gc, mode, w, event)
  538. GC gc;
  539. int mode;
  540. Widget w;
  541. XButtonEvent *event;
  542. {
  543.     BitmapEditWidget cw = (BitmapEditWidget) w;
  544.     int newx = (cw->bitmapEdit.cur_x + event->x) / 
  545.              cw->bitmapEdit.cell_size_in_pixels;
  546.     int newy = (cw->bitmapEdit.cur_y + event->y) / 
  547.              cw->bitmapEdit.cell_size_in_pixels;
  548.     XExposeEvent fake_event;
  549.  
  550.     /* if already done, return */
  551.     if (cw->bitmapEdit.cell[newx + newy * cw->bitmapEdit.pixmap_width_in_cells] == mode)
  552.         return;
  553.  
  554.     /* otherwise, draw or undraw */
  555.     XFillRectangle(XtDisplay(cw), cw->bitmapEdit.big_picture, gc,
  556.             cw->bitmapEdit.cell_size_in_pixels*newx + 2, 
  557.         cw->bitmapEdit.cell_size_in_pixels*newy + 2, 
  558.         (unsigned int)cw->bitmapEdit.cell_size_in_pixels - 3, 
  559.         (unsigned int)cw->bitmapEdit.cell_size_in_pixels - 3);
  560.  
  561.     cw->bitmapEdit.cell[newx + newy * cw->bitmapEdit.pixmap_width_in_cells] = mode;
  562.     info.mode = mode;
  563.     info.newx = newx;
  564.     info.newy = newy;
  565.  
  566.     fake_event.x = cw->bitmapEdit.cell_size_in_pixels * newx - cw->bitmapEdit.cur_x;
  567.     fake_event.y = cw->bitmapEdit.cell_size_in_pixels * newy - cw->bitmapEdit.cur_y;
  568.     fake_event.width = cw->bitmapEdit.cell_size_in_pixels;
  569.     fake_event.height = cw->bitmapEdit.cell_size_in_pixels;
  570.  
  571.     Redisplay(cw, &fake_event);
  572.     XtCallCallbacks(cw, XtNtoggleCallback, &info);
  573. }
  574.  
  575. CreateBigPixmap(w)
  576. Widget w;
  577. {
  578.     BitmapEditWidget cw = (BitmapEditWidget) w;
  579.     /* always a 1 bit deep pixmap, regardless of screen depth */
  580.     cw->bitmapEdit.big_picture = XCreatePixmap(XtDisplay(cw),
  581.             RootWindow(XtDisplay(cw), DefaultScreen(XtDisplay(cw))),
  582.             cw->bitmapEdit.pixmap_width_in_pixels + 2, 
  583.             cw->bitmapEdit.pixmap_height_in_pixels + 2, 1);
  584. }
  585.  
  586. DrawIntoBigPixmap(w)
  587. Widget w;
  588. {
  589.     BitmapEditWidget cw = (BitmapEditWidget) w;
  590.     int n_horiz_segments, n_vert_segments;
  591.     XSegment segment[MAXLINES];
  592.     register int x, y;
  593.  
  594.     XFillRectangle(XtDisplay(cw), cw->bitmapEdit.big_picture,
  595.         cw->bitmapEdit.undraw_gc, 0, 0, 
  596.         cw->bitmapEdit.pixmap_width_in_pixels 
  597.         + 2, cw->bitmapEdit.pixmap_height_in_pixels + 2);
  598.  
  599.     n_horiz_segments = cw->bitmapEdit.pixmap_height_in_cells + 1;
  600.     n_vert_segments = cw->bitmapEdit.pixmap_width_in_cells + 1;
  601.  
  602.     for (x = 0; x < n_horiz_segments; x++) {
  603.         segment[x].x1 = 0;
  604.         segment[x].x2 = (short) cw->bitmapEdit.pixmap_width_in_pixels;
  605.         segment[x].y1 = (short) cw->bitmapEdit.cell_size_in_pixels * x;
  606.         segment[x].y2 = (short) cw->bitmapEdit.cell_size_in_pixels * x;
  607.     }
  608.  
  609.     XDrawSegments(XtDisplay(cw), cw->bitmapEdit.big_picture, cw->bitmapEdit.draw_gc, segment, n_horiz_segments);
  610.  
  611.     for (y = 0; y < n_vert_segments; y++) {
  612.         segment[y].x1 = (short) y * cw->bitmapEdit.cell_size_in_pixels;
  613.         segment[y].x2 = (short) y * cw->bitmapEdit.cell_size_in_pixels;
  614.         segment[y].y1 = 0;
  615.         segment[y].y2 = (short) cw->bitmapEdit.pixmap_height_in_pixels;
  616.     }
  617.  
  618.     XDrawSegments(XtDisplay(cw), cw->bitmapEdit.big_picture, cw->bitmapEdit.draw_gc, segment, n_vert_segments);
  619.  
  620.     /* draw current cell array into pixmap */
  621.     for (x = 0; x < cw->bitmapEdit.pixmap_width_in_cells; x++) {
  622.         for (y = 0; y < cw->bitmapEdit.pixmap_height_in_cells; y++) {
  623.             if (cw->bitmapEdit.cell[x + (y * cw->bitmapEdit.pixmap_width_in_cells)] == DRAWN)
  624.                 DoCell(cw, x, y, cw->bitmapEdit.draw_gc);
  625.             else
  626.                 DoCell(cw, x, y, cw->bitmapEdit.undraw_gc);
  627.         }
  628.     }
  629. }
  630.  
  631. /* A Public function, not static */
  632. char *
  633. BitmapEditGetArray(w, width_in_cells, height_in_cells)
  634. Widget w;
  635. int *width_in_cells, *height_in_cells;
  636. {
  637.     BitmapEditWidget cw = (BitmapEditWidget) w;
  638.  
  639.     *width_in_cells = cw->bitmapEdit.pixmap_width_in_cells;
  640.     *height_in_cells = cw->bitmapEdit.pixmap_height_in_cells;
  641.     return (cw->bitmapEdit.cell);
  642. }
  643.  
  644. /* ARGSUSED */
  645. static void
  646. Resize(w)
  647. Widget w;
  648. {
  649.     BitmapEditWidget cw = (BitmapEditWidget) w;
  650.     /* resize does nothing unless new size is bigger than entire pixmap */
  651.     if ((cw->core.width > cw->bitmapEdit.pixmap_width_in_pixels) &&
  652.             (cw->core.height > cw->bitmapEdit.pixmap_height_in_pixels)) {
  653.         /* 
  654.          * Calculate the maximum cell size that will allow the
  655.          * entire bitmap to be displayed.
  656.          */
  657.         Dimension w_temp_cell_size_in_pixels, h_temp_cell_size_in_pixels;
  658.         Dimension new_cell_size_in_pixels;
  659.     
  660.         w_temp_cell_size_in_pixels = cw->core.width / cw->bitmapEdit.pixmap_width_in_cells;
  661.         h_temp_cell_size_in_pixels = cw->core.height / cw->bitmapEdit.pixmap_height_in_cells;
  662.     
  663.         if (w_temp_cell_size_in_pixels < h_temp_cell_size_in_pixels)
  664.             new_cell_size_in_pixels = w_temp_cell_size_in_pixels;
  665.         else
  666.             new_cell_size_in_pixels = h_temp_cell_size_in_pixels;
  667.     
  668.         /* if size change mandates a new pixmap, make one */
  669.         if (new_cell_size_in_pixels != cw->bitmapEdit.cell_size_in_pixels)
  670.             ChangeCellSize(cw, new_cell_size_in_pixels);
  671.     }
  672. }
  673.  
  674. static void
  675. ChangeCellSize(w, new_cell_size)
  676. Widget w;
  677. int new_cell_size;
  678. {
  679.     BitmapEditWidget cw = (BitmapEditWidget) w;
  680.     int x, y;
  681.  
  682.     cw->bitmapEdit.cell_size_in_pixels = new_cell_size;
  683.  
  684.     /* recalculate variables based on cell size */
  685.     cw->bitmapEdit.pixmap_width_in_pixels = 
  686.              cw->bitmapEdit.pixmap_width_in_cells * 
  687.              cw->bitmapEdit.cell_size_in_pixels;
  688.  
  689.     cw->bitmapEdit.pixmap_height_in_pixels = 
  690.              cw->bitmapEdit.pixmap_height_in_cells * 
  691.              cw->bitmapEdit.cell_size_in_pixels;
  692.     
  693.     /* destroy old and create new pixmap of correct size */
  694.     XFreePixmap(XtDisplay(cw), cw->bitmapEdit.big_picture);
  695.     CreateBigPixmap(cw);
  696.     
  697.     /* draw lines into new pixmap */
  698.     DrawIntoBigPixmap(cw);
  699.     
  700.     /* draw current cell array into pixmap */
  701.     for (x = 0; x < cw->bitmapEdit.pixmap_width_in_cells; x++) {
  702.         for (y = 0; y < cw->bitmapEdit.pixmap_height_in_cells; y++) {
  703.             if (cw->bitmapEdit.cell[x + (y * cw->bitmapEdit.pixmap_width_in_cells)] == DRAWN)
  704.                 DoCell(cw, x, y, cw->bitmapEdit.draw_gc);
  705.             else
  706.                 DoCell(cw, x, y, cw->bitmapEdit.undraw_gc);
  707.         }
  708.     }
  709. }
  710.  
  711. static void
  712. DoCell(w, x, y, gc)
  713. Widget w;
  714. int x, y;
  715. GC gc;
  716. {
  717.     BitmapEditWidget cw = (BitmapEditWidget) w;
  718.         /* otherwise, draw or undraw */
  719.     XFillRectangle(XtDisplay(cw), cw->bitmapEdit.big_picture, gc,
  720.              cw->bitmapEdit.cell_size_in_pixels * x + 2,
  721.              cw->bitmapEdit.cell_size_in_pixels * y + 2,
  722.              (unsigned int)cw->bitmapEdit.cell_size_in_pixels - 3,
  723.              (unsigned int)cw->bitmapEdit.cell_size_in_pixels - 3);
  724.  
  725. }
  726.  
  727. static XtGeometryResult QueryGeometry(w, proposed, answer)
  728. Widget w;
  729. XtWidgetGeometry *proposed, *answer;
  730. {
  731.     BitmapEditWidget cw = (BitmapEditWidget) w;
  732.  
  733.     /* set fields we care about */
  734.     answer->request_mode = CWWidth | CWHeight;
  735.  
  736.     /* initial width and height */
  737.     if (cw->bitmapEdit.show_all == True)
  738.         answer->width = cw->bitmapEdit.pixmap_width_in_pixels;
  739.     else
  740.         answer->width = (cw->bitmapEdit.pixmap_width_in_pixels > 
  741.                 DEFAULTWIDTH) ? DEFAULTWIDTH : 
  742.                 cw->bitmapEdit.pixmap_width_in_pixels;
  743.  
  744.     if (cw->bitmapEdit.show_all == True)
  745.         answer->height = cw->bitmapEdit.pixmap_height_in_pixels;
  746.     else
  747.         answer->height = (cw->bitmapEdit.pixmap_height_in_pixels > 
  748.                 DEFAULTWIDTH) ? DEFAULTWIDTH : 
  749.                 cw->bitmapEdit.pixmap_height_in_pixels;
  750.  
  751.     if (  ((proposed->request_mode & (CWWidth | CWHeight))
  752.             == (CWWidth | CWHeight)) &&
  753.             proposed->width == answer->width &&
  754.             proposed->height == answer->height)
  755.         return XtGeometryYes;
  756.     else if (answer->width == cw->core.width &&
  757.             answer->height == cw->core.height)
  758.         return XtGeometryNo;
  759.     else
  760.         return XtGeometryAlmost;
  761. }
  762.