Vuo 2.4.4
Loading...
Searching...
No Matches
VuoEditorWindowToolbar.mm
Go to the documentation of this file.
1
11#include "ui_VuoEditorWindow.h"
12
14#include "VuoEditor.hh"
15#include "VuoEditorWindow.hh"
16#include "VuoErrorDialog.hh"
17#include "VuoCodeWindow.hh"
19
20#if defined(slots)
21#undef slots
22#endif
23
25#include <AppKit/AppKit.h>
26
30@interface VuoEditorZoomButtons : NSSegmentedControl
31{
32 QMacToolBarItem *_toolBarItem;
33 bool _isDark;
34 bool _isCodeEditor;
35}
36@end
37
38@implementation VuoEditorZoomButtons
42- (id)initWithQMacToolBarItem:(QMacToolBarItem *)toolBarItem isCodeEditor:(bool)codeEditor
43{
44 if (!(self = [super init]))
45 return nil;
46
47 _toolBarItem = toolBarItem;
48 _isDark = false;
49 _isCodeEditor = codeEditor;
50
51 self.accessibilityLabel = [NSString stringWithUTF8String:VuoEditor::tr("Zoom").toUtf8().data()];
52
53 NSImage *zoomOutImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"zoom-out" ofType:@"pdf"]];
54 [zoomOutImage setTemplate:YES];
55 NSImage *zoomFitImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"zoom-fit" ofType:@"pdf"]];
56 [zoomFitImage setTemplate:YES];
57 NSImage *zoomActualImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"zoom-actual" ofType:@"pdf"]];
58 [zoomActualImage setTemplate:YES];
59 NSImage *zoomInImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"zoom-in" ofType:@"pdf"]];
60 [zoomInImage setTemplate:YES];
61
62 [self setSegmentCount:4];
63 int segmentCount = 0;
64
65 [self setImage:zoomOutImage forSegment:segmentCount];
66 [self.cell setToolTip:[NSString stringWithUTF8String:VuoEditor::tr("Zoom Out").toUtf8().data()] forSegment:segmentCount];
67 [zoomOutImage release];
68 ++segmentCount;
69
70 [self setImage:zoomActualImage forSegment:segmentCount];
71 [self.cell setToolTip:[NSString stringWithUTF8String:VuoEditor::tr("Actual Size").toUtf8().data()] forSegment:segmentCount];
72 [zoomActualImage release];
73 ++segmentCount;
74
75 if (!codeEditor)
76 {
77 [self setImage:zoomFitImage forSegment:segmentCount];
78 [self.cell setToolTip:[NSString stringWithUTF8String:VuoEditor::tr("Zoom to Fit").toUtf8().data()] forSegment:segmentCount];
79 [zoomFitImage release];
80 ++segmentCount;
81 }
82
83 [self setImage:zoomInImage forSegment:segmentCount];
84 [self.cell setToolTip:[NSString stringWithUTF8String:VuoEditor::tr("Zoom In").toUtf8().data()] forSegment:segmentCount];
85 [zoomInImage release];
86 ++segmentCount;
87
88 [self setSegmentCount:segmentCount];
89
90 [[self cell] setTrackingMode:NSSegmentSwitchTrackingMomentary];
91
92 return self;
93}
94
98- (NSRect)bounds
99{
100 return NSMakeRect(0, 0, [self segmentCount] == 4 ? 149 : 109, 24);
101}
102
106- (NSString *)itemIdentifier
107{
108 if (_isCodeEditor)
109 {
110 VuoCodeWindow *window = static_cast<VuoCodeWindow *>(_toolBarItem->parent()->parent());
111 if ([self isSelectedForSegment:0])
112 window->getZoomOutAction()->trigger();
113 else if ([self isSelectedForSegment:1])
114 window->getZoom11Action()->trigger();
115 else if ([self isSelectedForSegment:2])
116 window->getZoomInAction()->trigger();
117 }
118 else
119 {
120 VuoEditorWindow *window = static_cast<VuoEditorWindow *>(_toolBarItem->parent()->parent());
121 if ([self isSelectedForSegment:0])
122 window->getZoomOutAction()->trigger();
123 else if ([self isSelectedForSegment:1])
124 window->getZoom11Action()->trigger();
125 else if ([self isSelectedForSegment:2])
126 window->getZoomToFitAction()->trigger();
127 else if ([self isSelectedForSegment:3])
128 window->getZoomInAction()->trigger();
129 }
130
131 return QString::number(qulonglong(_toolBarItem)).toNSString();
132}
133
137- (void)drawRect:(NSRect)dirtyRect
138{
139 NSColor *color = [NSColor colorWithCalibratedWhite:0 alpha:(_isDark ? .1 : .06)];
140 [color setStroke];
141 [NSBezierPath setDefaultLineWidth:1];
142 NSRect rect = [self bounds];
143
144 // Draw a line between each icon, with a 2 pixel margin above/below the icon extents.
145 float top = 3;
146 float bottom = NSHeight(rect) - 2;
147 float right = NSWidth(rect);
148 int buttonCount = _isCodeEditor ? 3 : 4;
149 for (int i = 1; i < buttonCount; ++i)
150 [NSBezierPath strokeLineFromPoint:NSMakePoint(round(right * (float)i/buttonCount) - 2.5, top) toPoint:NSMakePoint(round(right * (float)i/buttonCount) - 2.5, bottom)];
151
152 [[self cell] drawInteriorWithFrame:dirtyRect inView:self];
153}
154
158- (void)updateColor:(bool)isDark
159{
160 _isDark = isDark;
161
162 // Disable image-templating in dark mode, since it makes the icons too faint.
163 int segments = self.segmentCount;
164 for (int i = 0; i < segments; ++i)
165 [[self imageForSegment:i] setTemplate:!isDark];
166
167 self.needsDisplay = YES;
168}
169@end
170
171
175@interface VuoEditorEventsButton : NSView
176{
177 QMacToolBarItem *_toolBarItem;
178 NSButton *button;
179 bool _isDark;
180}
181- (id)initWithQMacToolBarItem:(QMacToolBarItem *)toolBarItem;
182- (NSString *)itemIdentifier;
183- (void)setState:(bool)state;
184- (NSButton *)button;
185@end
186
187@implementation VuoEditorEventsButton
191- (id)initWithQMacToolBarItem:(QMacToolBarItem *)toolBarItem
192{
193 if (!(self = [super init]))
194 return nil;
195
196 _toolBarItem = toolBarItem;
197 _isDark = false;
198
199 button = [NSButton new];
200 [button setFrame:NSMakeRect(0,1,32,24)];
201
202 [button setButtonType:NSButtonTypeMomentaryChange];
203 [button setBordered:NO];
204
205 [button setAction:@selector(itemIdentifier)];
206 [button setTarget:self];
207
208 [[button cell] setImageScaling:NSImageScaleNone];
209 [[button cell] setShowsStateBy:NSContentsCellMask];
210
211 button.cell.accessibilityLabel = [NSString stringWithUTF8String:VuoEditor::tr("Show Events").toUtf8().data()];
212
213 // Wrap the button in a fixed-width subview, so the toolbar item doesn't change width when the label changes.
214 [self setFrame:NSMakeRect(0,0,32,24)];
215 [self addSubview:button];
216
217 return self;
218}
219
223- (NSRect)bounds
224{
225 // So the left side of the Zoom widget lines up with the left side of the canvas.
226 double width = 68;
227
228#ifdef VUO_PRO
229 VuoEditorEventsButton_Pro();
230#endif
231
232 NSRect frame = button.frame;
233 frame.origin.x = (width - frame.size.width) / 2.;
234 button.frame = frame;
235
236 return NSMakeRect(0, 0, width, 24);
237}
238
242- (NSString *)itemIdentifier
243{
244 VuoEditorWindow *window = static_cast<VuoEditorWindow *>(_toolBarItem->parent()->parent());
245 window->getShowEventsAction()->trigger();
246
247 return QString::number(qulonglong(_toolBarItem)).toNSString();
248}
249
253- (void)setState:(bool)state
254{
255 [button setState:state];
256
257 NSImage *offImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"showEvents" ofType:@"pdf"]];
258 if (state)
259 {
260 // Manage state manually, since we need to use NSButtonTypeMomentaryChange to prevent the grey background when clicking.
261 NSImage *onImage = [offImage copy];
262 [onImage lockFocus];
263 [[NSColor colorWithCalibratedRed:29./255 green:106./255 blue:229./255 alpha:1] set]; // #1d6ae5
264 NSRectFillUsingOperation(NSMakeRect(0, 0, [onImage size].width, [onImage size].height), NSCompositingOperationSourceAtop);
265 [onImage unlockFocus];
266 [button setImage:onImage];
267 [onImage release];
268 }
269 else
270 {
271 [offImage setTemplate:YES];
272 [button setImage:offImage];
273 }
274
275 [offImage release];
276
277 [self display];
278}
279
283- (NSButton *)button
284{
285 return button;
286}
287
291- (void)drawRect:(NSRect)dirtyRect
292{
293 if (button.state)
294 {
295 NSColor *color = [NSColor colorWithCalibratedWhite:1 alpha:(_isDark ? .2 : 1)];
296 [color setFill];
297
298 NSRect rect = [button frame];
299 rect.origin.y -= 1;
300 rect.size.height -= 1;
301 NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:rect xRadius:5.0 yRadius:5.0];
302 [path fill];
303 }
304
305 [super drawRect:dirtyRect];
306}
307
311- (void)updateColor:(bool)isDark
312{
313 _isDark = isDark;
314 self.needsDisplay = YES;
315}
316@end
317
321VuoEditorWindowToolbar * VuoEditorWindowToolbar::create(QMainWindow *window, bool isCodeEditor)
322{
323 VuoEditorWindowToolbar *toolbar = new VuoEditorWindowToolbar(window, isCodeEditor);
324 toolbar->setUp();
325 return toolbar;
326}
327
331VuoEditorWindowToolbar::VuoEditorWindowToolbar(QMainWindow *window, bool isCodeEditor)
332 : VuoToolbar(window)
333{
334 this->isCodeEditor = isCodeEditor;
335
336 activityIndicatorTimer = NULL;
337
338 running = false;
339 buildInProgress = false;
340 buildPending = false;
341 stopInProgress = false;
342
343#if VUO_PRO
344 VuoEditorWindowToolbar_Pro();
345#endif
346}
347
352{
353 {
354 runImage11 = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"run-1x1" ofType:@"pdf"]];
355 runImage1611 = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"run-16x11" ofType:@"pdf"]];
356 [runImage11 setTemplate:YES];
357 [runImage1611 setTemplate:YES];
358 runImage = runImage11;
359
360 toolbarRunItem = qtToolbar->addItem(QIcon(), VuoEditor::tr("Run"));
361 NSToolbarItem *ti = toolbarRunItem->nativeToolBarItem();
362 [ti setImage:runImage];
363 [ti setAutovalidates:NO];
364 ti.toolTip = [NSString stringWithUTF8String:VuoEditor::tr("Compile and launch this composition.").toUtf8().data()];
365
366 connect(toolbarRunItem, SIGNAL(activated()), window, SLOT(on_runComposition_triggered()));
367 }
368
369
370 {
371 stopImage11 = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"stop-1x1" ofType:@"pdf"]];
372 stopImage1611 = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"stop-16x11" ofType:@"pdf"]];
373 [stopImage11 setTemplate:YES];
374 [stopImage1611 setTemplate:YES];
375 stopImage = stopImage11;
376
377 toolbarStopItem = qtToolbar->addItem(QIcon(), VuoEditor::tr("Stop"));
378 NSToolbarItem *ti = toolbarStopItem->nativeToolBarItem();
379 [ti setImage:stopImage];
380 [ti setAutovalidates:NO];
381 ti.toolTip = [NSString stringWithUTF8String:VuoEditor::tr("Shut down this composition.").toUtf8().data()];
382
383 connect(toolbarStopItem, SIGNAL(activated()), window, SLOT(on_stopComposition_triggered()));
384 }
385
386
387 if (isCodeEditor)
388 {
389 eventsButton = NULL;
390 toolbarEventsItem = NULL;
391 qtToolbar->addSeparator();
392 }
393 else
394 {
395 toolbarEventsItem = qtToolbar->addItem(QIcon(), VuoEditor::tr("Show Events"));
396 NSToolbarItem *ti = toolbarEventsItem->nativeToolBarItem();
397 eventsButton = [[VuoEditorEventsButton alloc] initWithQMacToolBarItem:toolbarEventsItem];
398 [ti setView:eventsButton];
399#pragma clang diagnostic push
400#pragma clang diagnostic ignored "-Wdeprecated-declarations"
401 // `setMinSize:` is deprecated with no apparent replacement.
402 [ti setMinSize:[eventsButton bounds].size];
403#pragma clang diagnostic pop
404 ti.toolTip = [NSString stringWithUTF8String:VuoEditor::tr("Toggle whether the canvas shows event flow by highlighting trigger ports and nodes.").toUtf8().data()];
405 }
406
407
408 {
409 toolbarZoomItem = qtToolbar->addItem(QIcon(), VuoEditor::tr("Zoom"));
410 NSToolbarItem *ti = toolbarZoomItem->nativeToolBarItem();
411 zoomButtons = [[VuoEditorZoomButtons alloc] initWithQMacToolBarItem:toolbarZoomItem isCodeEditor:isCodeEditor];
412 [ti setView:zoomButtons];
413#pragma clang diagnostic push
414#pragma clang diagnostic ignored "-Wdeprecated-declarations"
415 // `setMinSize:` is deprecated with no apparent replacement.
416 [ti setMinSize:[zoomButtons bounds].size];
417#pragma clang diagnostic pop
418 }
419
420
421#if VUO_PRO
422 addToolbarItems_Pro();
423#endif
424}
425
430{
431#if VUO_PRO
432 VuoEditorWindowToolbarDestructor_Pro();
433#endif
434}
435
440{
441 return true;
442}
443
448{
449 return @"Vuo Composition";
450}
451
455void VuoEditorWindowToolbar::update(bool eventsShown, bool zoomedToActualSize, bool zoomedToFit)
456{
457#if VUO_PRO
458 update_Pro();
459#endif
460
461 if (!toolbarRunItem)
462 return;
463
464 NSToolbarItem *runItem = toolbarRunItem->nativeToolBarItem();
465 NSToolbarItem *stopItem = toolbarStopItem->nativeToolBarItem();
466
467 if (stopInProgress)
468 {
469 [runItem setEnabled:!buildPending];
470 [stopItem setEnabled:NO];
471 }
472 else if (buildInProgress)
473 {
474 [runItem setEnabled:NO];
475 [stopItem setEnabled:YES];
476 }
477 else if (running)
478 {
479 [runItem setEnabled:NO];
480 [stopItem setEnabled:YES];
481 }
482 else
483 {
484 [runItem setEnabled:YES];
485 [stopItem setEnabled:NO];
486 }
487
488 if (toolbarEventsItem)
489 {
490 NSToolbarItem *eventsItem = toolbarEventsItem->nativeToolBarItem();
491 [eventsItem setLabel:[NSString stringWithUTF8String:VuoEditor::tr("Show Events").toUtf8().data()]];
492 VuoEditorEventsButton *eventsButton = (VuoEditorEventsButton *)[eventsItem view];
493 [eventsButton setState:eventsShown];
494 }
495
496 // Enable/disable the zoom11 (actual size) segment.
497 [(NSSegmentedControl *)[toolbarZoomItem->nativeToolBarItem() view] setEnabled:!zoomedToActualSize forSegment:1];
498
499 // Enable/disable the "Zoom to Fit" segment.
500 [(NSSegmentedControl *)[toolbarZoomItem->nativeToolBarItem() view] setEnabled:!zoomedToFit forSegment:2];
501
502 updateActivityIndicators();
503}
504
510{
511 buildPending = true;
512}
513
518{
519 buildPending = false;
520 buildInProgress = true;
521}
522
527{
528 buildInProgress = false;
529 running = true;
530}
531
536{
537 stopInProgress = true;
538}
539
544{
545 buildInProgress = false;
546 running = false;
547 stopInProgress = false;
548}
549
554{
555 return buildPending;
556}
557
562{
563 return buildInProgress;
564}
565
570{
571 return running;
572}
573
578{
579 return stopInProgress;
580}
581
587{
588 return [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay;
589}
590
594void VuoEditorWindowToolbar::updateActivityIndicators(void)
595{
596 if (buildInProgress || stopInProgress)
597 {
598 if (! activityIndicatorTimer)
599 {
600 activityIndicatorFrame = 0;
601
602 activityIndicatorTimer = new QTimer(this);
603 activityIndicatorTimer->setObjectName("VuoEditorWindowToolbar::activityIndicatorTimer");
604 connect(activityIndicatorTimer, SIGNAL(timeout()), this, SLOT(updateActivityIndicators()));
605 activityIndicatorTimer->start(250);
606 }
607 }
608 else
609 {
610 if (activityIndicatorTimer)
611 {
612 activityIndicatorTimer->stop();
613 delete activityIndicatorTimer;
614 activityIndicatorTimer = NULL;
615 }
616 }
617
618 if (buildInProgress)
619 {
620 VuoActivityIndicator *iconEngine = new VuoActivityIndicator(activityIndicatorFrame++);
621 toolbarRunItem->setIcon(QIcon(iconEngine));
622 }
623 else
624 [(NSToolbarItem *)toolbarRunItem->nativeToolBarItem() setImage:runImage];
625
626 if (stopInProgress)
627 {
628 VuoActivityIndicator *iconEngine = new VuoActivityIndicator(activityIndicatorFrame++);
629 toolbarStopItem->setIcon(QIcon(iconEngine));
630 }
631 else
632 [(NSToolbarItem *)toolbarStopItem->nativeToolBarItem() setImage:stopImage];
633}
634
639{
641
642 [(VuoEditorEventsButton *)eventsButton updateColor:isDark];
643 [(VuoEditorEventsButton *)zoomButtons updateColor:isDark];
644}