Subversion Repositories Kolibri OS

Rev

Rev 9731 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. (*
  2.     Copyright 2021-2023 Anton Krotov
  3.  
  4.     This file is part of CEdit.
  5.  
  6.     CEdit is free software: you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation, either version 3 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     CEdit is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with CEdit. If not, see <http://www.gnu.org/licenses/>.
  18. *)
  19.  
  20. MODULE Menu;
  21.  
  22. IMPORT
  23.     SYSTEM, G := Graph, List, K := KolibriOS, U := Utils;
  24.  
  25. CONST
  26.     itemHeight = 22;
  27.     fontWidth = 8;
  28.  
  29.     MainMenuHeight* = K.fontHeight + 7;
  30.         MainMenuX* = 3;
  31.  
  32.     RIGHT = 16;
  33.     LEFT = 16;
  34.     TOP = 1;
  35.  
  36.     maxLEVEL = 1;
  37.  
  38.     backColor = 0F0F0F0H;
  39.     foreColor = 0;
  40.     selBackColor = 091C9F7H;
  41.     selForeColor = 0;
  42.     disBackColor = backColor;
  43.     disForeColor = 808080H;
  44.     disSelBackColor = 0E4E4E4H;
  45.     disSelForeColor = disForeColor;
  46.  
  47.         SHIFT* = 256;
  48.         CTRL*  = 512;
  49.  
  50.  
  51. TYPE
  52.  
  53.         tMainItem* = POINTER TO descMainItem;
  54.  
  55.     tMain* = POINTER TO RECORD (List.tList)
  56.         id: INTEGER;
  57.         canvas: G.tCanvas
  58.     END;
  59.  
  60.     tMenu* = POINTER TO RECORD
  61.         tid*: INTEGER;
  62.         active*, keyboard: BOOLEAN;
  63.         parent*, child: tMenu;
  64.         mainTID: INTEGER;
  65.         mainID: INTEGER;
  66.         x*, winX, winY, width*, height*: INTEGER;
  67.         selItem, cliItem: INTEGER;
  68.  
  69.         font: G.tFont;
  70.         canvas: G.tCanvas;
  71.  
  72.         items: List.tList
  73.     END;
  74.  
  75.     tItem* = POINTER TO RECORD (List.tItem)
  76.         id*, check: INTEGER;
  77.         text: ARRAY 32 OF WCHAR;
  78.         enabled, delim: BOOLEAN;
  79.         child: tMenu
  80.     END;
  81.  
  82.     descMainItem = RECORD (List.tItem)
  83.         id*, x: INTEGER;
  84.         text: ARRAY 32 OF WCHAR;
  85.         menu*: tMenu;
  86.         main: tMain;
  87.         selected: BOOLEAN
  88.     END;
  89.  
  90.     tShortcut = POINTER TO RECORD (List.tItem)
  91.         key, MenuItem: INTEGER
  92.     END;
  93.  
  94.     tProc = PROCEDURE;
  95.  
  96. VAR
  97.         MenuItem*: INTEGER;
  98.     stack: ARRAY maxLEVEL + 1, 2500 OF INTEGER;
  99.     TIDs: ARRAY maxLEVEL + 1 OF INTEGER;
  100.     resetTimer: tProc;
  101.     _open: PROCEDURE (m: tMenu; x, y: INTEGER);
  102.     shortcuts: List.tList;
  103. (*
  104.     backColor, foreColor, selBackColor, selForeColor,
  105.     disBackColor, disForeColor, disSelBackColor, disSelForeColor: INTEGER;
  106. *)
  107.  
  108. PROCEDURE AddMainItem* (main: tMain; text: ARRAY OF WCHAR; menu: tMenu);
  109. VAR
  110.         item, prev: tMainItem;
  111. BEGIN
  112.         NEW(item);
  113.         item.id := main.id + main.count;
  114.         COPY(text, item.text);
  115.         item.menu := menu;
  116.         item.main := main;
  117.         item.selected := FALSE;
  118.         menu.mainID := item.id;
  119.         List.append(main, item);
  120.         prev := item.prev(tMainItem);
  121.         IF prev # NIL THEN
  122.                 item.x := prev.x + LENGTH(prev.text)*fontWidth + 9
  123.         ELSE
  124.                 item.x := MainMenuX
  125.         END;
  126.         menu.x := item.x;
  127.         G.destroy(main.canvas);
  128.         main.canvas := G.CreateCanvas(item.x + LENGTH(item.text)*fontWidth + 9, MainMenuHeight);
  129.         G.SetFont(main.canvas, G.fonts[1])
  130. END AddMainItem;
  131.  
  132.  
  133. PROCEDURE CreateMain* (id: INTEGER): tMain;
  134. VAR
  135.         res: tMain;
  136.         list: List.tList;
  137. BEGIN
  138.         NEW(res);
  139.         res.id := id;
  140.         res.canvas := NIL;
  141.         list := List.create(res)
  142.         RETURN res
  143. END CreateMain;
  144.  
  145.  
  146. PROCEDURE drawMainItem (item: tMainItem);
  147. VAR
  148.         menuColor, textColor, n: INTEGER;
  149.         canvas: G.tCanvas;
  150. BEGIN
  151.         IF item.selected OR (item.menu.tid # 0) THEN
  152.                 menuColor := K.colors.button;
  153.                 textColor := K.colors.button_text
  154.         ELSE
  155.                 menuColor := K.colors.work;
  156.                 textColor := K.colors.work_text
  157.         END;
  158.         n := LENGTH(item.text);
  159.         canvas := item.main.canvas;
  160.         G.SetColor(canvas, menuColor);
  161.         G.FillRect(canvas, item.x, 0, item.x + n*fontWidth + 2, MainMenuHeight - 1);
  162.         G.SetTextColor(canvas, textColor);
  163.         G.SetBkColor(canvas, menuColor);
  164.         G.TextOut2(canvas, item.x + 1, (MainMenuHeight - K.fontHeight) DIV 2 + 1, item.text, n);
  165. END drawMainItem;
  166.  
  167.  
  168. PROCEDURE DrawMain* (main: tMain);
  169. VAR
  170.         item: tMainItem;
  171. BEGIN
  172.         G.SetColor(main.canvas, K.colors.work);
  173.         G.clear(main.canvas);
  174.         item := main.first(tMainItem);
  175.         WHILE item # NIL DO
  176.                 drawMainItem(item);
  177.                 K.CreateButton(item.id + ORD({30}), item.x, 0, LENGTH(item.text)*fontWidth + 2, MainMenuHeight, 0, "");
  178.                 item := item.next(tMainItem)
  179.         END;
  180.         G.DrawCanvas(main.canvas, 0, 0)
  181. END DrawMain;
  182.  
  183.  
  184. PROCEDURE MouseMove* (main: tMain; x, y: INTEGER);
  185. VAR
  186.         item: tMainItem;
  187. BEGIN
  188.         item := main.first(tMainItem);
  189.         WHILE item # NIL DO
  190.                 item.selected :=
  191.                         U.between(item.x, x, item.x + LENGTH(item.text)*fontWidth + 1) &
  192.                                 U.between(0, y, MainMenuHeight - 1);
  193.                 drawMainItem(item);
  194.                 item := item.next(tMainItem)
  195.         END;
  196.         G.DrawCanvas(main.canvas, 0, 0)
  197. END MouseMove;
  198.  
  199.  
  200. PROCEDURE getMainID (m: tMenu): INTEGER;
  201. BEGIN
  202.         WHILE m.parent # NIL DO
  203.                 m := m.parent
  204.         END
  205.         RETURN m.mainID
  206. END getMainID;
  207.  
  208.  
  209. PROCEDURE ClickMain* (main: tMain; btn: INTEGER): tMenu;
  210. VAR
  211.         item: List.tItem;
  212.         res: tMenu;
  213. BEGIN
  214.         item := List.getItem(main, btn - main.id);
  215.         IF item # NIL THEN
  216.                 res := item(tMainItem).menu
  217.         ELSE
  218.                 res := NIL
  219.         END
  220.         RETURN res
  221. END ClickMain;
  222.  
  223.  
  224. PROCEDURE isSender* (tid: INTEGER): BOOLEAN;
  225. VAR
  226.         i: INTEGER;
  227. BEGIN
  228.         i := 0;
  229.         WHILE (i <= maxLEVEL) & (TIDs[i] # tid) DO
  230.                 INC(i)
  231.         END
  232.         RETURN i <= maxLEVEL
  233. END isSender;
  234.  
  235.  
  236. PROCEDURE exit (m: tMenu);
  237. BEGIN
  238.     m.active := FALSE;
  239.         resetTimer;
  240.     m.tid := 0;
  241.     G.destroy(m.canvas);
  242.     K.Exit
  243. END exit;
  244.  
  245.  
  246. PROCEDURE escape (m: tMenu);
  247. BEGIN
  248.     m.active := FALSE;
  249.     IF m.parent = NIL THEN
  250.         resetTimer
  251.     END;
  252.     m.tid := 0;
  253.     G.destroy(m.canvas);
  254.     K.Exit
  255. END escape;
  256.  
  257.  
  258. PROCEDURE repaint (m: tMenu);
  259. VAR
  260.     y, i, X, Y, Y1: INTEGER;
  261.     item: tItem;
  262.     BkColor, TextColor: INTEGER;
  263.     canvas: G.tCanvas;
  264.  
  265. BEGIN
  266. (*
  267.     backColor := K.winColor;
  268.     foreColor := K.textColor;
  269.     selBackColor := K.btnColor;
  270.     selForeColor := K.btnTextColor;
  271.  
  272.     disBackColor := backColor;
  273.     disForeColor := K.darkColor;
  274.     disSelBackColor := K.lightColor;
  275.     disSelForeColor := disForeColor;
  276. *)
  277.     canvas := m.canvas;
  278.     G.SetColor(canvas, backColor);
  279.     G.clear(canvas);
  280.     G.SetColor(canvas, foreColor);
  281.     G.Rect(canvas, 0, 0, m.width, m.height);
  282.     y := TOP;
  283.     i := 0;
  284.     item := m.items.first(tItem);
  285.     WHILE item # NIL DO
  286.         IF item.enabled THEN
  287.             IF i # m.selItem THEN
  288.                 BkColor := backColor;
  289.                 TextColor := foreColor
  290.             ELSE
  291.                 BkColor := selBackColor;
  292.                 TextColor := selForeColor
  293.             END
  294.         ELSE
  295.             IF i # m.selItem THEN
  296.                 BkColor := disBackColor;
  297.                 TextColor := disForeColor
  298.             ELSE
  299.                 BkColor := disSelBackColor;
  300.                 TextColor := disSelForeColor
  301.             END
  302.         END;
  303.         Y := y + (itemHeight - 16) DIV 2;
  304.         G.SetColor(canvas, BkColor);
  305.         G.FillRect(canvas, 1, y, m.width - 1, y + itemHeight - 4);
  306.         G.SetTextColor(canvas, TextColor);
  307.         G.SetBkColor(canvas, BkColor);
  308.         G.TextOut2(canvas, LEFT, Y - 2, item.text, LENGTH(item.text));
  309.  
  310.         G.SetColor(canvas, TextColor);
  311.         IF item.check = 1 THEN
  312.             G.DLine(canvas, 4,  7, Y + 5, -1);
  313.             G.DLine(canvas, 4,  7, Y + 6, -1);
  314.             G.DLine(canvas, 7, 12, Y + 8,  1);
  315.             G.DLine(canvas, 7, 12, Y + 9,  1)
  316.         ELSIF item.check = 2 THEN
  317.             Y1 := y + itemHeight DIV 2 - 2;
  318.             G.FillRect(canvas, 7, Y1 - 2,  9, Y1 + 2);
  319.             G.FillRect(canvas, 6, Y1 - 1, 10, Y1 + 1)
  320.         END;
  321.  
  322.         IF item.child # NIL THEN
  323.             X := m.width - 9;
  324.                 G.Triangle(canvas, X, Y + 2, X, Y + 10, G.triRight)
  325.         END;
  326.  
  327.         INC(y, itemHeight);
  328.         IF item.delim THEN
  329.             G.SetColor(canvas, foreColor);
  330.             G.HLine(canvas, y - 2, 1, m.width - 1)
  331.         END;
  332.         INC(i);
  333.         item := item.next(tItem)
  334.     END;
  335.     G.DrawCanvas(canvas, 0, 0)
  336. END repaint;
  337.  
  338.  
  339. PROCEDURE draw_window (m: tMenu);
  340. BEGIN
  341.     K.BeginDraw;
  342.     K.CreateWindow(m.winX, m.winY, m.width, m.height, 0, 61H, 0, 1, "");
  343.     repaint(m);
  344.     K.EndDraw
  345. END draw_window;
  346.  
  347.  
  348. PROCEDURE close* (m: tMenu);
  349. VAR
  350.         temp: INTEGER;
  351. BEGIN
  352.     IF (m # NIL) & (m.tid # 0) THEN
  353.         IF m.child # NIL THEN
  354.                 close(m.child);
  355.                 m.child := NIL
  356.         END;
  357.         temp := m.tid;
  358.         m.tid := 0;
  359.         G.destroy(m.canvas);
  360.         K.ExitID(temp);
  361.         m.active := FALSE
  362.     END
  363. END close;
  364.  
  365.  
  366. PROCEDURE SetItem* (id: INTEGER);
  367. BEGIN
  368.         MenuItem := id
  369. END SetItem;
  370.  
  371.  
  372. PROCEDURE click (m: tMenu; i: INTEGER);
  373. VAR
  374.     item: List.tItem;
  375.     p: tMenu;
  376.     id: INTEGER;
  377. BEGIN
  378.         id := -1;
  379.         IF i < 0 THEN
  380.                 id := i
  381.         ELSE
  382.             item := List.getItem(m.items, i);
  383.             IF (item # NIL) & item(tItem).enabled & (item(tItem).child = NIL) THEN
  384.                 id := item(tItem).id
  385.             END
  386.     END;
  387.     IF id # -1 THEN
  388.         SetItem(id);
  389.             p := m.parent;
  390.                 WHILE p # NIL DO
  391.                         p.child := NIL;
  392.                         close(p);
  393.                         p := p.parent
  394.                 END;
  395.                 exit(m)
  396.         END
  397. END click;
  398.  
  399.  
  400. PROCEDURE opened* (m: tMenu): BOOLEAN;
  401.     RETURN m.tid # 0
  402. END opened;
  403.  
  404.  
  405. PROCEDURE isActive (m: tMenu): BOOLEAN;
  406.         RETURN (m # NIL) & ((m.tid # 0) & m.active OR isActive(m.child))
  407. END isActive;
  408.  
  409.  
  410. PROCEDURE closeChild (m: tMenu);
  411. BEGIN
  412.         IF m.child # NIL THEN
  413.                 close(m.child);
  414.                 m.child := NIL
  415.         END
  416. END closeChild;
  417.  
  418.  
  419. PROCEDURE submenu (m: tMenu; keyboard: BOOLEAN): BOOLEAN;
  420. VAR
  421.         item: List.tItem;
  422.         res: BOOLEAN;
  423. BEGIN
  424.         res := FALSE;
  425.     item := List.getItem(m.items, m.selItem);
  426.     IF (item # NIL) & item(tItem).enabled & (item(tItem).child # NIL) THEN
  427.         res := TRUE;
  428.         IF ~opened(item(tItem).child) THEN
  429.                 closeChild(m);
  430.                 item(tItem).child.keyboard := keyboard;
  431.                 _open(item(tItem).child, m.winX + m.width - 2, m.winY + m.selItem*itemHeight);
  432.                 m.child := item(tItem).child;
  433.         END
  434.     ELSE
  435.         closeChild(m)
  436.     END
  437.     RETURN res
  438. END submenu;
  439.  
  440.  
  441. PROCEDURE getShortcut (key: INTEGER): BOOLEAN;
  442. VAR
  443.         item: tShortcut;
  444.         res: INTEGER;
  445. BEGIN
  446.         item := shortcuts.first(tShortcut);
  447.         WHILE (item # NIL) & (item.key # key) DO
  448.                 item := item.next(tShortcut)
  449.         END;
  450.         IF item # NIL THEN
  451.                 res := item.MenuItem
  452.         ELSE
  453.                 res := 0
  454.         END;
  455.         SetItem(res)
  456.         RETURN res # 0
  457. END getShortcut;
  458.  
  459.  
  460. PROCEDURE [stdcall] window (m: tMenu);
  461. VAR
  462.     x, y: INTEGER;
  463.     msState: SET;
  464.     key, temp: INTEGER;
  465.     shift, ctrl: BOOLEAN;
  466. BEGIN
  467.     m.selItem := ORD(m.keyboard) - 1;
  468.     m.cliItem := -1;
  469.     m.keyboard := FALSE;
  470.     K.SetEventsMask({0, 1, 5});
  471.     WHILE TRUE DO
  472.         CASE K.EventTimeout(100) OF
  473.         |0:
  474.         |1:
  475.             draw_window(m)
  476.         |2:
  477.                 K.getKBState(shift, ctrl);
  478.             key := K.GetKey() DIV 65536;
  479.                     IF shift THEN
  480.                         INC(key, SHIFT)
  481.                     END;
  482.                     IF ctrl THEN
  483.                         INC(key, CTRL)
  484.                     END;
  485.  
  486.                 CASE key OF
  487.             |72:
  488.                 m.selItem := (m.selItem - 1) MOD m.items.count
  489.             |80:
  490.                 m.selItem := (m.selItem + 1) MOD m.items.count
  491.             |28:
  492.                 IF m.selItem >= 0 THEN
  493.                     click(m, m.selItem)
  494.                 END;
  495.                 m.cliItem := -1
  496.             |77:
  497.                 IF ~submenu(m, TRUE) THEN
  498.                         click(m, -(getMainID(m) + 1))
  499.                 END;
  500.                 m.cliItem := -1
  501.             |75:
  502.                 IF m.parent # NIL THEN
  503.                         escape(m)
  504.                 ELSE
  505.                         click(m, -(getMainID(m) - 1))
  506.                 END;
  507.                 m.cliItem := -1
  508.             |1:
  509.                 escape(m)
  510.             ELSE
  511.                     IF getShortcut(key) THEN
  512.                         IF m.parent # NIL THEN
  513.                                 temp := m.parent.tid;
  514.                                 m.parent.tid := 0;
  515.                                 G.destroy(m.parent.canvas);
  516.                                 K.ExitID(temp)
  517.                         END;
  518.                         exit(m)
  519.                     END
  520.             END;
  521.             repaint(m)
  522.         |6:
  523.                 K.mouse(msState, x, y);
  524.                 temp := (x + m.winX)*65536 + (y + m.winY);
  525.                 K.SendIPC(m.mainTID, SYSTEM.ADR(temp), SYSTEM.SIZE(INTEGER));
  526.             IF (0 <= x) & (x < m.width) & (0 <= y) & (y < m.height) THEN
  527.                 m.active := TRUE;
  528.                 m.selItem := (y - TOP) DIV itemHeight;
  529.                 IF 8 IN msState THEN
  530.                     m.cliItem := (y - TOP) DIV itemHeight
  531.                 END;
  532.                 IF 16 IN msState THEN
  533.                     IF m.cliItem = m.selItem THEN
  534.                         click(m, m.cliItem)
  535.                     END;
  536.                     m.cliItem := -1
  537.                 END
  538.             ELSE
  539.                 m.active := FALSE;
  540.                 m.cliItem := -1;
  541.                 IF ({8, 9, 10, 16} * msState # {}) & ~isActive(m.child) THEN
  542.                     exit(m)
  543.                 END
  544.             END;
  545.             repaint(m);
  546.             IF submenu(m, FALSE) THEN END
  547.         END
  548.     END
  549. END window;
  550.  
  551.  
  552. PROCEDURE level (m: tMenu): INTEGER;
  553. VAR
  554.         res: INTEGER;
  555. BEGIN
  556.         res := 0;
  557.         WHILE m.parent # NIL DO
  558.                 INC(res);
  559.                 m := m.parent
  560.         END
  561.         RETURN res
  562. END level;
  563.  
  564.  
  565. PROCEDURE open* (m: tMenu; x, y: INTEGER);
  566. VAR
  567.         L: INTEGER;
  568. BEGIN
  569.     IF m.tid = 0 THEN
  570.         L := level(m);
  571.         IF K.GetThreadSlot(TIDs[L]) = 0 THEN
  572.                 m.winX := x;
  573.                 m.winY := y;
  574.                 IF m.canvas = NIL THEN
  575.                         m.canvas := G.CreateCanvas(m.width + 1, m.height + 1);
  576.                             G.SetFont(m.canvas, m.font)
  577.                 END;
  578.                 SYSTEM.PUT(SYSTEM.ADR(stack[L][LEN(stack[0]) - 1]), m);
  579.             m.tid := K.CreateThread(SYSTEM.ADR(window), stack[L]);
  580.                 TIDs[L] := m.tid
  581.         END
  582.     END
  583. END open;
  584.  
  585.  
  586. PROCEDURE AddMenuItem* (items: List.tList; id: INTEGER; s: ARRAY OF WCHAR);
  587. VAR
  588.     item: tItem;
  589. BEGIN
  590.     NEW(item);
  591.     item.id := id;
  592.     item.text := s;
  593.     item.enabled := TRUE;
  594.     item.delim := FALSE;
  595.     item.child := NIL;
  596.     List.append(items, item);
  597. END AddMenuItem;
  598.  
  599.  
  600. PROCEDURE delimiter* (items: List.tList);
  601. BEGIN
  602.     items.last(tItem).delim := TRUE
  603. END delimiter;
  604.  
  605.  
  606. PROCEDURE child* (items: List.tList; menu: tMenu);
  607. BEGIN
  608.     items.last(tItem).child := menu
  609. END child;
  610.  
  611.  
  612. PROCEDURE getItem (m: tMenu; id: INTEGER): tItem;
  613. VAR
  614.     item: tItem;
  615. BEGIN
  616.     item := m.items.first(tItem);
  617.     WHILE (item # NIL) & (item.id # id) DO
  618.         item := item.next(tItem)
  619.     END
  620.     RETURN item
  621. END getItem;
  622.  
  623.  
  624. PROCEDURE setEnabled* (m: tMenu; id: INTEGER; value: BOOLEAN);
  625. VAR
  626.     item: tItem;
  627. BEGIN
  628.     item := getItem(m, id);
  629.     IF item # NIL THEN
  630.         item.enabled := value
  631.     END
  632. END setEnabled;
  633.  
  634.  
  635. PROCEDURE check* (m: tMenu; id: INTEGER; value: BOOLEAN);
  636. VAR
  637.     item: tItem;
  638. BEGIN
  639.     item := getItem(m, id);
  640.     IF item # NIL THEN
  641.         item.check := ORD(value)
  642.     END
  643. END check;
  644.  
  645.  
  646. PROCEDURE option* (m: tMenu; id: INTEGER; value: BOOLEAN);
  647. VAR
  648.     item: tItem;
  649. BEGIN
  650.     item := getItem(m, id);
  651.     IF item # NIL THEN
  652.         item.check := ORD(value)*2
  653.     END
  654. END option;
  655.  
  656.  
  657. PROCEDURE isEnabled* (m: tMenu; id: INTEGER): BOOLEAN;
  658. VAR
  659.     item: tItem;
  660. BEGIN
  661.     item := getItem(m, id)
  662.     RETURN (item # NIL) & item.enabled
  663. END isEnabled;
  664.  
  665.  
  666. PROCEDURE create* (items: List.tList; mainTID: INTEGER): tMenu;
  667. VAR
  668.     m: tMenu;
  669.     maxLength: INTEGER;
  670.     item: tItem;
  671. BEGIN
  672.     NEW(m);
  673.     m.tid := 0;
  674.     m.active := FALSE;
  675.     m.parent := NIL;
  676.     m.child := NIL;
  677.     m.mainID := 0;
  678.     m.mainTID := mainTID;
  679.     m.items  := items;
  680.     maxLength := 0;
  681.     item := items.first(tItem);
  682.     WHILE item # NIL DO
  683.         maxLength := MAX(maxLength, LENGTH(item.text));
  684.         item := item.next(tItem)
  685.     END;
  686.     m.width  := maxLength*fontWidth + LEFT + RIGHT;
  687.     m.height := items.count*itemHeight - 2;
  688.     m.font := G.fonts[1];
  689. (*    m.canvas := G.CreateCanvas(m.width + 1, m.height + 1);
  690.     G.SetFont(m.canvas, m.font)*)
  691.     RETURN m
  692. END create;
  693.  
  694.  
  695. PROCEDURE AddShortcut* (key, MenuItem: INTEGER);
  696. VAR
  697.         item: tShortcut;
  698. BEGIN
  699.         NEW(item);
  700.         item.key := key;
  701.         item.MenuItem := MenuItem;
  702.         List.append(shortcuts, item)
  703. END AddShortcut;
  704.  
  705.  
  706. PROCEDURE init* (_resetTimer: tProc);
  707. VAR
  708.         i: INTEGER;
  709. BEGIN
  710.         SetItem(0);
  711.         shortcuts := List.create(NIL);
  712.         resetTimer := _resetTimer;
  713.         _open := open;
  714.         FOR i := 0 TO maxLEVEL DO
  715.                 TIDs[i] := 0
  716.         END
  717. END init;
  718.  
  719.  
  720. END Menu.