]> git.sesse.net Git - vlc/blob - modules/gui/qt4/util/customwidgets.cpp
Qt: fix copyright years
[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     // Qt::Key_MediaLast
238 };
239
240 static int keycmp( const void *a, const void *b )
241 {
242     const int *q = (const int *)a;
243     const vlc_qt_key_t *m = (const vlc_qt_key_t *)b;
244
245     return *q - m->qt;
246 }
247
248 int qtEventToVLCKey( QKeyEvent *e )
249 {
250     int qtk = e->key();
251     uint32_t i_vlck = 0;
252
253     if( qtk <= 0xff )
254     {
255         /* VLC and X11 use lowercase whereas Qt uses uppercase, this
256          * method should be equal to towlower in case of latin1 */
257         if( qtk >= 'A' && qtk <= 'Z' ) i_vlck = qtk+32;
258         else if( qtk >= 0xC0 && qtk <= 0xDE && qtk != 0xD7) i_vlck = qtk+32;
259         else i_vlck = qtk;
260     }
261     else
262     {
263         const vlc_qt_key_t *map;
264
265         map = (const vlc_qt_key_t *)
266               bsearch( &qtk, (const void *)keys, sizeof(keys)/sizeof(keys[0]),
267                        sizeof(*keys), keycmp );
268         if( map != NULL )
269             i_vlck = map->vlc;
270     }
271
272     /* Handle modifiers */
273     i_vlck |= qtKeyModifiersToVLC( e );
274     return i_vlck;
275 }
276
277 int qtWheelEventToVLCKey( QWheelEvent *e )
278 {
279     int i_vlck = 0;
280     /* Handle modifiers */
281     i_vlck |= qtKeyModifiersToVLC( e );
282     if ( e->delta() > 0 )
283         i_vlck |= KEY_MOUSEWHEELUP;
284     else
285         i_vlck |= KEY_MOUSEWHEELDOWN;
286     return i_vlck;
287 }
288
289 QString VLCKeyToString( unsigned val )
290 {
291     char *base = vlc_keycode2str (val);
292     if (base == NULL)
293         return qtr( "Unset" );
294
295     QString r = qfu( base );
296
297     free( base );
298     return r;
299 }
300
301
302 /* Animated Icon implementation */
303
304 AnimatedIcon::AnimatedIcon( QWidget *parent )
305     : QLabel( parent ), mTimer( this ), mIdleFrame( NULL )
306 {
307     mCurrentFrame = mRemainingLoops = 0;
308     connect( &mTimer, SIGNAL( timeout() ), this, SLOT( onTimerTick() ) );
309 }
310
311 AnimatedIcon::~AnimatedIcon()
312 {
313     // We don't need to destroy the timer, he's our child
314     delete mIdleFrame;
315     foreach( QPixmap *frame, mFrames )
316         delete frame;
317 }
318
319 void AnimatedIcon::addFrame( const QPixmap &pxm, int index )
320 {
321     if( index == 0 )
322     {
323         // Replace idle frame
324         delete mIdleFrame;
325         mIdleFrame = new QPixmap( pxm );
326         setPixmap( *mIdleFrame );
327         return;
328     }
329     QPixmap *copy = new QPixmap( pxm );
330     mFrames.insert( ( index < 0 || index > mFrames.count() ) ? mFrames.count() :
331                     index, copy );
332     if( !pixmap() )
333         setPixmap( *copy );
334 }
335
336 void AnimatedIcon::play( int loops, int interval )
337 {
338     if( interval < 20 )
339     {
340         interval = 20;
341     }
342
343     if( !mIdleFrame && (mFrames.isEmpty() || loops != 0 ) )
344     {
345         return;
346     }
347
348     if( loops == 0 )
349     {
350         // Stop playback
351         mCurrentFrame = mRemainingLoops = 0;
352         mTimer.stop();
353         setPixmap( mIdleFrame != NULL ? *mIdleFrame : *mFrames.last() );
354         return;
355     }
356
357     if( loops <= -1 )
358         loops = -1;
359
360     mCurrentFrame = 1;
361     mRemainingLoops = loops;
362     mTimer.start( interval );
363     setPixmap( *mFrames.first() );
364 }
365
366 // private slot
367 void AnimatedIcon::onTimerTick()
368 {
369     //assert( !mFrames.isEmpty() );
370     if( ++mCurrentFrame > mFrames.count() )
371     {
372         if( mRemainingLoops != -1 )
373         {
374             if( --mRemainingLoops == 0 )
375             {
376                 mTimer.stop();
377                 setPixmap( mIdleFrame ? *mIdleFrame : *mFrames.last() );
378                 return;
379             }
380         }
381         mCurrentFrame = 1;
382     }
383     //assert( mCurrentFrame >= 1 && mCurrentFrame <= mFrames.count() );
384     setPixmap( *mFrames.at( mCurrentFrame - 1 ) );
385 }
386
387
388 /* SpinningIcon implementation */
389
390 SpinningIcon::SpinningIcon( QWidget *parent, bool noIdleFrame )
391     : AnimatedIcon( parent )
392 {
393     if( noIdleFrame )
394         addFrame( QPixmap(), 0 );
395     else
396         addFrame( QPixmap( ":/util/wait0" ), 0 );
397     addFrame( QPixmap( ":/util/wait1" ) );
398     addFrame( QPixmap( ":/util/wait2" ) );
399     addFrame( QPixmap( ":/util/wait3" ) );
400     addFrame( QPixmap( ":/util/wait4" ) );
401     setScaledContents( true );
402     setFixedSize( 16, 16 );
403 }
404
405 QToolButtonExt::QToolButtonExt(QWidget *parent, int ms )
406     : QToolButton( parent ),
407       shortClick( false ),
408       longClick( false )
409 {
410     setAutoRepeat( true );
411     /* default to twice the doubleclick delay */
412     setAutoRepeatDelay( ( ms > 0 )? ms : 2 * QApplication::doubleClickInterval() );
413     setAutoRepeatInterval( 100 );
414     connect( this, SIGNAL(released()), this, SLOT(releasedSlot()) );
415     connect( this, SIGNAL(clicked()), this, SLOT(clickedSlot()) );
416 }
417
418 /* table illustrating the different scenarios and the events generated
419  * ====================
420  *
421  *  event     isDown()
422  *
423  *  released  false   }
424  *  clicked   false   }= short click
425  *
426  *  released  false    = cancelled click (mouse released outside of button area,
427  *                                        before long click delay kicks in)
428  *
429  *  released  true    }
430  *  clicked   true    }= long click (multiple of these generated)
431  *  released  false    = stop long click (mouse released / moved outside of
432  *                                        button area)
433  * (clicked   false)   = stop long click (additional event if mouse released
434  *                                        inside of button area)
435  */
436
437 void QToolButtonExt::releasedSlot()
438 {
439     if( isDown() )
440     {
441         // we are beginning a long click
442         longClick = true;
443         shortClick = false;
444     }
445     else
446     {
447         if( longClick )
448         {
449             // we are stopping a long click
450             longClick = false;
451             shortClick = false;
452         }
453         else
454         {
455             // we are generating a short click
456             longClick = false;
457             shortClick = true;
458         }
459     }
460 }
461
462 void QToolButtonExt::clickedSlot()
463 {
464     if( longClick )
465         emit longClicked();
466     else if( shortClick )
467         emit shortClicked();
468 }