Subversion Repositories Kolibri OS

Rev

Rev 8762 | Rev 9175 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
8728 leency 1
(*
2
    Copyright 2021 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 .
18
*)
19
 
20
MODULE Menu;
21
 
22
IMPORT
23
    SYSTEM, G := Graph, List, K := KolibriOS;
24
 
25
CONST
9174 akron1 26
    fontHeight = 22;
8728 leency 27
    fontWidth = 8;
28
 
29
    RIGHT = 16;
30
    LEFT = 16;
31
    TOP = 1;
32
 
9174 akron1 33
    maxLEVEL = 1;
34
 
8728 leency 35
    backColor = 0F0F0F0H;
36
    foreColor = 0;
37
    selBackColor = 091C9F7H;
38
    selForeColor = 0;
39
    disBackColor = backColor;
40
    disForeColor = 808080H;
41
    disSelBackColor = 0E4E4E4H;
42
    disSelForeColor = disForeColor;
43
 
44
 
45
TYPE
46
 
47
    tMenu* = POINTER TO RECORD
48
        tid*: INTEGER;
9174 akron1 49
        active*: BOOLEAN;
50
        parent*, child: tMenu;
8728 leency 51
        winX, winY, width*, height*: INTEGER;
52
        selItem, cliItem: INTEGER;
53
 
54
        font: G.tFont;
55
        canvas: G.tCanvas;
56
 
57
        items: List.tList;
58
        click: PROCEDURE (menu: tMenu; id: INTEGER);
59
        key: PROCEDURE (menu: tMenu; key: INTEGER): BOOLEAN
60
    END;
61
 
9174 akron1 62
    tItem* = POINTER TO RECORD (List.tItem)
63
        id*, check: INTEGER;
64
        text: ARRAY 32 OF WCHAR;
65
        enabled, delim: BOOLEAN;
66
        child: tMenu
67
    END;
68
 
8728 leency 69
    tClick = PROCEDURE (menu: tMenu; id: INTEGER);
70
    tKey = PROCEDURE (menu: tMenu; key: INTEGER): BOOLEAN;
9174 akron1 71
    tProc = PROCEDURE;
8728 leency 72
 
73
VAR
9174 akron1 74
    stack: ARRAY maxLEVEL + 1, 250000 OF INTEGER;
75
    TIDs: ARRAY maxLEVEL + 1 OF INTEGER;
76
    resetTimer: tProc;
77
    _open: PROCEDURE (m: tMenu; x, y: INTEGER);
78
    redraw*: BOOLEAN;
8728 leency 79
 
80
 
9174 akron1 81
PROCEDURE isSender* (tid: INTEGER): BOOLEAN;
82
VAR
83
	i: INTEGER;
84
BEGIN
85
	i := 0;
86
	WHILE (i <= maxLEVEL) & (TIDs[i] # tid) DO
87
		INC(i)
88
	END
89
	RETURN i <= maxLEVEL
90
END isSender;
91
 
92
 
8728 leency 93
PROCEDURE exit (m: tMenu);
94
BEGIN
95
    m.tid := 0;
9174 akron1 96
    m.active := FALSE;
97
    resetTimer;
8728 leency 98
    K.Exit
99
END exit;
100
 
101
 
102
PROCEDURE repaint (m: tMenu);
103
VAR
9174 akron1 104
    y, i, X, Y1, Y2: INTEGER;
8728 leency 105
    item: tItem;
106
    BkColor, TextColor: INTEGER;
107
    canvas: G.tCanvas;
108
 
109
BEGIN
110
    canvas := m.canvas;
111
    G.SetColor(canvas, backColor);
112
    G.clear(canvas);
113
    G.SetColor(canvas, ORD((-BITS(backColor))*{0..23}) );
114
    G.Rect(canvas, 0, 0, m.width, m.height);
115
    y := TOP;
116
    i := 0;
117
    item := m.items.first(tItem);
118
    WHILE item # NIL DO
119
        IF item.enabled THEN
120
            IF i # m.selItem THEN
121
                BkColor := backColor;
122
                TextColor := foreColor
123
            ELSE
124
                BkColor := selBackColor;
125
                TextColor := selForeColor
126
            END
127
        ELSE
128
            IF i # m.selItem THEN
129
                BkColor := disBackColor;
130
                TextColor := disForeColor
131
            ELSE
132
                BkColor := disSelBackColor;
133
                TextColor := disSelForeColor
134
            END
135
        END;
136
        G.SetColor(canvas, BkColor);
137
        G.FillRect(canvas, 1, y, m.width - 1, y + fontHeight - 4);
138
        G.SetTextColor(canvas, TextColor);
139
        G.SetBkColor(canvas, BkColor);
140
        G.TextOut2(canvas, LEFT, y + (fontHeight - 16) DIV 2 - 2, item.text, LENGTH(item.text));
141
 
9174 akron1 142
        G.SetColor(canvas, TextColor);
8728 leency 143
        IF item.check = 1 THEN
144
            G.DLine(canvas, 4, 7, y + (fontHeight - 16) DIV 2 + 5, -1);
145
            G.DLine(canvas, 4, 7, y + (fontHeight - 16) DIV 2 + 6, -1);
146
            G.DLine(canvas, 7, 12, y + (fontHeight - 16) DIV 2 + 8, 1);
147
            G.DLine(canvas, 7, 12, y + (fontHeight - 16) DIV 2 + 9, 1);
148
        ELSIF item.check = 2 THEN
149
            G.FillRect(canvas, 6, y + fontHeight DIV 2 - 4, 10, y + fontHeight DIV 2)
150
        END;
151
 
9174 akron1 152
        IF item.child # NIL THEN
153
            X := m.width - 9;
154
            Y1 := y + (fontHeight - 16) DIV 2 + 2;
155
            Y2 := Y1 + 8;
156
        	G.Triangle(canvas, X, Y1, X, Y2, G.triRight)
157
        END;
158
 
8728 leency 159
        INC(y, fontHeight);
160
        IF item.delim THEN
161
            G.SetColor(canvas, ORD((-BITS(backColor))*{0..23}));
162
            G.HLine(canvas, y - 2, 1, m.width - 1)
163
        END;
164
        INC(i);
165
        item := item.next(tItem)
166
    END;
167
    G.DrawCanvas(canvas, 0, 0)
168
END repaint;
169
 
170
 
171
PROCEDURE draw_window (m: tMenu);
172
BEGIN
173
    K.BeginDraw;
174
    K.CreateWindow(m.winX, m.winY, m.width, m.height, 0, 61H, 0, 1, "");
175
    repaint(m);
176
    K.EndDraw
177
END draw_window;
178
 
179
 
180
PROCEDURE mouse (m: tMenu; VAR x, y: INTEGER);
181
VAR
182
    mouseX, mouseY: INTEGER;
183
BEGIN
184
    K.MousePos(mouseX, mouseY);
185
    x := mouseX - m.winX;
186
    y := mouseY - m.winY;
187
END mouse;
188
 
189
 
9174 akron1 190
PROCEDURE close* (m: tMenu);
191
BEGIN
192
    IF (m # NIL) & (m.tid # 0) THEN
193
    	IF m.child # NIL THEN
194
    		close(m.child);
195
    		m.child := NIL
196
    	END;
197
        K.ExitID(m.tid);
198
        m.tid := 0;
199
        m.active := FALSE
200
    END
201
END close;
202
 
203
 
8728 leency 204
PROCEDURE click (m: tMenu; i: INTEGER);
205
VAR
206
    item: List.tItem;
9174 akron1 207
    p: tMenu;
8728 leency 208
BEGIN
209
    item := List.getItem(m.items, i);
9174 akron1 210
    IF (item # NIL) & item(tItem).enabled & (item(tItem).child = NIL) THEN
8728 leency 211
        m.click(m, item(tItem).id);
9174 akron1 212
        p := m.parent;
213
       	WHILE p # NIL DO
214
       		p.child := NIL;
215
       		close(p);
216
       		p := p.parent
217
       	END;
218
       	redraw := TRUE;
219
       	exit(m)
8728 leency 220
    END
221
END click;
222
 
223
 
9174 akron1 224
PROCEDURE opened* (m: tMenu): BOOLEAN;
225
    RETURN m.tid # 0
226
END opened;
227
 
228
 
229
PROCEDURE isActive (m: tMenu): BOOLEAN;
230
	RETURN (m # NIL) & ((m.tid # 0) & m.active OR isActive(m.child))
231
END isActive;
232
 
233
 
234
PROCEDURE closeChild (m: tMenu);
235
BEGIN
236
	IF m.child # NIL THEN
237
		redraw := FALSE;
238
		close(m.child);
239
		m.child := NIL
240
	END
241
END closeChild;
242
 
243
 
244
PROCEDURE submenu (m: tMenu);
245
VAR
246
	item: List.tItem;
247
BEGIN
248
    item := List.getItem(m.items, m.selItem);
249
    IF (item # NIL) & item(tItem).enabled & (item(tItem).child # NIL) THEN
250
    	IF ~opened(item(tItem).child) THEN
251
    		closeChild(m);
252
    		_open(item(tItem).child, m.winX + m.width - 2, m.winY + m.selItem*fontHeight);
253
    		m.child := item(tItem).child
254
    	END
255
    ELSE
256
    	closeChild(m)
257
    END
258
END submenu;
259
 
260
 
8728 leency 261
PROCEDURE [stdcall] window (m: tMenu);
262
VAR
263
    x, y: INTEGER;
264
    key: INTEGER;
265
    msState: SET;
266
BEGIN
267
    m.selItem := -1;
268
    m.cliItem := -1;
269
    K.SetEventsMask({0, 1, 5});
270
    WHILE TRUE DO
271
        CASE K.WaitForEvent() OF
272
        |1:
273
            draw_window(m)
274
        |2:
275
            key := K.GetKey();
276
            IF key DIV 65536 = 72 THEN
277
                DEC(m.selItem);
278
                IF m.selItem < 0 THEN
279
                    m.selItem := 0
280
                END
281
            ELSIF key DIV 65536 = 80 THEN
282
                INC(m.selItem);
283
                IF m.selItem >= m.items.count THEN
284
                    m.selItem := m.items.count - 1
285
                END
286
            ELSIF key DIV 65536 = 28 THEN
287
                IF m.selItem >= 0 THEN
288
                    click(m, m.selItem)
289
                END;
290
                m.cliItem := -1
9174 akron1 291
            ELSIF key DIV 65536 = 77 THEN
292
                submenu(m)
293
            ELSIF key DIV 65536 = 75 THEN
294
            	IF m.parent # NIL THEN
295
                	exit(m)
296
                END
8728 leency 297
            ELSE
298
                IF m.key(m, key) THEN
299
                    exit(m)
300
                END
301
            END;
302
            repaint(m)
303
        |6:
304
            msState := K.MouseState();
305
            mouse(m, x, y);
306
            IF (0 <= x) & (x < m.width) & (0 <= y) & (y < m.height) THEN
9174 akron1 307
            	m.active := TRUE;
8728 leency 308
                m.selItem := (y - TOP) DIV fontHeight;
309
                IF 8 IN msState THEN
310
                    m.cliItem := (y - TOP) DIV fontHeight
311
                END;
312
                IF 16 IN msState THEN
313
                    IF m.cliItem = m.selItem THEN
314
                        click(m, m.cliItem)
315
                    END;
316
                    m.cliItem := -1
317
                END
318
            ELSE
9174 akron1 319
            	m.active := FALSE;
8728 leency 320
                m.cliItem := -1;
9174 akron1 321
                IF ({8, 9, 10, 16} * msState # {}) & ~isActive(m.child) THEN
8728 leency 322
                    exit(m)
323
                END
324
            END;
9174 akron1 325
            repaint(m);
326
            submenu(m)
8728 leency 327
        END
328
    END
329
END window;
330
 
331
 
9174 akron1 332
PROCEDURE level (m: tMenu): INTEGER;
333
VAR
334
	res: INTEGER;
335
BEGIN
336
	res := 0;
337
	WHILE m.parent # NIL DO
338
		INC(res);
339
		m := m.parent
340
	END
341
	RETURN res
342
END level;
343
 
344
 
345
PROCEDURE open* (m: tMenu; x, y: INTEGER);
346
VAR
347
	L: INTEGER;
348
BEGIN
349
    IF m.tid = 0 THEN
350
        m.winX := x;
351
        m.winY := y;
352
        L := level(m);
353
        SYSTEM.PUT(SYSTEM.ADR(stack[L][LEN(stack[0]) - 1]), m);
354
        m.tid := K.CreateThread(SYSTEM.ADR(window), stack[L]);
355
        TIDs[L] := m.tid
356
    END
357
END open;
358
 
359
 
8728 leency 360
PROCEDURE AddMenuItem* (items: List.tList; id: INTEGER; s: ARRAY OF WCHAR);
361
VAR
362
    item: tItem;
363
BEGIN
364
    NEW(item);
365
    item.id := id;
366
    item.text := s;
367
    item.enabled := TRUE;
368
    item.delim := FALSE;
9174 akron1 369
    item.child := NIL;
8728 leency 370
    List.append(items, item);
371
END AddMenuItem;
372
 
373
 
374
PROCEDURE delimiter* (items: List.tList);
375
BEGIN
376
    items.last(tItem).delim := TRUE
377
END delimiter;
378
 
379
 
9174 akron1 380
PROCEDURE child* (items: List.tList; menu: tMenu);
381
BEGIN
382
    items.last(tItem).child := menu
383
END child;
384
 
385
 
8728 leency 386
PROCEDURE getItem (m: tMenu; id: INTEGER): tItem;
387
VAR
388
    item: tItem;
389
BEGIN
390
    item := m.items.first(tItem);
391
    WHILE (item # NIL) & (item.id # id) DO
392
        item := item.next(tItem)
393
    END
394
    RETURN item
395
END getItem;
396
 
397
 
398
PROCEDURE setEnabled* (m: tMenu; id: INTEGER; value: BOOLEAN);
399
VAR
400
    item: tItem;
401
BEGIN
402
    item := getItem(m, id);
403
    IF item # NIL THEN
404
        item.enabled := value
405
    END
406
END setEnabled;
407
 
408
 
409
PROCEDURE setCheck* (m: tMenu; id: INTEGER; value: INTEGER);
410
VAR
411
    item: tItem;
412
BEGIN
413
    item := getItem(m, id);
414
    IF item # NIL THEN
415
        item.check := value
416
    END
417
END setCheck;
418
 
419
 
420
PROCEDURE isEnabled* (m: tMenu; id: INTEGER): BOOLEAN;
421
VAR
422
    item: tItem;
423
BEGIN
424
    item := getItem(m, id)
425
    RETURN (item # NIL) & item.enabled
426
END isEnabled;
427
 
428
 
429
PROCEDURE create* (items: List.tList; click: tClick; key: tKey): tMenu;
430
VAR
431
    m: tMenu;
432
    maxLength: INTEGER;
433
    item: tItem;
434
BEGIN
435
    NEW(m);
436
    m.tid := 0;
9174 akron1 437
    m.active := FALSE;
438
    m.parent := NIL;
439
    m.child := NIL;
8728 leency 440
    m.items  := items;
441
    m.click := click;
442
    m.key := key;
443
    maxLength := 0;
444
    item := items.first(tItem);
445
    WHILE item # NIL DO
446
        maxLength := MAX(maxLength, LENGTH(item.text));
447
        item := item.next(tItem)
448
    END;
449
    m.width  := maxLength*fontWidth + LEFT + RIGHT;
450
    m.height := items.count*fontHeight - 2;
451
    m.font := G.CreateFont(1, "", {});
452
    m.canvas := G.CreateCanvas(m.width + 1, m.height + 1);
453
    G.SetFont(m.canvas, m.font);
454
    RETURN m
455
END create;
456
 
457
 
9174 akron1 458
PROCEDURE Redraw*;
8728 leency 459
BEGIN
9174 akron1 460
	redraw := TRUE
461
END Redraw;
462
 
463
 
464
PROCEDURE init* (_resetTimer: tProc);
465
VAR
466
	i: INTEGER;
467
BEGIN
468
	Redraw;
469
	resetTimer := _resetTimer;
470
	_open := open;
471
	FOR i := 0 TO maxLEVEL DO
472
		TIDs[i] := 0
473
	END
474
END init;
475
 
476
 
8728 leency 477
END Menu.