1 /* $Id: macctrls.c,v 1.6 2003/03/19 00:40:15 ben Exp $ */
3 * Copyright (c) 2003 Ben Harris
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or
11 * sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
23 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 #include <Appearance.h>
31 #include <ControlDefinitions.h>
32 #include <Resources.h>
34 #include <TextUtils.h>
44 struct macctrl_generic
{
51 /* Template from which this was generated */
55 struct macctrl_generic generic
;
59 struct macctrl_generic generic
;
63 struct macctrl_generic generic
;
67 struct macctrl_generic generic
;
72 struct mac_layoutstate
{
77 #define ctrlevent(mcs, mc, event) do { \
78 if ((mc)->generic.ctrl->generic.handler != NULL) \
79 (*(mc)->generic.ctrl->generic.handler)((mc)->generic.ctrl, (mc),\
80 (mcs)->data, (event)); \
83 static void macctrl_layoutset(struct mac_layoutstate
*, struct controlset
*,
84 WindowPtr
, struct macctrls
*);
85 static void macctrl_text(struct macctrls
*, WindowPtr
,
86 struct mac_layoutstate
*, union control
*);
87 static void macctrl_radio(struct macctrls
*, WindowPtr
,
88 struct mac_layoutstate
*, union control
*);
89 static void macctrl_checkbox(struct macctrls
*, WindowPtr
,
90 struct mac_layoutstate
*, union control
*);
91 static void macctrl_button(struct macctrls
*, WindowPtr
,
92 struct mac_layoutstate
*, union control
*);
93 #if !TARGET_API_MAC_CARBON
94 static pascal SInt32
macctrl_sys7_text_cdef(SInt16
, ControlRef
,
95 ControlDefProcMessage
, SInt32
);
96 static pascal SInt32
macctrl_sys7_default_cdef(SInt16
, ControlRef
,
97 ControlDefProcMessage
, SInt32
);
100 #if !TARGET_API_MAC_CARBON
102 * This trick enables us to keep all the CDEF code in the main
103 * application, which makes life easier. For details, see
104 * <http://developer.apple.com/technotes/tn/tn2003.html#custom_code_base>.
107 #pragma options align=mac68k
109 short jmpabs
; /* 4EF9 */
110 ControlDefUPP theUPP
;
112 #pragma options align=reset
115 static void macctrl_init()
117 #if !TARGET_API_MAC_CARBON
118 static int inited
= 0;
122 cdef
= (PatchCDEF
)GetResource(kControlDefProcResourceType
, CDEF_Text
);
123 (*cdef
)->theUPP
= NewControlDefProc(macctrl_sys7_text_cdef
);
124 cdef
= (PatchCDEF
)GetResource(kControlDefProcResourceType
, CDEF_Default
);
125 (*cdef
)->theUPP
= NewControlDefProc(macctrl_sys7_default_cdef
);
131 static int macctrl_cmp_byctrl(void *av
, void *bv
)
133 union macctrl
*a
= (union macctrl
*)av
;
134 union macctrl
*b
= (union macctrl
*)bv
;
136 if (a
->generic
.ctrl
< b
->generic
.ctrl
)
138 else if (a
->generic
.ctrl
> b
->generic
.ctrl
)
144 void macctrl_layoutbox(struct controlbox
*cb
, WindowPtr window
,
145 struct macctrls
*mcs
)
148 struct mac_layoutstate curstate
;
153 #if TARGET_API_MAC_CARBON
154 GetPortBounds(GetWindowPort(window
), &rect
);
156 rect
= window
->portRect
;
158 curstate
.pos
.h
= rect
.left
+ 13;
159 curstate
.pos
.v
= rect
.top
+ 13;
160 curstate
.width
= rect
.right
- rect
.left
- (13 * 2);
161 if (mac_gestalts
.apprvers
>= 0x100)
162 CreateRootControl(window
, &root
);
163 mcs
->byctrl
= newtree234(macctrl_cmp_byctrl
);
164 for (i
= 0; i
< cb
->nctrlsets
; i
++)
165 macctrl_layoutset(&curstate
, cb
->ctrlsets
[i
], window
, mcs
);
168 static void macctrl_layoutset(struct mac_layoutstate
*curstate
,
169 struct controlset
*s
,
170 WindowPtr window
, struct macctrls
*mcs
)
174 fprintf(stderr
, "--- begin set ---\n");
175 if (s
->boxname
&& *s
->boxname
)
176 fprintf(stderr
, "boxname = %s\n", s
->boxname
);
178 fprintf(stderr
, "boxtitle = %s\n", s
->boxtitle
);
181 for (i
= 0; i
< s
->ncontrols
; i
++) {
182 union control
*ctrl
= s
->ctrls
[i
];
185 switch (ctrl
->generic
.type
) {
186 case CTRL_TEXT
: s
= "text"; break;
187 case CTRL_EDITBOX
: s
= "editbox"; break;
188 case CTRL_RADIO
: s
= "radio"; break;
189 case CTRL_CHECKBOX
: s
= "checkbox"; break;
190 case CTRL_BUTTON
: s
= "button"; break;
191 case CTRL_LISTBOX
: s
= "listbox"; break;
192 case CTRL_COLUMNS
: s
= "columns"; break;
193 case CTRL_FILESELECT
: s
= "fileselect"; break;
194 case CTRL_FONTSELECT
: s
= "fontselect"; break;
195 case CTRL_TABDELAY
: s
= "tabdelay"; break;
196 default: s
= "unknown"; break;
198 fprintf(stderr
, " control: %s\n", s
);
199 switch (ctrl
->generic
.type
) {
201 macctrl_text(mcs
, window
, curstate
, ctrl
);
204 macctrl_radio(mcs
, window
, curstate
, ctrl
);
207 macctrl_checkbox(mcs
, window
, curstate
, ctrl
);
210 macctrl_button(mcs
, window
, curstate
, ctrl
);
217 static void macctrl_text(struct macctrls
*mcs
, WindowPtr window
,
218 struct mac_layoutstate
*curstate
,
221 union macctrl
*mc
= smalloc(sizeof *mc
);
224 fprintf(stderr
, " label = %s\n", ctrl
->text
.label
);
225 mc
->generic
.type
= MACCTRL_TEXT
;
226 mc
->generic
.ctrl
= ctrl
;
227 bounds
.left
= curstate
->pos
.h
;
228 bounds
.right
= bounds
.left
+ curstate
->width
;
229 bounds
.top
= curstate
->pos
.v
;
230 bounds
.bottom
= bounds
.top
+ 16;
231 if (mac_gestalts
.apprvers
>= 0x100) {
235 mc
->text
.tbctrl
= NewControl(window
, &bounds
, NULL
, TRUE
, 0, 0, 0,
236 kControlStaticTextProc
, (long)mc
);
237 SetControlData(mc
->text
.tbctrl
, kControlEntireControl
,
238 kControlStaticTextTextTag
,
239 strlen(ctrl
->text
.label
), ctrl
->text
.label
);
240 GetControlData(mc
->text
.tbctrl
, kControlEntireControl
,
241 kControlStaticTextTextHeightTag
,
242 sizeof(height
), &height
, &olen
);
243 fprintf(stderr
, " height = %d\n", height
);
244 SizeControl(mc
->text
.tbctrl
, curstate
->width
, height
);
245 curstate
->pos
.v
+= height
+ 6;
249 c2pstrcpy(title
, ctrl
->text
.label
);
250 mc
->text
.tbctrl
= NewControl(window
, &bounds
, title
, TRUE
, 0, 0, 0,
251 SYS7_TEXT_PROC
, (long)mc
);
253 add234(mcs
->byctrl
, mc
);
256 #if !TARGET_API_MAC_CARBON
257 static pascal SInt32
macctrl_sys7_text_cdef(SInt16 variant
, ControlRef control
,
258 ControlDefProcMessage msg
, SInt32 param
)
264 if ((*control
)->contrlVis
)
265 TETextBox((*control
)->contrlTitle
+ 1, (*control
)->contrlTitle
[0],
266 &(*control
)->contrlRect
, teFlushDefault
);
269 if (param
& (1 << 31)) {
275 rgn
= (RgnHandle
)param
;
276 RectRgn(rgn
, &(*control
)->contrlRect
);
280 rgn
= (RgnHandle
)param
;
289 static void macctrl_radio(struct macctrls
*mcs
, WindowPtr window
,
290 struct mac_layoutstate
*curstate
,
293 union macctrl
*mc
= smalloc(sizeof *mc
);
296 unsigned int i
, colwidth
;
298 fprintf(stderr
, " label = %s\n", ctrl
->radio
.label
);
299 mc
->generic
.type
= MACCTRL_RADIO
;
300 mc
->generic
.ctrl
= ctrl
;
302 smalloc(sizeof(*mc
->radio
.tbctrls
) * ctrl
->radio
.nbuttons
);
303 colwidth
= (curstate
->width
+ 13) / ctrl
->radio
.ncolumns
;
304 for (i
= 0; i
< ctrl
->radio
.nbuttons
; i
++) {
305 fprintf(stderr
, " button = %s\n", ctrl
->radio
.buttons
[i
]);
306 bounds
.top
= curstate
->pos
.v
;
307 bounds
.bottom
= bounds
.top
+ 16;
308 bounds
.left
= curstate
->pos
.h
+ colwidth
* (i
% ctrl
->radio
.ncolumns
);
309 if (i
== ctrl
->radio
.nbuttons
- 1 ||
310 i
% ctrl
->radio
.ncolumns
== ctrl
->radio
.ncolumns
- 1) {
311 bounds
.right
= curstate
->pos
.h
+ curstate
->width
;
312 curstate
->pos
.v
+= 22;
314 bounds
.right
= bounds
.left
+ colwidth
- 13;
315 c2pstrcpy(title
, ctrl
->radio
.buttons
[i
]);
316 mc
->radio
.tbctrls
[i
] = NewControl(window
, &bounds
, title
, TRUE
,
317 0, 0, 1, radioButProc
, (long)mc
);
319 add234(mcs
->byctrl
, mc
);
320 ctrlevent(mcs
, mc
, EVENT_REFRESH
);
323 static void macctrl_checkbox(struct macctrls
*mcs
, WindowPtr window
,
324 struct mac_layoutstate
*curstate
,
327 union macctrl
*mc
= smalloc(sizeof *mc
);
331 fprintf(stderr
, " label = %s\n", ctrl
->checkbox
.label
);
332 mc
->generic
.type
= MACCTRL_CHECKBOX
;
333 mc
->generic
.ctrl
= ctrl
;
334 bounds
.left
= curstate
->pos
.h
;
335 bounds
.right
= bounds
.left
+ curstate
->width
;
336 bounds
.top
= curstate
->pos
.v
;
337 bounds
.bottom
= bounds
.top
+ 16;
338 c2pstrcpy(title
, ctrl
->checkbox
.label
);
339 mc
->checkbox
.tbctrl
= NewControl(window
, &bounds
, title
, TRUE
, 0, 0, 1,
340 checkBoxProc
, (long)mc
);
341 add234(mcs
->byctrl
, mc
);
342 curstate
->pos
.v
+= 22;
343 ctrlevent(mcs
, mc
, EVENT_REFRESH
);
346 static void macctrl_button(struct macctrls
*mcs
, WindowPtr window
,
347 struct mac_layoutstate
*curstate
,
350 union macctrl
*mc
= smalloc(sizeof *mc
);
354 fprintf(stderr
, " label = %s\n", ctrl
->button
.label
);
355 if (ctrl
->button
.isdefault
)
356 fprintf(stderr
, " is default\n");
357 mc
->generic
.type
= MACCTRL_BUTTON
;
358 mc
->generic
.ctrl
= ctrl
;
359 bounds
.left
= curstate
->pos
.h
;
360 bounds
.right
= bounds
.left
+ 100; /* XXX measure string */
361 bounds
.top
= curstate
->pos
.v
;
362 bounds
.bottom
= bounds
.top
+ 20;
363 c2pstrcpy(title
, ctrl
->button
.label
);
364 mc
->button
.tbctrl
= NewControl(window
, &bounds
, title
, TRUE
, 0, 0, 1,
365 pushButProc
, (long)mc
);
366 if (mac_gestalts
.apprvers
>= 0x100) {
367 Boolean isdefault
= ctrl
->button
.isdefault
;
369 SetControlData(mc
->button
.tbctrl
, kControlEntireControl
,
370 kControlPushButtonDefaultTag
,
371 sizeof(isdefault
), &isdefault
);
372 } else if (ctrl
->button
.isdefault
) {
373 InsetRect(&bounds
, -4, -4);
374 NewControl(window
, &bounds
, title
, TRUE
, 0, 0, 1,
375 SYS7_DEFAULT_PROC
, (long)mc
);
377 if (mac_gestalts
.apprvers
>= 0x110) {
378 Boolean iscancel
= ctrl
->button
.iscancel
;
380 SetControlData(mc
->button
.tbctrl
, kControlEntireControl
,
381 kControlPushButtonCancelTag
,
382 sizeof(iscancel
), &iscancel
);
384 add234(mcs
->byctrl
, mc
);
385 curstate
->pos
.v
+= 26;
388 #if !TARGET_API_MAC_CARBON
389 static pascal SInt32
macctrl_sys7_default_cdef(SInt16 variant
,
391 ControlDefProcMessage msg
,
400 if ((*control
)->contrlVis
) {
401 rect
= (*control
)->contrlRect
;
404 oval
= (rect
.bottom
- rect
.top
) / 2 + 2;
405 FrameRoundRect(&rect
, oval
, oval
);
409 if (param
& (1 << 31)) {
415 rgn
= (RgnHandle
)param
;
416 RectRgn(rgn
, &(*control
)->contrlRect
);
420 rgn
= (RgnHandle
)param
;
430 void macctrl_activate(WindowPtr window
, EventRecord
*event
)
432 Boolean active
= (event
->modifiers
& activeFlag
) != 0;
437 SetPort((GrafPtr
)GetWindowPort(window
));
438 if (mac_gestalts
.apprvers
>= 0x100) {
439 SetThemeWindowBackground(window
, active ?
440 kThemeBrushModelessDialogBackgroundActive
:
441 kThemeBrushModelessDialogBackgroundInactive
,
443 GetRootControl(window
, &root
);
445 ActivateControl(root
);
447 DeactivateControl(root
);
449 /* (De)activate controls one at a time */
454 void macctrl_click(WindowPtr window
, EventRecord
*event
)
457 ControlHandle control
;
461 struct macctrls
*mcs
= mac_winctrls(window
);
465 SetPort((GrafPtr
)GetWindowPort(window
));
466 mouse
= event
->where
;
467 GlobalToLocal(&mouse
);
468 part
= FindControl(mouse
, window
, &control
);
470 if (TrackControl(control
, mouse
, NULL
) != 0) {
471 mc
= (union macctrl
*)GetControlReference(control
);
472 switch (mc
->generic
.type
) {
474 for (i
= 0; i
< mc
->generic
.ctrl
->radio
.nbuttons
; i
++) {
475 if (mc
->radio
.tbctrls
[i
] == control
)
476 SetControlValue(mc
->radio
.tbctrls
[i
],
477 kControlRadioButtonCheckedValue
);
479 SetControlValue(mc
->radio
.tbctrls
[i
],
480 kControlRadioButtonUncheckedValue
);
482 ctrlevent(mcs
, mc
, EVENT_VALCHANGE
);
484 case MACCTRL_CHECKBOX
:
485 SetControlValue(control
, !GetControlValue(control
));
486 ctrlevent(mcs
, mc
, EVENT_VALCHANGE
);
489 ctrlevent(mcs
, mc
, EVENT_ACTION
);
496 void macctrl_update(WindowPtr window
)
498 #if TARGET_API_MAC_CARBON
506 SetPort((GrafPtr
)GetWindowPort(window
));
507 if (mac_gestalts
.apprvers
>= 0x101) {
508 #if TARGET_API_MAC_CARBON
509 GetPortBounds(GetWindowPort(window
), &rect
);
511 rect
= window
->portRect
;
513 InsetRect(&rect
, -1, -1);
514 DrawThemeModelessDialogFrame(&rect
, mac_frontwindow() == window ?
515 kThemeStateActive
: kThemeStateInactive
);
517 #if TARGET_API_MAC_CARBON
519 GetPortVisibleRegion(GetWindowPort(window
), visrgn
);
520 UpdateControls(window
, visrgn
);
523 UpdateControls(window
, window
->visRgn
);
529 #if TARGET_API_MAC_CARBON
530 #define EnableItem EnableMenuItem
531 #define DisableItem DisableMenuItem
533 void macctrl_adjustmenus(WindowPtr window
)
537 menu
= GetMenuHandle(mFile
);
538 DisableItem(menu
, iSave
); /* XXX enable if modified */
539 EnableItem(menu
, iSaveAs
);
540 EnableItem(menu
, iDuplicate
);
542 menu
= GetMenuHandle(mEdit
);
543 DisableItem(menu
, 0);
546 void macctrl_close(WindowPtr window
)
548 struct macctrls
*mcs
= mac_winctrls(window
);
551 while ((mc
= index234(mcs
->byctrl
, 0)) != NULL
) {
552 del234(mcs
->byctrl
, mc
);
556 freetree234(mcs
->byctrl
);
560 DisposeWindow(window);
561 if (s->window == NULL)
566 void dlg_update_start(union control
*ctrl
, void *dlg
)
572 void dlg_update_done(union control
*ctrl
, void *dlg
)
578 void dlg_set_focus(union control
*ctrl
, void *dlg
)
581 if (mac_gestalts
.apprvers
>= 0x100) {
582 /* Use SetKeyboardFocus() */
584 /* Do our own mucking around */
588 union control
*dlg_last_focused(union control
*ctrl
, void *dlg
)
594 void dlg_beep(void *dlg
)
600 void dlg_error_msg(void *dlg
, char *msg
)
604 c2pstrcpy(pmsg
, msg
);
605 ParamText(pmsg
, NULL
, NULL
, NULL
);
606 StopAlert(128, NULL
);
609 void dlg_end(void *dlg
, int value
)
614 void dlg_refresh(union control
*ctrl
, void *dlg
)
619 void *dlg_get_privdata(union control
*ctrl
, void *dlg
)
625 void dlg_set_privdata(union control
*ctrl
, void *dlg
, void *ptr
)
628 fatalbox("dlg_set_privdata");
631 void *dlg_alloc_privdata(union control
*ctrl
, void *dlg
, size_t size
)
634 fatalbox("dlg_alloc_privdata");
639 * Radio Button control
642 void dlg_radiobutton_set(union control
*ctrl
, void *dlg
, int whichbutton
)
644 union macctrl
*mc
= dlg
;
647 for (i
= 0; i
< ctrl
->radio
.nbuttons
; i
++) {
648 if (i
== whichbutton
)
649 SetControlValue(mc
->radio
.tbctrls
[i
],
650 kControlRadioButtonCheckedValue
);
652 SetControlValue(mc
->radio
.tbctrls
[i
],
653 kControlRadioButtonUncheckedValue
);
658 int dlg_radiobutton_get(union control
*ctrl
, void *dlg
)
660 union macctrl
*mc
= dlg
;
663 for (i
= 0; i
< ctrl
->radio
.nbuttons
; i
++) {
664 if (GetControlValue(mc
->radio
.tbctrls
[i
]) ==
665 kControlRadioButtonCheckedValue
)
676 void dlg_checkbox_set(union control
*ctrl
, void *dlg
, int checked
)
678 union macctrl
*mc
= dlg
;
680 SetControlValue(mc
->checkbox
.tbctrl
,
681 checked ? kControlCheckBoxCheckedValue
:
682 kControlCheckBoxUncheckedValue
);
685 int dlg_checkbox_get(union control
*ctrl
, void *dlg
)
687 union macctrl
*mc
= dlg
;
689 return GetControlValue(mc
->checkbox
.tbctrl
);
697 void dlg_editbox_set(union control
*ctrl
, void *dlg
, char const *text
)
702 void dlg_editbox_get(union control
*ctrl
, void *dlg
, char *buffer
, int length
)
712 void dlg_listbox_clear(union control
*ctrl
, void *dlg
)
717 void dlg_listbox_del(union control
*ctrl
, void *dlg
, int index
)
722 void dlg_listbox_add(union control
*ctrl
, void *dlg
, char const *text
)
727 void dlg_listbox_addwithindex(union control
*ctrl
, void *dlg
,
728 char const *text
, int id
)
733 int dlg_listbox_getid(union control
*ctrl
, void *dlg
, int index
)
739 int dlg_listbox_index(union control
*ctrl
, void *dlg
)
745 int dlg_listbox_issel(union control
*ctrl
, void *dlg
, int index
)
751 void dlg_listbox_select(union control
*ctrl
, void *dlg
, int index
)
761 void dlg_text_set(union control
*ctrl
, void *dlg
, char const *text
)
763 union macctrl
*mc
= dlg
;
766 if (mac_gestalts
.apprvers
>= 0x100)
767 SetControlData(mc
->text
.tbctrl
, kControlEntireControl
,
768 kControlStaticTextTextTag
,
769 strlen(ctrl
->text
.label
), ctrl
->text
.label
);
771 c2pstrcpy(title
, text
);
772 SetControlTitle(mc
->text
.tbctrl
, title
);
778 * File Selector control
781 void dlg_filesel_set(union control
*ctrl
, void *dlg
, Filename fn
)
786 void dlg_filesel_get(union control
*ctrl
, void *dlg
, Filename
*fn
)
793 * Font Selector control
796 void dlg_fontsel_set(union control
*ctrl
, void *dlg
, FontSpec fn
)
801 void dlg_fontsel_get(union control
*ctrl
, void *dlg
, FontSpec
*fn
)
808 * Printer enumeration
811 printer_enum
*printer_start_enum(int *nprinters
)
818 char *printer_get_name(printer_enum
*pe
, int thing
)
824 void printer_finish_enum(printer_enum
*pe
)
831 * Colour selection stuff
834 void dlg_coloursel_start(union control
*ctrl
, void *dlg
,
840 int dlg_coloursel_results(union control
*ctrl
, void *dlg
,
841 int *r
, int *g
, int *b
)
849 * c-file-style: "simon"