1 /* $Id: macctrls.c,v 1.7 2003/03/20 23:15:25 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>
46 struct macctrl_generic
{
53 /* Template from which this was generated */
57 struct macctrl_generic generic
;
61 struct macctrl_generic generic
;
65 struct macctrl_generic generic
;
69 struct macctrl_generic generic
;
74 struct mac_layoutstate
{
79 #define ctrlevent(mcs, mc, event) do { \
80 if ((mc)->generic.ctrl->generic.handler != NULL) \
81 (*(mc)->generic.ctrl->generic.handler)((mc)->generic.ctrl, (mcs),\
82 (mcs)->data, (event)); \
85 #define findbyctrl(mcs, ctrl) \
86 find234((mcs)->byctrl, (ctrl), macctrl_cmp_byctrl_find)
88 static void macctrl_layoutset(struct mac_layoutstate
*, struct controlset
*,
89 WindowPtr
, struct macctrls
*);
90 static void macctrl_text(struct macctrls
*, WindowPtr
,
91 struct mac_layoutstate
*, union control
*);
92 static void macctrl_radio(struct macctrls
*, WindowPtr
,
93 struct mac_layoutstate
*, union control
*);
94 static void macctrl_checkbox(struct macctrls
*, WindowPtr
,
95 struct mac_layoutstate
*, union control
*);
96 static void macctrl_button(struct macctrls
*, WindowPtr
,
97 struct mac_layoutstate
*, union control
*);
98 #if !TARGET_API_MAC_CARBON
99 static pascal SInt32
macctrl_sys7_text_cdef(SInt16
, ControlRef
,
100 ControlDefProcMessage
, SInt32
);
101 static pascal SInt32
macctrl_sys7_default_cdef(SInt16
, ControlRef
,
102 ControlDefProcMessage
, SInt32
);
105 #if !TARGET_API_MAC_CARBON
107 * This trick enables us to keep all the CDEF code in the main
108 * application, which makes life easier. For details, see
109 * <http://developer.apple.com/technotes/tn/tn2003.html#custom_code_base>.
112 #pragma options align=mac68k
114 short jmpabs
; /* 4EF9 */
115 ControlDefUPP theUPP
;
117 #pragma options align=reset
120 static void macctrl_init()
122 #if !TARGET_API_MAC_CARBON
123 static int inited
= 0;
127 cdef
= (PatchCDEF
)GetResource(kControlDefProcResourceType
, CDEF_Text
);
128 (*cdef
)->theUPP
= NewControlDefProc(macctrl_sys7_text_cdef
);
129 cdef
= (PatchCDEF
)GetResource(kControlDefProcResourceType
, CDEF_Default
);
130 (*cdef
)->theUPP
= NewControlDefProc(macctrl_sys7_default_cdef
);
136 static int macctrl_cmp_byctrl(void *av
, void *bv
)
138 union macctrl
*a
= (union macctrl
*)av
;
139 union macctrl
*b
= (union macctrl
*)bv
;
141 if (a
->generic
.ctrl
< b
->generic
.ctrl
)
143 else if (a
->generic
.ctrl
> b
->generic
.ctrl
)
149 static int macctrl_cmp_byctrl_find(void *av
, void *bv
)
151 union control
*a
= (union control
*)av
;
152 union macctrl
*b
= (union macctrl
*)bv
;
154 if (a
< b
->generic
.ctrl
)
156 else if (a
> b
->generic
.ctrl
)
162 void macctrl_layoutbox(struct controlbox
*cb
, WindowPtr window
,
163 struct macctrls
*mcs
)
166 struct mac_layoutstate curstate
;
171 #if TARGET_API_MAC_CARBON
172 GetPortBounds(GetWindowPort(window
), &rect
);
174 rect
= window
->portRect
;
176 curstate
.pos
.h
= rect
.left
+ 13;
177 curstate
.pos
.v
= rect
.top
+ 13;
178 curstate
.width
= rect
.right
- rect
.left
- (13 * 2);
179 if (mac_gestalts
.apprvers
>= 0x100)
180 CreateRootControl(window
, &root
);
181 mcs
->byctrl
= newtree234(macctrl_cmp_byctrl
);
182 for (i
= 0; i
< cb
->nctrlsets
; i
++)
183 macctrl_layoutset(&curstate
, cb
->ctrlsets
[i
], window
, mcs
);
186 static void macctrl_layoutset(struct mac_layoutstate
*curstate
,
187 struct controlset
*s
,
188 WindowPtr window
, struct macctrls
*mcs
)
192 fprintf(stderr
, "--- begin set ---\n");
193 fprintf(stderr
, "pathname = %s\n", s
->pathname
);
194 if (s
->boxname
&& *s
->boxname
)
195 fprintf(stderr
, "boxname = %s\n", s
->boxname
);
197 fprintf(stderr
, "boxtitle = %s\n", s
->boxtitle
);
200 for (i
= 0; i
< s
->ncontrols
; i
++) {
201 union control
*ctrl
= s
->ctrls
[i
];
204 switch (ctrl
->generic
.type
) {
205 case CTRL_TEXT
: s
= "text"; break;
206 case CTRL_EDITBOX
: s
= "editbox"; break;
207 case CTRL_RADIO
: s
= "radio"; break;
208 case CTRL_CHECKBOX
: s
= "checkbox"; break;
209 case CTRL_BUTTON
: s
= "button"; break;
210 case CTRL_LISTBOX
: s
= "listbox"; break;
211 case CTRL_COLUMNS
: s
= "columns"; break;
212 case CTRL_FILESELECT
: s
= "fileselect"; break;
213 case CTRL_FONTSELECT
: s
= "fontselect"; break;
214 case CTRL_TABDELAY
: s
= "tabdelay"; break;
215 default: s
= "unknown"; break;
217 fprintf(stderr
, " control: %s\n", s
);
218 switch (ctrl
->generic
.type
) {
220 macctrl_text(mcs
, window
, curstate
, ctrl
);
223 macctrl_radio(mcs
, window
, curstate
, ctrl
);
226 macctrl_checkbox(mcs
, window
, curstate
, ctrl
);
229 macctrl_button(mcs
, window
, curstate
, ctrl
);
236 static void macctrl_text(struct macctrls
*mcs
, WindowPtr window
,
237 struct mac_layoutstate
*curstate
,
240 union macctrl
*mc
= smalloc(sizeof *mc
);
243 fprintf(stderr
, " label = %s\n", ctrl
->text
.label
);
244 mc
->generic
.type
= MACCTRL_TEXT
;
245 mc
->generic
.ctrl
= ctrl
;
246 bounds
.left
= curstate
->pos
.h
;
247 bounds
.right
= bounds
.left
+ curstate
->width
;
248 bounds
.top
= curstate
->pos
.v
;
249 bounds
.bottom
= bounds
.top
+ 16;
250 if (mac_gestalts
.apprvers
>= 0x100) {
254 mc
->text
.tbctrl
= NewControl(window
, &bounds
, NULL
, TRUE
, 0, 0, 0,
255 kControlStaticTextProc
, (long)mc
);
256 SetControlData(mc
->text
.tbctrl
, kControlEntireControl
,
257 kControlStaticTextTextTag
,
258 strlen(ctrl
->text
.label
), ctrl
->text
.label
);
259 GetControlData(mc
->text
.tbctrl
, kControlEntireControl
,
260 kControlStaticTextTextHeightTag
,
261 sizeof(height
), &height
, &olen
);
262 fprintf(stderr
, " height = %d\n", height
);
263 SizeControl(mc
->text
.tbctrl
, curstate
->width
, height
);
264 curstate
->pos
.v
+= height
+ 6;
268 c2pstrcpy(title
, ctrl
->text
.label
);
269 mc
->text
.tbctrl
= NewControl(window
, &bounds
, title
, TRUE
, 0, 0, 0,
270 SYS7_TEXT_PROC
, (long)mc
);
272 add234(mcs
->byctrl
, mc
);
275 #if !TARGET_API_MAC_CARBON
276 static pascal SInt32
macctrl_sys7_text_cdef(SInt16 variant
, ControlRef control
,
277 ControlDefProcMessage msg
, SInt32 param
)
283 if ((*control
)->contrlVis
)
284 TETextBox((*control
)->contrlTitle
+ 1, (*control
)->contrlTitle
[0],
285 &(*control
)->contrlRect
, teFlushDefault
);
288 if (param
& (1 << 31)) {
294 rgn
= (RgnHandle
)param
;
295 RectRgn(rgn
, &(*control
)->contrlRect
);
299 rgn
= (RgnHandle
)param
;
308 static void macctrl_radio(struct macctrls
*mcs
, WindowPtr window
,
309 struct mac_layoutstate
*curstate
,
312 union macctrl
*mc
= smalloc(sizeof *mc
);
315 unsigned int i
, colwidth
;
317 fprintf(stderr
, " label = %s\n", ctrl
->radio
.label
);
318 mc
->generic
.type
= MACCTRL_RADIO
;
319 mc
->generic
.ctrl
= ctrl
;
321 smalloc(sizeof(*mc
->radio
.tbctrls
) * ctrl
->radio
.nbuttons
);
322 colwidth
= (curstate
->width
+ 13) / ctrl
->radio
.ncolumns
;
323 for (i
= 0; i
< ctrl
->radio
.nbuttons
; i
++) {
324 fprintf(stderr
, " button = %s\n", ctrl
->radio
.buttons
[i
]);
325 bounds
.top
= curstate
->pos
.v
;
326 bounds
.bottom
= bounds
.top
+ 16;
327 bounds
.left
= curstate
->pos
.h
+ colwidth
* (i
% ctrl
->radio
.ncolumns
);
328 if (i
== ctrl
->radio
.nbuttons
- 1 ||
329 i
% ctrl
->radio
.ncolumns
== ctrl
->radio
.ncolumns
- 1) {
330 bounds
.right
= curstate
->pos
.h
+ curstate
->width
;
331 curstate
->pos
.v
+= 22;
333 bounds
.right
= bounds
.left
+ colwidth
- 13;
334 c2pstrcpy(title
, ctrl
->radio
.buttons
[i
]);
335 mc
->radio
.tbctrls
[i
] = NewControl(window
, &bounds
, title
, TRUE
,
336 0, 0, 1, radioButProc
, (long)mc
);
338 add234(mcs
->byctrl
, mc
);
339 ctrlevent(mcs
, mc
, EVENT_REFRESH
);
342 static void macctrl_checkbox(struct macctrls
*mcs
, WindowPtr window
,
343 struct mac_layoutstate
*curstate
,
346 union macctrl
*mc
= smalloc(sizeof *mc
);
350 fprintf(stderr
, " label = %s\n", ctrl
->checkbox
.label
);
351 mc
->generic
.type
= MACCTRL_CHECKBOX
;
352 mc
->generic
.ctrl
= ctrl
;
353 bounds
.left
= curstate
->pos
.h
;
354 bounds
.right
= bounds
.left
+ curstate
->width
;
355 bounds
.top
= curstate
->pos
.v
;
356 bounds
.bottom
= bounds
.top
+ 16;
357 c2pstrcpy(title
, ctrl
->checkbox
.label
);
358 mc
->checkbox
.tbctrl
= NewControl(window
, &bounds
, title
, TRUE
, 0, 0, 1,
359 checkBoxProc
, (long)mc
);
360 add234(mcs
->byctrl
, mc
);
361 curstate
->pos
.v
+= 22;
362 ctrlevent(mcs
, mc
, EVENT_REFRESH
);
365 static void macctrl_button(struct macctrls
*mcs
, WindowPtr window
,
366 struct mac_layoutstate
*curstate
,
369 union macctrl
*mc
= smalloc(sizeof *mc
);
373 fprintf(stderr
, " label = %s\n", ctrl
->button
.label
);
374 if (ctrl
->button
.isdefault
)
375 fprintf(stderr
, " is default\n");
376 mc
->generic
.type
= MACCTRL_BUTTON
;
377 mc
->generic
.ctrl
= ctrl
;
378 bounds
.left
= curstate
->pos
.h
;
379 bounds
.right
= bounds
.left
+ 100; /* XXX measure string */
380 bounds
.top
= curstate
->pos
.v
;
381 bounds
.bottom
= bounds
.top
+ 20;
382 c2pstrcpy(title
, ctrl
->button
.label
);
383 mc
->button
.tbctrl
= NewControl(window
, &bounds
, title
, TRUE
, 0, 0, 1,
384 pushButProc
, (long)mc
);
385 if (mac_gestalts
.apprvers
>= 0x100) {
386 Boolean isdefault
= ctrl
->button
.isdefault
;
388 SetControlData(mc
->button
.tbctrl
, kControlEntireControl
,
389 kControlPushButtonDefaultTag
,
390 sizeof(isdefault
), &isdefault
);
391 } else if (ctrl
->button
.isdefault
) {
392 InsetRect(&bounds
, -4, -4);
393 NewControl(window
, &bounds
, title
, TRUE
, 0, 0, 1,
394 SYS7_DEFAULT_PROC
, (long)mc
);
396 if (mac_gestalts
.apprvers
>= 0x110) {
397 Boolean iscancel
= ctrl
->button
.iscancel
;
399 SetControlData(mc
->button
.tbctrl
, kControlEntireControl
,
400 kControlPushButtonCancelTag
,
401 sizeof(iscancel
), &iscancel
);
403 add234(mcs
->byctrl
, mc
);
404 curstate
->pos
.v
+= 26;
407 #if !TARGET_API_MAC_CARBON
408 static pascal SInt32
macctrl_sys7_default_cdef(SInt16 variant
,
410 ControlDefProcMessage msg
,
419 if ((*control
)->contrlVis
) {
420 rect
= (*control
)->contrlRect
;
423 oval
= (rect
.bottom
- rect
.top
) / 2 + 2;
424 FrameRoundRect(&rect
, oval
, oval
);
428 if (param
& (1 << 31)) {
434 rgn
= (RgnHandle
)param
;
435 RectRgn(rgn
, &(*control
)->contrlRect
);
439 rgn
= (RgnHandle
)param
;
449 void macctrl_activate(WindowPtr window
, EventRecord
*event
)
451 Boolean active
= (event
->modifiers
& activeFlag
) != 0;
456 SetPort((GrafPtr
)GetWindowPort(window
));
457 if (mac_gestalts
.apprvers
>= 0x100) {
458 SetThemeWindowBackground(window
, active ?
459 kThemeBrushModelessDialogBackgroundActive
:
460 kThemeBrushModelessDialogBackgroundInactive
,
462 GetRootControl(window
, &root
);
464 ActivateControl(root
);
466 DeactivateControl(root
);
468 /* (De)activate controls one at a time */
473 void macctrl_click(WindowPtr window
, EventRecord
*event
)
476 ControlHandle control
;
480 struct macctrls
*mcs
= mac_winctrls(window
);
484 SetPort((GrafPtr
)GetWindowPort(window
));
485 mouse
= event
->where
;
486 GlobalToLocal(&mouse
);
487 part
= FindControl(mouse
, window
, &control
);
489 if (TrackControl(control
, mouse
, NULL
) != 0) {
490 mc
= (union macctrl
*)GetControlReference(control
);
491 switch (mc
->generic
.type
) {
493 for (i
= 0; i
< mc
->generic
.ctrl
->radio
.nbuttons
; i
++) {
494 if (mc
->radio
.tbctrls
[i
] == control
)
495 SetControlValue(mc
->radio
.tbctrls
[i
],
496 kControlRadioButtonCheckedValue
);
498 SetControlValue(mc
->radio
.tbctrls
[i
],
499 kControlRadioButtonUncheckedValue
);
501 ctrlevent(mcs
, mc
, EVENT_VALCHANGE
);
503 case MACCTRL_CHECKBOX
:
504 SetControlValue(control
, !GetControlValue(control
));
505 ctrlevent(mcs
, mc
, EVENT_VALCHANGE
);
508 ctrlevent(mcs
, mc
, EVENT_ACTION
);
515 void macctrl_update(WindowPtr window
)
517 #if TARGET_API_MAC_CARBON
525 SetPort((GrafPtr
)GetWindowPort(window
));
526 if (mac_gestalts
.apprvers
>= 0x101) {
527 #if TARGET_API_MAC_CARBON
528 GetPortBounds(GetWindowPort(window
), &rect
);
530 rect
= window
->portRect
;
532 InsetRect(&rect
, -1, -1);
533 DrawThemeModelessDialogFrame(&rect
, mac_frontwindow() == window ?
534 kThemeStateActive
: kThemeStateInactive
);
536 #if TARGET_API_MAC_CARBON
538 GetPortVisibleRegion(GetWindowPort(window
), visrgn
);
539 UpdateControls(window
, visrgn
);
542 UpdateControls(window
, window
->visRgn
);
548 #if TARGET_API_MAC_CARBON
549 #define EnableItem EnableMenuItem
550 #define DisableItem DisableMenuItem
552 void macctrl_adjustmenus(WindowPtr window
)
556 menu
= GetMenuHandle(mFile
);
557 DisableItem(menu
, iSave
); /* XXX enable if modified */
558 EnableItem(menu
, iSaveAs
);
559 EnableItem(menu
, iDuplicate
);
561 menu
= GetMenuHandle(mEdit
);
562 DisableItem(menu
, 0);
565 void macctrl_close(WindowPtr window
)
567 struct macctrls
*mcs
= mac_winctrls(window
);
570 while ((mc
= index234(mcs
->byctrl
, 0)) != NULL
) {
571 del234(mcs
->byctrl
, mc
);
575 freetree234(mcs
->byctrl
);
579 DisposeWindow(window);
580 if (s->window == NULL)
585 void dlg_update_start(union control
*ctrl
, void *dlg
)
591 void dlg_update_done(union control
*ctrl
, void *dlg
)
597 void dlg_set_focus(union control
*ctrl
, void *dlg
)
600 if (mac_gestalts
.apprvers
>= 0x100) {
601 /* Use SetKeyboardFocus() */
603 /* Do our own mucking around */
607 union control
*dlg_last_focused(union control
*ctrl
, void *dlg
)
613 void dlg_beep(void *dlg
)
619 void dlg_error_msg(void *dlg
, char *msg
)
623 c2pstrcpy(pmsg
, msg
);
624 ParamText(pmsg
, NULL
, NULL
, NULL
);
625 StopAlert(128, NULL
);
628 void dlg_end(void *dlg
, int value
)
633 void dlg_refresh(union control
*ctrl
, void *dlg
)
638 void *dlg_get_privdata(union control
*ctrl
, void *dlg
)
644 void dlg_set_privdata(union control
*ctrl
, void *dlg
, void *ptr
)
647 fatalbox("dlg_set_privdata");
650 void *dlg_alloc_privdata(union control
*ctrl
, void *dlg
, size_t size
)
653 fatalbox("dlg_alloc_privdata");
658 * Radio Button control
661 void dlg_radiobutton_set(union control
*ctrl
, void *dlg
, int whichbutton
)
663 struct macctrls
*mcs
= dlg
;
664 union macctrl
*mc
= findbyctrl(mcs
, ctrl
);
668 for (i
= 0; i
< ctrl
->radio
.nbuttons
; i
++) {
669 if (i
== whichbutton
)
670 SetControlValue(mc
->radio
.tbctrls
[i
],
671 kControlRadioButtonCheckedValue
);
673 SetControlValue(mc
->radio
.tbctrls
[i
],
674 kControlRadioButtonUncheckedValue
);
679 int dlg_radiobutton_get(union control
*ctrl
, void *dlg
)
681 struct macctrls
*mcs
= dlg
;
682 union macctrl
*mc
= findbyctrl(mcs
, ctrl
);
686 for (i
= 0; i
< ctrl
->radio
.nbuttons
; i
++) {
687 if (GetControlValue(mc
->radio
.tbctrls
[i
]) ==
688 kControlRadioButtonCheckedValue
)
699 void dlg_checkbox_set(union control
*ctrl
, void *dlg
, int checked
)
701 struct macctrls
*mcs
= dlg
;
702 union macctrl
*mc
= findbyctrl(mcs
, ctrl
);
705 SetControlValue(mc
->checkbox
.tbctrl
,
706 checked ? kControlCheckBoxCheckedValue
:
707 kControlCheckBoxUncheckedValue
);
710 int dlg_checkbox_get(union control
*ctrl
, void *dlg
)
712 struct macctrls
*mcs
= dlg
;
713 union macctrl
*mc
= findbyctrl(mcs
, ctrl
);
716 return GetControlValue(mc
->checkbox
.tbctrl
);
724 void dlg_editbox_set(union control
*ctrl
, void *dlg
, char const *text
)
729 void dlg_editbox_get(union control
*ctrl
, void *dlg
, char *buffer
, int length
)
739 void dlg_listbox_clear(union control
*ctrl
, void *dlg
)
744 void dlg_listbox_del(union control
*ctrl
, void *dlg
, int index
)
749 void dlg_listbox_add(union control
*ctrl
, void *dlg
, char const *text
)
754 void dlg_listbox_addwithindex(union control
*ctrl
, void *dlg
,
755 char const *text
, int id
)
760 int dlg_listbox_getid(union control
*ctrl
, void *dlg
, int index
)
766 int dlg_listbox_index(union control
*ctrl
, void *dlg
)
772 int dlg_listbox_issel(union control
*ctrl
, void *dlg
, int index
)
778 void dlg_listbox_select(union control
*ctrl
, void *dlg
, int index
)
788 void dlg_text_set(union control
*ctrl
, void *dlg
, char const *text
)
790 struct macctrls
*mcs
= dlg
;
791 union macctrl
*mc
= findbyctrl(mcs
, ctrl
);
795 if (mac_gestalts
.apprvers
>= 0x100)
796 SetControlData(mc
->text
.tbctrl
, kControlEntireControl
,
797 kControlStaticTextTextTag
,
798 strlen(ctrl
->text
.label
), ctrl
->text
.label
);
800 c2pstrcpy(title
, text
);
801 SetControlTitle(mc
->text
.tbctrl
, title
);
807 * File Selector control
810 void dlg_filesel_set(union control
*ctrl
, void *dlg
, Filename fn
)
815 void dlg_filesel_get(union control
*ctrl
, void *dlg
, Filename
*fn
)
822 * Font Selector control
825 void dlg_fontsel_set(union control
*ctrl
, void *dlg
, FontSpec fn
)
830 void dlg_fontsel_get(union control
*ctrl
, void *dlg
, FontSpec
*fn
)
837 * Printer enumeration
840 printer_enum
*printer_start_enum(int *nprinters
)
847 char *printer_get_name(printer_enum
*pe
, int thing
)
853 void printer_finish_enum(printer_enum
*pe
)
860 * Colour selection stuff
863 void dlg_coloursel_start(union control
*ctrl
, void *dlg
,
869 int dlg_coloursel_results(union control
*ctrl
, void *dlg
,
870 int *r
, int *g
, int *b
)
878 * c-file-style: "simon"