BSD 4_3 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Thu, 30 Jan 1986 23:40:31 +0000 (15:40 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Thu, 30 Jan 1986 23:40:31 +0000 (15:40 -0800)
Work on file usr/contrib/X/xdemo/menus.clu
Work on file usr/contrib/X/xdemo/balls.clu

Synthesized-from: CSRG/cd1/4.3

usr/contrib/X/xdemo/balls.clu [new file with mode: 0644]
usr/contrib/X/xdemo/menus.clu [new file with mode: 0644]

diff --git a/usr/contrib/X/xdemo/balls.clu b/usr/contrib/X/xdemo/balls.clu
new file mode 100644 (file)
index 0000000..a52ed51
--- /dev/null
@@ -0,0 +1,174 @@
+% from Lucasfilm Ltd.
+
+ballsdemo = proc ()
+    ai = array[int]
+    n = 20
+    bsize = 21
+    rad = bsize / 2
+    nx = 48
+    ny = -36
+    nz = 80
+    qi = sequence[int]
+    dmat = sequence[qi]$[qi$[1, 13, 4, 16],
+                        qi$[9, 5, 12, 8],
+                        qi$[3, 15, 2, 14],
+                        qi$[11, 7, 10, 6]]
+
+    bwidth: int := int$parse(xdemo_default("balls", "BorderWidth"))
+       except when not_found, overflow, bad_format: bwidth := 2 end
+    back: x_pixmap := x_display$white()
+    bdr: x_pixmap := x_display$black()
+    plane: int := 1
+    if x_display$cells() > 2
+       then begin
+           r, g, b: int := x_parse_color(xdemo_default("balls", "Border"))
+           bdr := x_pixmap$tile(x_display$alloc_color(r, g, b))
+           end except when not_found: end
+           cback: string := xdemo_default("balls", "Background")
+              except when not_found: cback := "" end
+           cfore: string := xdemo_default("balls", "Foreground")
+              except when not_found: cfore := "" end
+           if string$empty(cback)  cand  string$empty(cfore)
+              then exit done end
+           pixs: pixellist
+           pixs, plane := x_display$alloc_cells(1, 1, false)
+           back := x_pixmap$tile(pixs[1])
+           r, g, b: int
+           if string$empty(cback)
+              then r, g, b := x_display$query_color(WhitePixel)
+              else r, g, b := x_parse_color(cback)
+              end
+           x_display$store_color(pixs[1], r, g, b)
+           if string$empty(cfore)
+              then r, g, b := x_display$query_color(BlackPixel)
+              else r, g, b := x_parse_color(cfore)
+              end
+           x_display$store_color(pixs[1] + plane, r, g, b)
+       end except when done: end
+    w: x_window, wid0, hgt0: int := x_cons("balls", back, bdr,
+                                          xdemo_geometry(), "=400x400+1+1",
+                                          40, 40, bwidth)
+    w.name := "balls"
+    w.input := UnmapWindow
+    x_window$map(w)
+    w.input := ExposeWindow + UnmapWindow
+    x: ai := ai$fill(0, n, 0)
+    y: ai := ai$fill(0, n, 0)
+    vx: ai := ai$fill(0, n, 0)
+    vy: ai := ai$fill(0, n, 0)
+    r: _wordvec := _wordvec$create(bsize)
+    r[1] := 1
+    swap: bool := _wordvec$bfetch(r, 1) = 0
+    r[1] := 0
+    for xx: int in int$from_to(-rad, rad) do
+       maxy: int := isqrt(rad * rad - xx * xx)
+       for yy: int in int$from_to(-maxy, maxy) do
+           if (nx * xx + ny * yy +
+               nz * isqrt(rad * rad - xx * xx - yy * yy)) *
+              17 / (100 * rad) < dmat[xx // 4 + 1][yy // 4 + 1]
+              then yy := yy + rad + 1
+                   r[yy] := r[yy] + 2 ** (xx + rad)
+              end
+           end
+       end
+    if swap
+       then for i: int in int$from_to_by(1, 4 * bsize, 4) do
+               v: int := _wordvec$bfetch(r, i)
+               _wordvec$bstore(r, i, _wordvec$bfetch(r, i + 2))
+               _wordvec$bstore(r, i + 2, v)
+               v := _wordvec$bfetch(r, i + 1)
+               _wordvec$bstore(r, i + 1, _wordvec$bfetch(r, i + 3))
+               _wordvec$bstore(r, i + 3, v)
+               end
+       end
+    ball: x_pixmap := x_pixmap$create(x_bitmap$create(bsize, bsize, r),
+                                     plane, 0)
+    ev: event := x_input$empty_event()
+    while true do
+       sx, sy, width, height, bw, ms, wk: int, iw: x_window := x_window$query(w)
+       if width <= 5 * bsize  cor  height <= 5 * bsize
+          then x_window$destroy(w)
+               return
+          end
+       x_window$clear(w)
+       width := width - bsize
+       height := height - bsize
+       for i: int in int$from_to(0, n - 1) do
+           x[i] := random$next(width)
+           y[i] := random$next(height)
+           vx[i] := random$next(13) - 6
+           vy[i] := random$next(13) - 6
+           x_window$pixmap_put(w, ball, 0, 0, bsize, bsize, x[i], y[i],
+                               GXxor, plane)
+           end
+       count: int := 0
+       while count ~= 0  cor  ~x_input$pending() do
+           if count = 4
+              then count := 0
+              else count := count + 1
+              end
+           for i: int in int$from_to(0, n - 1) do
+               x0: int := x[i]
+               y0: int := y[i]
+               xx: int := x0 + vx[i]
+               if xx < 0
+                  then xx := -xx
+                       vx[i] := -vx[i]
+                elseif xx >= width
+                  then xx := 2 * (width - 1) - xx
+                       vx[i] := -vx[i]
+                end
+               x[i] := xx
+               yy: int := y0 + vy[i]
+               if yy < 0
+                  then yy := -yy
+                       vy[i] := -vy[i]
+                elseif yy >= height
+                  then yy := 2* (height - 1) - yy
+                       vy[i] := -vy[i]
+                end
+               y[i] := yy
+               x_window$pixmap_put(w, ball, 0, 0, bsize, bsize, x0, y0,
+                                   GXxor, plane)
+               x_window$pixmap_put(w, ball, 0, 0, bsize, bsize, xx, yy,
+                                   GXxor, plane)
+               end
+           for i: int in int$from_to(1, n - 1) do
+               for j: int in int$from_to(0, i - 1) do
+                   x0: int := x[i] - x[j]
+                   y0: int := y[i] - y[j]
+                   if int$abs(x0) >= bsize  cor  int$abs(y0) >= bsize  cor
+                      x0 * x0 + y0 * y0 >= bsize * bsize
+                      then continue end
+                   if y0 < 0
+                      then y0 := -y0
+                           x0 := -x0
+                      end
+                   if rad * int$abs(x0) > rad * int$abs(y0)
+                      then vx[i] := -vx[i]
+                           vx[j] := -vx[j]
+                    elseif rad * int$abs(y0) > (rad + 2) * int$abs(x0)
+                      then vy[i] := -vy[i]
+                           vy[j] := -vy[j]
+                    elseif y0 > 0
+                      then t: int := vx[i]
+                           vx[i] := -vy[i]
+                           vy[i] := -t
+                           t := vx[j]
+                           vx[j] := -vy[j]
+                           vy[j] := -t
+                    else t: int := vx[i]
+                         vx[i] := -vy[i]
+                         vy[i] := t
+                         t := vx[j]
+                         vx[j] := -vy[j]
+                         vy[j] := t
+                    end
+                   end
+               end
+           end
+       x_input$deq(ev)
+       if ev.kind = UnmapWindow
+          then x_input$deq(ev) end
+       end
+    end ballsdemo
diff --git a/usr/contrib/X/xdemo/menus.clu b/usr/contrib/X/xdemo/menus.clu
new file mode 100644 (file)
index 0000000..9e5983e
--- /dev/null
@@ -0,0 +1,877 @@
+
+left_Arrow = "\000\000\002\000\006\000\016\000\036\000\076\000" ||
+            "\176\000\376\000\376\001\376\003\376\007\176\000" ||
+            "\156\000\306\000\302\000\200\001\200\001\000\000"
+left_Mask  = "\003\000\007\000\017\000\037\000\077\000\177\000" ||
+            "\377\000\377\001\377\003\377\007\377\017\377\017" ||
+            "\377\000\357\001\347\001\303\003\300\003\200\001"
+
+la_Width   = 12
+la_Height  = 18
+la_X      = 1
+la_Y       = 1
+
+vLine_Width   = 1
+vBottom_Space = 2
+vTop_Space    = 2
+vLeft_Space   = 1   %% avg_width chars
+vRight_Space  = 1
+
+
+menu_bar = cluster is
+       init,
+       reset,
+       insert,
+       append,
+       remove,
+       select,
+       get_cursor, get_fore, get_back, get_forepix, get_backpix, get_plane
+
+    title = record [ Menu:   menu,
+                    Window: x_window ]
+    at = array[title]
+
+    rep = record[
+             Window:   x_window,
+             White_W:  x_window,
+             MBW:      x_window,
+             Cursor:   x_cursor,
+             Font:     x_font,
+             Fore:     x_pixmap,
+             Back:     x_pixmap,
+             ForePix:  int,
+             BackPix:  int,
+             Plane:    int,
+             Titles:   at,
+             Ch_Width: int,
+             Height:   int,
+             Width:    int
+                ]
+
+    vExtra_Width  = 4 * vLine_Width
+    vExtra_Height = 4 * vLine_Width
+    vWhite_Border  = 1
+    vWExtra_Width  = vExtra_Width  + (2 * vWhite_Border)
+    vWExtra_Height = vExtra_Height + (2 * vWhite_Border)
+    vLeft_Offset  = vLine_Width
+    vTop_Offset   = vLine_Width
+    vHighLight_Offset = vLine_Width
+    vHighLight_Height = vExtra_Height - vTop_Offset  - vHighLight_Offset
+    vHighLight_Width  = vExtra_Width  - vLeft_Offset - vHighLight_Offset
+
+    Init = proc (W: x_window, Font: x_font, BackPix, Plane, MousePix: int)
+            returns (cvt) signals (error(string))
+       ForePix: int := i_xor(BackPix, Plane)
+       Cursor: x_cursor := x_cursor$SCons(la_Width, la_Height,
+                                         left_Arrow, left_Mask,
+                                         MousePix, BackPix,
+                                         la_X, la_Y, GXcopy)
+       Avg_Width: int,
+       Height: int,
+       Ch1: char,
+       ChLast: char,
+       BaseLine: int,
+       FixedWidth: bool := x_font$Query(Font)
+          resignal Error
+       Height := Height + vTop_Space + vBottom_Space
+       Back: x_pixmap := x_pixmap$Tile(BackPix)
+       Fore: x_pixmap := x_pixmap$Tile(ForePix)
+       White_W: x_window := x_window$Create(
+                                0,
+                                0,
+                                vWExtra_Width,
+                                Height + vWExtra_Height,
+                                Back,
+                                x_display$Root(),
+                                0,
+                                Back)
+       White_W.Input := buttonReleased % + enterWindow
+       White_W.Cursor := Cursor
+       MBW: x_window := x_window$Create(
+                            1,
+                            1,
+                            vExtra_Width,
+                            Height + vExtra_Height,
+                            Fore,
+                            White_W,
+                            0,
+                            Fore)
+       MBW.Input := buttonReleased % + enterWindow)
+       MBW.Cursor := Cursor
+       x_window$Map(MBW)
+       return (rep${ Window:   W,
+                     White_W:  White_W,
+                     MBW:      MBW,
+                     Cursor:   Cursor,
+                     Font:     Font,
+                     Fore:     Fore,
+                     Back:     Back,
+                     ForePix:  ForePix,
+                     BackPix:  BackPix,
+                     Plane:    Plane,
+                     Titles:   at$[],
+                     Ch_Width: Avg_Width,
+                     Height:   Height,
+                     Width:    vLeft_Offset })
+       end Init
+
+    Reset = proc (MB: cvt)
+       x_window$Destroy(MB.White_W)
+       for T: title in at$Elements(MB.Titles) do
+           menu$Reset(T.Menu)
+           end
+       MB.Titles := at$[]
+       MB.Width  := vLeft_Offset
+       MB.White_W := x_window$Create(
+                     0,
+                     0,
+                     vWExtra_Width,
+                     MB.Height + vWExtra_Height,
+                     MB.Back,
+                     x_display$Root(),
+                     0,
+                     MB.Back)
+       MB.White_W.Input := buttonReleased % + enterWindow)
+       MB.White_W.Cursor := MB.Cursor
+       MB.MBW := x_window$Create(
+                     1,
+                     1,
+                     vExtra_Width,
+                     MB.Height + vExtra_Height,
+                     MB.Fore,
+                     MB.White_W,
+                     0,
+                     MB.Fore)
+       MB.MBW.Input := buttonReleased % + enterWindow)
+       MB.MBW.Cursor := MB.Cursor
+       x_window$Map(MB.MBW)
+       end Reset
+
+    Insert = proc (MB: cvt, M: menu, Before_M: menu) signals (not_found)
+       for I: int in at$Indexes(MB.Titles) do
+           T: title := MB.Titles[I]
+           if (T.Menu = Before_M)
+              then M.Width := x_font$Width(MB.Font, M.Title) +
+                              (MB.Ch_Width *
+                               (vLeft_Space + vRight_Space))
+                   MB.Width := MB.Width + M.Width
+                   x_window$Change(MB.White_W, 
+                                   MB.Width - vLeft_Offset + vWExtra_Width,
+                                   MB.Height + vWExtra_Height)
+                   x_window$Change(MB.MBW, 
+                                   MB.Width - vLeft_Offset + vExtra_Width,
+                                   MB.Height + vExtra_Height)
+                   M.Start := T.Menu.Start
+                   MW: x_window := x_window$Create(
+                                       M.Start, vTop_Offset,
+                                       M.Width, MB.Height,
+                                       MB.Back,
+                                       MB.MBW,
+                                       0,
+                                       MB.Fore)
+                   MW.Input := buttonReleased + enterWindow
+                   MW.Cursor := MB.Cursor
+                   x_window$Map(MW)
+                   New_T: title := title${ Menu:   M,
+                                           Window: MW }
+                   at$AddH(MB.Titles, New_T)
+                   for J: int in int$From_To(at$High(MB.Titles) - 1, I) do
+                       T := MB.Titles[J]
+                       MB.Titles[J+1] := MB.Titles[J]
+                       T.Menu.Start := T.Menu.Start + M.Width
+                       x_window$Move(T.Window, T.Menu.Start, 0)
+                       end
+                   MB.Titles[I] := New_T
+                   return
+              end
+           end
+       signal Not_Found
+       end Insert
+
+    Append = proc (MB: cvt, M: menu)
+       M.Start  := MB.Width
+       M.Width := x_font$Width(MB.Font, M.Title) +
+                  (MB.Ch_Width *
+                   (vLeft_Space + vRight_Space))
+       MB.Width := MB.Width + M.Width
+       x_window$Change(MB.White_W, 
+                       MB.Width - vLeft_Offset + vWExtra_Width,
+                       MB.Height + vWExtra_Height)
+       x_window$Change(MB.MBW, 
+                       MB.Width - vLeft_Offset + vExtra_Width,
+                       MB.Height + vExtra_Height)
+       MW: x_window := x_window$Create(
+                           M.Start, vTop_Offset,
+                           M.Width, MB.Height,
+                           MB.Back,
+                           MB.MBW,
+                           0,
+                           MB.Fore)
+       MW.Input := buttonReleased + enterWindow
+       MW.Cursor := MB.Cursor
+       x_window$Map(MW)
+       at$AddH(MB.Titles, title${ Menu:   M,
+                                  Window: MW })
+       end Append
+
+    Remove = proc (MB: cvt, M: menu) signals (not_found)
+       for I: int in at$Indexes(MB.Titles) do
+           if (MB.Titles[I].Menu = M)
+              then MW: x_window := MB.Titles[I].Window
+                   for J: int in int$From_To(I+1, at$High(MB.Titles)) do
+                       T: title := MB.Titles[J]
+                       T.Menu.Start := T.Menu.Start - M.Width
+                       MB.Titles[J-1] := T
+                       end
+                   at$RemH(MB.Titles)
+                   x_window$Destroy(MW)
+                   MB.Width := MB.Width - M.Width
+                   x_window$Change(MB.White_W,
+                                   MB.Width - vLeft_Offset + vWExtra_Width,
+                                   MB.Height + vWExtra_Height)
+                   x_window$Change(MB.MBW,
+                                   MB.Width - vLeft_Offset + vExtra_Width,
+                                   MB.Height + vExtra_Height)
+                   menu$Reset(M)
+                   return
+              end
+           end
+       signal Not_Found
+       end Remove
+
+    Select = proc [evt: type] (MB: cvt, Start_X: int, Start_Y: int,
+                              Expose_Handler: ehand_proc, Expose_Hand_Arg: evt)
+              returns (menu, menu_item) signals (none)
+       ehand_proc = proctype(x_window, int, int, int, int, x_window, evt)
+       own E: event := x_input$Empty_Event()
+       %% There are three windows of interest:
+       %%   The main window (of which this is a menu bar) (MB.Window)
+       %%   The pop-up menu bar window.
+       %%   The (current) pull-down menu.
+       W_X:      int,
+       W_Y:      int,
+       W_Width:  int,
+       W_Height: int,
+       W_Border: int,
+       W_Map:    int,
+       W_Kind:   int,
+       W_Icon:   x_window := x_window$Query(MB.Window)
+       Left: int := int$Max(W_X + Start_X - (MB.Width / 2), 0)
+       Top:  int := int$Max(W_Y + Start_Y - (MB.Height / 2), 0)
+
+       Display_Bar(MB, Left, Top)
+
+       X: int := W_X + Start_X + vLeft_Offset - Left
+       Y: int := W_Y + Start_Y + vTop_Offset - Top
+
+       Selected_T: title := Title_Selected(X, Y, MB)
+       Select_Menu(Selected_T, MB, Top, Left)
+
+       Have_Item: bool := false
+       Selected_Item: menu_item
+
+       while (true) do
+           x_input$DeQ(E)
+           if      (E.Kind = ButtonReleased  cand  E.Value = MiddleButton)
+              then break
+            elseif (E.Kind = EnterWindow)
+              then %% Check if a Title.
+                   if (E.Win = Selected_T.Window)
+                      then continue           %% Same old title
+                      end
+                   for New_T: title in at$Elements(MB.Titles) do
+                       if (E.Win = New_T.Window)
+                          then DeSelect_Menu(Selected_T, MB)
+                               Select_Menu(New_T, MB, Top, Left)
+                               Selected_T := New_T
+                               continue        %% New title
+                          end
+                       end;
+                   %% Must be a new item.
+                   if (Have_Item)
+                      then %%% ???
+                           continue
+                      end
+                   Selected_Item := Item_Selected(E.Win,
+                                                  Selected_T, MB)
+                      except when None:
+                                  continue
+                             end
+                   Select_Item(Selected_Item, Selected_T)
+                   Have_Item := true
+            elseif (E.Kind = LeaveWindow)
+              then if (~ (Have_Item cand 
+                          menu_item$Match(Selected_Item, E.Win)))
+                      then %%% ?????
+                           continue
+                      else DeSelect_Item(Selected_Item,
+                                         Selected_T)
+                           Have_Item := false
+                      end
+            elseif (E.Kind = ExposeRegion)
+              then Expose_Handler(E.Win, E.X, E.Y, E.X0, E.Y0, E.Sub, Expose_Hand_Arg)
+            end
+           end
+       %X, Y, SubW := x_window$Query_Mouse(TopW)
+       %Item_Was_Selected: bool := (Have_Item cand
+       %                           Inside_Item(SubW, Selected_Item))
+       Item_Was_Selected: bool := Have_Item
+       if (Item_Was_Selected)
+          then Flash_Item(Selected_Item, Selected_T)
+               DeSelect_Item(Selected_Item, Selected_T)
+          end
+       DeSelect_Menu(Selected_T, MB)
+
+       x_window$UnMap(MB.White_W)
+       if (Item_Was_Selected)
+          then return (Selected_T.Menu, Selected_Item)
+          else signal None
+          end
+       end Select
+
+    Title_Selected  = proc (X: int, Y: int, MB: rep) returns (title) signals (none)
+       if ((Y < 0) cor (Y >= MB.Height))
+          then signal None
+          end
+       for T: title in at$Elements(MB.Titles) do
+           if ((X >= T.Menu.Start) cand (X < T.Menu.Start + T.Menu.Width))
+              then return (T)
+              end
+           end
+       signal None
+       end Title_Selected
+
+    Select_Menu = proc (Menu_T: title, MB: rep, Top: int, Left: int)
+       if (Menu_T = at$Bottom(MB.Titles))
+          then Left := Left - vLeft_Offset
+          end
+       menu$Select(Menu_T.Menu,
+                   (Left + Menu_T.Menu.Start + vLine_Width),
+                   (Top + vTop_Offset + MB.Height + vLine_Width))
+       x_window$Pix_Fill(Menu_T.Window, 0, x_bitmap$None(), 0, 0,
+                         Menu_T.Menu.Width, MB.Height, GXinvert, MB.Plane)
+       end Select_Menu
+
+    DeSelect_Menu = proc (Menu_T: title, MB: rep)
+       menu$DeSelect(Menu_T.Menu)
+       if (Menu_T = at$Bottom(MB.Titles))
+          then %% Lower left highlight
+               x_window$Pix_Set(MB.MBW, MB.BackPix,
+                                0,
+                                MB.Height + vExtra_Height - vHighLight_Height,
+                                vHighLight_Height, vHighLight_Width)
+
+          end
+       x_window$Pix_Fill(Menu_T.Window, 0, x_bitmap$None(), 0, 0,
+                         Menu_T.Menu.Width, MB.Height, GXinvert, MB.Plane)
+       end DeSelect_Menu
+
+    Inside_Item = proc (SubW: x_window, MI: menu_item)
+                   returns (bool)
+       return (menu_item$Match(MI, SubW))
+       end Inside_Item
+
+    Item_Selected = proc (Sub_W: x_window, T: title, MB: rep)
+                     returns (menu_item) signals (none)
+       for TstMI: menu_item in menu$All_Items(T.Menu) do
+           if (menu_item$Match(TstMI, Sub_W))
+              then if (TstMI.Selectable cand TstMI.Enabled)
+                      then return (TstMI)
+                      else signal None
+                      end
+              end
+           end
+       signal None
+       end Item_Selected
+
+    Select_Item = proc (MI: menu_item, M_T: title)
+       menu_item$Invert(MI, M_T.Menu.Max_Width)
+       end Select_Item
+
+    DeSelect_Item = proc (MI: menu_item, M_T: title)
+       menu_item$Invert(MI, M_T.Menu.Max_Width)
+       end DeSelect_Item
+
+    Flash_Item = proc (MI: menu_item, M_T: title)
+       M: menu := M_T.Menu
+       for I: int in int$From_To(1, 6) do
+           menu_item$Invert(MI, M.Max_Width)
+           x_flush()
+           _Sleep(30)
+           end
+       end Flash_Item
+
+    Display_Bar = proc (MB: rep, Left: int, Top: int)
+       White_W: x_window := MB.White_W
+       x_window$Move(White_W, Left, Top)
+       x_window$Map(White_W)
+       Black_W: x_window := MB.MBW
+       %% Lower left highlight
+       x_window$Pix_Set(Black_W, MB.BackPix,
+                        0,
+                        MB.Height + vExtra_Height - vHighLight_Height,
+                        vHighLight_Height, vHighLight_Width)
+       %% Upper right highlight
+       x_window$Pix_Set(Black_W, MB.BackPix,
+                        MB.Width - vLeft_Offset + vExtra_Width - vHighLight_Width,
+                        0,
+                        vHighLight_Height, vHighLight_Width)
+       for T: title in at$Elements(MB.Titles) do
+           x_window$Text(T.Window, T.Menu.Title, MB.Font,
+                         i_xor(MB.BackPix, MB.Plane), MB.BackPix,
+                         (vLeft_Space * MB.Ch_Width),
+                         vTop_Space)
+           end
+       end Display_Bar
+
+   Get_Cursor = proc (MB: cvt) returns (x_cursor)
+       return(MB.Cursor)
+       end Get_Cursor
+
+   Get_Fore = proc (MB: cvt) returns (x_pixmap)
+       return(MB.Fore)
+       end Get_Fore
+
+   Get_Back = proc (MB: cvt) returns (x_pixmap)
+       return(MB.Back)
+       end Get_Back
+
+   Get_ForePix = proc (MB: cvt) returns (int)
+       return(MB.ForePix)
+       end Get_ForePix
+
+   Get_BackPix = proc (MB: cvt) returns (int)
+       return(MB.BackPix)
+       end Get_BackPix
+
+   Get_Plane = proc (MB: cvt) returns (int)
+       return(MB.Plane)
+       end Get_Plane
+
+    end menu_bar
+
+menu = cluster is 
+       new,
+       reset,
+       equal,
+       get_title,
+       append,
+       remove,
+       item_changed,
+       all_items,
+       set_start,     get_start,
+       set_width,     get_width,
+       get_num_items,
+       get_max_width,
+       get_window,
+       select,         deselect
+       
+    mis = sequence[menu_item]
+
+    rep = record[ Title:     string,
+                 MB:        menu_bar,
+                 Items:     mis,
+                 Start:     int,
+                 Height:    int,
+                 Max_Width: int,
+                 Width:     int,
+                 White_W:   x_window,
+                 Window:    x_window ]
+
+    vExtra_Width  = 4 * vLine_Width
+    vExtra_Height = 4 * vLine_Width
+    vWhite_Border  = 1
+    vWExtra_Width  = vExtra_Width  + (2 * vWhite_Border)
+    vWExtra_Height = vExtra_Height + (2 * vWhite_Border)
+    vTop_Offset   = vLine_Width
+    vLeft_Offset  = vLine_Width
+    vHighLight_Offset = vLine_Width
+    vHighLight_Height = vExtra_Height - vTop_Offset  - vHighLight_Offset
+    vHighLight_Width  = vExtra_Width  - vLeft_Offset - vHighLight_Offset
+
+    New = proc (MB: menu_bar, Title: string) returns (cvt)
+       White_W: x_window := x_window$Create(   % A minimal window
+                               0, 0,
+                               vWExtra_Width,
+                               vWExtra_Height,
+                               MB.Back,
+                               x_display$Root(),
+                               0,
+                               MB.Back)
+       White_W.Input :=  buttonReleased % +
+                             %enterWindow +
+                             %leaveWindow
+       White_W.Cursor := MB.Cursor
+       Menu_W: x_window := x_window$Create(    % A minimal window
+                               1, 1,
+                               vExtra_Width,
+                               vExtra_Height,
+                               MB.Fore,
+                               White_W,
+                               0,
+                               MB.Fore)
+       Menu_W.Input := buttonReleased % +
+                             %enterWindow +
+                             %leaveWindow
+       Menu_W.Cursor := MB.Cursor
+       x_window$Map(Menu_W)
+       return (rep${ Title:     Title,
+                     MB:        MB,
+                     Items:     mis$[],
+                     Start:     0,
+                     Height:    vTop_Offset,
+                     Max_Width: 0,
+                     Width:     vLeft_Offset,
+                     White_W:   White_W,
+                     Window:    Menu_W })
+       end New
+
+    Reset = proc (M: cvt)
+       %% ???
+       end Reset
+
+    Equal = proc (M1: cvt, M2: cvt) returns (bool)
+       return (M1 = M2)
+       end Equal
+
+    Get_Title = proc (M: cvt) returns (string)
+       return (M.Title)
+       end Get_Title
+
+    Set_Width = proc (M: cvt, W: int)
+       M.Width := W
+       end Set_Width
+
+    Get_Width = proc (M: cvt) returns (int)
+       return (M.Width)
+       end Get_Width
+
+    Set_Start = proc (M: cvt, S: int)
+       M.Start := S
+       end Set_Start
+
+    Get_Start = proc (M: cvt) returns (int)
+       return (M.Start)
+       end Get_Start
+
+    Append = proc (M: cvt, MI: menu_item)
+       Max_Width: int := int$Max(MI.Width, M.Max_Width)
+       MI.Start := M.Height
+       M.Height := M.Height + MI.Height
+       x_window$Change(M.White_W,
+                       Max_Width + vWExtra_Width,
+                       M.Height - vTop_Offset + vWExtra_Height)
+       x_window$Change(M.Window,
+                       Max_Width + vExtra_Width,
+                       M.Height - vTop_Offset + vExtra_Height)
+       if (Max_Width > M.Max_Width)
+          then M.Max_Width := Max_Width
+               for TMI: menu_item in mis$Elements(M.Items) do
+                   menu_item$Setup(TMI, M.Window, vLeft_Offset, M.Max_Width)
+                   end
+          end
+       M.Items := mis$AddH(M.Items, MI)
+       menu_item$Setup(MI, M.Window, vLeft_Offset, M.Max_Width)
+       end Append
+
+    Remove = proc (M: cvt, MI: menu_item) signals (not_found)
+       Max_Width: int := 0
+       Found: bool := false
+       for Tst_MI: menu_item in mis$Elements(M.Items) do
+           if (Tst_MI = MI)
+              then Found := true
+                   continue
+              end
+           if (Found)
+              then Tst_MI.Start := Tst_MI.Start - MI.Height
+              end
+           Max_Width := int$Max(Max_Width, Tst_MI.Width)
+           end
+       if (~ Found)
+          then signal Not_Found
+          end
+       M.Height    := M.Height - MI.Height
+       x_window$Change(M.White_W,
+                       Max_Width + vWExtra_Width,
+                       M.Height - vTop_Offset + vWExtra_Height)
+       x_window$Change(M.Window,
+                       Max_Width + vExtra_Width,
+                       M.Height - vTop_Offset + vExtra_Height)
+       M.Max_Width := Max_Width
+       for TMI: menu_item in mis$Elements(M.Items) do
+           menu_item$Setup(TMI, M.Window, vLeft_Offset, M.Max_Width)
+           end
+       menu_item$Reset(MI)
+       end Remove
+
+    Item_Changed = proc (M: cvt, MI: menu_item) signals (not_found)
+       Max_Width: int := 0
+       for Tst_MI: menu_item in mis$Elements(M.Items) do
+           Max_Width := int$Max(Max_Width, Tst_MI.Width)
+           end
+       if (Max_Width ~= M.Max_Width)
+          then M.Max_Width := Max_Width
+               x_window$Change(M.White_W,
+                               Max_Width + vWExtra_Width,
+                               M.Height - vTop_Offset + vWExtra_Height)
+               x_window$Change(M.Window,
+                               Max_Width + vExtra_Width,
+                               M.Height - vTop_Offset + vExtra_Height)
+               for TMI: menu_item in mis$Elements(M.Items) do
+                   menu_item$Setup(TMI, M.Window, vLeft_Offset, M.Max_Width)
+                   end
+          end
+       end Item_Changed
+
+    Get_Num_Items = proc (M: cvt) returns (int)
+       return (mis$Size(M.Items))
+       end Get_Num_Items
+
+    Get_Max_Width = proc (M: cvt) returns (int)
+       return (M.Max_Width)
+       end Get_Max_Width
+
+    All_Items = iter (M: cvt) yields (menu_item)
+       for MI: menu_item in mis$Elements(M.Items) do
+           yield(MI)
+           end
+       end All_Items
+
+    Get_Window = proc (M: cvt) returns (x_window)
+       return (M.Window)
+       end Get_Window
+
+    Select = proc (M: cvt, X: int, Y: int)
+       x_window$Move(M.White_W, X-1, Y)
+       x_window$Map(M.White_W)
+       %% Lower left highlight
+       x_window$Pix_Set(M.Window, M.MB.BackPix,
+                        0,
+                        M.Height - vTop_Offset + vExtra_Height - vHighLight_Height,
+                        vHighLight_Height, vHighLight_Width)
+       %% Upper right highlight
+       x_window$Pix_Set(M.Window, M.MB.BackPix,
+                        M.Max_Width + vExtra_Width -  vHighLight_Height,
+                        0,
+                        vHighLight_Height, vHighLight_Width)
+       for MI: menu_item in mis$Elements(M.Items) do
+           menu_item$Display(MI, M.Max_Width)
+           end;
+       end Select
+
+    DeSelect = proc (M: cvt)
+       x_window$UnMap(M.White_W)
+       end DeSelect
+
+    end menu
+
+menu_item = cluster is
+       create, empty, equal,
+       set_enabled,    get_enabled,
+       set_selectable, get_selectable,
+       set_text,       get_text,
+       set_checked,    get_checked,
+       get_width,      get_height,
+       set_start,      get_start,
+       setup,          reset,
+       display,
+       invert,
+       match
+
+
+    mw = oneof[one: x_window, none: null]
+    mf = oneof[one: x_font, none: null]
+
+    rep = record[
+             Checked:    bool,
+             Enabled:    bool,
+             Font:       mf,
+             MB:         menu_bar,
+             Chk_Width:  int,
+             Left_Fill:  int,
+             Height:     int,
+             Selectable: bool,
+             Start:      int,
+             Text:       string,
+             Width:      int,
+             Window:     mw
+                ]
+
+    vCheck_String = "* "
+
+    Create = proc (MB: menu_bar, Text: string, Font: x_font) returns (cvt) 
+              signals (error(string))
+       Avg_Width: int,
+       Height: int,
+       Ch1: char,
+       ChLast: char,
+       BaseLine: int,
+       FixedWidth: bool := x_font$Query(Font)
+          resignal Error
+       Width: int := x_font$Width(Font, Text) + 
+                     x_font$Width(Font, vCheck_String) +
+                     (vLeft_Space + vRight_Space) * Avg_Width
+       return (rep${ Checked:    false,
+                     Enabled:    true,
+                     Font:       mf$Make_One(Font),
+                     MB:         MB,
+                     Chk_Width:   x_font$Width(Font, vCheck_String),
+                     Left_Fill:  (vLeft_Space * Avg_Width),
+                     Height:     Height + vTop_Space + vBottom_Space,
+                     Selectable: true,
+                     Start:      0,
+                     Text:       Text,
+                     Width:      Width,
+                     Window:     mw$Make_None(nil) })
+       end Create
+
+    Empty = proc (MB: menu_bar) returns (cvt)
+       vEmpty_Height = 10
+       return (rep${ Checked:    false,
+                     Enabled:    false,
+                     Font:       mf$Make_None(nil),
+                     MB:         MB,
+                     Chk_Width:  0,
+                     Left_Fill:  0,
+                     Height:     vEmpty_Height,
+                     Selectable: false,
+                     Start:      0,
+                     Text:       "",
+                     Width:      0,
+                     Window:     mw$Make_None(nil) })
+       end Empty
+
+    Equal = proc (MI1: cvt, MI2: cvt) returns (bool)
+       return (MI1 = MI2)
+       end Equal
+
+    Set_Enabled = proc (MI: cvt, E: bool)
+       MI.Enabled := E
+       end Set_Enabled
+
+    Get_Enabled = proc (MI: cvt) returns (bool)
+       return (MI.Enabled)
+       end Get_Enabled
+
+    Set_Checked = proc (MI: cvt, C: bool)
+       MI.Checked := C
+       end Set_Checked
+
+    Get_Checked = proc (MI: cvt) returns (bool)
+       return (MI.Checked)
+       end Get_Checked
+
+    Set_Selectable = proc (MI: cvt, S: bool)
+       MI.Selectable := S
+       end Set_Selectable
+
+    Get_Selectable = proc (MI: cvt) returns (bool)
+       return (MI.Selectable)
+       end Get_Selectable
+
+    Set_Text = proc (MI: cvt, Text: string) signals (is_empty)
+       Font: x_font := mf$Value_One(MI.Font)
+          except when Wrong_Tag:
+                      signal Is_Empty
+                 end
+       MI.Text := Text
+       Avg_Width: int,
+       Height: int,
+       Ch1: char,
+       ChLast: char,
+       BaseLine: int,
+       FixedWidth: bool := x_font$Query(Font)
+       MI.Width := x_font$Width(Font, Text) + 
+                   x_font$Width(Font, vCheck_String) +
+                   (vLeft_Space + vRight_Space) * Avg_Width
+       end Set_Text
+
+    Get_Text = proc (MI: cvt) returns (string)
+       return (MI.Text)
+       end Get_Text
+
+    Get_Width = proc (MI: cvt) returns (int)
+       return (MI.Width)
+       end Get_Width
+
+    Get_Height = proc (MI: cvt) returns (int)
+       return (MI.Height)
+       end Get_Height
+
+    Get_Start = proc (MI: cvt) returns (int)
+       return (MI.Start)
+       end Get_Start
+
+    Set_Start = proc (MI: cvt, Start: int)
+       MI.Start := Start
+       end Set_Start
+
+    Setup = proc (MI: cvt, Menu_W: x_window, Left_Start: int, Full_Width: int)
+       W: x_window := mw$Value_One(MI.Window)
+          except when Wrong_Tag:
+                      W := x_window$Create(
+                               Left_Start, MI.Start,
+                               Full_Width, MI.Height,
+                               MI.MB.Back,
+                               Menu_W,
+                               0,
+                               MI.MB.Fore)
+                      W.Input := buttonReleased + 
+                                 enterWindow +
+                                 leaveWindow
+                      W.Cursor := MI.MB.Cursor
+                      x_window$Map(W)
+                      MI.Window := mw$Make_One(W)
+                      return
+                 end
+       x_window$Change(W, Full_Width, MI.Height)
+       x_window$Move(W, Left_Start, MI.Start)
+       end Setup
+
+    Display = proc (MI: cvt, Full_Width: int)
+       W: x_window := mw$Value_One(MI.Window)
+       if (MI.Selectable)
+          then if (MI.Checked)
+                  then x_window$Text(W,
+                                     vCheck_String, mf$Value_One(MI.Font),
+                                     MI.MB.ForePix, MI.MB.BackPix,
+                                     MI.Left_Fill, vTop_Space)
+                  end
+               x_window$Text(W,
+                             MI.Text, mf$Value_One(MI.Font),
+                             MI.MB.ForePix, MI.MB.BackPix,
+                             (MI.Left_Fill + MI.Chk_Width), vTop_Space)
+               if (~ MI.Enabled)
+                  then % x_window$Tile_Set(W, x_display$Gray(),
+                       %                 0, vTop_Space,
+                       %                 Full_Width,
+                       %                 MI.Height)
+                  end
+          end
+          except when Wrong_Tag:  %% No Font.
+                 end
+       end Display
+
+    Reset = proc (MI: cvt)
+       x_window$Destroy(mw$Value_One(MI.Window))
+          except when Wrong_Tag:
+                      return
+                 end
+       MI.Window := mw$Make_None(nil)
+       end Reset
+    Invert = proc (MI: cvt, Full_Width: int)
+       x_window$Pix_Fill(mw$Value_One(MI.Window), 0, x_bitmap$None(), 0, 0,
+                         Full_Width, MI.Height, GXinvert, MI.MB.Plane)
+          except when Wrong_Tag:
+                 end
+       end Invert
+
+    Match = proc (MI: cvt, W: x_window) returns (bool)
+       return (mw$Value_One(MI.Window) = W)
+          except when Wrong_Tag:
+                      return (false)
+                 end
+       end Match
+
+    end menu_item
\ No newline at end of file