Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/Ruby_bindings/RubyDialogController.m

Parent Directory Parent Directory | Revision Log Revision Log


Revision 146 - (show annotations) (download)
Sun Dec 17 04:05:28 2017 UTC (6 years, 5 months ago) by toshinagata1964
File size: 47996 byte(s)
Xcode project is updated so that ppc/i386 universal binary can be built (as before)
1 //
2 // RubyDialogController.m
3 // Alchemusica
4 //
5 // Created by Toshi Nagata on 08/04/13.
6 // Copyright 2008-2016 Toshi Nagata. All rights reserved.
7 //
8 /*
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation version 2 of the License.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17 */
18
19 #import <Cocoa/Cocoa.h>
20
21 #include "RubyDialogController.h"
22 #include "MDRuby.h"
23
24 VALUE cMRDialog = Qfalse;
25
26 @implementation RubyDialogController
27
28 - (void)windowDidLoad
29 {
30 NSView *contentView;
31 [super windowDidLoad];
32 autoResizeEnabled = YES;
33 ditems = [[NSMutableArray array] retain];
34 [ditems addObject: [[[self window] contentView] viewWithTag: 0]]; /* OK button */
35 [ditems addObject: [[[self window] contentView] viewWithTag: 1]]; /* Cancel button */
36 gRubyDialogIsFlipped = 1;
37 contentView = [[self window] contentView];
38 [contentView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
39 [contentView setAutoresizesSubviews:NO];
40 mySize = [[[self window] contentView] frame].size;
41 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidResize:)
42 name:NSWindowDidResizeNotification object:[self window]];
43 }
44
45 - (void)dealloc
46 {
47 if (myTimer != nil)
48 [myTimer invalidate];
49 [ditems release];
50 [super dealloc];
51 }
52
53 - (void)dialogItemAction: (id)sender
54 {
55 RubyDialog_doItemAction(dval, (RDItem *)sender, 0);
56
57 // int tag = [self searchDialogItem: sender];
58 // if (tag == 0) /* OK button */
59 // [NSApp stopModal];
60 // else if (tag == 1) /* Cancel button */
61 // [NSApp abortModal];
62 }
63
64 - (void)setRubyObject: (RubyValue)val
65 {
66 dval = val;
67 }
68
69 - (void)addDialogItem: (id)ditem
70 {
71 [[[self window] contentView] addSubview: ditem];
72 [ditems addObject: ditem];
73 }
74
75 - (id)dialogItemAtIndex: (int)index
76 {
77 if (index >= 0 && index < [ditems count])
78 return [ditems objectAtIndex: index];
79 else return nil;
80 }
81
82 - (int)searchDialogItem: (id)ditem
83 {
84 NSUInteger ui = [ditems indexOfObjectIdenticalTo: ditem];
85 if (ui == NSNotFound)
86 return -1;
87 else return (int)ui;
88 }
89
90 - (void)timerCallback:(NSTimer *)theTimer
91 {
92 RubyDialog_doTimerAction((RubyValue)dval);
93 }
94
95 - (int)startIntervalTimer: (float)millisec
96 {
97 if (myTimer != nil)
98 [myTimer invalidate];
99 myTimer = [NSTimer scheduledTimerWithTimeInterval:millisec / 1000.0 target:self selector:@selector(timerCallback:) userInfo:nil repeats:YES];
100 return 1;
101 }
102
103 - (void)stopIntervalTimer
104 {
105 if (myTimer != nil) {
106 [myTimer invalidate];
107 myTimer = nil;
108 }
109 }
110
111 - (void)cancel:(id)sender
112 {
113 // Send action for the "cancel" button
114 id ditem;
115 // If we are editing a text view, then ignore ESC or control-period
116 if ([[[self window] firstResponder] isKindOfClass:[NSTextView class]])
117 return;
118 ditem = [self dialogItemAtIndex:1];
119 if (ditem != nil && ![ditem isHidden] && [ditem isEnabled])
120 RubyDialog_doItemAction(dval, (RDItem *)ditem, 0);
121 }
122
123 - (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor
124 {
125 if (dval == NULL)
126 return NO;
127 return (RubyDialog_validateItemContent(dval, (RDItem *)control, [[fieldEditor string] UTF8String]) != 0);
128 }
129
130 - (void)controlTextDidEndEditing:(NSNotification *)aNotification
131 {
132 if (dval == NULL)
133 return;
134 /* Send action */
135 id obj = [aNotification object];
136 [obj sendAction:[obj action] to:[obj target]];
137 if ([obj isKindOfClass:[NSTextField class]] && [self searchDialogItem:obj] >= 0) {
138 // User-defined text field
139 id movementCode = [[aNotification userInfo] objectForKey:@"NSTextMovement"];
140 if (movementCode != nil && [movementCode intValue] == NSReturnTextMovement) {
141 // Return key is pressed
142 // Send key event to the window (to process default button)
143 // See the Cocoa documentation for -[NSTextField textDidEndEditing:]
144 [[self window] performKeyEquivalent:[NSApp currentEvent]];
145 }
146 }
147 }
148
149 - (void)textDidChange:(NSNotification *) aNotification
150 {
151 id view = [[aNotification object] enclosingScrollView];
152 [self dialogItemAction:view];
153 }
154
155 static void
156 sResizeSubViews(RubyValue dval, NSView *view, int dx, int dy)
157 {
158 NSArray *subviews = [view subviews];
159 int idx, n = (int)[subviews count];
160 for (idx = 0; idx < n; idx++) {
161 int i, d, f, d1, d2, d3, ddx, ddy;
162 NSView *current = [subviews objectAtIndex:idx];
163 NSRect frame = [current frame];
164 int flex = RubyDialog_getFlexFlags(dval, (RDItem *)current);
165 if (flex < 0)
166 continue;
167 for (i = 0, f = flex; i < 2; i++, f /= 2) {
168 if (i == 0)
169 d = dx;
170 else
171 d = dy;
172 switch (f & 21) { /* left, right, width (or top, bottom, height) */
173 case 21: /* all flex */
174 d1 = d2 = d / 3;
175 d3 = d - d1 - d2;
176 break;
177 case 5: /* left & right */
178 d1 = d / 2;
179 d2 = 0;
180 d3 = d - d1;
181 break;
182 case 17: /* left & width */
183 d1 = d / 2;
184 d2 = d - d1;
185 d3 = 0;
186 break;
187 case 20: /* right & width */
188 d1 = 0;
189 d2 = d / 2;
190 d3 = d - d2;
191 break;
192 case 1: /* left */
193 d1 = d;
194 d2 = d3 = 0;
195 break;
196 case 4: /* right */
197 d3 = d;
198 d1 = d2 = 0;
199 break;
200 case 16: /* width */
201 d2 = d;
202 d1 = d3 = 0;
203 break;
204 default: /* no resize */
205 d1 = d2 = d3 = 0;
206 break;
207 }
208 if (i == 0) {
209 frame.origin.x += d1;
210 frame.size.width += d2;
211 ddx = d2;
212 } else {
213 frame.origin.y += (gRubyDialogIsFlipped ? d3 : d1);
214 frame.size.height += d2;
215 ddy = d2;
216 }
217 }
218 if (ddx != 0 || ddy != 0)
219 sResizeSubViews(dval, current, ddx, ddy);
220 [current setFrame:frame];
221 }
222 }
223
224 - (void)windowDidResize:(NSNotification *)notification
225 {
226 NSSize size = [[self window] frame].size;
227 if (mySize.width != 0 && mySize.height != 0 && autoResizeEnabled) {
228 /* Resize the subviews */
229 sResizeSubViews((RubyValue)dval, [[self window] contentView], size.width - mySize.width, size.height - mySize.height);
230 }
231 mySize.width = size.width;
232 mySize.height = size.height;
233 }
234
235 #pragma mark ====== TableView data source protocol ======
236
237 - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
238 {
239 return RubyDialog_GetTableItemCount((RubyValue)dval, (RDItem *)[aTableView enclosingScrollView]);
240 }
241
242 - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
243 {
244 char buf[1024];
245 int column = (int)[[aTableView tableColumns] indexOfObject:aTableColumn];
246 RubyDialog_GetTableItemText((RubyValue)dval, (RDItem *)[aTableView enclosingScrollView], (int)rowIndex, column, buf, sizeof buf);
247 return [NSString stringWithUTF8String:buf];
248 }
249
250 - (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
251 {
252 int column = (int)[[aTableView tableColumns] indexOfObject:aTableColumn];
253 RubyDialog_SetTableItemText((RubyValue)dval, (RDItem *)[aTableView enclosingScrollView], (int)rowIndex, column, [anObject UTF8String]);
254 }
255
256 @end
257
258 #pragma mark ====== Plain C Interface ======
259
260 RubyValue
261 RubyDialogCallback_parentModule(void)
262 {
263 return RubyFalse;
264 }
265
266 RubyDialog *
267 RubyDialogCallback_new(int style)
268 {
269 NSRect rect = NSMakeRect(390, 382, 220, 55);
270 NSWindow *win;
271 int mask = NSTitledWindowMask;
272
273 // Window style
274 if (style & rd_Resizable)
275 mask |= NSResizableWindowMask;
276 if (style & rd_HasCloseBox)
277 mask |= NSClosableWindowMask | NSMiniaturizableWindowMask;
278
279 win = [[NSWindow alloc] initWithContentRect:rect
280 styleMask:mask
281 backing:NSBackingStoreBuffered defer:YES];
282
283 // RubyDialogController *cont = [[RubyDialogController alloc] initWithWindowNibName: @"RubyDialog"];
284
285 RubyDialogController *cont = [[RubyDialogController alloc] initWithWindow:win];
286 cont->style = style;
287
288 {
289 /* Create OK/Cancel buttons */
290 int i;
291 for (i = 0; i < 2; i++) {
292 if (i == 0) {
293 rect = NSMakeRect(125, 13, 80, 28);
294 } else {
295 rect = NSMakeRect(15, 13, 80, 28);
296 }
297 NSButton *bn = [[[NSButton alloc] initWithFrame: rect] autorelease];
298 [bn setButtonType: NSMomentaryPushInButton];
299 [bn setBezelStyle: NSRoundedBezelStyle];
300 [[bn cell] setControlSize: NSSmallControlSize];
301 [bn setTag:i];
302 [bn setTitle: (i == 0 ? @"OK" : @"Cancel")];
303 [bn setAction: @selector(dialogItemAction:)];
304 [bn setTarget: cont];
305 [[win contentView] addSubview:bn];
306 }
307 }
308
309 [cont windowDidLoad];
310 [win autorelease];
311 [[cont window] orderOut: nil];
312 return (RubyDialog *)cont;
313 }
314
315 void
316 RubyDialogCallback_release(RubyDialog *dref)
317 {
318 RubyDialogController *cont = (RubyDialogController *)dref;
319 [cont close];
320 [cont release];
321 }
322
323 void
324 RubyDialogCallback_setRubyObject(RubyDialog *dref, RubyValue val)
325 {
326 [(RubyDialogController *)dref setRubyObject: val];
327 }
328
329 void
330 RubyDialogCallback_setWindowTitle(RubyDialog *dref, const char *title)
331 {
332 [[(RubyDialogController *)dref window] setTitle: [NSString stringWithUTF8String: title]];
333 }
334
335 int
336 RubyDialogCallback_runModal(RubyDialog *dref)
337 {
338 RubyDialogController *cont = (RubyDialogController *)dref;
339 int status;
340 if (cont->style & rd_HasCloseBox)
341 return -1; /* Cannot run */
342 [[cont window] makeKeyAndOrderFront: nil];
343 cont->isModal = YES;
344 status = (int)[NSApp runModalForWindow: [cont window]];
345 cont->isModal = NO;
346 if (status == NSRunStoppedResponse)
347 return 0; /* OK */
348 else return 1; /* Cancel */
349 }
350
351 void
352 RubyDialogCallback_endModal(RubyDialog *dref, int status)
353 {
354 [NSApp stopModalWithCode: (status == 0 ? NSRunStoppedResponse : NSRunAbortedResponse)];
355 }
356
357 int
358 RubyDialogCallback_isModal(RubyDialog *dref)
359 {
360 return ((RubyDialogController *)dref)->isModal;
361 }
362
363 void
364 RubyDialogCallback_destroy(RubyDialog *dref)
365 {
366 [(RubyDialogController *)dref stopIntervalTimer];
367 [(RubyDialogController *)dref close];
368 }
369
370
371 void
372 RubyDialogCallback_close(RubyDialog *dref)
373 {
374 [(RubyDialogController *)dref stopIntervalTimer];
375 [(RubyDialogController *)dref close];
376 }
377
378 void
379 RubyDialogCallback_show(RubyDialog *dref)
380 {
381 if (((RubyDialogController *)dref)->myTimer != NULL)
382 [(RubyDialogController *)dref startIntervalTimer:-1];
383 [[(RubyDialogController *)dref window] makeKeyAndOrderFront:nil];
384 }
385
386 void
387 RubyDialogCallback_hide(RubyDialog *dref)
388 {
389 [(RubyDialogController *)dref stopIntervalTimer];
390 [[(RubyDialogController *)dref window] orderOut:nil];
391 }
392
393 int
394 RubyDialogCallback_isActive(RubyDialog *dref)
395 {
396 return [[(RubyDialogController *)dref window] isVisible];
397 }
398
399 int
400 RubyDialogCallback_startIntervalTimer(RubyDialog *dref, float interval)
401 {
402 return [(RubyDialogController *)dref startIntervalTimer:interval * 1000];
403 }
404
405 void
406 RubyDialogCallback_stopIntervalTimer(RubyDialog *dref)
407 {
408 [(RubyDialogController *)dref stopIntervalTimer];
409 }
410
411 void
412 RubyDialogCallback_enableOnKeyHandler(RubyDialog *dref, int flag)
413 {
414 ((RubyDialogController *)dref)->onKeyHandlerEnabled = (flag != 0);
415 }
416
417 static inline RDRect
418 RDRectFromNSRect(NSRect frame)
419 {
420 RDRect rframe;
421 rframe.origin.x = frame.origin.x;
422 rframe.origin.y = frame.origin.y;
423 rframe.size.width = frame.size.width;
424 rframe.size.height = frame.size.height;
425 return rframe;
426 }
427
428 static inline NSRect
429 NSRectFromRDRect(RDRect rframe)
430 {
431 return NSMakeRect(rframe.origin.x, rframe.origin.y, rframe.size.width, rframe.size.height);
432 }
433
434 static inline RDSize
435 RDSizeFromNSSize(NSSize size)
436 {
437 RDSize rsize;
438 rsize.width = size.width;
439 rsize.height = size.height;
440 return rsize;
441 }
442
443 #if 0
444 static inline NSRect
445 sConvertForViewFromRDRect(RDItem *item, RDRect rframe)
446 {
447 /* Take care of the flipped view */
448 NSRect rect, superrect;
449 NSView *superview = [(NSView *)item superview];
450 if (superview == nil)
451 return NSRectFromRDRect(rframe);
452 superrect = [superview frame];
453 rect.origin.x = rframe.origin.x;
454 rect.size.width = rframe.size.width;
455 rect.origin.y = superrect.size.height - rframe.size.height - rframe.origin.y;
456 rect.size.height = rframe.size.height;
457 return rect;
458 }
459 #endif
460
461 RDSize
462 RubyDialogCallback_windowMinSize(RubyDialog *dref)
463 {
464 return RDSizeFromNSSize([[(RubyDialogController *)dref window] minSize]);
465 }
466
467 void
468 RubyDialogCallback_setWindowMinSize(RubyDialog *dref, RDSize size)
469 {
470 [[(RubyDialogController *)dref window] setMinSize:NSMakeSize(size.width, size.height)];
471 }
472
473 RDSize
474 RubyDialogCallback_windowSize(RubyDialog *dref)
475 {
476 NSSize size = [[[(RubyDialogController *)dref window] contentView] bounds].size;
477 RDSize rsize;
478 rsize.width = size.width;
479 rsize.height = size.height;
480 return rsize;
481 }
482
483 void
484 RubyDialogCallback_setWindowSize(RubyDialog *dref, RDSize size)
485 {
486 NSWindow *win = [(RubyDialogController *)dref window];
487 NSSize nsize;
488 nsize.width = size.width;
489 nsize.height = size.height;
490 [win setContentSize: nsize];
491 [win center];
492 }
493
494 void
495 RubyDialogCallback_setAutoResizeEnabled(RubyDialog *dref, int flag)
496 {
497 ((RubyDialogController *)dref)->autoResizeEnabled = (flag != 0);
498 // NSWindow *win = [(RubyDialogController *)dref window];
499 // [[win contentView] setAutoresizesSubviews:(flag != 0)];
500 }
501
502 int
503 RubyDialogCallback_isAutoResizeEnabled(RubyDialog *dref)
504 {
505 return ((RubyDialogController *)dref)->autoResizeEnabled;
506 // NSWindow *win = [(RubyDialogController *)dref window];
507 // return [[win contentView] autoresizesSubviews];
508 }
509
510 void
511 RubyDialogCallback_createStandardButtons(RubyDialog *dref, const char *oktitle, const char *canceltitle)
512 {
513 RubyDialogController *cont = (RubyDialogController *)dref;
514 id okButton = [cont dialogItemAtIndex: 0];
515 id cancelButton = [cont dialogItemAtIndex: 1];
516 if (oktitle != NULL && oktitle[0] != 0) {
517 [okButton setTitle: [NSString stringWithUTF8String: oktitle]];
518 [[cont window] setDefaultButtonCell:[okButton cell]];
519 } else [okButton setHidden: YES];
520 if (canceltitle != NULL && canceltitle[0] != 0)
521 [cancelButton setTitle: [NSString stringWithUTF8String: canceltitle]];
522 else [cancelButton setHidden: YES];
523 }
524
525 static NSRect
526 OffsetForItemRect(const char *type)
527 {
528 NSRect offset = NSMakeRect(0, 0, 0, 0);
529 if (strcmp(type, "textfield") == 0)
530 offset.size.height = 5;
531 // else if (strcmp(type, "button") == 0) {
532 // offset.size.width = 24;
533 // offset.size.height = 14;
534 // }
535 return offset;
536 }
537
538 RDItem *
539 RubyDialogCallback_createItem(RubyDialog *dref, const char *type, const char *title, RDRect frame)
540 {
541 NSView *view = nil;
542 NSView *itemView = nil; // The textview object is NSScrollView but the content is NSTextView
543 NSRect rect, offset;
544 RubyDialogController *cont = ((RubyDialogController *)dref);
545 NSString *tstr = (title ? [NSString stringWithUTF8String: title] : nil);
546 NSFont *font;
547 font = [NSFont systemFontOfSize: [NSFont smallSystemFontSize]];
548
549 rect = NSRectFromRDRect(frame);
550 if (rect.size.width == 0.0f)
551 rect.size.width = 1.0f;
552 if (rect.size.height == 0.0f)
553 rect.size.height = 1.0f;
554
555 offset = OffsetForItemRect(type);
556
557 if (strcmp(type, "text") == 0 || strcmp(type, "textfield") == 0) {
558 /* Static text or editable text field */
559 NSTextField *tf;
560 BOOL isTextField = (type[4] == 'f');
561 tf = [[[NSTextField alloc] initWithFrame: rect] autorelease];
562 [tf setStringValue: tstr];
563 [tf setFont: font];
564 [tf setDelegate: cont];
565 if (isTextField) {
566 [tf setEditable: YES];
567 [tf setBezeled: YES];
568 [tf setDrawsBackground: YES];
569 [tf setDelegate:cont];
570 } else {
571 [tf setEditable: NO];
572 [tf setBezeled: NO];
573 [tf setBordered: NO];
574 [tf setDrawsBackground: NO];
575 [tf sizeToFit];
576 }
577 view = tf;
578 } else if (strcmp(type, "textview") == 0) {
579 /* Text view */
580 NSScrollView *sv;
581 NSTextView *tv;
582 NSSize contentSize;
583 sv = [[[NSScrollView alloc] initWithFrame: rect] autorelease];
584 [sv setHasVerticalScroller: YES];
585 [sv setHasHorizontalScroller: NO];
586 [sv setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
587 [sv setBorderType: NSBezelBorder];
588 [[sv verticalScroller] setControlSize: NSSmallControlSize];
589 contentSize = [sv contentSize];
590 tv = [[[NSTextView alloc] initWithFrame: NSMakeRect(0, 0, contentSize.width, contentSize.height)] autorelease];
591 [tv setMinSize: NSMakeSize(0.0f, contentSize.height)];
592 [tv setMaxSize: NSMakeSize(FLT_MAX, FLT_MAX)];
593 [tv setVerticallyResizable: YES];
594 [tv setHorizontallyResizable: NO];
595 [tv setAutoresizingMask: NSViewWidthSizable];
596 [[tv textContainer] setContainerSize: NSMakeSize(contentSize.width, FLT_MAX)];
597 [[tv textContainer] setWidthTracksTextView: YES];
598 [[tv textContainer] setHeightTracksTextView: NO];
599 font = [NSFont userFixedPitchFontOfSize: 10.0f];
600 [tv setFont: font];
601 [tv setDelegate: cont];
602 [tv setRichText: NO];
603 [tv setSelectable: YES];
604 [tv setEditable: YES];
605 [sv setDocumentView: tv];
606 view = sv;
607 itemView = tv;
608 } else if (strcmp(type, "view") == 0) {
609 /* Panel */
610 view = [[[NSView alloc] initWithFrame: rect] autorelease];
611 /* Autoresizing is handled in our own way */
612 [view setAutoresizesSubviews:NO];
613 [view setAutoresizingMask:NSViewNotSizable];
614 } else if (strcmp(type, "layout_view") == 0) {
615 /* Panel (for layout only) */
616 view = [[[NSView alloc] initWithFrame: rect] autorelease];
617 /* Autoresizing is handled in our own way */
618 [view setAutoresizesSubviews:NO];
619 [view setAutoresizingMask:NSViewNotSizable];
620 } else if (strcmp(type, "line") == 0) {
621 /* Separator line */
622 NSBox *box;
623 if (rect.size.width > rect.size.height)
624 rect.size.height = 1.0f;
625 else rect.size.width = 1.0f;
626 box = [[[NSBox alloc] initWithFrame: rect] autorelease];
627 [box setBoxType:NSBoxSeparator];
628 view = box;
629 } else if (strcmp(type, "button") == 0) {
630 /* Button */
631 NSButton *bn = [[[NSButton alloc] initWithFrame: rect] autorelease];
632 [bn setButtonType: NSMomentaryPushInButton];
633 [bn setBezelStyle: NSRoundedBezelStyle];
634 [[bn cell] setControlSize: NSSmallControlSize];
635 [bn setFont: font];
636 [bn setTitle: tstr];
637 [bn sizeToFit];
638 view = bn;
639 } else if (strcmp(type, "togglebutton") == 0) {
640 /* Toggle Button */
641 NSButton *bn = [[[NSButton alloc] initWithFrame: rect] autorelease];
642 [bn setButtonType: NSToggleButton];
643 [bn setBezelStyle: NSRegularSquareBezelStyle];
644 [[bn cell] setControlSize: NSSmallControlSize];
645 [bn setFont: font];
646 [bn setTitle: tstr];
647 [bn sizeToFit];
648 view = bn;
649 } else if (strcmp(type, "popup") == 0) {
650 /* Popup button (wxChoice) */
651 NSPopUpButton *pn = [[[NSPopUpButton alloc] initWithFrame: rect] autorelease];
652 [[pn cell] setControlSize: NSSmallControlSize];
653 [pn setFont: font];
654 view = pn;
655 } else if (strcmp(type, "checkbox") == 0) {
656 NSButton *bn = [[[NSButton alloc] initWithFrame: rect] autorelease];
657 [bn setButtonType: NSSwitchButton];
658 [[bn cell] setControlSize: NSSmallControlSize];
659 [bn setFont: font];
660 [bn setTitle: tstr];
661 [bn sizeToFit];
662 view = bn;
663 } else if (strcmp(type, "radio") == 0) {
664 NSButton *bn = [[[NSButton alloc] initWithFrame: rect] autorelease];
665 [bn setButtonType: NSRadioButton];
666 [[bn cell] setControlSize: NSSmallControlSize];
667 [bn setFont: font];
668 [bn setTitle: tstr];
669 [bn sizeToFit];
670 view = bn;
671 } else if (strcmp(type, "table") == 0) {
672 NSTableView *tv;
673 NSScrollView *sv;
674 NSSize contentSize;
675 sv = [[[NSScrollView alloc] initWithFrame: rect] autorelease];
676 [sv setHasVerticalScroller: YES];
677 [sv setHasHorizontalScroller: YES];
678 [sv setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
679 [sv setBorderType: NSBezelBorder];
680 [[sv verticalScroller] setControlSize: NSSmallControlSize];
681 [[sv horizontalScroller] setControlSize: NSSmallControlSize];
682 contentSize = [sv contentSize];
683 tv = [[[NSTableView alloc] initWithFrame: NSMakeRect(0, 0, contentSize.width, contentSize.height)] autorelease];
684 [tv setDataSource:cont];
685 [tv setDelegate:cont];
686 [sv setDocumentView: tv];
687 view = sv;
688 itemView = tv;
689 } else return NULL;
690
691 { /* Resize the frame rect */
692 RDSize minSize = RubyDialogCallback_sizeOfString((RDItem *)view, title);
693 minSize.width += offset.size.width;
694 minSize.height += offset.size.height;
695 rect = [view frame];
696 if (rect.size.height < minSize.height)
697 rect.size.height = minSize.height;
698 if (rect.size.width < minSize.width)
699 rect.size.width = minSize.width;
700 [view setFrame: rect]; /* For flipped coordinate system (like Cocoa), the y-coordinate will need update after being added to the superview */
701 }
702
703 if (strcmp(type, "layout_view") == 0) {
704 /* Layout view: resize the window if it is too small */
705 NSRect contentFrame = [[[cont window] contentView] frame];
706 NSRect crect = rect;
707 id btn1, btn2;
708 BOOL mod = NO;
709 crect.size.width += crect.origin.x * 2;
710 crect.size.height += crect.origin.y * 2;
711 crect.origin.x = crect.origin.y = 0;
712 btn1 = btn2 = nil;
713 if (((btn1 = [cont dialogItemAtIndex:0]) != nil && ![btn1 isHidden]) ||
714 ((btn2 = [cont dialogItemAtIndex:1]) != nil && ![btn2 isHidden])) {
715 // At least one standard button is visible: we need to add area for the buttons
716 NSRect r1, r2;
717 r1 = (btn1 != nil ? [btn1 frame] : NSZeroRect);
718 r2 = (btn2 != nil ? [btn2 frame] : NSZeroRect);
719 r1 = NSUnionRect(r1, r2);
720 crect.size.height += r1.size.height + r1.origin.y;
721 }
722 if (contentFrame.size.width < crect.size.width) {
723 contentFrame.size.width = crect.size.width;
724 mod = YES;
725 }
726 if (contentFrame.size.height < crect.size.height) {
727 contentFrame.size.height = crect.size.height;
728 mod = YES;
729 }
730 if (mod)
731 [[cont window] setContentSize:contentFrame.size];
732 }
733
734 [cont addDialogItem: view];
735 if (itemView == nil)
736 itemView = view;
737
738 if ([itemView respondsToSelector: @selector(setAction:)]) {
739 [(id)itemView setAction: @selector(dialogItemAction:)];
740 [(id)itemView setTarget: cont];
741 }
742
743 if (gRubyDialogIsFlipped) {
744 /* Update the y coordinate */
745 NSRect superRect = [[view superview] frame];
746 rect.origin.y = superRect.size.height - rect.size.height - rect.origin.y;
747 [view setFrame: rect];
748 }
749
750 return (RDItem *)view;
751 }
752
753 RDItem *
754 RubyDialogCallback_dialogItemAtIndex(RubyDialog *dref, int idx)
755 {
756 if (idx == -1)
757 return (RDItem *)[[(RubyDialogController *)dref window] contentView];
758 else return (RDItem *)[(RubyDialogController *)dref dialogItemAtIndex: idx];
759 }
760
761 int
762 RubyDialogCallback_indexOfItem(RubyDialog *dref, RDItem *item)
763 {
764 return [(RubyDialogController *)dref searchDialogItem: (id)item];
765 }
766
767 void
768 RubyDialogCallback_moveItemUnderView(RDItem *item, RDItem *superView, RDPoint origin)
769 {
770 if (item == NULL || superView == NULL || item == superView)
771 return;
772 [(NSView *)item removeFromSuperview];
773 [(NSView *)superView addSubview: (NSView *)item];
774 if (gRubyDialogIsFlipped) {
775 NSRect rect = [(NSView *)item frame];
776 NSRect superRect = [(NSView *)superView frame];
777 origin.y = superRect.size.height - rect.size.height - origin.y;
778 }
779 [(NSView *)item setFrameOrigin: NSMakePoint(origin.x, origin.y)];
780 }
781
782 RDItem *
783 RubyDialogCallback_superview(RDItem *item)
784 {
785 return (RDItem *)[(NSView *)item superview];
786 }
787
788 RDRect
789 RubyDialogCallback_frameOfItem(RDItem *item)
790 {
791 NSRect rect = [(NSView *)item frame];
792 if (gRubyDialogIsFlipped) {
793 NSView *superview = [(NSView *)item superview];
794 if (superview != nil) {
795 NSRect superRect = [superview frame];
796 rect.origin.y = superRect.size.height - rect.size.height - rect.origin.y;
797 }
798 }
799 return RDRectFromNSRect(rect);
800 }
801
802 void
803 RubyDialogCallback_setFrameOfItem(RDItem *item, RDRect rect)
804 {
805 NSRect wrect = NSRectFromRDRect(rect);
806 if (gRubyDialogIsFlipped) {
807 NSView *superview = [(NSView *)item superview];
808 if (superview != NULL) {
809 NSRect srect = [superview frame];
810 wrect.origin.y = srect.size.height - wrect.size.height - wrect.origin.y;
811 }
812 }
813 [(NSView *)item setFrame: wrect];
814 }
815
816 void
817 RubyDialogCallback_setStringToItem(RDItem *item, const char *s)
818 {
819 NSView *view = (NSView *)item;
820 NSString *str = [NSString stringWithUTF8String: s];
821 if ([view isKindOfClass: [NSScrollView class]]) {
822 [[(NSScrollView *)view documentView] setString: str];
823 } else if ([view respondsToSelector: @selector(setStringValue:)]) {
824 [(id)view setStringValue: str];
825 }
826 }
827
828 void
829 RubyDialogCallback_getStringFromItem(RDItem *item, char *buf, int bufsize)
830 {
831 NSView *view = (NSView *)item;
832 NSString *str;
833 if ([view isKindOfClass: [NSScrollView class]]) {
834 str = [[(NSScrollView *)view documentView] string];
835 } else if ([view respondsToSelector: @selector(stringValue)]) {
836 str = [(id)view stringValue];
837 } else {
838 buf[0] = 0;
839 return;
840 }
841 snprintf(buf, bufsize, "%s", [str UTF8String]);
842 }
843
844 char *
845 RubyDialogCallback_getStringPtrFromItem(RDItem *item)
846 {
847 NSView *view = (NSView *)item;
848 NSString *str;
849 if ([view isKindOfClass: [NSScrollView class]]) {
850 str = [[(NSScrollView *)view documentView] string];
851 } else if ([view respondsToSelector: @selector(stringValue)]) {
852 str = [(id)view stringValue];
853 } else return NULL;
854 return strdup([str UTF8String]);
855 }
856
857 char *
858 RubyDialogCallback_titleOfItem(RDItem *item)
859 {
860 NSString *str;
861 NSView *view = (NSView *)item;
862 if ([view isKindOfClass: [NSTextField class]]) {
863 str = [(NSTextField *)view stringValue];
864 } else if ([view respondsToSelector: @selector(title)]) {
865 str = [(id)view title];
866 } else return NULL;
867 return strdup([str UTF8String]);
868 }
869
870 void
871 RubyDialogCallback_setTitleToItem(RDItem *item, const char *s)
872 {
873 NSString *str = [NSString stringWithUTF8String: s];
874 NSView *view = (NSView *)item;
875 if ([view isKindOfClass: [NSTextField class]]) {
876 [(NSTextField *)view setStringValue: str];
877 } else if ([view respondsToSelector: @selector(setTitle:)]) {
878 [(id)view setTitle: str];
879 }
880 }
881
882 void
883 RubyDialogCallback_setEnabledForItem(RDItem *item, int flag)
884 {
885 NSView *view = (NSView *)item;
886 if ([view isKindOfClass: [NSScrollView class]]) {
887 [[(NSScrollView *)view documentView] setEditable: (flag != 0)];
888 } else if ([view respondsToSelector: @selector(setEnabled:)]) {
889 [(id)view setEnabled: (flag != 0)];
890 }
891 }
892
893 int
894 RubyDialogCallback_isItemEnabled(RDItem *item)
895 {
896 NSView *view = (NSView *)item;
897 if ([view isKindOfClass: [NSScrollView class]]) {
898 return [[(NSScrollView *)view documentView] isEditable];
899 } else if ([view respondsToSelector: @selector(isEnabled)]) {
900 return [(id)view isEnabled];
901 } else return 0;
902 }
903
904 void
905 RubyDialogCallback_setHiddenForItem(RDItem *item, int flag)
906 {
907 [(NSView *)item setHidden: (flag != 0)];
908 }
909
910 int
911 RubyDialogCallback_isItemHidden(RDItem *item)
912 {
913 return [(NSView *)item isHidden];
914 }
915
916 void
917 RubyDialogCallback_setFontForItem(RDItem *item, int size, int family, int style, int weight)
918 {
919 NSFont *font;
920 NSFontDescriptor *desc;
921 int mask = 0;
922 NSView *itemView = (NSView *)item;
923 if ([itemView isKindOfClass:[NSScrollView class]])
924 itemView = [(NSScrollView *)itemView documentView];
925 if (![itemView respondsToSelector:@selector(font)])
926 return;
927 font = [(id)itemView font];
928 desc = [font fontDescriptor];
929 if (size != 0)
930 desc = [desc fontDescriptorWithSize:size];
931 if (family == 2)
932 desc = [desc fontDescriptorWithFamily:@"Times"];
933 else if (family == 3)
934 desc = [desc fontDescriptorWithFamily:@"Helvetica"];
935 else if (family == 4)
936 desc = [desc fontDescriptorWithFamily:@"Monaco"];
937 if ((style == 2 || style == 3) && family != 4)
938 mask |= NSItalicFontMask;
939 if (weight == 2 && family != 4)
940 mask |= NSBoldFontMask;
941 if (mask != 0)
942 desc = [desc fontDescriptorWithSymbolicTraits:mask];
943 font = [NSFont fontWithDescriptor:desc size:0]; // Setting size here does not work.
944 [(id)itemView setFont:font];
945 }
946
947 int
948 RubyDialogCallback_getFontForItem(RDItem *item, int *size, int *family, int *style, int *weight)
949 {
950 NSFont *font;
951 NSFontDescriptor *desc;
952 unsigned int symbolicTrait;
953 int fam, sz, st, w;
954 const unsigned int serifs =
955 NSFontOldStyleSerifsClass | NSFontTransitionalSerifsClass | NSFontModernSerifsClass |
956 NSFontClarendonSerifsClass | NSFontSlabSerifsClass | NSFontFreeformSerifsClass;
957 const unsigned int sans_serifs = NSFontSansSerifClass;
958 const unsigned int monospace = NSFontMonoSpaceTrait;
959 NSView *itemView = (NSView *)item;
960 if ([itemView isKindOfClass:[NSScrollView class]])
961 itemView = [(NSScrollView *)itemView documentView];
962
963 if (![itemView respondsToSelector:@selector(font)])
964 return 0;
965 font = [(id)itemView font];
966 desc = [font fontDescriptor];
967 symbolicTrait = [desc symbolicTraits];
968
969 fam = sz = st = w = 0;
970 sz = [font pointSize];
971 if (symbolicTrait & serifs)
972 fam = 2;
973 if (symbolicTrait & sans_serifs)
974 fam = 3;
975 if (symbolicTrait & monospace)
976 fam = 4;
977 if (symbolicTrait & NSFontItalicTrait)
978 st = 3;
979 if (symbolicTrait & NSFontBoldTrait)
980 w = 2;
981 if (family != NULL)
982 *family = fam;
983 if (style != NULL)
984 *style = st;
985 if (size != NULL)
986 *size = sz;
987 if (weight != NULL)
988 *weight = w;
989 return 1;
990 }
991
992 void
993 RubyDialogCallback_setForegroundColorForItem(RDItem *item, const double *col)
994 {
995 NSView *itemView = (NSView *)item;
996 if ([itemView isKindOfClass:[NSScrollView class]])
997 itemView = [(NSScrollView *)itemView documentView];
998 if ([itemView respondsToSelector:@selector(setTextColor:)]) {
999 NSColor *color = [NSColor colorWithDeviceRed:(CGFloat)col[0] green:(CGFloat)col[1] blue:(CGFloat)col[2] alpha:(CGFloat)col[3]];
1000 [(id)itemView setTextColor:color];
1001 }
1002 }
1003
1004 void
1005 RubyDialogCallback_setBackgroundColorForItem(RDItem *item, const double *col)
1006 {
1007 NSView *itemView = (NSView *)item;
1008 if ([itemView isKindOfClass:[NSScrollView class]])
1009 itemView = [(NSScrollView *)itemView documentView];
1010 if ([itemView respondsToSelector:@selector(setBackgroundColor:)]) {
1011 NSColor *color = [NSColor colorWithDeviceRed:(CGFloat)col[0] green:(CGFloat)col[1] blue:(CGFloat)col[2] alpha:(CGFloat)col[3]];
1012 [(id)itemView setBackgroundColor:color];
1013 }
1014 }
1015
1016 void
1017 RubyDialogCallback_getForegroundColorForItem(RDItem *item, double *col)
1018 {
1019 NSView *itemView = (NSView *)item;
1020 if ([itemView isKindOfClass:[NSScrollView class]])
1021 itemView = [(NSScrollView *)itemView documentView];
1022 if ([itemView respondsToSelector:@selector(textColor)]) {
1023 CGFloat rgba[4];
1024 NSColor *color = [(id)item textColor];
1025 [color getRed:rgba green:rgba + 1 blue:rgba + 2 alpha:rgba + 3];
1026 col[0] = rgba[0];
1027 col[1] = rgba[1];
1028 col[2] = rgba[2];
1029 col[3] = rgba[3];
1030 }
1031 }
1032
1033 void
1034 RubyDialogCallback_getBackgroundColorForItem(RDItem *item, double *col)
1035 {
1036 NSView *itemView = (NSView *)item;
1037 if ([itemView isKindOfClass:[NSScrollView class]])
1038 itemView = [(NSScrollView *)itemView documentView];
1039 if ([itemView respondsToSelector:@selector(backgroundColor)]) {
1040 CGFloat rgba[4];
1041 NSColor *color = [(id)item textColor];
1042 [color getRed:rgba green:rgba + 1 blue:rgba + 2 alpha:rgba + 3];
1043 col[0] = rgba[0];
1044 col[1] = rgba[1];
1045 col[2] = rgba[2];
1046 col[3] = rgba[3];
1047 }
1048 }
1049
1050 int
1051 RubyDialogCallback_appendString(RDItem *item, const char *str)
1052 {
1053 NSView *itemView = (NSView *)item;
1054 if ([itemView isKindOfClass:[NSScrollView class]])
1055 itemView = [(NSScrollView *)itemView documentView];
1056 if ([itemView respondsToSelector:@selector(textStorage)]) {
1057 NSTextStorage *st = [(id)itemView textStorage];
1058 [st replaceCharactersInRange:NSMakeRange([st length], 0) withString:[NSString stringWithUTF8String:str]];
1059 return 1;
1060 } else if ([itemView respondsToSelector:@selector(setStringValue:)]) {
1061 NSString *st = [(id)itemView stringValue];
1062 [(id)itemView setStringValue:[st stringByAppendingFormat:@"%s", str]];
1063 return 1;
1064 }
1065 return 0;
1066 }
1067
1068 void
1069 RubyDialogCallback_setEditableForItem(RDItem *item, int flag)
1070 {
1071 RubyDialogCallback_setEnabledForItem(item, flag);
1072 }
1073
1074 int
1075 RubyDialogCallback_isItemEditable(RDItem *item)
1076 {
1077 return RubyDialogCallback_isItemEnabled(item);
1078 }
1079
1080 void
1081 RubyDialogCallback_setStateForItem(RDItem *item, int state)
1082 {
1083 if ([(id)item isKindOfClass:[NSButton class]])
1084 [(NSButton *)item setState:(state ? NSOnState : NSOffState)];
1085 }
1086
1087 int
1088 RubyDialogCallback_getStateForItem(RDItem *item)
1089 {
1090 if ([(id)item isKindOfClass:[NSButton class]])
1091 return [(NSButton *)item state] == NSOnState ? 1 : 0;
1092 else return 0;
1093 }
1094
1095 void
1096 RubyDialogCallback_setNeedsDisplay(RDItem *item, int flag)
1097 {
1098 [(NSView *)item setNeedsDisplay:flag];
1099 }
1100
1101 void
1102 RubyDialogCallback_setNeedsDisplayInRect(RDItem *item, RDRect rect, int eraseBackground)
1103 {
1104 NSRect nrect = NSMakeRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
1105 [(NSView *)item setNeedsDisplayInRect:nrect];
1106 }
1107
1108 int
1109 RubyDialogCallback_countSubItems(RDItem *item)
1110 {
1111 if ([(NSView *)item respondsToSelector: @selector(numberOfItems)]) {
1112 return (int)[(id)item numberOfItems];
1113 } else return 0;
1114 }
1115
1116 int
1117 RubyDialogCallback_appendSubItem(RDItem *item, const char *s)
1118 {
1119 if ([(NSView *)item isKindOfClass: [NSPopUpButton class]]) {
1120 NSMenu *menu = [(NSPopUpButton *)item menu];
1121 id menuItem = [menu addItemWithTitle: [NSString stringWithUTF8String: s] action: nil keyEquivalent: @""];
1122 return (int)[menu indexOfItem: menuItem];
1123 } else return -1;
1124 }
1125
1126 int
1127 RubyDialogCallback_insertSubItem(RDItem *item, const char *s, int pos)
1128 {
1129 if ([(NSView *)item isKindOfClass: [NSPopUpButton class]]) {
1130 NSMenu *menu = [(NSPopUpButton *)item menu];
1131 id menuItem = [menu insertItemWithTitle: [NSString stringWithUTF8String: s] action: nil keyEquivalent: @"" atIndex: pos];
1132 return (int)[menu indexOfItem: menuItem];
1133 } else return -1;
1134 }
1135
1136 int
1137 RubyDialogCallback_deleteSubItem(RDItem *item, int pos)
1138 {
1139 if ([(NSView *)item isKindOfClass: [NSPopUpButton class]]) {
1140 NSPopUpButton *p = (NSPopUpButton *)item;
1141 if (pos >= 0 && pos < [p numberOfItems]) {
1142 [p removeItemAtIndex: pos];
1143 return pos;
1144 }
1145 }
1146 return -1;
1147 }
1148
1149 char *
1150 RubyDialogCallback_titleOfSubItem(RDItem *item, int pos)
1151 {
1152 if ([(NSView *)item isKindOfClass: [NSPopUpButton class]]) {
1153 NSPopUpButton *p = (NSPopUpButton *)item;
1154 if (pos >= 0 && pos < [p numberOfItems]) {
1155 NSString *str = [p itemTitleAtIndex: pos];
1156 return strdup([str UTF8String]);
1157 }
1158 }
1159 return NULL;
1160 }
1161
1162 void
1163 RubyDialogCallback_setSelectedSubItem(RDItem *item, int pos)
1164 {
1165 if ([(NSView *)item isKindOfClass: [NSPopUpButton class]]) {
1166 NSPopUpButton *p = (NSPopUpButton *)item;
1167 if (pos >= 0 && pos < [p numberOfItems]) {
1168 [p selectItemAtIndex: pos];
1169 }
1170 }
1171 }
1172
1173 int
1174 RubyDialogCallback_selectedSubItem(RDItem *item)
1175 {
1176 if ([(NSView *)item isKindOfClass: [NSPopUpButton class]]) {
1177 return (int)[(NSPopUpButton *)item indexOfSelectedItem];
1178 }
1179 return -1;
1180 }
1181
1182 RDSize
1183 RubyDialogCallback_sizeOfString(RDItem *item, const char *s)
1184 {
1185 NSView *itemView = (NSView *)item;
1186 if ([itemView isKindOfClass:[NSScrollView class]])
1187 itemView = [(NSScrollView *)itemView documentView];
1188 if ([itemView respondsToSelector: @selector(font)]) {
1189 NSFont *font = [(id)itemView font];
1190 NSString *str = [NSString stringWithUTF8String: s];
1191 NSDictionary *attr = [NSDictionary dictionaryWithObjectsAndKeys: font, NSFontAttributeName, nil];
1192 NSSize size = [str sizeWithAttributes: attr];
1193 return RDSizeFromNSSize(size);
1194 } else {
1195 RDSize zeroSize = {0, 0};
1196 return zeroSize;
1197 }
1198 }
1199
1200 RDSize
1201 RubyDialogCallback_resizeToBest(RDItem *item)
1202 {
1203 NSSize size;
1204 if ([(NSView *)item respondsToSelector: @selector(sizeToFit)]) {
1205 [(id)item sizeToFit];
1206 }
1207 size = [(NSView *)item frame].size;
1208 return RDSizeFromNSSize(size);
1209 }
1210
1211 char
1212 RubyDialogCallback_deleteTableColumn(RDItem *item, int col)
1213 {
1214 NSView *itemView = (NSView *)item;
1215 if ([itemView isKindOfClass:[NSScrollView class]]) {
1216 itemView = [(NSScrollView *)itemView documentView];
1217 if ([itemView isKindOfClass:[NSTableView class]]) {
1218 id column = [(NSTableView *)itemView tableColumnWithIdentifier:[NSString stringWithFormat:@"%d", col]];
1219 if (column != nil) {
1220 [(NSTableView *)itemView removeTableColumn:column];
1221 return 1;
1222 }
1223 }
1224 }
1225 return 0;
1226 }
1227
1228 char
1229 RubyDialogCallback_insertTableColumn(RDItem *item, int col, const char *heading, int format, int width)
1230 {
1231 NSView *itemView = (NSView *)item;
1232 if ([itemView isKindOfClass:[NSScrollView class]]) {
1233 itemView = [(NSScrollView *)itemView documentView];
1234 if ([itemView isKindOfClass:[NSTableView class]]) {
1235 NSTableColumn *column = [[[NSTableColumn alloc] initWithIdentifier:[NSString stringWithFormat:@"%d", col]] autorelease];
1236 [[column headerCell] setStringValue:[NSString stringWithUTF8String:heading]];
1237 [(NSTableView *)itemView addTableColumn:column];
1238 return 1;
1239 }
1240 }
1241 return 0;
1242 }
1243
1244 int
1245 RubyDialogCallback_countTableColumn(RDItem *item)
1246 {
1247 NSView *itemView = (NSView *)item;
1248 if ([itemView isKindOfClass:[NSScrollView class]]) {
1249 itemView = [(NSScrollView *)itemView documentView];
1250 if ([itemView isKindOfClass:[NSTableView class]]) {
1251 return (int)[(NSTableView *)itemView numberOfColumns];
1252 }
1253 }
1254 return -1;
1255 }
1256
1257 char
1258 RubyDialogCallback_isTableRowSelected(RDItem *item, int row)
1259 {
1260 NSView *itemView = (NSView *)item;
1261 if ([itemView isKindOfClass:[NSScrollView class]]) {
1262 itemView = [(NSScrollView *)itemView documentView];
1263 if ([itemView isKindOfClass:[NSTableView class]]) {
1264 return [(NSTableView *)itemView isRowSelected:row];
1265 }
1266 }
1267 return 0;
1268 }
1269
1270 IntGroup *
1271 RubyDialogCallback_selectedTableRows(RDItem *item)
1272 {
1273 NSView *itemView = (NSView *)item;
1274 if ([itemView isKindOfClass:[NSScrollView class]]) {
1275 itemView = [(NSScrollView *)itemView documentView];
1276 if ([itemView isKindOfClass:[NSTableView class]]) {
1277 NSIndexSet *iset = [(NSTableView *)itemView selectedRowIndexes];
1278 NSUInteger buf[20];
1279 int i, n;
1280 IntGroup *ig = IntGroupNew();
1281 NSRange range = NSMakeRange(0, 10000000);
1282 while ((n = (int)[iset getIndexes:buf maxCount:20 inIndexRange:&range]) > 0) {
1283 for (i = 0; i < n; i++)
1284 IntGroupAdd(ig, (int)buf[i], 1);
1285 }
1286 return ig;
1287 }
1288 }
1289 return NULL;
1290 }
1291
1292 char
1293 RubyDialogCallback_setSelectedTableRows(RDItem *item, struct IntGroup *rg, int extend)
1294 {
1295 NSView *itemView = (NSView *)item;
1296 if ([itemView isKindOfClass:[NSScrollView class]]) {
1297 itemView = [(NSScrollView *)itemView documentView];
1298 if ([itemView isKindOfClass:[NSTableView class]]) {
1299 NSMutableIndexSet *iset = [NSMutableIndexSet indexSet];
1300 int i, n;
1301 for (i = 0; (n = IntGroupGetNthPoint(rg, i)) >= 0; i++)
1302 [iset addIndex: i];
1303 [(NSTableView *)itemView selectRowIndexes:iset byExtendingSelection:extend];
1304 return 1;
1305 }
1306 }
1307 return 0;
1308 }
1309
1310 void
1311 RubyDialogCallback_refreshTable(RDItem *item)
1312 {
1313 NSView *itemView = (NSView *)item;
1314 if ([itemView isKindOfClass:[NSScrollView class]]) {
1315 itemView = [(NSScrollView *)itemView documentView];
1316 if ([itemView isKindOfClass:[NSTableView class]]) {
1317 [(NSTableView *)itemView reloadData];
1318 }
1319 }
1320 }
1321
1322 int
1323 RubyDialogCallback_lastKeyCode(void)
1324 {
1325 NSEvent *currentEvent = [NSApp currentEvent];
1326 if ([currentEvent type] == NSKeyDown)
1327 return [[currentEvent characters] characterAtIndex:0];
1328 else return -1;
1329 }
1330
1331 int
1332 RubyDialogCallback_savePanel(const char *title, const char *dirname, const char *wildcard, char *buf, int bufsize)
1333 {
1334 int result;
1335 NSSavePanel *panel = [NSSavePanel savePanel];
1336 // NSString *dirstr = (dirname != NULL ? [NSString stringWithUTF8String: dirname] : nil);
1337 [panel setTitle: [NSString stringWithUTF8String: title]];
1338 if (dirname != NULL)
1339 [panel setDirectoryURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:dirname]]];
1340 if (buf != NULL)
1341 [panel setNameFieldStringValue:[NSString stringWithUTF8String:buf]];
1342 result = (int)[panel runModal];
1343 if (result == NSFileHandlingPanelOKButton) {
1344 strncpy(buf, [[[panel URL] path] UTF8String], bufsize - 1);
1345 buf[bufsize - 1] = 0;
1346 result = 1;
1347 } else {
1348 buf[0] = 0;
1349 result = 0;
1350 }
1351 [panel close];
1352 return result;
1353 }
1354
1355 int
1356 RubyDialogCallback_openPanel(const char *title, const char *dirname, const char *wildcard, char ***array, int for_directories, int multiple_selection)
1357 {
1358 int result = 0;
1359 NSOpenPanel *panel = [NSOpenPanel openPanel];
1360 // NSString *dirstr = (dirname != NULL ? [NSString stringWithUTF8String: dirname] : nil);
1361 [panel setTitle: [NSString stringWithUTF8String: title]];
1362 if (for_directories) {
1363 [panel setCanChooseFiles: NO];
1364 [panel setCanChooseDirectories: YES];
1365 }
1366 if (dirname != NULL)
1367 [panel setDirectoryURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:dirname]]];
1368 result = (int)[panel runModal];
1369 if (result == NSOKButton) {
1370 NSArray *URLs = [panel URLs];
1371 int n = (int)[URLs count];
1372 int i;
1373 *array = (char **)malloc(sizeof(char *) * n);
1374 for (i = 0; i < n; i++) {
1375 (*array)[i] = strdup([[[URLs objectAtIndex: i] path] UTF8String]);
1376 }
1377 result = n;
1378 } else result = 0;
1379 [panel close];
1380 return result;
1381 }
1382
1383 int
1384 RubyDialogCallback_setSelectionInTextView(RDItem *item, int fromPos, int toPos)
1385 {
1386 NSView *itemView = (NSView *)item;
1387 if ([itemView isKindOfClass:[NSScrollView class]]) {
1388 itemView = [(NSScrollView *)itemView documentView];
1389 } else if ([itemView isKindOfClass:[NSTextField class]]) {
1390 itemView = [(id)itemView currentEditor];
1391 }
1392 if (itemView != nil && [itemView respondsToSelector:@selector(setSelectedRange:)]) {
1393 [(id)itemView setSelectedRange:NSMakeRange(fromPos, toPos - fromPos)];
1394 return 1;
1395 } else return 0;
1396 }
1397
1398 int
1399 RubyDialogCallback_getSelectionInTextView(RDItem *item, int *fromPos, int *toPos)
1400 {
1401 NSView *itemView = (NSView *)item;
1402 if ([itemView isKindOfClass:[NSScrollView class]]) {
1403 itemView = [(NSScrollView *)itemView documentView];
1404 } else if ([itemView isKindOfClass:[NSTextField class]]) {
1405 itemView = [(id)itemView currentEditor];
1406 }
1407 if (itemView != nil && [itemView respondsToSelector:@selector(selectedRanges)]) {
1408 NSRange range = [[[(id)itemView selectedRanges] objectAtIndex:0] rangeValue];
1409 if (fromPos != NULL)
1410 *fromPos = (int)range.location;
1411 if (toPos != NULL)
1412 *toPos = (int)(range.location + range.length);
1413 return 1;
1414 } else {
1415 if (fromPos != NULL)
1416 *fromPos = -1;
1417 if (toPos != NULL)
1418 *toPos = -1;
1419 return 0;
1420 }
1421 }
1422
1423 #pragma mark ====== Plain C Interface (Device Context) ======
1424
1425 RDDeviceContext *
1426 RubyDialogCallback_getDeviceContextForRubyDialog(RubyDialog *dref)
1427 {
1428 RubyDialogController *cont = (RubyDialogController *)dref;
1429 return (RDDeviceContext *)[[[cont window] graphicsContext] graphicsPort];
1430 }
1431
1432 void
1433 RubyDialogCallback_clear(RDDeviceContext *dc)
1434 {
1435 CGContextRef cref = (CGContextRef)dc;
1436 CGRect rect = CGContextGetClipBoundingBox(cref);
1437 CGContextClearRect(cref, rect);
1438 }
1439
1440 void
1441 RubyDialogCallback_drawEllipse(RDDeviceContext *dc, float x, float y, float r1, float r2)
1442 {
1443 CGContextRef cref = (CGContextRef)dc;
1444 CGRect rect = CGRectMake(x - r1, x - r2, r1 * 2, r2 * 2);
1445 CGContextStrokeEllipseInRect(cref, rect);
1446 }
1447
1448 void
1449 RubyDialogCallback_drawLine(RDDeviceContext *dc, int ncoords, float *coords)
1450 {
1451 int i;
1452 CGContextRef cref = (CGContextRef)dc;
1453 CGContextBeginPath(cref);
1454 CGContextMoveToPoint(cref, coords[0], coords[1]);
1455 for (i = 1; i < ncoords; i++) {
1456 CGContextAddLineToPoint(cref, coords[i * 2], coords[i * 2 + 1]);
1457 }
1458 CGContextStrokePath(cref);
1459 }
1460
1461 void
1462 RubyDialogCallback_drawRectangle(RDDeviceContext *dc, float x, float y, float width, float height, float round)
1463 {
1464 CGContextRef cref = (CGContextRef)dc;
1465 if (round * 2 > width)
1466 round = width * 0.5f;
1467 if (round * 2 > height)
1468 round = height * 0.5f;
1469 if (round < 1.0f)
1470 round = 0.0f;
1471 if (round > 0) {
1472 CGContextBeginPath(cref);
1473 CGContextAddArc(cref, x + round, y + round, round, 3.1415927f, 3.1415927f * 1.5f, 0);
1474 CGContextAddArc(cref, x + width - round, y + round, round, 3.1415927f * 1.5f, 3.1415927f * 2.0f, 0);
1475 CGContextAddArc(cref, x + width - round, y + height - round, round, 0, 3.1415927f * 0.5f, 0);
1476 CGContextAddArc(cref, x + round, y + height - round, round, 3.1415927f * 0.5f, 3.1415927f, 0);
1477 CGContextClosePath(cref);
1478 CGContextStrokePath(cref);
1479 } else {
1480 CGRect r = CGRectMake(x, y, width, height);
1481 CGContextStrokeRect(cref, r);
1482 }
1483 }
1484
1485 void
1486 RubyDialogCallback_drawText(RDDeviceContext *dc, const char *s, float x, float y)
1487 {
1488 CGContextRef cref = (CGContextRef)dc;
1489 CGContextShowTextAtPoint(cref, x, y, s, strlen(s));
1490 }
1491
1492 void
1493 RubyDialogCallback_setFont(RDDeviceContext *dc, void **args)
1494 {
1495 int i;
1496 float fontSize = 12;
1497 const char *fontName = NULL;
1498 CGContextRef cref = (CGContextRef)dc;
1499 for (i = 0; args[i] != NULL; i += 2) {
1500 if (strcmp((const char *)args[i], "size") == 0) {
1501 fontSize = *((float *)(args[i + 1]));
1502 } else if (strcmp((const char *)args[i], "style") == 0) {
1503 } else if (strcmp((const char *)args[i], "family") == 0) {
1504 } else if (strcmp((const char *)args[i], "weight") == 0) {
1505 } else if (strcmp((const char *)args[i], "name") == 0) {
1506 fontName = (const char *)args[i + 1];
1507 }
1508 }
1509 if (fontName == NULL)
1510 CGContextSetFontSize(cref, fontSize);
1511 else
1512 CGContextSelectFont(cref, fontName, fontSize, kCGEncodingFontSpecific);
1513 }
1514
1515 void
1516 RubyDialogCallback_setPen(RDDeviceContext *dc, void **args)
1517 {
1518 int i;
1519 float width;
1520 CGContextRef cref = (CGContextRef)dc;
1521 width = 1.0f;
1522 if (args != NULL) {
1523 for (i = 0; args[i] != NULL; i += 2) {
1524 if (strcmp((const char *)args[i], "color") == 0) {
1525 float *fp = (float *)args[i + 1];
1526 CGContextSetRGBStrokeColor(cref, fp[0], fp[1], fp[2], fp[3]);
1527 } else if (strcmp((const char *)args[i], "width") == 0) {
1528 width = *((float *)(args[i + 1]));
1529 CGContextSetLineWidth(cref, width);
1530 } else if (strcmp((const char *)args[i], "style") == 0) {
1531 int style = (int)(args[i + 1]);
1532 CGFloat dash[4];
1533 CGFloat *dashp = dash;
1534 int dashLen;
1535 switch (style) {
1536 case 0: dashp = NULL; dashLen = 0; break;
1537 case 1: CGContextSetRGBStrokeColor(cref, 0, 0, 0, 0); break;
1538 case 2: dash[0] = dash[1] = width; dashLen = 2; break;
1539 case 3: dash[0] = width * 4; dash[1] = width * 2; dashLen = 2; break;
1540 case 4: dash[0] = dash[1] = width * 2; dashLen = 2; break;
1541 case 5: dash[0] = dash[1] = width; dash[2] = dash[3] = width * 4; dashLen = 4; break;
1542 default: dashp = NULL; dashLen = 0; break;
1543 }
1544 if (style != 1)
1545 CGContextSetLineDash(cref, 0, dashp, dashLen);
1546 }
1547 }
1548 }
1549 }
1550
1551 void
1552 RubyDialogCallback_setBrush(RDDeviceContext *dc, void **args)
1553 {
1554 int i;
1555 CGContextRef cref = (CGContextRef)dc;
1556 if (args != NULL) {
1557 for (i = 0; args[i] != NULL; i += 2) {
1558 if (strcmp((const char *)args[i], "color") == 0) {
1559 float *fp = (float *)args[i + 1];
1560 CGContextSetRGBFillColor(cref, fp[0], fp[1], fp[2], fp[3]);
1561 }
1562 }
1563 }
1564 }
1565
1566 #pragma mark ====== Bitmap ======
1567
1568 RDBitmap *
1569 RubyDialogCallback_createBitmap(int width, int height, int depth)
1570 {
1571 CGContextRef bitmap;
1572 void *data = malloc(width * height * (depth / 8));
1573 CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
1574 bitmap = CGBitmapContextCreate(data, width, height, depth / 4, (depth / 8) * width, colorSpace, kCGImageAlphaLast);
1575 CGColorSpaceRelease(colorSpace);
1576 return (RDBitmap *)bitmap;
1577 }
1578
1579 void
1580 RubyDialogCallback_releaseBitmap(RDBitmap *bitmap)
1581 {
1582 if (bitmap != NULL) {
1583 void *data = CGBitmapContextGetData((CGContextRef)bitmap);
1584 free(data);
1585 CGContextRelease((CGContextRef)bitmap);
1586 }
1587 }
1588
1589
1590 /* Set focus on a bitmap and execute the given function */
1591 /* This trick is necessary for platform like wxWidgets where the device context
1592 must be allocated on stack.
1593 It is not necessary for platform like Quartz-OSX where the device context is
1594 allocated in the heap. */
1595 static RDBitmap *s_temp_dc_pointer = NULL;
1596 int
1597 RubyDialogCallback_executeWithFocusOnBitmap(RDBitmap *bitmap, void (*callback)(void *), void *ptr)
1598 {
1599 if (s_temp_dc_pointer != NULL)
1600 return -1; /* Recursive call is not allowed */
1601 s_temp_dc_pointer = bitmap;
1602 (*callback)(ptr);
1603 s_temp_dc_pointer = NULL;
1604 return 0;
1605 }
1606
1607 RDDeviceContext *
1608 RubyDialogCallback_getDeviceContextForBitmap(RDBitmap *bitmap)
1609 {
1610 return (RDDeviceContext *)bitmap;
1611 }
1612
1613 int
1614 RubyDialogCallback_saveBitmapToFile(RDBitmap *bitmap, const char *fname)
1615 {
1616 CGImageRef outImage = CGBitmapContextCreateImage((CGContextRef)bitmap);
1617 CFURLRef outURL = (CFURLRef)[NSURL fileURLWithPath:[NSString stringWithUTF8String:fname]];
1618 int len = (int)strlen(fname);
1619 CFStringRef bitmapType = kUTTypePNG;
1620 int retval = 1;
1621 if (len >= 4) {
1622 if (strcasecmp(fname + len - 4, ".png") == 0)
1623 bitmapType = kUTTypePNG;
1624 else if (strcasecmp(fname + len - 4, ".tif") == 0 || (len >= 5 && strcasecmp(fname + len - 5, ".tiff") == 0))
1625 bitmapType = kUTTypeTIFF;
1626 }
1627 CGImageDestinationRef outDestination = CGImageDestinationCreateWithURL(outURL, kUTTypeJPEG, 1, NULL);
1628 CGImageDestinationAddImage(outDestination, outImage, NULL);
1629 if (!CGImageDestinationFinalize(outDestination))
1630 retval = 0;
1631 CFRelease(outDestination);
1632 CGImageRelease(outImage);
1633 return retval;
1634 }

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