]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - mac/macctrls.c
Handle Return and Escape keys in dialogue box, triggering the default and
[PuTTY.git] / mac / macctrls.c
1 /* $Id: macctrls.c,v 1.28 2003/04/05 17:19:38 ben Exp $ */
2 /*
3  * Copyright (c) 2003 Ben Harris
4  * All rights reserved.
5  *
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
13  * conditions:
14  * 
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  * 
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
25  * SOFTWARE.
26  */
27
28 #include <MacTypes.h>
29 #include <Appearance.h>
30 #include <Controls.h>
31 #include <ControlDefinitions.h>
32 #include <Events.h>
33 #include <Menus.h>
34 #include <Resources.h>
35 #include <Script.h>
36 #include <Sound.h>
37 #include <TextEdit.h>
38 #include <TextUtils.h>
39 #include <ToolUtils.h>
40 #include <Windows.h>
41
42 #include <assert.h>
43 #include <string.h>
44
45 #include "putty.h"
46 #include "mac.h"
47 #include "macresid.h"
48 #include "dialog.h"
49 #include "tree234.h"
50
51 /* Range of menu IDs for popup menus */
52 #define MENU_MIN        1024
53 #define MENU_MAX        2048
54
55
56 union macctrl {
57     struct macctrl_generic {
58         enum {
59             MACCTRL_TEXT,
60             MACCTRL_EDITBOX,
61             MACCTRL_RADIO,
62             MACCTRL_CHECKBOX,
63             MACCTRL_BUTTON,
64             MACCTRL_POPUP
65         } type;
66         /* Template from which this was generated */
67         union control *ctrl;
68         /* Next control in this panel */
69         union macctrl *next;
70         void *privdata;
71         int freeprivdata;
72     } generic;
73     struct {
74         struct macctrl_generic generic;
75         ControlRef tbctrl;
76     } text;
77     struct {
78         struct macctrl_generic generic;
79         ControlRef tbctrl;
80         ControlRef tblabel;
81     } editbox;
82     struct {
83         struct macctrl_generic generic;
84         ControlRef *tbctrls;
85         ControlRef tblabel;
86     } radio;
87     struct {
88         struct macctrl_generic generic;
89         ControlRef tbctrl;
90     } checkbox;
91     struct {
92         struct macctrl_generic generic;
93         ControlRef tbctrl;
94     } button;
95     struct {
96         struct macctrl_generic generic;
97         ControlRef tbctrl;
98         MenuRef menu;
99         int menuid;
100         unsigned int nids;
101         int *ids;
102     } popup;
103 };
104
105 struct mac_layoutstate {
106     Point pos;
107     unsigned int width;
108     unsigned int panelnum;
109 };
110
111 #define ctrlevent(mcs, mc, event) do {                                  \
112     if ((mc)->generic.ctrl->generic.handler != NULL)                    \
113         (*(mc)->generic.ctrl->generic.handler)((mc)->generic.ctrl, (mcs),\
114                                                (mcs)->data, (event));   \
115 } while (0)
116
117 #define findbyctrl(mcs, ctrl)                                           \
118     find234((mcs)->byctrl, (ctrl), macctrl_cmp_byctrl_find)
119
120 static void macctrl_layoutset(struct mac_layoutstate *, struct controlset *, 
121                               WindowPtr, struct macctrls *);
122 static void macctrl_switchtopanel(struct macctrls *, unsigned int);
123 static void macctrl_setfocus(struct macctrls *, union macctrl *);
124 static void macctrl_text(struct macctrls *, WindowPtr,
125                          struct mac_layoutstate *, union control *);
126 static void macctrl_editbox(struct macctrls *, WindowPtr,
127                             struct mac_layoutstate *, union control *);
128 static void macctrl_radio(struct macctrls *, WindowPtr,
129                           struct mac_layoutstate *, union control *);
130 static void macctrl_checkbox(struct macctrls *, WindowPtr,
131                              struct mac_layoutstate *, union control *);
132 static void macctrl_button(struct macctrls *, WindowPtr,
133                            struct mac_layoutstate *, union control *);
134 static void macctrl_popup(struct macctrls *, WindowPtr,
135                           struct mac_layoutstate *, union control *);
136 #if !TARGET_API_MAC_CARBON
137 static pascal SInt32 macctrl_sys7_editbox_cdef(SInt16, ControlRef,
138                                                ControlDefProcMessage, SInt32);
139 static pascal SInt32 macctrl_sys7_default_cdef(SInt16, ControlRef,
140                                                ControlDefProcMessage, SInt32);
141 #endif
142
143 #if !TARGET_API_MAC_CARBON
144 /*
145  * This trick enables us to keep all the CDEF code in the main
146  * application, which makes life easier.  For details, see
147  * <http://developer.apple.com/technotes/tn/tn2003.html#custom_code_base>.
148  */
149
150 #pragma options align=mac68k
151 typedef struct {
152     short               jmpabs; /* 4EF9 */
153     ControlDefUPP       theUPP;
154 } **PatchCDEF;
155 #pragma options align=reset
156 #endif
157
158 static void macctrl_init()
159 {
160 #if !TARGET_API_MAC_CARBON
161     static int inited = 0;
162     PatchCDEF cdef;
163
164     if (inited) return;
165     cdef = (PatchCDEF)GetResource(kControlDefProcResourceType, CDEF_EditBox);
166     (*cdef)->theUPP = NewControlDefProc(macctrl_sys7_editbox_cdef);
167     cdef = (PatchCDEF)GetResource(kControlDefProcResourceType, CDEF_Default);
168     (*cdef)->theUPP = NewControlDefProc(macctrl_sys7_default_cdef);
169     inited = 1;
170 #endif
171 }
172
173
174 static int macctrl_cmp_byctrl(void *av, void *bv)
175 {
176     union macctrl *a = (union macctrl *)av;
177     union macctrl *b = (union macctrl *)bv;
178
179     if (a->generic.ctrl < b->generic.ctrl)
180         return -1;
181     else if (a->generic.ctrl > b->generic.ctrl)
182         return +1;
183     else
184         return 0;
185 }
186
187 static int macctrl_cmp_byctrl_find(void *av, void *bv)
188 {
189     union control *a = (union control *)av;
190     union macctrl *b = (union macctrl *)bv;
191
192     if (a < b->generic.ctrl)
193         return -1;
194     else if (a > b->generic.ctrl)
195         return +1;
196     else
197         return 0;
198 }
199
200 void macctrl_layoutbox(struct controlbox *cb, WindowPtr window,
201                        struct macctrls *mcs)
202 {
203     int i;
204     struct mac_layoutstate curstate;
205     ControlRef root;
206     Rect rect;
207
208     macctrl_init();
209 #if TARGET_API_MAC_CARBON
210     GetPortBounds(GetWindowPort(window), &rect);
211 #else
212     rect = window->portRect;
213 #endif
214     curstate.pos.h = rect.left + 13;
215     curstate.pos.v = rect.bottom - 33;
216     curstate.width = rect.right - rect.left - (13 * 2);
217     if (mac_gestalts.apprvers >= 0x100)
218         CreateRootControl(window, &root);
219     mcs->window = window;
220     mcs->byctrl = newtree234(macctrl_cmp_byctrl);
221     mcs->focus = NULL;
222     mcs->defbutton = NULL;
223     mcs->canbutton = NULL;
224     /* Count the number of panels */
225     mcs->npanels = 1;
226     for (i = 1; i < cb->nctrlsets; i++)
227         if (strcmp(cb->ctrlsets[i]->pathname, cb->ctrlsets[i-1]->pathname))
228             mcs->npanels++;
229     mcs->panels = snewn(mcs->npanels, union macctrl *);
230     memset(mcs->panels, 0, sizeof(*mcs->panels) * mcs->npanels);
231     curstate.panelnum = 0;
232     for (i = 0; i < cb->nctrlsets; i++) {
233         if (i > 0 && strcmp(cb->ctrlsets[i]->pathname,
234                             cb->ctrlsets[i-1]->pathname)) {
235             curstate.pos.v = rect.top + 13;
236             curstate.panelnum++;
237             assert(curstate.panelnum < mcs->npanels);
238         }
239         macctrl_layoutset(&curstate, cb->ctrlsets[i], window, mcs);
240     }
241     macctrl_switchtopanel(mcs, 1);
242     /* 14 = proxies, 20 = SSH bugs */
243 }
244
245 #define MAXCOLS 16
246
247 static void macctrl_layoutset(struct mac_layoutstate *curstate,
248                               struct controlset *s,
249                               WindowPtr window, struct macctrls *mcs)
250 {
251     unsigned int i, j, ncols, colstart;
252     struct mac_layoutstate cols[MAXCOLS];
253
254     fprintf(stderr, "--- begin set ---\n");
255     fprintf(stderr, "pathname = %s\n", s->pathname);
256     if (s->boxname && *s->boxname)
257         fprintf(stderr, "boxname = %s\n", s->boxname);
258     if (s->boxtitle)
259         fprintf(stderr, "boxtitle = %s\n", s->boxtitle);
260
261     cols[0] = *curstate;
262     ncols = 1;
263
264     for (i = 0; i < s->ncontrols; i++) {
265         union control *ctrl = s->ctrls[i];
266         char const *s;
267
268         colstart = COLUMN_START(ctrl->generic.column);
269         switch (ctrl->generic.type) {
270           case CTRL_TEXT: s = "text"; break;
271           case CTRL_EDITBOX: s = "editbox"; break;
272           case CTRL_RADIO: s = "radio"; break;
273           case CTRL_CHECKBOX: s = "checkbox"; break;
274           case CTRL_BUTTON: s = "button"; break;
275           case CTRL_LISTBOX: s = "listbox"; break;
276           case CTRL_COLUMNS: s = "columns"; break;
277           case CTRL_FILESELECT: s = "fileselect"; break;
278           case CTRL_FONTSELECT: s = "fontselect"; break;
279           case CTRL_TABDELAY: s = "tabdelay"; break;
280           default: s = "unknown"; break;
281         }
282         fprintf(stderr, "  control: %s\n", s);
283         switch (ctrl->generic.type) {
284           case CTRL_COLUMNS:
285             if (ctrl->columns.ncols != 1) {
286                 ncols = ctrl->columns.ncols;
287                 fprintf(stderr, "  split to %d\n", ncols);
288                 assert(ncols <= MAXCOLS);
289                 for (j = 0; j < ncols; j++) {
290                     cols[j] = cols[0];
291                     if (j > 0)
292                         cols[j].pos.h = cols[j-1].pos.h + cols[j-1].width + 6;
293                     if (j == ncols - 1)
294                         cols[j].width = curstate->width -
295                             (cols[j].pos.h - curstate->pos.h);
296                     else
297                         cols[j].width = (curstate->width + 6) * 
298                             ctrl->columns.percentages[j] / 100 - 6;
299                 }
300             } else {
301                 fprintf(stderr, "  join\n");
302                 for (j = 0; j < ncols; j++)
303                     if (cols[j].pos.v > cols[0].pos.v)
304                         cols[0].pos.v = cols[j].pos.v;
305                 cols[0].width = curstate->width;
306                 ncols = 1;
307             }
308             break;
309           case CTRL_TEXT:
310             macctrl_text(mcs, window, &cols[colstart], ctrl);
311             break;
312           case CTRL_EDITBOX:
313             macctrl_editbox(mcs, window, &cols[colstart], ctrl);
314             break;
315           case CTRL_RADIO:
316             macctrl_radio(mcs, window, &cols[colstart], ctrl);
317             break;
318           case CTRL_CHECKBOX:
319             macctrl_checkbox(mcs, window, &cols[colstart], ctrl);
320             break;
321           case CTRL_BUTTON:
322             macctrl_button(mcs, window, &cols[colstart], ctrl);
323             break;
324           case CTRL_LISTBOX:
325             if (ctrl->listbox.height == 0)
326                 macctrl_popup(mcs, window, &cols[colstart], ctrl);
327             break;
328         }
329     }
330     for (j = 0; j < ncols; j++)
331         if (cols[j].pos.v > curstate->pos.v)
332             curstate->pos.v = cols[j].pos.v;
333 }
334
335 static void macctrl_switchtopanel(struct macctrls *mcs, unsigned int which)
336 {
337     unsigned int i, j;
338     union macctrl *mc;
339
340 #define hideshow(c) do {                                                \
341     if (i == which) ShowControl(c); else HideControl(c);                \
342 } while (0)
343
344     mcs->curpanel = which;
345     /* Panel 0 is special and always visible. */
346     for (i = 1; i < mcs->npanels; i++)
347         for (mc = mcs->panels[i]; mc != NULL; mc = mc->generic.next) {
348 #if !TARGET_API_MAC_CARBON
349             if (mcs->focus == mc)
350                 macctrl_setfocus(mcs, NULL);
351 #endif
352             switch (mc->generic.type) {
353               case MACCTRL_TEXT:
354                 hideshow(mc->text.tbctrl);
355                 break;
356               case MACCTRL_EDITBOX:
357                 hideshow(mc->editbox.tbctrl);
358                 if (mc->editbox.tblabel != NULL)
359                     hideshow(mc->editbox.tblabel);
360                 break;
361               case MACCTRL_RADIO:
362                 for (j = 0; j < mc->generic.ctrl->radio.nbuttons; j++)
363                     hideshow(mc->radio.tbctrls[j]);
364                 if (mc->radio.tblabel != NULL)
365                     hideshow(mc->radio.tblabel);
366                 break;
367               case MACCTRL_CHECKBOX:
368                 hideshow(mc->checkbox.tbctrl);
369                 break;
370               case MACCTRL_BUTTON:
371                 hideshow(mc->button.tbctrl);
372                 break;
373               case MACCTRL_POPUP:
374                 hideshow(mc->popup.tbctrl);
375                 break;
376             }
377         }
378 }
379
380 #if !TARGET_API_MAC_CARBON
381 /*
382  * System 7 focus manipulation
383  */
384 static void macctrl_defocus(union macctrl *mc)
385 {
386
387     assert(mac_gestalts.apprvers < 0x100);
388     switch (mc->generic.type) {
389       case MACCTRL_EDITBOX:
390         TEDeactivate((TEHandle)(*mc->editbox.tbctrl)->contrlData);
391         break;
392     }
393 }
394
395 static void macctrl_enfocus(union macctrl *mc)
396 {
397
398     assert(mac_gestalts.apprvers < 0x100);
399     switch (mc->generic.type) {
400       case MACCTRL_EDITBOX:
401         TEActivate((TEHandle)(*mc->editbox.tbctrl)->contrlData);
402         break;
403     }
404 }
405
406 static void macctrl_setfocus(struct macctrls *mcs, union macctrl *mc)
407 {
408
409     if (mcs->focus != NULL)
410         macctrl_defocus(mcs->focus);
411     mcs->focus = mc;
412     if (mc != NULL)
413         macctrl_enfocus(mc);
414 }
415 #endif
416
417 static void macctrl_text(struct macctrls *mcs, WindowPtr window,
418                          struct mac_layoutstate *curstate,
419                          union control *ctrl)
420 {
421     union macctrl *mc = snew(union macctrl);
422     Rect bounds;
423     SInt16 height;
424
425     assert(ctrl->text.label != NULL);
426     fprintf(stderr, "    label = %s\n", ctrl->text.label);
427     mc->generic.type = MACCTRL_TEXT;
428     mc->generic.ctrl = ctrl;
429     mc->generic.privdata = NULL;
430     bounds.left = curstate->pos.h;
431     bounds.right = bounds.left + curstate->width;
432     bounds.top = curstate->pos.v;
433     bounds.bottom = bounds.top + 16;
434     if (mac_gestalts.apprvers >= 0x100) {
435         Size olen;
436
437         mc->text.tbctrl = NewControl(window, &bounds, NULL, TRUE, 0, 0, 0,
438                                      kControlStaticTextProc, (long)mc);
439         SetControlData(mc->text.tbctrl, kControlEntireControl,
440                        kControlStaticTextTextTag,
441                        strlen(ctrl->text.label), ctrl->text.label);
442         GetControlData(mc->text.tbctrl, kControlEntireControl,
443                        kControlStaticTextTextHeightTag,
444                        sizeof(height), &height, &olen);
445     }
446 #if !TARGET_API_MAC_CARBON
447     else {
448         TEHandle te;
449
450         mc->text.tbctrl = NewControl(window, &bounds, NULL, TRUE, 0, 0, 0,
451                                      SYS7_TEXT_PROC, (long)mc);
452         te = (TEHandle)(*mc->text.tbctrl)->contrlData;
453         TESetText(ctrl->text.label, strlen(ctrl->text.label), te);
454         height = TEGetHeight(1, (*te)->nLines, te);
455     }
456 #endif
457     fprintf(stderr, "    height = %d\n", height);
458     SizeControl(mc->text.tbctrl, curstate->width, height);
459     curstate->pos.v += height + 6;
460     add234(mcs->byctrl, mc);
461     mc->generic.next = mcs->panels[curstate->panelnum];
462     mcs->panels[curstate->panelnum] = mc;
463 }
464
465 static void macctrl_editbox(struct macctrls *mcs, WindowPtr window,
466                             struct mac_layoutstate *curstate,
467                             union control *ctrl)
468 {
469     union macctrl *mc = snew(union macctrl);
470     Rect lbounds, bounds;
471
472     if (ctrl->editbox.label != NULL)
473         fprintf(stderr, "    label = %s\n", ctrl->editbox.label);
474     fprintf(stderr, "    percentwidth = %d\n", ctrl->editbox.percentwidth);
475     if (ctrl->editbox.password) fprintf(stderr, "    password\n");
476     if (ctrl->editbox.has_list) fprintf(stderr, "    has list\n");
477     mc->generic.type = MACCTRL_EDITBOX;
478     mc->generic.ctrl = ctrl;
479     mc->generic.privdata = NULL;
480     lbounds.left = curstate->pos.h;
481     lbounds.top = curstate->pos.v;
482     if (ctrl->editbox.percentwidth == 100) {
483         if (ctrl->editbox.label != NULL) {
484             lbounds.right = lbounds.left + curstate->width;
485             lbounds.bottom = lbounds.top + 16;
486             curstate->pos.v += 18;
487         }
488         bounds.left = curstate->pos.h;
489         bounds.right = bounds.left + curstate->width;
490     } else {
491         lbounds.right = lbounds.left +
492             curstate->width * (100 - ctrl->editbox.percentwidth) / 100;
493         lbounds.bottom = lbounds.top + 22;
494         bounds.left = lbounds.right;
495         bounds.right = lbounds.left + curstate->width;
496     }
497     bounds.top = curstate->pos.v;
498     bounds.bottom = bounds.top + 22;
499     if (mac_gestalts.apprvers >= 0x100) {
500         if (ctrl->editbox.label == NULL)
501             mc->editbox.tblabel = NULL;
502         else {
503             mc->editbox.tblabel = NewControl(window, &lbounds, NULL, TRUE,
504                                              0, 0, 0, kControlStaticTextProc,
505                                              (long)mc);
506             SetControlData(mc->editbox.tblabel, kControlEntireControl,
507                            kControlStaticTextTextTag,
508                            strlen(ctrl->editbox.label), ctrl->editbox.label);
509         }
510         InsetRect(&bounds, 3, 3);
511         mc->editbox.tbctrl = NewControl(window, &bounds, NULL, TRUE, 0, 0, 0,
512                                         ctrl->editbox.password ?
513                                         kControlEditTextPasswordProc :
514                                         kControlEditTextProc, (long)mc);
515     }
516 #if !TARGET_API_MAC_CARBON
517     else {
518         if (ctrl->editbox.label == NULL)
519             mc->editbox.tblabel = NULL;
520         else {
521             mc->editbox.tblabel = NewControl(window, &lbounds, NULL, TRUE,
522                                              0, 0, 0, SYS7_TEXT_PROC,
523                                              (long)mc);
524             TESetText(ctrl->editbox.label, strlen(ctrl->editbox.label),
525                       (TEHandle)(*mc->editbox.tblabel)->contrlData);
526         }
527         mc->editbox.tbctrl = NewControl(window, &bounds, NULL, TRUE, 0, 0, 0,
528                                         SYS7_EDITBOX_PROC, (long)mc);
529     }
530 #endif
531     curstate->pos.v += 28;
532     add234(mcs->byctrl, mc);
533     mc->generic.next = mcs->panels[curstate->panelnum];
534     mcs->panels[curstate->panelnum] = mc;
535     ctrlevent(mcs, mc, EVENT_REFRESH);
536 }
537
538 #if !TARGET_API_MAC_CARBON
539 static pascal SInt32 macctrl_sys7_editbox_cdef(SInt16 variant,
540                                                ControlRef control,
541                                                ControlDefProcMessage msg,
542                                                SInt32 param)
543 {
544     RgnHandle rgn;
545     Rect rect;
546     TEHandle te;
547     long ssfs;
548     Point mouse;
549
550     switch (msg) {
551       case initCntl:
552         rect = (*control)->contrlRect;
553         if (variant == SYS7_EDITBOX_VARIANT)
554             InsetRect(&rect, 3, 3); /* 2 if it's 20 pixels high */
555         te = TENew(&rect, &rect);
556         ssfs = GetScriptVariable(smSystemScript, smScriptSysFondSize);
557         (*te)->txSize = LoWord(ssfs);
558         (*te)->txFont = HiWord(ssfs);
559         (*control)->contrlData = (Handle)te;
560         return noErr;
561       case dispCntl:
562         TEDispose((TEHandle)(*control)->contrlData);
563         return 0;
564       case drawCntl:
565         if ((*control)->contrlVis) {
566             rect = (*control)->contrlRect;
567             if (variant == SYS7_EDITBOX_VARIANT) {
568                 PenNormal();
569                 FrameRect(&rect);
570                 InsetRect(&rect, 3, 3);
571             }
572             (*(TEHandle)(*control)->contrlData)->viewRect = rect;
573             TEUpdate(&rect, (TEHandle)(*control)->contrlData);
574         }
575         return 0;
576       case testCntl:
577         if (variant == SYS7_TEXT_VARIANT)
578             return kControlNoPart;
579         mouse.h = LoWord(param);
580         mouse.v = HiWord(param);
581         rect = (*control)->contrlRect;
582         InsetRect(&rect, 3, 3);
583         return PtInRect(mouse, &rect) ? kControlEditTextPart : kControlNoPart;
584       case calcCRgns:
585         if (param & (1 << 31)) {
586             param &= ~(1 << 31);
587             goto calcthumbrgn;
588         }
589         /* FALLTHROUGH */
590       case calcCntlRgn:
591         rgn = (RgnHandle)param;
592         RectRgn(rgn, &(*control)->contrlRect);
593         return 0;
594       case calcThumbRgn:
595       calcthumbrgn:
596         rgn = (RgnHandle)param;
597         SetEmptyRgn(rgn);
598         return 0;
599     }
600
601     return 0;
602 }
603 #endif
604
605 static void macctrl_radio(struct macctrls *mcs, WindowPtr window,
606                           struct mac_layoutstate *curstate,
607                           union control *ctrl)
608 {
609     union macctrl *mc = snew(union macctrl);
610     Rect bounds;
611     Str255 title;
612     unsigned int i, colwidth;
613
614     if (ctrl->radio.label != NULL)
615         fprintf(stderr, "    label = %s\n", ctrl->radio.label);
616     mc->generic.type = MACCTRL_RADIO;
617     mc->generic.ctrl = ctrl;
618     mc->generic.privdata = NULL;
619     mc->radio.tbctrls = snewn(ctrl->radio.nbuttons, ControlRef);
620     colwidth = (curstate->width + 13) / ctrl->radio.ncolumns;
621     bounds.top = curstate->pos.v;
622     bounds.bottom = bounds.top + 16;
623     bounds.left = curstate->pos.h;
624     bounds.right = bounds.left + curstate->width;
625     if (ctrl->radio.label == NULL)
626         mc->radio.tblabel = NULL;
627     else {
628         if (mac_gestalts.apprvers >= 0x100) {
629             mc->radio.tblabel = NewControl(window, &bounds, NULL, TRUE,
630                                            0, 0, 0, kControlStaticTextProc,
631                                            (long)mc);
632             SetControlData(mc->radio.tblabel, kControlEntireControl,
633                            kControlStaticTextTextTag,
634                            strlen(ctrl->radio.label), ctrl->radio.label);
635         }
636 #if !TARGET_API_MAC_CARBON
637         else {
638             mc->radio.tblabel = NewControl(window, &bounds, NULL, TRUE,
639                                            0, 0, 0, SYS7_TEXT_PROC, (long)mc);
640             TESetText(ctrl->radio.label, strlen(ctrl->radio.label),
641                       (TEHandle)(*mc->radio.tblabel)->contrlData);
642         }
643 #endif
644         curstate->pos.v += 18;
645     }
646     for (i = 0; i < ctrl->radio.nbuttons; i++) {
647         fprintf(stderr, "    button = %s\n", ctrl->radio.buttons[i]);
648         bounds.top = curstate->pos.v - 2;
649         bounds.bottom = bounds.top + 18;
650         bounds.left = curstate->pos.h + colwidth * (i % ctrl->radio.ncolumns);
651         if (i == ctrl->radio.nbuttons - 1 ||
652             i % ctrl->radio.ncolumns == ctrl->radio.ncolumns - 1) {
653             bounds.right = curstate->pos.h + curstate->width;
654             curstate->pos.v += 18;
655         } else
656             bounds.right = bounds.left + colwidth - 13;
657         c2pstrcpy(title, ctrl->radio.buttons[i]);
658         mc->radio.tbctrls[i] = NewControl(window, &bounds, title, TRUE,
659                                           0, 0, 1, radioButProc, (long)mc);
660     }
661     curstate->pos.v += 4;
662     add234(mcs->byctrl, mc);
663     mc->generic.next = mcs->panels[curstate->panelnum];
664     mcs->panels[curstate->panelnum] = mc;
665     ctrlevent(mcs, mc, EVENT_REFRESH);
666 }
667
668 static void macctrl_checkbox(struct macctrls *mcs, WindowPtr window,
669                              struct mac_layoutstate *curstate,
670                              union control *ctrl)
671 {
672     union macctrl *mc = snew(union macctrl);
673     Rect bounds;
674     Str255 title;
675
676     assert(ctrl->checkbox.label != NULL);
677     fprintf(stderr, "    label = %s\n", ctrl->checkbox.label);
678     mc->generic.type = MACCTRL_CHECKBOX;
679     mc->generic.ctrl = ctrl;
680     mc->generic.privdata = NULL;
681     bounds.left = curstate->pos.h;
682     bounds.right = bounds.left + curstate->width;
683     bounds.top = curstate->pos.v;
684     bounds.bottom = bounds.top + 16;
685     c2pstrcpy(title, ctrl->checkbox.label);
686     mc->checkbox.tbctrl = NewControl(window, &bounds, title, TRUE, 0, 0, 1,
687                                      checkBoxProc, (long)mc);
688     add234(mcs->byctrl, mc);
689     curstate->pos.v += 22;
690     mc->generic.next = mcs->panels[curstate->panelnum];
691     mcs->panels[curstate->panelnum] = mc;
692     ctrlevent(mcs, mc, EVENT_REFRESH);
693 }
694
695 static void macctrl_button(struct macctrls *mcs, WindowPtr window,
696                            struct mac_layoutstate *curstate,
697                            union control *ctrl)
698 {
699     union macctrl *mc = snew(union macctrl);
700     Rect bounds;
701     Str255 title;
702
703     assert(ctrl->button.label != NULL);
704     fprintf(stderr, "    label = %s\n", ctrl->button.label);
705     if (ctrl->button.isdefault)
706         fprintf(stderr, "    is default\n");
707     mc->generic.type = MACCTRL_BUTTON;
708     mc->generic.ctrl = ctrl;
709     mc->generic.privdata = NULL;
710     bounds.left = curstate->pos.h;
711     bounds.right = bounds.left + curstate->width;
712     bounds.top = curstate->pos.v;
713     bounds.bottom = bounds.top + 20;
714     c2pstrcpy(title, ctrl->button.label);
715     mc->button.tbctrl = NewControl(window, &bounds, title, TRUE, 0, 0, 1,
716                                    pushButProc, (long)mc);
717     if (mac_gestalts.apprvers >= 0x100) {
718         Boolean isdefault = ctrl->button.isdefault;
719
720         SetControlData(mc->button.tbctrl, kControlEntireControl,
721                        kControlPushButtonDefaultTag,
722                        sizeof(isdefault), &isdefault);
723     } else if (ctrl->button.isdefault) {
724         InsetRect(&bounds, -4, -4);
725         NewControl(window, &bounds, title, TRUE, 0, 0, 1,
726                    SYS7_DEFAULT_PROC, (long)mc);
727     }
728     if (mac_gestalts.apprvers >= 0x110) {
729         Boolean iscancel = ctrl->button.iscancel;
730
731         SetControlData(mc->button.tbctrl, kControlEntireControl,
732                        kControlPushButtonCancelTag,
733                        sizeof(iscancel), &iscancel);
734     }
735     if (ctrl->button.isdefault)
736         mcs->defbutton = mc;
737     if (ctrl->button.iscancel)
738         mcs->canbutton = mc;
739     add234(mcs->byctrl, mc);
740     mc->generic.next = mcs->panels[curstate->panelnum];
741     mcs->panels[curstate->panelnum] = mc;
742     curstate->pos.v += 26;
743 }
744
745 #if !TARGET_API_MAC_CARBON
746 static pascal SInt32 macctrl_sys7_default_cdef(SInt16 variant,
747                                                ControlRef control,
748                                                ControlDefProcMessage msg,
749                                                SInt32 param)
750 {
751     RgnHandle rgn;
752     Rect rect;
753     int oval;
754
755     switch (msg) {
756       case drawCntl:
757         if ((*control)->contrlVis) {
758             rect = (*control)->contrlRect;
759             PenNormal();
760             PenSize(3, 3);
761             oval = (rect.bottom - rect.top) / 2 + 2;
762             FrameRoundRect(&rect, oval, oval);
763         }
764         return 0;
765       case calcCRgns:
766         if (param & (1 << 31)) {
767             param &= ~(1 << 31);
768             goto calcthumbrgn;
769         }
770         /* FALLTHROUGH */
771       case calcCntlRgn:
772         rgn = (RgnHandle)param;
773         RectRgn(rgn, &(*control)->contrlRect);
774         return 0;
775       case calcThumbRgn:
776       calcthumbrgn:
777         rgn = (RgnHandle)param;
778         SetEmptyRgn(rgn);
779         return 0;
780     }
781
782     return 0;
783 }
784 #endif
785
786 static void macctrl_popup(struct macctrls *mcs, WindowPtr window,
787                           struct mac_layoutstate *curstate,
788                           union control *ctrl)
789 {
790     union macctrl *mc = snew(union macctrl);
791     Rect bounds;
792     Str255 title;
793     unsigned int labelwidth;
794     static int nextmenuid = MENU_MIN;
795     int menuid;
796     MenuRef menu;
797
798     /* 
799      * <http://developer.apple.com/qa/tb/tb42.html> explains how to
800      * create a popup menu with dynamic content.
801      */
802     assert(ctrl->listbox.height == 0);
803     assert(!ctrl->listbox.draglist);
804     assert(!ctrl->listbox.multisel);
805
806     if (ctrl->listbox.label != NULL)
807         fprintf(stderr, "    label = %s\n", ctrl->listbox.label);
808     fprintf(stderr, "    percentwidth = %d\n", ctrl->listbox.percentwidth);
809
810     mc->generic.type = MACCTRL_POPUP;
811     mc->generic.ctrl = ctrl;
812     mc->generic.privdata = NULL;
813     c2pstrcpy(title, ctrl->button.label == NULL ? "" : ctrl->button.label);
814
815     /* Find a spare menu ID and create the menu */
816     while (GetMenuHandle(nextmenuid) != NULL)
817         if (++nextmenuid >= MENU_MAX) nextmenuid = MENU_MIN;
818     menuid = nextmenuid++;
819     menu = NewMenu(menuid, "\pdummy");
820     if (menu == NULL) return;
821     mc->popup.menu = menu;
822     mc->popup.menuid = menuid;
823     InsertMenu(menu, kInsertHierarchicalMenu);
824
825     /* The menu starts off empty */
826     mc->popup.nids = 0;
827     mc->popup.ids = NULL;
828
829     bounds.left = curstate->pos.h;
830     bounds.right = bounds.left + curstate->width;
831     bounds.top = curstate->pos.v;
832     bounds.bottom = bounds.top + 20;
833     /* XXX handle percentwidth == 100 */
834     labelwidth = curstate->width * (100 - ctrl->listbox.percentwidth) / 100;
835     mc->popup.tbctrl = NewControl(window, &bounds, title, TRUE,
836                                   popupTitleLeftJust, menuid, labelwidth,
837                                   popupMenuProc + popupFixedWidth, (long)mc);
838     add234(mcs->byctrl, mc);
839     curstate->pos.v += 26;
840     mc->generic.next = mcs->panels[curstate->panelnum];
841     mcs->panels[curstate->panelnum] = mc;
842     ctrlevent(mcs, mc, EVENT_REFRESH);
843 }
844
845
846 void macctrl_activate(WindowPtr window, EventRecord *event)
847 {
848     struct macctrls *mcs = mac_winctrls(window);
849     Boolean active = (event->modifiers & activeFlag) != 0;
850     GrafPtr saveport;
851     int i, j;
852     ControlPartCode state;
853     union macctrl *mc;
854
855     GetPort(&saveport);
856     SetPort((GrafPtr)GetWindowPort(window));
857     if (mac_gestalts.apprvers >= 0x100)
858         SetThemeWindowBackground(window, active ?
859                                  kThemeBrushModelessDialogBackgroundActive :
860                                  kThemeBrushModelessDialogBackgroundInactive,
861                                  TRUE);
862     state = active ? kControlNoPart : kControlInactivePart;
863     for (i = 0; i <= mcs->curpanel; i += mcs->curpanel)
864         for (mc = mcs->panels[i]; mc != NULL; mc = mc->generic.next) {
865             switch (mc->generic.type) {
866               case MACCTRL_TEXT:
867                 HiliteControl(mc->text.tbctrl, state);
868                 break;
869               case MACCTRL_EDITBOX:
870                 HiliteControl(mc->editbox.tbctrl, state);
871                 if (mc->editbox.tblabel != NULL)
872                     HiliteControl(mc->editbox.tblabel, state);
873                 break;
874               case MACCTRL_RADIO:
875                 for (j = 0; j < mc->generic.ctrl->radio.nbuttons; j++)
876                     HiliteControl(mc->radio.tbctrls[j], state);
877                 if (mc->radio.tblabel != NULL)
878                     HiliteControl(mc->radio.tblabel, state);
879                 break;
880               case MACCTRL_CHECKBOX:
881                 HiliteControl(mc->checkbox.tbctrl, state);
882                 break;
883               case MACCTRL_BUTTON:
884                 HiliteControl(mc->button.tbctrl, state);
885                 break;
886               case MACCTRL_POPUP:
887                 HiliteControl(mc->popup.tbctrl, state);
888                 break;
889             }
890 #if !TARGET_API_MAC_CARBON
891             if (mcs->focus == mc) {
892                 if (active)
893                     macctrl_enfocus(mc);
894                 else
895                     macctrl_defocus(mc);
896             }
897 #endif
898         }
899     SetPort(saveport);
900 }
901
902 void macctrl_click(WindowPtr window, EventRecord *event)
903 {
904     Point mouse;
905     ControlHandle control;
906     int part, trackresult;
907     GrafPtr saveport;
908     union macctrl *mc;
909     struct macctrls *mcs = mac_winctrls(window);
910     int i;
911     UInt32 features;
912
913     GetPort(&saveport);
914     SetPort((GrafPtr)GetWindowPort(window));
915     mouse = event->where;
916     GlobalToLocal(&mouse);
917     part = FindControl(mouse, window, &control);
918     if (control != NULL) {
919         mc = (union macctrl *)GetControlReference(control);
920         if (mac_gestalts.apprvers >= 0x100) {
921             if (GetControlFeatures(control, &features) == noErr &&
922                 (features & kControlSupportsFocus) &&
923                 (features & kControlGetsFocusOnClick))
924                 SetKeyboardFocus(window, control, part);
925             trackresult = HandleControlClick(control, mouse, event->modifiers,
926                                              (ControlActionUPP)-1);
927         } else {
928 #if !TARGET_API_MAC_CARBON
929             if (mc->generic.type == MACCTRL_EDITBOX &&
930                 control == mc->editbox.tbctrl) {
931                 TEHandle te = (TEHandle)(*control)->contrlData;
932
933                 macctrl_setfocus(mcs, mc);
934                 TEClick(mouse, !!(event->modifiers & shiftKey), te);
935                 goto done;
936             }
937 #endif
938             trackresult = TrackControl(control, mouse, (ControlActionUPP)-1);
939         }
940         switch (mc->generic.type) {
941           case MACCTRL_RADIO:
942             if (trackresult != 0) {
943                 for (i = 0; i < mc->generic.ctrl->radio.nbuttons; i++)
944                     if (mc->radio.tbctrls[i] == control)
945                         SetControlValue(mc->radio.tbctrls[i],
946                                         kControlRadioButtonCheckedValue);
947                     else
948                         SetControlValue(mc->radio.tbctrls[i],
949                                         kControlRadioButtonUncheckedValue);
950                 ctrlevent(mcs, mc, EVENT_VALCHANGE);
951             }
952             break;
953           case MACCTRL_CHECKBOX:
954             if (trackresult != 0) {
955                 SetControlValue(control, !GetControlValue(control));
956                 ctrlevent(mcs, mc, EVENT_VALCHANGE);
957             }
958             break;
959           case MACCTRL_BUTTON:
960             if (trackresult != 0)
961                 ctrlevent(mcs, mc, EVENT_ACTION);
962             break;
963           case MACCTRL_POPUP:
964             ctrlevent(mcs, mc, EVENT_SELCHANGE);
965             break;
966         }
967     }
968   done:
969     SetPort(saveport);
970 }
971
972 void macctrl_key(WindowPtr window, EventRecord *event)
973 {
974     ControlRef control;
975     struct macctrls *mcs = mac_winctrls(window);
976     union macctrl *mc;
977     unsigned long dummy;
978
979     switch (event->message & charCodeMask) {
980       case kEnterCharCode:
981       case kReturnCharCode:
982         if (mcs->defbutton != NULL) {
983             assert(mcs->defbutton->generic.type == MACCTRL_BUTTON);
984             HiliteControl(mcs->defbutton->button.tbctrl, kControlButtonPart);
985             /*
986              * I'd like to delay unhilighting the button until after
987              * the event has been processed, but by them the entire
988              * dialgue box might have been destroyed.
989              */
990             Delay(6, &dummy);
991             HiliteControl(mcs->defbutton->button.tbctrl, kControlNoPart);
992             ctrlevent(mcs, mcs->defbutton, EVENT_ACTION);
993         }
994         return;
995       case kEscapeCharCode:
996         if (mcs->canbutton != NULL) {
997             assert(mcs->canbutton->generic.type == MACCTRL_BUTTON);
998             HiliteControl(mcs->canbutton->button.tbctrl, kControlButtonPart);
999             Delay(6, &dummy);
1000             HiliteControl(mcs->defbutton->button.tbctrl, kControlNoPart);
1001             ctrlevent(mcs, mcs->canbutton, EVENT_ACTION);
1002         }
1003         return;
1004     }
1005     if (mac_gestalts.apprvers >= 0x100) {
1006         if (GetKeyboardFocus(window, &control) == noErr && control != NULL) {
1007             HandleControlKey(control, (event->message & keyCodeMask) >> 8,
1008                              event->message & charCodeMask, event->modifiers);
1009             mc = (union macctrl *)GetControlReference(control);
1010             ctrlevent(mcs, mc, EVENT_VALCHANGE);
1011         }
1012     }
1013 #if !TARGET_API_MAC_CARBON
1014     else {
1015         TEHandle te;
1016
1017         if (mcs->focus != NULL) {
1018             mc = mcs->focus;
1019             switch (mc->generic.type) {
1020               case MACCTRL_EDITBOX:
1021                 te = (TEHandle)(*mc->editbox.tbctrl)->contrlData;
1022                 TEKey(event->message & charCodeMask, te);
1023                 ctrlevent(mcs, mc, EVENT_VALCHANGE);
1024                 break;
1025             }
1026         }
1027     }
1028 #endif
1029 }
1030
1031 void macctrl_update(WindowPtr window)
1032 {
1033 #if TARGET_API_MAC_CARBON
1034     RgnHandle visrgn;
1035 #endif
1036     Rect rect;
1037     GrafPtr saveport;
1038
1039     BeginUpdate(window);
1040     GetPort(&saveport);
1041     SetPort((GrafPtr)GetWindowPort(window));
1042     if (mac_gestalts.apprvers >= 0x101) {
1043 #if TARGET_API_MAC_CARBON
1044         GetPortBounds(GetWindowPort(window), &rect);
1045 #else
1046         rect = window->portRect;
1047 #endif
1048         InsetRect(&rect, -1, -1);
1049         DrawThemeModelessDialogFrame(&rect, mac_frontwindow() == window ?
1050                                      kThemeStateActive : kThemeStateInactive);
1051     }
1052 #if TARGET_API_MAC_CARBON
1053     visrgn = NewRgn();
1054     GetPortVisibleRegion(GetWindowPort(window), visrgn);
1055     UpdateControls(window, visrgn);
1056     DisposeRgn(visrgn);
1057 #else
1058     UpdateControls(window, window->visRgn);
1059 #endif
1060     SetPort(saveport);
1061     EndUpdate(window);
1062 }
1063
1064 #if TARGET_API_MAC_CARBON
1065 #define EnableItem EnableMenuItem
1066 #define DisableItem DisableMenuItem
1067 #endif
1068 void macctrl_adjustmenus(WindowPtr window)
1069 {
1070     MenuHandle menu;
1071
1072     menu = GetMenuHandle(mFile);
1073     DisableItem(menu, iSave); /* XXX enable if modified */
1074     EnableItem(menu, iSaveAs);
1075     EnableItem(menu, iDuplicate);
1076
1077     menu = GetMenuHandle(mEdit);
1078     DisableItem(menu, 0);
1079 }
1080
1081 void macctrl_close(WindowPtr window)
1082 {
1083     struct macctrls *mcs = mac_winctrls(window);
1084     union macctrl *mc;
1085
1086     /*
1087      * Mostly, we don't bother disposing of the Toolbox controls,
1088      * since that will happen automatically when the window is
1089      * disposed of.  Popup menus are an exception, because we have to
1090      * dispose of the menu ourselves, and doing that while the control
1091      * still holds a reference to it seems rude.
1092      */
1093     while ((mc = index234(mcs->byctrl, 0)) != NULL) {
1094         if (mc->generic.privdata != NULL && mc->generic.freeprivdata)
1095             sfree(mc->generic.privdata);
1096         switch (mc->generic.type) {
1097           case MACCTRL_POPUP:
1098             DisposeControl(mc->popup.tbctrl);
1099             DeleteMenu(mc->popup.menuid);
1100             DisposeMenu(mc->popup.menu);
1101             break;
1102         }
1103         del234(mcs->byctrl, mc);
1104         sfree(mc);
1105     }
1106
1107     freetree234(mcs->byctrl);
1108     mcs->byctrl = NULL;
1109     sfree(mcs->panels);
1110     mcs->panels = NULL;
1111 }
1112
1113 void dlg_update_start(union control *ctrl, void *dlg)
1114 {
1115
1116     /* No-op for now */
1117 }
1118
1119 void dlg_update_done(union control *ctrl, void *dlg)
1120 {
1121
1122     /* No-op for now */
1123 }
1124
1125 void dlg_set_focus(union control *ctrl, void *dlg)
1126 {
1127
1128     if (mac_gestalts.apprvers >= 0x100) {
1129         /* Use SetKeyboardFocus() */
1130     } else {
1131         /* Do our own mucking around */
1132     }
1133 }
1134
1135 union control *dlg_last_focused(union control *ctrl, void *dlg)
1136 {
1137
1138     return NULL;
1139 }
1140
1141 void dlg_beep(void *dlg)
1142 {
1143
1144     SysBeep(30);
1145 }
1146
1147 void dlg_error_msg(void *dlg, char *msg)
1148 {
1149     Str255 pmsg;
1150
1151     c2pstrcpy(pmsg, msg);
1152     ParamText(pmsg, NULL, NULL, NULL);
1153     StopAlert(128, NULL);
1154 }
1155
1156 void dlg_end(void *dlg, int value)
1157 {
1158     struct macctrls *mcs = dlg;
1159
1160     if (mcs->end != NULL)
1161         (*mcs->end)(mcs->window, value);
1162 };
1163
1164 void dlg_refresh(union control *ctrl, void *dlg)
1165 {
1166     struct macctrls *mcs = dlg;
1167     union macctrl *mc;
1168
1169     if (ctrl == NULL)
1170         return; /* FIXME */
1171     mc = findbyctrl(mcs, ctrl);
1172     assert(mc != NULL);
1173     ctrlevent(mcs, mc, EVENT_REFRESH);
1174 };
1175
1176 void *dlg_get_privdata(union control *ctrl, void *dlg)
1177 {
1178     struct macctrls *mcs = dlg;
1179     union macctrl *mc = findbyctrl(mcs, ctrl);
1180
1181     assert(mc != NULL);
1182     return mc->generic.privdata;
1183 }
1184
1185 void dlg_set_privdata(union control *ctrl, void *dlg, void *ptr)
1186 {
1187     struct macctrls *mcs = dlg;
1188     union macctrl *mc = findbyctrl(mcs, ctrl);
1189
1190     assert(mc != NULL);
1191     mc->generic.privdata = ptr;
1192     mc->generic.freeprivdata = FALSE;
1193 }
1194
1195 void *dlg_alloc_privdata(union control *ctrl, void *dlg, size_t size)
1196 {
1197     struct macctrls *mcs = dlg;
1198     union macctrl *mc = findbyctrl(mcs, ctrl);
1199
1200     assert(mc != NULL);
1201     mc->generic.privdata = smalloc(size);
1202     mc->generic.freeprivdata = TRUE;
1203     return mc->generic.privdata;
1204 }
1205
1206
1207 /*
1208  * Radio Button control
1209  */
1210
1211 void dlg_radiobutton_set(union control *ctrl, void *dlg, int whichbutton)
1212 {
1213     struct macctrls *mcs = dlg;
1214     union macctrl *mc = findbyctrl(mcs, ctrl);
1215     int i;
1216
1217     assert(mc != NULL);
1218     for (i = 0; i < ctrl->radio.nbuttons; i++) {
1219         if (i == whichbutton)
1220             SetControlValue(mc->radio.tbctrls[i],
1221                             kControlRadioButtonCheckedValue);
1222         else
1223             SetControlValue(mc->radio.tbctrls[i],
1224                             kControlRadioButtonUncheckedValue);
1225     }
1226
1227 };
1228
1229 int dlg_radiobutton_get(union control *ctrl, void *dlg)
1230 {
1231     struct macctrls *mcs = dlg;
1232     union macctrl *mc = findbyctrl(mcs, ctrl);
1233     int i;
1234
1235     assert(mc != NULL);
1236     for (i = 0; i < ctrl->radio.nbuttons; i++) {
1237         if (GetControlValue(mc->radio.tbctrls[i])  ==
1238             kControlRadioButtonCheckedValue)
1239             return i;
1240     }
1241     return -1;
1242 };
1243
1244
1245 /*
1246  * Check Box control
1247  */
1248
1249 void dlg_checkbox_set(union control *ctrl, void *dlg, int checked)
1250 {
1251     struct macctrls *mcs = dlg;
1252     union macctrl *mc = findbyctrl(mcs, ctrl);
1253
1254     assert(mc != NULL);
1255     SetControlValue(mc->checkbox.tbctrl,
1256                     checked ? kControlCheckBoxCheckedValue :
1257                               kControlCheckBoxUncheckedValue);
1258 }
1259
1260 int dlg_checkbox_get(union control *ctrl, void *dlg)
1261 {
1262     struct macctrls *mcs = dlg;
1263     union macctrl *mc = findbyctrl(mcs, ctrl);
1264
1265     assert(mc != NULL);
1266     return GetControlValue(mc->checkbox.tbctrl);
1267 }
1268
1269
1270 /*
1271  * Edit Box control
1272  */
1273
1274 void dlg_editbox_set(union control *ctrl, void *dlg, char const *text)
1275 {
1276     struct macctrls *mcs = dlg;
1277     union macctrl *mc = findbyctrl(mcs, ctrl);
1278     GrafPtr saveport;
1279
1280     assert(mc != NULL);
1281     assert(mc->generic.type == MACCTRL_EDITBOX);
1282     GetPort(&saveport);
1283     SetPort((GrafPtr)(GetWindowPort(mcs->window)));
1284     if (mac_gestalts.apprvers >= 0x100)
1285         SetControlData(mc->editbox.tbctrl, kControlEntireControl,
1286                        ctrl->editbox.password ?
1287                        kControlEditTextPasswordTag :
1288                        kControlEditTextTextTag,
1289                        strlen(text), text);
1290 #if !TARGET_API_MAC_CARBON
1291     else
1292         TESetText(text, strlen(text),
1293                   (TEHandle)(*mc->editbox.tbctrl)->contrlData);
1294 #endif
1295     DrawOneControl(mc->editbox.tbctrl);
1296     SetPort(saveport);
1297 }
1298
1299 void dlg_editbox_get(union control *ctrl, void *dlg, char *buffer, int length)
1300 {
1301     struct macctrls *mcs = dlg;
1302     union macctrl *mc = findbyctrl(mcs, ctrl);
1303     Size olen;
1304
1305     assert(mc != NULL);
1306     assert(mc->generic.type == MACCTRL_EDITBOX);
1307     if (mac_gestalts.apprvers >= 0x100) {
1308         if (GetControlData(mc->editbox.tbctrl, kControlEntireControl,
1309                            ctrl->editbox.password ?
1310                            kControlEditTextPasswordTag :
1311                            kControlEditTextTextTag,
1312                            length - 1, buffer, &olen) != noErr)
1313             olen = 0;
1314         if (olen > length - 1)
1315             olen = length - 1;
1316     }
1317 #if !TARGET_API_MAC_CARBON
1318     else {
1319         TEHandle te = (TEHandle)(*mc->editbox.tbctrl)->contrlData;
1320
1321         olen = (*te)->teLength;
1322         if (olen > length - 1)
1323             olen = length - 1;
1324         memcpy(buffer, *(*te)->hText, olen);
1325     }
1326 #endif
1327     buffer[olen] = '\0';
1328     fprintf(stderr, "dlg_editbox_get: %s\n", buffer);
1329 }
1330
1331
1332 /*
1333  * List Box control
1334  */
1335
1336 static void dlg_macpopup_clear(union control *ctrl, void *dlg)
1337 {
1338     struct macctrls *mcs = dlg;
1339     union macctrl *mc = findbyctrl(mcs, ctrl);
1340     MenuRef menu = mc->popup.menu;
1341     unsigned int i, n;
1342
1343     fprintf(stderr, "      popup_clear\n");
1344     n = CountMenuItems(menu);
1345     for (i = 0; i < n; i++)
1346         DeleteMenuItem(menu, n - i);
1347     mc->popup.nids = 0;
1348     sfree(mc->popup.ids);
1349     mc->popup.ids = NULL;
1350     SetControlMaximum(mc->popup.tbctrl, CountMenuItems(menu));
1351 }
1352
1353 void dlg_listbox_clear(union control *ctrl, void *dlg)
1354 {
1355
1356     if (ctrl->listbox.height == 0)
1357         dlg_macpopup_clear(ctrl, dlg);
1358 }
1359
1360 static void dlg_macpopup_del(union control *ctrl, void *dlg, int index)
1361 {
1362     struct macctrls *mcs = dlg;
1363     union macctrl *mc = findbyctrl(mcs, ctrl);
1364     MenuRef menu = mc->popup.menu;
1365
1366     fprintf(stderr, "      popup_del %d\n", index);
1367     DeleteMenuItem(menu, index + 1);
1368     if (mc->popup.ids != NULL)
1369         memcpy(mc->popup.ids + index, mc->popup.ids + index + 1,
1370                (mc->popup.nids - index - 1) * sizeof(*mc->popup.ids));
1371     SetControlMaximum(mc->popup.tbctrl, CountMenuItems(menu));
1372 }
1373
1374 void dlg_listbox_del(union control *ctrl, void *dlg, int index)
1375 {
1376
1377     if (ctrl->listbox.height == 0)
1378         dlg_macpopup_del(ctrl, dlg, index);
1379 }
1380
1381 static void dlg_macpopup_add(union control *ctrl, void *dlg, char const *text)
1382 {
1383     struct macctrls *mcs = dlg;
1384     union macctrl *mc = findbyctrl(mcs, ctrl);
1385     MenuRef menu = mc->popup.menu;
1386     Str255 itemstring;
1387
1388     fprintf(stderr, "      popup_add %s\n", text);
1389     assert(text[0] != '\0');
1390     c2pstrcpy(itemstring, text);
1391     AppendMenu(menu, "\pdummy");
1392     SetMenuItemText(menu, CountMenuItems(menu), itemstring);
1393     SetControlMaximum(mc->popup.tbctrl, CountMenuItems(menu));
1394 }
1395
1396 void dlg_listbox_add(union control *ctrl, void *dlg, char const *text)
1397 {
1398
1399     if (ctrl->listbox.height == 0)
1400         dlg_macpopup_add(ctrl, dlg, text);
1401 }
1402
1403 static void dlg_macpopup_addwithid(union control *ctrl, void *dlg,
1404                                    char const *text, int id)
1405 {
1406     struct macctrls *mcs = dlg;
1407     union macctrl *mc = findbyctrl(mcs, ctrl);
1408     MenuRef menu = mc->popup.menu;
1409     unsigned int index;
1410
1411     fprintf(stderr, "      popup_addwthindex %s, %d\n", text, id);
1412     dlg_macpopup_add(ctrl, dlg, text);
1413     index = CountMenuItems(menu) - 1;
1414     if (mc->popup.nids <= index) {
1415         mc->popup.nids = index + 1;
1416         mc->popup.ids = sresize(mc->popup.ids, mc->popup.nids, int);
1417     }
1418     mc->popup.ids[index] = id;
1419 }
1420
1421 void dlg_listbox_addwithid(union control *ctrl, void *dlg,
1422                            char const *text, int id)
1423 {
1424
1425     if (ctrl->listbox.height == 0)
1426         dlg_macpopup_addwithid(ctrl, dlg, text, id);
1427 }
1428
1429 int dlg_listbox_getid(union control *ctrl, void *dlg, int index)
1430 {
1431     struct macctrls *mcs = dlg;
1432     union macctrl *mc = findbyctrl(mcs, ctrl);
1433
1434     if (ctrl->listbox.height == 0) {
1435         assert(mc->popup.ids != NULL && mc->popup.nids > index);
1436         return mc->popup.ids[index];
1437     }
1438     return 0;
1439 }
1440
1441 int dlg_listbox_index(union control *ctrl, void *dlg)
1442 {
1443     struct macctrls *mcs = dlg;
1444     union macctrl *mc = findbyctrl(mcs, ctrl);
1445
1446     if (ctrl->listbox.height == 0)
1447         return GetControlValue(mc->popup.tbctrl) - 1;
1448     return 0;
1449 };
1450
1451 int dlg_listbox_issel(union control *ctrl, void *dlg, int index)
1452 {
1453     struct macctrls *mcs = dlg;
1454     union macctrl *mc = findbyctrl(mcs, ctrl);
1455
1456     if (ctrl->listbox.height == 0)
1457         return GetControlValue(mc->popup.tbctrl) - 1 == index;
1458     return 0;
1459 };
1460
1461 void dlg_listbox_select(union control *ctrl, void *dlg, int index)
1462 {
1463     struct macctrls *mcs = dlg;
1464     union macctrl *mc = findbyctrl(mcs, ctrl);
1465
1466     if (ctrl->listbox.height == 0)
1467         SetControlValue(mc->popup.tbctrl, index + 1);
1468 };
1469
1470
1471 /*
1472  * Text control
1473  */
1474
1475 void dlg_text_set(union control *ctrl, void *dlg, char const *text)
1476 {
1477     struct macctrls *mcs = dlg;
1478     union macctrl *mc = findbyctrl(mcs, ctrl);
1479
1480     assert(mc != NULL);
1481     if (mac_gestalts.apprvers >= 0x100)
1482         SetControlData(mc->text.tbctrl, kControlEntireControl,
1483                        kControlStaticTextTextTag, strlen(text), text);
1484 #if !TARGET_API_MAC_CARBON
1485     else
1486         TESetText(text, strlen(text),
1487                   (TEHandle)(*mc->text.tbctrl)->contrlData);
1488 #endif
1489 }
1490
1491
1492 /*
1493  * File Selector control
1494  */
1495
1496 void dlg_filesel_set(union control *ctrl, void *dlg, Filename fn)
1497 {
1498
1499 }
1500
1501 void dlg_filesel_get(union control *ctrl, void *dlg, Filename *fn)
1502 {
1503
1504 }
1505
1506
1507 /*
1508  * Font Selector control
1509  */
1510
1511 void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec fn)
1512 {
1513
1514 }
1515
1516 void dlg_fontsel_get(union control *ctrl, void *dlg, FontSpec *fn)
1517 {
1518
1519 }
1520
1521
1522 /*
1523  * Printer enumeration
1524  */
1525
1526 printer_enum *printer_start_enum(int *nprinters)
1527 {
1528
1529     *nprinters = 0;
1530     return NULL;
1531 }
1532
1533 char *printer_get_name(printer_enum *pe, int thing)
1534 {
1535
1536     return "<none>";
1537 }
1538
1539 void printer_finish_enum(printer_enum *pe)
1540 {
1541
1542 }
1543
1544
1545 /*
1546  * Colour selection stuff
1547  */
1548
1549 void dlg_coloursel_start(union control *ctrl, void *dlg,
1550                          int r, int g, int b)
1551 {
1552
1553 }
1554
1555 int dlg_coloursel_results(union control *ctrl, void *dlg,
1556                           int *r, int *g, int *b)
1557 {
1558
1559     return 0;
1560 }
1561
1562 /*
1563  * Local Variables:
1564  * c-file-style: "simon"
1565  * End:
1566  */