blob: 8cc9f224dff8cec0824c2c034e23d56454ab07f9 [file] [log] [blame]
Alexandre Lisionc5148052015-03-04 15:10:35 -05001/*
Alexandre Lision9fe374b2016-01-06 10:17:31 -05002 * Copyright (C) 2015-2016 Savoir-faire Linux Inc.
Alexandre Lisionc5148052015-03-04 15:10:35 -05003 * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Alexandre Lisionc5148052015-03-04 15:10:35 -050018 */
19#import "CurrentCallVC.h"
20
21#import <QuartzCore/QuartzCore.h>
22
Alexandre Lision210fe212016-01-27 11:15:13 -050023///Qt
24#import <QMimeData>
25#import <QtMacExtras/qmacfunctions.h>
26#import <QtCore/qabstractitemmodel.h>
27#import <QItemSelectionModel>
28#import <QItemSelection>
29#import <QPixmap>
30
31///LRC
Alexandre Lisionc5148052015-03-04 15:10:35 -050032#import <call.h>
33#import <callmodel.h>
Alexandre Lision89edc6a2015-11-09 11:30:47 -050034#import <recentmodel.h>
Alexandre Lisionc5148052015-03-04 15:10:35 -050035#import <useractionmodel.h>
36#import <contactmethod.h>
Alexandre Lisionc5148052015-03-04 15:10:35 -050037#import <video/previewmanager.h>
38#import <video/renderer.h>
Alexandre Lision58cab672015-06-09 15:25:40 -040039#import <media/text.h>
Alexandre Lision2db8f472015-07-22 15:05:46 -040040#import <person.h>
Alexandre Lision210fe212016-01-27 11:15:13 -050041#import <globalinstances.h>
Alexandre Lisionc5148052015-03-04 15:10:35 -050042
Alexandre Lisionf47a2562015-06-15 15:48:29 -040043#import "views/ITProgressIndicator.h"
Alexandre Lision74dd47f2015-04-14 13:47:42 -040044#import "views/CallView.h"
Alexandre Lision210fe212016-01-27 11:15:13 -050045#import "delegates/ImageManipulationDelegate.h"
Alexandre Lision2db8f472015-07-22 15:05:46 -040046#import "PersonLinkerVC.h"
Alexandre Lision16d9c0a2015-08-10 12:05:15 -040047#import "ChatVC.h"
Alexandre Lision883719f2015-10-22 17:37:45 -040048#import "BrokerVC.h"
Alexandre Lision4baba4c2016-02-11 13:00:57 -050049#import "views/IconButton.h"
Alexandre Lision74dd47f2015-04-14 13:47:42 -040050
Alexandre Lisionc5148052015-03-04 15:10:35 -050051@interface RendererConnectionsHolder : NSObject
52
53@property QMetaObject::Connection frameUpdated;
54@property QMetaObject::Connection started;
55@property QMetaObject::Connection stopped;
56
57@end
58
59@implementation RendererConnectionsHolder
60
61@end
62
Alexandre Lision2db8f472015-07-22 15:05:46 -040063@interface CurrentCallVC () <NSPopoverDelegate, ContactLinkedDelegate>
Alexandre Lisionc5148052015-03-04 15:10:35 -050064
Alexandre Lision210fe212016-01-27 11:15:13 -050065// Main container
66@property (unsafe_unretained) IBOutlet NSSplitView* splitView;
67
Alexandre Lision89edc6a2015-11-09 11:30:47 -050068// Header info
69@property (unsafe_unretained) IBOutlet NSView* headerContainer;
Alexandre Lision883719f2015-10-22 17:37:45 -040070@property (unsafe_unretained) IBOutlet NSTextField* personLabel;
71@property (unsafe_unretained) IBOutlet NSTextField* stateLabel;
Alexandre Lision89edc6a2015-11-09 11:30:47 -050072@property (unsafe_unretained) IBOutlet NSTextField* timeSpentLabel;
Alexandre Lision210fe212016-01-27 11:15:13 -050073@property (unsafe_unretained) IBOutlet NSImageView* personPhoto;
Alexandre Lision89edc6a2015-11-09 11:30:47 -050074
75// Call Controls
76@property (unsafe_unretained) IBOutlet NSView* controlsPanel;
Alexandre Lision4baba4c2016-02-11 13:00:57 -050077@property QHash<int, IconButton*> actionHash;
78@property (unsafe_unretained) IBOutlet IconButton* holdOnOffButton;
79@property (unsafe_unretained) IBOutlet IconButton* hangUpButton;
80@property (unsafe_unretained) IBOutlet IconButton* recordOnOffButton;
81@property (unsafe_unretained) IBOutlet IconButton* pickUpButton;
82@property (unsafe_unretained) IBOutlet IconButton* muteAudioButton;
83@property (unsafe_unretained) IBOutlet IconButton* muteVideoButton;
84@property (unsafe_unretained) IBOutlet IconButton* addContactButton;
85@property (unsafe_unretained) IBOutlet IconButton* transferButton;
86@property (unsafe_unretained) IBOutlet IconButton* addParticipantButton;
87@property (unsafe_unretained) IBOutlet IconButton* chatButton;
Alexandre Lisiond18fa272015-06-15 11:18:03 -040088
89
Alexandre Lision89edc6a2015-11-09 11:30:47 -050090// Join call panel
91@property (unsafe_unretained) IBOutlet NSView* joinPanel;
92@property (unsafe_unretained) IBOutlet NSButton* mergeCallsButton;
93
Alexandre Lision2db8f472015-07-22 15:05:46 -040094@property (strong) NSPopover* addToContactPopover;
Alexandre Lision89edc6a2015-11-09 11:30:47 -050095@property (strong) NSPopover* brokerPopoverVC;
Alexandre Lision883719f2015-10-22 17:37:45 -040096@property (strong) IBOutlet ChatVC* chatVC;
Alexandre Lisionf23ec5a2015-07-16 11:24:06 -040097
Alexandre Lision210fe212016-01-27 11:15:13 -050098// Ringing call panel
99@property (unsafe_unretained) IBOutlet NSView* ringingPanel;
100@property (unsafe_unretained) IBOutlet NSImageView* incomingPersonPhoto;
101@property (unsafe_unretained) IBOutlet NSTextField* incomingDisplayName;
102
103// Outgoing call panel
104@property (unsafe_unretained) IBOutlet NSView* outgoingPanel;
105@property (unsafe_unretained) IBOutlet ITProgressIndicator *loadingIndicator;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500106
107// Video
Alexandre Lision58cab672015-06-09 15:25:40 -0400108@property (unsafe_unretained) IBOutlet CallView *videoView;
Alexandre Lision58cab672015-06-09 15:25:40 -0400109@property (unsafe_unretained) IBOutlet NSView *previewView;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500110
111@property RendererConnectionsHolder* previewHolder;
112@property RendererConnectionsHolder* videoHolder;
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400113@property QMetaObject::Connection videoStarted;
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500114@property QMetaObject::Connection selectedCallChanged;
Alexandre Lisionb65c0272015-07-22 15:51:29 -0400115@property QMetaObject::Connection messageConnection;
116@property QMetaObject::Connection mediaAddedConnection;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500117
118@end
119
120@implementation CurrentCallVC
Alexandre Lision210fe212016-01-27 11:15:13 -0500121@synthesize personLabel, personPhoto, actionHash, stateLabel, holdOnOffButton, hangUpButton,
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500122 recordOnOffButton, pickUpButton, chatButton, transferButton, addParticipantButton, timeSpentLabel,
Alexandre Lision210fe212016-01-27 11:15:13 -0500123 muteVideoButton, muteAudioButton, controlsPanel, headerContainer, videoView, incomingDisplayName, incomingPersonPhoto,
124 previewView, splitView, loadingIndicator, ringingPanel, joinPanel, outgoingPanel;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500125
126@synthesize previewHolder;
127@synthesize videoHolder;
128
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400129- (void) updateAllActions
Alexandre Lisionc5148052015-03-04 15:10:35 -0500130{
Alexandre Lisionf7e11142015-12-15 10:58:11 -0500131 for (int i = 0 ; i < CallModel::instance().userActionModel()->rowCount() ; i++) {
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400132 [self updateActionAtIndex:i];
133 }
134}
135
136- (void) updateActionAtIndex:(int) row
137{
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400138 const QModelIndex& idx = CallModel::instance().userActionModel()->index(row,0);
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400139 UserActionModel::Action action = qvariant_cast<UserActionModel::Action>(idx.data(UserActionModel::Role::ACTION));
Alexandre Lision4baba4c2016-02-11 13:00:57 -0500140 if (auto a = actionHash[(int) action]) {
Alexandre Lision266fca02015-09-28 14:47:05 -0400141 [a setHidden:!(idx.flags() & Qt::ItemIsEnabled)];
Alexandre Lision4baba4c2016-02-11 13:00:57 -0500142 [a setPressed:(idx.data(Qt::CheckStateRole) == Qt::Checked) ? YES : NO];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500143 }
144}
145
Alexandre Lision210fe212016-01-27 11:15:13 -0500146-(void) updateCall:(BOOL) firstRun
Alexandre Lisionc5148052015-03-04 15:10:35 -0500147{
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400148 QModelIndex callIdx = CallModel::instance().selectionModel()->currentIndex();
Alexandre Lision2db8f472015-07-22 15:05:46 -0400149 if (!callIdx.isValid()) {
150 return;
151 }
Alexandre Lision210fe212016-01-27 11:15:13 -0500152 auto current = CallModel::instance().selectedCall();
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500153
Alexandre Lision58cab672015-06-09 15:25:40 -0400154 [personLabel setStringValue:callIdx.data(Qt::DisplayRole).toString().toNSString()];
155 [timeSpentLabel setStringValue:callIdx.data((int)Call::Role::Length).toString().toNSString()];
Alexandre Lision57227772016-01-15 17:19:36 -0500156 [stateLabel setStringValue:callIdx.data((int)Call::Role::HumanStateName).toString().toNSString()];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500157
Alexandre Lision210fe212016-01-27 11:15:13 -0500158 if (firstRun) {
Alexandre Lision261f1b92016-04-04 12:35:34 -0400159 QVariant photo = GlobalInstances::pixmapManipulator().callPhoto(current, QSize(100,100));
Alexandre Lision210fe212016-01-27 11:15:13 -0500160 [personPhoto setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
161 }
162
Alexandre Lision2db8f472015-07-22 15:05:46 -0400163 auto contactmethod = qvariant_cast<Call*>(callIdx.data(static_cast<int>(Call::Role::Object)))->peerContactMethod();
164 BOOL shouldShow = (!contactmethod->contact() || contactmethod->contact()->isPlaceHolder());
165 [self.addContactButton setHidden:!shouldShow];
166
Alexandre Lision266fca02015-09-28 14:47:05 -0400167 // Default values for this views
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400168 [loadingIndicator setHidden:YES];
Alexandre Lision266fca02015-09-28 14:47:05 -0400169 [videoView setShouldAcceptInteractions:NO];
Alexandre Lision210fe212016-01-27 11:15:13 -0500170 [ringingPanel setHidden:YES];
171 [outgoingPanel setHidden:YES];
172 [controlsPanel setHidden:NO];
173 [headerContainer setHidden:NO];
Alexandre Lision266fca02015-09-28 14:47:05 -0400174
Alexandre Lision210fe212016-01-27 11:15:13 -0500175 auto state = callIdx.data((int)Call::Role::State).value<Call::State>();
Alexandre Lisionc5148052015-03-04 15:10:35 -0500176 switch (state) {
Alexandre Lisione6dbf092015-04-11 17:19:35 -0400177 case Call::State::NEW:
Alexandre Lisione6dbf092015-04-11 17:19:35 -0400178 break;
Alexandre Lision22d615b2016-01-25 12:54:34 -0500179 case Call::State::DIALING:
Alexandre Lisionc5148052015-03-04 15:10:35 -0500180 case Call::State::INITIALIZATION:
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400181 case Call::State::CONNECTED:
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400182 [loadingIndicator setHidden:NO];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500183 case Call::State::RINGING:
Alexandre Lision210fe212016-01-27 11:15:13 -0500184 [controlsPanel setHidden:YES];
185 [outgoingPanel setHidden:NO];
186 break;
187 case Call::State::INCOMING:
188 [self setupIncoming:current];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500189 break;
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500190 case Call::State::CONFERENCE:
Alexandre Lision210fe212016-01-27 11:15:13 -0500191 [self setupConference:current];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500192 break;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500193 case Call::State::CURRENT:
Alexandre Lision210fe212016-01-27 11:15:13 -0500194 [self setupCurrent:current];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500195 break;
196 case Call::State::HOLD:
Alexandre Lisionc5148052015-03-04 15:10:35 -0500197 break;
198 case Call::State::BUSY:
Alexandre Lisionc5148052015-03-04 15:10:35 -0500199 break;
200 case Call::State::OVER:
Alexandre Lision266fca02015-09-28 14:47:05 -0400201 case Call::State::FAILURE:
Alexandre Lision210fe212016-01-27 11:15:13 -0500202 [controlsPanel setHidden:YES];
203 [outgoingPanel setHidden:NO];
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400204 if(self.splitView.isInFullScreenMode)
205 [self.splitView exitFullScreenModeWithOptions:nil];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500206 break;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500207 }
208
209}
210
Alexandre Lision210fe212016-01-27 11:15:13 -0500211-(void) setupIncoming:(Call*) c
212{
213 [ringingPanel setHidden:NO];
214 [controlsPanel setHidden:YES];
215 [headerContainer setHidden:YES];
216 QVariant photo = GlobalInstances::pixmapManipulator().callPhoto(c, QSize(100,100));
217 [incomingPersonPhoto setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
218 [incomingDisplayName setStringValue:c->formattedName().toNSString()];
219}
220
221-(void) setupCurrent:(Call*) c
222{
223 [joinPanel setHidden:!c->hasParentCall()];
224 [controlsPanel setHidden:c->hasParentCall()];
225 [videoView setShouldAcceptInteractions:YES];
226 [self.chatButton setHidden:NO];
227 [self.addParticipantButton setHidden:NO];
228 [self.transferButton setHidden:NO];
229}
230
231-(void) setupConference:(Call*) c
232{
233 [videoView setShouldAcceptInteractions:YES];
234 [self.chatButton setHidden:NO];
235 [joinPanel setHidden:YES];
236 [self.addParticipantButton setHidden:NO];
237 [self.transferButton setHidden:YES];
238}
239
240
Alexandre Lisionc5148052015-03-04 15:10:35 -0500241- (void)awakeFromNib
242{
243 NSLog(@"INIT CurrentCall VC");
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400244 [self.view setWantsLayer:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500245
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400246 actionHash[ (int)UserActionModel::Action::ACCEPT] = pickUpButton;
247 actionHash[ (int)UserActionModel::Action::HOLD ] = holdOnOffButton;
248 actionHash[ (int)UserActionModel::Action::RECORD] = recordOnOffButton;
249 actionHash[ (int)UserActionModel::Action::HANGUP] = hangUpButton;
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400250 actionHash[ (int)UserActionModel::Action::MUTE_AUDIO] = muteAudioButton;
251 actionHash[ (int)UserActionModel::Action::MUTE_VIDEO] = muteVideoButton;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500252
Alexandre Lisionc5148052015-03-04 15:10:35 -0500253 [videoView setWantsLayer:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500254 [videoView.layer setBackgroundColor:[NSColor blackColor].CGColor];
255 [videoView.layer setFrame:videoView.frame];
256 [videoView.layer setContentsGravity:kCAGravityResizeAspect];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500257
Alexandre Lisionc5148052015-03-04 15:10:35 -0500258 [previewView setWantsLayer:YES];
Alexandre Lision22d615b2016-01-25 12:54:34 -0500259 [previewView.layer setBackgroundColor:[NSColor blackColor].CGColor];
260 [previewView.layer setContentsGravity:kCAGravityResizeAspectFill];
261 [previewView.layer setFrame:previewView.frame];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500262
263 [controlsPanel setWantsLayer:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500264 [controlsPanel.layer setBackgroundColor:[NSColor clearColor].CGColor];
265 [controlsPanel.layer setFrame:controlsPanel.frame];
266
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400267 previewHolder = [[RendererConnectionsHolder alloc] init];
268 videoHolder = [[RendererConnectionsHolder alloc] init];
269
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400270 [loadingIndicator setColor:[NSColor whiteColor]];
271 [loadingIndicator setNumberOfLines:100];
272 [loadingIndicator setWidthOfLine:2];
273 [loadingIndicator setLengthOfLine:2];
274 [loadingIndicator setInnerMargin:30];
275
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400276 [self.videoView setCallDelegate:self];
Alexandre Lision58cab672015-06-09 15:25:40 -0400277
Alexandre Lisionc5148052015-03-04 15:10:35 -0500278 [self connect];
279}
280
281- (void) connect
282{
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500283 QObject::connect(RecentModel::instance().selectionModel(),
Alexandre Lisionc5148052015-03-04 15:10:35 -0500284 &QItemSelectionModel::currentChanged,
285 [=](const QModelIndex &current, const QModelIndex &previous) {
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500286 auto call = RecentModel::instance().getActiveCall(current);
287 if(!current.isValid() || !call) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500288 return;
289 }
Alexandre Lisionbb5dbcd2015-07-09 16:36:47 -0400290
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500291 [self changeCallSelection:call];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500292
Alexandre Lisionbb5dbcd2015-07-09 16:36:47 -0400293 if (call->state() == Call::State::HOLD) {
294 call << Call::Action::HOLD;
295 }
296
Alexandre Lision58cab672015-06-09 15:25:40 -0400297 [self collapseRightView];
Alexandre Lision210fe212016-01-27 11:15:13 -0500298 [self updateCall:YES];
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400299 [self updateAllActions];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500300 });
301
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400302 QObject::connect(CallModel::instance().userActionModel(),
Alexandre Lisionc5148052015-03-04 15:10:35 -0500303 &QAbstractItemModel::dataChanged,
304 [=](const QModelIndex &topLeft, const QModelIndex &bottomRight) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500305 const int first(topLeft.row()),last(bottomRight.row());
306 for(int i = first; i <= last;i++) {
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400307 [self updateActionAtIndex:i];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500308 }
309 });
310
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400311 QObject::connect(&CallModel::instance(),
Alexandre Lisionc5148052015-03-04 15:10:35 -0500312 &CallModel::callStateChanged,
313 [self](Call* c, Call::State state) {
Alexandre Lision57227772016-01-15 17:19:36 -0500314 auto current = CallModel::instance().selectionModel()->currentIndex();
315 if (!current.isValid())
316 [self animateOut];
317 else if (CallModel::instance().getIndex(c) == current) {
318 if (c->state() == Call::State::OVER) {
Alexandre Lision01cf5e32016-01-21 15:54:30 -0500319 RecentModel::instance().selectionModel()->clearCurrentIndex();
Alexandre Lision57227772016-01-15 17:19:36 -0500320 } else {
Alexandre Lision210fe212016-01-27 11:15:13 -0500321 [self updateCall:NO];
Alexandre Lision57227772016-01-15 17:19:36 -0500322 }
323 }
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500324 });
325
326 QObject::connect(&CallModel::instance(),
327 &CallModel::incomingCall,
328 [self](Call* c) {
329 [self changeCallSelection:c];
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500330 });
331}
332
333- (void) changeCallSelection:(Call* )c
334{
335 QObject::disconnect(self.selectedCallChanged);
336 CallModel::instance().selectCall(c);
337 self.selectedCallChanged = QObject::connect(CallModel::instance().selectedCall(),
338 &Call::changed,
339 [=]() {
Alexandre Lision210fe212016-01-27 11:15:13 -0500340 [self updateCall:NO];
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500341 });
Alexandre Lisionc5148052015-03-04 15:10:35 -0500342}
343
Alexandre Lisionb65c0272015-07-22 15:51:29 -0400344- (void) monitorIncomingTextMessages:(Media::Text*) media
345{
346 /* connect to incoming chat messages to open the chat view */
347 QObject::disconnect(self.messageConnection);
348 self.messageConnection = QObject::connect(media,
349 &Media::Text::messageReceived,
350 [self] (const QMap<QString,QString>& m) {
351 if([[self splitView] isSubviewCollapsed:[[[self splitView] subviews] objectAtIndex: 1]])
352 [self uncollapseRightView];
353 });
354}
355
Alexandre Lisionc5148052015-03-04 15:10:35 -0500356-(void) connectVideoSignals
357{
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400358 QModelIndex idx = CallModel::instance().selectionModel()->currentIndex();
359 Call* call = CallModel::instance().getCall(idx);
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500360 QObject::disconnect(self.videoStarted);
Alexandre Lision58cab672015-06-09 15:25:40 -0400361 self.videoStarted = QObject::connect(call,
Alexandre Lisionc5148052015-03-04 15:10:35 -0500362 &Call::videoStarted,
363 [=](Video::Renderer* renderer) {
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400364 NSLog(@"Video started!");
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400365 [self connectVideoRenderer:renderer];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500366 });
367
368 if(call->videoRenderer())
369 {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500370 [self connectVideoRenderer:call->videoRenderer()];
371 }
372
373 [self connectPreviewRenderer];
374
375}
376
377-(void) connectPreviewRenderer
378{
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400379 QObject::disconnect(previewHolder.frameUpdated);
380 QObject::disconnect(previewHolder.stopped);
381 QObject::disconnect(previewHolder.started);
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400382 previewHolder.started = QObject::connect(&Video::PreviewManager::instance(),
Alexandre Lisionc5148052015-03-04 15:10:35 -0500383 &Video::PreviewManager::previewStarted,
384 [=](Video::Renderer* renderer) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500385 QObject::disconnect(previewHolder.frameUpdated);
386 previewHolder.frameUpdated = QObject::connect(renderer,
387 &Video::Renderer::frameUpdated,
388 [=]() {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400389 [self renderer:Video::PreviewManager::instance().previewRenderer()
Alexandre Lisionc5148052015-03-04 15:10:35 -0500390 renderFrameForView:previewView];
391 });
392 });
393
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400394 previewHolder.stopped = QObject::connect(&Video::PreviewManager::instance(),
Alexandre Lisionc5148052015-03-04 15:10:35 -0500395 &Video::PreviewManager::previewStopped,
396 [=](Video::Renderer* renderer) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500397 QObject::disconnect(previewHolder.frameUpdated);
398 [previewView.layer setContents:nil];
399 });
400
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400401 previewHolder.frameUpdated = QObject::connect(Video::PreviewManager::instance().previewRenderer(),
Alexandre Lisionc5148052015-03-04 15:10:35 -0500402 &Video::Renderer::frameUpdated,
403 [=]() {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400404 [self renderer:Video::PreviewManager::instance().previewRenderer()
Alexandre Lisionc5148052015-03-04 15:10:35 -0500405 renderFrameForView:previewView];
406 });
407}
408
409-(void) connectVideoRenderer: (Video::Renderer*)renderer
410{
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400411 QObject::disconnect(videoHolder.frameUpdated);
412 QObject::disconnect(videoHolder.started);
413 QObject::disconnect(videoHolder.stopped);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500414 videoHolder.frameUpdated = QObject::connect(renderer,
415 &Video::Renderer::frameUpdated,
416 [=]() {
417 [self renderer:renderer renderFrameForView:videoView];
418 });
419
420 videoHolder.started = QObject::connect(renderer,
421 &Video::Renderer::started,
422 [=]() {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500423 QObject::disconnect(videoHolder.frameUpdated);
424 videoHolder.frameUpdated = QObject::connect(renderer,
425 &Video::Renderer::frameUpdated,
426 [=]() {
427 [self renderer:renderer renderFrameForView:videoView];
428 });
429 });
430
431 videoHolder.stopped = QObject::connect(renderer,
432 &Video::Renderer::stopped,
433 [=]() {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500434 QObject::disconnect(videoHolder.frameUpdated);
435 [videoView.layer setContents:nil];
436 });
437}
438
439-(void) renderer: (Video::Renderer*)renderer renderFrameForView:(NSView*) view
440{
Alexandre Lisionc5148052015-03-04 15:10:35 -0500441 QSize res = renderer->size();
442
Alexandre Lision6731e132015-10-14 14:29:06 -0400443 auto frame_ptr = renderer->currentFrame();
444 auto frame_data = frame_ptr.ptr;
445 if (!frame_data)
446 return;
447
Alexandre Lisionc5148052015-03-04 15:10:35 -0500448
449 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
Alexandre Lision6731e132015-10-14 14:29:06 -0400450 CGContextRef newContext = CGBitmapContextCreate(frame_data,
Alexandre Lisionc5148052015-03-04 15:10:35 -0500451 res.width(),
452 res.height(),
453 8,
454 4*res.width(),
455 colorSpace,
456 kCGImageAlphaPremultipliedLast);
457
458
459 CGImageRef newImage = CGBitmapContextCreateImage(newContext);
460
461 /*We release some components*/
462 CGContextRelease(newContext);
463 CGColorSpaceRelease(colorSpace);
464
465 [CATransaction begin];
466 view.layer.contents = (__bridge id)newImage;
467 [CATransaction commit];
468
469 CFRelease(newImage);
470}
471
472- (void) initFrame
473{
474 [self.view setFrame:self.view.superview.bounds];
475 [self.view setHidden:YES];
476 self.view.layer.position = self.view.frame.origin;
Alexandre Lisionbb5dbcd2015-07-09 16:36:47 -0400477 [self collapseRightView];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500478}
479
480# pragma private IN/OUT animations
481
482-(void) animateIn
483{
Alexandre Lisionc5148052015-03-04 15:10:35 -0500484 CGRect frame = CGRectOffset(self.view.superview.bounds, -self.view.superview.bounds.size.width, 0);
485 [self.view setHidden:NO];
486
487 [CATransaction begin];
488 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
489 [animation setFromValue:[NSValue valueWithPoint:frame.origin]];
490 [animation setToValue:[NSValue valueWithPoint:self.view.superview.bounds.origin]];
491 [animation setDuration:0.2f];
Alexandre Lision22d615b2016-01-25 12:54:34 -0500492 [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500493 [CATransaction setCompletionBlock:^{
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400494
495 // when call comes in we want to show the controls/header
496 [self mouseIsMoving:YES];
497
Alexandre Lisionc5148052015-03-04 15:10:35 -0500498 [self connectVideoSignals];
Alexandre Lisionb65c0272015-07-22 15:51:29 -0400499 /* check if text media is already present */
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400500 if(!CallModel::instance().selectedCall())
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400501 return;
Alexandre Lision21666f32015-09-22 17:04:36 -0400502
Alexandre Lision22d615b2016-01-25 12:54:34 -0500503 [loadingIndicator setAnimates:YES];
Alexandre Lision210fe212016-01-27 11:15:13 -0500504 [self updateCall:YES];
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500505
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400506 if (CallModel::instance().selectedCall()->hasMedia(Media::Media::Type::TEXT, Media::Media::Direction::IN)) {
507 Media::Text *text = CallModel::instance().selectedCall()->firstMedia<Media::Text>(Media::Media::Direction::IN);
Alexandre Lisionb65c0272015-07-22 15:51:29 -0400508 [self monitorIncomingTextMessages:text];
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400509 } else if (CallModel::instance().selectedCall()->hasMedia(Media::Media::Type::TEXT, Media::Media::Direction::OUT)) {
510 Media::Text *text = CallModel::instance().selectedCall()->firstMedia<Media::Text>(Media::Media::Direction::OUT);
Alexandre Lisionb65c0272015-07-22 15:51:29 -0400511 [self monitorIncomingTextMessages:text];
512 } else {
513 /* monitor media for messaging text messaging */
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400514 self.mediaAddedConnection = QObject::connect(CallModel::instance().selectedCall(),
Alexandre Lisionb65c0272015-07-22 15:51:29 -0400515 &Call::mediaAdded,
516 [self] (Media::Media* media) {
517 if (media->type() == Media::Media::Type::TEXT) { [self monitorIncomingTextMessages:(Media::Text*)media];
518 QObject::disconnect(self.mediaAddedConnection);
519 }
520 });
521 }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500522 }];
523 [self.view.layer addAnimation:animation forKey:animation.keyPath];
524
525 [CATransaction commit];
526}
527
528-(void) cleanUp
529{
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400530 QObject::disconnect(videoHolder.frameUpdated);
531 QObject::disconnect(videoHolder.started);
532 QObject::disconnect(videoHolder.stopped);
533 QObject::disconnect(previewHolder.frameUpdated);
534 QObject::disconnect(previewHolder.stopped);
535 QObject::disconnect(previewHolder.started);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500536 [videoView.layer setContents:nil];
537 [previewView.layer setContents:nil];
Alexandre Lision883719f2015-10-22 17:37:45 -0400538
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500539 [_brokerPopoverVC performClose:self];
Alexandre Lision883719f2015-10-22 17:37:45 -0400540 [self.addToContactPopover performClose:self];
Alexandre Lision0e66aea2015-11-02 16:36:30 -0500541
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500542 [self.chatButton setHidden:YES];
543 [self.addParticipantButton setHidden:YES];
544 [self.transferButton setHidden:YES];
545
Alexandre Lision4baba4c2016-02-11 13:00:57 -0500546 [self.chatButton setPressed:NO];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500547 [self.mergeCallsButton setState:NSOffState];
Alexandre Lision883719f2015-10-22 17:37:45 -0400548 [self collapseRightView];
Alexandre Lision57227772016-01-15 17:19:36 -0500549
550 [personLabel setStringValue:@""];
551 [timeSpentLabel setStringValue:@""];
552 [stateLabel setStringValue:@""];
553 [self.addContactButton setHidden:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500554}
555
556-(void) animateOut
557{
Alexandre Lisionc5148052015-03-04 15:10:35 -0500558 if(self.view.frame.origin.x < 0) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500559 return;
560 }
561
562 CGRect frame = CGRectOffset(self.view.frame, -self.view.frame.size.width, 0);
563 [CATransaction begin];
564 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
565 [animation setFromValue:[NSValue valueWithPoint:self.view.frame.origin]];
566 [animation setToValue:[NSValue valueWithPoint:frame.origin]];
567 [animation setDuration:0.2f];
Alexandre Lision22d615b2016-01-25 12:54:34 -0500568 [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500569
570 [CATransaction setCompletionBlock:^{
571 [self.view setHidden:YES];
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400572 // first make sure everything is disconnected
Alexandre Lisionc5148052015-03-04 15:10:35 -0500573 [self cleanUp];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500574 if (RecentModel::instance().getActiveCall(RecentModel::instance().selectionModel()->currentIndex())) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500575 [self animateIn];
576 }
577 }];
578 [self.view.layer addAnimation:animation forKey:animation.keyPath];
Alexandre Lisiona1c6d752015-06-23 12:27:38 -0400579
580 [self.view.layer setPosition:frame.origin];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500581 [CATransaction commit];
582}
583
584/**
585 * Debug purpose
586 */
587-(void) dumpFrame:(CGRect) frame WithName:(NSString*) name
588{
589 NSLog(@"frame %@ : %f %f %f %f \n\n",name ,frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
590}
591
Alexandre Lision58cab672015-06-09 15:25:40 -0400592-(void)collapseRightView
593{
594 NSView *right = [[splitView subviews] objectAtIndex:1];
595 NSView *left = [[splitView subviews] objectAtIndex:0];
596 NSRect leftFrame = [left frame];
597 [right setHidden:YES];
598 [splitView display];
599}
Alexandre Lisionc5148052015-03-04 15:10:35 -0500600
Alexandre Lision58cab672015-06-09 15:25:40 -0400601-(void)uncollapseRightView
602{
603 NSView *left = [[splitView subviews] objectAtIndex:0];
604 NSView *right = [[splitView subviews] objectAtIndex:1];
605 [right setHidden:NO];
606
607 CGFloat dividerThickness = [splitView dividerThickness];
608
609 // get the different frames
610 NSRect leftFrame = [left frame];
611 NSRect rightFrame = [right frame];
612
613 leftFrame.size.width = (leftFrame.size.width - rightFrame.size.width - dividerThickness);
614 rightFrame.origin.x = leftFrame.size.width + dividerThickness;
615 [left setFrameSize:leftFrame.size];
616 [right setFrame:rightFrame];
617 [splitView display];
Alexandre Lision16d9c0a2015-08-10 12:05:15 -0400618
619 [self.chatVC takeFocus];
Alexandre Lision58cab672015-06-09 15:25:40 -0400620}
621
622
623#pragma mark - Button methods
624
Alexandre Lision2db8f472015-07-22 15:05:46 -0400625- (IBAction)addToContact:(NSButton*) sender {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400626 auto contactmethod = CallModel::instance().getCall(CallModel::instance().selectionModel()->currentIndex())->peerContactMethod();
Alexandre Lision2db8f472015-07-22 15:05:46 -0400627
628 if (self.addToContactPopover != nullptr) {
629 [self.addToContactPopover performClose:self];
630 self.addToContactPopover = NULL;
631 } else if (!contactmethod->contact() || contactmethod->contact()->isPlaceHolder()) {
632 auto* editorVC = [[PersonLinkerVC alloc] initWithNibName:@"PersonLinker" bundle:nil];
633 [editorVC setMethodToLink:contactmethod];
634 [editorVC setContactLinkedDelegate:self];
635 self.addToContactPopover = [[NSPopover alloc] init];
636 [self.addToContactPopover setContentSize:editorVC.view.frame.size];
637 [self.addToContactPopover setContentViewController:editorVC];
638 [self.addToContactPopover setAnimates:YES];
639 [self.addToContactPopover setBehavior:NSPopoverBehaviorTransient];
640 [self.addToContactPopover setDelegate:self];
641
642 [self.addToContactPopover showRelativeToRect:sender.bounds ofView:sender preferredEdge:NSMaxXEdge];
643 }
Alexandre Lision883719f2015-10-22 17:37:45 -0400644
645 [videoView setCallDelegate:nil];
Alexandre Lision2db8f472015-07-22 15:05:46 -0400646}
647
Alexandre Lisionc5148052015-03-04 15:10:35 -0500648- (IBAction)hangUp:(id)sender {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400649 CallModel::instance().getCall(CallModel::instance().selectionModel()->currentIndex()) << Call::Action::REFUSE;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500650}
651
652- (IBAction)accept:(id)sender {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400653 CallModel::instance().getCall(CallModel::instance().selectionModel()->currentIndex()) << Call::Action::ACCEPT;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500654}
655
656- (IBAction)toggleRecording:(id)sender {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400657 CallModel::instance().getCall(CallModel::instance().selectionModel()->currentIndex()) << Call::Action::RECORD_AUDIO;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500658}
659
660- (IBAction)toggleHold:(id)sender {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400661 CallModel::instance().getCall(CallModel::instance().selectionModel()->currentIndex()) << Call::Action::HOLD;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500662}
663
Alexandre Lision58cab672015-06-09 15:25:40 -0400664-(IBAction)toggleChat:(id)sender;
665{
666 BOOL rightViewCollapsed = [[self splitView] isSubviewCollapsed:[[[self splitView] subviews] objectAtIndex: 1]];
667 if (rightViewCollapsed) {
668 [self uncollapseRightView];
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400669 CallModel::instance().getCall(CallModel::instance().selectionModel()->currentIndex())->addOutgoingMedia<Media::Text>();
Alexandre Lision58cab672015-06-09 15:25:40 -0400670 } else {
671 [self collapseRightView];
672 }
673 [chatButton setState:rightViewCollapsed];
674}
675
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400676- (IBAction)muteAudio:(id)sender
677{
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400678 UserActionModel* uam = CallModel::instance().userActionModel();
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400679 uam << UserActionModel::Action::MUTE_AUDIO;
680}
681
682- (IBAction)muteVideo:(id)sender
683{
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400684 UserActionModel* uam = CallModel::instance().userActionModel();
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400685 uam << UserActionModel::Action::MUTE_VIDEO;
686}
Alexandre Lision883719f2015-10-22 17:37:45 -0400687
688- (IBAction)toggleTransferView:(id)sender {
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500689 if (_brokerPopoverVC != nullptr) {
690 [_brokerPopoverVC performClose:self];
691 _brokerPopoverVC = NULL;
Alexandre Lision883719f2015-10-22 17:37:45 -0400692 [self.transferButton setState:NSOffState];
693 } else {
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500694 auto* brokerVC = [[BrokerVC alloc] initWithMode:BrokerMode::TRANSFER];
695 _brokerPopoverVC = [[NSPopover alloc] init];
696 [_brokerPopoverVC setContentSize:brokerVC.view.frame.size];
697 [_brokerPopoverVC setContentViewController:brokerVC];
698 [_brokerPopoverVC setAnimates:YES];
699 [_brokerPopoverVC setBehavior:NSPopoverBehaviorTransient];
700 [_brokerPopoverVC setDelegate:self];
701 [_brokerPopoverVC showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
Alexandre Lision883719f2015-10-22 17:37:45 -0400702 [videoView setCallDelegate:nil];
703 }
Alexandre Lisionf23ec5a2015-07-16 11:24:06 -0400704}
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400705
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500706- (IBAction)toggleAddParticipantView:(id)sender {
707 if (_brokerPopoverVC != nullptr) {
708 [_brokerPopoverVC performClose:self];
709 _brokerPopoverVC = NULL;
710 [self.addParticipantButton setState:NSOffState];
711 } else {
712 auto* brokerVC = [[BrokerVC alloc] initWithMode:BrokerMode::CONFERENCE];
713 _brokerPopoverVC = [[NSPopover alloc] init];
714 [_brokerPopoverVC setContentSize:brokerVC.view.frame.size];
715 [_brokerPopoverVC setContentViewController:brokerVC];
716 [_brokerPopoverVC setAnimates:YES];
717 [_brokerPopoverVC setBehavior:NSPopoverBehaviorTransient];
718 [_brokerPopoverVC setDelegate:self];
719 [_brokerPopoverVC showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
720 [videoView setCallDelegate:nil];
721 }
722}
723
724/**
725 * Merge current call with its parent call
726 */
727- (IBAction)mergeCalls:(id)sender
728{
729 auto current = CallModel::instance().selectedCall();
730 current->joinToParent();
731}
732
Alexandre Lision2db8f472015-07-22 15:05:46 -0400733#pragma mark - NSPopOverDelegate
734
Alexandre Lision266fca02015-09-28 14:47:05 -0400735- (void)popoverWillClose:(NSNotification *)notification
736{
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500737 if (_brokerPopoverVC != nullptr) {
738 [_brokerPopoverVC performClose:self];
739 _brokerPopoverVC = NULL;
Alexandre Lision883719f2015-10-22 17:37:45 -0400740 }
Alexandre Lision266fca02015-09-28 14:47:05 -0400741
Alexandre Lision2db8f472015-07-22 15:05:46 -0400742 if (self.addToContactPopover != nullptr) {
743 [self.addToContactPopover performClose:self];
744 self.addToContactPopover = NULL;
745 }
Alexandre Lision883719f2015-10-22 17:37:45 -0400746
Alexandre Lision883719f2015-10-22 17:37:45 -0400747 [self.addContactButton setState:NSOffState];
748 [self.transferButton setState:NSOffState];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500749 [self.addParticipantButton setState:NSOffState];
Alexandre Lision883719f2015-10-22 17:37:45 -0400750}
751
752- (void)popoverDidClose:(NSNotification *)notification
753{
754 [videoView setCallDelegate:self];
Alexandre Lision2db8f472015-07-22 15:05:46 -0400755}
756
757#pragma mark - ContactLinkedDelegate
758
759- (void)contactLinked
760{
761 if (self.addToContactPopover != nullptr) {
762 [self.addToContactPopover performClose:self];
763 self.addToContactPopover = NULL;
764 }
765}
766
Alexandre Lision58cab672015-06-09 15:25:40 -0400767#pragma mark - NSSplitViewDelegate
768
769/* Return YES if the subview should be collapsed because the user has double-clicked on an adjacent divider. If a split view has a delegate, and the delegate responds to this message, it will be sent once for the subview before a divider when the user double-clicks on that divider, and again for the subview after the divider, but only if the delegate returned YES when sent -splitView:canCollapseSubview: for the subview in question. When the delegate indicates that both subviews should be collapsed NSSplitView's behavior is undefined.
770 */
771- (BOOL)splitView:(NSSplitView *)splitView shouldCollapseSubview:(NSView *)subview forDoubleClickOnDividerAtIndex:(NSInteger)dividerIndex;
772{
773 NSView* rightView = [[splitView subviews] objectAtIndex:1];
774 return ([subview isEqual:rightView]);
775}
776
777
778- (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview;
779{
780 NSView* rightView = [[splitView subviews] objectAtIndex:1];
781 return ([subview isEqual:rightView]);
782}
783
784
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400785# pragma mark - CallnDelegate
Alexandre Lision58cab672015-06-09 15:25:40 -0400786
787- (void) callShouldToggleFullScreen
788{
789 if(self.splitView.isInFullScreenMode)
790 [self.splitView exitFullScreenModeWithOptions:nil];
791 else {
792 NSApplicationPresentationOptions options = NSApplicationPresentationDefault +NSApplicationPresentationAutoHideDock +
793 NSApplicationPresentationAutoHideMenuBar + NSApplicationPresentationAutoHideToolbar;
794 NSDictionary *opts = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:options],
795 NSFullScreenModeApplicationPresentationOptions, nil];
796
797 [self.splitView enterFullScreenMode:[NSScreen mainScreen] withOptions:opts];
798 }
799}
800
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400801-(void) mouseIsMoving:(BOOL) move
802{
803 [[controlsPanel animator] setAlphaValue:move]; // fade out
804 [[headerContainer animator] setAlphaValue:move];
805}
806
Alexandre Lisionc5148052015-03-04 15:10:35 -0500807@end