Subversion Repositories Kolibri OS

Rev

Rev 9190 | Rev 9448 | 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
9190 akron1 23
    SYSTEM, G := Graph, List, K := KolibriOS, KOSAPI;
8728 leency 24
 
25
CONST
9174 akron1 26
    fontHeight = 22;
8728 leency 27
    fontWidth = 8;
28
 
9187 akron1 29
    MainMenuHeight* = K.fontHeight + 7;
30
 
8728 leency 31
    RIGHT = 16;
32
    LEFT = 16;
33
    TOP = 1;
34
 
9174 akron1 35
    maxLEVEL = 1;
36
 
8728 leency 37
    backColor = 0F0F0F0H;
38
    foreColor = 0;
39
    selBackColor = 091C9F7H;
40
    selForeColor = 0;
41
    disBackColor = backColor;
42
    disForeColor = 808080H;
43
    disSelBackColor = 0E4E4E4H;
44
    disSelForeColor = disForeColor;
45
 
46
 
47
TYPE
48
 
9187 akron1 49
	tMainItem* = POINTER TO descMainItem;
50
 
51
    tMain* = POINTER TO RECORD (List.tList)
52
    	id: INTEGER
53
    END;
54
 
8728 leency 55
    tMenu* = POINTER TO RECORD
56
        tid*: INTEGER;
9187 akron1 57
        active*, keyboard: BOOLEAN;
9174 akron1 58
        parent*, child: tMenu;
9187 akron1 59
        mainID: INTEGER;
8728 leency 60
        winX, winY, width*, height*: INTEGER;
61
        selItem, cliItem: INTEGER;
62
 
63
        font: G.tFont;
64
        canvas: G.tCanvas;
65
 
66
        items: List.tList;
67
        click: PROCEDURE (menu: tMenu; id: INTEGER);
68
        key: PROCEDURE (menu: tMenu; key: INTEGER): BOOLEAN
69
    END;
70
 
9174 akron1 71
    tItem* = POINTER TO RECORD (List.tItem)
72
        id*, check: INTEGER;
73
        text: ARRAY 32 OF WCHAR;
74
        enabled, delim: BOOLEAN;
75
        child: tMenu
76
    END;
77
 
9187 akron1 78
    descMainItem = RECORD (List.tItem)
79
        id*, x: INTEGER;
80
        text: ARRAY 32 OF WCHAR;
81
        menu*: tMenu;
82
        main: tMain
83
    END;
84
 
8728 leency 85
    tClick = PROCEDURE (menu: tMenu; id: INTEGER);
86
    tKey = PROCEDURE (menu: tMenu; key: INTEGER): BOOLEAN;
9174 akron1 87
    tProc = PROCEDURE;
8728 leency 88
 
89
VAR
9174 akron1 90
    stack: ARRAY maxLEVEL + 1, 250000 OF INTEGER;
91
    TIDs: ARRAY maxLEVEL + 1 OF INTEGER;
92
    resetTimer: tProc;
93
    _open: PROCEDURE (m: tMenu; x, y: INTEGER);
9175 akron1 94
(*
95
    backColor, foreColor, selBackColor, selForeColor,
96
    disBackColor, disForeColor, disSelBackColor, disSelForeColor: INTEGER;
97
*)
8728 leency 98
 
9187 akron1 99
PROCEDURE AddMainItem* (main: tMain; text: ARRAY OF WCHAR; menu: tMenu);
100
VAR
101
	item, prev: tMainItem;
102
BEGIN
103
	NEW(item);
104
	item.id := main.id + main.count;
105
	COPY(text, item.text);
106
	item.menu := menu;
107
	item.main := main;
108
	menu.mainID := item.id;
109
	List.append(main, item);
110
	prev := item.prev(tMainItem);
111
	IF prev # NIL THEN
112
		item.x := prev.x + LENGTH(prev.text)*fontWidth + 9
113
	ELSE
114
		item.x := 0
115
	END
116
END AddMainItem;
117
 
118
 
119
PROCEDURE CreateMain* (id: INTEGER): tMain;
120
VAR
121
	res: tMain;
122
	list: List.tList;
123
BEGIN
124
	NEW(res);
125
	res.id := id;
126
	list := List.create(res)
127
	RETURN res
128
END CreateMain;
129
 
130
 
131
PROCEDURE drawMainItem (item: tMainItem);
132
VAR
133
    menuColor, textColor, n: INTEGER;
134
BEGIN
135
    IF item.menu.tid # 0 THEN
136
        menuColor := K.textColor;
137
        textColor := K.winColor
138
    ELSE
139
        menuColor := K.winColor;
140
        textColor := K.textColor
141
    END;
142
    n := LENGTH(item.text);
143
    K.DrawRect(item.x, 0, n*fontWidth + 2, MainMenuHeight, menuColor);
144
    K.CreateButton(item.id + ORD({30}), item.x, 0, n*fontWidth + 2, MainMenuHeight, K.btnColor, "");
145
    K.DrawText(item.x + 1, (MainMenuHeight - K.fontHeight) DIV 2 + 1, textColor, item.text)
146
END drawMainItem;
147
 
148
 
149
PROCEDURE DrawMain* (main: tMain);
150
VAR
151
	item: List.tItem;
152
BEGIN
153
	item := main.first;
154
	WHILE item # NIL DO
155
		drawMainItem(item(tMainItem));
156
		item := item.next
157
	END
158
END DrawMain;
159
 
160
 
161
PROCEDURE getMainID (m: tMenu): INTEGER;
162
BEGIN
163
	WHILE m.parent # NIL DO
164
		m := m.parent
165
	END
166
	RETURN m.mainID
167
END getMainID;
168
 
169
 
170
PROCEDURE ClickMain* (main: tMain; btn: INTEGER): tMenu;
171
VAR
172
	item: List.tItem;
173
	res: tMenu;
174
BEGIN
175
	item := List.getItem(main, btn - main.id);
176
	IF item # NIL THEN
177
		res := item(tMainItem).menu
178
	ELSE
179
		res := NIL
180
	END
181
	RETURN res
182
END ClickMain;
183
 
184
 
9174 akron1 185
PROCEDURE isSender* (tid: INTEGER): BOOLEAN;
186
VAR
187
	i: INTEGER;
188
BEGIN
189
	i := 0;
190
	WHILE (i <= maxLEVEL) & (TIDs[i] # tid) DO
191
		INC(i)
192
	END
193
	RETURN i <= maxLEVEL
194
END isSender;
195
 
196
 
8728 leency 197
PROCEDURE exit (m: tMenu);
198
BEGIN
9187 akron1 199
    m.active := FALSE;
200
   	resetTimer;
8728 leency 201
    m.tid := 0;
202
    K.Exit
203
END exit;
204
 
205
 
9187 akron1 206
PROCEDURE escape (m: tMenu);
207
BEGIN
208
    m.active := FALSE;
209
    IF m.parent = NIL THEN
210
    	resetTimer
211
    END;
212
    m.tid := 0;
213
    K.Exit
214
END escape;
215
 
216
 
8728 leency 217
PROCEDURE repaint (m: tMenu);
218
VAR
9208 akron1 219
    y, i, X, Y: INTEGER;
8728 leency 220
    item: tItem;
221
    BkColor, TextColor: INTEGER;
222
    canvas: G.tCanvas;
223
 
224
BEGIN
9175 akron1 225
(*
226
    backColor := K.winColor;
227
    foreColor := K.textColor;
228
    selBackColor := K.btnColor;
229
    selForeColor := K.btnTextColor;
230
 
231
    disBackColor := backColor;
232
    disForeColor := K.darkColor;
233
    disSelBackColor := K.lightColor;
234
    disSelForeColor := disForeColor;
235
*)
8728 leency 236
    canvas := m.canvas;
237
    G.SetColor(canvas, backColor);
238
    G.clear(canvas);
9180 akron1 239
    G.SetColor(canvas, foreColor);
8728 leency 240
    G.Rect(canvas, 0, 0, m.width, m.height);
241
    y := TOP;
242
    i := 0;
243
    item := m.items.first(tItem);
244
    WHILE item # NIL DO
245
        IF item.enabled THEN
246
            IF i # m.selItem THEN
247
                BkColor := backColor;
248
                TextColor := foreColor
249
            ELSE
250
                BkColor := selBackColor;
251
                TextColor := selForeColor
252
            END
253
        ELSE
254
            IF i # m.selItem THEN
255
                BkColor := disBackColor;
256
                TextColor := disForeColor
257
            ELSE
258
                BkColor := disSelBackColor;
259
                TextColor := disSelForeColor
260
            END
261
        END;
262
        G.SetColor(canvas, BkColor);
263
        G.FillRect(canvas, 1, y, m.width - 1, y + fontHeight - 4);
264
        G.SetTextColor(canvas, TextColor);
265
        G.SetBkColor(canvas, BkColor);
266
        G.TextOut2(canvas, LEFT, y + (fontHeight - 16) DIV 2 - 2, item.text, LENGTH(item.text));
267
 
9174 akron1 268
        G.SetColor(canvas, TextColor);
8728 leency 269
        IF item.check = 1 THEN
270
            G.DLine(canvas, 4, 7, y + (fontHeight - 16) DIV 2 + 5, -1);
271
            G.DLine(canvas, 4, 7, y + (fontHeight - 16) DIV 2 + 6, -1);
272
            G.DLine(canvas, 7, 12, y + (fontHeight - 16) DIV 2 + 8, 1);
273
            G.DLine(canvas, 7, 12, y + (fontHeight - 16) DIV 2 + 9, 1);
274
        ELSIF item.check = 2 THEN
275
            G.FillRect(canvas, 6, y + fontHeight DIV 2 - 4, 10, y + fontHeight DIV 2)
276
        END;
277
 
9174 akron1 278
        IF item.child # NIL THEN
279
            X := m.width - 9;
9208 akron1 280
            Y := y + (fontHeight - 16) DIV 2 + 2;
281
        	G.Triangle(canvas, X, Y, X, Y + 8, G.triRight)
9174 akron1 282
        END;
283
 
8728 leency 284
        INC(y, fontHeight);
285
        IF item.delim THEN
9180 akron1 286
            G.SetColor(canvas, foreColor);
8728 leency 287
            G.HLine(canvas, y - 2, 1, m.width - 1)
288
        END;
289
        INC(i);
290
        item := item.next(tItem)
291
    END;
292
    G.DrawCanvas(canvas, 0, 0)
293
END repaint;
294
 
295
 
296
PROCEDURE draw_window (m: tMenu);
297
BEGIN
298
    K.BeginDraw;
299
    K.CreateWindow(m.winX, m.winY, m.width, m.height, 0, 61H, 0, 1, "");
300
    repaint(m);
301
    K.EndDraw
302
END draw_window;
303
 
304
 
9174 akron1 305
PROCEDURE close* (m: tMenu);
9187 akron1 306
VAR
307
	temp: INTEGER;
9174 akron1 308
BEGIN
309
    IF (m # NIL) & (m.tid # 0) THEN
310
    	IF m.child # NIL THEN
311
    		close(m.child);
312
    		m.child := NIL
313
    	END;
9187 akron1 314
    	temp := m.tid;
315
    	m.tid := 0;
316
        K.ExitID(temp);
9174 akron1 317
        m.active := FALSE
318
    END
319
END close;
320
 
321
 
8728 leency 322
PROCEDURE click (m: tMenu; i: INTEGER);
323
VAR
324
    item: List.tItem;
9174 akron1 325
    p: tMenu;
9187 akron1 326
    id: INTEGER;
8728 leency 327
BEGIN
9187 akron1 328
	id := -1;
329
	IF i < 0 THEN
330
		id := i
331
	ELSE
332
	    item := List.getItem(m.items, i);
333
	    IF (item # NIL) & item(tItem).enabled & (item(tItem).child = NIL) THEN
334
	    	id := item(tItem).id
335
	    END
336
    END;
337
    IF id # -1 THEN
338
	    m.click(m, id);
339
	    p := m.parent;
340
	   	WHILE p # NIL DO
341
	   		p.child := NIL;
342
	   		close(p);
343
	   		p := p.parent
344
	   	END;
345
	   	exit(m)
346
   	END
8728 leency 347
END click;
348
 
349
 
9174 akron1 350
PROCEDURE opened* (m: tMenu): BOOLEAN;
351
    RETURN m.tid # 0
352
END opened;
353
 
354
 
355
PROCEDURE isActive (m: tMenu): BOOLEAN;
356
	RETURN (m # NIL) & ((m.tid # 0) & m.active OR isActive(m.child))
357
END isActive;
358
 
359
 
360
PROCEDURE closeChild (m: tMenu);
361
BEGIN
362
	IF m.child # NIL THEN
363
		close(m.child);
364
		m.child := NIL
365
	END
366
END closeChild;
367
 
368
 
9187 akron1 369
PROCEDURE submenu (m: tMenu; keyboard: BOOLEAN): BOOLEAN;
9174 akron1 370
VAR
371
	item: List.tItem;
9187 akron1 372
	res: BOOLEAN;
9174 akron1 373
BEGIN
9187 akron1 374
	res := FALSE;
9174 akron1 375
    item := List.getItem(m.items, m.selItem);
376
    IF (item # NIL) & item(tItem).enabled & (item(tItem).child # NIL) THEN
9187 akron1 377
    	res := TRUE;
9174 akron1 378
    	IF ~opened(item(tItem).child) THEN
379
    		closeChild(m);
9187 akron1 380
    		item(tItem).child.keyboard := keyboard;
9174 akron1 381
    		_open(item(tItem).child, m.winX + m.width - 2, m.winY + m.selItem*fontHeight);
9187 akron1 382
    		m.child := item(tItem).child;
9174 akron1 383
    	END
384
    ELSE
385
    	closeChild(m)
386
    END
9187 akron1 387
    RETURN res
9174 akron1 388
END submenu;
389
 
390
 
8728 leency 391
PROCEDURE [stdcall] window (m: tMenu);
392
VAR
393
    x, y: INTEGER;
9187 akron1 394
    key, temp: INTEGER;
8728 leency 395
    msState: SET;
9187 akron1 396
    shift, ctrl: BOOLEAN;
8728 leency 397
BEGIN
9187 akron1 398
    m.selItem := ORD(m.keyboard) - 1;
8728 leency 399
    m.cliItem := -1;
9187 akron1 400
    m.keyboard := FALSE;
8728 leency 401
    K.SetEventsMask({0, 1, 5});
402
    WHILE TRUE DO
403
        CASE K.WaitForEvent() OF
404
        |1:
405
            draw_window(m)
406
        |2:
9187 akron1 407
        	K.getKBState(shift, ctrl);
8728 leency 408
            key := K.GetKey();
9187 akron1 409
            IF ~shift & ~ ctrl THEN
410
	            IF key DIV 65536 = 72 THEN
411
	                DEC(m.selItem);
412
	                IF m.selItem < 0 THEN
413
	                    m.selItem := m.items.count - 1
414
	                END
415
	            ELSIF key DIV 65536 = 80 THEN
416
	                INC(m.selItem);
417
	                IF m.selItem >= m.items.count THEN
418
	                    m.selItem := 0
419
	                END
420
	            ELSIF key DIV 65536 = 28 THEN
421
	                IF m.selItem >= 0 THEN
422
	                    click(m, m.selItem)
423
	                END;
424
	                m.cliItem := -1
425
	            ELSIF key DIV 65536 = 77 THEN
426
	                IF ~submenu(m, TRUE) THEN
427
	                	click(m, -(getMainID(m) + 1))
428
	                END;
429
	                m.cliItem := -1
430
	            ELSIF key DIV 65536 = 75 THEN
431
	            	IF m.parent # NIL THEN
432
	                	escape(m)
433
	            	ELSE
434
	            		click(m, -(getMainID(m) - 1))
435
	                END;
436
	                m.cliItem := -1
437
	            ELSIF key DIV 65536 = 1 THEN
438
	            	escape(m)
439
	            ELSE
440
	                IF m.key(m, key) THEN
441
	                	IF m.parent # NIL THEN
442
	                		temp := m.parent.tid;
443
	                		m.parent.tid := 0;
444
	                		K.ExitID(temp)
445
	                	END;
446
	                    exit(m)
447
	                END
8728 leency 448
                END
449
            ELSE
450
                IF m.key(m, key) THEN
9187 akron1 451
                	IF m.parent # NIL THEN
452
                		temp := m.parent.tid;
453
                		m.parent.tid := 0;
454
                		K.ExitID(temp)
455
                	END;
8728 leency 456
                    exit(m)
457
                END
458
            END;
459
            repaint(m)
460
        |6:
9208 akron1 461
        	K.mouse(msState, x, y);
8728 leency 462
            IF (0 <= x) & (x < m.width) & (0 <= y) & (y < m.height) THEN
9174 akron1 463
            	m.active := TRUE;
8728 leency 464
                m.selItem := (y - TOP) DIV fontHeight;
465
                IF 8 IN msState THEN
466
                    m.cliItem := (y - TOP) DIV fontHeight
467
                END;
468
                IF 16 IN msState THEN
469
                    IF m.cliItem = m.selItem THEN
470
                        click(m, m.cliItem)
471
                    END;
472
                    m.cliItem := -1
473
                END
474
            ELSE
9174 akron1 475
            	m.active := FALSE;
8728 leency 476
                m.cliItem := -1;
9174 akron1 477
                IF ({8, 9, 10, 16} * msState # {}) & ~isActive(m.child) THEN
8728 leency 478
                    exit(m)
479
                END
480
            END;
9174 akron1 481
            repaint(m);
9187 akron1 482
            IF submenu(m, FALSE) THEN END
8728 leency 483
        END
484
    END
485
END window;
486
 
487
 
9174 akron1 488
PROCEDURE level (m: tMenu): INTEGER;
489
VAR
490
	res: INTEGER;
491
BEGIN
492
	res := 0;
493
	WHILE m.parent # NIL DO
494
		INC(res);
495
		m := m.parent
496
	END
497
	RETURN res
498
END level;
499
 
500
 
501
PROCEDURE open* (m: tMenu; x, y: INTEGER);
502
VAR
503
	L: INTEGER;
504
BEGIN
505
    IF m.tid = 0 THEN
506
        L := level(m);
9187 akron1 507
        IF KOSAPI.sysfunc3(18, 21, TIDs[L]) = 0 THEN
508
        	m.winX := x;
509
        	m.winY := y;
510
	        SYSTEM.PUT(SYSTEM.ADR(stack[L][LEN(stack[0]) - 1]), m);
511
    	    m.tid := K.CreateThread(SYSTEM.ADR(window), stack[L]);
512
        	TIDs[L] := m.tid
513
        END
9174 akron1 514
    END
515
END open;
516
 
517
 
8728 leency 518
PROCEDURE AddMenuItem* (items: List.tList; id: INTEGER; s: ARRAY OF WCHAR);
519
VAR
520
    item: tItem;
521
BEGIN
522
    NEW(item);
523
    item.id := id;
524
    item.text := s;
525
    item.enabled := TRUE;
526
    item.delim := FALSE;
9174 akron1 527
    item.child := NIL;
8728 leency 528
    List.append(items, item);
529
END AddMenuItem;
530
 
531
 
532
PROCEDURE delimiter* (items: List.tList);
533
BEGIN
534
    items.last(tItem).delim := TRUE
535
END delimiter;
536
 
537
 
9174 akron1 538
PROCEDURE child* (items: List.tList; menu: tMenu);
539
BEGIN
540
    items.last(tItem).child := menu
541
END child;
542
 
543
 
8728 leency 544
PROCEDURE getItem (m: tMenu; id: INTEGER): tItem;
545
VAR
546
    item: tItem;
547
BEGIN
548
    item := m.items.first(tItem);
549
    WHILE (item # NIL) & (item.id # id) DO
550
        item := item.next(tItem)
551
    END
552
    RETURN item
553
END getItem;
554
 
555
 
556
PROCEDURE setEnabled* (m: tMenu; id: INTEGER; value: BOOLEAN);
557
VAR
558
    item: tItem;
559
BEGIN
560
    item := getItem(m, id);
561
    IF item # NIL THEN
562
        item.enabled := value
563
    END
564
END setEnabled;
565
 
566
 
9182 akron1 567
PROCEDURE check* (m: tMenu; id: INTEGER; value: BOOLEAN);
8728 leency 568
VAR
569
    item: tItem;
570
BEGIN
571
    item := getItem(m, id);
572
    IF item # NIL THEN
9182 akron1 573
        item.check := ORD(value)
8728 leency 574
    END
9182 akron1 575
END check;
8728 leency 576
 
577
 
9182 akron1 578
PROCEDURE option* (m: tMenu; id: INTEGER; value: BOOLEAN);
579
VAR
580
    item: tItem;
581
BEGIN
582
    item := getItem(m, id);
583
    IF item # NIL THEN
584
        item.check := ORD(value)*2
585
    END
586
END option;
587
 
588
 
8728 leency 589
PROCEDURE isEnabled* (m: tMenu; id: INTEGER): BOOLEAN;
590
VAR
591
    item: tItem;
592
BEGIN
593
    item := getItem(m, id)
594
    RETURN (item # NIL) & item.enabled
595
END isEnabled;
596
 
597
 
598
PROCEDURE create* (items: List.tList; click: tClick; key: tKey): tMenu;
599
VAR
600
    m: tMenu;
601
    maxLength: INTEGER;
602
    item: tItem;
603
BEGIN
604
    NEW(m);
605
    m.tid := 0;
9174 akron1 606
    m.active := FALSE;
607
    m.parent := NIL;
608
    m.child := NIL;
9187 akron1 609
    m.mainID := 0;
8728 leency 610
    m.items  := items;
611
    m.click := click;
612
    m.key := key;
613
    maxLength := 0;
614
    item := items.first(tItem);
615
    WHILE item # NIL DO
616
        maxLength := MAX(maxLength, LENGTH(item.text));
617
        item := item.next(tItem)
618
    END;
619
    m.width  := maxLength*fontWidth + LEFT + RIGHT;
620
    m.height := items.count*fontHeight - 2;
621
    m.font := G.CreateFont(1, "", {});
622
    m.canvas := G.CreateCanvas(m.width + 1, m.height + 1);
623
    G.SetFont(m.canvas, m.font);
624
    RETURN m
625
END create;
626
 
9174 akron1 627
 
628
PROCEDURE init* (_resetTimer: tProc);
629
VAR
630
	i: INTEGER;
631
BEGIN
632
	resetTimer := _resetTimer;
633
	_open := open;
634
	FOR i := 0 TO maxLEVEL DO
635
		TIDs[i] := 0
636
	END
637
END init;
638
 
639
 
8728 leency 640
END Menu.