Reverse order of incr/decr pitch buttons.
[stretchplayer:stretchplayer.git] / src / PlayerWidget.cpp
1 /*
2  * Copyright(c) 2009 by Gabriel M. Beddingfield <gabriel@teuton.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY, without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  */
19
20 #include "PlayerWidget.hpp"
21 #include "Engine.hpp"
22 #include "StatusWidget.hpp"
23
24 #include <QWidget>
25 #include <QToolButton>
26 #include <QLabel>
27 #include <QVBoxLayout>
28 #include <QHBoxLayout>
29 #include <QSlider>
30 #include <QFont>
31 #include <QTimer>
32 #include <QSpinBox>
33 #include <QFileDialog>
34 #include <QPainter>
35 #include <QBitmap>
36 #include <QAction>
37 #include <QResizeEvent>
38 #include <QCoreApplication>
39
40 #include <cmath>
41
42 namespace StretchPlayer
43 {
44     namespace Details
45     {
46         class PlayerWidgetMessageCallback : public EngineMessageCallback
47         {
48         public:
49             PlayerWidgetMessageCallback(PlayerWidget* w) : _widget(w)
50                 {}
51             virtual ~PlayerWidgetMessageCallback() {}
52
53             virtual void operator()(const QString& msg) {
54                 _widget->status_message(msg);
55                 QCoreApplication::processEvents();
56             }
57         private:
58             PlayerWidget* _widget;
59         };
60
61     }
62
63     PlayerWidget::PlayerWidget(QWidget *parent)
64         : QMainWindow(parent)
65     {
66         setWindowFlags( Qt::Window
67                         | Qt::FramelessWindowHint
68             );
69
70 #if QT_VERSION >= 0x040500
71         setAttribute( Qt::WA_TranslucentBackground );
72         _compositing = true;
73 #else
74         _compositing = false;
75 #endif
76         setMinimumSize(_sizes.preferred_width()*2/3, _sizes.preferred_height()*2/3);
77
78         QSizePolicy policy(QSizePolicy::Fixed, QSizePolicy::Fixed);
79         policy.setHeightForWidth(true);
80         setSizePolicy(policy);
81
82         setMouseTracking(true);
83
84         resize(_sizes.preferred_width(), _sizes.preferred_height());
85
86         _setup_color_scheme(0);
87         _load_icons();
88         _setup_actions();
89         _setup_widgets();
90         _setup_signals_and_slots();
91         _layout_widgets();
92     }
93
94     PlayerWidget::~PlayerWidget()
95     {
96     }
97
98     void PlayerWidget::load_song(const QString& filename)
99     {
100         QString name = _engine->load_song(filename);
101         if(name.isEmpty()) {
102             _status->song_name("No song loaded.");
103         } else {
104             _status->song_name(name);
105         }
106     }
107
108     int PlayerWidget::heightForWidth(int w)
109     {
110         return _sizes.height_for_width(w);
111     }
112
113     void PlayerWidget::play_pause()
114     {
115         _engine->play_pause();
116     }
117
118     void PlayerWidget::stop()
119     {
120         _engine->stop();
121         _engine->locate(0);
122     }
123
124     void PlayerWidget::ab()
125     {
126         _engine->loop_ab();
127     }
128
129     void PlayerWidget::open_file()
130     {
131         _engine->stop();
132         QString filename = QFileDialog::getOpenFileName(
133             this,
134             "Open song file..."
135             );
136         if( ! filename.isNull() ) {
137             load_song(filename);
138         }
139     }
140
141     void PlayerWidget::status_message(const QString& msg) {
142         _status->message(msg);
143     }
144
145     void PlayerWidget::locate(float pos)
146     {
147         _engine->locate(pos * _engine->get_length());
148     }
149
150     void PlayerWidget::pitch_inc()
151     {
152         _engine->set_pitch( _engine->get_pitch() + 1 );
153     }
154
155     void PlayerWidget::pitch_dec()
156     {
157         _engine->set_pitch( _engine->get_pitch() - 1);
158     }
159
160     void PlayerWidget::speed_inc()
161     {
162         _engine->set_stretch( _engine->get_stretch() + .05 );
163     }
164
165     void PlayerWidget::speed_dec()
166     {
167         _engine->set_stretch( _engine->get_stretch() - .05 );
168     }
169
170     void PlayerWidget::volume_inc()
171     {
172         float gain = _from_fader(_volume->value() + 50);
173         _engine->set_volume( gain );
174     }
175
176     void PlayerWidget::volume_dec()
177     {
178         float gain = _from_fader(_volume->value() - 50);
179         _engine->set_volume( gain );
180     }
181
182     void PlayerWidget::stretch(int pos)
183     {
184         _engine->set_stretch( 0.5 + double(pos)/1000.0 );
185     }
186
187     void PlayerWidget::volume(int vol)
188     {
189         _engine->set_volume( _from_fader(vol) );
190     }
191
192     /**
193      * "Traditional" fader mapping
194      */
195     float PlayerWidget::_from_fader(int p_val)
196     {
197         float fader = float(p_val)/1000.0f;
198         float gain;
199         float db;
200
201         if(fader == 0) {
202             gain = 0.0f;
203         } else if(fader < .04) {
204             gain = fader * 1e-6f / .04f;
205         } else if(fader < .16) {
206             db = -60.0 + 20.0f * (fader-.04) / .12f;
207             gain = exp10(db/10.0);
208         } else if(fader < .52) {
209             db = -40.0 + 10.0f * (fader-.16) / .12f;
210             gain = exp10(db/10.0);
211         } else {
212             db = -10.0 + 15.0f * (fader-.52) / .48f;
213             gain = exp10(db/10.0);
214         }
215
216         return gain;
217     }
218
219     /**
220      * "Traditional" fader mapping
221      */
222     int PlayerWidget::_to_fader(float gain)
223     {
224         if(gain == 0.0f) return 0;
225
226         float fader;
227         float db = 10.0 * log10(gain);
228
229         if(db < -60.0) {
230             fader = gain * .04f / 1e-6f;
231         } else if(db < -40.0) {
232             fader = .04f + ((db + 60.0f) * .12f / 20.0f);
233         } else if(db < -10.0) {
234             fader = .16f + ((db + 40.0f) * .12f / 10.0f);
235         } else {
236             fader = .52f + ((db + 10.0f) * .48f / 15.0f);
237         }
238
239         if( fader > 1.0 ) fader = 1.0f;
240
241         return ::round(fader * 1000.0);
242     }
243
244     void PlayerWidget::reset()
245     {
246         stop();
247         _engine->set_pitch(0);
248         _engine->set_stretch(1.0);
249     }
250
251     void PlayerWidget::update_time()
252     {
253         float pos = _engine->get_position();
254         _status->time(pos);
255
256         float len = _engine->get_length();
257         _status->position(pos/len);
258
259         float sch = _engine->get_stretch();
260         _status->speed(sch);
261
262         int pit = _engine->get_pitch();
263         _status->pitch(pit);
264
265         float cpu = _engine->get_cpu_load();
266         _status->cpu(cpu);
267
268         float vol = _engine->get_volume();
269         _volume->setValue( _to_fader(vol) );
270         _status->volume( _volume->value() / 1000.0 );
271
272         _stretch->setValue( (sch-0.5) * 1000 );
273         update();
274     }
275
276     void PlayerWidget::resizeEvent(QResizeEvent * /*event*/)
277     {
278         _sizes.set_scale_from(width(), height());
279         _layout_widgets();
280     }
281
282     void PlayerWidget::paintEvent(QPaintEvent * event)
283     {
284         QPainter painter(this);
285         painter.setRenderHints(QPainter::Antialiasing);
286
287         const QPalette& pal = palette();
288
289         float thickline = _sizes.thicker_line();
290         float border_rad = thickline * 4.0;
291
292         float w = width();
293         float h = height();
294
295         if(_compositing) {
296             QImage mask_img(width(), height(), QImage::Format_Mono);
297             mask_img.fill(0xff);
298             QPainter mask_ptr(&mask_img);
299             mask_ptr.setBrush( QBrush( QColor(0, 0, 0) ) );
300             mask_ptr.drawRoundedRect( QRectF( 0, 0, w, h),
301                                       border_rad+thickline/2.0,
302                                       border_rad+thickline/2.0 );
303             QBitmap bmp = QBitmap::fromImage(mask_img);
304             setMask( bmp );
305         }
306
307         QBrush bg_brush( pal.color(QPalette::Active, QPalette::Window) );
308         QPen border_pen( pal.color(QPalette::Active, QPalette::Dark) );
309
310         border_pen.setWidthF(thickline);
311         border_pen.setJoinStyle(Qt::RoundJoin);
312         painter.setPen(border_pen);
313         QRectF bg_rect = QRectF( thickline/2.0,
314                                  thickline/2.0,
315                                  w-thickline,
316                                  h-thickline );
317         if(!_compositing) {
318             painter.setBrush( pal.color(QPalette::Active, QPalette::Dark) );
319             painter.drawRect( 0, 0, width(), height() );
320         }
321         painter.setBrush(bg_brush);
322         painter.drawRoundedRect( bg_rect,
323                                  border_rad,
324                                  border_rad );
325
326         QWidget::paintEvent(event);
327     }
328
329     void PlayerWidget::mousePressEvent(QMouseEvent *event)
330     {
331         if(event->button() & Qt::LeftButton) {
332             Qt::CursorShape cur = cursor().shape();
333             switch(cur) {
334             case Qt::SizeAllCursor:
335                 _anchor = event->globalPos();
336             case Qt::SizeHorCursor:
337             case Qt::SizeVerCursor:
338             case Qt::SizeFDiagCursor:
339             case Qt::SizeBDiagCursor:
340                 event->accept();
341                 _drag_resize(cur, event);
342                 break;
343             default:
344                 event->ignore();
345             }
346         } else {
347             event->ignore();
348         }
349     }
350
351     void PlayerWidget::mouseMoveEvent(QMouseEvent *event)
352     {
353         Qt::CursorShape cur = cursor().shape();
354         Qt::CursorShape loc = _which_cursor(event->pos());
355         if( (event->buttons() & Qt::LeftButton)
356             && (cur != Qt::ArrowCursor) ) {
357             _drag_resize(cur, event);
358         } else if( cur != loc ) {
359             event->accept();
360             QCursor new_cur(loc);
361             setCursor(new_cur);
362         } else {
363             event->ignore();
364         }
365     }
366
367     void PlayerWidget::_setup_color_scheme(int profile)
368     {
369         QPalette p;
370         QColor base, bright, light, mid, dark;
371
372         switch(profile) {
373         // case 0: // default
374         case 1: // Blue
375             bright.setRgb(0xff, 0xff, 0xff, 0xff); // white
376             light.setRgb(0x76, 0xc6, 0xf5, 0xff); // light blue
377             mid.setRgb(68, 141, 189, 0xff); // average
378             dark.setRgb(0x12, 0x55, 0x85, 0xff); // dark blue
379             base = light;
380             break;
381         default: // Yellow
382             bright.setRgb(0xff, 0xff, 0xff, 0xff); //white
383             light.setRgb(0xe5, 0xd7, 0x3a, 0xff); // yellow
384             mid.setRgb(114, 107, 29, 0xff); // average
385             dark.setRgb(0, 0, 0, 0xff); // black
386             base = light;
387         }
388
389         p.setColorGroup(QPalette::Active,
390                         dark, // Window Text
391                         light, // button
392                         light, // light
393                         dark, // dark
394                         mid, // mid
395                         dark, // text
396                         bright, // bright text
397                         base, // base
398                         light // window
399             );
400
401         setPalette(p);
402     }
403
404     void PlayerWidget::_load_icons()
405     {
406         _ico.play.addFile(":img/play.png");
407         _ico.stop.addFile(":img/stop.png");
408         _ico.ab.addFile(":img/ab.png");
409         _ico.help.addFile(":img/help.png");
410         _ico.quit.addFile(":img/quit.png");
411         _ico.plus.addFile(":img/plus.png");
412         _ico.minus.addFile(":img/minus.png");
413         _ico.open.addFile(":img/file.png");
414     }
415
416     void PlayerWidget::_setup_actions()
417     {
418         memset(&_act, 0, sizeof(_act));
419
420         _act.play_pause = new QAction("P", this);
421         _act.play_pause->setToolTip("Play/Pause [Space]");
422         _act.play_pause->setShortcut(Qt::Key_Space);
423         _act.play_pause->setShortcutContext(Qt::ApplicationShortcut);
424         _act.play_pause->setIcon( _ico.play );
425         addAction(_act.play_pause);
426         connect(_act.play_pause, SIGNAL(triggered()),
427                 this, SLOT(play_pause()));
428
429         _act.stop = new QAction("S", this);
430         _act.stop->setToolTip("Stop [S]");
431         _act.stop->setShortcut(Qt::Key_S);
432         _act.stop->setShortcutContext(Qt::ApplicationShortcut);
433         _act.stop->setIcon( _ico.stop );
434         addAction(_act.stop);
435         connect(_act.stop, SIGNAL(triggered()),
436                 this, SLOT(stop()));
437
438         QList<QKeySequence> ab_shortcuts;
439         ab_shortcuts << Qt::Key_Enter;
440         ab_shortcuts << Qt::Key_Return;
441         _act.ab = new QAction("AB", this);
442         _act.ab->setToolTip("AB Repeat [Enter]");
443         _act.ab->setShortcuts(ab_shortcuts);
444         _act.ab->setShortcutContext(Qt::ApplicationShortcut);
445         _act.ab->setIcon( _ico.ab );
446         addAction(_act.ab);
447         connect(_act.ab, SIGNAL(triggered()),
448                 this, SLOT(ab()));
449
450         _act.open = new QAction("O", this);
451         _act.open->setToolTip("Open [O]");
452         _act.open->setShortcut(Qt::Key_O);
453         _act.open->setShortcutContext(Qt::ApplicationShortcut);
454         _act.open->setIcon( _ico.open );
455         addAction(_act.open);
456         connect(_act.open, SIGNAL(triggered()),
457                 this, SLOT(open_file()));
458
459         _act.quit = new QAction("X", this);
460         _act.quit->setToolTip("Quit [Esc]");
461         _act.quit->setShortcut(Qt::Key_Escape);
462         _act.quit->setShortcutContext(Qt::ApplicationShortcut);
463         _act.quit->setIcon( _ico.quit );
464         addAction(_act.quit);
465         connect(_act.quit, SIGNAL(triggered()),
466                 this, SLOT(close()));
467
468         QList<QKeySequence> inc_shortcuts;
469         inc_shortcuts << Qt::Key_Plus;
470         inc_shortcuts << Qt::Key_Equal;
471         _act.pitch_inc = new QAction("+", this);
472         _act.pitch_inc->setToolTip("Pitch Increase [+]");
473         _act.pitch_inc->setShortcuts(inc_shortcuts);
474         _act.pitch_inc->setShortcutContext(Qt::ApplicationShortcut);
475         _act.pitch_inc->setIcon( _ico.plus );
476         addAction(_act.pitch_inc);
477         connect(_act.pitch_inc, SIGNAL(triggered()),
478                 this, SLOT(pitch_inc()));
479
480         _act.pitch_dec = new QAction("-", this);
481         _act.pitch_dec->setToolTip("Pitch Decrease [-]");
482         _act.pitch_dec->setShortcut(Qt::Key_Minus);
483         _act.pitch_dec->setShortcutContext(Qt::ApplicationShortcut);
484         _act.pitch_dec->setIcon( _ico.minus );
485         addAction(_act.pitch_dec);
486         connect(_act.pitch_dec, SIGNAL(triggered()),
487                 this, SLOT(pitch_dec()));
488
489         _act.speed_inc = new QAction("Faster", this);
490         _act.speed_inc->setToolTip("Play faster [Right Arrow]");
491         _act.speed_inc->setShortcut(Qt::Key_Right);
492         _act.speed_inc->setShortcutContext(Qt::ApplicationShortcut);
493         addAction(_act.speed_inc);
494         connect(_act.speed_inc, SIGNAL(triggered()),
495                 this, SLOT(speed_inc()));
496
497         _act.speed_dec = new QAction("Slower", this);
498         _act.speed_dec->setToolTip("Play slower [Left Arrow]");
499         _act.speed_dec->setShortcut(Qt::Key_Left);
500         _act.speed_dec->setShortcutContext(Qt::ApplicationShortcut);
501         addAction(_act.speed_dec);
502         connect(_act.speed_dec, SIGNAL(triggered()),
503                 this, SLOT(speed_dec()));
504
505         _act.vol_inc = new QAction("Louder", this);
506         _act.vol_inc->setToolTip("Louder [Up]");
507         _act.vol_inc->setShortcut(Qt::Key_Up);
508         _act.vol_inc->setShortcutContext(Qt::ApplicationShortcut);
509         addAction(_act.vol_inc);
510         connect(_act.vol_inc, SIGNAL(triggered()),
511                 this, SLOT(volume_inc()));
512
513         _act.vol_dec = new QAction("Louder", this);
514         _act.vol_dec->setToolTip("Quieter [Down]");
515         _act.vol_dec->setShortcut(Qt::Key_Down);
516         _act.vol_dec->setShortcutContext(Qt::ApplicationShortcut);
517         addAction(_act.vol_dec);
518         connect(_act.vol_dec, SIGNAL(triggered()),
519                 this, SLOT(volume_dec()));
520
521         _act.reset = new QAction("Reset", this);
522         _act.reset->setToolTip("Reset all settings [Home]");
523         _act.reset->setShortcut(Qt::Key_Home);
524         _act.reset->setShortcutContext(Qt::ApplicationShortcut);
525         addAction(_act.reset);
526         connect(_act.reset, SIGNAL(triggered()),
527                 this, SLOT(reset()));
528     }
529
530     void PlayerWidget::_setup_widgets()
531     {
532         _btn.play = new QToolButton(this);
533         _btn.play->setDefaultAction(_act.play_pause);
534         _btn.play->setAutoRaise(true);
535         _btn.play->setContentsMargins(0, 0, 0, 0);
536         _btn.play->setMaximumSize(256, 256);
537
538         _btn.stop = new QToolButton(this);
539         _btn.stop->setDefaultAction(_act.stop);
540         _btn.stop->setAutoRaise(true);
541         _btn.stop->setContentsMargins(0, 0, 0, 0);
542
543         _btn.ab = new QToolButton(this);
544         _btn.ab->setDefaultAction(_act.ab);
545         _btn.ab->setAutoRaise(true);
546         _btn.ab->setContentsMargins(0, 0, 0, 0);
547
548         _btn.open = new QToolButton(this);
549         _btn.open->setDefaultAction(_act.open);
550         _btn.open->setAutoRaise(true);
551         _btn.open->setContentsMargins(0, 0, 0, 0);
552
553         _btn.quit = new QToolButton(this);
554         _btn.quit->setDefaultAction(_act.quit);
555         _btn.quit->setAutoRaise(true);
556         _btn.quit->setContentsMargins(0, 0, 0, 0);
557
558         _btn.pitch_inc = new QToolButton(this);
559         _btn.pitch_inc->setDefaultAction(_act.pitch_inc);
560         _btn.pitch_inc->setAutoRaise(true);
561
562         _btn.pitch_dec = new QToolButton(this);
563         _btn.pitch_dec->setDefaultAction(_act.pitch_dec);
564         _btn.pitch_dec->setAutoRaise(true);
565
566         _status = new StatusWidget(this, &_sizes);
567
568         _stretch = new QSlider(Qt::Horizontal, this);
569         _stretch->setMinimum(0);
570         _stretch->setMaximum(1000);
571         _stretch->setToolTip("Playback Speed [Left/Right Arrow]");
572
573         _volume = new QSlider(Qt::Vertical, this);
574         _volume->setMinimum(0);
575         _volume->setMaximum(1000);
576         _volume->setToolTip("Volume [Up/Down]");
577     }
578
579     void PlayerWidget::_layout_widgets()
580     {
581         int h, w;
582         int margin;
583         int grid;
584
585         h = height();
586         w = width();
587         grid = _sizes.widget_grid_size() + .5;
588         margin = _margin();
589
590         QSize grid_size(grid, grid);
591         int n_ctrl_btns = 6;
592
593         int btn_y = h - margin - grid;
594         int btn_x = margin;
595
596         // CONTROL BAR (BOTTOM)
597         _btn.play->setIconSize(grid_size);
598         _btn.play->setGeometry( btn_x, btn_y, grid, grid );
599         btn_x += grid;
600
601         _btn.stop->setIconSize(grid_size);
602         _btn.stop->setGeometry( btn_x, btn_y, grid, grid );
603         btn_x += grid;
604
605         _btn.ab->setIconSize(grid_size);
606         _btn.ab->setGeometry( btn_x, btn_y, grid, grid );
607         btn_x += grid;
608
609         _stretch->setGeometry( btn_x,
610                                btn_y,
611                                w - 2*margin - n_ctrl_btns*grid,
612                                grid );
613         btn_x += _stretch->width();
614
615         _btn.pitch_dec->setIconSize(grid_size);
616         _btn.pitch_dec->setGeometry( btn_x, btn_y, grid, grid );
617         btn_x += grid;
618
619         _btn.pitch_inc->setIconSize(grid_size);
620         _btn.pitch_inc->setGeometry( btn_x, btn_y, grid, grid );
621         btn_x += grid;
622
623         _btn.open->setIconSize(grid_size);
624         _btn.open->setGeometry( btn_x, btn_y, grid, grid );
625         btn_x += grid;
626
627         // STATUS AND VERT CONTROLS
628         _status->setGeometry( margin,
629                               margin,
630                               w - 2*margin - margin/2 - grid,
631                               h - 2*margin - margin/2 - grid );
632
633         _btn.quit->setIconSize(grid_size);
634         _btn.quit->setGeometry( w - margin - grid,
635                                 margin,
636                                 grid,
637                                 grid );
638         _volume->setGeometry( w - margin - grid,
639                               margin + grid,
640                               grid,
641                               h - 2*margin - 2*grid );
642     }
643
644     void PlayerWidget::_setup_signals_and_slots()
645     {
646         _engine_callback.reset(new Details::PlayerWidgetMessageCallback(this));
647         _engine.reset(new Engine);
648         _engine->subscribe_errors(_engine_callback.get());
649         _engine->subscribe_messages(_engine_callback.get());
650
651         connect(_stretch, SIGNAL(sliderMoved(int)),
652                 this, SLOT(stretch(int)));
653         connect(_status, SIGNAL(locate(float)),
654                 this, SLOT(locate(float)));
655         connect(_volume, SIGNAL(sliderMoved(int)),
656                 this, SLOT(volume(int)));
657
658         QTimer* timer = new QTimer(this);
659         timer->setSingleShot(false);
660         timer->setInterval(200);
661         connect(timer, SIGNAL(timeout()),
662                 this, SLOT(update_time()));
663         timer->start();
664     }
665
666     float PlayerWidget::_margin()
667     {
668         return _sizes.thicker_line() * 3.0;
669     }
670
671     /**
672      * \selects correct cursor.
673      *
674      * Along left and top edges:  move window.
675      * Along bottom and right edges: resize window.
676      *
677      */
678     Qt::CursorShape PlayerWidget::_which_cursor(const QPoint& pos)
679     {
680         bool left = false;
681         bool right = false;
682         bool top = false;
683         bool bottom = false;
684         Qt::CursorShape rv = Qt::ArrowCursor;
685
686         int margin = _sizes.thicker_line() * 3 / 2;
687
688         if( pos.x() <= margin ) left = true;
689         if( pos.x() >= width()-margin ) right = true;
690         if( pos.y() <= margin ) top = true;
691         if( pos.y() >= height()-margin ) bottom = true;
692
693         // Check for corners
694         int rad = 2*margin;
695         if( pos.x() <= rad ) {
696             if( pos.y() <= rad ) {
697                 left = true;
698                 top = true;
699             } else if( pos.y() >= height()-rad ) {
700                 left = true;
701                 bottom = true;
702             }
703         } else if( pos.x() >= width()-rad ) {
704             if( pos.y() <= rad ) {
705                 right = true;
706                 top = true;
707             } else if( pos.y() >= height()-rad ) {
708                 right = true;
709                 bottom = true;
710             }
711         }
712
713         if( left ) {
714             rv = Qt::SizeAllCursor;
715         } else if( right ) {
716             if( top ) {
717                 rv = Qt::SizeAllCursor;
718             } else if(bottom) {
719                 rv = Qt::SizeFDiagCursor;
720             } else {
721                 rv = Qt::SizeHorCursor;
722             }
723         } else if( top ) {
724             rv = Qt::SizeAllCursor;
725         } else if( bottom ) {
726             rv = Qt::SizeVerCursor;
727         }
728
729         return rv;
730     }
731
732     /**
733      * Evokes resize events based on cursor type.
734      *
735      * Note the assumptions made with _which_cursor();
736      */
737     void PlayerWidget::_drag_resize(Qt::CursorShape cur, QMouseEvent* ev)
738     {
739         QRect win(pos().x(), pos().y(), width(), height());
740         QPoint gps = ev->globalPos();
741
742         switch(cur) {
743         case Qt::SizeAllCursor:
744             win.translate(gps - _anchor);
745             _anchor = gps;
746             break;
747         case Qt::SizeHorCursor:
748             // Right edge
749             win.setRight( gps.x() );
750             break;
751         case Qt::SizeVerCursor:
752             win.setBottom( gps.y() );
753             break;
754         case Qt::SizeFDiagCursor:
755             win.setBottomRight( gps );
756             break;
757         case Qt::SizeBDiagCursor:
758             // Not used
759             break;
760         default:
761             break;
762         }
763
764         setGeometry(win);
765     }
766
767 } // namespace StretchPlayer