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