Subversion Repositories Kolibri OS

Rev

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