1 /* $Id: macctrls.c,v 1.3 2003/03/18 19:06:51 simon 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);
98 #if !TARGET_API_MAC_CARBON
100 * This trick enables us to keep all the CDEF code in the main
101 * application, which makes life easier. For details, see
102 * <http://developer.apple.com/technotes/tn/tn2003.html#custom_code_base>.
105 #pragma options align=mac68k
107 short jmpabs; /* 4EF9 */
108 ControlDefUPP theUPP;
110 #pragma options align=reset
113 static void macctrl_init()
115 #if !TARGET_API_MAC_CARBON
116 static int inited = 0;
120 cdef = (PatchCDEF)GetResource(kControlDefProcResourceType, CDEF_Text);
121 (*cdef)->theUPP = NewControlDefProc(macctrl_sys7_text_cdef);
127 static int macctrl_cmp_byctrl(void *av, void *bv)
129 union macctrl *a = (union macctrl *)av;
130 union macctrl *b = (union macctrl *)bv;
132 if (a->generic.ctrl < b->generic.ctrl)
134 else if (a->generic.ctrl > b->generic.ctrl)
140 void macctrl_layoutbox(struct controlbox *cb, WindowPtr window,
141 struct macctrls *mcs)
144 struct mac_layoutstate curstate;
149 #if TARGET_API_MAC_CARBON
150 GetPortBounds(GetWindowPort(window), &rect);
152 rect = window->portRect;
154 curstate.pos.h = rect.left + 13;
155 curstate.pos.v = rect.top + 13;
156 curstate.width = rect.right - rect.left - (13 * 2);
157 if (mac_gestalts.apprvers >= 0x100)
158 CreateRootControl(window, &root);
159 mcs->byctrl = newtree234(macctrl_cmp_byctrl);
160 for (i = 0; i < cb->nctrlsets; i++)
161 macctrl_layoutset(&curstate, cb->ctrlsets[i], window, mcs);
164 static void macctrl_layoutset(struct mac_layoutstate *curstate,
165 struct controlset *s,
166 WindowPtr window, struct macctrls *mcs)
170 fprintf(stderr, "--- begin set ---\n");
171 if (s->boxname && *s->boxname)
172 fprintf(stderr, "boxname = %s\n", s->boxname);
174 fprintf(stderr, "boxtitle = %s\n", s->boxtitle);
177 for (i = 0; i < s->ncontrols; i++) {
178 union control *ctrl = s->ctrls[i];
181 switch (ctrl->generic.type) {
182 case CTRL_TEXT: s = "text"; break;
183 case CTRL_EDITBOX: s = "editbox"; break;
184 case CTRL_RADIO: s = "radio"; break;
185 case CTRL_CHECKBOX: s = "checkbox"; break;
186 case CTRL_BUTTON: s = "button"; break;
187 case CTRL_LISTBOX: s = "listbox"; break;
188 case CTRL_COLUMNS: s = "columns"; break;
189 case CTRL_FILESELECT: s = "fileselect"; break;
190 case CTRL_FONTSELECT: s = "fontselect"; break;
191 case CTRL_TABDELAY: s = "tabdelay"; break;
192 default: s = "unknown"; break;
194 fprintf(stderr, " control: %s\n", s);
195 switch (ctrl->generic.type) {
197 macctrl_text(mcs, window, curstate, ctrl);
200 macctrl_radio(mcs, window, curstate, ctrl);
203 macctrl_checkbox(mcs, window, curstate, ctrl);
206 macctrl_button(mcs, window, curstate, ctrl);
213 static void macctrl_text(struct macctrls *mcs, WindowPtr window,
214 struct mac_layoutstate *curstate,
217 union macctrl *mc = smalloc(sizeof *mc);
220 fprintf(stderr, " label = %s\n", ctrl->text.label);
221 mc->generic.type = MACCTRL_TEXT;
222 mc->generic.ctrl = ctrl;
223 bounds.left = curstate->pos.h;
224 bounds.right = bounds.left + curstate->width;
225 bounds.top = curstate->pos.v;
226 bounds.bottom = bounds.top + 16;
227 if (mac_gestalts.apprvers >= 0x100) {
231 mc->text.tbctrl = NewControl(window, &bounds, NULL, TRUE, 0, 0, 0,
232 kControlStaticTextProc, (long)mc);
233 SetControlData(mc->text.tbctrl, kControlEntireControl,
234 kControlStaticTextTextTag,
235 strlen(ctrl->text.label), ctrl->text.label);
236 GetControlData(mc->text.tbctrl, kControlEntireControl,
237 kControlStaticTextTextHeightTag,
238 sizeof(height), &height, &olen);
239 fprintf(stderr, " height = %d\n", height);
240 SizeControl(mc->text.tbctrl, curstate->width, height);
241 curstate->pos.v += height + 6;
245 c2pstrcpy(title, ctrl->text.label);
246 mc->text.tbctrl = NewControl(window, &bounds, title, TRUE, 0, 0, 0,
247 SYS7_TEXT_PROC, (long)mc);
249 add234(mcs->byctrl, mc);
252 #if !TARGET_API_MAC_CARBON
253 static pascal SInt32 macctrl_sys7_text_cdef(SInt16 variant, ControlRef control,
254 ControlDefProcMessage msg, SInt32 param)
260 if ((*control)->contrlVis)
261 TETextBox((*control)->contrlTitle + 1, (*control)->contrlTitle[0],
262 &(*control)->contrlRect, teFlushDefault);
265 if (param & (1 << 31)) {
271 rgn = (RgnHandle)param;
272 RectRgn(rgn, &(*control)->contrlRect);
276 rgn = (RgnHandle)param;
285 static void macctrl_radio(struct macctrls *mcs, WindowPtr window,
286 struct mac_layoutstate *curstate,
289 union macctrl *mc = smalloc(sizeof *mc);
292 unsigned int i, colwidth;
294 fprintf(stderr, " label = %s\n", ctrl->radio.label);
295 mc->generic.type = MACCTRL_RADIO;
296 mc->generic.ctrl = ctrl;
298 smalloc(sizeof(*mc->radio.tbctrls) * ctrl->radio.nbuttons);
299 colwidth = (curstate->width + 13) / ctrl->radio.ncolumns;
300 for (i = 0; i < ctrl->radio.nbuttons; i++) {
301 fprintf(stderr, " button = %s\n", ctrl->radio.buttons[i]);
302 bounds.top = curstate->pos.v;
303 bounds.bottom = bounds.top + 16;
304 bounds.left = curstate->pos.h + colwidth * (i % ctrl->radio.ncolumns);
305 if (i == ctrl->radio.nbuttons - 1 ||
306 i % ctrl->radio.ncolumns == ctrl->radio.ncolumns - 1) {
307 bounds.right = curstate->pos.h + curstate->width;
308 curstate->pos.v += 22;
310 bounds.right = bounds.left + colwidth - 13;
311 c2pstrcpy(title, ctrl->radio.buttons[i]);
312 mc->radio.tbctrls[i] = NewControl(window, &bounds, title, TRUE,
313 0, 0, 1, radioButProc, (long)mc);
315 add234(mcs->byctrl, mc);
316 ctrlevent(mcs, mc, EVENT_REFRESH);
319 static void macctrl_checkbox(struct macctrls *mcs, WindowPtr window,
320 struct mac_layoutstate *curstate,
323 union macctrl *mc = smalloc(sizeof *mc);
327 fprintf(stderr, " label = %s\n", ctrl->checkbox.label);
328 mc->generic.type = MACCTRL_CHECKBOX;
329 mc->generic.ctrl = ctrl;
330 bounds.left = curstate->pos.h;
331 bounds.right = bounds.left + curstate->width;
332 bounds.top = curstate->pos.v;
333 bounds.bottom = bounds.top + 16;
334 c2pstrcpy(title, ctrl->checkbox.label);
335 mc->checkbox.tbctrl = NewControl(window, &bounds, title, TRUE, 0, 0, 1,
336 checkBoxProc, (long)mc);
337 add234(mcs->byctrl, mc);
338 curstate->pos.v += 22;
339 ctrlevent(mcs, mc, EVENT_REFRESH);
342 static void macctrl_button(struct macctrls *mcs, WindowPtr window,
343 struct mac_layoutstate *curstate,
346 union macctrl *mc = smalloc(sizeof *mc);
350 fprintf(stderr, " label = %s\n", ctrl->button.label);
351 if (ctrl->button.isdefault)
352 fprintf(stderr, " is default\n");
353 mc->generic.type = MACCTRL_BUTTON;
354 mc->generic.ctrl = ctrl;
355 bounds.left = curstate->pos.h;
356 bounds.right = bounds.left + 100; /* XXX measure string */
357 bounds.top = curstate->pos.v;
358 bounds.bottom = bounds.top + 20;
359 c2pstrcpy(title, ctrl->button.label);
360 mc->button.tbctrl = NewControl(window, &bounds, title, TRUE, 0, 0, 1,
361 pushButProc, (long)mc);
362 if (mac_gestalts.apprvers >= 0x100) {
363 Boolean isdefault = ctrl->button.isdefault;
365 SetControlData(mc->button.tbctrl, kControlEntireControl,
366 kControlPushButtonDefaultTag,
367 sizeof(isdefault), &isdefault);
369 add234(mcs->byctrl, mc);
370 curstate->pos.v += 26;
374 void macctrl_activate(WindowPtr window, EventRecord *event)
376 Boolean active = (event->modifiers & activeFlag) != 0;
381 SetPort((GrafPtr)GetWindowPort(window));
382 if (mac_gestalts.apprvers >= 0x100) {
383 SetThemeWindowBackground(window, active ?
384 kThemeBrushModelessDialogBackgroundActive :
385 kThemeBrushModelessDialogBackgroundInactive,
387 GetRootControl(window, &root);
389 ActivateControl(root);
391 DeactivateControl(root);
393 /* (De)activate controls one at a time */
398 void macctrl_click(WindowPtr window, EventRecord *event)
401 ControlHandle control;
405 struct macctrls *mcs = mac_winctrls(window);
409 SetPort((GrafPtr)GetWindowPort(window));
410 mouse = event->where;
411 GlobalToLocal(&mouse);
412 part = FindControl(mouse, window, &control);
414 if (TrackControl(control, mouse, NULL) != 0) {
415 mc = (union macctrl *)GetControlReference(control);
416 switch (mc->generic.type) {
418 for (i = 0; i < mc->generic.ctrl->radio.nbuttons; i++) {
419 if (mc->radio.tbctrls[i] == control)
420 SetControlValue(mc->radio.tbctrls[i],
421 kControlRadioButtonCheckedValue);
423 SetControlValue(mc->radio.tbctrls[i],
424 kControlRadioButtonUncheckedValue);
426 ctrlevent(mcs, mc, EVENT_VALCHANGE);
428 case MACCTRL_CHECKBOX:
429 SetControlValue(control, !GetControlValue(control));
430 ctrlevent(mcs, mc, EVENT_VALCHANGE);
433 ctrlevent(mcs, mc, EVENT_ACTION);
440 void macctrl_update(WindowPtr window)
442 #if TARGET_API_MAC_CARBON
450 SetPort((GrafPtr)GetWindowPort(window));
451 if (mac_gestalts.apprvers >= 0x101) {
452 #if TARGET_API_MAC_CARBON
453 GetPortBounds(GetWindowPort(window), &rect);
455 rect = window->portRect;
457 InsetRect(&rect, -1, -1);
458 DrawThemeModelessDialogFrame(&rect, mac_frontwindow() == window ?
459 kThemeStateActive : kThemeStateInactive);
461 #if TARGET_API_MAC_CARBON
463 GetPortVisibleRegion(GetWindowPort(window), visrgn);
464 UpdateControls(window, visrgn);
467 UpdateControls(window, window->visRgn);
473 #if TARGET_API_MAC_CARBON
474 #define EnableItem EnableMenuItem
475 #define DisableItem DisableMenuItem
477 void macctrl_adjustmenus(WindowPtr window)
481 menu = GetMenuHandle(mFile);
482 DisableItem(menu, iSave); /* XXX enable if modified */
483 EnableItem(menu, iSaveAs);
484 EnableItem(menu, iDuplicate);
486 menu = GetMenuHandle(mEdit);
487 DisableItem(menu, 0);
490 void macctrl_close(WindowPtr window)
492 struct macctrls *mcs = mac_winctrls(window);
495 while ((mc = index234(mcs->byctrl, 0)) != NULL) {
496 del234(mcs->byctrl, mc);
500 freetree234(mcs->byctrl);
504 DisposeWindow(window);
505 if (s->window == NULL)
510 void dlg_update_start(union control *ctrl, void *dlg)
516 void dlg_update_done(union control *ctrl, void *dlg)
522 void dlg_set_focus(union control *ctrl, void *dlg)
525 if (mac_gestalts.apprvers >= 0x100) {
526 /* Use SetKeyboardFocus() */
528 /* Do our own mucking around */
532 union control *dlg_last_focused(union control *ctrl, void *dlg)
538 void dlg_beep(void *dlg)
544 void dlg_error_msg(void *dlg, char *msg)
548 c2pstrcpy(pmsg, msg);
549 ParamText(pmsg, NULL, NULL, NULL);
550 StopAlert(128, NULL);
553 void dlg_end(void *dlg, int value)
558 void dlg_refresh(union control *ctrl, void *dlg)
563 void *dlg_get_privdata(union control *ctrl, void *dlg)
569 void dlg_set_privdata(union control *ctrl, void *dlg, void *ptr)
572 fatalbox("dlg_set_privdata");
575 void *dlg_alloc_privdata(union control *ctrl, void *dlg, size_t size)
578 fatalbox("dlg_alloc_privdata");
583 * Radio Button control
586 void dlg_radiobutton_set(union control *ctrl, void *dlg, int whichbutton)
588 union macctrl *mc = dlg;
591 for (i = 0; i < ctrl->radio.nbuttons; i++) {
592 if (i == whichbutton)
593 SetControlValue(mc->radio.tbctrls[i],
594 kControlRadioButtonCheckedValue);
596 SetControlValue(mc->radio.tbctrls[i],
597 kControlRadioButtonUncheckedValue);
602 int dlg_radiobutton_get(union control *ctrl, void *dlg)
604 union macctrl *mc = dlg;
607 for (i = 0; i < ctrl->radio.nbuttons; i++) {
608 if (GetControlValue(mc->radio.tbctrls[i]) ==
609 kControlRadioButtonCheckedValue)
620 void dlg_checkbox_set(union control *ctrl, void *dlg, int checked)
622 union macctrl *mc = dlg;
624 SetControlValue(mc->checkbox.tbctrl,
625 checked ? kControlCheckBoxCheckedValue :
626 kControlCheckBoxUncheckedValue);
629 int dlg_checkbox_get(union control *ctrl, void *dlg)
631 union macctrl *mc = dlg;
633 return GetControlValue(mc->checkbox.tbctrl);
641 void dlg_editbox_set(union control *ctrl, void *dlg, char const *text)
646 void dlg_editbox_get(union control *ctrl, void *dlg, char *buffer, int length)
656 void dlg_listbox_clear(union control *ctrl, void *dlg)
661 void dlg_listbox_del(union control *ctrl, void *dlg, int index)
666 void dlg_listbox_add(union control *ctrl, void *dlg, char const *text)
671 void dlg_listbox_addwithindex(union control *ctrl, void *dlg,
672 char const *text, int id)
677 int dlg_listbox_getid(union control *ctrl, void *dlg, int index)
683 int dlg_listbox_index(union control *ctrl, void *dlg)
689 int dlg_listbox_issel(union control *ctrl, void *dlg, int index)
695 void dlg_listbox_select(union control *ctrl, void *dlg, int index)
705 void dlg_text_set(union control *ctrl, void *dlg, char const *text)
707 union macctrl *mc = dlg;
709 if (mac_gestalts.apprvers >= 0x100)
710 SetControlData(mc->text.tbctrl, kControlEntireControl,
711 kControlStaticTextTextTag,
712 strlen(ctrl->text.label), ctrl->text.label);
717 * File Selector control
720 void dlg_filesel_set(union control *ctrl, void *dlg, Filename fn)
725 void dlg_filesel_get(union control *ctrl, void *dlg, Filename *fn)
732 * Font Selector control
735 void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec fn)
740 void dlg_fontsel_get(union control *ctrl, void *dlg, FontSpec *fn)
747 * Printer enumeration
750 printer_enum *printer_start_enum(int *nprinters)
757 char *printer_get_name(printer_enum *pe, int thing)
763 void printer_finish_enum(printer_enum *pe)
770 * Colour selection stuff
773 void dlg_coloursel_start(union control *ctrl, void *dlg,
779 int dlg_coloursel_results(union control *ctrl, void *dlg,
780 int *r, int *g, int *b)
788 * c-file-style: "simon"