[comp.windows.news] ruler application

marshall@software.ORG (Eric Marshall) (10/13/88)

	Here is my first full NeWS application, the always
popular *ruler*.  Not just one ruler mind you, but three!  The
kind of rulers supported are English, Metric, and Unit.  I almost
forgot to mention that the ruler can be displayed either horizontally
or vertically.  Will the features ever stop?

	The only machine specific stuff about the ruler is
the variable /units_per_inch, which is set to the number of units
per inch :-)  If your version of NeWS supports a correct default
user space, set it to 72, otherwise figure the value out somehow.
Sun NeWS 1.1 has the default user space set to be the monitor
resolution, and the standard Sun monochrome monitor (which is
what I have) has 83 pixels per inch.  Enjoy.


Eric Marshall
Software Productivity Consortium
1880 North Campus Commons Drive
Reston, VA 22091
(703) 391-1838

CSNET: marshall@software.org
ARPANET: marshall%software.org@relay.cs.net  OR
         @relay.cs.net:marshall@software.org

------------------------------------------------------------------------------
			  	  The OSF.
				Just say NO.


----- 8< ----- 8< ----- 8< ----- 8< ----- 8< ----- 8< ----- 8< ----- 8< -----

#! /usr/NeWS/bin/psh

%
%  An English, Metric, and Unit ruler.
%

%% Sun NeWS 1.1 bug fixes --------------------------------------------

% default user space equals the device resolution rather than
% 72 units per inch, standard Sun monochrome monitor resolution is
/units_per_inch 83 def

% work around show bug when using rotated text on monochrome
% monitors, individually emit each character of the string
/SHOW { { cvis show } forall } def

%% Global Definitions ------------------------------------------------

% upper case letters are 17 units tall for 24 point Times-Bold
% font (so says charpath and pathbbox)
/half_text_height 8.5 def

% kinds of rulers
/english 1 def
/metric  2 def
/unit    3 def

/ruler_kind        unit def
/horizontal_ruler? true def

/ruler_width     0 def     % logical width
/ruler_height    0 def     % logical height

/ruler_menu [
  (English)        { /ruler_kind english store draw_ruler }
  (Metric)         { /ruler_kind metric  store draw_ruler }
  (Unit)           { /ruler_kind unit    store draw_ruler }
  (Vertical Ruler) { make_vertical_ruler }
  (Stretch Edge)   { getfbclick pop pop /stretchwindowedge ThisWindow send }
  (Quit)           { currentprocess killprocessgroup }
] /new DefaultMenu send def

%% English Stuff ----------------------------------------------------------

/english_hash_distance units_per_inch 8 div def
/english_unit_width units_per_inch def

%
% Draw the ruler markings for an English ruler.
%
/draw_english_markings { % draw_hash_labels? => -
  /draw_hash_labels? exch def
  /hash_counter 1 def
  /current_hash_label 1 def

  english_hash_distance
  english_hash_distance
  ruler_width english_unit_width add {
    /x exch def
    x 0 moveto
    0
    hash_counter 8 eq { % inch
      draw_hash_labels? {
        (Inch) draw_ruler_kind
        current_hash_label x draw_hash_label
      } if

      /current_hash_label current_hash_label 1 add def
      /hash_counter 0 def
      20
    } {
      hash_counter 4 eq { % 1/2 inch
        12.5
      } {
        hash_counter 2 mod 0 eq { % 1/4 inch
          8
        } { % 1/8 inch
          5
        } ifelse
      } ifelse
    } ifelse

    rlineto stroke

    /hash_counter hash_counter 1 add def
  } for
} def

%% Metric Stuff ----------------------------------------------------------

/metric_hash_distance units_per_inch 25.4 div def
/metric_unit_width metric_hash_distance 50 mul def

%
% Draw the ruler markings for a Metric ruler.
%
/draw_metric_markings { % draw_hash_labels? => -
  /draw_hash_labels? exch def
  /hash_counter 1 def
  /current_hash_label 5 def

  metric_hash_distance
  metric_hash_distance
  ruler_width metric_unit_width add {
    /x exch def
    x 0 moveto
    0
    hash_counter 10 mod 0 eq { % centimeter
      hash_counter 50 eq {
        draw_hash_labels? {
          (CM) draw_ruler_kind
          current_hash_label x draw_hash_label
        } if

        /current_hash_label current_hash_label 5 add def
        /hash_counter 0 def
      } if

      20
    } { % millimeter
      5
    } ifelse

    rlineto stroke

    /hash_counter hash_counter 1 add def
  } for
} def


%% Unit Stuff ----------------------------------------------------------

/unit_hash_distance 10 def
/unit_unit_width 100 def

%
% Draw the ruler markings for a Unit ruler.
%
/draw_unit_markings { % draw_hash_labels? => -
  /draw_hash_labels? exch def
  /hash_counter 1 def
  /current_hash_label 100 def

  unit_hash_distance
  unit_hash_distance
  ruler_width unit_unit_width add {
    /x exch def
    x 0 moveto
    0
    hash_counter 10 mod 0 eq { % 100 units
      20
      draw_hash_labels? {
        (Unit) draw_ruler_kind
        current_hash_label x draw_hash_label
      } if

      /current_hash_label current_hash_label 100 add def
      /hash_counter 0 def
    } {
      hash_counter 5 mod 0 eq { % 50 units
        10
      } { % 10 units
        5
      } ifelse
    } ifelse

    rlineto stroke

    /hash_counter hash_counter 1 add def
  } for
} def

%% Ruler Stuff ----------------------------------------------------------

%
% Convert the horizontal ruler into a vertical ruler.
%
/make_vertical_ruler { % - => -
  /horizontal_ruler? false store

  % pivot the ruler about its center point
  /center_x win /FrameX get ruler_width 2 div add def
  /center_y win /FrameY get ruler_height 2 div add def

  center_x ruler_height 2 div sub
  center_y ruler_width 2 div sub
  ruler_height
  ruler_width
  /reshape win send

  % change menu entry back to "Horizontal Ruler"
  3 (Horizontal Ruler) { make_horizontal_ruler } /changeitem ruler_menu send
} def


%
% Convert the vertical ruler into a horizontal ruler.
%
/make_horizontal_ruler { % - => -
  /horizontal_ruler? true store

  % pivot the ruler about its center point
  /center_x win /FrameX get ruler_height 2 div add def
  /center_y win /FrameY get ruler_width 2 div add def

  center_x ruler_width 2 div sub
  center_y ruler_height 2 div sub
  ruler_width
  ruler_height
  /reshape win send

  % change menu entry back to "Vertical Ruler"
  3 (Vertical Ruler) { make_vertical_ruler } /changeitem ruler_menu send
} def


%
% Draw the kind of the ruler, English, Metric, or Unit.
%
/draw_ruler_kind { % ruler_kind => -
  gsave
    10 ruler_height 2 idiv half_text_height sub moveto
    SHOW
  grestore
} def


%
% Draw one of the ruler hash labels centered within the ruler.
%
/draw_hash_label { % x_position hash_label => -
  /x exch def
  /hash_label exch def

  /label_string 4 string def
  hash_label label_string cvs
  stringwidth
  pop
  /half_string_width exch 2 idiv def
  x half_string_width sub
  ruler_height 2 idiv half_text_height sub
  gsave
    moveto
    label_string
    SHOW
  grestore
} def


%
% Draw the hash marks on the edge of the ruler.
%
/draw_hash_marks { % - => -
  0 0 moveto

  % draw the bottom and top hash marks
  1 1 2 {
    % invert the Y axis for the hash marks on the top
    2 eq {
      0 ruler_height translate
      [ 1 0 0 -1 0 0 ] concat
      false     % draw_hash_labels? parameter to draw_XXX_markings routines
    } {
      true      % draw_hash_labels? parameter to draw_XXX_markings routines
    } ifelse

    ruler_kind english eq {
      draw_english_markings
    } {
      ruler_kind metric eq {
        draw_metric_markings
      } {
        draw_unit_markings
      } ifelse
    } ifelse
  } for
} def


%
% Draw the entire ruler.
%
/draw_ruler { % - => -
  win /ClientCanvas get setcanvas

  erasepage
  0 strokecanvas

  % set up ruler for either horizontal or vertical display
  horizontal_ruler? {
    /ruler_width win /ClientWidth get store
    /ruler_height win /ClientHeight get store
  } {
    /ruler_width win /ClientHeight get store
    /ruler_height win /ClientWidth get store
    0 ruler_width translate
    -90 rotate
  } ifelse

  draw_hash_marks
} def

%% Main ----------------------------------------------------------

/Times-Bold findfont 24 scalefont setfont

/win framebuffer /new DefaultWindow send def

{
  % remove the frame border, and redefine its associated methods
  /BorderLeft   0 def
  /BorderBottom 0 def
  /BorderRight  0 def
  /BorderTop    0 def
  /PaintFrame   nullproc def
  /PaintFocus   nullproc def

  /PaintClient { draw_ruler } def

  % redefine the menu
  /ClientMenu ruler_menu def
} win send

150 450 850 90

/reshape win send
/map win send