Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
8129 IgorA 1
#include 
2
#include 
3
#include 
8252 IgorA 4
#include 
5
#include 
1769 yogev_ezra 6
#include "lifegen.h"
7
#include "life_bmp.h"
8
 
8129 IgorA 9
using namespace Kolibri;
1769 yogev_ezra 10
 
8252 IgorA 11
char library_path[2048];
1769 yogev_ezra 12
 
8252 IgorA 13
OpenDialog_data ofd;
14
unsigned char procinfo[1024];
15
char plugin_path[4096], filename_area[256];
16
od_filter filter1 = { 8, "LIF\0\0" };
1769 yogev_ezra 17
 
8252 IgorA 18
namespace Kolibri{
19
	char CurrentDirectoryPath[2048];
20
}
21
 
22
void __stdcall DrawWindow()
1769 yogev_ezra 23
{
8252 IgorA 24
	asm{
25
		push ebx
26
		mcall SF_REDRAW,SSF_BEGIN_DRAW
1769 yogev_ezra 27
	}
8252 IgorA 28
	//KolibriOnPaint();
29
	asm{
30
		mcall SF_REDRAW,SSF_END_DRAW
31
		pop ebx
32
	}
1769 yogev_ezra 33
}
34
 
35
void __stdcall OneGeneration(int w, int h, void *dest, const void *src, int flag);
36
 
37
struct GenerateParam
38
{
39
	unsigned int gps;
40
	unsigned int paint_time, time, count;
41
	bool stop;
42
	int paint;
43
	double speed;
44
};
45
 
46
struct AxisParam
47
{
48
	unsigned int win;
49
	int p;
50
	double shift;
51
};
52
 
53
struct MouseParam
54
{
55
	int hit_x, hit_y, last_x, last_y;
56
	int button, hit_type;
57
 
58
	enum {HitNull = 0, HitLine, HitCircle, HitScroll};
59
};
60
 
61
struct MenuButtonParam
62
{
63
	int left, size, border;
64
	bool check;
65
	const unsigned char *bitmap;
66
 
67
	int Left() const {return left;}
68
	int Right() const {return left + size;}
69
};
70
 
71
const int MenuDig = 10;
72
 
73
struct MenuParam
74
{
75
	enum {Size = 20, NButton = 14};
76
 
77
	bool draw;
78
	int pressed, current, edit;
79
	int edit_index, edit_num[2], edit_num_max;
80
	MenuButtonParam button[NButton];
81
	const unsigned char *digit[MenuDig];
82
};
83
 
84
struct TimeGeneration
85
{
86
	unsigned int t, g;
87
};
88
 
89
enum MenuItem {MenuIHide, MenuIClear, MenuIOpen, MenuIAbout, MenuIExit,
90
				MenuIGenerate, MenuIRandom, MenuIVCircle, MenuIHCircle,
91
				MenuILine, MenuIScroll, MenuIWinSize, MenuISize, MenuISpeed};
92
 
93
enum {PaintWNull = 0, PaintWPole = 1, PaintWMenuBorder = 2, PaintWMenu = 6,
94
		PaintWSpeed = 8, PaintWAll = 15, PaintWFast = 64, PaintWNow = 128};
95
 
96
enum {TimeGenLength = 500};
97
 
98
unsigned char *life_data = 0, *picture = 0;
99
GenerateParam generate = {0, 0, 0, 0, false, PaintWNull, 0};
100
AxisParam xpar = {0, 0, 0};
101
AxisParam ypar = {0, 0, 0};
102
MouseParam mpar = {0, 0, 0, 0, 0, MouseParam::HitNull};
103
MenuParam menu;
8252 IgorA 104
bool open_file_str = false;
1769 yogev_ezra 105
TimeGeneration timegen[TimeGenLength];
106
int timegenpos = 0;
107
 
8170 IgorA 108
#ifdef __KOLIBRI__
1769 yogev_ezra 109
 
110
inline int abs(int i) {return (i >= 0) ? i : (-i);}
111
 
112
unsigned int rand_data[4];
113
 
114
void randomize()
115
{
116
	rand_data[0] = (unsigned int)Clock();
117
	rand_data[1] = (unsigned int)GetPackedTime();
118
	rand_data[2] = (unsigned int)GetPackedDate();
119
	rand_data[3] = (unsigned int)0xA3901BD2 ^ GetPid();
120
}
121
 
122
unsigned int rand()
123
{
124
	rand_data[0] ^= _HashDword(rand_data[3] + 0x2835C013U);
125
	rand_data[1] += _HashDword(rand_data[0]);
126
	rand_data[2] -= _HashDword(rand_data[1]);
127
	rand_data[3] ^= _HashDword(rand_data[2]);
128
	return rand_data[3];
129
}
130
 
131
#define random(k)  (rand() % (k))
132
 
133
#else
134
 
135
#include 
136
 
137
#endif
138
 
139
/*void DebugPutNumber(int x)
140
{
141
	char word[12], *w = word, *s, c;
142
	int i;
143
	if (x < 0) {*(w++) = '-'; x = -x;}
144
	s = w;
145
	do
146
	{
147
		*(s++) = char('0' + (unsigned int)x % 10U);
148
		(unsigned int&)x /= 10U;
149
	} while(x);
150
	for (i = 0; w + i < s - 1 - i; i++)
151
	{
152
		c = w[i]; w[i] = s[-1 - i]; s[-1 - i] = c;
153
	}
154
	*s = 0;
155
	DebugPutString(word);
156
}*/
157
 
158
bool SetPictureSize(int w = -1, int h = -1)
159
{
160
	if (w > 32767) w = 32767;
161
	if (h > 32767) h = 32767;
162
	if (w > 0) xpar.win = (unsigned short)w;
163
	if (h > 0) ypar.win = (unsigned short)h;
164
	if (picture) {Free(picture); picture = 0;}
165
	if (w == 0 || h == 0 || xpar.win == 0 || ypar.win == 0) return true;
166
	picture = (unsigned char*)Alloc(3 * xpar.win * ypar.win);
167
	return picture != 0;
168
 
169
}
170
 
171
bool SetPoleSize(int w = -1, int h = -1)
172
{
173
	int s;
174
	if (w > 32767) w = 32767;
175
	if (h > 32767) h = 32767;
176
	if (w > 0) xpar.p = (unsigned short)w;
177
	if (h > 0) ypar.p = (unsigned short)h;
178
	if (xpar.p < 4) xpar.p = 4;
179
	if (ypar.p < 4) ypar.p = 4;
180
	if (life_data) {Free(life_data); life_data = 0;}
181
	if (w == 0 || h == 0) return true;
182
	s = GetDataSize(xpar.p, ypar.p);
183
	life_data = (unsigned char*)Alloc(2*s + DataMemAdd);
184
	if (!life_data) return false;
185
	MemSet(GetDataAddress(life_data), 0, s);
186
	return true;
187
}
188
 
189
int GetMenuHeight();
190
 
191
void GetPaintSize(int &w, int &h, int &xx, int &yy)
192
{
193
	int t = GetMenuHeight();
194
	w = xpar.win; h = ypar.win - t;
195
	xx = 0; yy = t;
196
}
197
 
198
double GetAxisRatio(const AxisParam &par, int s)
199
{
200
	int t = par.p - s;
201
	if (s <= 0 || t <= 0) return 0;
202
	return double(t) / 2;
203
}
204
 
205
void GetAxisShift(const AxisParam &par, int &s, int &k, int &kk)
206
{
207
	int t = par.p - s;
208
	if (t < 0) {kk += (-t) / 2; t = 0; s = par.p;}
209
	if (s <= 0 || t <= 0) k = 0;
210
	else
211
	{
212
		double r = double(t) / 2;
213
		k = (int)Floor(r * (1 + par.shift));
214
		if (k < 0) k = 0;
215
		else if (k > t) k = t;
216
	}
217
}
218
 
219
void GetPaintOrigin(int &w, int &h, int &x, int &y, int &xx, int &yy)
220
{
221
	GetPaintSize(w, h, xx, yy);
222
	GetAxisShift(xpar, w, x, xx);
223
	GetAxisShift(ypar, h, y, yy);
224
}
225
 
226
void ApplyScroll(unsigned char *data1 = life_data, unsigned char *data0 = 0)
227
{
228
	if (!data0) data0 = data1;
229
	data0 = (unsigned char*)GetDataAddress(data0);
230
	data1 = (unsigned char*)GetDataAddress(data1);
231
	const double min_ratio = 1e-2;
232
	double r;
233
	int w, h, xx, yy;
234
	GetPaintSize(w, h, xx, yy);
235
	xx = 0; yy = 0;
236
	r = GetAxisRatio(xpar, w);
237
	if (menu.button[MenuIHCircle].check)
238
	{
239
		xx = mpar.hit_x - mpar.last_x + (int)Floor(xpar.shift * r + 0.5);
240
		xx %= xpar.p - 2;
241
		if (xx < 0) xx += xpar.p - 2;
242
		xpar.shift = 0;
243
	}
244
	else if (r < min_ratio) xpar.shift = 0;
245
	else
246
	{
247
		xpar.shift -= double(mpar.last_x - mpar.hit_x) / r;
248
		if (xpar.shift < -1) xpar.shift = -1;
249
		else if (xpar.shift > 1) xpar.shift = 1;
250
	}
251
	r = GetAxisRatio(ypar, h);
252
	if (menu.button[MenuIVCircle].check)
253
	{
254
		yy = mpar.hit_y - mpar.last_y + (int)Floor(ypar.shift * r + 0.5);
255
		yy %= ypar.p - 2;
256
		if (yy < 0) yy += ypar.p - 2;
257
		ypar.shift = 0;
258
	}
259
	else if (r < min_ratio) ypar.shift = 0;
260
	else
261
	{
262
		ypar.shift -= double(mpar.last_y - mpar.hit_y) / r;
263
		if (ypar.shift < -1) ypar.shift = -1;
264
		else if (ypar.shift > 1) ypar.shift = 1;
265
	}
266
	if (xx == 0 && yy == 0)
267
	{
268
		if (data0 != data1) MemCopy(data0, data1, GetDataSize(xpar.p, ypar.p));
269
	}
270
	else
271
	{
272
		int i, j;
273
		i = GetDataSize(xpar.p, ypar.p);
274
		if (data0 == data1)
275
		{
276
			data1 += i;
277
			MemCopy(data1, data0, i);
278
		}
279
		MemSet(data0, 0, i);
280
		APosPixel pixel0(xpar.p, ypar.p, data0);
281
		APosPixel pixel1(xpar.p, ypar.p, data1);
282
		for (i = 0; i < xpar.p; i++)
283
		{
284
			pixel0.SetTo(i, 0);
285
			pixel1.SetTo(xx, yy);
286
			j = ypar.p - yy;
287
			for (;;)
288
			{
289
				if (pixel1.GetPixel()) pixel0.Set1Pixel();
290
				if (--j == 0) break;
291
				pixel0.AddY1(); pixel1.AddY1();
292
			}
293
			if (yy)
294
			{
295
				pixel0.AddY1();
296
				pixel1.SetTo(xx, 2);
297
				j = yy;
298
				for (;;)
299
				{
300
					if (pixel1.GetPixel()) pixel0.Set1Pixel();
301
					if (--j == 0) break;
302
					pixel0.AddY1(); pixel1.AddY1();
303
				}
304
			}
305
			xx++;
306
			if (xx >= xpar.p) xx = 2;
307
		}
308
	}
309
}
310
 
311
void DrawLine(int x0, int y0, int x1, int y1, bool c, unsigned char *data0 = life_data)
312
{
313
	int i;
314
	if (y0 == y1)
315
	{
316
		if (x0 > x1) {i = x0; x0 = x1; x1 = i;}
317
		if (x1 < 0 || x0 >= xpar.p || y1 < 0 || y0 >= ypar.p) return;
318
		if (x0 < 0) x0 = 0;
319
		if (x1 >= xpar.p) x1 = xpar.p - 1;
320
		APosPixel pixel(xpar.p, ypar.p, data0, x0, y0);
321
		for (i = x1 - x0; i >= 0; pixel.AddX1(), i--) pixel.SetPixel(c);
322
	}
323
	else if (x0 == x1)
324
	{
325
		if (y0 > y1) {i = y0; y0 = y1; y1 = i;}
326
		if (x1 < 0 || x0 >= xpar.p || y1 < 0 || y0 >= ypar.p) return;
327
		if (y0 < 0) y0 = 0;
328
		if (y1 >= ypar.p) y1 = ypar.p - 1;
329
		APosPixel pixel(xpar.p, ypar.p, data0, x0, y0);
330
		for (i = y1 - y0; i >= 0; pixel.AddY1(), i--) pixel.SetPixel(c);
331
	}
332
	else
333
	{
334
		long dx = x1 - x0, dy = y1 - y0;
335
		int i;
336
		if (abs(dx) >= abs(dy))
337
		{
338
			if (dx < 0)
339
			{
340
				i = x0; x0 = x1; x1 = i; dx = -dx;
341
				y0 = y1; dy = -dy;
342
			}
343
			long vy = 0, b_x = dx / 2;
344
			APosPixel pixel(xpar.p, ypar.p, data0, x0, y0);
345
			for (i = x0;; i++, pixel.AddX1())
346
			{
347
				pixel.SetPixel(c);
348
				if (i >= x1) break;
349
				vy += dy;
350
				if (vy > b_x)
351
				{
352
					vy -= dx;
353
					pixel.AddY1();
354
				}
355
				else if (vy < -b_x)
356
				{
357
					vy += dx;
358
					pixel.SubY1();
359
				}
360
			}
361
		}
362
		else
363
		{
364
			if (dy < 0)
365
			{
366
				i = y0; y0 = y1; y1 = i; dy = -dy;
367
				x0 = x1; dx = -dx;
368
			}
369
			long vx = 0, b_y = dy / 2;
370
			APosPixel pixel(xpar.p, ypar.p, data0, x0, y0);
371
			for (i = y0;; i++, pixel.AddY1())
372
			{
373
				pixel.SetPixel(c);
374
				if (i >= y1) break;
375
				vx += dx;
376
				if (vx > b_y)
377
				{
378
					vx -= dy;
379
					pixel.AddX1();
380
				}
381
				else if (vx < -b_y)
382
				{
383
					vx += dy;
384
					pixel.SubX1();
385
				}
386
			}
387
		}
388
	}
389
}
390
 
391
void FillCircle(int x0, int y0, int r, bool c, unsigned char *data0 = life_data)
392
{
393
	int x = 0, y = r, v = 0;
394
	while (x <= y)
395
	{
396
		DrawLine(x0 - x, y0 + y, x0 + x, y0 + y, c, data0);
397
		if (y) DrawLine(x0 - x, y0 - y, x0 + x, y0 - y, c, data0);
398
		if (x < y)
399
		{
400
			DrawLine(x0 - y, y0 + x, x0 + y, y0 + x, c, data0);
401
			DrawLine(x0 - y, y0 - x, x0 + y, y0 - x, c, data0);
402
		}
403
		v += 2 * (x++) + 1;
404
		if (v >= y) v -= 2 * (y--) - 1;
405
	}
406
}
407
 
408
void RandomDraw(unsigned char *data0 = life_data)
409
{
410
	if (!data0 || random(300) >= 1) return;
411
	int d = xpar.p;
412
	if (d > ypar.p) d = ypar.p;
413
	data0 = (unsigned char*)GetDataAddress(data0);
414
	d = random((d * 3) / 4);
415
	int x = random(xpar.p - d), y = random(ypar.p - d);
416
	if (random(10) < 1)
417
	{
418
		int NBusy, NTest = 4096;
419
		NBusy = 5 * xpar.p * ypar.p;
420
		if (NTest > NBusy) NTest = NBusy;
421
		NBusy = 0;
422
		for (int k = 0; k < NTest; k++)
423
		{
424
			if (GetDataBit(GetDataWidth(xpar.p), GetDataHeight(ypar.p), data0, random(xpar.p), random(ypar.p))) NBusy++;
425
		}
426
		if (NBusy * 100 < NTest)
427
		{
428
			if (random(3) == 0)
429
			{
430
				DrawLine(x, y, x + d, y + d, true, data0);
431
				DrawLine(x, y + d, x + d, y, true, data0);
432
			}
433
			else
434
			{
435
				DrawLine(x + d/2, y, x + d/2, y + d, true, data0);
436
				DrawLine(x, y + d/2, x + d, y + d/2, true, data0);
437
			}
438
			return;
439
		}
440
	}
441
	if (2*d < xpar.p && 2*d < ypar.p && random(10) < 3)
442
	{
443
		FillCircle(x + d/2, y + d/2, d/2, false, data0);
444
	}
445
	else if (random(2)) DrawLine(x, y, x + d, y + d, true, data0);
446
	else DrawLine(x, y + d, x + d, y, true, data0);
447
}
448
 
449
void LineInScreen(int ax, int ay, int bx, int by, bool c, unsigned char *data0 = life_data)
450
{
451
	int mul = 1, sbeg, send, t0, t1;
452
	if (ax != bx) mul *= abs(ax - bx);
453
	if (ay != by) mul *= abs(ay - by);
454
	sbeg = 0; send = mul;
455
	if (ax != bx)
456
	{
457
		t0 = ax * (mul / (ax - bx));
458
		t1 = (ax - xpar.p + 1) * (mul / (ax - bx));
459
		if (t0 < t1)
460
		{
461
			if (sbeg < t0) sbeg = t0;
462
			if (send > t1) send = t1;
463
		}
464
		else
465
		{
466
			if (sbeg < t1) sbeg = t1;
467
			if (send > t0) send = t0;
468
		}
469
	}
470
	else if (ax < 0 || ax >= xpar.p) return;
471
	if (ay != by)
472
	{
473
		t0 = ay * (mul / (ay - by));
474
		t1 = (ay - ypar.p + 1) * (mul / (ay - by));
475
		if (t0 < t1)
476
		{
477
			if (sbeg < t0) sbeg = t0;
478
			if (send > t1) send = t1;
479
		}
480
		else
481
		{
482
			if (sbeg < t1) sbeg = t1;
483
			if (send > t0) send = t0;
484
		}
485
	}
486
	else if (ay < 0 || ay > ypar.p) return;
487
	if (send < sbeg) return;
488
	DrawLine(ax + (bx - ax) * sbeg / mul, ay + (by - ay) * sbeg / mul,
489
			ax + (bx - ax) * send / mul, ay + (by - ay) * send / mul, c, data0);
490
}
491
 
492
int GetRadius(int ax, int ay, int bx, int by)
493
{
494
	int s, t0, t1, t, tt;
495
	bx -= ax; by -= ay;
496
	s = bx*bx + by*by;
497
	t0 = 0; t1 = s;
498
	while (t0 + 1 < t1)
499
	{
500
		t = (t0 + t1) / 2;
501
		tt = t*t;
502
		if (tt / t == t && s > tt + t) t0 = t; else t1 = t;
503
	}
504
	return t1;
505
}
506
 
507
int ReadNumberFromString(const unsigned char *&str)
508
{
509
	int x = 0, s = 1;
510
	while (*str == ' ' || *str == '\t' || *str == '\r') str++;
511
	if (*str == '-') {s = -1; str++;}
512
	else if (*str == '+') str++;
513
	while (*str >= '0' && *str <= '9')
514
	{
515
		x = 10*x + (*str - '0');
516
		str++;
517
	}
518
	return x*s;
519
}
520
 
521
const unsigned char *StringPrefSpace(const unsigned char *pict, int size, const unsigned char *pref)
522
{
523
	const unsigned char *pict_end = pict + size;
524
	for (;;)
525
	{
526
		if (!*pref) return pict;
527
		else if (*pref == ' ')
528
		{
529
			if (pict >= pict_end || !(*pict == ' ' || *pict == '\t' || *pict == '\r')) return 0;
530
			while (pict < pict_end && (*pict == ' ' || *pict == '\t' || *pict == '\r')) pict++;
531
			pref++;
532
		}
533
		else if (*pref == '\n')
534
		{
535
			while (pict < pict_end && (*pict == ' ' || *pict == '\t' || *pict == '\r')) pict++;
536
			if (pict >= pict_end || *pict != '\n') return 0;
537
			pict++; pref++;
538
		}
539
		else if (pict >= pict_end || *pict != *pref) return 0;
540
		else {pict++; pref++;}
541
	}
542
}
543
 
544
int LifeGetPictureType(const unsigned char *&pict, int size)
545
{
546
	const unsigned char *p;
547
	p = StringPrefSpace(pict, size, (const unsigned char*)"#LifeBin 2.0\n");
548
	if (p && p + 4 <= pict + size) {pict = p; return 1;}
549
	p = StringPrefSpace(pict, size, (const unsigned char*)"#Life 1.05\n");
550
	if (p) {pict = p; return 2;}
551
	if (size >= 54 && pict[0] == 'B' && pict[1] == 'M' && *(int*)(pict+6) == 0 &&
552
		*(int*)(pict+14) == 0x28 && *(short*)(pict+26) == 1 && *(int*)(pict+30) == 0 &&
553
		*(short*)(pict+28) > 0 && *(short*)(pict+28) <= 32 &&
554
		*(int*)(pict+18) >= 0 && *(int*)(pict+22) >= 0 &&
555
		*(int*)(pict+10) >= 54 && *(int*)(pict+10) <= *(int*)(pict+2) &&
556
		*(int*)(pict+2) <= size && *(int*)(pict+34) >= 0 &&
557
		*(int*)(pict+34) <= *(int*)(pict+2) - *(int*)(pict+10) &&
558
		*(int*)(pict+46) <= 256 && *(int*)(pict+50) <= *(int*)(pict+46) &&
559
		(*(short*)(pict+28) >= 8 || *(int*)(pict+46) <= (1 << *(short*)(pict+28))))
560
	{
561
		if (*(int*)(pict+18) == 0 || *(int*)(pict+22) == 0) return 3;
562
		int s = *(int*)(pict+34);
563
		if (s == 0)
564
		{
565
			s = ((*(int*)(pict+18) * *(short*)(pict+28) - 1) / 32 + 1) * *(int*)(pict+22) * 4;
566
		}
567
		if (s > 0 && s <= *(int*)(pict+2) - *(int*)(pict+10))
568
		{
569
			s /= *(int*)(pict+22);
570
			if (s < (1 << 28) && (s * 8) / *(short*)(pict+28) >= *(int*)(pict+18)) return 3;
571
		}
572
	}
573
	return 0;
574
}
575
 
576
void LifeGetPictureSize(int &w, int &h, const unsigned char *pict, int size)
577
{
578
	const unsigned char *pict_end = pict + size;
579
	int type = LifeGetPictureType(pict, size);
580
	w = 0; h = 0;
581
	if (type == 1)
582
	{
583
		w = (int)pict[0] + ((int)pict[1] << 8);
584
		h = (int)pict[2] + ((int)pict[3] << 8);
585
	}
586
	else if (type == 2)
587
	{
588
		int x = 0, y = 0, xb = x;
589
		int x0 = 0, y0 = 0, x1 = -1, y1 = -1;
590
		while (pict < pict_end && *pict)
591
		{
592
			while (pict < pict_end && *pict == '\n') pict++;
593
			if (pict < pict_end && *pict == '#')
594
			{
595
				pict++;
596
				if (pict < pict_end && (*pict == 'p' || *pict == 'P'))
597
				{
598
					pict++;
599
					x = ReadNumberFromString(pict);
600
					y = ReadNumberFromString(pict);
601
					xb = x;
602
				}
603
				while (pict < pict_end && *pict)
604
				{
605
					if (*pict == '\n') {pict++; break;}
606
					pict++;
607
				}
608
				continue;
609
			}
610
			for (; pict < pict_end && *pict; pict++)
611
			{
612
				if (*pict == '\n')
613
				{
614
					x = xb; y++;
615
					if (pict + 1 < pict_end && pict[1] == '#') break;
616
					continue;
617
				}
618
				else if (*pict == '\r') continue;
619
				if (*pict == '*')
620
				{
621
					if (x0 > x) x0 = x;
622
					if (x1 < x) x1 = x;
623
					if (y0 > y) y0 = y;
624
					if (y1 < y) y1 = y;
625
				}
626
				x++;
627
			}
628
		}
629
		x0 = -2*x0; x1 = 2*x1 + 1;
630
		y0 = -2*y0; y1 = 2*y1 + 1;
631
		w = (x0 < x1) ? x1 : x0;
632
		h = (y0 < y1) ? y1 : y0;
633
	}
634
	else if (type == 3)
635
	{
636
		w = *(int*)(pict+18);
637
		h = *(int*)(pict+22);
638
		if (w == 0) h = 0;
639
		else if (h == 0) w = 0;
640
	}
641
}
642
 
643
void LifePutPicture(int x0, int y0, const unsigned char *pict, int size, unsigned char *data0 = life_data)
644
{
645
	const unsigned char *pict_end = pict + size;
646
	int type = LifeGetPictureType(pict, size);
647
	if (type == 1)
648
	{
649
		int w = (int)pict[0] + ((int)pict[1] << 8);
650
		int h = (int)pict[2] + ((int)pict[3] << 8);
651
		if (w && h)
652
		{
653
			int i, j, x, y;
654
			pict += 4;
655
			x0 -= w / 2; y0 -= h / 2;
656
			x = x0 + w; y = y0 - 1;
657
			APosPixel pixel(xpar.p, ypar.p, data0);
658
			while (pict < pict_end)
659
			{
660
				if (x >= x0 + w)
661
				{
662
					i = (x - x0) / w;
663
					x -= i * w; y += i;
664
					if (y >= y0 + h) break;
665
					j = 0;
666
					if (x >= 0 && x < xpar.p) j |= 1;
667
					if (y >= 0 && y < ypar.p) j |= 2;
668
					if (j == 3)	pixel.SetTo(x, y);
669
				}
670
				i = *(pict++);
671
				if (i == 0)
672
				{
673
					if (j == 3) pixel.Set1Pixel();
674
					i = 1;
675
				}
676
				x += i;
677
				if ((j & 2) && x < x0 + w)
678
				{
679
					if (x >= 0 && x < xpar.p)
680
					{
681
						if ((j & 1) && i < 5)
682
						{
683
							while (i--) pixel.AddX1();
684
						}
685
						else
686
						{
687
							j |= 1;
688
							pixel.SetTo(x, y);
689
						}
690
					}
691
					else j &= ~1;
692
				}
693
			}
694
		}
695
	}
696
	else if (type == 2)
697
	{
698
		int x = x0, y = y0, xb = x;
699
		while (pict < pict_end && *pict)
700
		{
701
			while (pict < pict_end && *pict == '\n') pict++;
702
			if (pict < pict_end && *pict == '#')
703
			{
704
				pict++;
705
				if (pict < pict_end && (*pict == 'p' || *pict == 'P'))
706
				{
707
					pict++;
708
					x = x0 + ReadNumberFromString(pict);
709
					y = y0 + ReadNumberFromString(pict);
710
					xb = x;
711
				}
712
				while (pict < pict_end && *pict)
713
				{
714
					if (*pict == '\n') {pict++; break;}
715
					pict++;
716
				}
717
				continue;
718
			}
719
			if (y >= ypar.p || x >= xpar.p)
720
			{
721
				for (; pict < pict_end && *pict; pict++) if (*pict == '\n')
722
				{
723
					y++;
724
					if (pict + 1 < pict_end && pict[1] == '#') break;
725
				}
726
				continue;
727
			}
728
			if (y < 0)
729
			{
730
				for (; pict < pict_end && *pict; pict++) if (*pict == '\n')
731
				{
732
					y++;
733
					if (y >= 0 || (pict + 1 < pict_end && pict[1] == '#')) break;
734
				}
735
				if (pict + 1 < pict_end && *pict == '\n' && pict[1] == '#') continue;
736
			}
737
			APosPixel pixel(xpar.p, ypar.p, data0);
738
			if (x >= 0) pixel.SetTo(x, y);
739
			for (; pict < pict_end && *pict; pict++)
740
			{
741
				if (*pict == '\n')
742
				{
743
					x = xb; y++;
744
					if (y >= ypar.p) break;
745
					if (x >= 0) pixel.SetTo(x, y);
746
					if (pict + 1 < pict_end && pict[1] == '#') break;
747
					continue;
748
				}
749
				else if (*pict == '\r') continue;
750
				if (*pict == '*') pixel.Set1Pixel();
751
				x++;
752
				if (x < 0) continue;
753
				if (x >= xpar.p)
754
				{
755
					while (pict < pict_end && *pict && *pict != '\n') pict++;
756
					if (pict < pict_end && *pict == '\n') pict--;
757
					continue;
758
				}
759
				if (x == 0) pixel.SetTo(0, y);
760
				else pixel.AddX1();
761
			}
762
		}
763
	}
764
	else if (type == 3)
765
	{
766
		int w = *(int*)(pict+18), h = *(int*)(pict+22);
767
		if (w && h)
768
		{
769
			int n, i, j;
770
			unsigned char ch;
771
			const unsigned char *p = pict + *(int*)(pict+10);
772
			short bp = *(short*)(pict+28);
773
			int s = *(int*)(pict+34);
774
			x0 -= w / 2; y0 -= h / 2;
775
			if (x0 < xpar.p && y0 < ypar.p && x0 + w > 0 && y0 + h > 0)
776
			{
777
				if (s) s /= *(int*)(pict+22);
778
				else s = ((*(int*)(pict+18) * *(short*)(pict+28) - 1) / 32 + 1) * 4;
779
				n = (*(int*)(pict+10) - 54) / 4;
780
				APosPixel pixel(xpar.p, ypar.p, data0);
781
				if (y0 + h <= ypar.p) i = h - 1;
782
				else
783
				{
784
					i = ypar.p - y0 - 1;
785
					p += (ypar.p - y0) * s;
786
				}
787
				for (; i >= 0; i--)
788
				{
789
					int tj = 0, tl = 0;
790
					if (y0 + i < 0) break;
791
					if (x0 > 0) pixel.SetTo(x0, y0 + i);
792
					for (j = 0; j < 8*s; j += 8)
793
					{
794
						if (tj >= w || x0 + tj >= xpar.p) {p += (s - j/8); break;}
795
						ch = *(p++);
796
						while (tj < w && x0 + tj < xpar.p && j + 8 >= (tj+1) * bp)
797
						{
798
							union
799
							{
800
								long za;
801
								unsigned char z[4];
802
							};
803
 
804
							tl |= (unsigned long)(ch) >> ((int)j + 8 - (tj+1) * bp);
805
							if (n)
806
							{
807
								if (tl >= n) za = 0;
808
								else
809
								{
810
									const unsigned char *zp = pict + 54 + 4*tl;
811
									z[0] = zp[3];
812
									z[1] = zp[2];
813
									z[2] = zp[1];
814
									z[3] = zp[0];
815
								}
816
							}
817
							else if (bp == 8)
818
							{
819
								z[0] = 0;
820
								z[1] = z[2] = z[3] = (char)tl;
821
							}
822
							else if (bp == 32) za = tl;
823
							else za = tl << (32 - bp);
824
 
825
							if (x0 + tj >= 0)
826
							{
827
								if (x0 + tj == 0) pixel.SetTo(0, y0 + i);
828
								else pixel.AddX1();
829
								if ((int)z[1] + (int)z[2] + (int)z[3] >= 384)
830
								{
831
									pixel.Set1Pixel();
832
								}
833
							}
834
 
835
							tl = 0;
836
							ch &= (unsigned char)((1 << ((int)j + 8 - (tj+1) * bp)) - 1);
837
							tj++;
838
						}
839
						tl |= (int)ch << ((tj+1) * bp - (j + 8));
840
					}
841
				}
842
			}
843
		}
844
	}
845
}
846
 
847
void ApplyHit(unsigned char *data1 = life_data, unsigned char *data0 = 0)
848
{
849
	if (!data0) data0 = data1;
850
	if (!data0) return;
851
	data0 = (unsigned char*)GetDataAddress(data0);
852
	data1 = (unsigned char*)GetDataAddress(data1);
853
	if (data0 != data1 && mpar.hit_type != MouseParam::HitScroll)
854
	{
855
		MemCopy(data0, data1, GetDataSize(xpar.p, ypar.p));
856
	}
857
	switch (mpar.hit_type)
858
	{
859
	case MouseParam::HitLine:
860
		LineInScreen(mpar.hit_x, mpar.hit_y, mpar.last_x, mpar.last_y, true, data0);
861
		break;
862
	case MouseParam::HitCircle:
863
		FillCircle(mpar.hit_x, mpar.hit_y,
864
				GetRadius(mpar.hit_x, mpar.hit_y, mpar.last_x, mpar.last_y), false, data0);
865
		break;
866
	case MouseParam::HitScroll:
867
		ApplyScroll(data1, data0);
868
		break;
869
	}
870
}
871
 
872
void MoveGenerateTime(unsigned int t)
873
{
874
	static const unsigned int COUNT_MAX = 1 << 24;
875
 
876
	if (generate.stop)
877
	{
878
		if (generate.count > COUNT_MAX) generate.count = COUNT_MAX;
879
	}
880
	else if (!generate.gps) generate.count = COUNT_MAX;
881
	else if (t > 100 || generate.count >= generate.gps)
882
	{
883
		generate.count = generate.gps;
884
	}
885
	else if (t)
886
	{
887
		generate.count += (generate.gps * t -
888
					(((generate.time + t) % 100U) * generate.gps) % 100 +
889
					((generate.time % 100U) * generate.gps) % 100) / 100;
890
		if (generate.count > generate.gps) generate.count = generate.gps;
891
	}
892
	generate.time += t;
893
	if (timegen[timegenpos].t > (~t)) timegen[timegenpos].t = -1;
894
	else timegen[timegenpos].t += t;
895
}
896
 
897
void ResetGenerate()
898
{
899
	generate.time = Clock();
900
	generate.paint_time = generate.time - 100;
901
	generate.count = 0;
902
	if (generate.stop)
903
	{
904
		generate.stop = false;
905
		menu.button[MenuIGenerate].check = false;
906
	}
907
}
908
 
909
void InitGenerate()
910
{
911
	int i;
912
	for (i = 0; i < TimeGenLength; i++)
913
	{
914
		timegen[timegenpos].t = -1;
915
		timegen[timegenpos].g = 0;
916
	}
917
	ResetGenerate();
918
}
919
 
920
bool AddGenerateCount(int c)
921
{
922
	if (c < 0) return false;
923
	if (!menu.button[MenuIGenerate].check)
924
	{
925
		ResetGenerate();
926
		menu.button[MenuIGenerate].check = true;
927
		generate.paint |= PaintWMenuBorder | PaintWSpeed;
928
		generate.stop = true;
929
		generate.count += c;
930
	}
931
	else if (generate.stop) generate.count += c;
932
	else return false;
933
	return true;
934
}
935
 
936
void InitMenuButton()
937
{
938
	int i;
939
	const unsigned char *p = menu_picture, *p_end = menu_picture + sizeof(menu_picture);
940
	const unsigned int separator = 5;
941
	for (i = 0; i < MenuParam::NButton; i++)
942
	{
943
		menu.button[i].left = 0;
944
		menu.button[i].size = MenuParam::Size - 2;
945
		menu.button[i].border = 2;
946
		menu.button[i].check = false;
947
		menu.button[i].bitmap = p;
948
		if (p && !p[0])
949
		{
950
			menu.button[i].bitmap = 0;
951
			if (p[1]) p = 0;
952
		}
953
		if (p)
954
		{
955
			p += 2 + 3 * (int)p[0] * (int)p[1];
956
			if (p > p_end) menu.button[i].bitmap = 0;
957
			if (p >= p_end) p = 0;
958
		}
959
	}
960
	p = digits_picture; p_end = digits_picture + sizeof(digits_picture);
961
	for (i = 0; i < MenuDig; i++)
962
	{
963
		menu.digit[i] = p;
964
		if (p && !p[0])
965
		{
966
			menu.digit[i] = 0;
967
			if (p[1]) p = 0;
968
		}
969
		if (p)
970
		{
971
			p += 2 + ((int)p[0] * (int)p[1] + 7) / 8;
972
			if (p > p_end) menu.digit[i] = 0;
973
			if (p >= p_end) p = 0;
974
		}
975
	}
976
	menu.draw = false;
977
	menu.pressed = -1;
978
	menu.current = MenuILine;
979
	menu.edit = -1;
980
	menu.button[menu.current].check = true;
981
	menu.button[MenuIHide].size /= 2;
982
	menu.button[MenuIGenerate].left += separator;
983
	menu.button[MenuIGenerate].check = true;
984
	menu.button[MenuIRandom].check = true;
985
	menu.button[MenuILine].left += separator;
986
	menu.button[MenuIWinSize].left += separator;
987
	menu.button[MenuISize].size += 80;
988
	menu.button[MenuISpeed].left += separator;
989
	menu.button[MenuISpeed].size += 60;
990
	menu.button[0].left = 1;
991
	for (i = 1; i < MenuParam::NButton; i++)
992
	{
993
		menu.button[i].left += menu.button[i-1].left + menu.button[i-1].size;
994
	}
995
}
996
 
997
int GetMenuYPos()
998
{
999
	return 0;
1000
}
1001
 
1002
int GetMenuHeight()
1003
{
1004
	if (!menu.draw) return 0;
1005
	return (ypar.win <= MenuParam::Size) ? 0 : MenuParam::Size;
1006
}
1007
 
1008
int GetMenuNumber(int k, int i)
1009
{
1010
	if (k == menu.edit) return menu.edit_num[i];
1011
	switch (k)
1012
	{
1013
	case MenuISize:
1014
		return i ? ypar.p : xpar.p;
1015
	case MenuISpeed:
1016
		return menu.button[MenuIGenerate].check ? (int)Floor(generate.speed + 0.5) : 0;
1017
	default:
1018
		return 0;
1019
	}
1020
}
1021
 
1022
void WinDrawRect(int x, int y, int w, int h, const unsigned char *const *color)
1023
{
1024
	unsigned char *p = picture + 3 * (y * xpar.win + x);
1025
	int j;
1026
	w--; h--;
1027
	for (j = w; j > 0; j--)
1028
	{
1029
		p[0] = color[0][0]; p[1] = color[0][1]; p[2] = color[0][2];
1030
		p += 3;
1031
	}
1032
	for (j = h; j > 0; j--)
1033
	{
1034
		p[0] = color[1][0]; p[1] = color[1][1]; p[2] = color[1][2];
1035
		p += 3 * xpar.win;
1036
	}
1037
	for (j = w; j > 0; j--)
1038
	{
1039
		p[0] = color[2][0]; p[1] = color[2][1]; p[2] = color[2][2];
1040
		p -= 3;
1041
	}
1042
	for (j = h; j > 0; j--)
1043
	{
1044
		p[0] = color[3][0]; p[1] = color[3][1]; p[2] = color[3][2];
1045
		p -= 3 * xpar.win;
1046
	}
1047
}
1048
 
1049
void WinFillRect(int x, int y, int w, int h, const unsigned char *color)
1050
{
1051
	if (x >= xpar.win || y >= ypar.win || w <= 0 || h <= 0) return;
1052
	if (w > xpar.win - x) w = xpar.win - x;
1053
	if (h > ypar.win - y) h = ypar.win - y;
1054
	unsigned char *p, *pp = picture + 3 * (y * xpar.win + x);
1055
	int i, j;
1056
	for (i = h; i > 0; i--)
1057
	{
1058
		p = pp;
1059
		for (j = w; j > 0; j--)
1060
		{
1061
			*(p++) = color[0]; *(p++) = color[1]; *(p++) = color[2];
1062
		}
1063
		pp += 3 * xpar.win;
1064
	}
1065
}
1066
 
1067
void WinBitmapRect(int x, int y, const unsigned char *bmp)
1068
{
1069
	if (!bmp || !bmp[0] || !bmp[1]) return;
1070
	int w = bmp[0], h = bmp[1], strl = 3 * (int)bmp[0];
1071
	bmp += 2;
1072
	x -= w/2; y -= h/2;
1073
	if (x >= xpar.win || y >= ypar.win) return;
1074
	if (w > xpar.win - x) w = xpar.win - x;
1075
	if (h > ypar.win - y) h = ypar.win - y;
1076
	unsigned char *p, *pp = picture + 3 * (y * xpar.win + x);
1077
	const unsigned char *b;
1078
	int i, j;
1079
	for (i = h; i > 0; i--)
1080
	{
1081
		p = pp; b = bmp;
1082
		for (j = w; j > 0; j--)
1083
		{
1084
			*(p++) = *(b++); *(p++) = *(b++); *(p++) = *(b++);
1085
		}
1086
		pp += 3 * xpar.win; bmp += strl;
1087
	}
1088
}
1089
 
1090
void WinBitSetRect(int x, int y, const unsigned char *set, const unsigned char *color)
1091
{
1092
	if (!set || !set[0] || !set[1]) return;
1093
	int w = set[0], h = set[1], strr = (int)set[0];
1094
	set += 2;
1095
	x -= w/2; y -= h/2;
1096
	if (x >= xpar.win || y >= ypar.win) return;
1097
	if (w > xpar.win - x) w = xpar.win - x;
1098
	if (h > ypar.win - y) h = ypar.win - y;
1099
	strr -= w;
1100
	unsigned char *p, *pp = picture + 3 * (y * xpar.win + x);
1101
	int i, j, m = 1;
1102
	for (i = h; i > 0; i--)
1103
	{
1104
		p = pp;
1105
		for (j = w; j > 0; j--)
1106
		{
1107
			if (*set & m) {p[0] = color[0]; p[1] = color[1]; p[2] = color[2];}
1108
			p += 3;
1109
			m <<= 1;
1110
			if (!(m & 255)) {m = 1; set++;}
1111
		}
1112
		pp += 3 * xpar.win;
1113
		m <<= strr % 8; set += strr / 8;
1114
		if (!(m & 255)) {m >>= 8; set++;}
1115
	}
1116
}
1117
 
1118
void WinNumberRect(int x, int y, unsigned int n, const unsigned char *color)
1119
{
1120
	int w, m, i;
1121
	w = 0; m = n;
1122
	do
1123
	{
1124
		i = m % MenuDig; m /= MenuDig;
1125
		if (menu.digit[i]) w += 2 + menu.digit[i][0];
1126
	} while(m);
1127
	if (w <= 2) return;
1128
	x += w - (w-2) / 2;
1129
	m = n;
1130
	do
1131
	{
1132
		i = m % MenuDig; m /= MenuDig;
1133
		if (menu.digit[i])
1134
		{
1135
			x -= 2 + menu.digit[i][0];
1136
			WinBitSetRect(x + menu.digit[i][0] / 2, y, menu.digit[i], color);
1137
		}
1138
	} while(m);
1139
}
1140
 
1141
void WinNumberEditRect(int x, int y, int w, int h, unsigned int n,
1142
			const unsigned char *color, const unsigned char *bg_color)
1143
{
1144
	if (bg_color) WinFillRect(x, y, w, h, bg_color);
1145
	WinNumberRect(x + w/2, y + h/2, n, color);
1146
}
1147
 
1148
void MenuPaint(int what)
1149
{
1150
	static const unsigned char color_light0[3] = {255, 255, 255};
1151
	static const unsigned char color_light[3] = {208, 208, 208};
1152
	static const unsigned char color_face[3] = {192, 192, 192};
1153
	static const unsigned char color_shadow[3] = {128, 128, 128};
1154
	static const unsigned char color_shadow0[3] = {64, 64, 64};
1155
	static const unsigned char color_black[3] = {0, 0, 0};
1156
	static const unsigned char (&color_white)[3] = color_light0;
1157
 
1158
	if (GetMenuHeight() < MenuParam::Size) return;
1159
	const unsigned char *color[4];
1160
	int menuy = GetMenuYPos(), i, k, x, xx, y, yy;
1161
	if ((what & PaintWSpeed) && !(what & (PaintWMenu & ~PaintWMenuBorder)) &&
1162
				menu.button[MenuISpeed].Right() < xpar.win)
1163
	{
1164
		k = MenuISpeed;
1165
		i = menu.button[k].border + 1;
1166
		xx = menu.button[k].Left() + i;
1167
		yy = menuy + 1 + i;
1168
		x = menu.button[k].size - 2*i;
1169
		y = MenuParam::Size - 2 - 2*i;
1170
		i = 0;
1171
		if (menu.button[k].bitmap) i += menu.button[k].bitmap[0] + 2;
1172
		WinNumberEditRect(xx + i, yy, x - i, y, GetMenuNumber(k, 0), color_black,
1173
					(menu.edit == k && menu.edit_index == 0) ? color_white : color_face);
1174
	}
1175
	if (!(what & PaintWMenu)) return;
1176
	if (what & (PaintWMenu & ~PaintWMenuBorder))
1177
	{
1178
		x = menu.button[MenuParam::NButton - 1].Right();
1179
		WinFillRect(0, menuy, x, 1, color_face);
1180
		WinFillRect(0, menuy + MenuParam::Size - 1, x, 1, color_face);
1181
		WinFillRect(x, menuy, xpar.win - x, MenuParam::Size, color_face);
1182
	}
1183
	for (k = 0; k < MenuParam::NButton; k++)
1184
	{
1185
		xx = menu.button[k].Left();
1186
		yy = menuy + 1;
1187
		x = menu.button[k].size;
1188
		y = MenuParam::Size - 2;
1189
		if (xx + x >= xpar.win)
1190
		{
1191
			if (what & (PaintWMenu & ~PaintWMenuBorder))
1192
			{
1193
				i = (k >= 1) ? menu.button[k-1].Right() : 0;
1194
				WinFillRect(i, yy, xpar.win - i, y, color_face);
1195
			}
1196
			break;
1197
		}
1198
		if (what & (PaintWMenu & ~PaintWMenuBorder))
1199
		{
1200
			i = (k >= 1) ? menu.button[k-1].Right() : 0;
1201
			WinFillRect(i, yy, xx - i, y, color_face);
1202
		}
1203
		for (i = 0; i < menu.button[k].border; i++)
1204
		{
1205
			if (i <= 1)
1206
			{
1207
				if (menu.button[k].check)
1208
				{
1209
					color[0] = color[3] = i ? color_shadow : color_shadow0;
1210
					color[1] = color[2] = i ? color_light : color_light0;
1211
				}
1212
				else
1213
				{
1214
					color[0] = color[3] = i ? color_light : color_light0;
1215
					color[1] = color[2] = i ? color_shadow : color_shadow0;
1216
				}
1217
			}
1218
			WinDrawRect(xx, yy, x, y, color);
1219
			xx++; yy++; x -= 2; y -= 2;
1220
		}
1221
		if (what & (PaintWMenu & ~PaintWMenuBorder))
1222
		{
1223
			WinFillRect(xx, yy, x, y, color_face);
1224
			if (menu.button[k].bitmap)
1225
			{
1226
				i = (k == MenuISpeed) ? (1 + menu.button[k].bitmap[0] / 2) : (x / 2);
1227
				WinBitmapRect(xx + i, yy + y/2, menu.button[k].bitmap);
1228
			}
1229
			if (k == MenuISize)
1230
			{
1231
				xx++; yy++; x -= 2; y -= 2;
1232
				i = x - 4;
1233
				if (menu.button[k].bitmap) i -= menu.button[k].bitmap[0];
1234
				i /= 2;
1235
				WinNumberEditRect(xx, yy, i, y, GetMenuNumber(k, 0), color_black,
1236
							(menu.edit == k && menu.edit_index == 0) ? color_white : 0);
1237
				WinNumberEditRect(xx + x - i, yy, i, y, GetMenuNumber(k, 1), color_black,
1238
							(menu.edit == k && menu.edit_index == 1) ? color_white : 0);
1239
			}
1240
			else if (k == MenuISpeed)
1241
			{
1242
				xx++; yy++; x -= 2; y -= 2;
1243
				i = 0;
1244
				if (menu.button[k].bitmap) i += menu.button[k].bitmap[0] + 2;
1245
				WinNumberEditRect(xx + i, yy, x - i, y, GetMenuNumber(k, 0), color_black,
1246
							(menu.edit == k && menu.edit_index == 0) ? color_white : 0);
1247
			}
1248
		}
1249
	}
1250
}
1251
 
1252
void Paint(int what, TThreadData th);
1253
 
1254
void SetMenuDraw(bool draw, TThreadData th)
1255
{
1256
	if (draw == menu.draw) return;
1257
	if (menu.pressed >= 0) menu.button[menu.pressed].check = false;
1258
	menu.pressed = -1;
1259
	menu.draw = draw;
1260
	Paint(PaintWAll | PaintWFast, th);
1261
}
1262
 
1263
void SetMenuPressed(int k, TThreadData th)
1264
{
1265
	if (menu.pressed == k) return;
1266
	if (menu.pressed >= 0) menu.button[menu.pressed].check = false;
1267
	if (k >= 0) menu.button[k].check = true;
1268
	menu.pressed = k;
1269
	Paint(PaintWMenuBorder | PaintWFast, th);
1270
}
1271
 
1272
void SetMenuCurrent(int k, TThreadData th)
1273
{
1274
	if (menu.current == k) return;
1275
	if (menu.current >= 0) menu.button[menu.current].check = false;
1276
	if (k >= 0) menu.button[k].check = true;
1277
	menu.current = k;
1278
	Paint(PaintWMenuBorder | PaintWFast, th);
1279
}
1280
 
1281
void SetMenuEdit(int k, int i, TThreadData th)
1282
{
1283
	if (menu.edit != k)
1284
	{
1285
		if (menu.edit >= 0) menu.button[menu.edit].check = false;
1286
		if (k >= 0) menu.button[k].check = true;
1287
		if (k == MenuISize) {menu.edit_num[0] = xpar.p; menu.edit_num[1] = ypar.p;}
1288
		else if (k == MenuISpeed) menu.edit_num[0] = generate.gps;
1289
	}
1290
	else if (menu.edit_index == i) return;
1291
	if (k == MenuISize) menu.edit_num_max = 32767;
1292
	else if (k == MenuISpeed) menu.edit_num_max = 9999999;
1293
	menu.edit = k; menu.edit_index = i;
1294
	Paint(PaintWMenu | PaintWFast, th);
1295
}
1296
 
1297
void ApplyMenuEdit(TThreadData th)
1298
{
1299
	if (menu.edit < 0) return;
1300
	if (menu.edit == MenuISize)
1301
	{
1302
		int w = menu.edit_num[0], h = menu.edit_num[1];
1303
		ResetGenerate();
1304
		if (xpar.p != w || ypar.p != h)
1305
		{
1306
			if (w <= 0) w = 1;
1307
			if (h <= 0) h = 1;
1308
			SetPoleSize(w, h);
1309
			generate.paint |= PaintWPole | PaintWMenu | PaintWFast;
1310
		}
1311
	}
1312
	else if (menu.edit == MenuISpeed)
1313
	{
1314
		generate.gps = menu.edit_num[0];
1315
	}
1316
	SetMenuEdit(-1, -1, th);
1317
}
1318
 
1319
int GetMenuEditIndex(int k, int x)
1320
{
1321
	if (k == MenuISize) return x >= menu.button[k].left + menu.button[k].size / 2;
1322
	else return 0;
1323
}
1324
 
1325
void LifeScreenPutPicture(const unsigned char *pict, int size, TThreadData th)
1326
{
1327
	int w, h;
1328
	ResetGenerate();
1329
	LifeGetPictureSize(w, h, pict, size);
1330
	w += 10; h += 10;
1331
	if (!life_data || xpar.p < w || ypar.p < h)
1332
	{
1333
		if (xpar.p >= w) w = xpar.p;
1334
		if (ypar.p >= h) h = ypar.p;
1335
		SetPoleSize(w, h);
1336
		if (!life_data)
1337
		{
1338
			Paint(PaintWMenu | PaintWFast, th);
1339
			return;
1340
		}
1341
	}
1342
	MemSet(GetDataAddress(life_data), 0, GetDataSize(xpar.p, ypar.p));
1343
	LifePutPicture(xpar.p / 2, ypar.p / 2, pict, size, life_data);
1344
	menu.button[MenuIRandom].check = false;
1345
	xpar.shift = 0; ypar.shift = 0;
1346
	generate.paint |= PaintWPole | PaintWMenu | PaintWFast;
1347
//	SetMenuCurrent(MenuIScroll, th);
1348
	Paint(PaintWNull, th);
1349
}
1350
 
1351
void MenuOpenDialogEnd(TThreadData th)
1352
{
8252 IgorA 1353
	if(!ofd.openfile_path[0] || !open_file_str) return;
1354
	open_file_str = false;
1355
	char *name = ofd.openfile_path;
1769 yogev_ezra 1356
	if (!name) return;
8184 IgorA 1357
	FileInfoBlock* file = FileOpen(name);
1769 yogev_ezra 1358
	if (!file) return;
1359
	int k = FileGetLength(file);
1360
	unsigned char *pict = 0;
1361
	if (k > 0 && k < (1 << 24))
1362
	{
1363
		pict = (unsigned char*)Alloc(k+1);
1364
		if (pict)
1365
		{
1366
			if (FileRead(file, pict, k) == k) pict[k] = 0;
1367
			else {Free(pict); pict = 0;}
1368
		}
1369
	}
1370
	FileClose(file);
1371
	if (!pict) return;
1372
	LifeScreenPutPicture(pict, k, th);
1373
	Free(pict);
1374
}
1375
 
1376
void MenuWinSizeClick(TThreadData th)
1377
{
1378
	int w = xpar.win, h = ypar.win - GetMenuHeight();
1379
	ResetGenerate();
1380
	if (w > 0 && h > 0 && (xpar.p != w || ypar.p != h))
1381
	{
1382
		SetPoleSize(w, h);
1383
		Paint(PaintWPole | PaintWMenu | PaintWFast, th);
1384
	}
1385
}
1386
 
1387
void MenuGenerateClick(TThreadData th)
1388
{
1389
	generate.stop = false;
1390
	ResetGenerate();
1391
	menu.button[MenuIGenerate].check = !menu.button[MenuIGenerate].check;
1392
	Paint(PaintWMenuBorder | PaintWSpeed | PaintWFast, th);
1393
}
1394
 
1395
void MenuClearClick(TThreadData th)
1396
{
1397
	ResetGenerate();
1398
	if (life_data) MemSet(GetDataAddress(life_data), 0, GetDataSize(xpar.p, ypar.p));
1399
	Paint(PaintWPole | PaintWFast, th);
1400
}
1401
 
1402
void MenuAboutClick(TThreadData th)
1403
{
1404
	generate.stop = false;
1405
	menu.button[MenuIGenerate].check = true;
1406
	generate.paint |= PaintWSpeed;
1407
	LifeScreenPutPicture(about_picture, sizeof(about_picture), th);
1408
}
1409
 
1410
void MenuMouseClick(int x, int y, int m, TThreadData th)
1411
{
1412
	int k, i, j = GetMenuYPos();
1413
	if (menu.edit >= 0)
1414
	{
1415
		k = menu.edit;
1416
		j = GetMenuYPos();
1417
		if (GetMenuHeight() < MenuParam::Size || y < j + 1 || y >= j + MenuParam::Size - 1 ||
1418
					x < menu.button[k].Left() || x >= menu.button[k].Right())
1419
		{
1420
			if (m == 1) ApplyMenuEdit(th);
1421
			else SetMenuEdit(-1, -1, th);
1422
		}
1423
		else SetMenuEdit(k, GetMenuEditIndex(k, x), th);
1424
		return;
1425
	}
1426
	if (GetMenuHeight() < MenuParam::Size || y < j + 1 || y >= j + MenuParam::Size - 1)
1427
	{
1428
		if (m < 0) x = -1;
1429
		else return;
1430
	}
1431
	if (m < 0)
1432
	{
1433
		if (menu.pressed < 0) return;
1434
		k = menu.pressed;
1435
		if (x < menu.button[k].Left() || x >= menu.button[k].Right())
1436
		{
1437
			if (menu.button[k].check)
1438
			{
1439
				menu.button[k].check = false;
1440
				Paint(PaintWMenuBorder | PaintWFast, th);
1441
			}
1442
		}
1443
		else if (!menu.button[k].check)
1444
		{
1445
			menu.button[k].check = true;
1446
			Paint(PaintWMenuBorder | PaintWFast, th);
1447
		}
1448
		return;
1449
	}
1450
	if (m == 0)
1451
	{
1452
		if (menu.pressed < 0 || !menu.button[menu.pressed].check) return;
1453
		switch (menu.pressed)
1454
		{
1455
		case MenuIHide:
1456
			SetMenuDraw(false, th);
1457
			break;
1458
		case MenuIClear:
1459
			MenuClearClick(th);
1460
			break;
1461
		case MenuIOpen:
8252 IgorA 1462
			ofd.type = 0; // 0 - open
1463
			OpenDialog_Start(&ofd);
1464
			if(ofd.status==1) open_file_str = true;
1769 yogev_ezra 1465
			break;
1466
		case MenuIAbout:
1467
			MenuAboutClick(th);
1468
			break;
1469
		case MenuIExit:
1470
			CloseWindow(th);
1471
			break;
1472
		case MenuIWinSize:
1473
			MenuWinSizeClick(th);
1474
			break;
1475
		}
1476
		return;
1477
	}
1478
	k = -1; i = MenuParam::NButton;
1479
	while (k + 1 < i)
1480
	{
1481
		j = (k + i) / 2;
1482
		if (x < menu.button[j].Left()) i = j;
1483
		else k = j;
1484
	}
1485
	i = menu.button[k].Right();
1486
	if (k < 0 || x >= i || i >= xpar.win) return;
1487
	switch (k)
1488
	{
1489
	case MenuIHide:
1490
	case MenuIClear:
1491
	case MenuIOpen:
1492
	case MenuIAbout:
1493
	case MenuIExit:
1494
	case MenuIWinSize:
1495
		SetMenuPressed(k, th);
1496
		break;
1497
	case MenuIGenerate:
1498
		MenuGenerateClick(th);
1499
		break;
1500
	case MenuIRandom:
1501
	case MenuIVCircle:
1502
	case MenuIHCircle:
1503
		menu.button[k].check = !menu.button[k].check;
1504
		Paint(PaintWMenuBorder | PaintWFast, th);
1505
		break;
1506
	case MenuILine:
1507
	case MenuIScroll:
1508
		SetMenuCurrent(k, th);
1509
		break;
1510
	case MenuISize:
1511
	case MenuISpeed:
1512
		SetMenuEdit(k, GetMenuEditIndex(k, x), th);
1513
		break;
1514
	}
1515
}
1516
 
1517
void PoleMouseClick(int m, TThreadData th)
1518
{
1519
	if (m != 1 && m != 2) return;
1520
	mpar.hit_type = MouseParam::HitNull;
1521
	switch (menu.current)
1522
	{
1523
	case MenuILine:
1524
		if (menu.draw)
1525
		{
1526
			menu.button[MenuIRandom].check = false;
1527
			generate.paint |= PaintWMenuBorder | PaintWFast;
1528
			if (m == 1) mpar.hit_type = MouseParam::HitLine;
1529
			else mpar.hit_type = MouseParam::HitCircle;
1530
		}
1531
		break;
1532
	case MenuIScroll:
1533
		if (m == 1) mpar.hit_type = MouseParam::HitScroll;
1534
		break;
1535
	}
1536
	if (mpar.hit_type) Paint(PaintWPole | PaintWFast, th);
1537
	else if (!menu.draw) SetMenuDraw(true, th);
1538
}
1539
 
1540
void MenuEditPressKey(int ch, TThreadData th)
1541
{
1542
	if (menu.edit < 0) return;
1543
	int &num = menu.edit_num[menu.edit_index];
1544
	if (ch == 27) SetMenuEdit(-1, -1, th);
1545
	else if (ch == '\r') ApplyMenuEdit(th);
1546
	else if (ch == 8) {num /= 10; Paint(PaintWMenu | PaintWFast, th);}
1547
	else if (ch >= '0' && ch <= '9')
1548
	{
1549
		num = 10 * num + (ch - '0');
1550
		if (num >= menu.edit_num_max) num = menu.edit_num_max;
1551
		Paint(PaintWMenu | PaintWFast, th);
1552
	}
1553
	else if (menu.edit == MenuISize)
1554
	{
1555
		if (ch == '\t') SetMenuEdit(MenuISize, !menu.edit_index, th);
1556
		else if (ch == 'x' || ch == 'X') SetMenuEdit(MenuISize, 0, th);
1557
		else if (ch == 'y' || ch == 'Y') SetMenuEdit(MenuISize, 1, th);
1558
	}
1559
}
1560
 
1561
void CalculateSpeed()
1562
{
1563
	double t = 0, g = 0, dn, n = 0, st = 0, sg = 0, ss = 0, sp = 0;
1564
	int i = timegenpos;
1565
	do
1566
	{
1567
		if (t >= 500) break;
1568
		g += timegen[i].g;
1569
		dn = timegen[i].g;
1570
		n += dn * (500 - t);
1571
		st += dn * t;
1572
		sg += dn * g;
1573
		ss += dn * t * t;
1574
		sp += dn * g * t;
1575
		if (--i < 0) i = TimeGenLength;
1576
		t += timegen[i].t;
1577
	} while(i != timegenpos);
1578
	ss = n * ss - st * st;
1579
	sp = n * sp - sg * st;
1580
	if (st < 1e-4 || ss < 1e-4 * st * st) g = 0;
1581
	else g = sp / ss;
1582
	generate.speed = 100 * g;
1583
}
1584
 
1585
void Paint(int what, TThreadData th)
1586
{
1587
	what |= generate.paint;
1588
	if (!(what & PaintWAll) || !life_data || xpar.win <= 0 || ypar.win <= 0) return;
1589
 
1590
	const unsigned int FAST_PAINT_TIME = 2, WAIT_PAINT_TIME = 8;
1591
	unsigned int t = Clock() - generate.paint_time;
1592
	unsigned int wt = (what & PaintWFast) ? FAST_PAINT_TIME : WAIT_PAINT_TIME;
1593
	if (!(what & PaintWNow) && t >= (unsigned int)(-WAIT_PAINT_TIME))
1594
	{
1595
		if ((unsigned int)(-t) > wt) generate.paint_time += t + wt;
1596
		generate.paint = what;
1597
		return;
1598
	}
1599
	generate.paint_time += t + wt;
1600
	generate.paint = PaintWNull;
1601
 
1602
	if (!picture)
1603
	{
1604
		SetPictureSize();
1605
		if (!picture) return;
1606
	}
1607
	if (what & PaintWPole)
1608
	{
1609
		const unsigned char bgcolor[3] = {128, 128, 0};
1610
		int w, h, x, y, xx, yy, i, j;
1611
		int menu0 = GetMenuYPos(), menu1 = menu0 + GetMenuHeight();
1612
		unsigned char *p = picture;
1613
		unsigned char *data0 = (unsigned char*)GetDataAddress(life_data);
1614
		int size = GetDataSize(xpar.p, ypar.p);
1615
		if (xpar.win <= 0 || ypar.win <= 0) return;
1616
		if (mpar.hit_type > 0)
1617
		{
1618
			double shift_x = xpar.shift, shift_y = ypar.shift;
1619
			ApplyHit(data0, data0 + size);
1620
			data0 += size;
1621
			GetPaintOrigin(w, h, x, y, xx, yy);
1622
			xpar.shift = shift_x; ypar.shift = shift_y;
1623
		}
1624
		else GetPaintOrigin(w, h, x, y, xx, yy);
1625
		APosPixel pixel(xpar.p, ypar.p, data0);
1626
		j = menu0;
1627
		if (j < 0) j = 0;
1628
		else if (j > yy) j = yy;
1629
		for (i = j * xpar.win; i > 0; i--)
1630
		{
1631
			*(p++) = bgcolor[0]; *(p++) = bgcolor[1]; *(p++) = bgcolor[2];
1632
		}
1633
		i = menu1;
1634
		if (i < 0) i = 0;
1635
		else if (i > yy) i = yy;
1636
		p += 3 * xpar.win * (i - j);
1637
		for (i = (yy - i) * xpar.win; i > 0; i--)
1638
		{
1639
			*(p++) = bgcolor[0]; *(p++) = bgcolor[1]; *(p++) = bgcolor[2];
1640
		}
1641
		for (i = 0; i < h; i++)
1642
		{
1643
			for (j = xx; j > 0; j--)
1644
			{
1645
				*(p++) = bgcolor[0]; *(p++) = bgcolor[1]; *(p++) = bgcolor[2];
1646
			}
1647
			pixel.SetTo(x, (y + i) % ypar.p);
1648
			j = xpar.p - x;
1649
			if (j > w) j = w;
1650
			for (;;)
1651
			{
1652
				if (pixel.GetPixel()) {*(p++) = 255; *(p++) = 255; *(p++) = 255;}
1653
				else {*(p++) = 0; *(p++) = 0; *(p++) = 0;}
1654
				if (--j <= 0) break;
1655
				pixel.AddX1();
1656
			}
1657
			j = w - (xpar.p - x);
1658
			if (j > 0)
1659
			{
1660
				pixel.SetTo(0, (y + i) % ypar.p);
1661
				for (;;)
1662
				{
1663
					if (pixel.GetPixel()) {*(p++) = 255; *(p++) = 255; *(p++) = 255;}
1664
					else {*(p++) = 0; *(p++) = 0; *(p++) = 0;}
1665
					if (--j <= 0) break;
1666
					pixel.AddX1();
1667
				}
1668
			}
1669
			for (j = xpar.win - xx - w; j > 0; j--)
1670
			{
1671
				*(p++) = bgcolor[0]; *(p++) = bgcolor[1]; *(p++) = bgcolor[2];
1672
			}
1673
		}
1674
		j = menu0;
1675
		if (j < yy + h) j = yy + h;
1676
		else if (j > ypar.win) j = ypar.win;
1677
		for (i = (j - yy - h) * xpar.win; i > 0; i--)
1678
		{
1679
			*(p++) = bgcolor[0]; *(p++) = bgcolor[1]; *(p++) = bgcolor[2];
1680
		}
1681
		i = menu1;
1682
		if (i < yy + h) i = yy + h;
1683
		else if (i > ypar.win) i = ypar.win;
1684
		p += 3 * xpar.win * (i - j);
1685
		for (i = (ypar.win - i) * xpar.win; i > 0; i--)
1686
		{
1687
			*(p++) = bgcolor[0]; *(p++) = bgcolor[1]; *(p++) = bgcolor[2];
1688
		}
1689
	}
1690
	if (what & PaintWSpeed) CalculateSpeed();
1691
	MenuPaint(what);
1692
	SetPicture(picture, (unsigned short)xpar.win, (unsigned short)ypar.win, th);
1693
}
1694
 
8133 IgorA 1695
bool KolibriOnStart(TStartData &me_start, TThreadData th)
1769 yogev_ezra 1696
{
1697
	randomize();
1698
	me_start.WinData.Title = "Black and white Life";
1699
	me_start.Width = 500; me_start.Height = 400;
1700
	InitGenerate();
1701
	InitMenuButton();
8252 IgorA 1702
	if(LoadLibrary("proc_lib.obj", library_path, "/sys/lib/proc_lib.obj", &import_proc_lib))
1769 yogev_ezra 1703
	{
8252 IgorA 1704
		ofd.procinfo = procinfo;
1705
		ofd.com_area_name = "FFFFFFFF_open_dialog";
1706
		ofd.com_area = 0;
1707
		ofd.opendir_path = plugin_path;
9585 vitalkrilo 1708
		ofd.dir_default_path = "/sys";
1709
		ofd.start_path = "/sys/File managers/opendial";
8252 IgorA 1710
		ofd.draw_window = DrawWindow;
1711
		ofd.status = 0;
1712
		ofd.openfile_path = CommandLine;
1713
		ofd.filename_area = filename_area;
1714
		ofd.filter_area = &filter1;
1715
		ofd.x_size = 420;
1716
		ofd.x_start = 10;
1717
		ofd.y_size = 320;
1718
		ofd.y_start = 10;
1719
		OpenDialog_Init(&ofd);
1720
	} else return false;
1721
	if (CommandLine[0]) open_file_str = true;
1769 yogev_ezra 1722
	return true;
1723
}
1724
 
8133 IgorA 1725
bool KolibriOnClose(TThreadData)
1769 yogev_ezra 1726
{
1727
	SetPictureSize(0, 0);
1728
	SetPoleSize(0, 0);
1729
	return true;
1730
}
1731
 
8133 IgorA 1732
int KolibriOnIdle(TThreadData th)
1769 yogev_ezra 1733
{
1734
	static const unsigned int WAIT_TIME = 2, GEN_TIME = 1;
1735
	int res = -1;
8252 IgorA 1736
	if (open_file_str)
1769 yogev_ezra 1737
	{
1738
		MenuOpenDialogEnd(th);
1739
		res = 0;
1740
	}
1741
	else
1742
	{
1743
		if (life_data && menu.button[MenuIGenerate].check)
1744
		{
1745
			unsigned int t = Clock() - generate.time;
1746
			if (t >= (unsigned int)(-WAIT_TIME)) res = -t;
1747
			else
1748
			{
1749
				MoveGenerateTime(t);
1750
				if (generate.count > 0)
1751
				{
1752
					unsigned char *data0 = (unsigned char*)GetDataAddress(life_data);
1753
					int size = GetDataSize(xpar.p, ypar.p);
1754
					int flag = (menu.button[MenuIHCircle].check ? 4 : 1) +
1755
								(menu.button[MenuIVCircle].check ? 8 : 2);
1756
					if (++timegenpos >= TimeGenLength) timegenpos = 0;
1757
					timegen[timegenpos].t = 0;
1758
					timegen[timegenpos].g = 0;
1759
					for (;;)
1760
					{
1761
						OneGeneration(xpar.p, ypar.p, data0 + size, data0, flag);
1762
						if (menu.button[MenuIRandom].check) RandomDraw(data0 + size);
1763
						timegen[timegenpos].g++;
1764
						if (--generate.count == 0 || (unsigned int)(Clock() - generate.time) >= GEN_TIME)
1765
						{
1766
							MemCopy(data0, data0 + size, size);
1767
							break;
1768
						}
1769
						OneGeneration(xpar.p, ypar.p, data0, data0 + size, flag);
1770
						if (menu.button[MenuIRandom].check) RandomDraw(data0);
1771
						timegen[timegenpos].g++;
1772
						if (--generate.count == 0 || (unsigned int)(Clock() - generate.time) >= GEN_TIME) break;
1773
					}
1774
					generate.paint |= PaintWPole | PaintWSpeed;
1775
				}
1776
				if (generate.stop && generate.count == 0)
1777
				{
1778
					ResetGenerate();
1779
					menu.button[MenuIGenerate].check = false;
1780
					generate.paint |= PaintWMenuBorder | PaintWSpeed;
1781
					res = -1;
1782
				}
1783
				else
1784
				{
1785
					MoveGenerateTime(Clock() - generate.time);
1786
					res = (generate.count <= generate.gps / 100) ? WAIT_TIME : 0;
1787
					MoveGenerateTime(res);
1788
				}
1789
			}
1790
		}
1791
	}
1792
	if (generate.paint)
1793
	{
1794
		Paint((res < 0 || res > WAIT_TIME) ? (PaintWNull | PaintWNow) : PaintWNull, th);
1795
	}
1796
	return res;
1797
}
1798
 
8133 IgorA 1799
void KolibriOnSize(int window_rect[], Kolibri::TThreadData th)
1769 yogev_ezra 1800
{
1801
	unsigned short w, h;
1802
	GetClientSize(w, h, window_rect[2], window_rect[3], th);
1803
	SetPictureSize(w, h);
1804
	generate.paint |= PaintWAll | PaintWFast;
1805
	if (!life_data) MenuWinSizeClick(th);
1806
	Paint(PaintWNull | PaintWNow, th);
1807
}
1808
 
8133 IgorA 1809
void KolibriOnKeyPress(TThreadData th)
1769 yogev_ezra 1810
{
1811
	int ch;
1812
	while ((ch = GetKey()) >= 0)
1813
	{
1814
		if (mpar.hit_type > 0)
1815
		{
1816
			mpar.hit_type = 0;
1817
			generate.paint |= PaintWPole | PaintWFast;
1818
			SetMenuPressed(-1, th);
1819
			if (generate.paint) Paint(PaintWNull, th);
1820
		}
1821
		else if (menu.pressed >= 0) SetMenuPressed(-1, th);
1822
		else if (menu.edit >= 0) MenuEditPressKey(ch, th);
1823
		else
1824
		{
1825
			switch (ch)
1826
			{
1827
			case 'm':
1828
			case 'M':
1829
				SetMenuDraw(!menu.draw, th);
1830
				break;
1831
			case 'c':
1832
			case 'C':
1833
				MenuClearClick(th);
1834
				break;
1835
			case 'o':
1836
			case 'O':
8252 IgorA 1837
				ofd.type = 0; // 0 - open
1838
				OpenDialog_Start(&ofd);
1839
				if(ofd.status==1) open_file_str=true;
1769 yogev_ezra 1840
				break;
1841
			case 'a':
1842
			case 'A':
1843
				MenuAboutClick(th);
1844
				break;
1845
			case 'q':
1846
			case 'Q':
1847
				CloseWindow(th);
1848
				break;
1849
			case 'w':
1850
			case 'W':
1851
				MenuWinSizeClick(th);
1852
				break;
1853
			case 'g':
1854
			case 'G':
1855
				MenuGenerateClick(th);
1856
				break;
1857
			case 'r':
1858
			case 'R':
1859
				menu.button[MenuIRandom].check = !menu.button[MenuIRandom].check;
1860
				Paint(PaintWMenuBorder | PaintWFast, th);
1861
				break;
1862
			case 'v':
1863
			case 'V':
1864
				menu.button[MenuIVCircle].check = !menu.button[MenuIVCircle].check;
1865
				Paint(PaintWMenuBorder | PaintWFast, th);
1866
				break;
1867
			case 'h':
1868
			case 'H':
1869
				menu.button[MenuIHCircle].check = !menu.button[MenuIHCircle].check;
1870
				Paint(PaintWMenuBorder | PaintWFast, th);
1871
				break;
1872
			case 'l':
1873
			case 'L':
1874
				SetMenuCurrent(MenuILine, th);
1875
				break;
1876
			case 's':
1877
			case 'S':
1878
				SetMenuCurrent(MenuIScroll, th);
1879
				break;
1880
			case 'x':
1881
			case 'X':
1882
				if (!menu.draw) SetMenuDraw(true, th);
1883
				SetMenuEdit(MenuISize, 0, th);
1884
				break;
1885
			case 'y':
1886
			case 'Y':
1887
				if (!menu.draw) SetMenuDraw(true, th);
1888
				SetMenuEdit(MenuISize, 1, th);
1889
				break;
1890
			case 'f':
1891
			case 'F':
1892
				if (!menu.draw) SetMenuDraw(true, th);
1893
				SetMenuEdit(MenuISpeed, 0, th);
1894
				break;
1895
			case ' ':
1896
			case '\\':
1897
			case '|':
1898
				if (menu.button[MenuIGenerate].check && !generate.stop)
1899
				{
1900
					menu.button[MenuIGenerate].check = false;
1901
					Paint(PaintWMenuBorder | PaintWSpeed | PaintWFast, th);
1902
				}
1903
				else AddGenerateCount((ch == ' ') ? 1 : 15);
1904
				break;
1905
			}
1906
		}
1907
	}
1908
}
1909
 
8133 IgorA 1910
void KolibriOnMouse(TThreadData th)
1769 yogev_ezra 1911
{
1912
	short xp = 0, yp = 0;
1913
	int w, h, x, y, xx, yy, m;
1914
	GetMousePosPicture(xp, yp);
1915
	m = GetMouseButton();
1916
	GetPaintOrigin(w, h, x, y, xx, yy);
1917
	x += xp - xx;
1918
	y += yp - yy;
1919
	if (mpar.hit_type > 0)
1920
	{
1921
		if (mpar.last_x != x || mpar.last_y != y)
1922
		{
1923
			mpar.last_x = x; mpar.last_y = y;
1924
			generate.paint |= PaintWPole | PaintWFast;
1925
		}
1926
		if (m != mpar.button)
1927
		{
1928
			if ((m & ~mpar.button) == 0) ApplyHit();
1929
			mpar.hit_type = 0;
1930
			generate.paint |= PaintWPole | PaintWFast;
1931
			SetMenuPressed(-1, th);
1932
			if (generate.paint) Paint(PaintWNull, th);
1933
		}
1934
	}
1935
	else if (menu.pressed >= 0)
1936
	{
1937
		if (mpar.last_x != x || mpar.last_y != y)
1938
		{
1939
			MenuMouseClick(xp, yp, -1, th);
1940
		}
1941
		if (m != mpar.button)
1942
		{
1943
			if ((m & ~mpar.button) == 0) MenuMouseClick(xp, yp, 0, th);
1944
			SetMenuPressed(-1, th);
1945
		}
1946
	}
1947
	else if (mpar.button == 0 && (m == 1 || m == 2))
1948
	{
1949
		if (xp >= 0 && xp < xpar.win && yp >= 0 && yp < ypar.win)
1950
		{
1951
			mpar.hit_x = x; mpar.hit_y = y; mpar.last_x = x; mpar.last_y = y;
1952
			yy = GetMenuYPos();
1953
			if (menu.edit >= 0 || (yp >= yy && yp < yy + GetMenuHeight()))
1954
			{
1955
				MenuMouseClick(xp, yp, m, th);
1956
			}
1957
			else PoleMouseClick(m, th);
1958
		}
1959
	}
1960
	mpar.button = m;
1961
}