Subversion Repositories Kolibri OS

Rev

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