Subversion Repositories Kolibri OS

Rev

Rev 9659 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
8728 leency 1
(*
9906 akron1 2
    Copyright 2021-2023 Anton Krotov
8728 leency 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 Scroll;
21
 
9187 akron1 22
IMPORT G := Graph, K := KolibriOS, U := Utils;
8728 leency 23
 
9174 akron1 24
CONST
25
 
9208 akron1 26
	DELAY = 40;
9174 akron1 27
 
8728 leency 28
TYPE
29
 
9648 akron1 30
	tProcedure = PROCEDURE;
31
 
9174 akron1 32
	tScroll* = RECORD
9648 akron1 33
		vertical, mouse: BOOLEAN;
9174 akron1 34
		top*, left*,
35
		width*, height*: INTEGER; (* read only *)
36
		btnSize, sliderSize: INTEGER;
37
		pos, Slider, pos0, maxVal*, value*: INTEGER;
9648 akron1 38
		canvas: G.tCanvas;
39
		change: tProcedure;
40
		delay: INTEGER;
41
		btn*: INTEGER
9174 akron1 42
	END;
8728 leency 43
 
44
 
9208 akron1 45
PROCEDURE MouseUp (VAR scroll: tScroll);
46
BEGIN
47
	scroll.Slider := -1;
9648 akron1 48
	scroll.btn := 0;
9208 akron1 49
	scroll.mouse := FALSE;
9648 akron1 50
	scroll.delay := DELAY
9208 akron1 51
END MouseUp;
52
 
53
 
9648 akron1 54
PROCEDURE create* (vertical: BOOLEAN; width, height: INTEGER; btnSize, sliderSize: INTEGER; change: tProcedure; VAR scroll: tScroll);
9187 akron1 55
VAR
56
	res: tScroll;
8728 leency 57
BEGIN
9208 akron1 58
	MouseUp(res);
9187 akron1 59
	res.vertical := vertical;
60
	res.left := 0;
61
	res.top := 0;
62
	res.width := width;
63
	res.height := height;
64
	res.btnSize := btnSize;
65
	res.sliderSize := sliderSize;
66
	res.pos := 0;
67
	res.maxVal := 0;
68
	res.canvas := G.CreateCanvas(width, height);
9648 akron1 69
	res.change := change;
9187 akron1 70
	scroll := res
9174 akron1 71
END create;
8728 leency 72
 
73
 
9174 akron1 74
PROCEDURE Rect (canvas: G.tCanvas; left, top, right, bottom: INTEGER);
75
BEGIN
76
	G.FillRect(canvas, left, top, right, bottom);
9628 akron1 77
	G.SetColor(canvas, K.colors.line);
9174 akron1 78
	G.Rect(canvas, left, top, right, bottom);
79
END Rect;
80
 
81
 
9630 akron1 82
PROCEDURE _draw (scroll: tScroll);
8728 leency 83
VAR
9174 akron1 84
	canvas: G.tCanvas;
85
	x, y, d, x1, x2, y1, y2,
86
	width, height, btn: INTEGER;
87
 
88
 
89
	PROCEDURE SetColor (canvas: G.tCanvas; c: BOOLEAN);
90
	VAR
91
		color: INTEGER;
92
	BEGIN
93
		IF c THEN
9628 akron1 94
			color := K.colors.button
9174 akron1 95
		ELSE
9628 akron1 96
			color := K.colors.button_text
9174 akron1 97
		END;
98
		G.SetColor(canvas, color)
99
	END SetColor;
100
 
101
 
8728 leency 102
BEGIN
9174 akron1 103
	btn := scroll.btnSize;
104
	width := scroll.width;
105
	height := scroll.height;
106
	canvas := scroll.canvas;
9628 akron1 107
	G.SetColor(canvas, K.colors.light);
9180 akron1 108
	G.clear(canvas);
9628 akron1 109
	G.SetColor(canvas, K.colors.line);
9174 akron1 110
	G.Rect(canvas, 0, 0, width - 1, height - 1);
9906 akron1 111
	SetColor(canvas, scroll.btn # -1);
9174 akron1 112
	IF scroll.vertical THEN
113
		Rect(canvas, 0, 0, width - 1, btn - 1);
9648 akron1 114
		SetColor(canvas, scroll.btn # 1);
9174 akron1 115
		Rect(canvas, 0, height - btn, width - 1, height - 1);
9628 akron1 116
		G.SetColor(canvas, K.colors.button);
9174 akron1 117
		Rect(canvas, 0, btn + scroll.pos - 1, width - 1, btn + scroll.pos + scroll.sliderSize - 1);
8728 leency 118
 
9628 akron1 119
		G.SetColor(canvas, K.colors.button_text);
8728 leency 120
 
9174 akron1 121
		y := btn + scroll.pos + scroll.sliderSize DIV 2 - 1;
122
		G.HLine(canvas, y, width DIV 4, 3*width DIV 4);
123
		G.HLine(canvas, y - 3, width DIV 3, 2*width DIV 3);
124
		G.HLine(canvas, y + 3, width DIV 3, 2*width DIV 3);
125
 
126
		d := 4*width DIV 10;
127
		x1 := (width - d) DIV 2;
128
		x2 := x1 + d;
129
 
9648 akron1 130
		SetColor(canvas, scroll.btn = -1);
9174 akron1 131
		y := (btn - d DIV 2) DIV 2 + d DIV 2 - 1;
132
		G.Triangle(canvas, x1 - 1, y, x2, y, G.triUp);
133
 
9648 akron1 134
		SetColor(canvas, scroll.btn = 1);
9174 akron1 135
		y := y + height - btn - d DIV 2 + 1;
136
		G.Triangle(canvas, x1 - 1, y, x2, y, G.triDown);
137
	ELSE
138
		Rect(canvas, 0, 0, btn - 1, height - 1);
9648 akron1 139
		SetColor(canvas, scroll.btn # 1);
9174 akron1 140
		Rect(canvas, width - btn, 0, width - 1, height - 1);
9628 akron1 141
		G.SetColor(canvas, K.colors.button);
9174 akron1 142
		Rect(canvas, btn + scroll.pos - 1, 0, btn + scroll.pos + scroll.sliderSize - 1, height - 1);
143
 
9628 akron1 144
		G.SetColor(canvas, K.colors.button_text);
9174 akron1 145
 
146
		x := btn + scroll.pos + scroll.sliderSize DIV 2 - 1;
147
		G.VLine(canvas, x, height DIV 4, 3*height DIV 4);
148
		G.VLine(canvas, x - 3, height DIV 3, 2*height DIV 3);
149
		G.VLine(canvas, x + 3, height DIV 3, 2*height DIV 3);
150
 
151
		d := 4*height DIV 10;
152
		y1 := (height - d) DIV 2;
153
		y2 := y1 + d;
154
 
9648 akron1 155
		SetColor(canvas, scroll.btn = -1);
9174 akron1 156
		x := (btn - d DIV 2) DIV 2 + d DIV 2 - 1;
157
		G.Triangle(canvas, x, y1 - 1, x, y2, G.triLeft);
158
 
9648 akron1 159
		SetColor(canvas, scroll.btn = 1);
9174 akron1 160
		x := x + width - btn - d DIV 2 + 1;
161
		G.Triangle(canvas, x, y1 - 1, x, y2, G.triRight);
162
	END;
163
	G.DrawCanvas(scroll.canvas, scroll.left, scroll.top)
9630 akron1 164
END _draw;
9174 akron1 165
 
166
 
9630 akron1 167
PROCEDURE draw* (scroll: tScroll);
8728 leency 168
BEGIN
9174 akron1 169
	IF scroll.canvas # NIL THEN
9630 akron1 170
		_draw(scroll)
9174 akron1 171
	END
9630 akron1 172
END draw;
9174 akron1 173
 
174
 
175
PROCEDURE resize* (VAR scroll: tScroll; width, height: INTEGER);
176
BEGIN
177
	G.destroy(scroll.canvas);
178
	scroll.canvas := G.CreateCanvas(width, height);
179
	scroll.width := width;
180
	scroll.height := height;
9630 akron1 181
	draw(scroll)
8728 leency 182
END resize;
183
 
184
 
9174 akron1 185
PROCEDURE setValue* (VAR scroll: tScroll; value: INTEGER);
8728 leency 186
VAR
9659 akron1 187
	pos, maxPos, maxVal, n, m: INTEGER;
8728 leency 188
BEGIN
9659 akron1 189
	maxVal := scroll.maxVal;
9174 akron1 190
	IF scroll.vertical THEN
191
		maxPos := scroll.height
192
	ELSE
193
		maxPos := scroll.width
194
	END;
195
	maxPos := maxPos - scroll.btnSize*2 - scroll.sliderSize + 1;
9659 akron1 196
	IF (value < 0) OR (maxVal <= 0) THEN
9174 akron1 197
		value := 0;
198
		pos := 0
9659 akron1 199
	ELSIF value > maxVal THEN
200
		value := maxVal;
9174 akron1 201
		pos := maxPos
202
	ELSE
9659 akron1 203
		IF (maxPos + 1) >= maxVal THEN
204
			n := (maxPos + 1) DIV maxVal;
205
			m := (maxPos + 1) MOD maxVal;
9174 akron1 206
			pos := value*n + MIN(value, m)
207
		ELSE
9659 akron1 208
			pos := FLOOR(FLT(value)*FLT(maxPos + 1)/FLT(maxVal))
9174 akron1 209
		END;
210
		IF pos > maxPos THEN
211
			pos := maxPos;
9659 akron1 212
			value := maxVal
9174 akron1 213
		END
214
	END;
215
	scroll.pos := pos;
216
	scroll.value := value
217
END setValue;
8728 leency 218
 
219
 
9174 akron1 220
PROCEDURE ceil (p, q: INTEGER): INTEGER;
221
	RETURN p DIV q + ORD(p MOD q # 0)
222
END ceil;
223
 
224
 
225
PROCEDURE setPos (VAR scroll: tScroll; pos: INTEGER);
226
VAR
9659 akron1 227
	maxPos, value, maxVal, n, m, x, x0, q: INTEGER;
9174 akron1 228
BEGIN
9659 akron1 229
	maxVal := scroll.maxVal;
230
	IF maxVal > 0 THEN
9174 akron1 231
		IF scroll.vertical THEN
232
			maxPos := scroll.height
233
		ELSE
234
			maxPos := scroll.width
235
		END;
236
		maxPos := maxPos - scroll.btnSize*2 - scroll.sliderSize + 1;
237
		IF pos <= 0 THEN
238
			pos := 0;
239
			value := 0
240
		ELSIF pos >= maxPos THEN
241
			pos := maxPos;
9659 akron1 242
			value := maxVal
9174 akron1 243
		ELSE
9659 akron1 244
			IF maxVal <= maxPos + 1 THEN
245
				n := (maxPos + 1) DIV maxVal;
246
				m := (maxPos + 1) MOD maxVal;
9174 akron1 247
 
248
				q := m*(n + 1);
249
				IF q < pos THEN
250
					value := ceil(pos - m, n)
251
				ELSIF q > pos THEN
252
					value := ceil(pos, n + 1)
253
				ELSE
254
					value := m
255
				END;
256
 
257
				x := value*n + MIN(value, m);
258
				x0 := (value - 1)*n + MIN(value - 1, m);
259
 
260
				IF x - pos > pos - x0 THEN
261
					pos := x0;
262
					DEC(value)
263
				ELSE
264
					pos := x;
265
					IF pos > maxPos THEN
266
						pos := maxPos;
9659 akron1 267
						value := maxVal
9174 akron1 268
					END
269
				END
270
			ELSE
9659 akron1 271
				value := FLOOR(FLT(maxVal)*FLT(pos)/FLT(maxPos + 1))
9174 akron1 272
			END
273
		END
274
	ELSE
275
		pos := 0;
9659 akron1 276
		value := 0
9174 akron1 277
	END;
278
	scroll.pos := pos;
279
	scroll.value := value
280
END setPos;
281
 
282
 
9208 akron1 283
PROCEDURE MouseMove (VAR scroll: tScroll; x, y: INTEGER);
9174 akron1 284
VAR
285
	c: INTEGER;
286
BEGIN
9210 akron1 287
	IF scroll.vertical THEN
288
		c := y - scroll.top
289
	ELSE
290
		c := x - scroll.left
291
	END;
292
	setPos(scroll, scroll.pos0 + c - scroll.Slider);
9630 akron1 293
	draw(scroll)
9174 akron1 294
END MouseMove;
295
 
296
 
9648 akron1 297
PROCEDURE button (VAR scroll: tScroll);
9210 akron1 298
VAR
9648 akron1 299
	btn: INTEGER;
9174 akron1 300
BEGIN
9648 akron1 301
	WHILE scroll.btn # 0 DO
302
		btn := scroll.btn;
303
		setValue(scroll, scroll.value + btn);
304
		draw(scroll);
305
		IF scroll.change # NIL THEN
306
			scroll.change
9208 akron1 307
		END;
9648 akron1 308
		scroll.btn := 0;
309
		IF 0 IN K.MouseState() THEN
310
			WHILE (0 IN K.MouseState()) & (scroll.delay > 0) DO
311
				K.Pause(1);
312
				DEC(scroll.delay)
313
			END;
314
			IF scroll.delay = 0 THEN
315
				scroll.btn := btn;
316
				scroll.delay := 3
317
			ELSE
318
				scroll.delay := DELAY
319
			END
9208 akron1 320
		ELSE
9648 akron1 321
			scroll.delay := DELAY
9208 akron1 322
		END
323
	END
9648 akron1 324
END button;
9208 akron1 325
 
326
 
327
PROCEDURE MouseDown (VAR scroll: tScroll; x, y: INTEGER);
9174 akron1 328
VAR
329
	c, size: INTEGER;
330
BEGIN
9210 akron1 331
	DEC(x, scroll.left);
332
	DEC(y, scroll.top);
333
	scroll.mouse := TRUE;
334
	IF U.between(1, x, scroll.width - 2) & U.between(1, y, scroll.height - 2) THEN
335
		IF scroll.vertical THEN
336
			c := y;
337
			size := scroll.height
338
		ELSE
339
			c := x;
340
			size := scroll.width
341
		END;
342
		IF U.between(scroll.btnSize + scroll.pos - 1, c, scroll.btnSize + scroll.pos + scroll.sliderSize - 1) THEN
343
			scroll.pos0 := scroll.pos;
344
			scroll.Slider := c
345
		ELSIF U.between(0, c, scroll.btnSize - 1) THEN
9648 akron1 346
			scroll.btn := -1
9210 akron1 347
		ELSIF U.between(size - scroll.btnSize, c, size - 1) THEN
9648 akron1 348
			scroll.btn := 1
9210 akron1 349
		ELSE
350
			setPos(scroll, c - scroll.btnSize - scroll.sliderSize DIV 2);
351
			scroll.pos0 := scroll.pos;
352
			scroll.Slider := c;
9630 akron1 353
			draw(scroll)
9174 akron1 354
		END
355
	END
356
END MouseDown;
357
 
358
 
9208 akron1 359
PROCEDURE mouse* (VAR scroll: tScroll);
360
VAR
361
	msState: SET;
362
	x, y: INTEGER;
9174 akron1 363
BEGIN
9208 akron1 364
	K.mouse(msState, x, y);
365
	IF 0 IN msState THEN
9210 akron1 366
		IF ~scroll.mouse THEN
367
			MouseDown(scroll, x, y)
368
		ELSIF scroll.Slider # -1 THEN
369
			MouseMove(scroll, x, y)
370
		END
9208 akron1 371
	ELSIF scroll.mouse THEN
372
		MouseUp(scroll);
9630 akron1 373
		draw(scroll)
9648 akron1 374
	END;
375
	button(scroll)
9208 akron1 376
END mouse;
8728 leency 377
 
378
 
379
END Scroll.