The R Project SVN R

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4394 ripley 1
/*
2
 * GraphApp - Cross-Platform Graphics Programming Library.
3
 *
4
 * File: buttons.c -- creating buttons, scrollbars, etc.
5
 * Platform: Windows  Version: 2.41  Date: 1998/06/06
6
 *
7
 * Version: 1.00  Changes: Original version by Lachlan Patrick.
8
 * Version: 1.60  Changes: Minor changes.
9
 * Version: 2.00  Changes: New object class system.
10
 * Version: 2.10  Changes: Radiogroups fully implemented.
11
 * Version: 2.20  Changes: Added non-native buttons.
12
 * Version: 2.21  Changes: 32-bit fix by Wim Rijnders.
13
 * Version: 2.22  Changes: Added newtextarea function.
14
 * Version: 2.23  Changes: Added newpassword function.
15
 * Version: 2.30  Changes: Added imagebuttons.
16
 * Version: 2.35  Changes: Added newpicture function.
17
 * Version: 2.40  Changes: Added new list controls.
18
 * Version: 2.41  Changes: Updated imagebuttons.
19
 * Version: 2.42  Changes: Fixed drop-down list height.
20
 */
21
 
22
/* Copyright (C) 1993-1998 Lachlan Patrick
23
 
24
   This file is part of GraphApp, a cross-platform C graphics library.
25
 
26
   GraphApp is free software; you can redistribute it and/or modify it
27
   under the terms of the GNU Library General Public License.
28
   GraphApp is distributed in the hope that it will be useful, but
29
   WITHOUT ANY WARRANTY.
30
 
31
   See the file COPYLIB.TXT for details.
32
*/
33
 
9184 ripley 34
/* Changes for R:
35
 
36
   set the system font for labels
37
   add newscrollbar, field_no_border
38
   add extended selections, pass on de-selections
39
 
40
 */
41
 
4394 ripley 42
#include "internal.h"
43
 
44
#define SHADOW_WIDTH 1
45
 
46
#define isarmed(obj) ((obj)->state & Armed)
47
#define arm(obj)     ((obj)->state |= Armed)
48
#define disarm(obj)  ((obj)->state &= ~Armed)
49
 
50
#define hasfocus(obj) ((obj)->state & Focus)
51
#define setfocus(obj) SetFocus((obj)->handle)
52
 
53
/*
54
 *  Ensure there is a current window, create one if there isn't.
55
 *  If a window is created, it is also shown on the screen.
56
 */
57
static void ensure_window(void)
58
{
59
	if (! current_window) {
60
		current_window = simple_window();
61
		show(current_window);
62
	}
63
}
64
 
65
/*
66
 *  Save the winproc for later and set our own winproc instead.
67
 */
68
static void set_new_winproc(object obj)
69
{
4985 ripley 70
  #if TRUE
4394 ripley 71
	HWND hwnd;
72
	hwnd = obj->handle;
73
	obj->winproc = (WNDPROC) GetWindowLong(hwnd, GWL_WNDPROC);
74
	SetWindowLong(hwnd, GWL_WNDPROC, (LONG) app_control_proc);
75
  #endif
76
}
77
 
78
/*
79
 *  Private object destructor.
80
 */
81
static void private_delcontrol(control obj)
82
{
83
	ShowWindow(obj->handle, SW_HIDE);
84
#if USE_NATIVE_CONTROLS
85
	if (obj->bgbrush)
86
		DeleteObject(obj->bgbrush);
87
#endif
88
	DestroyWindow(obj->handle);
89
}
90
 
91
/*
92
 *  Creating controls.
93
 */
94
control newcontrol(char *text, rect r)
95
{
96
	control obj;
97
 
98
	ensure_window();
99
	obj = newwindow(text, r, ChildWindow | TrackMouse);
100
	if (obj) {
101
		obj->kind = UserObject;
102
		obj->die = private_delcontrol;
103
	}
104
	set_new_winproc(obj); /* set custom winproc */
105
	show(obj);
106
 
107
	return obj;
108
}
109
 
110
drawing newdrawing(rect r, drawfn fn)
111
{
112
	drawing obj = newcontrol(NULL, r);
113
	if (obj) {
114
		setredraw(obj, fn);
115
		show(obj);
116
		draw(obj);
117
	}
118
	return obj;
119
}
120
 
121
static object newchildwin(char *kind, char *text,
122
		unsigned long style, rect r, actionfn fn)
123
{
124
	HWND hwnd;
125
	object obj;
126
 
127
	ensure_window();
128
	r = rcanon(r);
129
 
130
	hwnd = CreateWindow(kind, text,
131
		(WS_CHILD | WS_VISIBLE) | style,
132
		r.x, r.y, r.width, r.height,
133
		current_window->handle,
134
		(HMENU) child_id, this_instance, NULL);
135
 
136
	obj = new_object(ControlObject, hwnd, current_window);
137
	if (! obj) {
138
		DestroyWindow(hwnd);
139
		return NULL;
140
	}
141
	obj->die = private_delcontrol;
142
	obj->rect = r;
143
	obj->id = child_id++;
144
	obj->action = fn;
145
	obj->state = (Visible | Enabled);
146
	obj->flags = ChildWindow;
147
	obj->text = new_string(text);
148
	set_new_winproc(obj); /* set custom winproc */
4606 ripley 149
	settextfont(obj, SystemFont);
4394 ripley 150
	return obj;
151
}
152
 
153
/*
154
 *  The old native version of newlabel.
155
 */
156
#if USE_NATIVE_LABELS
157
label newlabel(char *text, rect r, int alignment)
158
{
159
	label obj;
160
	unsigned long style = SS_LEFT;
161
 
162
	if ((alignment & AlignRight) == AlignRight)
163
		style = SS_RIGHT;
164
	if ((alignment & Center) == Center)
165
		style = SS_CENTER;
166
 
167
	obj = newchildwin("static", text, style, r, NULL);
168
	obj->kind = LabelObject;
169
	setbackground(obj, getbackground(parentwindow(obj)));
170
	return obj;
171
}
172
#else
173
/*
174
 *  Private label redraw function.
175
 */
176
static void draw_label(control c, rect r)
177
{
178
	/* Draw the label. */
179
	if (!isenabled(c))
180
		setcolour(Grey);
181
	else
182
		setcolour(Black);
183
	setfont(gettextfont(c));
184
	drawtext(r, getvalue(c), getname(c));
185
}
186
 
187
/*
188
 *  Create a new static text label. Now implemented using
189
 *  GraphApp code instead of native MS-Windows "static"
190
 *  text. This gives more flexibility, better cross-platform
191
 *  support and there are no 'look and feel' issues with
192
 *  labels, so no problems are introduced by doing this.
193
 */
194
control newlabel(char *text, rect r, int alignment)
195
{
196
	control obj = newcontrol(text, r);
197
	if (obj) {
198
		obj->kind = LabelObject;
199
		setredraw(obj, draw_label);
200
		setvalue(obj, alignment);
201
		setbackground(obj, getbackground(parentwindow(obj)));
202
		settextfont(obj, SystemFont);
203
		show(obj);
204
	}
205
	return obj;
206
}
207
#endif
208
 
209
/*
210
 *  Uncheck any neighbouring radio buttons, up to any bounding
211
 *  radiogroup objects, or to the start or end of the list of
212
 *  siblings.
213
 */
214
static void uncheck_neighbours(object obj)
215
{
216
	object first = obj->parent->child;
217
	object last  = first->prev;
218
	object which;
219
 
220
	for (which=obj; ; which=which->prev) {
221
		if (which->kind == RadiogroupObject)
222
			break;
223
		if ((which->kind == RadioObject) && (which != obj))
224
			uncheck(which);
225
		if (which == first)
226
			break;
227
	}
228
	for (which=obj; ; which=which->next) {
229
		if (which->kind == RadiogroupObject)
230
			break;
231
		if ((which->kind == RadioObject) && (which != obj))
232
			uncheck(which);
233
		if (which == last)
234
			break;
235
	}
236
}
237
 
238
/*
239
 *  A radiogroup separates radiobuttons from each other.
240
 */
241
object newradiogroup(void)
242
{
243
	object obj;
244
	ensure_window();
245
	obj = new_object(RadiogroupObject, NULL, current_window);
246
	return obj;
247
}
248
 
249
/*
250
 *  Draw a button shadow.
251
 */
252
static void draw_shadow(rect r, rgb col1, rgb col2, int size)
253
{
254
	rgb hue = current->hue;
255
 
256
	/* Draw top-left button border. */
257
	setcolour(col1);
258
	fillrect(rect(r.x,r.y,r.width,size));
259
	fillrect(rect(r.x,r.y,size,r.height));
260
 
261
	/* Draw bottom-right button border. */
262
	setcolour(col2);
263
	while (size > 0) {
264
		fillrect(rect(r.x+r.width-1,r.y,1,r.height));
265
		fillrect(rect(r.x,r.y+r.height-1,r.width,1));
266
		r = insetr(r,1);
267
		size--;
268
	}
269
	setcolour(hue);
270
}
271
 
272
/*
273
 *  Various button call-backs.
274
 */
275
static void button_mousedown(control c, int buttons, point xy)
276
{
277
	arm(c);
278
	highlight(c);
279
}
280
 
281
static void button_mousemove(control c, int buttons, point xy)
282
{
283
	if (!isarmed(c))
284
		return;
285
	if (buttons && ptinr(xy,getrect(c)))
286
		highlight(c);
287
	else
288
		unhighlight(c);
289
}
290
 
291
static void button_mouseup(control c, int buttons, point xy)
292
{
293
	if (!isarmed(c))
294
		return;
295
	disarm(c);
296
	unhighlight(c);
297
	if (ptinr(xy, getrect(c)))
298
		activatecontrol(c);
299
}
300
 
301
static void button_keydown(control c, int ch)
302
{
303
	if (ch == ' ') {
304
		flashcontrol(c);
305
		activatecontrol(c);
306
	}
307
}
308
 
309
/*
310
 *  Various checkbox call-backs.
311
 */
312
static void checkbox_mousedown(control c, int buttons, point xy)
313
{
314
	arm(c);
315
	highlight(c);
316
}
317
 
318
static void checkbox_mousemove(control c, int buttons, point xy)
319
{
320
	if (!isarmed(c))
321
		return;
322
	if (buttons && ptinr(xy,getrect(c)))
323
		highlight(c);
324
	else
325
		unhighlight(c);
326
}
327
 
328
static void checkbox_mouseup(control c, int buttons, point xy)
329
{
330
	if (! isenabled(c))
331
		return;
332
	disarm(c);
333
	unhighlight(c);
334
	if (! ptinr(xy, getrect(c)))
335
		return;
336
	if (ischecked(c))
337
		uncheck(c);
338
	else
339
		check(c);
340
	activatecontrol(c);
341
}
342
 
343
static void checkbox_keydown(control c, int ch)
344
{
345
	if (ch == ' ') {
346
		if (ischecked(c))
347
			uncheck(c);
348
		else
349
			check(c);
350
		activatecontrol(c);
351
	}
352
}
353
 
354
/*
355
 *  The imagebutton type:
356
 */
357
 
358
void setimage(control obj, image img)
359
{
360
	/* Change the stored image and draw it. */
361
	obj->img = img;
362
	draw(obj);
363
}
364
 
365
static void draw_image_button(button obj, rect r)
366
{
367
	image   img;
368
	bitmap	store = NULL;
369
	rect    ir;
370
	rgb     up, down;
371
	rgb     old = currentcolour();
372
 
373
	img = obj->img;
374
	if (has_transparent_pixels(img)) {
375
		store = newbitmap(r.width, r.height, 0);
376
		drawto(store);
377
		setcolour(getbackground(obj));
378
		fillrect(r);
379
	}
380
 
381
	if (img) {
382
		ir = insetr(r,2);
383
		if (ishighlighted(obj)) /* button is pressed */
384
			ir.x += 1, ir.y += 1;
385
 
386
		/* Draw the button image. */
387
		if (ischecked(obj))
388
			drawdarker(img, ir, getrect(img));
389
		else if (isenabled(obj))
390
			drawimage(img, ir, getrect(img));
391
		else
392
			drawgreyscale(img, ir, getrect(img));
393
 
394
		if (ishighlighted(obj)) { /* fill the gap */
395
			ir.x -= 1, ir.y -= 1;
396
			setcolour(getbackground(obj));
397
			drawline(topleft(ir),topright(ir));
398
			drawline(topleft(ir),bottomleft(ir));
399
		}
400
	}
401
 
402
	/* Draw button border. */
403
	setcolour(getforeground(obj));
404
	setlinewidth(1);
405
	drawrect(r);
406
 
407
	/* Draw button shadow. */
408
	up = White, down = Grey;
409
	if (ishighlighted(obj))
410
		up = Grey, down = LightGrey;
411
	draw_shadow(insetr(r,1), up, down, 1);
412
 
413
	if (store != NULL) {
414
		drawto(obj);
415
		copyrect(store, pt(0,0), getrect(store));
416
		del(store);
417
	}
418
 
419
	setcolour(old);
420
}
421
 
422
 
423
button newimagebutton(image img, rect r, actionfn fn)
424
{
425
	button obj;
426
 
427
	obj = newcontrol(NULL, r);
428
	if (! obj)
429
		return NULL;
430
 
431
	setredraw(obj, draw_image_button);
432
	setmousedown(obj, button_mousedown);
433
	setmousemove(obj, button_mousemove);
434
	setmousedrag(obj, button_mousemove);
435
	setmouseup(obj, button_mouseup);
436
	setkeydown(obj, button_keydown);
437
	setaction(obj, fn);
438
	setbackground(obj, LightGrey);
439
	settextfont(obj, SystemFont);
440
 
441
	setimage(obj, img);
442
 
443
	show(obj);
444
	return obj;
445
}
446
 
447
static void draw_picture(control obj, rect r)
448
{
449
	image   img;
450
	bitmap	store = NULL;
451
	rgb     old = currentcolour();
452
 
453
	img = obj->img;
454
	if (has_transparent_pixels(img)) {
455
		store = newbitmap(r.width, r.height, 0);
456
		drawto(store);
457
		setcolour(getbackground(obj));
458
		fillrect(r);
459
	}
460
 
461
	if (img) {
462
		/* Draw the button image. */
463
		if (ischecked(obj))
464
			drawdarker(img, r, getrect(img));
465
		else if (isenabled(obj))
466
			drawimage(img, r, getrect(img));
467
		else
468
			drawimage(img, r, getrect(img)); /* never grey */
469
	}
470
 
471
	if (store != NULL) {
472
		drawto(obj);
473
		copyrect(store, pt(0,0), getrect(store));
474
		del(store);
475
	}
476
 
477
	setcolour(old);
478
}
479
 
480
control newpicture(image img, rect r)
481
{
482
	control obj;
483
 
484
	obj = newcontrol(NULL, r);
485
	if (! obj)
486
		return NULL;
487
 
488
	setredraw(obj, draw_picture);
489
	setimage(obj, img);
490
	disable(obj);
491
 
492
	show(obj);
493
	return obj;
494
}
495
 
496
button newimagecheckbox(image img, rect r, actionfn fn)
497
{
498
	button obj;
499
 
500
	obj = newdrawing(r, draw_image_button);
501
	if (! obj)
502
		return NULL;
503
 
504
	setmousedown(obj, checkbox_mousedown);
505
	setmousemove(obj, checkbox_mousemove);
506
	setmousedrag(obj, checkbox_mousemove);
507
	setmouseup(obj, checkbox_mouseup);
508
	setkeydown(obj, checkbox_keydown);
509
	setaction(obj, fn);
510
	setbackground(obj, LightGrey);
511
	settextfont(obj, SystemFont);
512
 
513
	setimage(obj, img);
514
 
515
	show(obj);
516
	return obj;
517
}
518
 
519
 
520
#if USE_NATIVE_BUTTONS
521
button newbutton(char *text, rect r, actionfn fn)
522
{
523
	button obj;
524
	obj = newchildwin("button", text, BS_PUSHBUTTON, r, fn);
525
	if (obj)
526
		obj->kind = ButtonObject;
527
	return obj;
528
}
529
#else
530
static void draw_button(control c, rect r)
531
{
532
	rect textrect;
533
	rgb up, down;
534
	font f;
535
	rgb old = currentcolour();
536
 
537
	clear(c);
538
 
539
	/* Draw the button name. */
540
	if (isenabled(c))
541
		setcolour(getforeground(c));
542
	else
543
		setcolour(Grey);
544
	f = gettextfont(c);
545
	setfont(f);
546
	textrect = r;
547
	if (ishighlighted(c))
548
		textrect.x += 1, textrect.y += 1;
549
	drawtext(textrect, Center|VCenter, getname(c));
550
 
551
	/* Draw button border. */
552
	setlinewidth(1);
553
	drawrect(r);
554
	r = insetr(r,1);
555
 
556
	/* Draw button shadow. */
557
	up = White, down = Grey;
558
	if (ishighlighted(c))
559
		up = Grey, down = LightGrey;
560
	else if (hasfocus(c)) {
561
		setcolour(Black);
562
		drawrect(r);
563
		r = insetr(r,1);
564
	}
565
	draw_shadow(r, up, down, SHADOW_WIDTH);
566
 
567
	setcolour(old);
568
}
569
 
570
button newbutton(char *text, rect r, actionfn fn)
571
{
572
	button obj = newcontrol(text, r);
573
	if (obj) {
574
		obj->kind = ButtonObject;
575
		setredraw(obj, draw_button);
576
		setmousedown(obj, button_mousedown);
577
		setmousemove(obj, button_mousemove);
578
		setmousedrag(obj, button_mousemove);
579
		setmouseup(obj, button_mouseup);
580
		setkeydown(obj, button_keydown);
581
		setaction(obj, fn);
582
		setbackground(obj, LightGrey);
583
		settextfont(obj, SystemFont);
584
		show(obj);
585
	}
586
	return obj;
587
}
588
#endif
589
 
590
#if USE_NATIVE_TOGGLES
591
checkbox newcheckbox(char *text, rect r, actionfn fn)
592
{
593
	checkbox obj = newchildwin("button", text, BS_CHECKBOX, r, fn);
594
	if (obj) {
595
		obj->kind = CheckboxObject;
596
		setbackground(obj, getbackground(parentwindow(obj)));
597
	}
598
	return obj;
599
}
600
 
601
radiobutton newradiobutton(char *text, rect r, actionfn fn)
602
{
603
	radiobutton obj = newchildwin("button", text, BS_RADIOBUTTON, r, fn);
604
	if (obj) {
605
		obj->kind = RadioObject;
606
		setbackground(obj, getbackground(parentwindow(obj)));
607
	}
608
	return obj;
609
}
610
#else
611
static void draw_checkmark(rect r)
612
{
613
	int len;
614
 
615
	if (r.width < 8) {
616
		r = insetr(r,1);
617
		fillrect(r);
618
		return;
619
	}
620
 
621
	len = r.width/3;
622
	if (len < 3)
623
		len = 3;
624
 
625
	drawline(pt(r.x+1, r.y+r.height-len-2),
626
		 pt(r.x+len, r.y+r.height-3));
627
	drawline(pt(r.x+2, r.y+r.height-len-2),
628
		 pt(r.x+len, r.y+r.height-4));
629
	drawline(pt(r.x+len, r.y+r.height-3),
630
		 pt(r.x+r.width-1, r.y+len-2));
631
	drawline(pt(r.x+len, r.y+r.height-4),
632
		 pt(r.x+r.width-2, r.y+len-2));
633
}
634
 
635
static void draw_checkbox(control c, rect r)
636
{
637
	int w;
638
	rect box, textrect;
639
	char *name;
640
	int style = (AlignLeft | AlignTop);
641
	font f;
642
	rgb old = currentcolour();
643
 
644
	/* Calculate rectangles. */
645
	f = gettextfont(c);
646
	setfont(f);
647
	w = strwidth(f,"W");
648
	if (w > r.width)  w = r.width;
649
	if (w > r.height) w = r.height;
650
	box = rect(r.x,r.y+1,w,w);
651
	if (w < getheight(f) - getdescent(f))
652
		box.y += getheight(f) - getdescent(f) - w;
653
	textrect = rect(r.x+w+w/2,r.y,r.width-(w+w/2),r.height);
654
 
655
	/* Clear check area. */
656
	setlinewidth(1);
657
	setcolour(White);
658
	fillrect(insetr(box,1));
659
 
660
	/* Draw check area */
661
	if (isenabled(c))
662
		setcolour(Black);
663
	else
664
		setcolour(Grey);
665
	drawrect(box);
666
 
667
	/* 'Pressed button' effect by black border in box. */
668
	if (ishighlighted(c))
669
		drawrect(insetr(box,1));
670
 
671
	/* Put tick in box if checked. */
672
	if (ischecked(c))
673
		draw_checkmark(insetr(box,1));
674
 
675
	name = getname(c);
676
	if (isenabled(c)) {
677
		/* if (hasfocus(c)) {
678
			style |= Underline;
679
			setlinewidth(2);
680
		} */
681
		setcolour(getforeground(c));
682
	}
683
	drawtext(textrect, style, name);
684
 
685
	setcolour(old);
686
}
687
 
688
checkbox newcheckbox(char *text, rect r, actionfn fn)
689
{
690
	checkbox obj = newcontrol(text, r);
691
	if (obj) {
692
		obj->kind = CheckboxObject;
693
		setredraw(obj, draw_checkbox);
694
		setmousedown(obj, checkbox_mousedown);
695
		setmousemove(obj, checkbox_mousemove);
696
		setmousedrag(obj, checkbox_mousemove);
697
		setmouseup(obj, checkbox_mouseup);
698
		setkeydown(obj, checkbox_keydown);
699
		setaction(obj, fn);
700
		setbackground(obj, getbackground(parentwindow(obj)));
701
		settextfont(obj, SystemFont);
702
		show(obj);
703
	}
704
	return obj;
705
}
706
 
707
static void draw_radio(control c, rect r)
708
{
709
	int w;
710
	rect box, textrect;
711
	char *name;
712
	int style = (AlignLeft | AlignTop);
713
	font f;
714
	rgb old = currentcolour();
715
 
716
	/* Calculate rectangles. */
717
	f = gettextfont(c);
718
	setfont(f);
719
	w = strwidth(f,"W");
720
	if (w > r.width)  w = r.width;
721
	if (w > r.height) w = r.height;
722
	box = rect(r.x,r.y+1,w,w);
723
	if (w < getheight(f) - getdescent(f))
724
		box.y += getheight(f) - getdescent(f) - w;
725
	textrect = rect(r.x+w+w/2,r.y,r.width-(w+w/2),r.height);
726
 
727
	/* Clear the check area. */
728
	setlinewidth(1);
729
	setcolour(White);
730
	fillellipse(insetr(box,1));
731
 
732
	/* Draw the check area */
733
	if (isenabled(c))
734
		setcolour(Black);
735
	else
736
		setcolour(Grey);
737
	drawellipse(box);
738
 
739
	/* Provide 'pressed button' effect by black border. */
740
	if (ishighlighted(c)) {
741
		setlinewidth(2);
742
		drawellipse(box);
743
		setlinewidth(1);
744
	}
745
 
746
	/* Put o in circle if checked. */
747
	if (ischecked(c))
748
		fillellipse(insetr(box,3));
749
 
750
	name = getname(c);
751
	if (isenabled(c)) {
752
		/* if (hasfocus(c)) {
753
			style |= Underline;
754
			setlinewidth(2);
755
		} */
756
		setcolour(getforeground(c));
757
	}
758
	drawtext(textrect, style, name);
759
 
760
	setcolour(old);
761
}
762
 
763
static void radio_hit(control c)
764
{
765
	if (!ischecked(c)) {
766
		uncheck_neighbours(c);
767
		check(c);
768
		activatecontrol(c);
769
	}
770
}
771
 
772
static void radio_mouseup(control c, int buttons, point xy)
773
{
774
	if (! isarmed(c))
775
		return;
776
	disarm(c);
777
	unhighlight(c);
778
	if (! ptinr(xy, getrect(c)))
779
		return;
780
	radio_hit(c);
781
}
782
 
783
static void radio_keydown(control c, int ch)
784
{
785
	if (ch == ' ')
786
		radio_hit(c);
787
}
788
 
789
radiobutton newradiobutton(char *text, rect r, actionfn fn)
790
{
791
	radiobutton obj = newcontrol(text, r);
792
	if (obj) {
793
		obj->kind = RadioObject;
794
		setredraw(obj, draw_radio);
795
		setmousedown(obj, checkbox_mousedown);
796
		setmousemove(obj, checkbox_mousemove);
797
		setmousedrag(obj, checkbox_mousemove);
798
		setmouseup(obj, radio_mouseup);
799
		setkeydown(obj, radio_keydown);
800
		setaction(obj, fn);
801
		setbackground(obj, getbackground(parentwindow(obj)));
802
		settextfont(obj, SystemFont);
803
		show(obj);
804
	}
805
	return obj;
806
}
807
#endif
808
 
809
#if 0
810
void undotext(control obj)
811
{
812
	if (! obj)
813
		return;
814
	if ((obj->kind != FieldObject) && (obj->kind != TextboxObject))
815
		return;
816
	sendmessage(obj->handle, EM_UNDO, 0, 0L);
817
}
818
#endif
819
 
820
void cuttext(control obj)
821
{
822
	if (! obj)
823
		return;
824
	if ((obj->kind != FieldObject) && (obj->kind != TextboxObject))
825
		return;
826
	sendmessage(obj->handle, WM_CUT, 0, 0L);
827
}
828
 
829
void copytext(control obj)
830
{
831
	if (! obj)
832
		return;
833
	if ((obj->kind != FieldObject) && (obj->kind != TextboxObject))
834
		return;
835
	sendmessage(obj->handle, WM_COPY, 0, 0L);
836
}
837
 
838
void cleartext(control obj)
839
{
840
	if (! obj)
841
		return;
842
	if ((obj->kind != FieldObject) && (obj->kind != TextboxObject))
843
		return;
844
	sendmessage(obj->handle, WM_CLEAR, 0, 0L);
845
}
846
 
847
void pastetext(control obj)
848
{
849
	if (! obj)
850
		return;
851
	if ((obj->kind != FieldObject) && (obj->kind != TextboxObject))
852
		return;
853
	sendmessage(obj->handle, WM_PASTE, 0, 0L);
854
}
855
 
856
void inserttext(control obj, char *text)
857
{
858
	if (! obj)
859
		return;
860
	if ((obj->kind != FieldObject) && (obj->kind != TextboxObject))
861
		return;
862
	text = to_dos_string(text);
863
	sendmessage(obj->handle, EM_REPLACESEL, 0, (long) text);
864
	if (text)
865
		discard(text);
866
}
867
 
868
void selecttext(control obj, long start, long end)
869
{
870
	int left, right;
871
	long length;
872
 
873
	if (! obj)
874
		return;
875
	if ((obj->kind != FieldObject) && (obj->kind != TextboxObject))
876
		return;
877
	length = GetWindowTextLength(obj->handle);
878
	left = (start < 0) ? length : start;
879
	right = (end < 0) ? length : end;
880
#ifdef WIN32
881
	sendmessage(obj->handle, EM_SETSEL, left,right);
882
#else
883
	sendmessage(obj->handle, EM_SETSEL, 0, MAKELONG(left,right));
884
#endif
885
}
886
 
887
void textselection(control obj, long *start, long *end)
888
{
889
	unsigned long sel;
890
 
891
	if (! obj)
892
		return;
893
	if ((obj->kind != FieldObject) && (obj->kind != TextboxObject))
894
		return;
895
	sel = sendmessage(obj->handle, EM_GETSEL, 0, 0);
896
	if (start) *start = LOWORD(sel);
897
	if (end) *end = HIWORD(sel);
898
}
899
 
900
 
901
field newfield(char *text, rect r)
902
{
903
	field obj = newchildwin("edit", NULL,
904
			WS_BORDER | ES_LEFT | ES_AUTOHSCROLL,
905
			r, NULL);
906
	if (obj) {
907
		obj->kind = FieldObject;
908
		settext(obj, text);
909
	}
910
	return obj;
911
}
912
 
9053 ripley 913
 
914
field newfield_no_border(char *text, rect r)
915
{
916
	field obj = newchildwin("edit", NULL,
917
			ES_LEFT | ES_AUTOHSCROLL,
918
			r, NULL);
919
	if (obj) {
920
		obj->kind = FieldObject;
921
		settext(obj, text);
922
	}
923
	return obj;
924
}
925
 
4394 ripley 926
field newpassword(char *text, rect r)
927
{
928
	field obj = newchildwin("edit", NULL,
929
			WS_BORDER | ES_LEFT | ES_AUTOHSCROLL
930
			| ES_PASSWORD, r, NULL);
931
	if (obj) {
932
		obj->kind = FieldObject;
4606 ripley 933
		settextfont(obj, SystemFont);
4394 ripley 934
		settext(obj, text);
935
	}
936
	return obj;
937
}
938
 
939
textbox newtextbox(char *text, rect r)
940
{
941
	textbox obj = newchildwin("edit", NULL,
942
			/* WS_HSCROLL | ES_AUTOHSCROLL | */
943
			WS_VSCROLL | ES_AUTOVSCROLL |
944
			WS_BORDER | ES_LEFT |
945
			ES_MULTILINE,
946
			r, NULL);
947
	if (obj) {
948
		obj->kind = TextboxObject;
949
		settext(obj, text);
950
	}
951
	return obj;
952
}
953
 
954
textbox newtextarea(char *text, rect r)
955
{
956
	textbox obj = newchildwin("edit", NULL,
957
			WS_HSCROLL | ES_AUTOHSCROLL |
958
			WS_VSCROLL | ES_AUTOVSCROLL |
959
			WS_BORDER | ES_LEFT |
960
			ES_MULTILINE,
961
			r, NULL);
962
	if (obj) {
963
		obj->kind = TextboxObject;
964
		settext(obj, text);
965
	}
966
	return obj;
967
}
968
 
17533 ripley 969
static SCROLLINFO si;
4394 ripley 970
 
971
scrollbar newscrollbar(rect r, int max, int pagesize, scrollfn fn)
972
{
973
	scrollbar obj;
974
	HWND hwnd;
975
 
976
	r = rcanon(r);
977
 
978
	obj = newchildwin("scrollbar", NULL,
979
			(r.width > r.height) ? SBS_HORZ : SBS_VERT,
980
			r, NULL);
981
	if (obj) {
982
		obj->kind = ScrollbarObject;
983
		obj->hit = fn;
984
		obj->value = 0;
985
		obj->max = max;
986
		obj->size = pagesize;
987
 
988
		hwnd = obj->handle;
989
		si.cbSize = sizeof(si);
990
		si.fMask = SIF_ALL;
991
		si.nMin = 0;
992
		si.nMax = max + pagesize - 1;
993
		si.nPage = pagesize;
994
		si.nPos = 0;
995
		SetScrollInfo(hwnd, SB_CTL, &si, 1);
996
	}
997
	return obj;
998
}
999
 
1000
void changescrollbar(scrollbar obj, int where, int max, int pagesize)
1001
{
1002
	HWND hwnd;
1003
 
1004
	if (! obj)
1005
		return;
1006
	hwnd = obj->handle;
1007
	obj->max = max;
1008
	obj->size = pagesize;
1009
 
1010
	si.cbSize = sizeof(si);
1011
	si.fMask = SIF_ALL;
1012
	si.nMin = 0;
1013
	si.nMax = max + pagesize - 1;
1014
	si.nPage = pagesize;
1015
	si.nPos = where;
1016
	SetScrollInfo(hwnd, SB_CTL, &si, 1);
1017
}
1018
 
1019
listbox newlistbox(char *list[], rect r, scrollfn fn)
1020
{
1021
	listbox obj;
1022
 
1023
	obj = newchildwin("listbox", NULL,
1024
				LBS_NOTIFY | WS_BORDER |
1025
				WS_VSCROLL | WS_HSCROLL,
1026
				r, NULL);
1027
	if (! obj)
1028
		return obj;
1029
	obj->kind = ListboxObject;
1030
	obj->hit = fn;
1031
 
1032
	changelistbox(obj, list);
1033
 
1034
	return obj;
1035
}
1036
 
1037
listbox newmultilist(char *list[], rect r, scrollfn fn)
1038
{
1039
	listbox obj;
1040
 
1041
	obj = newchildwin("listbox", NULL,
1042
				LBS_NOTIFY |
4985 ripley 1043
				LBS_MULTIPLESEL | LBS_EXTENDEDSEL |
4394 ripley 1044
				WS_BORDER |
1045
				WS_VSCROLL | WS_HSCROLL,
1046
				r, NULL);
1047
	if (! obj)
1048
		return obj;
1049
	obj->kind = MultilistObject;
1050
	obj->hit = fn;
1051
 
1052
	changelistbox(obj, list);
1053
 
1054
	return obj;
1055
}
1056
 
1057
listbox newdroplist(char *list[], rect r, scrollfn fn)
1058
{
1059
	listbox obj;
1060
	int h, i;
1061
 
1062
	initapp(0,0);
1063
	h = getheight(SystemFont);
1064
	r.height = h+h;
1065
	for (i = 0; list && list[i]; i++)
1066
		r.height += h;
1067
 
1068
	obj = newchildwin("combobox", NULL,
1069
				CBS_DROPDOWNLIST |
9210 ripley 1070
				//CBS_DISABLENOSCROLL |
4394 ripley 1071
				WS_BORDER |
1072
				WS_VSCROLL | WS_HSCROLL,
1073
				r, NULL);
1074
	if (! obj)
1075
		return obj;
1076
	obj->kind = DroplistObject;
1077
	obj->hit = fn;
1078
 
1079
	changelistbox(obj, list);
1080
 
1081
	return obj;
1082
}
1083
 
1084
listbox newdropfield(char *list[], rect r, scrollfn fn)
1085
{
1086
	listbox obj;
1087
	int h, i;
1088
 
1089
	initapp(0,0);
1090
	h = getheight(SystemFont);
1091
	r.height = h+h;
1092
	for (i = 0; list && list[i]; i++)
1093
		r.height += h;
1094
 
1095
	obj = newchildwin("combobox", NULL,
1096
				CBS_DROPDOWN |
1097
				CBS_DISABLENOSCROLL |
1098
				WS_BORDER |
1099
				WS_VSCROLL | WS_HSCROLL,
1100
				r, NULL);
1101
	if (! obj)
1102
		return obj;
1103
	obj->kind = DroplistObject;
1104
	obj->hit = fn;
1105
 
1106
	changelistbox(obj, list);
1107
 
1108
	return obj;
1109
}
1110
 
1111
void setlistitem(listbox obj, int index)
1112
{
1113
	int count;
1114
 
1115
	if (! obj)
1116
		return;
1117
	if (index < 0)
1118
		index = -1;
1119
	switch (obj->kind)
1120
	{
1121
	case ListboxObject:
1122
	  sendmessage(obj->handle, LB_SETCURSEL, index, 0L);
1123
	  break;
1124
	case MultilistObject:
1125
	  if (index >= 0)
1126
	    sendmessage(obj->handle, LB_SETSEL, TRUE, MAKELPARAM(index, 0));
1127
	  else {
1128
	    count = sendmessage(obj->handle, LB_GETCOUNT, 0, 0L);
1129
	    sendmessage(obj->handle, LB_SELITEMRANGE, FALSE, MAKELPARAM(0,count-1));
1130
	  }
1131
	case DroplistObject:
1132
	case DropfieldObject:
1133
	  sendmessage(obj->handle, CB_SETCURSEL, index, 0L);
1134
	  break;
1135
	default:
1136
	  break;
1137
	}
1138
}
1139
 
1140
int isselected(listbox obj, int index)
1141
{
1142
	if (! obj)
1143
		return -1;
1144
	switch (obj->kind)
1145
	{
1146
	case ListboxObject:
1147
	  return (index == sendmessage(obj->handle, LB_GETCURSEL, 0, 0L));
1148
	case MultilistObject:
1149
	  return sendmessage(obj->handle, LB_GETSEL, index, 0L);
1150
	case DroplistObject:
1151
	case DropfieldObject:
1152
	  return (index == sendmessage(obj->handle, CB_GETCURSEL, 0, 0L));
1153
	default:
1154
	  return 0;
1155
	}
1156
}
1157
 
1158
int getlistitem(listbox obj)
1159
{
1160
	int index, count;
1161
 
1162
	if (! obj)
1163
		return -1;
1164
	switch (obj->kind)
1165
	{
1166
	case ListboxObject:
1167
	  return sendmessage(obj->handle, LB_GETCURSEL, 0, 0L);
1168
	case MultilistObject:
1169
	  count = sendmessage(obj->handle, LB_GETCOUNT, 0, 0L);
1170
	  for (index=0; index < count; index++)
1171
	    if (isselected(obj, index))
1172
	      return index;
1173
	  return -1;
1174
	case DroplistObject:
1175
	case DropfieldObject:
1176
	  return sendmessage(obj->handle, CB_GETCURSEL, 0, 0L);
1177
	default:
1178
	  return -1;
1179
	}
1180
}
1181
 
1182
void changelistbox(listbox obj, char **list)
1183
{
1184
	int i;
1185
	HWND hwnd;
1186
	UINT reset_msg, add_msg;
1187
 
1188
	if (! obj)
1189
		return;
1190
	hwnd = obj->handle;
1191
 
1192
	switch (obj->kind) {
1193
	  case ListboxObject: case MultilistObject:
1194
		reset_msg = LB_RESETCONTENT;
1195
		add_msg = LB_ADDSTRING;
1196
		break;
1197
	  case DroplistObject: case DropfieldObject:
1198
		reset_msg = CB_RESETCONTENT;
1199
		add_msg = CB_ADDSTRING;
1200
		break;
1201
	  default:
1202
		return;
1203
	}
1204
 
1205
	sendmessage(hwnd, WM_SETREDRAW, FALSE, 0L);
1206
	sendmessage(hwnd, reset_msg, 0, 0L);
1207
	for (i=0; list && list[i]; i++)
1208
	    sendmessage(hwnd, add_msg, 0, (LPSTR) list[i]);
1209
	sendmessage(hwnd, WM_SETREDRAW, TRUE, 0L);
1210
	if (obj->kind == ListboxObject)
1211
		sendmessage(hwnd, LB_SETCURSEL, 0, 0L);
1212
}
1213
 
1214
/*
1215
 *  Activate a control's action function. We do several things here.
1216
 *  Checking to see what kind of control it is, we handle some
1217
 *  events and discard others. We automatically toggle the state of
1218
 *  checkboxes and radio buttons, and handle listbox changes and
1219
 *  allow text box update events to call the control's action.
1220
 */
1221
PROTECTED
1222
void handle_control(HWND hwnd, UINT message)
1223
{
1224
	object obj;
1225
	int index;
1226
 
1227
	obj = find_by_handle(hwnd);
1228
 
1229
	if ((! obj) || (! (obj->state & Enabled)))
1230
		return;
1231
 
1232
	/* Only let certain events cause activation. */
1233
	switch (obj->kind)
1234
	{
1235
	  case CheckboxObject:
1236
		if (obj->state & Checked)
1237
			uncheck(obj);
1238
		else
1239
			check(obj);
1240
		break;
1241
 
1242
	  case RadioObject:
1243
		if (!(obj->state & Checked)) {
1244
			uncheck_neighbours(obj);
1245
			check(obj);
1246
		}
1247
		break;
1248
 
1249
	  case ListboxObject:
1250
		/* Ignore all but selection-change events. */
1251
		if (message != LBN_SELCHANGE)
1252
			return;
1253
		index = sendmessage(hwnd, LB_GETCURSEL, 0, 0L);
1254
		obj->value = index;
1255
		break;
1256
 
1257
	  case MultilistObject:
1258
		/* Ignore all but selection-change events. */
1259
		if (message != LBN_SELCHANGE)
1260
			return;
1261
		index = sendmessage(hwnd, LB_GETCARETINDEX, 0, 0L);
4985 ripley 1262
		/* We do want to see de-selection events too 
4394 ripley 1263
		if (! sendmessage(hwnd, LB_GETSEL, index, 0L))
4985 ripley 1264
		  return;*/
4394 ripley 1265
		obj->value = index;
1266
		break;
1267
 
1268
	  case DroplistObject:
1269
	  case DropfieldObject:
1270
		/* Ignore all but selection-change events. */
1271
		if (message != CBN_SELCHANGE)
1272
			return;
1273
		index = sendmessage(hwnd, CB_GETCURSEL, 0, 0L);
1274
		obj->value = index;
1275
		break;
1276
 
1277
	  case FieldObject:
1278
	  case TextboxObject:
1279
		/* For the moment we ignore all but killfocus. */
1280
		if (message != EN_KILLFOCUS)
1281
			return;
1282
		break;
1283
 
1284
	  default:
1285
		break;
1286
	}
1287
	/* activate the control's callback */
1288
	activatecontrol(obj);
1289
}
13710 ripley 1290
 
1291
#include <commctrl.h>
1292
/* smooth  != 0 gives continuous not segmented bar */
1293
progressbar newprogressbar(rect r, int pbmin, int pbmax, int incr, int smooth)
1294
{
1295
	HWND hwnd;
1296
	progressbar obj;
1297
	int sm;
1298
 
1299
	ensure_window();
1300
	r = rcanon(r);
1301
	sm = smooth ? PBS_SMOOTH : 0 ;
1302
	hwnd = CreateWindowEx(0, PROGRESS_CLASS, NULL,
1303
		(WS_CHILD | WS_VISIBLE | sm),
1304
		r.x, r.y, r.width, r.height,
1305
		current_window->handle,
1306
		(HMENU) child_id, this_instance, NULL);
1307
	obj = new_object(ControlObject, hwnd, current_window);
1308
	if (! obj) {
1309
		DestroyWindow(hwnd);
1310
		return NULL;
1311
	}
1312
	obj->die = private_delcontrol;
1313
	obj->rect = r;
1314
	obj->id = child_id++;
1315
	obj->action = NULL;
1316
	obj->state = (Visible | Enabled);
1317
	obj->flags = ChildWindow;
1318
	set_new_winproc(obj); /* set custom winproc */
1319
	settextfont(obj, SystemFont);
1320
	obj->kind = ListboxObject;
1321
	SendMessage(hwnd, PBM_SETRANGE32, (WPARAM) pbmin, (LPARAM) pbmax); 
1322
	SendMessage(hwnd, PBM_SETSTEP, (WPARAM) incr, 0);
1323
 
1324
	return obj;
1325
}
1326
 
1327
void setprogressbar(progressbar obj, int n)
1328
{
1329
	if (! obj) return;
1330
        SendMessage(obj->handle, PBM_SETPOS, (WPARAM) n, 0); 
1331
}
1332
 
1333
void stepprogressbar(progressbar obj, int n)
1334
{
1335
	if (! obj) return;
1336
        SendMessage(obj->handle, PBM_STEPIT, 0, 0); 
1337
}
1338
 
1339
void setprogressbarrange(progressbar obj, int pbmin, int pbmax)
1340
{
1341
	if (! obj) return;
1342
	SendMessage(obj->handle, PBM_SETRANGE32, (WPARAM) pbmin, 
1343
		    (LPARAM) pbmax); 
1344
}