1 /*
2 * GraphApp - Cross-Platform Graphics Programming Library.
3 *
4 * File: controls.c -- manipulating scrollbars, buttons, etc.
5 * Platform: Windows Version: 2.40 Date: 1998/04/04
6 *
7 * Version: 1.00 Changes: Original version by Lachlan Patrick.
8 * Version: 1.60 Changes: Added clear(), draw(), flashcontrol().
9 * Version: 2.00 Changes: New object class system.
10 * Version: 2.15 Changes: Transparent backgrounds added.
11 * Version: 2.20 Changes: Non-native buttons supported.
12 * Version: 2.35 Changes: New reference count technique.
13 * Version: 2.40 Changes: Support for new controls.
14 */
15
16 /* Copyright (C) 1993-1998 Lachlan Patrick
17
18 This file is part of GraphApp, a cross-platform C graphics library.
19
20 GraphApp is free software; you can redistribute it and/or modify it
21 under the terms of the GNU Library General Public License.
22 GraphApp is distributed in the hope that it will be useful, but
23 WITHOUT ANY WARRANTY.
24
25 See the file COPYLIB.TXT for details.
26 */
27
28 /* Copyright (C) 2004 The R Foundation
29
30 Changes for R:
31
32 sort out resize (confused screen and client coords)
33 add printer and metafile handling
34 Remove assumption of current->dest being non-NULL
35
36 */
37
38 #include "internal.h"
39 #include <richedit.h>
40
41 # define alloca(x) __builtin_alloca((x))
42
43 /*
44 * Setting control call-backs.
45 */
setaction(control obj,actionfn fn)46 void setaction(control obj, actionfn fn)
47 {
48 if (obj)
49 obj->action = fn;
50 }
51
sethit(control obj,intfn fn)52 void sethit(control obj, intfn fn)
53 {
54 if (obj)
55 obj->hit = fn;
56 }
57
setdel(control obj,actionfn fn)58 void setdel(control obj, actionfn fn)
59 {
60 if (obj)
61 if (obj->call)
62 obj->call->die = fn;
63 }
64
setclose(control obj,actionfn fn)65 void setclose(control obj, actionfn fn)
66 {
67 if (obj)
68 if (obj->call)
69 obj->call->close = fn;
70 }
71
setredraw(control obj,drawfn fn)72 void setredraw(control obj, drawfn fn)
73 {
74 if (obj)
75 if (obj->call)
76 obj->call->redraw = fn;
77 }
78
setresize(control obj,drawfn fn)79 void setresize(control obj, drawfn fn)
80 {
81 if (obj)
82 if (obj->call)
83 obj->call->resize = fn;
84 }
85
setkeydown(control obj,keyfn fn)86 void setkeydown(control obj, keyfn fn)
87 {
88 if (obj)
89 if (obj->call)
90 obj->call->keydown = fn;
91 }
92
setkeyaction(control obj,keyfn fn)93 void setkeyaction(control obj, keyfn fn)
94 {
95 if (obj)
96 if (obj->call)
97 obj->call->keyaction = fn;
98 }
99
setmousedown(control obj,mousefn fn)100 void setmousedown(control obj, mousefn fn)
101 {
102 if (obj)
103 if (obj->call)
104 obj->call->mousedown = fn;
105 }
106
setmouseup(control obj,mousefn fn)107 void setmouseup(control obj, mousefn fn)
108 {
109 if (obj)
110 if (obj->call)
111 obj->call->mouseup = fn;
112 }
113
setmousemove(control obj,mousefn fn)114 void setmousemove(control obj, mousefn fn)
115 {
116 if (obj)
117 if (obj->call)
118 obj->call->mousemove = fn;
119 }
120
setmousedrag(control obj,mousefn fn)121 void setmousedrag(control obj, mousefn fn)
122 {
123 if (obj)
124 if (obj->call)
125 obj->call->mousedrag = fn;
126 }
127
setmouserepeat(control obj,mousefn fn)128 void setmouserepeat(control obj, mousefn fn)
129 {
130 if (obj)
131 if (obj->call)
132 obj->call->mouserepeat = fn;
133 }
134
setdrop(control obj,dropfn fn)135 void setdrop(control obj, dropfn fn)
136 {
137 if (obj)
138 if (obj->call) {
139 DragAcceptFiles(obj->handle, TRUE);
140 obj->call->drop = fn;
141 }
142 }
143
setonfocus(control obj,actionfn fn)144 void setonfocus(control obj, actionfn fn)
145 {
146 if (obj)
147 obj->call->focus = fn;
148 }
149
setim(control obj,imfn fn)150 void setim(control obj, imfn fn)
151 {
152 if (obj)
153 obj->call->im = fn;
154 }
155
156 /*
157 * Drawing controls and windows.
158 */
clear(control obj)159 void clear(control obj)
160 {
161 drawing prev;
162 rgb old;
163
164 if (! obj)
165 return;
166 if (! isvisible(obj))
167 return;
168 if (! isvisible(parentwindow(obj)))
169 return;
170 if (obj->bg == Transparent)
171 return;
172 prev = current->dest;
173 drawto(obj);
174 old = currentrgb();
175 setrgb(obj->bg);
176 fillrect(getrect(obj));
177 if (prev) {
178 setrgb(old);
179 drawto(prev);
180 }
181 }
182
draw(control obj)183 void draw(control obj)
184 {
185 drawing prev;
186 drawstate old = NULL;
187
188 if (! obj)
189 return;
190 if (obj->kind == MenubarObject) {
191 DrawMenuBar(obj->parent->handle);
192 return;
193 }
194
195 if (! isvisible(obj))
196 return;
197 if (! isvisible(parentwindow(obj)))
198 return;
199 if ((obj->call == NULL) || (obj->call->redraw == NULL))
200 return;
201 prev = current->dest;
202 drawto(obj);
203 if (prev) old = copydrawstate();
204 moveto(pt(0,0));
205 obj->call->redraw(obj, getrect(obj));
206 if (prev) {
207 restoredrawstate(old);
208 drawto(prev);
209 }
210 }
211
redraw(control obj)212 void redraw(control obj)
213 {
214 clear(obj);
215 draw(obj);
216 }
217
218 /* void getscreenrect(control obj, rect *r) */
219 /* { */
220 /* RECT W; */
221 /* GetWindowRect(obj->handle, &W); */
222 /* r->x = W.left; */
223 /* r->y = W.top; */
224 /* r->width = W.right - W.left; */
225 /* r->height = W.bottom - W.top; */
226 /* } */
227
228
229 /* The original here used GetWindowRect (which used screen coordinates)
230 and MoveWindow (which uses client coordinates) so got the positioning
231 hopelessly wrong. This version works for WindowObjects, but I would be
232 suspicious of it for other cases. BDR 2000/04/05
233 */
resize(control obj,rect r)234 void resize(control obj, rect r)
235 {
236 RECT R;
237 WINDOWPLACEMENT W;
238 int dw, dh, dx, dy;
239
240 if (! obj)
241 return;
242 r = rcanon(r);
243 if (obj->kind == WindowObject) {
244 W.length = sizeof(WINDOWPLACEMENT);
245 r.x = obj->rect.x;
246 r.y = obj->rect.y;
247 if (!equalr(r, obj->rect)) {
248 GetWindowPlacement(obj->handle, &W);
249 if (!isvisible(obj)) W.showCmd = SW_HIDE; /* stops the resize from revealing the window */
250 dx = r.x - obj->rect.x;
251 dy = r.y - obj->rect.y;
252 /* don't believe current sizes!
253 dw = r.width - obj->rect.width;
254 dh = r.height - obj->rect.height;
255 Rprintf("dw %d dh %d\n", dw, dh); */
256 GetClientRect(obj->handle, &R);
257 dw = r.width - (R.right - R.left);
258 dh = r.height - (R.bottom - R.top);
259 W.rcNormalPosition.left += dx;
260 W.rcNormalPosition.top += dy;
261 W.rcNormalPosition.right += dx + dw;
262 W.rcNormalPosition.bottom += dy + dh;
263 SetWindowPlacement(obj->handle, &W);
264 }
265 }
266 else {
267 if (! equalr(r, obj->rect))
268 MoveWindow(obj->handle, r.x, r.y, r.width, r.height, 1);
269 obj->rect.x = r.x;
270 obj->rect.y = r.y;
271 }
272 obj->rect.width = r.width;
273 obj->rect.height = r.height;
274 }
275
276 /*
277 * Showing and hiding controls and windows.
278 */
show(control obj)279 void show(control obj)
280 {
281 if (! obj)
282 return;
283 switch (obj->kind) {
284 case CursorObject: case FontObject: case BitmapObject:
285 case MenubarObject: case MenuObject: case MenuitemObject:
286 break;
287 case WindowObject:
288 obj->state |= GA_Visible;
289 show_window(obj);
290 break;
291 default:
292 ShowWindow(obj->handle, SW_SHOWNORMAL);
293 SetFocus(obj->handle);
294 UpdateWindow(obj->handle);
295 }
296 obj->state |= GA_Visible;
297 }
298
hide(control obj)299 void hide(control obj)
300 {
301 if (! obj)
302 return;
303 switch (obj->kind) {
304 case CursorObject: case FontObject: case BitmapObject:
305 case MenubarObject: case MenuObject: case MenuitemObject:
306 break;
307 case WindowObject:
308 hide_window(obj);
309 break;
310 default:
311 ShowWindow(obj->handle, SW_HIDE);
312 }
313 obj->state &= ~GA_Visible;
314 }
315
isvisible(control obj)316 int isvisible(control obj)
317 {
318 if (! obj)
319 return 0;
320 return (obj->state & GA_Visible) ? 1 : 0;
321 }
322
323 /*
324 * Enabling and disabling controls and windows.
325 */
enable(control obj)326 void enable(control obj)
327 {
328 if (! obj)
329 return;
330 switch (obj->kind) {
331 case CursorObject: case FontObject: case BitmapObject:
332 case MenubarObject:
333 break;
334 case MenuObject: case MenuitemObject:
335 EnableMenuItem(obj->parent->handle,
336 obj->id, MF_ENABLED | MF_BYCOMMAND);
337 break;
338 case FieldObject: case TextboxObject:
339 sendmessage(obj->handle, EM_SETREADONLY, FALSE, 0L);
340 break;
341 default:
342 if (! isenabled(obj)) {
343 EnableWindow(obj->handle, 1);
344 obj->state |= GA_Enabled;
345 draw(obj);
346 }
347 }
348 obj->state |= GA_Enabled;
349 }
350
disable(control obj)351 void disable(control obj)
352 {
353 if (! obj)
354 return;
355 switch (obj->kind) {
356 case CursorObject: case FontObject: case BitmapObject:
357 case MenubarObject: case MenuObject:
358 break;
359 case MenuitemObject:
360 EnableMenuItem(obj->parent->handle,
361 obj->id, MF_GRAYED | MF_BYCOMMAND);
362 break;
363 case FieldObject: case TextboxObject:
364 sendmessage(obj->handle, EM_SETREADONLY, TRUE, 0L);
365 break;
366 default:
367 if (isenabled(obj)) {
368 EnableWindow(obj->handle, 0);
369 obj->state &= ~GA_Enabled;
370 draw(obj);
371 }
372 }
373 obj->state &= ~GA_Enabled;
374 }
375
isenabled(control obj)376 int isenabled(control obj)
377 {
378 if (! obj)
379 return 0;
380 return (obj->state & GA_Enabled) ? 1 : 0;
381 }
382
383 /*
384 * Checking and unchecking controls.
385 */
check(control obj)386 void check(control obj)
387 {
388 if (! obj)
389 return;
390 switch (obj->kind) {
391 case CursorObject: case FontObject: case BitmapObject:
392 case MenubarObject: case MenuObject:
393 break;
394 case MenuitemObject:
395 CheckMenuItem(obj->parent->handle, obj->id,
396 MF_CHECKED | MF_BYCOMMAND);
397 break;
398 #if USE_NATIVE_BUTTONS
399 case ButtonObject:
400 sendmessage(obj->handle, BM_SETCHECK, 1, 0L);
401 break;
402 #endif
403 #if USE_NATIVE_TOGGLES
404 case CheckboxObject: case RadioObject:
405 sendmessage(obj->handle, BM_SETCHECK, 1, 0L);
406 break;
407 #endif
408 default:
409 if (! ischecked(obj)) {
410 obj->state |= GA_Checked;
411 draw(obj);
412 }
413 }
414 obj->state |= GA_Checked;
415
416 }
417
uncheck(control obj)418 void uncheck(control obj)
419 {
420 if (! obj)
421 return;
422 switch (obj->kind) {
423 case CursorObject: case FontObject: case BitmapObject:
424 case MenubarObject: case MenuObject:
425 break;
426 case MenuitemObject:
427 CheckMenuItem(obj->parent->handle, obj->id,
428 MF_UNCHECKED | MF_BYCOMMAND);
429 break;
430 #if USE_NATIVE_BUTTONS
431 case ButtonObject:
432 sendmessage(obj->handle, BM_SETCHECK, 0, 0L);
433 break;
434 #endif
435 #if USE_NATIVE_TOGGLES
436 case CheckboxObject: case RadioObject:
437 sendmessage(obj->handle, BM_SETCHECK, 0, 0L);
438 break;
439 #endif
440 default:
441 if (ischecked(obj)) {
442 obj->state &= ~GA_Checked;
443 draw(obj);
444 }
445 }
446 obj->state &= ~GA_Checked;
447 }
448
ischecked(control obj)449 int ischecked(control obj)
450 {
451 if (! obj)
452 return 0;
453 return (obj->state & GA_Checked) ? 1 : 0;
454 }
455
456 /*
457 * Highlighting and unhighlighting controls.
458 */
highlight(control obj)459 void highlight(control obj)
460 {
461 if (! obj)
462 return;
463 switch (obj->kind) {
464 case CursorObject: case FontObject: case BitmapObject:
465 case MenubarObject: case MenuObject: case MenuitemObject:
466 break;
467 #if USE_NATIVE_BUTTONS
468 case ButtonObject:
469 sendmessage(obj->handle, BM_SETSTATE, 1, 0L);
470 break;
471 #endif
472 #if USE_NATIVE_TOGGLES
473 case CheckboxObject: case RadioObject:
474 sendmessage(obj->handle, BM_SETSTATE, 1, 0L);
475 break;
476 #endif
477 case FieldObject: case TextboxObject:
478 sendmessage(obj->handle, EM_SETSEL, 0, MAKELONG(0,-1));
479 break;
480 default:
481 if (! ishighlighted(obj)) {
482 obj->state |= GA_Highlighted;
483 draw(obj);
484 }
485 }
486 obj->state |= GA_Highlighted;
487 }
488
unhighlight(control obj)489 void unhighlight(control obj)
490 {
491 if (! obj)
492 return;
493 switch (obj->kind) {
494 case CursorObject: case FontObject: case BitmapObject:
495 case MenubarObject: case MenuObject: case MenuitemObject:
496 break;
497 #if USE_NATIVE_BUTTONS
498 case ButtonObject:
499 sendmessage(obj->handle, BM_SETSTATE, 0, 0L);
500 break;
501 #endif
502 #if USE_NATIVE_TOGGLES
503 case CheckboxObject: case RadioObject:
504 sendmessage(obj->handle, BM_SETSTATE, 0, 0L);
505 break;
506 #endif
507 case FieldObject: case TextboxObject:
508 sendmessage(obj->handle, EM_SETSEL, 0, MAKELONG(0,0));
509 break;
510 default:
511 if (ishighlighted(obj)) {
512 obj->state &= ~GA_Highlighted;
513 draw(obj);
514 }
515 }
516 obj->state &= ~GA_Highlighted;
517 }
518
ishighlighted(control obj)519 int ishighlighted(control obj)
520 {
521 if (! obj)
522 return 0;
523 return (obj->state & GA_Highlighted) ? 1 : 0;
524 }
525
526 /*
527 * The flashcontrol function highlights a control as if the user
528 * just used it, e.g. a button will become pressed down for a
529 * moment. Used in conjunction with activatecontrol() below,
530 * it can simulate a mouse-click on a button.
531 */
flashcontrol(control obj)532 void flashcontrol(control obj)
533 {
534 highlight(obj);
535 delay(150);
536 unhighlight(obj);
537 }
538
539 /*
540 * The activatecontrol function is really useful. It causes
541 * a variety of controls to call their 'action functions.'
542 *
543 * There are two types of action functions which a control can use.
544 * The first (obj->action) takes one argument, the control itself,
545 * and is used in buttons, checkboxes and the like as a response
546 * to a user clicking on these controls. The second function,
547 * (obj->hit) function, takes two arguments: the control and its
548 * current 'value'. A scrollbar's value changes as the user scrolls,
549 * and so its hit function is called whenever that happens.
550 *
551 * The activatecontrol function tries to call the action function,
552 * and if that doesn't exist, calls the hit function, passing the
553 * object's value to it.
554 */
activatecontrol(control obj)555 void activatecontrol(control obj)
556 {
557 if (! obj)
558 return;
559 drawto(obj);
560 if (obj->action != NULL)
561 obj->action(obj);
562 else if (obj->hit != NULL)
563 obj->hit(obj, obj->value);
564 }
565
566 /*
567 * Changing and determining the state of an object.
568 * These functions do not automatically redraw the object.
569 */
570 #if 0
571 void setstate(control obj, long state)
572 {
573 if (obj)
574 obj->state = state;
575 }
576
577 long getstate(control obj)
578 {
579 if (obj)
580 return obj->state;
581 else
582 return 0;
583 }
584 #endif
585
setvalue(control obj,int value)586 void setvalue(control obj, int value)
587 {
588 if (obj)
589 obj->value = value;
590 }
591
getvalue(control obj)592 int getvalue(control obj)
593 {
594 if (obj)
595 return obj->value;
596 else
597 return 0;
598 }
599
setforeground(control obj,rgb fg)600 void setforeground(control obj, rgb fg)
601 {
602 if (! obj)
603 return;
604 obj->fg = fg;
605 if (obj->kind == TextboxObject) {
606 if (obj->handle) {
607 CHARFORMAT format;
608 COLORREF wincolour = RGB((fg&gaRed)>>16,(fg&gaGreen)>>8,(fg&gaBlue));
609 format.cbSize = sizeof(format);
610 format.dwMask = CFM_COLOR;
611 format.dwEffects = 0;
612 format.crTextColor = wincolour;
613
614 sendmessage(obj->handle, EM_SETCHARFORMAT, 0, (LPARAM)&format);
615 }
616 } else {
617 InvalidateRect(obj->handle, NULL, TRUE);
618 redraw(obj);
619 }
620 }
621
getforeground(control obj)622 rgb getforeground(control obj)
623 {
624 if (obj)
625 return obj->fg;
626 else
627 return Black;
628 }
629
setbackground(control obj,rgb bg)630 void setbackground(control obj, rgb bg)
631 {
632 COLORREF wincolour = RGB((bg&gaRed)>>16,(bg&gaGreen)>>8,(bg&gaBlue));
633
634 if (! obj)
635 return;
636 obj->bg = bg;
637 if (obj->kind == TextboxObject) {
638 if (obj->handle)
639 sendmessage(obj->handle, EM_SETBKGNDCOLOR, 0, wincolour);
640 } else {
641 if (obj->bgbrush)
642 DeleteObject(obj->bgbrush);
643 obj->bgbrush = CreateSolidBrush(wincolour);
644
645 InvalidateRect(obj->handle, NULL, TRUE);
646 redraw(obj);
647 }
648 }
649
getbackground(control obj)650 rgb getbackground(control obj)
651 {
652 if (obj)
653 return obj->bg;
654 else
655 return Transparent;
656 }
657
setdata(control obj,void * data)658 void setdata(control obj, void *data)
659 {
660 if (obj)
661 obj->data = data;
662 }
663
getdata(control obj)664 void *getdata(control obj)
665 {
666 if (obj)
667 return obj->data;
668 else
669 return NULL;
670 }
671
672 /* These two are in none of the headers */
673 #ifdef UNUSED
_setextradata(control obj,void * data)674 void _setextradata(control obj, void *data)
675 {
676 if (obj)
677 obj->extra = data;
678 }
679
_getextradata(control obj)680 void *_getextradata(control obj)
681 {
682 if (obj)
683 return obj->extra;
684 else
685 return NULL;
686 }
687 #endif
688
689 /*
690 * Set the text of an object. This will set the names appearing
691 * in a window's title bar, a button, checkbox or radio button,
692 * or the value in a textbox or a text field.
693 */
settext(control obj,const char * text)694 void settext(control obj, const char *text)
695 {
696 char *old_text;
697
698 if (! obj)
699 return;
700 if (! text)
701 text = "";
702 old_text = GA_gettext(obj);
703 if (old_text && strcmp(old_text, text) == 0)
704 return; /* no changes to be made */
705 if (obj->text) {
706 /* discard prior information */
707 discard(obj->text);
708 obj->text = NULL;
709 }
710 /* Set the new text. */
711 obj->text = new_string(text);
712 if (text) {
713 if (obj->kind & ControlObject) {
714 text = to_dos_string(text);
715 if(localeCP > 0 && (localeCP != GetACP())) {
716 /* This seems not actually to work */
717 wchar_t *wc;
718 int nc = strlen(text) + 1;
719 wc = (wchar_t*) alloca(nc*sizeof(wchar_t));
720 mbstowcs(wc, text, nc);
721 SetWindowTextW(obj->handle, wc);
722 } else SetWindowText(obj->handle, text);
723 discard(text);
724 }
725 if (obj->kind == MenuitemObject) {
726 if(localeCP > 0 && (localeCP != GetACP())) {
727 /* But this does */
728 wchar_t wc[1000];
729 mbstowcs(wc, text, 1000);
730 ModifyMenuW(obj->parent->handle, obj->id,
731 MF_BYCOMMAND|MF_STRING, obj->id, wc);
732
733 } else
734 ModifyMenu(obj->parent->handle, obj->id,
735 MF_BYCOMMAND|MF_STRING, obj->id, text);
736 }
737
738 }
739 /* Redraw it if it's a redrawable object. */
740 if (obj->call && obj->call->redraw)
741 redraw(obj);
742 }
743
744 /*
745 * Get the text string from a window's title bar or from a
746 * control. This may be a button's name, for example, or
747 * the value inside a text field.
748 */
GA_gettext(control obj)749 char *GA_gettext(control obj)
750 {
751 static char *empty = "";
752 char *text;
753 int length, index;
754 HWND hwnd;
755 UINT len_msg, gettext_msg;
756 WPARAM arg1, arg2;
757
758 if (! obj)
759 return empty;
760 if ((obj->kind & ControlObject) == 0)
761 return obj->text ? obj->text : empty;
762
763 hwnd = obj->handle;
764
765 switch (obj->kind) {
766 case ListboxObject:
767 case MultilistObject:
768 len_msg = LB_GETTEXTLEN;
769 gettext_msg = LB_GETTEXT;
770 index = getlistitem(obj);
771 if (index < 0) return empty;
772 arg1 = arg2 = index;
773 break;
774 case DroplistObject:
775 len_msg = CB_GETLBTEXTLEN;
776 gettext_msg = CB_GETLBTEXT;
777 index = getlistitem(obj);
778 if (index < 0) return empty;
779 arg1 = arg2 = index;
780 break;
781 case DropfieldObject:
782 // use default mechanism
783 default:
784 len_msg = WM_GETTEXTLENGTH;
785 gettext_msg = WM_GETTEXT;
786 arg1 = 0;
787 arg2 = sendmessage(hwnd, len_msg, 0, 0L)+1;
788 break;
789 }
790
791 /* Free any previous information. */
792 if (obj->text)
793 discard(obj->text);
794 /* Find the length of the string. */
795 length = sendmessage(obj->handle, len_msg, arg1, 0L);
796 if (length == 0)
797 return (obj->text = new_string(NULL));
798 /* Copy the text from the object. */
799 text = array(length+2, char);
800 sendmessage(obj->handle, gettext_msg, arg2, (LPCSTR) text);
801 obj->text = to_c_string(text);
802 discard(text);
803 /* Return the resultant string. */
804 if (! obj->text)
805 obj->text = new_string(NULL);
806 return obj->text;
807 }
808
809 /*
810 * Set the font used by a control.
811 */
settextfont(object obj,font f)812 void settextfont(object obj, font f)
813 {
814 if (! obj)
815 return;
816 if (! f)
817 f = SystemFont;
818 if (obj->drawstate) {
819 decrease_refcount(obj->drawstate->fnt);
820 obj->drawstate->fnt = f;
821 increase_refcount(f);
822 }
823 else {
824 sendmessage(obj->handle, WM_SETFONT, f->handle, 0L);
825 }
826 }
827
828 /*
829 * Get the font used by a control.
830 */
gettextfont(object obj)831 font gettextfont(object obj)
832 {
833 font f = NULL;
834 if (obj) {
835 if (obj->drawstate)
836 f = obj->drawstate->fnt;
837 }
838 if (! f)
839 f = SystemFont;
840 return f;
841 }
842
843 /*
844 * Control and window functions.
845 * Parentwindow of a window is itself.
846 */
parentwindow(control obj)847 window parentwindow(control obj)
848 {
849 while (obj) {
850 if (obj->kind == WindowObject)
851 break;
852 obj = obj->parent;
853 }
854 return (window) obj;
855 }
856
857 /*
858 * Polymorphic functions:
859 */
objrect(object obj)860 rect objrect(object obj)
861 {
862 rect r;
863 image img;
864
865 if (! obj)
866 return rect(0,0,0,0);
867
868 switch (obj->kind)
869 {
870 case Image8: case Image32:
871 img = (image) obj;
872 r = rect(0,0,img->width,img->height);
873 break;
874 case BitmapObject:
875 case FontObject:
876 case CursorObject:
877 case PrinterObject:
878 r = obj->rect;
879 break;
880 case MetafileObject:
881 r = obj->rect;
882 break;
883 default:
884 GetClientRect(obj->handle, rect2RECT(&r));
885 break;
886 }
887 return r;
888 }
889
objwidth(object obj)890 int objwidth(object obj)
891 {
892 rect r = objrect(obj);
893 return r.width;
894 }
895
objheight(object obj)896 int objheight(object obj)
897 {
898 rect r = objrect(obj);
899 return r.height;
900 }
901
objdepth(object obj)902 int objdepth(object obj)
903 {
904 HDC screendc;
905 int depth;
906
907 if (! obj)
908 return 0;
909
910 switch (obj->kind)
911 {
912 case Image8: case Image32:
913 depth = ((image)obj)->depth;
914 break;
915 case BitmapObject:
916 case FontObject: case CursorObject:
917 depth = obj->depth;
918 break;
919 default:
920 screendc = GetDC(NULL);
921 depth = GetDeviceCaps(screendc, BITSPIXEL) *
922 GetDeviceCaps(screendc, PLANES);
923 ReleaseDC(NULL, screendc);
924 break;
925 }
926
927 return depth;
928 }
929
delobj(object obj)930 void delobj(object obj)
931 {
932 if (! obj)
933 return;
934 switch (obj->kind)
935 {
936 case Image8:
937 case Image32:
938 delimage((image)obj);
939 break;
940 default:
941 /* if (obj->refcount == 1) why would this test be here?? */
942 decrease_refcount(obj);
943 break;
944 }
945 }
946
setcaret(object obj,int x,int y,int width,int height)947 void setcaret(object obj, int x, int y, int width, int height)
948 {
949 if (! obj)
950 return;
951 if (width != obj->caretwidth || height != obj->caretheight) {
952 if (obj->caretwidth > 0 && (obj->state & GA_Focus)) DestroyCaret();
953 obj->caretwidth = width;
954 obj->caretheight = height;
955 if (width > 0) {
956 if (obj->state & GA_Focus)
957 CreateCaret(obj->handle, (HBITMAP) NULL, width, height);
958 obj->caretshowing = 0;
959 }
960 }
961 if (obj->state & GA_Focus)
962 SetCaretPos(x, y);
963 }
964
showcaret(object obj,int showing)965 void showcaret(object obj, int showing)
966 {
967 if (! obj || showing == obj->caretshowing)
968 return;
969 obj->caretshowing = showing;
970 if (showing)
971 ShowCaret(obj->handle);
972 else
973 HideCaret(obj->handle);
974 }
975