blob: bf13cfa42baf66d0dbbc9fb9f63d06e115254502 [file] [log] [blame]
Alexandre Lisionc5148052015-03-04 15:10:35 -05001/*
2 * Copyright (C) 2004-2015 Savoir-Faire Linux Inc.
3 * 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.
18 *
19 * Additional permission under GNU GPL version 3 section 7:
20 *
21 * If you modify this program, or any covered work, by linking or
22 * combining it with the OpenSSL project's OpenSSL library (or a
23 * modified version of that library), containing parts covered by the
24 * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
25 * grants you additional permission to convey the resulting work.
26 * Corresponding Source for a non-source form of such a combination
27 * shall include the source code for the parts of OpenSSL used as well
28 * as that of the covered work.
29 */
30#import "CurrentCallVC.h"
31
32#import <QuartzCore/QuartzCore.h>
33
34#import <call.h>
35#import <callmodel.h>
36#import <useractionmodel.h>
37#import <contactmethod.h>
38#import <qabstractitemmodel.h>
39#import <QItemSelectionModel>
40#import <QItemSelection>
Alexandre Lisionc5148052015-03-04 15:10:35 -050041#import <video/previewmanager.h>
42#import <video/renderer.h>
Alexandre Lision58cab672015-06-09 15:25:40 -040043#import <media/text.h>
Alexandre Lisionc5148052015-03-04 15:10:35 -050044
Alexandre Lisionf47a2562015-06-15 15:48:29 -040045#import "views/ITProgressIndicator.h"
Alexandre Lision74dd47f2015-04-14 13:47:42 -040046#import "views/CallView.h"
47
Alexandre Lisionc5148052015-03-04 15:10:35 -050048@interface RendererConnectionsHolder : NSObject
49
50@property QMetaObject::Connection frameUpdated;
51@property QMetaObject::Connection started;
52@property QMetaObject::Connection stopped;
53
54@end
55
56@implementation RendererConnectionsHolder
57
58@end
59
60@interface CurrentCallVC ()
61
Alexandre Lision58cab672015-06-09 15:25:40 -040062@property (unsafe_unretained) IBOutlet NSTextField *personLabel;
63@property (unsafe_unretained) IBOutlet NSTextField *stateLabel;
64@property (unsafe_unretained) IBOutlet NSButton *holdOnOffButton;
65@property (unsafe_unretained) IBOutlet NSButton *hangUpButton;
66@property (unsafe_unretained) IBOutlet NSButton *recordOnOffButton;
67@property (unsafe_unretained) IBOutlet NSButton *pickUpButton;
Alexandre Lisiond18fa272015-06-15 11:18:03 -040068@property (unsafe_unretained) IBOutlet NSButton *muteAudioButton;
69@property (unsafe_unretained) IBOutlet NSButton *muteVideoButton;
70
Alexandre Lisionf47a2562015-06-15 15:48:29 -040071@property (unsafe_unretained) IBOutlet ITProgressIndicator *loadingIndicator;
Alexandre Lisiond18fa272015-06-15 11:18:03 -040072
Alexandre Lision58cab672015-06-09 15:25:40 -040073@property (unsafe_unretained) IBOutlet NSTextField *timeSpentLabel;
74@property (unsafe_unretained) IBOutlet NSView *controlsPanel;
75@property (unsafe_unretained) IBOutlet NSSplitView *splitView;
76@property (unsafe_unretained) IBOutlet NSButton *chatButton;
Alexandre Lisionc5148052015-03-04 15:10:35 -050077
78@property QHash<int, NSButton*> actionHash;
79
80// Video
Alexandre Lision58cab672015-06-09 15:25:40 -040081@property (unsafe_unretained) IBOutlet CallView *videoView;
Alexandre Lisionc5148052015-03-04 15:10:35 -050082@property CALayer* videoLayer;
Alexandre Lision58cab672015-06-09 15:25:40 -040083@property (unsafe_unretained) IBOutlet NSView *previewView;
Alexandre Lisionc5148052015-03-04 15:10:35 -050084@property CALayer* previewLayer;
85
86@property RendererConnectionsHolder* previewHolder;
87@property RendererConnectionsHolder* videoHolder;
Alexandre Lisionef6333a2015-03-24 12:30:31 -040088@property QMetaObject::Connection videoStarted;
Alexandre Lisionc5148052015-03-04 15:10:35 -050089
90@end
91
92@implementation CurrentCallVC
Alexandre Lisiond18fa272015-06-15 11:18:03 -040093@synthesize personLabel, actionHash, stateLabel, holdOnOffButton, hangUpButton,
94 recordOnOffButton, pickUpButton, chatButton, timeSpentLabel,
95 muteVideoButton, muteAudioButton, controlsPanel, videoView,
Alexandre Lisionf47a2562015-06-15 15:48:29 -040096 videoLayer, previewLayer, previewView, splitView, loadingIndicator;
Alexandre Lisionc5148052015-03-04 15:10:35 -050097
98@synthesize previewHolder;
99@synthesize videoHolder;
100
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400101- (void) updateAllActions
Alexandre Lisionc5148052015-03-04 15:10:35 -0500102{
103 for(int i = 0 ; i <= CallModel::instance()->userActionModel()->rowCount() ; i++) {
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400104 [self updateActionAtIndex:i];
105 }
106}
107
108- (void) updateActionAtIndex:(int) row
109{
110 const QModelIndex& idx = CallModel::instance()->userActionModel()->index(row,0);
111 UserActionModel::Action action = qvariant_cast<UserActionModel::Action>(idx.data(UserActionModel::Role::ACTION));
112 NSButton* a = actionHash[(int) action];
113 if (a != nil) {
114 [a setEnabled:(idx.flags() & Qt::ItemIsEnabled)];
115 [a setState:(idx.data(Qt::CheckStateRole) == Qt::Checked) ? NSOnState : NSOffState];
116
117 if(action == UserActionModel::Action::HOLD) {
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400118 NSString* imgName = (a.state == NSOnState ? @"ic_action_holdoff" : @"ic_action_hold");
119 [a setImage:[NSImage imageNamed:imgName]];
120
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400121 }
122 if(action == UserActionModel::Action::RECORD) {
123 [a setTitle:(a.state == NSOnState ? @"Record off" : @"Record")];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500124 }
125 }
126}
127
128-(void) updateCall
129{
130 QModelIndex callIdx = CallModel::instance()->selectionModel()->currentIndex();
Alexandre Lision58cab672015-06-09 15:25:40 -0400131 [personLabel setStringValue:callIdx.data(Qt::DisplayRole).toString().toNSString()];
132 [timeSpentLabel setStringValue:callIdx.data((int)Call::Role::Length).toString().toNSString()];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500133
Alexandre Lision58cab672015-06-09 15:25:40 -0400134 Call::State state = callIdx.data((int)Call::Role::State).value<Call::State>();
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400135 [loadingIndicator setHidden:YES];
136 [stateLabel setStringValue:callIdx.data((int)Call::Role::HumanStateName).toString().toNSString()];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500137 switch (state) {
Alexandre Lisione6dbf092015-04-11 17:19:35 -0400138 case Call::State::DIALING:
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400139 [loadingIndicator setHidden:NO];
Alexandre Lisione6dbf092015-04-11 17:19:35 -0400140 break;
141 case Call::State::NEW:
Alexandre Lisione6dbf092015-04-11 17:19:35 -0400142 break;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500143 case Call::State::INITIALIZATION:
Alexandre Lision74dd47f2015-04-14 13:47:42 -0400144 [videoView setShouldAcceptInteractions:NO];
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400145 [loadingIndicator setHidden:NO];
146 break;
147 case Call::State::CONNECTED:
148 [videoView setShouldAcceptInteractions:NO];
149 [loadingIndicator setHidden:NO];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500150 break;
151 case Call::State::RINGING:
Alexandre Lision74dd47f2015-04-14 13:47:42 -0400152 [videoView setShouldAcceptInteractions:NO];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500153 break;
154 case Call::State::CURRENT:
Alexandre Lision74dd47f2015-04-14 13:47:42 -0400155 [videoView setShouldAcceptInteractions:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500156 break;
157 case Call::State::HOLD:
Alexandre Lision74dd47f2015-04-14 13:47:42 -0400158 [videoView setShouldAcceptInteractions:NO];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500159 break;
160 case Call::State::BUSY:
Alexandre Lision74dd47f2015-04-14 13:47:42 -0400161 [videoView setShouldAcceptInteractions:NO];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500162 break;
163 case Call::State::OVER:
Alexandre Lision74dd47f2015-04-14 13:47:42 -0400164 [videoView setShouldAcceptInteractions:NO];
165 if(videoView.isInFullScreenMode)
166 [videoView exitFullScreenModeWithOptions:nil];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500167 break;
168 case Call::State::FAILURE:
Alexandre Lision74dd47f2015-04-14 13:47:42 -0400169 [videoView setShouldAcceptInteractions:NO];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500170 break;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500171 }
172
173}
174
175- (void)awakeFromNib
176{
177 NSLog(@"INIT CurrentCall VC");
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400178 [self.view setWantsLayer:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500179 [self.view setLayer:[CALayer layer]];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500180
181 [controlsPanel setWantsLayer:YES];
182 [controlsPanel setLayer:[CALayer layer]];
183 [controlsPanel.layer setZPosition:2.0];
184 [controlsPanel.layer setBackgroundColor:[NSColor whiteColor].CGColor];
185
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400186 actionHash[ (int)UserActionModel::Action::ACCEPT] = pickUpButton;
187 actionHash[ (int)UserActionModel::Action::HOLD ] = holdOnOffButton;
188 actionHash[ (int)UserActionModel::Action::RECORD] = recordOnOffButton;
189 actionHash[ (int)UserActionModel::Action::HANGUP] = hangUpButton;
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400190 actionHash[ (int)UserActionModel::Action::MUTE_AUDIO] = muteAudioButton;
191 actionHash[ (int)UserActionModel::Action::MUTE_VIDEO] = muteVideoButton;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500192
Alexandre Lisionc5148052015-03-04 15:10:35 -0500193 videoLayer = [CALayer layer];
194 [videoView setWantsLayer:YES];
195 [videoView setLayer:videoLayer];
196 [videoView.layer setBackgroundColor:[NSColor blackColor].CGColor];
197 [videoView.layer setFrame:videoView.frame];
198 [videoView.layer setContentsGravity:kCAGravityResizeAspect];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500199
200 previewLayer = [CALayer layer];
201 [previewView setWantsLayer:YES];
202 [previewView setLayer:previewLayer];
203 [previewLayer setBackgroundColor:[NSColor blackColor].CGColor];
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400204 [previewLayer setContentsGravity:kCAGravityResizeAspectFill];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500205 [previewLayer setFrame:previewView.frame];
206
207 [controlsPanel setWantsLayer:YES];
208 [controlsPanel setLayer:[CALayer layer]];
209 [controlsPanel.layer setBackgroundColor:[NSColor clearColor].CGColor];
210 [controlsPanel.layer setFrame:controlsPanel.frame];
211
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400212 previewHolder = [[RendererConnectionsHolder alloc] init];
213 videoHolder = [[RendererConnectionsHolder alloc] init];
214
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400215 [loadingIndicator setColor:[NSColor whiteColor]];
216 [loadingIndicator setNumberOfLines:100];
217 [loadingIndicator setWidthOfLine:2];
218 [loadingIndicator setLengthOfLine:2];
219 [loadingIndicator setInnerMargin:30];
220
Alexandre Lision58cab672015-06-09 15:25:40 -0400221 [self.videoView setFullScreenDelegate:self];
222
Alexandre Lisionc5148052015-03-04 15:10:35 -0500223 [self connect];
224}
225
226- (void) connect
227{
228 QObject::connect(CallModel::instance()->selectionModel(),
229 &QItemSelectionModel::currentChanged,
230 [=](const QModelIndex &current, const QModelIndex &previous) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500231 if(!current.isValid()) {
232 [self animateOut];
233 return;
234 }
Alexandre Lisionbb5dbcd2015-07-09 16:36:47 -0400235
236 auto call = CallModel::instance()->getCall(current);
237 if (call->state() == Call::State::HOLD) {
238 call << Call::Action::HOLD;
239 }
240
Alexandre Lision58cab672015-06-09 15:25:40 -0400241 [self collapseRightView];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500242 [self updateCall];
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400243 [self updateAllActions];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500244 [self animateOut];
245 });
246
247 QObject::connect(CallModel::instance(),
248 &QAbstractItemModel::dataChanged,
249 [=](const QModelIndex &topLeft, const QModelIndex &bottomRight) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500250 [self updateCall];
251 });
252
253 QObject::connect(CallModel::instance()->userActionModel(),
254 &QAbstractItemModel::dataChanged,
255 [=](const QModelIndex &topLeft, const QModelIndex &bottomRight) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500256 const int first(topLeft.row()),last(bottomRight.row());
257 for(int i = first; i <= last;i++) {
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400258 [self updateActionAtIndex:i];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500259 }
260 });
261
262 QObject::connect(CallModel::instance(),
263 &CallModel::callStateChanged,
264 [self](Call* c, Call::State state) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500265 [self updateCall];
266 });
267}
268
269-(void) connectVideoSignals
270{
271 QModelIndex idx = CallModel::instance()->selectionModel()->currentIndex();
272 Call* call = CallModel::instance()->getCall(idx);
Alexandre Lision58cab672015-06-09 15:25:40 -0400273 self.videoStarted = QObject::connect(call,
Alexandre Lisionc5148052015-03-04 15:10:35 -0500274 &Call::videoStarted,
275 [=](Video::Renderer* renderer) {
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400276 NSLog(@"Video started!");
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400277 [self connectVideoRenderer:renderer];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500278 });
279
280 if(call->videoRenderer())
281 {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500282 [self connectVideoRenderer:call->videoRenderer()];
283 }
284
285 [self connectPreviewRenderer];
286
287}
288
289-(void) connectPreviewRenderer
290{
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400291 QObject::disconnect(previewHolder.frameUpdated);
292 QObject::disconnect(previewHolder.stopped);
293 QObject::disconnect(previewHolder.started);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500294 previewHolder.started = QObject::connect(Video::PreviewManager::instance(),
295 &Video::PreviewManager::previewStarted,
296 [=](Video::Renderer* renderer) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500297 QObject::disconnect(previewHolder.frameUpdated);
298 previewHolder.frameUpdated = QObject::connect(renderer,
299 &Video::Renderer::frameUpdated,
300 [=]() {
301 [self renderer:Video::PreviewManager::instance()->previewRenderer()
302 renderFrameForView:previewView];
303 });
304 });
305
306 previewHolder.stopped = QObject::connect(Video::PreviewManager::instance(),
307 &Video::PreviewManager::previewStopped,
308 [=](Video::Renderer* renderer) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500309 QObject::disconnect(previewHolder.frameUpdated);
310 [previewView.layer setContents:nil];
311 });
312
313 previewHolder.frameUpdated = QObject::connect(Video::PreviewManager::instance()->previewRenderer(),
314 &Video::Renderer::frameUpdated,
315 [=]() {
316 [self renderer:Video::PreviewManager::instance()->previewRenderer()
317 renderFrameForView:previewView];
318 });
319}
320
321-(void) connectVideoRenderer: (Video::Renderer*)renderer
322{
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400323 QObject::disconnect(videoHolder.frameUpdated);
324 QObject::disconnect(videoHolder.started);
325 QObject::disconnect(videoHolder.stopped);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500326 videoHolder.frameUpdated = QObject::connect(renderer,
327 &Video::Renderer::frameUpdated,
328 [=]() {
329 [self renderer:renderer renderFrameForView:videoView];
330 });
331
332 videoHolder.started = QObject::connect(renderer,
333 &Video::Renderer::started,
334 [=]() {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500335 QObject::disconnect(videoHolder.frameUpdated);
336 videoHolder.frameUpdated = QObject::connect(renderer,
337 &Video::Renderer::frameUpdated,
338 [=]() {
339 [self renderer:renderer renderFrameForView:videoView];
340 });
341 });
342
343 videoHolder.stopped = QObject::connect(renderer,
344 &Video::Renderer::stopped,
345 [=]() {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500346 QObject::disconnect(videoHolder.frameUpdated);
347 [videoView.layer setContents:nil];
348 });
349}
350
351-(void) renderer: (Video::Renderer*)renderer renderFrameForView:(NSView*) view
352{
Alexandre Lision911e0072015-07-13 16:19:08 -0400353 auto data = renderer->currentSmartFrame();
Alexandre Lisionc5148052015-03-04 15:10:35 -0500354 QSize res = renderer->size();
355
Alexandre Lision911e0072015-07-13 16:19:08 -0400356 auto buf = reinterpret_cast<const unsigned char*>(data->data());
Alexandre Lisionc5148052015-03-04 15:10:35 -0500357
358 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
359 CGContextRef newContext = CGBitmapContextCreate((void *)buf,
360 res.width(),
361 res.height(),
362 8,
363 4*res.width(),
364 colorSpace,
365 kCGImageAlphaPremultipliedLast);
366
367
368 CGImageRef newImage = CGBitmapContextCreateImage(newContext);
369
370 /*We release some components*/
371 CGContextRelease(newContext);
372 CGColorSpaceRelease(colorSpace);
373
374 [CATransaction begin];
375 view.layer.contents = (__bridge id)newImage;
376 [CATransaction commit];
377
378 CFRelease(newImage);
379}
380
381- (void) initFrame
382{
383 [self.view setFrame:self.view.superview.bounds];
384 [self.view setHidden:YES];
385 self.view.layer.position = self.view.frame.origin;
Alexandre Lisionbb5dbcd2015-07-09 16:36:47 -0400386 [self collapseRightView];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500387}
388
389# pragma private IN/OUT animations
390
391-(void) animateIn
392{
393 NSLog(@"animateIn");
394 CGRect frame = CGRectOffset(self.view.superview.bounds, -self.view.superview.bounds.size.width, 0);
395 [self.view setHidden:NO];
396
397 [CATransaction begin];
398 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
399 [animation setFromValue:[NSValue valueWithPoint:frame.origin]];
400 [animation setToValue:[NSValue valueWithPoint:self.view.superview.bounds.origin]];
401 [animation setDuration:0.2f];
402 [animation setTimingFunction:[CAMediaTimingFunction functionWithControlPoints:.7 :0.9 :1 :1]];
403 [CATransaction setCompletionBlock:^{
Alexandre Lisionc5148052015-03-04 15:10:35 -0500404 [self connectVideoSignals];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500405 }];
406 [self.view.layer addAnimation:animation forKey:animation.keyPath];
407
408 [CATransaction commit];
409}
410
411-(void) cleanUp
412{
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400413 QObject::disconnect(videoHolder.frameUpdated);
414 QObject::disconnect(videoHolder.started);
415 QObject::disconnect(videoHolder.stopped);
416 QObject::disconnect(previewHolder.frameUpdated);
417 QObject::disconnect(previewHolder.stopped);
418 QObject::disconnect(previewHolder.started);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500419 [videoView.layer setContents:nil];
420 [previewView.layer setContents:nil];
421}
422
423-(void) animateOut
424{
425 NSLog(@"animateOut");
426 if(self.view.frame.origin.x < 0) {
427 NSLog(@"Already hidden");
428 if (CallModel::instance()->selectionModel()->currentIndex().isValid()) {
429 [self animateIn];
430 }
431 return;
432 }
433
434 CGRect frame = CGRectOffset(self.view.frame, -self.view.frame.size.width, 0);
435 [CATransaction begin];
436 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
437 [animation setFromValue:[NSValue valueWithPoint:self.view.frame.origin]];
438 [animation setToValue:[NSValue valueWithPoint:frame.origin]];
439 [animation setDuration:0.2f];
440 [animation setTimingFunction:[CAMediaTimingFunction functionWithControlPoints:.7 :0.9 :1 :1]];
441
442 [CATransaction setCompletionBlock:^{
443 [self.view setHidden:YES];
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400444 // first make sure everything is disconnected
Alexandre Lisionc5148052015-03-04 15:10:35 -0500445 [self cleanUp];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500446 if (CallModel::instance()->selectionModel()->currentIndex().isValid()) {
447 [self animateIn];
448 }
449 }];
450 [self.view.layer addAnimation:animation forKey:animation.keyPath];
Alexandre Lisiona1c6d752015-06-23 12:27:38 -0400451
452 [self.view.layer setPosition:frame.origin];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500453 [CATransaction commit];
454}
455
456/**
457 * Debug purpose
458 */
459-(void) dumpFrame:(CGRect) frame WithName:(NSString*) name
460{
461 NSLog(@"frame %@ : %f %f %f %f \n\n",name ,frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
462}
463
Alexandre Lision58cab672015-06-09 15:25:40 -0400464-(void)collapseRightView
465{
466 NSView *right = [[splitView subviews] objectAtIndex:1];
467 NSView *left = [[splitView subviews] objectAtIndex:0];
468 NSRect leftFrame = [left frame];
469 [right setHidden:YES];
470 [splitView display];
471}
Alexandre Lisionc5148052015-03-04 15:10:35 -0500472
Alexandre Lision58cab672015-06-09 15:25:40 -0400473-(void)uncollapseRightView
474{
475 NSView *left = [[splitView subviews] objectAtIndex:0];
476 NSView *right = [[splitView subviews] objectAtIndex:1];
477 [right setHidden:NO];
478
479 CGFloat dividerThickness = [splitView dividerThickness];
480
481 // get the different frames
482 NSRect leftFrame = [left frame];
483 NSRect rightFrame = [right frame];
484
485 leftFrame.size.width = (leftFrame.size.width - rightFrame.size.width - dividerThickness);
486 rightFrame.origin.x = leftFrame.size.width + dividerThickness;
487 [left setFrameSize:leftFrame.size];
488 [right setFrame:rightFrame];
489 [splitView display];
490}
491
492
493#pragma mark - Button methods
494
Alexandre Lisionc5148052015-03-04 15:10:35 -0500495- (IBAction)hangUp:(id)sender {
496 CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex()) << Call::Action::REFUSE;
497}
498
499- (IBAction)accept:(id)sender {
500 CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex()) << Call::Action::ACCEPT;
501}
502
503- (IBAction)toggleRecording:(id)sender {
Alexandre Lision66643432015-06-04 11:59:36 -0400504 CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex()) << Call::Action::RECORD_AUDIO;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500505}
506
507- (IBAction)toggleHold:(id)sender {
508 CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex()) << Call::Action::HOLD;
509}
510
Alexandre Lision58cab672015-06-09 15:25:40 -0400511-(IBAction)toggleChat:(id)sender;
512{
513 BOOL rightViewCollapsed = [[self splitView] isSubviewCollapsed:[[[self splitView] subviews] objectAtIndex: 1]];
514 if (rightViewCollapsed) {
515 [self uncollapseRightView];
516 CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex())->addOutgoingMedia<Media::Text>();
517 } else {
518 [self collapseRightView];
519 }
520 [chatButton setState:rightViewCollapsed];
521}
522
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400523- (IBAction)muteAudio:(id)sender
524{
525 UserActionModel* uam = CallModel::instance()->userActionModel();
526 uam << UserActionModel::Action::MUTE_AUDIO;
527}
528
529- (IBAction)muteVideo:(id)sender
530{
531 UserActionModel* uam = CallModel::instance()->userActionModel();
532 uam << UserActionModel::Action::MUTE_VIDEO;
533}
534
Alexandre Lision58cab672015-06-09 15:25:40 -0400535#pragma mark - NSSplitViewDelegate
536
537/* 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.
538 */
539- (BOOL)splitView:(NSSplitView *)splitView shouldCollapseSubview:(NSView *)subview forDoubleClickOnDividerAtIndex:(NSInteger)dividerIndex;
540{
541 NSView* rightView = [[splitView subviews] objectAtIndex:1];
542 return ([subview isEqual:rightView]);
543}
544
545
546- (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview;
547{
548 NSView* rightView = [[splitView subviews] objectAtIndex:1];
549 return ([subview isEqual:rightView]);
550}
551
552
553# pragma mark - FullScreenDelegate
554
555- (void) callShouldToggleFullScreen
556{
557 if(self.splitView.isInFullScreenMode)
558 [self.splitView exitFullScreenModeWithOptions:nil];
559 else {
560 NSApplicationPresentationOptions options = NSApplicationPresentationDefault +NSApplicationPresentationAutoHideDock +
561 NSApplicationPresentationAutoHideMenuBar + NSApplicationPresentationAutoHideToolbar;
562 NSDictionary *opts = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:options],
563 NSFullScreenModeApplicationPresentationOptions, nil];
564
565 [self.splitView enterFullScreenMode:[NSScreen mainScreen] withOptions:opts];
566 }
567}
568
Alexandre Lisionc5148052015-03-04 15:10:35 -0500569@end