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