]> git.sesse.net Git - vlc/blob - modules/gui/qt4/util/customwidgets.cpp
1a00fe00affc0cd5a9f6ef9992a2afc3030ed4aa
[vlc] / modules / gui / qt4 / util / customwidgets.cpp
1 /*****************************************************************************
2  * customwidgets.cpp: Custom widgets
3  ****************************************************************************
4  * Copyright (C) 2006-2011 the VideoLAN team
5  * Copyright (C) 2004 Daniel Molkentin <molkentin@kde.org>
6  * $Id$
7  *
8  * Authors: ClĂ©ment Stenac <zorglub@videolan.org>
9  * The "ClickLineEdit" control is based on code by  Daniel Molkentin
10  * <molkentin@kde.org> for libkdepim
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include "customwidgets.hpp"
32 #include "qt4.hpp"               /* needed for qtr,  but not necessary */
33
34 #include <QPainter>
35 #include <QRect>
36 #include <QKeyEvent>
37 #include <QWheelEvent>
38 #include <QPixmap>
39 #include <QApplication>
40 #include <vlc_keys.h>
41
42 QFramelessButton::QFramelessButton( QWidget *parent )
43                     : QPushButton( parent )
44 {
45     setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
46 }
47
48 void QFramelessButton::paintEvent( QPaintEvent * )
49 {
50     QPainter painter( this );
51     QPixmap pix = icon().pixmap( size() );
52     QPoint pos( (width() - pix.width()) / 2, (height() - pix.height()) / 2 );
53     painter.drawPixmap( QRect( pos.x(), pos.y(), pix.width(), pix.height() ), pix );
54 }
55
56 QElidingLabel::QElidingLabel( const QString &s, Qt::TextElideMode mode, QWidget * parent )
57                  : QLabel( s, parent ), elideMode( mode )
58 { }
59
60 void QElidingLabel::setElideMode( Qt::TextElideMode mode )
61 {
62     elideMode = mode;
63     repaint();
64 }
65
66 void QElidingLabel::paintEvent( QPaintEvent * )
67 {
68     QPainter p( this );
69     int space = frameWidth() + margin();
70     QRect r = rect().adjusted( space, space, -space, -space );
71     p.drawText( r, fontMetrics().elidedText( text(), elideMode, r.width() ), alignment() );
72 }
73
74 QString QVLCDebugLevelSpinBox::textFromValue( int v ) const
75 {
76     QString const texts[] = {
77     /* Note that min level 0 is 'errors' in Qt Ui
78        FIXME: fix debug levels accordingly to documentation */
79     /*  qtr("infos"),*/
80         qtr("errors"),
81         qtr("warnings"),
82         qtr("debug")
83     };
84     if ( v < 0 ) v = 0;
85     if ( v >= 2 ) v = 2;
86
87     return QString( "%1 (%2)" ).arg( v ).arg( texts[v] );
88 }
89
90 /***************************************************************************
91  * Hotkeys converters
92  ***************************************************************************/
93 int qtKeyModifiersToVLC( QInputEvent* e )
94 {
95     int i_keyModifiers = 0;
96     if( e->modifiers() & Qt::ShiftModifier ) i_keyModifiers |= KEY_MODIFIER_SHIFT;
97     if( e->modifiers() & Qt::AltModifier ) i_keyModifiers |= KEY_MODIFIER_ALT;
98     if( e->modifiers() & Qt::ControlModifier ) i_keyModifiers |= KEY_MODIFIER_CTRL;
99     if( e->modifiers() & Qt::MetaModifier ) i_keyModifiers |= KEY_MODIFIER_META;
100     return i_keyModifiers;
101 }
102
103 typedef struct
104 {
105     int      qt;
106     uint32_t vlc;
107 } vlc_qt_key_t;
108
109 static const vlc_qt_key_t keys[] =
110 {
111     { Qt::Key_Escape,                KEY_ESC },
112     { Qt::Key_Tab,                   '\t', },
113     // Qt::Key_Backtab
114     { Qt::Key_Backspace,             '\b' },
115     { Qt::Key_Return,                '\r' },
116     { Qt::Key_Enter,                 '\r' }, // numeric pad
117     { Qt::Key_Insert,                KEY_INSERT },
118     { Qt::Key_Delete,                KEY_DELETE },
119     // Qt::Key_Pause
120     // Qt::Key_Print
121     // Qt::Key_SysReq
122     // Qt::Key_Clear
123     { Qt::Key_Home,                  KEY_HOME },
124     { Qt::Key_End,                   KEY_END },
125     { Qt::Key_Left,                  KEY_LEFT },
126     { Qt::Key_Up,                    KEY_UP },
127     { Qt::Key_Right,                 KEY_RIGHT },
128     { Qt::Key_Down,                  KEY_DOWN },
129     { Qt::Key_PageUp,                KEY_PAGEUP },
130     { Qt::Key_PageDown,              KEY_PAGEDOWN },
131     // Qt::Key_Shift
132     // Qt::Key_Control
133     // Qt::Key_Meta
134     // Qt::Key_Alt
135     // Qt::Key_CapsLock
136     // Qt::Key_NumLock
137     // Qt::Key_ScrollLock
138     /* F1 - F35 - Qt goes to F35, VLC stops at F12 */
139     { Qt::Key_F1,                    KEY_F1 },
140     { Qt::Key_F2,                    KEY_F2 },
141     { Qt::Key_F3,                    KEY_F3 },
142     { Qt::Key_F4,                    KEY_F4 },
143     { Qt::Key_F5,                    KEY_F5 },
144     { Qt::Key_F6,                    KEY_F6 },
145     { Qt::Key_F7,                    KEY_F7 },
146     { Qt::Key_F8,                    KEY_F8 },
147     { Qt::Key_F9,                    KEY_F9 },
148     { Qt::Key_F10,                   KEY_F10 },
149     { Qt::Key_F11,                   KEY_F11 },
150     { Qt::Key_F12,                   KEY_F12 },
151     // Qt::Key_Super_L
152     // Qt::Key_Super_R
153     { Qt::Key_Menu,                  KEY_MENU },
154     // Qt::Key_Hyper_L
155     // Qt::Key_Hyper_R
156     // Qt::Key_Help
157     // Qt::Key_Direction_L
158     // Qt::Key_Direction_R
159
160     // Qt::Key_Multi_key
161     // Qt::Key_Codeinput
162     // Qt::Key_SingleCandidate
163     // Qt::Key_MultipleCandidate
164     // Qt::Key_PreviousCandidate
165     // Qt::Key_Mode_switch
166     // Qt::Key_Kanji
167     // Qt::Key_Muhenkan
168     // Qt::Key_Henkan
169     // Qt::Key_Romaji
170     // Qt::Key_Hiragana
171     // Qt::Key_Katakana
172     // Qt::Key_Hiragana_Katakana
173     // Qt::Key_Zenkaku
174     // Qt::Key_Hankaku
175     // Qt::Key_Zenkaku_Hankaku
176     // Qt::Key_Touroku
177     // Qt::Key_Massyo
178     // Qt::Key_Kana_Lock
179     // Qt::Key_Kana_Shift
180     // Qt::Key_Eisu_Shift
181     // Qt::Key_Eisu_toggle
182     // Qt::Key_Hangul
183     // Qt::Key_Hangul_Start
184     // Qt::Key_Hangul_End
185     // Qt::Key_Hangul_Hanja
186     // Qt::Key_Hangul_Jamo
187     // Qt::Key_Hangul_Romaja
188     // Qt::Key_Hangul_Jeonja
189     // Qt::Key_Hangul_Banja
190     // Qt::Key_Hangul_PreHanja
191     // Qt::Key_Hangul_PostHanja
192     // Qt::Key_Hangul_Special
193     // Qt::Key_Dead_Grave
194     // Qt::Key_Dead_Acute
195     // Qt::Key_Dead_Circumflex
196     // Qt::Key_Dead_Tilde
197     // Qt::Key_Dead_Macron
198     // Qt::Key_Dead_Breve
199     // Qt::Key_Dead_Abovedot
200     // Qt::Key_Dead_Diaeresis
201     // Qt::Key_Dead_Abovering
202     // Qt::Key_Dead_Doubleacute
203     // Qt::Key_Dead_Caron
204     // Qt::Key_Dead_Cedilla
205     // Qt::Key_Dead_Ogonek
206     // Qt::Key_Dead_Iota
207     // Qt::Key_Dead_Voiced_Sound
208     // Qt::Key_Dead_Semivoiced_Sound
209     // Qt::Key_Dead_Belowdot
210     // Qt::Key_Dead_Hook
211     // Qt::Key_Dead_Horn
212     { Qt::Key_Back,                  KEY_BROWSER_BACK },
213     { Qt::Key_Forward,               KEY_BROWSER_FORWARD },
214     { Qt::Key_Stop,                  KEY_BROWSER_STOP },
215     { Qt::Key_Refresh,               KEY_BROWSER_REFRESH },
216     { Qt::Key_VolumeDown,            KEY_VOLUME_DOWN },
217     { Qt::Key_VolumeMute,            KEY_VOLUME_MUTE },
218     { Qt::Key_VolumeUp,              KEY_VOLUME_UP },
219     // Qt::Key_BassBoost
220     // Qt::Key_BassUp
221     // Qt::Key_BassDown
222     // Qt::Key_TrebleUp
223     // Qt::Key_TrebleDown
224     { Qt::Key_MediaPlay,             KEY_MEDIA_PLAY_PAUSE },
225     { Qt::Key_MediaStop,             KEY_MEDIA_STOP },
226     { Qt::Key_MediaPrevious,         KEY_MEDIA_PREV_TRACK },
227     { Qt::Key_MediaNext,             KEY_MEDIA_NEXT_TRACK },
228     // Qt::Key_MediaRecord
229     { Qt::Key_HomePage,              KEY_BROWSER_HOME },
230     { Qt::Key_Favorites,             KEY_BROWSER_FAVORITES },
231     { Qt::Key_Search,                KEY_BROWSER_SEARCH },
232     // Qt::Key_Standby
233     // Qt::Key_OpenUrl
234     // Qt::Key_LaunchMail
235     // Qt::Key_LaunchMedia
236     /* Qt::Key_Launch0 through Qt::Key_LaunchF */
237     /* ... */
238     { Qt::Key_Reload,                KEY_BROWSER_REFRESH },
239 };
240
241 static int keycmp( const void *a, const void *b )
242 {
243     const int *q = (const int *)a;
244     const vlc_qt_key_t *m = (const vlc_qt_key_t *)b;
245
246     return *q - m->qt;
247 }
248
249 int qtEventToVLCKey( QKeyEvent *e )
250 {
251     int qtk = e->key();
252     uint32_t i_vlck = 0;
253
254     if( qtk <= 0xff )
255     {
256         /* VLC and X11 use lowercase whereas Qt uses uppercase, this
257          * method should be equal to towlower in case of latin1 */
258         if( qtk >= 'A' && qtk <= 'Z' ) i_vlck = qtk+32;
259         else if( qtk >= 0xC0 && qtk <= 0xDE && qtk != 0xD7) i_vlck = qtk+32;
260         else i_vlck = qtk;
261     }
262     else
263     {
264         const vlc_qt_key_t *map;
265
266         map = (const vlc_qt_key_t *)
267               bsearch( &qtk, (const void *)keys, sizeof(keys)/sizeof(keys[0]),
268                        sizeof(*keys), keycmp );
269         if( map != NULL )
270             i_vlck = map->vlc;
271     }
272
273     /* Handle modifiers */
274     i_vlck |= qtKeyModifiersToVLC( e );
275     return i_vlck;
276 }
277
278 int qtWheelEventToVLCKey( QWheelEvent *e )
279 {
280     int i_vlck = 0;
281     /* Handle modifiers */
282     i_vlck |= qtKeyModifiersToVLC( e );
283     if ( e->delta() > 0 )
284         i_vlck |= KEY_MOUSEWHEELUP;
285     else
286         i_vlck |= KEY_MOUSEWHEELDOWN;
287     return i_vlck;
288 }
289
290 QString VLCKeyToString( unsigned val )
291 {
292     char *base = vlc_keycode2str (val, true);
293     if (base == NULL)
294         return qtr( "Unset" );
295
296     QString r = qfu( base );
297
298     free( base );
299     return r;
300 }
301
302 PixmapAnimator::PixmapAnimator( QWidget *parent, QList<QString> frames )
303     : QAbstractAnimation( parent ), current_frame( 0 )
304 {
305     foreach( QString name, frames )
306         pixmaps.append( new QPixmap( name ) );
307     currentPixmap = pixmaps.at( 0 );
308     setFps( frames.count() ); /* default to 1 sec loop */
309     setLoopCount( -1 );
310 }
311
312 void PixmapAnimator::updateCurrentTime( int msecs )
313 {
314     int i = msecs / interval;
315     if ( i >= pixmaps.count() ) i = pixmaps.count() - 1; /* roundings */
316     if ( i != current_frame )
317     {
318         current_frame = i;
319         currentPixmap = pixmaps.at( current_frame );
320         emit pixmapReady( *currentPixmap );
321     }
322 }
323
324 /* Animated Icon implementation */
325 SpinningIcon::SpinningIcon( QWidget *parent ) : QLabel( parent )
326 {
327     QList<QString> frames;
328     frames << ":/util/wait1";
329     frames << ":/util/wait2";
330     frames << ":/util/wait3";
331     frames << ":/util/wait4";
332     animator = new PixmapAnimator( this, frames );
333     CONNECT( animator, pixmapReady( const QPixmap & ), this, setPixmap( const QPixmap & ) );
334     CONNECT( animator, pixmapReady( const QPixmap & ), this, repaint() );
335     setScaledContents( true );
336     setFixedSize( 16, 16 );
337     animator->setCurrentTime( 0 );
338 }
339
340 QToolButtonExt::QToolButtonExt(QWidget *parent, int ms )
341     : QToolButton( parent ),
342       shortClick( false ),
343       longClick( false )
344 {
345     setAutoRepeat( true );
346     /* default to twice the doubleclick delay */
347     setAutoRepeatDelay( ( ms > 0 )? ms : 2 * QApplication::doubleClickInterval() );
348     setAutoRepeatInterval( 100 );
349     connect( this, SIGNAL(released()), this, SLOT(releasedSlot()) );
350     connect( this, SIGNAL(clicked()), this, SLOT(clickedSlot()) );
351 }
352
353 /* table illustrating the different scenarios and the events generated
354  * ====================
355  *
356  *  event     isDown()
357  *
358  *  released  false   }
359  *  clicked   false   }= short click
360  *
361  *  released  false    = cancelled click (mouse released outside of button area,
362  *                                        before long click delay kicks in)
363  *
364  *  released  true    }
365  *  clicked   true    }= long click (multiple of these generated)
366  *  released  false    = stop long click (mouse released / moved outside of
367  *                                        button area)
368  * (clicked   false)   = stop long click (additional event if mouse released
369  *                                        inside of button area)
370  */
371
372 void QToolButtonExt::releasedSlot()
373 {
374     if( isDown() )
375     {
376         // we are beginning a long click
377         longClick = true;
378         shortClick = false;
379     }
380     else
381     {
382         if( longClick )
383         {
384             // we are stopping a long click
385             longClick = false;
386             shortClick = false;
387         }
388         else
389         {
390             // we are generating a short click
391             longClick = false;
392             shortClick = true;
393         }
394     }
395 }
396
397 void QToolButtonExt::clickedSlot()
398 {
399     if( longClick )
400         emit longClicked();
401     else if( shortClick )
402         emit shortClicked();
403 }
404
405 YesNoCheckBox::YesNoCheckBox( QWidget *parent ) : QCheckBox( parent )
406 {
407     setEnabled( false );
408     setStyleSheet("\
409                   QCheckBox::indicator:unchecked:hover,\
410                   QCheckBox::indicator:unchecked {\
411                       image: url(:/menu/quit);\
412                   }\
413                   QCheckBox::indicator:checked:hover,\
414                   QCheckBox::indicator:checked {\
415                       image: url(:/valid);\
416                   }\
417         ");
418 }