[comp.windows.news] Kanji: Browse the kanji font

sjs@jcricket.ctt.bellcore.com (Stan Switzer) (09/30/88)

In order to make up for so many postings of KeySee, I submit my kanji
font browser program for your enjoyment.

The Kanji font has normal ASCII glyphs in the regular ASCII range, but
if a character is greater than 127, it and the next character are
taken to represent Kanji characters.  Basically, only the ASCII
printable character range with the high bit on is mapped.  The rest of
the range is unmapped (sort of, see comments).

The program could be quite a bit simpler, but it diddles the scrollbar
(resulting in one whose bubble is proportional to the region displayed)
and implements "copyarea" scrolling, among other tweaks.

For what its worth, my wife's last name is (\307\317).

Enjoy,
Stan Switzer  sjs@ctt.bellcore.com

P.S.: I have an even newer and better version of KeySee now, but I
can't quite bring myself to post it again unless enough people mail me
requesting it.

----------- snip snip ------------------------
#!/usr/NeWS/bin/psh
%
% Explore the Kanji font
%
% Copyright (C) 1988 by Stan Switzer. All rights reserved.
% This program is provided for unrestricted use, provided that this 
% copyright message is preserved. There is no warranty, and no author 
% or distributer accepts responsibility for any damage caused by this 
% program. 
%

% Notes:
%
% It seems that Kanji is encoded by pairs of hyper-printable-ASCII
% characters.  If we were to give each Kanji char a number "n"
% beginning at 0, then "n", in terms of the pair (a,b) is given by
%    n = 96*(a-160) + (b-160)
% The -160 term comes from subtracting 128 for hyperASCII and 32
% for printable ASCII.  There are many ways to get the same character
% (when, for instance, b is not in the "normal" range of 160-255).
% This analysis is based on trial and error and error and ....
%
% For the sake of nomenclature, we will call this number the "ordinal"
% of the character
%
% Seems to crash NeWS server at dec 245,69 and 244,165:
% maxOrdinal is not arbitrary!

/F { exch findfont exch scalefont } def
/cvoi { (8#) exch append cvx stopped 0 if } def
/cvos { 8 (ZZZZZ) cvrs } def
/pair2ord { 160 sub exch 160 sub 96 mul add } def
/ord2pair { dup 96 idiv 160 add exch 96 mod 160 add } def
/nxtpair { 1 add dup 255 gt { pop 1 add 160 } if } def
/pair2char { (ZZ) dup 0 4 index put dup 1 3 index put } def

systemdict /Item known not { (NeWS/liteitem.ps) run } if

/SmallButton ButtonItem []
classbegin
  /new { /new super send begin
    /ItemBorder null def
    /ItemFrame 2 def
    /ItemGap 3 def
    /ItemRadius .2 def
  currentdict end } def
classend def

/BetterBar SimpleScrollbar dictbegin
    /BoxSize	1	def
dictend classbegin
    /SetScale {
	BoxSize  % leave on stack for later
	    /BoxSize BarMax BarMin sub BarPageValue exch div abs
	    ItemHeight ButtonSize dup add sub mul 12 max def
	    /SetScale super send
	BoxSize ne { /paint self send } if
    } def
    /BoxPath {
	ValueToY ItemFrame ItemWidth .15 mul 3 -1 roll       % dx x y
	ItemWidth .7 mul BoxSize rectframe
    } def
classend def

/VScrollWindow DefaultWindow
dictbegin
    /VScrollbar		null def
    /LeftSide?		true def
dictend
classbegin
    /ScrollWidth	18 def
    /BorderWidth	16 def
    /BorderLeft		{ LeftSide? ScrollWidth BorderWidth ifelse } def
    /BorderRight	{ LeftSide? BorderWidth ScrollWidth ifelse } def
    /destroy { % - => - (Create frame control canvases/items)
        /VScrollbar null def
        /destroy super send
    } def
    /CreateFrameControls { % - => - (Create frame control canvases/items)
        /CreateFrameControls super send
        /VScrollbar
            [1 0 .01 .1 null] 0 {} FrameCanvas /new BetterBar send
            def
    } def
    /CreateFrameInterests { % - => - (Create frame control interests)
        /CreateFrameInterests super send
        FrameInterests begin
        % Append the scroll bar "start" interests to the frame interests.
        % The odd "forall" is used to create unique names for inclusion
        % in the frame interests dictionary.
            /makestartinterests VScrollbar send {
                (VScrollbar) 1 index /Name get cvx 100 string cvs append
                cvn exch def
            } forall
        end
    } def
    /MoveFrameControls { % - => - ([Re]set frame control shapes)
        /MoveFrameControls super send
	LeftSide? 0 { FrameWidth BorderRight sub } ifelse
	BorderBottom 1 sub
	ScrollWidth FrameHeight BorderBottom sub BorderTop sub 2 add
	/reshape VScrollbar send
    } def
    /PaintFrameControls { % - => - (Paint frame control areas)
    gsave
	/PaintFrameControls super send
	/paint VScrollbar send
    grestore
    } def
classend def

/KanjiDemo VScrollWindow
dictbegin
  /Size 24 def
  /Kanji /Kanji //Size F def
  /Roman /Times-Roman 12 F def
  /Symbol /Symbol 18 F def
  /BigSym /Symbol 36 F def
  /FrameLabel (Kanji Demo) def
  /Items null def
  /ItemList null def
  /ItemProc null def
  /Ordinal 0 def
  /minOrdinal 0 def
  /maxOrdinal 8068 def		% Empirical constant
  /ClientMenu null def		% initialized on canvas create
  /TmpDict null def
  % Layout Params, set in Recalc:
  /Descend null def	/ItemX null def 	/RowLabelX null def
  /Col0 null def	/ColWidth null def	/nCols null def
  /ItemY null def	/ColLabelY null def	/Row0 null def
  /RowHeight null def	/nRows null def
dictend classbegin

  /new {
    /new super send begin
      /PaintClient {
        ClientFillColor fillcanvas
        ClientCanvas setcanvas
        ItemList paintitems
	0 nRows paint-me
      } def
      /TmpDict 20 dict store
    currentdict end
  } def

  /CreateFrameControls {
    /CreateFrameControls super send
    % attach scroll proc
    VScrollbar begin /NotifyUser { ItemValue /SCROLL ThisWindow send } def end
  } def

  /CreateClientCanvas {
    /CreateClientCanvas super send
   
    % various items:
    /Items dictbegin
      /nextpage (Next Page) { +1 /PAGE ThisWindow send }
	ClientCanvas 0 0 /new SmallButton send def
      /prevpage (Prev Page) { -1 /PAGE ThisWindow send }
	ClientCanvas 0 0 /new SmallButton send def
      /nexthalfpage (Up Half Page) { +.5 /PAGE ThisWindow send }
	ClientCanvas 0 0 /new SmallButton send def
      /prevhalfpage (Down Half Page) { -.5 /PAGE ThisWindow send }
	ClientCanvas 0 0 /new SmallButton send def
      /nextline (Up Line) { +1 /LINE ThisWindow send }
	ClientCanvas 0 0 /new SmallButton send def
      /prevline (Down Line) { -1 /LINE ThisWindow send }
	ClientCanvas 0 0 /new SmallButton send def
    dictend store

    % Display order (dictionaries do not retain order):
    /ItemList Items begin [
      nextpage prevpage nexthalfpage prevhalfpage nextline prevline
    ] end store

    /ItemProc ItemList forkitems store
  } def

  /ShapeClientCanvas {
    /ShapeClientCanvas super send
    Recalc	% recalc layoput params

    % Menus (here instead of in /new so FrameMenu is already set):
    ClientMenu null eq {
      /ClientMenu [	% Menu items:
	%(Next Page)	{ +1 /PAGE ThisWindow send }
	%(Prev Page)	{ -1 /PAGE ThisWindow send }
	%(Up Line)	{ +1 /LINE ThisWindow send }
	%(Down Line)	{ -1 /LINE ThisWindow send }
        %(Zap)		{ /destroy ThisWindow send }
	[(\335) Symbol]	{ +1 /PAGE ThisWindow send }
	[(\337) Symbol]	{ -1 /PAGE ThisWindow send }
	[(\255) Symbol]	{ +1 /LINE ThisWindow send }
	[(\257) Symbol]	{ -1 /LINE ThisWindow send }
	(24 pt.)	{ 24 /SIZE ThisWindow send }
	(16 pt.)	{ 16 /SIZE ThisWindow send }
        %[(\247) BigSym]	{ /destroy ThisWindow send }
        [(\304) BigSym]	{ /destroy ThisWindow send }
	/sun30		FrameMenu
      ] /new DefaultMenu send store
      {			% Menu options:
	/LayoutStyle	[4 2] def
	/CenterItems?	false def
      } ClientMenu send
    } if

    ClientCanvas setcanvas

    % now, move the items to their rightful places
    TmpDict begin /X ItemX def /Y ItemY def /Sep 5 def
      ItemList {
	X Y /move 3 index send
	  /ItemWidth exch send X add Sep add /X exch store
      } forall
    end
  } def

  /Recalc { % - => -  -- recalculates various layout parameters
    /Descend Kanji fontdescent store
    /ItemX 5 store
    /RowLabelX ItemX store
    /Col0 60 store
    /ColWidth Size 6 add store
    /nCols ClientWidth Col0 sub ColWidth div cvi store
    /ItemY ClientHeight 30 sub store
    /ColLabelY ItemY store
    /Row0 ColLabelY 20 sub store
    /RowHeight Size 6 add store
    /nRows ColLabelY Descend sub RowHeight div cvi store
  } def

  /ColRnd { % where => where
    nCols idiv nCols mul % round to lower multiple of nCols
  } def
    
  /SCROLL { % where => -
    ColRnd GoToChar
  } def

  /PAGE {  % npages => -
    nCols nRows mul mul Ordinal add ColRnd GoToChar
  } def

  /LINE {  % nlines => -
    nCols mul Ordinal add
    GoToChar
  } def

  /SIZE { % size => -
    ClientCanvas setcanvas 0 nRows erase-me
    /Size exch store
    /Kanji /Kanji Size F store
    Recalc
    DoIt
  } def

  /DoIt {
    Ordinal 0 lt { /Ordinal 0 store } if
    ClientCanvas setcanvas
    0 nRows erase-me
    0 nRows paint-me
  } def

  /FasterDoIt { % +/-rows =>
    ClientCanvas setcanvas
    TmpDict begin
      /slide exch def
      slide 0 lt { % down
	0 nRows slide add slide slide-me
	0 slide neg erase-me
	0 slide neg paint-me
      } { % up
	slide nRows slide sub slide slide-me
	nRows slide sub slide erase-me
	nRows slide sub slide paint-me
      } ifelse
    end
  } def

  /GoToChar { % Ordinal =>
    dup minOrdinal lt { pop minOrdinal } if
    dup maxOrdinal gt { pop maxOrdinal } if
    cvi Ordinal exch /Ordinal exch store
    TmpDict begin
      /OldOrd exch def
      /Diff Ordinal OldOrd sub def
      /DiffRows Diff nCols idiv def
      DiffRows abs nRows lt Diff nCols mod 0 eq and 
	{ DiffRows true }
	false
      ifelse
    end
    //FasterDoIt //DoIt ifelse
  } def

  /slide-me { % fstrow nrows dist => -
    % 3 copy 3 array astore (% % % slide-me\n) exch dbgprintf
    TmpDict begin
      /dist exch RowHeight mul def
      /nr exch RowHeight mul def /fstr exch RowHeight mul def
      0 ColLabelY nr sub fstr sub Descend sub
      ClientWidth nr rectpath
      0 dist copyarea fill
    end
  } def

  /erase-me { % fstrow nrows => -
    % 2 copy 2 array astore (% % erase-me\n) exch dbgprintf
    TmpDict begin gsave
      /nr exch RowHeight mul def /fstr exch RowHeight mul def
      0 ColLabelY nr sub fstr sub Descend sub
      ClientWidth nr rectpath
      ClientFillColor setshade fill
    grestore end
  } def

  % written to avoid multiplication especially especially division
  % in the inner loops.  Don't know whether it really matters, though.
  /paint-me { % fstrow nrows => -
    % 2 copy 2 array astore (% % paint-me\n) exch dbgprintf
    textcolor setshade
    TmpDict begin
      /nr exch def /fstr exch def
      /N Ordinal fstr nCols mul add def
      /R ColLabelY fstr RowHeight mul sub def
      /More? N maxOrdinal le def
      N ord2pair
      nr { /R R RowHeight sub store RowLabelX R moveto 
	More? { 2 copy Roman setfont exch cvos show (,)show cvos show } if
	Kanji setfont
	/C Col0 def
	nCols { C R moveto /C C ColWidth add store
	  N maxOrdinal gt {
	    /More? false store
	  } {
	    pair2char show
	    nxtpair
	    /N N 1 add store
	  } ifelse
	} repeat
	pause % give other pgms a chance
      } repeat
      pop pop
      [ maxOrdinal minOrdinal nCols dup nRows mul null ]
	/setrange VScrollbar send
      Ordinal /setvalue VScrollbar send
    end
  } def

classend def

/win framebuffer /new KanjiDemo send def
/reshapefromuser win send
/map win send

% ----- if anything follows this line it is not part of the program -----