Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/Ruby_bindings/MDRubyDialog.m

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (show annotations) (download)
Sat Sep 3 06:22:57 2011 UTC (12 years, 7 months ago) by toshinagata1964
File size: 24297 byte(s)
initial import
1 //
2 // MDRubyDialog.m
3 // Alchemusica
4 //
5 // Created by Toshi Nagata on 08/04/13.
6 // Copyright 2008-2011 __MyCompanyName__. All rights reserved.
7 //
8
9 #import <Cocoa/Cocoa.h>
10
11 #include "MDRuby.h"
12
13 static VALUE
14 sTextSymbol, sTextFieldSymbol, sRadioSymbol, sButtonSymbol,
15 sCheckBoxSymbol, sPopUpSymbol, sTextViewSymbol, sViewSymbol,
16 sTagSymbol, sTypeSymbol,
17 sTitleSymbol, sXSymbol, sYSymbol, sWidthSymbol, sHeightSymbol,
18 sOriginSymbol, sSizeSymbol, sFrameSymbol,
19 sEnabledSymbol, sHiddenSymbol, sValueSymbol,
20 sBlockSymbol, sRangeSymbol;
21
22 VALUE cMRDialog = Qfalse;
23
24 @implementation MDRubyDialogController
25
26 - (void)windowDidLoad
27 {
28 [super windowDidLoad];
29 ditems = [[NSMutableArray array] retain];
30 [ditems addObject: [[[self window] contentView] viewWithTag: 0]]; /* OK button */
31 [ditems addObject: [[[self window] contentView] viewWithTag: 1]]; /* Cancel button */
32 }
33
34 - (void)dealloc
35 {
36 [ditems release];
37 [super dealloc];
38 }
39
40 - (void)dialogItemAction: (id)sender
41 {
42 int tag = [self searchDialogItem: sender];
43 if (tag == 0) /* OK button */
44 [NSApp stopModal];
45 else if (tag == 1) /* Cancel button */
46 [NSApp abortModal];
47 }
48
49 - (void)setRubyObject: (VALUE)val
50 {
51 dval = val;
52 }
53
54 - (void)addDialogItem: (id)ditem
55 {
56 [[[self window] contentView] addSubview: ditem];
57 [ditems addObject: ditem];
58 }
59
60 - (id)dialogItemAtIndex: (int)index
61 {
62 if (index >= 0 && index < [ditems count])
63 return [ditems objectAtIndex: index];
64 else return nil;
65 }
66
67 - (int)searchDialogItem: (id)ditem
68 {
69 unsigned int ui = [ditems indexOfObjectIdenticalTo: ditem];
70 if (ui == NSNotFound)
71 return -1;
72 else return ui;
73 }
74
75 - (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor
76 {
77 VALUE items, item, val, val_min, val_max;
78 int nitems, itag;
79 NSString *s;
80
81 if (dval == Qfalse)
82 return NO;
83
84 s = [control stringValue];
85 items = rb_iv_get(dval, "_items");
86 nitems = RARRAY_LEN(items);
87 itag = [control tag];
88 if (itag < 0 || itag >= nitems)
89 return YES; /* Accept anything */
90
91 item = (RARRAY_PTR(items))[itag];
92 val = rb_hash_aref(item, sRangeSymbol);
93 if (NIL_P(val))
94 return YES; /* Accept anything */
95
96 val_min = MDRuby_ObjectAtIndex(val, 0);
97 val_max = MDRuby_ObjectAtIndex(val, 1);
98 if (FIXNUM_P(val_min) && FIXNUM_P(val_max)) {
99 int ival = [s intValue];
100 int imin = NUM2INT(val_min);
101 int imax = NUM2INT(val_max);
102 if (ival < imin || ival > imax)
103 return NO;
104 [control setStringValue: [NSString stringWithFormat: @"%d", ival]];
105 } else {
106 double d = [s doubleValue];
107 double dmin = NUM2DBL(val_min);
108 double dmax = NUM2DBL(val_max);
109 if (d < dmin || d > dmax)
110 return NO;
111 }
112 return YES;
113 }
114
115 @end
116
117 #if 0
118 /* Internal class for adding tags to a generic view */
119 @interface MDRubyTaggedView : NSView {
120 int tag;
121 }
122 - (void)setTag: (int)tag;
123 - (int)tag;
124 @end
125
126 @implementation MDRubyTaggedView
127 - (void)setTag: (int)aTag
128 {
129 tag = aTag;
130 }
131 - (int)tag
132 {
133 return tag;
134 }
135 @end;
136 #endif
137
138 #pragma mark ====== MRDialog alloc/init/release ======
139
140 typedef struct MRDialogInfo {
141 MDRubyDialogController *d;
142 } MRDialogInfo;
143
144 static MDRubyDialogController *
145 s_MRDialog_GetController(VALUE self)
146 {
147 MRDialogInfo *di;
148 Data_Get_Struct(self, MRDialogInfo, di);
149 if (di != NULL)
150 return di->d;
151 else return NULL;
152 }
153
154 static void
155 s_MRDialog_Release(void *p)
156 {
157 if (p != NULL) {
158 MDRubyDialogController *d = ((MRDialogInfo *)p)->d;
159 if (d != nil) {
160 [d setRubyObject: Qfalse]; /* Stop access to the Ruby object (in case the MDRubyDialogController is not dealloc'ed in the following line) */
161 [d release];
162 ((MRDialogInfo *)p)->d = nil;
163 }
164 free(p);
165 }
166 }
167
168 static VALUE
169 s_MRDialog_Alloc(VALUE klass)
170 {
171 VALUE val;
172 MRDialogInfo *di;
173 MDRubyDialogController *d = [[MDRubyDialogController alloc] initWithWindowNibName: @"RubyDialog"];
174 val = Data_Make_Struct(klass, MRDialogInfo, 0, s_MRDialog_Release, di);
175 di->d = d;
176 [d setRubyObject: val];
177 return val;
178 }
179
180 static VALUE
181 s_MRDialog_Initialize(int argc, VALUE *argv, VALUE self)
182 {
183 int i, j;
184 VALUE val1;
185 VALUE items;
186 MDRubyDialogController *d = s_MRDialog_GetController(self);
187
188 [d window]; // Load window
189
190 rb_scan_args(argc, argv, "01", &val1);
191 if (!NIL_P(val1)) {
192 char *p = StringValuePtr(val1);
193 [[d window] setTitle: [NSString stringWithUTF8String: p]];
194 }
195
196 // Array of item informations
197 items = rb_ary_new();
198
199 // Initialize "OK" and "Cancel" buttons (may be used for enabling/disabling buttons)
200 for (i = 0; i < 2; i++) {
201 VALUE item, vals[14];
202 id button = [[[d window] contentView] viewWithTag: i];
203 NSString *title = [button title];
204 NSRect frame = [button frame];
205 vals[0] = sTagSymbol;
206 vals[1] = rb_str_new2(i == 0 ? "ok" : "cancel");
207 vals[2] = sTypeSymbol;
208 vals[3] = sButtonSymbol;
209 vals[4] = sTitleSymbol;
210 vals[5] = rb_str_new2([title UTF8String]);
211 vals[6] = sXSymbol;
212 vals[7] = rb_float_new(frame.origin.x);
213 vals[8] = sYSymbol;
214 vals[9] = rb_float_new(frame.origin.y);
215 vals[10] = sWidthSymbol;
216 vals[11] = rb_float_new(frame.size.width);
217 vals[12] = sHeightSymbol;
218 vals[13] = rb_float_new(frame.size.height);
219 item = rb_hash_new();
220 for (j = 0; j < 7; j++) {
221 rb_hash_aset(item, vals[j * 2], vals[j * 2 + 1]);
222 }
223 rb_ary_push(items, item);
224 }
225
226 rb_iv_set(self, "_items", items);
227
228 return Qnil;
229 }
230
231 #pragma mark ====== Ruby methods ======
232
233 static int
234 s_MRDialog_ItemIndexForTag(VALUE self, VALUE tag)
235 {
236 VALUE items = rb_iv_get(self, "_items");
237 int len = RARRAY_LEN(items);
238 VALUE *ptr = RARRAY_PTR(items);
239 int i;
240 if (FIXNUM_P(tag) && (i = NUM2INT(tag)) >= 0 && i < len)
241 return i;
242 for (i = 0; i < len; i++) {
243 if (rb_equal(tag, rb_hash_aref(ptr[i], sTagSymbol)) == Qtrue)
244 return i;
245 }
246 rb_raise(rb_eStandardError, "MRDialog has no item with tag %s", StringValuePtr(tag));
247 return -1; /* Not reached */
248 }
249
250 static NSString *
251 s_CleanUpNewLine(NSString *s)
252 {
253 /* Convert various "newline" characters in an NSString to "\n" */
254 unsigned int start, end, contentsEnd;
255 NSRange range;
256 NSMutableString *ms = [NSMutableString stringWithString: s];
257 start = [ms length];
258 while (start > 0) {
259 /* Get the "last line" */
260 range.location = start - 1;
261 range.length = 1;
262 [ms getLineStart: &start end: &end contentsEnd: &contentsEnd forRange: range];
263 if (contentsEnd < end) {
264 /* Replace the EOL characters with @"\n" */
265 [ms replaceCharactersInRange: NSMakeRange(contentsEnd, end - contentsEnd) withString: @"\n"];
266 }
267 }
268 return ms;
269 }
270
271 /*
272 * call-seq:
273 * dialog.set_attr(tag, hash)
274 *
275 * Set the attributes given in the hash.
276 */
277 static VALUE
278 s_MRDialog_SetAttr(VALUE self, VALUE tag, VALUE hash)
279 {
280 int i;
281 VALUE items = rb_iv_get(self, "_items");
282 VALUE *ptr = RARRAY_PTR(items);
283 int itag = s_MRDialog_ItemIndexForTag(self, tag);
284 VALUE item = ptr[itag];
285 VALUE type = rb_hash_aref(item, sTypeSymbol);
286 MDRubyDialogController *d = s_MRDialog_GetController(self);
287 id view = [d dialogItemAtIndex: itag];
288 VALUE keys = rb_funcall(hash, rb_intern("keys"), 0);
289 int klen = RARRAY_LEN(keys);
290 VALUE *kptr = RARRAY_PTR(keys);
291
292 for (i = 0; i < klen; i++) {
293 VALUE key = kptr[i];
294 VALUE val = rb_hash_aref(hash, key);
295 BOOL flag;
296 NSString *s;
297 if (key == sRangeSymbol) {
298 /* Range of value (must be an array of two integers or two floats) */
299 VALUE val1, val2;
300 double d1, d2;
301 if (TYPE(val) != T_ARRAY || RARRAY_LEN(val) != 2)
302 rb_raise(rb_eTypeError, "the attribute 'range' should specify an array of two numbers");
303 val1 = RARRAY_PTR(val)[0];
304 val2 = RARRAY_PTR(val)[1];
305 d1 = NUM2DBL(val1);
306 d2 = NUM2DBL(val2);
307 if (!FIXNUM_P(val1) || !FIXNUM_P(val2)) {
308 /* Convert to a range of floats */
309 if (TYPE(val1) != T_FLOAT || TYPE(val2) != T_FLOAT) {
310 val1 = rb_float_new(NUM2DBL(val1));
311 val2 = rb_float_new(NUM2DBL(val2));
312 val = rb_ary_new3(2, val1, val2);
313 }
314 }
315 if (d1 > d2)
316 rb_raise(rb_eArgError, "invalid number range [%g,%g]", d1, d2);
317 rb_hash_aset(item, key, val);
318 } else if (key == sValueSymbol) {
319 /* Value */
320 if (type == sTextFieldSymbol || type == sTextViewSymbol) {
321 s = [NSString stringWithUTF8String: StringValuePtr(val)];
322 if (type == sTextFieldSymbol)
323 [view setStringValue: s];
324 else
325 [[view documentView] setString: s];
326 } else if (type == sCheckBoxSymbol) {
327 [view setState: (RTEST(val) ? NSOnState : NSOffState)];
328 }
329 } else if (key == sTitleSymbol) {
330 /* Title */
331 s = [NSString stringWithUTF8String: StringValuePtr(val)];
332 if (type == sTextSymbol)
333 [view setStringValue: s];
334 else [view setTitle: s];
335 } else if (key == sEnabledSymbol) {
336 /* Enabled */
337 flag = (val != Qnil && val != Qfalse);
338 if (type == sTextViewSymbol)
339 [[view documentView] setEditable: flag];
340 else
341 [view setEnabled: flag];
342 } else if (key == sHiddenSymbol) {
343 /* Hidden */
344 flag = (val != Qnil && val != Qfalse);
345 [view setHidden: flag];
346 } else if (key == sXSymbol || key == sYSymbol || key == sWidthSymbol || key == sHeightSymbol) {
347 /* Frame components */
348 NSRect frame;
349 float f = NUM2DBL(val);
350 frame = [view frame];
351 if (key == sXSymbol)
352 frame.origin.x = f;
353 else if (key == sYSymbol)
354 frame.origin.y = f;
355 else if (key == sWidthSymbol)
356 frame.size.width = f;
357 else
358 frame.size.height = f;
359 [view setFrame: frame];
360 } else if (key == sOriginSymbol || key == sSizeSymbol) {
361 /* Frame components */
362 NSRect frame;
363 float f0 = NUM2DBL(MDRuby_ObjectAtIndex(val, 0));
364 float f1 = NUM2DBL(MDRuby_ObjectAtIndex(val, 1));
365 frame = [view frame];
366 if (key == sOriginSymbol) {
367 frame.origin.x = f0;
368 frame.origin.y = f1;
369 } else {
370 frame.size.width = f0;
371 frame.size.height = f1;
372 }
373 [view setFrame: frame];
374 } else if (key == sFrameSymbol) {
375 /* Frame (x, y, width, height) */
376 NSRect frame;
377 frame.origin.x = NUM2DBL(MDRuby_ObjectAtIndex(val, 0));
378 frame.origin.y = NUM2DBL(MDRuby_ObjectAtIndex(val, 1));
379 frame.size.width = NUM2DBL(MDRuby_ObjectAtIndex(val, 2));
380 frame.size.height = NUM2DBL(MDRuby_ObjectAtIndex(val, 3));
381 [view setFrame: frame];
382 } else {
383 rb_hash_aset(item, key, val);
384 }
385 }
386 return Qnil;
387 }
388
389 /*
390 * call-seq:
391 * dialog.attr(tag, key)
392 *
393 * Get the attribute for the key.
394 */
395 static VALUE
396 s_MRDialog_Attr(VALUE self, VALUE tag, VALUE key)
397 {
398 BOOL flag;
399 VALUE items = rb_iv_get(self, "_items");
400 VALUE *ptr = RARRAY_PTR(items);
401 int itag = s_MRDialog_ItemIndexForTag(self, tag);
402 VALUE item = ptr[itag];
403 VALUE type = rb_hash_aref(item, sTypeSymbol);
404 MDRubyDialogController *d = s_MRDialog_GetController(self);
405 id view = [d dialogItemAtIndex: itag];
406
407 VALUE val = Qnil;
408 NSString *s;
409 if (key == sValueSymbol) {
410 /* Value */
411 if (type == sTextFieldSymbol) {
412 /* Is range specified? */
413 VALUE range = rb_hash_aref(item, sRangeSymbol);
414 s = [view stringValue];
415 if (TYPE(range) == T_ARRAY) {
416 if (FIXNUM_P((RARRAY_PTR(range))[0]))
417 val = INT2NUM([s intValue]);
418 else
419 val = rb_float_new([s doubleValue]);
420 } else val = rb_str_new2([s UTF8String]);
421 } else if (type == sTextViewSymbol) {
422 s = [[view documentView] string];
423 s = s_CleanUpNewLine(s);
424 val = rb_str_new2([s UTF8String]);
425 } else if (type == sCheckBoxSymbol) {
426 val = ([view state] == NSOnState ? Qtrue : Qfalse);
427 }
428 } else if (key == sTitleSymbol) {
429 if (type == sTextSymbol)
430 s = [view stringValue];
431 else s = [view title];
432 val = rb_str_new2([s UTF8String]);
433 } else if (key == sEnabledSymbol) {
434 /* Enabled */
435 if (type == sTextViewSymbol)
436 flag = [[view documentView] isEditable];
437 else
438 flag = [view isEnabled];
439 val = (flag ? Qtrue : Qfalse);
440 } else if (key == sHiddenSymbol) {
441 /* Hidden */
442 val = ([view isHiddenOrHasHiddenAncestor] ? Qtrue : Qfalse);
443 } else if (key == sXSymbol || key == sYSymbol || key == sWidthSymbol || key == sHeightSymbol) {
444 /* Frame components */
445 NSRect frame;
446 float f;
447 frame = [view frame];
448 if (key == sXSymbol)
449 f = frame.origin.x;
450 else if (key == sYSymbol)
451 f = frame.origin.y;
452 else if (key == sWidthSymbol)
453 f = frame.size.width;
454 else
455 f = frame.size.height;
456 val = rb_float_new(f);
457 } else if (key == sOriginSymbol || key == sSizeSymbol) {
458 /* Frame components */
459 NSRect frame;
460 float f0, f1;
461 frame = [view frame];
462 if (key == sOriginSymbol) {
463 f0 = frame.origin.x;
464 f1 = frame.origin.y;
465 } else {
466 f0 = frame.size.width;
467 f1 = frame.size.height;
468 }
469 val = rb_ary_new3(2, rb_float_new(f0), rb_float_new(f1));
470 rb_obj_freeze(val);
471 } else if (key == sFrameSymbol) {
472 /* Frame (x, y, width, height) */
473 NSRect frame = [view frame];
474 val = rb_ary_new3(4, rb_float_new(frame.origin.x), rb_float_new(frame.origin.y), rb_float_new(frame.size.width), rb_float_new(frame.size.height));
475 rb_obj_freeze(val);
476 } else {
477 val = rb_hash_aref(item, key);
478 }
479
480 return val;
481 }
482
483 /*
484 * call-seq:
485 * dialog.run
486 *
487 * Run the modal session for this dialog.
488 */
489 static VALUE
490 s_MRDialog_Run(VALUE self)
491 {
492 int retval;
493 MDRubyDialogController *d = s_MRDialog_GetController(self);
494
495 retval = [NSApp runModalForWindow: [d window]];
496 [d close];
497 if (retval == NSRunStoppedResponse) {
498 VALUE items = rb_iv_get(self, "_items");
499 int len = RARRAY_LEN(items);
500 VALUE *ptr = RARRAY_PTR(items);
501 VALUE hash = rb_hash_new();
502 int i;
503 /* Get values for editable controls */
504 for (i = 0; i < len; i++) {
505 // VALUE type = rb_hash_aref(ptr[i], sTypeSymbol);
506 VALUE tag = rb_hash_aref(ptr[i], sTagSymbol);
507 VALUE val;
508 if (NIL_P(tag))
509 continue;
510 val = s_MRDialog_Attr(self, tag, sValueSymbol);
511 rb_hash_aset(hash, tag, val);
512 }
513 return hash;
514 } else
515 return Qfalse;
516 }
517
518 /*
519 * call-seq:
520 * dialog.layout(row, column, i11, ..., i1c, i21, ..., i2c, ..., ir1, ..., irc, options) => integer
521 *
522 * Layout items in a table.
523 * Returns an integer that represents the NSView that wraps the items.
524 */
525 static VALUE
526 s_MRDialog_Layout(int argc, VALUE *argv, VALUE self)
527 {
528 VALUE rval, cval, nhash, items;
529 int row, col, i, j, n, itag, nitems;
530 MDRubyDialogController *d;
531 float *widths, *heights;
532 float f, fmin;
533 NSSize *sizes;
534 NSView *contentView;
535 NSView *layoutView;
536 NSSize contentMinSize;
537 NSRect layoutFrame;
538 float col_padding = 4.0; /* Padding between columns */
539 float row_padding = 4.0; /* Padding between rows */
540 float margin = 15.0;
541
542 d = s_MRDialog_GetController(self);
543 contentView = [[d window] contentView];
544 contentMinSize = [[d window] contentMinSize];
545 items = rb_iv_get(self, "_items");
546 nitems = RARRAY_LEN(items);
547
548 if (argc < 2)
549 rb_raise(rb_eArgError, "wrong number of arguments (should be at least 2 but only %d given)", argc);
550
551 rval = argv[0];
552 cval = argv[1];
553 row = NUM2INT(rval);
554 col = NUM2INT(cval);
555 if (row <= 0)
556 rb_raise(rb_eRangeError, "number of rows (%d) must be a positive integer", row);
557 if (col <= 0)
558 rb_raise(rb_eRangeError, "number of columns (%d) must be a positive integer", col);
559
560 /* Allocate temporary storage */
561 sizes = (NSSize *)calloc(sizeof(NSSize), row * col);
562 widths = (float *)calloc(sizeof(float), col);
563 heights = (float *)calloc(sizeof(float), row);
564 if (sizes == NULL || widths == NULL || heights == NULL)
565 rb_raise(rb_eNoMemError, "out of memory during layout");
566
567 /* Get frame sizes */
568 for (i = 0; i < row; i++) {
569 for (j = 0; j < col; j++) {
570 n = 2 + i * col + j;
571 if (n < argc && FIXNUM_P(argv[n])) {
572 itag = FIX2INT(argv[n]);
573 if (itag >= nitems)
574 rb_raise(rb_eRangeError, "item tag (%d) is out of range (should be 0..%d)", itag, nitems - 1);
575 sizes[n - 2] = [[d dialogItemAtIndex: itag] frame].size;
576 }
577 }
578 }
579
580 /* Calculate required widths */
581 fmin = 0.0;
582 for (j = 0; j < col; j++) {
583 for (i = 0; i < row; i++) {
584 for (n = j; n >= 0; n--) {
585 f = sizes[i * col + n].width;
586 if (f > 0.0) {
587 f += (n > 0 ? widths[n - 1] : 0.0);
588 break;
589 }
590 }
591 if (fmin < f)
592 fmin = f;
593 }
594 fmin += col_padding;
595 widths[j] = fmin;
596 }
597
598 /* Calculate required heights */
599 fmin = 0.0;
600 for (i = 0; i < row; i++) {
601 for (j = 0; j < col; j++) {
602 for (n = i; n >= 0; n--) {
603 f = sizes[n * col + j].height;
604 if (f > 0.0) {
605 f += (n > 0 ? heights[n - 1] : 0.0);
606 break;
607 }
608 }
609 if (fmin < f)
610 fmin = f;
611 }
612 fmin += row_padding;
613 heights[i] = fmin;
614 }
615
616 /* Create a layout view */
617 layoutFrame.size.width = widths[col - 1];
618 layoutFrame.size.height = heights[row - 1];
619 layoutFrame.origin.x = margin;
620 layoutFrame.origin.y = contentMinSize.height;
621 layoutView = [[[NSView alloc] initWithFrame: layoutFrame] autorelease];
622
623 /* Move the subviews into the layout view */
624 for (i = 0; i < row; i++) {
625 for (j = 0; j < col; j++) {
626 n = 2 + i * col + j;
627 if (n < argc && FIXNUM_P(argv[n]) && (itag = FIX2INT(argv[n])) < nitems) {
628 NSPoint pt;
629 NSView *subview = [d dialogItemAtIndex: itag];
630 float offset;
631 VALUE type = rb_hash_aref((RARRAY_PTR(items))[itag], sTypeSymbol);
632 if (type == sTextSymbol)
633 offset = 3.0;
634 else offset = 0.0;
635 pt.x = (j > 0 ? widths[j - 1] : 0.0) + col_padding * 0.5;
636 pt.y = layoutFrame.size.height - (i > 0 ? heights[i - 1] : 0.0) - sizes[n - 2].height - row_padding * 0.5 - offset;
637 [subview retain];
638 [subview removeFromSuperview];
639 [layoutView addSubview: subview];
640 [subview setFrameOrigin: pt];
641 [subview release];
642 }
643 }
644 }
645
646 free(sizes);
647 free(widths);
648 free(heights);
649
650 /* Create a new hash for the layout view and push to _items */
651 nhash = rb_hash_new();
652 rb_hash_aset(nhash, sTypeSymbol, sViewSymbol);
653 rb_ary_push(items, nhash);
654
655 /* Tag for the layout view */
656 itag = RARRAY_LEN(items) - 1;
657
658 /* Resize the window */
659 {
660 NSSize winSize;
661 winSize.width = layoutFrame.size.width + margin * 2;
662 if (winSize.width < contentMinSize.width)
663 winSize.width = contentMinSize.width;
664 winSize.height = layoutFrame.size.height + contentMinSize.height + margin;
665 [[d window] setContentSize: winSize];
666 }
667
668 /* Add to the window */
669 [d addDialogItem: layoutView];
670
671 /* Returns the integer tag */
672 return INT2NUM(itag);
673 }
674
675 /*
676 * call-seq:
677 * dialog.item(type, hash) => integer
678 *
679 * Create a dialog item.
680 * type: one of the following symbols; :text, :textfield, :radio, :checkbox, :popup
681 * hash: attributes that can be set by set_attr
682 * Returns an integer that represents the item. (0 and 1 are reserved for "OK" and "Cancel")
683 */
684 static VALUE
685 s_MRDialog_Item(int argc, VALUE *argv, VALUE self)
686 {
687 int itag; /* Integer tag for NSControl */
688 id control; /* A view */
689 NSRect rect, brect;
690 NSString *title;
691 NSDictionary *attr;
692 NSFont *font;
693 VALUE type, hash, val, nhash, items;
694 MDRubyDialogController *d;
695
696 d = s_MRDialog_GetController(self);
697 rb_scan_args(argc, argv, "11", &type, &hash);
698 if (NIL_P(hash))
699 hash = rb_hash_new();
700 rect.size.width = rect.size.height = 1.0;
701 rect.origin.x = rect.origin.y = 0.0;
702
703 val = rb_hash_aref(hash, sTitleSymbol);
704 if (!NIL_P(val)) {
705 title = [NSString stringWithUTF8String: StringValuePtr(val)];
706 } else {
707 title = @"";
708 }
709
710 Check_Type(type, T_SYMBOL);
711
712 if (type == sTextViewSymbol)
713 font = [NSFont userFixedPitchFontOfSize: 0];
714 else
715 font = [NSFont systemFontOfSize: [NSFont smallSystemFontSize]];
716 attr = [NSDictionary dictionaryWithObjectsAndKeys: font, NSFontAttributeName, nil];
717 brect.origin.x = brect.origin.y = 0.0;
718 brect.size = [title sizeWithAttributes: attr];
719 brect.size.width += 8;
720
721 /* Set rect if specified */
722 /* val = rb_hash_aref(hash, sXSymbol);
723 if (!NIL_P(val) && (dval = NUM2DBL(val)) > 0.0)
724 rect.origin.x = dval;
725 val = rb_hash_aref(hash, sYSymbol);
726 if (!NIL_P(val) && (dval = NUM2DBL(val)) > 0.0)
727 rect.origin.y = dval;
728 val = rb_hash_aref(hash, sWidthSymbol);
729 if (!NIL_P(val) && (dval = NUM2DBL(val)) > 0.0)
730 rect.size.width = dval;
731 val = rb_hash_aref(hash, sHeightSymbol);
732 if (!NIL_P(val) && (dval = NUM2DBL(val)) > 0.0)
733 rect.size.height = dval; */
734
735 /* Create a new hash for this item */
736 nhash = rb_hash_new();
737 rb_hash_aset(nhash, sTypeSymbol, type);
738
739 if (type == sTextSymbol || type == sTextFieldSymbol) {
740 if (rect.size.height == 1.0)
741 rect.size.height = brect.size.height;
742 if (rect.size.width == 1.0)
743 rect.size.width = brect.size.width;
744 if (type == sTextFieldSymbol)
745 rect.size.height += 5.0;
746 control = [[[NSTextField alloc] initWithFrame: rect] autorelease];
747 [control setStringValue: title];
748 [control setFont: font];
749 [control setDelegate: d];
750 if (type == sTextSymbol) {
751 [control setEditable: NO];
752 [control setBezeled: NO];
753 [control setBordered: NO];
754 [control setDrawsBackground: NO];
755 } else {
756 [control setEditable: YES];
757 [control setBezeled: YES];
758 [control setDrawsBackground: YES];
759 }
760 } else if (type == sTextViewSymbol) {
761 /* An NSTextView included within an NSScrollView */
762 NSTextView *tv;
763 NSSize contentSize;
764 if (rect.size.height == 1.0)
765 rect.size.height = brect.size.height;
766 if (rect.size.width == 1.0)
767 rect.size.width = 90;
768 control = [[[NSScrollView alloc] initWithFrame: rect] autorelease];
769 [control setHasVerticalScroller: YES];
770 [control setHasHorizontalScroller: NO];
771 [control setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
772 [control setBorderType: NSBezelBorder];
773 [[control verticalScroller] setControlSize: NSSmallControlSize];
774 contentSize = [control contentSize];
775 tv = [[[NSTextView alloc] initWithFrame: NSMakeRect(0, 0, contentSize.width, contentSize.height)] autorelease];
776 [tv setMinSize: NSMakeSize(0.0, contentSize.height)];
777 [tv setMaxSize: NSMakeSize(FLT_MAX, FLT_MAX)];
778 [tv setVerticallyResizable: YES];
779 [tv setHorizontallyResizable: NO];
780 [tv setAutoresizingMask: NSViewWidthSizable];
781 [[tv textContainer] setContainerSize: NSMakeSize(contentSize.width, FLT_MAX)];
782 [[tv textContainer] setWidthTracksTextView: YES];
783 [tv setFont: font];
784 // [control setDelegate: d];
785 [tv setRichText: NO];
786 [tv setSelectable: YES];
787 [tv setEditable: YES];
788 [control setDocumentView: tv];
789 } else if (type == sCheckBoxSymbol) {
790 if (rect.size.height == 1.0)
791 rect.size.height = 14;
792 if (rect.size.width == 1.0)
793 rect.size.width = brect.size.width + 20;
794 control = [[[NSButton alloc] initWithFrame: rect] autorelease];
795 [control setButtonType: NSSwitchButton];
796 [[control cell] setControlSize: NSSmallControlSize];
797 [control setFont: font];
798 [control setTitle: title];
799 } else {
800 rb_raise(rb_eStandardError, "item type :%s is not implemented", rb_id2name(SYM2ID(type)));
801 }
802
803 /* Push to _items */
804 items = rb_iv_get(self, "_items");
805 rb_ary_push(items, nhash);
806 itag = RARRAY_LEN(items) - 1;
807
808 /* Add to the window */
809 [d addDialogItem: control];
810
811 /* Tag as a Ruby integer */
812 val = INT2NUM(itag);
813
814 /* Set attributes */
815 s_MRDialog_SetAttr(self, val, hash);
816
817 return val;
818 }
819
820 /*
821 * call-seq:
822 * dialog._items => an array of hash
823 *
824 * Returns an internal array of items. For debugging use only.
825 */
826 static VALUE
827 s_MRDialog_Items(VALUE self)
828 {
829 return rb_iv_get(self, "_items");
830 }
831
832 #pragma mark ====== Initialize class ======
833
834 void
835 MRDialogInitClass(void)
836 {
837 if (cMRDialog != Qfalse)
838 return;
839
840 cMRDialog = rb_define_class("RubyDialog", rb_cObject);
841 rb_define_alloc_func(cMRDialog, s_MRDialog_Alloc);
842 rb_define_private_method(cMRDialog, "initialize", s_MRDialog_Initialize, -1);
843 rb_define_method(cMRDialog, "run", s_MRDialog_Run, 0);
844 rb_define_method(cMRDialog, "item", s_MRDialog_Item, -1);
845 rb_define_method(cMRDialog, "layout", s_MRDialog_Layout, -1);
846 rb_define_method(cMRDialog, "_items", s_MRDialog_Items, 0);
847 rb_define_method(cMRDialog, "set_attr", s_MRDialog_SetAttr, 2);
848 rb_define_method(cMRDialog, "attr", s_MRDialog_Attr, 2);
849
850 {
851 static VALUE *sTable1[] = { &sTextSymbol, &sTextFieldSymbol, &sRadioSymbol, &sButtonSymbol, &sCheckBoxSymbol, &sPopUpSymbol, &sTextViewSymbol, &sViewSymbol, &sTagSymbol, &sTypeSymbol, &sTitleSymbol, &sXSymbol, &sYSymbol, &sWidthSymbol, &sHeightSymbol, &sOriginSymbol, &sSizeSymbol, &sFrameSymbol, &sEnabledSymbol, &sHiddenSymbol, &sValueSymbol, &sBlockSymbol, &sRangeSymbol };
852 static const char *sTable2[] = { "text", "textfield", "radio", "button", "checkbox", "popup", "textview", "view", "tag", "type", "title", "x", "y", "width", "height", "origin", "size", "frame", "enabled", "hidden", "value", "block", "range" };
853 int i;
854 for (i = 0; i < sizeof(sTable1) / sizeof(sTable1[0]); i++)
855 *(sTable1[i]) = ID2SYM(rb_intern(sTable2[i]));
856 }
857 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26