home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / amiga / gui / x / xfig.lha / src / x11 / w_rulers.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-26  |  31.1 KB  |  1,077 lines

  1. /*
  2.  * FIG : Facility for Interactive Generation of figures
  3.  * Copyright (c) 1985 by Supoj Sutanthavibul
  4.  *
  5.  * "Permission to use, copy, modify, distribute, and sell this software and its
  6.  * documentation for any purpose is hereby granted without fee, provided that
  7.  * the above copyright notice appear in all copies and that both the copyright
  8.  * notice and this permission notice appear in supporting documentation. 
  9.  * No representations are made about the suitability of this software for 
  10.  * any purpose.  It is provided "as is" without express or implied warranty."
  11.  */
  12.  
  13. #include "fig.h"
  14. #include "figx.h"
  15. #include "resources.h"
  16. #include "mode.h"
  17. #include "paintop.h"
  18. #include "w_drawprim.h"
  19. #include "w_mousefun.h"
  20. #include "w_setup.h"
  21. #include "w_util.h"
  22. #include "w_zoom.h"
  23.  
  24. /*
  25.  * The following will create rulers the same size as the initial screen size.
  26.  * if the user resizes the xfig window, the rulers won't have numbers there.
  27.  * Should really reset the sizes if the screen resizes.
  28.  */
  29.  
  30. /*
  31.  * set maximum ruler size:
  32.  * color servers for Vaxstations screw up the pixmaps if the rulers are
  33.  * made too big (they can't handle pixmaps much larger than the screen)
  34.  */
  35.  
  36. #define            INCH_MARK        8
  37. #define            HALF_MARK        8
  38. #define            QUARTER_MARK        6
  39. #define            SIXTEENTH_MARK        4
  40.  
  41. #define            TRM_WID            16
  42. #define            TRM_HT            8
  43. #define            SRM_WID            8
  44. #define            SRM_HT            16
  45.  
  46. extern        pan_origin();
  47. GC        tr_gc, tr_xor_gc, tr_erase_gc;
  48. GC        sr_gc, sr_xor_gc, sr_erase_gc;
  49.  
  50. static int    lasty = -100, lastx = -100;
  51. static int    troffx = -8, troffy = -10;
  52. static int    orig_zoomoff;
  53. static int    last_drag_x, last_drag_y;
  54. static unsigned char    tr_marker_image[16] = {
  55.     0xFE, 0xFF,        /* ***************  */
  56.     0x04, 0x40,        /*  *           *  */
  57.     0x08, 0x20,        /*   *         *  */
  58.     0x10, 0x10,        /*    *       *  */
  59.     0x20, 0x08,        /*     *     *  */
  60.     0x40, 0x04,        /*      *   *  */
  61.     0x80, 0x02,        /*       * *  */
  62.     0x00, 0x01,        /*        *  */
  63. };
  64. static        mpr_static(trm_pr, TRM_WID, TRM_HT, 1, tr_marker_image);
  65. static int    srroffx = 2, srroffy = -7;
  66. static unsigned char    srr_marker_image[16] = {
  67.     0x80,        /*        *  */
  68.     0xC0,        /*       **  */
  69.     0xA0,        /*      * *  */
  70.     0x90,        /*     *  *  */
  71.     0x88,        /*    *   *  */
  72.     0x84,        /*   *    *  */
  73.     0x82,        /*  *     *  */
  74.     0x81,        /* *      *  */
  75.     0x82,        /*  *     *  */
  76.     0x84,        /*   *    *  */
  77.     0x88,        /*    *   *  */
  78.     0x90,        /*     *  *  */
  79.     0xA0,        /*      * *  */
  80.     0xC0,        /*       **  */
  81.     0x80,        /*        *  */
  82.     0x00
  83. };
  84. static        mpr_static(srrm_pr, SRM_WID, SRM_HT, 1, srr_marker_image);
  85.  
  86. static int    srloffx = -10, srloffy = -7;
  87. static unsigned char    srl_marker_image[16] = {
  88.     0x01,        /* *          */
  89.     0x03,        /* **          */
  90.     0x05,        /* * *          */
  91.     0x09,        /* *  *          */
  92.     0x11,        /* *   *      */
  93.     0x21,        /* *    *     */
  94.     0x41,        /* *     *    */
  95.     0x81,        /* *      *   */
  96.     0x41,        /* *     *    */
  97.     0x21,        /* *    *     */
  98.     0x11,        /* *   *      */
  99.     0x09,        /* *  *          */
  100.     0x05,        /* * *          */
  101.     0x03,        /* **          */
  102.     0x01,        /* *          */
  103.     0x00
  104. };
  105. static        mpr_static(srlm_pr, SRM_WID, SRM_HT, 1, srl_marker_image);
  106.  
  107. static Pixmap    toparrow_pm = 0, sidearrow_pm = 0;
  108. static Pixmap    topruler_pm = 0, sideruler_pm = 0;
  109.  
  110. DeclareStaticArgs(14);
  111.  
  112. static        topruler_selected();
  113. static        topruler_exposed();
  114. static        sideruler_selected();
  115. static        sideruler_exposed();
  116.  
  117. redisplay_rulers()
  118. {
  119.     redisplay_topruler();
  120.     redisplay_sideruler();
  121. }
  122.  
  123. setup_rulers()
  124. {
  125.     setup_topruler();
  126.     setup_sideruler();
  127. }
  128.  
  129. reset_rulers()
  130. {
  131.     reset_topruler();
  132.     reset_sideruler();
  133. }
  134.  
  135. set_rulermark(x, y)
  136.     int            x, y;
  137. {
  138.     if (appres.TRACKING) {
  139.     set_siderulermark(y);
  140.     set_toprulermark(x);
  141.     }
  142. }
  143.  
  144. erase_rulermark()
  145. {
  146.     if (appres.TRACKING) {
  147.     erase_siderulermark();
  148.     erase_toprulermark();
  149.     }
  150. }
  151.  
  152. #define HINCH    (PIX_PER_INCH / 2)
  153. #define QINCH    (PIX_PER_INCH / 4)
  154. #define SINCH    (PIX_PER_INCH / 16)
  155. #define TWOMM    (PIX_PER_CM / 5)
  156.  
  157. /************************* UNITBOX ************************/
  158.  
  159. extern Widget   make_popup_menu();
  160. extern Atom     wm_delete_window;
  161. extern char    *panel_get_value();
  162. void popup_unit_panel();
  163. static int      rul_unit_setting, fig_unit_setting=0, fig_scale_setting=0;
  164. static Widget   rul_unit_panel, fig_unit_panel, fig_scale_panel;
  165. static Widget   rul_unit_menu, fig_unit_menu, fig_scale_menu;
  166. static Widget   scale_factor_lab, scale_factor_panel;
  167. static Widget   user_unit_lab, user_unit_panel;
  168.  
  169.  
  170. XtActionsRec    unitbox_actions[] =
  171. {
  172.     {"EnterUnitBox", (XtActionProc) draw_mousefun_unitbox},
  173.     {"LeaveUnitBox", (XtActionProc) clear_mousefun},
  174.     {"HomeRulers", (XtActionProc) pan_origin},
  175.     {"PopupUnits", (XtActionProc) popup_unit_panel},
  176. };
  177.  
  178. static String    unitbox_translations =
  179. "<EnterWindow>:EnterUnitBox()\n\
  180.     <LeaveWindow>:LeaveUnitBox()\n\
  181.     <Btn1Down>:HomeRulers()\n\
  182.     <Btn3Down>:PopupUnits()\n";
  183.  
  184. int
  185. init_unitbox(tool)
  186.     TOOL        tool;
  187. {
  188.     FirstArg(XtNwidth, SIDERULER_WD);
  189.     NextArg(XtNheight, RULER_WD);
  190.     NextArg(XtNlabel, appres.INCHES ? "in" : "cm");
  191.     NextArg(XtNfont, button_font);
  192.     NextArg(XtNfromHoriz, canvas_sw);
  193.     NextArg(XtNhorizDistance, -INTERNAL_BW);
  194.     NextArg(XtNfromVert, msg_form);
  195.     NextArg(XtNvertDistance, -INTERNAL_BW);
  196.     NextArg(XtNresizable, False);
  197.     NextArg(XtNtop, XtChainTop);
  198.     NextArg(XtNbottom, XtChainTop);
  199.     NextArg(XtNleft, XtChainLeft);
  200.     NextArg(XtNright, XtChainLeft);
  201.     NextArg(XtNborderWidth, INTERNAL_BW);
  202.  
  203.     if (strlen(cur_fig_units))
  204.     fig_unit_setting = 1;
  205.     else {
  206.     strcpy(cur_fig_units, appres.INCHES ? "in" : "cm");
  207.     }
  208.  
  209.     if (appres.user_scale != 1.0)
  210.     fig_scale_setting = 1;
  211.  
  212.     unitbox_sw = XtCreateWidget("unitbox", labelWidgetClass, tool,
  213.                 Args, ArgCount);
  214.     XtAppAddActions(tool_app, unitbox_actions, XtNumber(unitbox_actions));
  215.     XtOverrideTranslations(unitbox_sw,
  216.                XtParseTranslationTable(unitbox_translations));
  217.     return (1);
  218. }
  219.  
  220. static String   unit_translations =
  221.         "<Message>WM_PROTOCOLS: QuitUnits()\n";
  222. static void     unit_panel_cancel(), unit_panel_set();
  223. static XtActionsRec     unit_actions[] =
  224. {
  225.     {"QuitUnits", (XtActionProc) unit_panel_cancel},
  226.     {"SetUnit", (XtActionProc) unit_panel_set},
  227. };
  228.  
  229. static Widget    unit_popup, form, cancel, set, beside, below, newvalue,
  230.         label;
  231.  
  232. /* handle unit/scale settings */
  233.  
  234. static void
  235. unit_panel_dismiss()
  236. {
  237.     XtDestroyWidget(unit_popup);
  238.     XtSetSensitive(unitbox_sw, True);
  239. }
  240.  
  241. static void
  242. unit_panel_cancel(w, ev)
  243.     Widget        w;
  244.     XButtonEvent   *ev;
  245. {
  246.     unit_panel_dismiss();
  247. }
  248.  
  249. static void
  250. unit_panel_set(w, ev)
  251.     Widget        w;
  252.     XButtonEvent   *ev;
  253. {
  254.     int old_rul_unit;
  255.     char        buf[32];
  256.  
  257.     old_rul_unit = appres.INCHES;
  258.     appres.INCHES = rul_unit_setting ? 1 : 0;
  259.     init_grid();    /* change point positioning messages if necessary */
  260.     if (fig_scale_setting)
  261.     appres.user_scale = (float) atof(panel_get_value(scale_factor_panel));
  262.     else
  263.     appres.user_scale = 1.0;
  264.  
  265.     if (fig_unit_setting) {
  266.         strncpy(cur_fig_units,
  267.         panel_get_value(user_unit_panel),
  268.         sizeof(cur_fig_units));
  269.     put_msg("Ruler scale: %s,  Figure scale: 1 %s = %.2f %s",
  270.         appres.INCHES ? "in" : "cm",
  271.         appres.INCHES ? "in" : "cm",
  272.         appres.user_scale, cur_fig_units);
  273.     } else {
  274.     strcpy(cur_fig_units, appres.INCHES ? "in" : "cm");
  275.     put_msg("Ruler scale: %s,  Figure scale = 1:%.2f",
  276.         appres.INCHES ? "in" : "cm", appres.user_scale);
  277.     }
  278.  
  279.     if (old_rul_unit != appres.INCHES)
  280.     reset_rulers();
  281.     unit_panel_dismiss();
  282. }
  283.  
  284. static void
  285. fig_unit_select(w, new_unit, garbage)
  286.     Widget          w;
  287.     XtPointer       new_unit, garbage;
  288. {
  289.     FirstArg(XtNlabel, XtName(w));
  290.     SetValues(fig_unit_panel);
  291.     fig_unit_setting = (int) new_unit;
  292.     XtSetSensitive(user_unit_lab, fig_unit_setting ? True : False);
  293.     XtSetSensitive(user_unit_panel, fig_unit_setting ? True : False);
  294.     put_msg(fig_unit_setting ? "user defined figure units"
  295.                  : "figure units = ruler units");
  296. }
  297.  
  298. static void
  299. fig_scale_select(w, new_scale, garbage)
  300.     Widget          w;
  301.     XtPointer       new_scale, garbage;
  302. {
  303.     FirstArg(XtNlabel, XtName(w));
  304.     SetValues(fig_scale_panel);
  305.     fig_scale_setting = (int) new_scale;
  306.     XtSetSensitive(scale_factor_lab, fig_scale_setting ? True : False);
  307.     XtSetSensitive(scale_factor_panel, fig_scale_setting ? True : False);
  308.     put_msg(fig_scale_setting ? "user defined scale factor"
  309.                  : "figure scale = 1:1");
  310. }
  311.  
  312. static void
  313. rul_unit_select(w, new_unit, garbage)
  314.     Widget          w;
  315.     XtPointer       new_unit, garbage;
  316. {
  317.     FirstArg(XtNlabel, XtName(w));
  318.     SetValues(rul_unit_panel);
  319.     rul_unit_setting = (int) new_unit;
  320.     if (rul_unit_setting)
  321.     put_msg("ruler scale : centimetres");
  322.     else
  323.     put_msg("ruler scale : inches");
  324. }
  325.  
  326. void
  327. popup_unit_panel()
  328. {
  329.     Position        x_val, y_val;
  330.     Dimension        width, height;
  331.     char        buf[32];
  332.     static int      actions_added=0;
  333.     static char    *rul_unit_items[] = {
  334.     "Metric (cm)  ", "Imperial (in)"};
  335.     static char    *fig_unit_items[] = {
  336.     "Ruler units ", "User defined"};
  337.     static char    *fig_scale_items[] = {
  338.     "Unity       ", "User defined"};
  339.  
  340.     FirstArg(XtNwidth, &width);
  341.     NextArg(XtNheight, &height);
  342.     GetValues(tool);
  343.     /* position the popup 2/3 in from left and 1/3 down from top */
  344.     XtTranslateCoords(tool, (Position) (2 * width / 3), (Position) (height / 3),
  345.               &x_val, &y_val);
  346.  
  347.     FirstArg(XtNx, x_val);
  348.     NextArg(XtNy, y_val);
  349.     NextArg(XtNwidth, 240);
  350.  
  351.     unit_popup = XtCreatePopupShell("xfig_set_unit_panel",
  352.                     transientShellWidgetClass, tool,
  353.                     Args, ArgCount);
  354.     XtOverrideTranslations(unit_popup,
  355.                        XtParseTranslationTable(unit_translations));
  356.     if (!actions_added) {
  357.         XtAppAddActions(tool_app, unit_actions, XtNumber(unit_actions));
  358.     actions_added = 1;
  359.     }
  360.  
  361.     form = XtCreateManagedWidget("form", formWidgetClass, unit_popup, NULL, 0);
  362.  
  363.     FirstArg(XtNborderWidth, 0);
  364.     sprintf(buf, "      Unit/Scale settings");
  365.     label = XtCreateManagedWidget(buf, labelWidgetClass, form, Args, ArgCount);
  366.  
  367.     /* make ruler units menu */
  368.  
  369.     rul_unit_setting = appres.INCHES ? 1 : 0;
  370.     FirstArg(XtNfromVert, label);
  371.     NextArg(XtNborderWidth, 0);
  372.     beside = XtCreateManagedWidget("Ruler Units  =", labelWidgetClass,
  373.                                    form, Args, ArgCount);
  374.  
  375.     FirstArg(XtNfromVert, label);
  376.     NextArg(XtNfromHoriz, beside);
  377.     rul_unit_panel = XtCreateManagedWidget(rul_unit_items[rul_unit_setting],
  378.                 menuButtonWidgetClass, form, Args, ArgCount);
  379.     below = rul_unit_panel;
  380.     rul_unit_menu = make_popup_menu(rul_unit_items, XtNumber(rul_unit_items),
  381.                                      rul_unit_panel, rul_unit_select);
  382.  
  383.     /* make figure units menu */
  384.  
  385.     FirstArg(XtNfromVert, below);
  386.     NextArg(XtNborderWidth, 0);
  387.     beside = XtCreateManagedWidget("Figure units =", labelWidgetClass,
  388.                                    form, Args, ArgCount);
  389.  
  390.     FirstArg(XtNfromVert, below);
  391.     NextArg(XtNfromHoriz, beside);
  392.     fig_unit_panel = XtCreateManagedWidget(fig_unit_items[fig_unit_setting],
  393.                 menuButtonWidgetClass, form, Args, ArgCount);
  394.     below = fig_unit_panel;
  395.     fig_unit_menu = make_popup_menu(fig_unit_items, XtNumber(fig_unit_items),
  396.                                      fig_unit_panel, fig_unit_select);
  397.  
  398.     /* user defined units */
  399.  
  400.     FirstArg(XtNfromVert, below);
  401.     NextArg(XtNborderWidth, 0);
  402.     NextArg(XtNlabel, "Unit Name =");
  403.     user_unit_lab = XtCreateManagedWidget("user_units",
  404.                                 labelWidgetClass, form, Args, ArgCount);
  405.  
  406.     FirstArg(XtNfromVert, below);
  407.     NextArg(XtNborderWidth, INTERNAL_BW);
  408.     NextArg(XtNfromHoriz, label);
  409.     NextArg(XtNstring, cur_fig_units);
  410.     NextArg(XtNinsertPosition, strlen(buf));
  411.     NextArg(XtNeditType, "append");
  412.     NextArg(XtNwidth, 40);
  413.     user_unit_panel = XtCreateManagedWidget(buf, asciiTextWidgetClass,
  414.                                     form, Args, ArgCount);
  415.     below = user_unit_panel;
  416.  
  417.     /* make figure scale menu */
  418.  
  419.     FirstArg(XtNfromVert, below);
  420.     NextArg(XtNborderWidth, 0);
  421.     beside = XtCreateManagedWidget("Figure scale =", labelWidgetClass,
  422.                                    form, Args, ArgCount);
  423.  
  424.     FirstArg(XtNfromVert, below);
  425.     NextArg(XtNfromHoriz, beside);
  426.     fig_scale_panel = XtCreateManagedWidget(fig_scale_items[fig_scale_setting],
  427.                 menuButtonWidgetClass, form, Args, ArgCount);
  428.     below = fig_scale_panel;
  429.     fig_scale_menu = make_popup_menu(fig_scale_items, XtNumber(fig_scale_items),
  430.                                      fig_scale_panel, fig_scale_select);
  431.  
  432.     /* scale factor widget */
  433.  
  434.     FirstArg(XtNfromVert, below);
  435.     NextArg(XtNborderWidth, 0);
  436.     NextArg(XtNlabel, "Scale factor =");
  437.     scale_factor_lab = XtCreateManagedWidget("scale_factor",
  438.                                 labelWidgetClass, form, Args, ArgCount);
  439.  
  440.     sprintf(buf, "%1.2f", appres.user_scale);
  441.     FirstArg(XtNfromVert, below);
  442.     NextArg(XtNborderWidth, INTERNAL_BW);
  443.     NextArg(XtNfromHoriz, label);
  444.     NextArg(XtNstring, buf);
  445.     NextArg(XtNinsertPosition, strlen(buf));
  446.     NextArg(XtNeditType, "append");
  447.     NextArg(XtNwidth, 40);
  448.     scale_factor_panel = XtCreateManagedWidget(buf, asciiTextWidgetClass,
  449.                                         form, Args, ArgCount);
  450.     below = scale_factor_panel;
  451.  
  452.     /* standard cancel/set buttons */
  453.  
  454.     FirstArg(XtNlabel, "cancel");
  455.     NextArg(XtNfromVert, below);
  456.     NextArg(XtNborderWidth, INTERNAL_BW);
  457.     cancel = XtCreateManagedWidget("cancel", commandWidgetClass,
  458.                    form, Args, ArgCount);
  459.     XtAddEventHandler(cancel, ButtonReleaseMask, (Boolean) 0,
  460.               (XtEventHandler)unit_panel_cancel, (XtPointer) NULL);
  461.  
  462.     FirstArg(XtNlabel, "set");
  463.     NextArg(XtNfromVert, below);
  464.     NextArg(XtNfromHoriz, cancel);
  465.     NextArg(XtNborderWidth, INTERNAL_BW);
  466.     set = XtCreateManagedWidget("set", commandWidgetClass,
  467.                 form, Args, ArgCount);
  468.     XtAddEventHandler(set, ButtonReleaseMask, (Boolean) 0,
  469.               (XtEventHandler)unit_panel_set, (XtPointer) NULL);
  470.  
  471.     XtPopup(unit_popup, XtGrabExclusive);
  472.  
  473.     XtSetSensitive(user_unit_lab, fig_unit_setting ? True : False);
  474.     XtSetSensitive(user_unit_panel, fig_unit_setting ? True : False);
  475.     XtSetSensitive(scale_factor_lab, fig_scale_setting ? True : False);
  476.     XtSetSensitive(scale_factor_panel, fig_scale_setting ? True : False);
  477.  
  478.     (void) XSetWMProtocols(XtDisplay(unit_popup), XtWindow(unit_popup),
  479.                            &wm_delete_window, 1);
  480. }
  481. /************************* TOPRULER ************************/
  482.  
  483. XtActionsRec    topruler_actions[] =
  484. {
  485.     {"EventTopRuler", (XtActionProc) topruler_selected},
  486.     {"ExposeTopRuler", (XtActionProc) topruler_exposed},
  487.     {"EnterTopRuler", (XtActionProc) draw_mousefun_topruler},
  488.     {"LeaveTopRuler", (XtActionProc) clear_mousefun},
  489. };
  490.  
  491. static String    topruler_translations =
  492. "Any<BtnDown>:EventTopRuler()\n\
  493.     Any<BtnUp>:EventTopRuler()\n\
  494.     <Btn2Motion>:EventTopRuler()\n\
  495.     Meta <Btn3Motion>:EventTopRuler()\n\
  496.     <EnterWindow>:EnterTopRuler()\n\
  497.     <LeaveWindow>:LeaveTopRuler()\n\
  498.     <Expose>:ExposeTopRuler()\n";
  499.  
  500. static
  501. topruler_selected(tool, event, params, nparams)
  502.     TOOL        tool;
  503.     XButtonEvent   *event;
  504.     String       *params;
  505.     Cardinal       *nparams;
  506. {
  507.     XButtonEvent   *be = (XButtonEvent *) event;
  508.  
  509.     switch (event->type) {
  510.     case ButtonPress:
  511.     if (be->button == Button3 && be->state & Mod1Mask) {
  512.         be->button = Button2;
  513.     }
  514.     switch (be->button) {
  515.     case Button1:
  516.         XDefineCursor(tool_d, topruler_win, l_arrow_cursor);
  517.         break;
  518.     case Button2:
  519.         XDefineCursor(tool_d, topruler_win, bull_cursor);
  520.         orig_zoomoff = zoomxoff;
  521.         last_drag_x = event->x;
  522.         break;
  523.     case Button3:
  524.         XDefineCursor(tool_d, topruler_win, r_arrow_cursor);
  525.         break;
  526.     }
  527.     break;
  528.     case ButtonRelease:
  529.     if (be->button == Button3 && be->state & Mod1Mask) {
  530.         be->button = Button2;
  531.     }
  532.     switch (be->button) {
  533.     case Button1:
  534.         pan_left();
  535.         break;
  536.     case Button2:
  537.         if (orig_zoomoff != zoomxoff)
  538.         setup_grid(cur_gridmode);
  539.         break;
  540.     case Button3:
  541.         pan_right();
  542.         break;
  543.     }
  544.     XDefineCursor(tool_d, topruler_win, lr_arrow_cursor);
  545.     break;
  546.     case MotionNotify:
  547.     if (event->x != last_drag_x)
  548.         if ((zoomxoff != 0) || (event->x < last_drag_x)) {
  549.         zoomxoff -= (event->x - last_drag_x);
  550.         if (zoomxoff < 0)
  551.             zoomxoff = 0;
  552.         reset_topruler();
  553.         redisplay_topruler();
  554.         }
  555.     last_drag_x = event->x;
  556.     break;
  557.     }
  558. }
  559.  
  560. erase_toprulermark()
  561. {
  562.     XClearArea(tool_d, topruler_win, ZOOMX(lastx) + troffx,
  563.            TOPRULER_HT + troffy, trm_pr.width,
  564.            trm_pr.height, False);
  565. }
  566.  
  567. set_toprulermark(x)
  568.     int            x;
  569. {
  570.     XClearArea(tool_d, topruler_win, ZOOMX(lastx) + troffx,
  571.            TOPRULER_HT + troffy, trm_pr.width,
  572.            trm_pr.height, False);
  573.     XCopyArea(tool_d, toparrow_pm, topruler_win, tr_xor_gc,
  574.           0, 0, trm_pr.width, trm_pr.height,
  575.           ZOOMX(x) + troffx, TOPRULER_HT + troffy);
  576.     lastx = x;
  577. }
  578.  
  579. static
  580. topruler_exposed(tool, event, params, nparams)
  581.     TOOL        tool;
  582.     XButtonEvent   *event;
  583.     String       *params;
  584.     Cardinal       *nparams;
  585. {
  586.     if (((XExposeEvent *) event)->count > 0)
  587.     return;
  588.     redisplay_topruler();
  589. }
  590.  
  591. redisplay_topruler()
  592. {
  593.     XClearWindow(tool_d, topruler_win);
  594. }
  595.  
  596. int
  597. init_topruler(tool)
  598.     TOOL        tool;
  599. {
  600.     FirstArg(XtNwidth, TOPRULER_WD);
  601.     NextArg(XtNheight, TOPRULER_HT);
  602.     NextArg(XtNlabel, "");
  603.     NextArg(XtNfromHoriz, mode_panel);
  604.     NextArg(XtNhorizDistance, -INTERNAL_BW);
  605.     NextArg(XtNfromVert, msg_form);
  606.     NextArg(XtNvertDistance, -INTERNAL_BW);
  607.     NextArg(XtNresizable, False);
  608.     NextArg(XtNtop, XtChainTop);
  609.     NextArg(XtNbottom, XtChainTop);
  610.     NextArg(XtNleft, XtChainLeft);
  611.     NextArg(XtNright, XtChainLeft);
  612.     NextArg(XtNborderWidth, INTERNAL_BW);
  613.  
  614.     topruler_sw = XtCreateWidget("topruler", labelWidgetClass, tool,
  615.                  Args, ArgCount);
  616.  
  617.     XtAppAddActions(tool_app, topruler_actions, XtNumber(topruler_actions));
  618.     XtOverrideTranslations(topruler_sw,
  619.                XtParseTranslationTable(topruler_translations));
  620.     return (1);
  621. }
  622.  
  623. setup_topruler()
  624. {
  625.     unsigned long   bg, fg;
  626.     XGCValues        gcv;
  627.     unsigned long   gcmask;
  628.  
  629.     topruler_win = XtWindow(topruler_sw);
  630.     gcv.font = roman_font->fid;
  631.     gcmask = GCFunction | GCForeground | GCBackground | GCFont;
  632.  
  633.     /* set up the GCs */
  634.     FirstArg(XtNbackground, &bg);
  635.     NextArg(XtNforeground, &fg);
  636.     GetValues(topruler_sw);
  637.  
  638.     gcv.foreground = bg;
  639.     gcv.background = bg;
  640.     gcv.function = GXcopy;
  641.     tr_erase_gc = XCreateGC(tool_d, topruler_win, gcmask, &gcv);
  642.  
  643.     gcv.foreground = fg;
  644.     tr_gc = XCreateGC(tool_d, topruler_win, gcmask, &gcv);
  645.     /*
  646.      * The arrows will be XORed into the rulers. We want the foreground color
  647.      * in the arrow to result in the foreground or background color in the
  648.      * display. so if the source pixel is fg^bg, it produces fg when XOR'ed
  649.      * with bg, and bg when XOR'ed with bg. If the source pixel is zero, it
  650.      * produces fg when XOR'ed with fg, and bg when XOR'ed with bg.
  651.      */
  652.     /* first make a temporary xor gc */
  653.     gcv.foreground = fg ^ bg;
  654.     gcv.background = (unsigned long) 0;
  655.     gcv.function = GXcopy;
  656.     tr_xor_gc = XCreateGC(tool_d, topruler_win, gcmask, &gcv);
  657.  
  658.     /* make pixmaps for top ruler arrow */
  659.     toparrow_pm = XCreatePixmap(tool_d, topruler_win, trm_pr.width,
  660.                 trm_pr.height, DefaultDepthOfScreen(tool_s));
  661.     XPutImage(tool_d, toparrow_pm, tr_xor_gc, &trm_pr, 0, 0, 0, 0,
  662.           trm_pr.width, trm_pr.height);
  663.     XFreeGC(tool_d, tr_xor_gc);
  664.  
  665.     /* now make the real xor gc */
  666.     gcv.background = bg;
  667.     gcv.function = GXxor;
  668.     tr_xor_gc = XCreateGC(tool_d, topruler_win, gcmask, &gcv);
  669.  
  670.     XDefineCursor(tool_d, topruler_win, lr_arrow_cursor);
  671.  
  672.     topruler_pm = XCreatePixmap(tool_d, topruler_win,
  673.                 TOPRULER_WD, TOPRULER_HT,
  674.                 DefaultDepthOfScreen(tool_s));
  675.  
  676.     reset_topruler();
  677. }
  678.  
  679. resize_topruler()
  680. {
  681.     XFreePixmap(tool_d, topruler_pm);
  682.     topruler_pm = XCreatePixmap(tool_d, topruler_win,
  683.                 TOPRULER_WD, TOPRULER_HT,
  684.                 DefaultDepthOfScreen(tool_s));
  685.  
  686.     reset_topruler();
  687. }
  688.  
  689. reset_topruler()
  690. {
  691.     register int    i, j;
  692.     register Pixmap p = topruler_pm;
  693.     char        number[4];
  694.     int            X0;
  695.  
  696.     /* top ruler, adjustments for digits are kludges based on 6x13 char */
  697.     XFillRectangle(tool_d, p, tr_erase_gc, 0, 0, TOPRULER_WD, TOPRULER_HT);
  698.  
  699.     X0 = BACKX(0);
  700.     if (appres.INCHES) {
  701.     X0 -= (X0 % SINCH);
  702.     for (i = X0+SINCH-1; i <= X0+round(TOPRULER_WD/zoomscale); i += SINCH) {
  703.         j = i + 1;
  704.         if (j % PIX_PER_INCH == 0) {
  705.         XDrawLine(tool_d, p, tr_gc, ZOOMX(i), TOPRULER_HT - 1, ZOOMX(i),
  706.               TOPRULER_HT - INCH_MARK - 1);
  707.         sprintf(number, "%d", j / PIX_PER_INCH);
  708.         XDrawString(tool_d, p, tr_gc, ZOOMX(i) - 3,
  709.                 TOPRULER_HT - INCH_MARK - 5, number,
  710.                 (j < PIX_PER_INCH*10)? 1 : (j<PIX_PER_INCH*100? 2:3));
  711.         } else if (j % HINCH == 0)
  712.         XDrawLine(tool_d, p, tr_gc, ZOOMX(i), TOPRULER_HT - 1, ZOOMX(i),
  713.               TOPRULER_HT - HALF_MARK - 1);
  714.         else if (j % QINCH == 0)
  715.         XDrawLine(tool_d, p, tr_gc, ZOOMX(i), TOPRULER_HT - 1, ZOOMX(i),
  716.               TOPRULER_HT - QUARTER_MARK - 1);
  717.         else if (j % SINCH == 0)
  718.         XDrawLine(tool_d, p, tr_gc, ZOOMX(i), TOPRULER_HT - 1, ZOOMX(i),
  719.               TOPRULER_HT - SIXTEENTH_MARK - 1);
  720.     }
  721.     } else {
  722.     X0 -= (X0 % TWOMM);
  723.     for (i = X0+TWOMM-1; i <= X0+round(TOPRULER_WD/zoomscale); i++) {
  724.         j = i + 1;
  725.         if (j % PIX_PER_CM == 0) {
  726.         XDrawLine(tool_d, p, tr_gc, ZOOMX(i), TOPRULER_HT - 1, ZOOMX(i),
  727.               TOPRULER_HT - INCH_MARK - 1);
  728.         sprintf(number, "%d", j / PIX_PER_CM);
  729.         XDrawString(tool_d, p, tr_gc, ZOOMX(i) - 3,
  730.                 TOPRULER_HT - INCH_MARK - 5, number,
  731.                 (j < PIX_PER_CM*10)? 1 : (j<PIX_PER_CM*100? 2:3));
  732.         } else if (j % TWOMM == 0)
  733.         XDrawLine(tool_d, p, tr_gc, ZOOMX(i), TOPRULER_HT - 1, ZOOMX(i),
  734.               TOPRULER_HT - QUARTER_MARK - 1);
  735.     }
  736.     }
  737.     /* change the pixmap ID to fool the intrinsics to actually set the pixmap */
  738.     FirstArg(XtNbackgroundPixmap, 0);
  739.     SetValues(topruler_sw);
  740.     FirstArg(XtNbackgroundPixmap, p);
  741.     SetValues(topruler_sw);
  742. }
  743.  
  744. /************************* SIDERULER ************************/
  745.  
  746. XtActionsRec    sideruler_actions[] =
  747. {
  748.     {"EventSideRuler", (XtActionProc) sideruler_selected},
  749.     {"ExposeSideRuler", (XtActionProc) sideruler_exposed},
  750.     {"EnterSideRuler", (XtActionProc) draw_mousefun_sideruler},
  751.     {"LeaveSideRuler", (XtActionProc) clear_mousefun},
  752. };
  753.  
  754. static String    sideruler_translations =
  755. "Any<BtnDown>:EventSideRuler()\n\
  756.     Any<BtnUp>:EventSideRuler()\n\
  757.     <Btn2Motion>:EventSideRuler()\n\
  758.     Meta <Btn3Motion>:EventSideRuler()\n\
  759.     <EnterWindow>:EnterSideRuler()\n\
  760.     <LeaveWindow>:LeaveSideRuler()\n\
  761.     <Expose>:ExposeSideRuler()\n";
  762.  
  763. static
  764. sideruler_selected(tool, event, params, nparams)
  765.     TOOL        tool;
  766.     XButtonEvent   *event;
  767.     String       *params;
  768.     Cardinal       *nparams;
  769. {
  770.     XButtonEvent   *be = (XButtonEvent *) event;
  771.  
  772.     switch (event->type) {
  773.     case ButtonPress:
  774.     if (be->button == Button3 && be->state & Mod1Mask) {
  775.         be->button = Button2;
  776.     }
  777.     switch (be->button) {
  778.     case Button1:
  779.         XDefineCursor(tool_d, sideruler_win, u_arrow_cursor);
  780.         break;
  781.     case Button2:
  782.         XDefineCursor(tool_d, sideruler_win, bull_cursor);
  783.         orig_zoomoff = zoomyoff;
  784.         last_drag_y = event->y;
  785.         break;
  786.     case Button3:
  787.         XDefineCursor(tool_d, sideruler_win, d_arrow_cursor);
  788.         break;
  789.     }
  790.     break;
  791.     case ButtonRelease:
  792.     if (be->button == Button3 && be->state & Mod1Mask) {
  793.         be->button = Button2;
  794.     }
  795.     switch (be->button) {
  796.     case Button1:
  797.         pan_up();
  798.         break;
  799.     case Button2:
  800.         if (orig_zoomoff != zoomyoff)
  801.         setup_grid(cur_gridmode);
  802.         break;
  803.     case Button3:
  804.         pan_down();
  805.         break;
  806.     }
  807.     XDefineCursor(tool_d, sideruler_win, ud_arrow_cursor);
  808.     break;
  809.     case MotionNotify:
  810.     if (event->y != last_drag_y)
  811.         if ((zoomyoff != 0) || (event->y < last_drag_y)) {
  812.         zoomyoff -= (event->y - last_drag_y);
  813.         if (zoomyoff < 0)
  814.             zoomyoff = 0;
  815.         reset_sideruler();
  816.         redisplay_sideruler();
  817.         }
  818.     last_drag_y = event->y;
  819.     break;
  820.     }
  821. }
  822.  
  823. static
  824. sideruler_exposed(tool, event, params, nparams)
  825.     TOOL        tool;
  826.     XButtonEvent   *event;
  827.     String       *params;
  828.     Cardinal       *nparams;
  829. {
  830.     if (((XExposeEvent *) event)->count > 0)
  831.     return;
  832.     redisplay_sideruler();
  833. }
  834.  
  835. int
  836. init_sideruler(tool)
  837.     TOOL        tool;
  838. {
  839.     FirstArg(XtNwidth, SIDERULER_WD);
  840.     NextArg(XtNheight, SIDERULER_HT);
  841.     NextArg(XtNlabel, "");
  842.     NextArg(XtNfromHoriz, canvas_sw);
  843.     NextArg(XtNhorizDistance, -INTERNAL_BW);
  844.     NextArg(XtNfromVert, topruler_sw);
  845.     NextArg(XtNvertDistance, -INTERNAL_BW);
  846.     NextArg(XtNresizable, False);
  847.     NextArg(XtNtop, XtChainTop);
  848.     NextArg(XtNbottom, XtChainTop);
  849.     NextArg(XtNleft, XtChainLeft);
  850.     NextArg(XtNright, XtChainLeft);
  851.     NextArg(XtNborderWidth, INTERNAL_BW);
  852.  
  853.     sideruler_sw = XtCreateWidget("sideruler", labelWidgetClass, tool,
  854.                   Args, ArgCount);
  855.  
  856.     XtAppAddActions(tool_app, sideruler_actions, XtNumber(sideruler_actions));
  857.     XtOverrideTranslations(sideruler_sw,
  858.                XtParseTranslationTable(sideruler_translations));
  859.     return (1);
  860. }
  861.  
  862. redisplay_sideruler()
  863. {
  864.     XClearWindow(tool_d, sideruler_win);
  865. }
  866.  
  867. setup_sideruler()
  868. {
  869.     unsigned long   bg, fg;
  870.     XGCValues        gcv;
  871.     unsigned long   gcmask;
  872.  
  873.     sideruler_win = XtWindow(sideruler_sw);
  874.     gcv.font = roman_font->fid;
  875.     gcmask = GCFunction | GCForeground | GCBackground | GCFont;
  876.  
  877.     /* set up the GCs */
  878.     FirstArg(XtNbackground, &bg);
  879.     NextArg(XtNforeground, &fg);
  880.     GetValues(sideruler_sw);
  881.  
  882.     gcv.foreground = bg;
  883.     gcv.background = bg;
  884.     gcv.function = GXcopy;
  885.     sr_erase_gc = XCreateGC(tool_d, sideruler_win, gcmask, &gcv);
  886.  
  887.     gcv.foreground = fg;
  888.     sr_gc = XCreateGC(tool_d, sideruler_win, gcmask, &gcv);
  889.     /*
  890.      * The arrows will be XORed into the rulers. We want the foreground color
  891.      * in the arrow to result in the foreground or background color in the
  892.      * display. so if the source pixel is fg^bg, it produces fg when XOR'ed
  893.      * with bg, and bg when XOR'ed with bg. If the source pixel is zero, it
  894.      * produces fg when XOR'ed with fg, and bg when XOR'ed with bg.
  895.      */
  896.     /* first make a temporary xor gc */
  897.     gcv.foreground = fg ^ bg;
  898.     gcv.background = (unsigned long) 0;
  899.     gcv.function = GXcopy;
  900.     sr_xor_gc = XCreateGC(tool_d, sideruler_win, gcmask, &gcv);
  901.  
  902.     /* make pixmaps for side ruler arrow */
  903.     if (appres.RHS_PANEL) {
  904.     sidearrow_pm = XCreatePixmap(tool_d, sideruler_win,
  905.                      srlm_pr.width, srlm_pr.height,
  906.                      DefaultDepthOfScreen(tool_s));
  907.     XPutImage(tool_d, sidearrow_pm, sr_xor_gc, &srlm_pr, 0, 0, 0, 0,
  908.           srlm_pr.width, srlm_pr.height);
  909.     } else {
  910.     sidearrow_pm = XCreatePixmap(tool_d, sideruler_win,
  911.                      srrm_pr.width, srrm_pr.height,
  912.                      DefaultDepthOfScreen(tool_s));
  913.     XPutImage(tool_d, sidearrow_pm, sr_xor_gc, &srrm_pr, 0, 0, 0, 0,
  914.           srrm_pr.width, srrm_pr.height);
  915.     }
  916.     XFreeGC(tool_d, sr_xor_gc);
  917.  
  918.     /* now make the real xor gc */
  919.     gcv.background = bg;
  920.     gcv.function = GXxor;
  921.     sr_xor_gc = XCreateGC(tool_d, sideruler_win, gcmask, &gcv);
  922.  
  923.     XDefineCursor(tool_d, sideruler_win, ud_arrow_cursor);
  924.  
  925.     sideruler_pm = XCreatePixmap(tool_d, sideruler_win,
  926.                  SIDERULER_WD, SIDERULER_HT,
  927.                  DefaultDepthOfScreen(tool_s));
  928.  
  929.     reset_sideruler();
  930. }
  931.  
  932. resize_sideruler()
  933. {
  934.     XFreePixmap(tool_d, sideruler_pm);
  935.     sideruler_pm = XCreatePixmap(tool_d, sideruler_win,
  936.                  SIDERULER_WD, SIDERULER_HT,
  937.                  DefaultDepthOfScreen(tool_s));
  938.     reset_sideruler();
  939. }
  940.  
  941. reset_sideruler()
  942. {
  943.     register int    i, j;
  944.     register Pixmap p = sideruler_pm;
  945.     char        number[4];
  946.     int            Y0;
  947.  
  948.     /* side ruler, adjustments for digits are kludges based on 6x13 char */
  949.     XFillRectangle(tool_d, p, sr_erase_gc, 0, 0, SIDERULER_WD,
  950.            (int) (SIDERULER_HT));
  951.  
  952.     Y0 = BACKY(0);
  953.     if (appres.INCHES) {
  954.     Y0 -= (Y0 % SINCH);
  955.     if (appres.RHS_PANEL) {
  956.         for (i = Y0+SINCH-1; i <= Y0+round(SIDERULER_HT/zoomscale); i += SINCH) {
  957.         j = i + 1;
  958.         if (j % PIX_PER_INCH == 0) {
  959.             XDrawLine(tool_d, p, sr_gc, SIDERULER_WD - INCH_MARK,
  960.                   ZOOMY(i), SIDERULER_WD, ZOOMY(i));
  961.             sprintf(number, "%3d", j / PIX_PER_INCH);
  962.             XDrawString(tool_d, p, sr_gc,
  963.                 SIDERULER_WD - INCH_MARK - 22, ZOOMY(i) + 3,
  964.                 number, 3);
  965.         } else if (j % HINCH == 0)
  966.             XDrawLine(tool_d, p, sr_gc,
  967.                   SIDERULER_WD - HALF_MARK, ZOOMY(i),
  968.                   SIDERULER_WD, ZOOMY(i));
  969.         else if (j % QINCH == 0)
  970.             XDrawLine(tool_d, p, sr_gc,
  971.                   SIDERULER_WD - QUARTER_MARK, ZOOMY(i),
  972.                   SIDERULER_WD, ZOOMY(i));
  973.         else if (j % SINCH == 0)
  974.             XDrawLine(tool_d, p, sr_gc,
  975.                   SIDERULER_WD - SIXTEENTH_MARK, ZOOMY(i),
  976.                   SIDERULER_WD, ZOOMY(i));
  977.         }
  978.     } else {
  979.         for (i = Y0+SINCH-1; i <= Y0+round(SIDERULER_HT/zoomscale); i += SINCH) {
  980.         j = i + 1;
  981.         if (j % PIX_PER_INCH == 0) {
  982.             XDrawLine(tool_d, p, sr_gc, 0, ZOOMY(i),
  983.                   INCH_MARK - 1, ZOOMY(i));
  984.             sprintf(number, "%3d", j / PIX_PER_INCH);
  985.             XDrawString(tool_d, p, sr_gc, INCH_MARK + 3,
  986.                 ZOOMY(i) + 3, number, 3);
  987.         } else if (j % HINCH == 0)
  988.             XDrawLine(tool_d, p, sr_gc, 0, ZOOMY(i),
  989.                   HALF_MARK - 1, ZOOMY(i));
  990.         else if (j % QINCH == 0)
  991.             XDrawLine(tool_d, p, sr_gc, 0, ZOOMY(i),
  992.                   QUARTER_MARK - 1, ZOOMY(i));
  993.         else if (j % SINCH == 0)
  994.             XDrawLine(tool_d, p, sr_gc, 0, ZOOMY(i),
  995.                   SIXTEENTH_MARK - 1, ZOOMY(i));
  996.         }
  997.     }
  998.     } else {
  999.     Y0 -= (Y0 % TWOMM);
  1000.     if (appres.RHS_PANEL) {
  1001.         for (i = Y0+TWOMM-1; i <= Y0+round(SIDERULER_HT/zoomscale); i++) {
  1002.         j = i + 1;
  1003.         if (j % PIX_PER_CM == 0) {
  1004.             XDrawLine(tool_d, p, sr_gc, SIDERULER_WD - INCH_MARK,
  1005.                   ZOOMY(i), SIDERULER_WD, ZOOMY(i));
  1006.             sprintf(number, "%3d", j / PIX_PER_CM);
  1007.             XDrawString(tool_d, p, sr_gc,
  1008.                 SIDERULER_WD - INCH_MARK - 14, ZOOMY(i) + 3,
  1009.                 number, 3);
  1010.         } else if (j % TWOMM == 0)
  1011.             XDrawLine(tool_d, p, sr_gc,
  1012.                   SIDERULER_WD - QUARTER_MARK, ZOOMY(i),
  1013.                   SIDERULER_WD, ZOOMY(i));
  1014.         }
  1015.     } else {
  1016.         for (i = Y0+TWOMM-1; i <= Y0+round(SIDERULER_HT/zoomscale); i++) {
  1017.         j = i + 1;
  1018.         if (j % PIX_PER_CM == 0) {
  1019.             XDrawLine(tool_d, p, sr_gc, 0, ZOOMY(i),
  1020.                   INCH_MARK - 1, ZOOMY(i));
  1021.             sprintf(number, "%3d", j / PIX_PER_CM);
  1022.             XDrawString(tool_d, p, sr_gc, INCH_MARK + 3,
  1023.                 ZOOMY(i) + 3, number, 3);
  1024.         } else if (j % TWOMM == 0)
  1025.             XDrawLine(tool_d, p, sr_gc, 0, ZOOMY(i),
  1026.                   QUARTER_MARK - 1, ZOOMY(i));
  1027.         }
  1028.     }
  1029.     }
  1030.     /* change the pixmap ID to fool the intrinsics to actually set the pixmap */
  1031.     FirstArg(XtNbackgroundPixmap, 0);
  1032.     SetValues(sideruler_sw);
  1033.     FirstArg(XtNbackgroundPixmap, p);
  1034.     SetValues(sideruler_sw);
  1035. }
  1036.  
  1037. erase_siderulermark()
  1038. {
  1039.     if (appres.RHS_PANEL)
  1040.     XClearArea(tool_d, sideruler_win,
  1041.            SIDERULER_WD + srloffx, ZOOMY(lasty) + srloffy,
  1042.            srlm_pr.width, srlm_pr.height, False);
  1043.     else
  1044.     XClearArea(tool_d, sideruler_win,
  1045.            srroffx, ZOOMY(lasty) + srroffy,
  1046.            srlm_pr.width, srlm_pr.height, False);
  1047. }
  1048.  
  1049. set_siderulermark(y)
  1050.     int            y;
  1051. {
  1052.     if (appres.RHS_PANEL) {
  1053.     /*
  1054.      * Because the ruler uses a background pixmap, we can win here by
  1055.      * using XClearArea to erase the old thing.
  1056.      */
  1057.     XClearArea(tool_d, sideruler_win,
  1058.            SIDERULER_WD + srloffx, ZOOMY(lasty) + srloffy,
  1059.            srlm_pr.width, srlm_pr.height, False);
  1060.     XCopyArea(tool_d, sidearrow_pm, sideruler_win,
  1061.           sr_xor_gc, 0, 0, srlm_pr.width,
  1062.           srlm_pr.height, SIDERULER_WD + srloffx, ZOOMY(y) + srloffy);
  1063.     } else {
  1064.     /*
  1065.      * Because the ruler uses a background pixmap, we can win here by
  1066.      * using XClearArea to erase the old thing.
  1067.      */
  1068.     XClearArea(tool_d, sideruler_win,
  1069.            srroffx, ZOOMY(lasty) + srroffy,
  1070.            srlm_pr.width, srlm_pr.height, False);
  1071.     XCopyArea(tool_d, sidearrow_pm, sideruler_win,
  1072.           sr_xor_gc, 0, 0, srrm_pr.width,
  1073.           srrm_pr.height, srroffx, ZOOMY(y) + srroffy);
  1074.     }
  1075.     lasty = y;
  1076. }
  1077.