]> git.sesse.net Git - vlc/blob - modules/gui/qt4/util/customwidgets.cpp
Qt: rename utility classes
[vlc] / modules / gui / qt4 / util / customwidgets.cpp
1 /*****************************************************************************
2  * customwidgets.cpp: Custom widgets
3  ****************************************************************************
4  * Copyright (C) 2006 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 and CONNECT, but not necessary */
33
34 #include <QPainter>
35 #include <QRect>
36 #include <QKeyEvent>
37 #include <QWheelEvent>
38 #include <QPixmap>
39 #include <vlc_keys.h>
40
41 QFramelessButton::QFramelessButton( QWidget *parent )
42                     : QPushButton( parent )
43 {
44     setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
45 }
46
47 void QFramelessButton::paintEvent( QPaintEvent * )
48 {
49     QPainter painter( this );
50     QPixmap pix = icon().pixmap( size() );
51     QPoint pos( (width() - pix.width()) / 2, (height() - pix.height()) / 2 );
52     painter.drawPixmap( QRect( pos.x(), pos.y(), pix.width(), pix.height() ), pix );
53 }
54
55 QElidingLabel::QElidingLabel( const QString &s, Qt::TextElideMode mode, QWidget * parent )
56                  : elideMode( mode ), QLabel( s, parent )
57 { }
58
59 void QElidingLabel::setElideMode( Qt::TextElideMode mode )
60 {
61     elideMode = mode;
62     repaint();
63 }
64
65 void QElidingLabel::paintEvent( QPaintEvent * event )
66 {
67     QPainter p( this );
68     int space = frameWidth() + margin();
69     QRect r = rect().adjusted( space, space, -space, -space );
70     p.drawText( r, fontMetrics().elidedText( text(), elideMode, r.width() ), alignment() );
71 }
72
73 QString QVLCDebugLevelSpinBox::textFromValue( int v ) const
74 {
75     QString const texts[] = {
76     /* Note that min level 0 is 'errors' in Qt Ui
77        FIXME: fix debug levels accordingly to documentation */
78     /*  qtr("infos"),*/
79         qtr("errors"),
80         qtr("warnings"),
81         qtr("debug")
82     };
83     if ( v < 0 ) v = 0;
84     if ( v >= 2 ) v = 2;
85
86     return QString( "%1 (%2)" ).arg( v ).arg( texts[v] );
87 }
88
89 /***************************************************************************
90  * Hotkeys converters
91  ***************************************************************************/
92 int qtKeyModifiersToVLC( QInputEvent* e )
93 {
94     int i_keyModifiers = 0;
95     if( e->modifiers() & Qt::ShiftModifier ) i_keyModifiers |= KEY_MODIFIER_SHIFT;
96     if( e->modifiers() & Qt::AltModifier ) i_keyModifiers |= KEY_MODIFIER_ALT;
97     if( e->modifiers() & Qt::ControlModifier ) i_keyModifiers |= KEY_MODIFIER_CTRL;
98     if( e->modifiers() & Qt::MetaModifier ) i_keyModifiers |= KEY_MODIFIER_META;
99     return i_keyModifiers;
100 }
101
102 typedef struct
103 {
104     int      qt;
105     uint32_t vlc;
106 } vlc_qt_key_t;
107
108 static const vlc_qt_key_t keys[] =
109 {
110     { Qt::Key_Escape,                KEY_ESC },
111     { Qt::Key_Tab,                   '\t', },
112     // Qt::Key_Backtab
113     { Qt::Key_Backspace,             '\b' },
114     { Qt::Key_Return,                '\r' },
115     { Qt::Key_Enter,                 '\r' }, // numeric pad
116     { Qt::Key_Insert,                KEY_INSERT },
117     { Qt::Key_Delete,                KEY_DELETE },
118     // Qt::Key_Pause
119     // Qt::Key_Print
120     // Qt::Key_SysReq
121     // Qt::Key_Clear
122     { Qt::Key_Home,                  KEY_HOME },
123     { Qt::Key_End,                   KEY_END },
124     { Qt::Key_Left,                  KEY_LEFT },
125     { Qt::Key_Up,                    KEY_UP },
126     { Qt::Key_Right,                 KEY_RIGHT },
127     { Qt::Key_Down,                  KEY_DOWN },
128     { Qt::Key_PageUp,                KEY_PAGEUP },
129     { Qt::Key_PageDown,              KEY_PAGEDOWN },
130     // Qt::Key_Shift
131     // Qt::Key_Control
132     // Qt::Key_Meta
133     // Qt::Key_Alt
134     // Qt::Key_CapsLock
135     // Qt::Key_NumLock
136     // Qt::Key_ScrollLock
137     /* F1 - F35 - Qt goes to F35, VLC stops at F12 */
138     { Qt::Key_F1,                    KEY_F1 },
139     { Qt::Key_F2,                    KEY_F2 },
140     { Qt::Key_F3,                    KEY_F3 },
141     { Qt::Key_F4,                    KEY_F4 },
142     { Qt::Key_F5,                    KEY_F5 },
143     { Qt::Key_F6,                    KEY_F6 },
144     { Qt::Key_F7,                    KEY_F7 },
145     { Qt::Key_F8,                    KEY_F8 },
146     { Qt::Key_F9,                    KEY_F9 },
147     { Qt::Key_F10,                   KEY_F10 },
148     { Qt::Key_F11,                   KEY_F11 },
149     { Qt::Key_F12,                   KEY_F12 },
150     // Qt::Key_Super_L
151     // Qt::Key_Super_R
152     { Qt::Key_Menu,                  KEY_MENU },
153     // Qt::Key_Hyper_L
154     // Qt::Key_Hyper_R
155     // Qt::Key_Help
156     // Qt::Key_Direction_L
157     // Qt::Key_Direction_R
158
159     // Qt::Key_Multi_key
160     // Qt::Key_Codeinput
161     // Qt::Key_SingleCandidate
162     // Qt::Key_MultipleCandidate
163     // Qt::Key_PreviousCandidate
164     // Qt::Key_Mode_switch
165     // Qt::Key_Kanji
166     // Qt::Key_Muhenkan
167     // Qt::Key_Henkan
168     // Qt::Key_Romaji
169     // Qt::Key_Hiragana
170     // Qt::Key_Katakana
171     // Qt::Key_Hiragana_Katakana
172     // Qt::Key_Zenkaku
173     // Qt::Key_Hankaku
174     // Qt::Key_Zenkaku_Hankaku
175     // Qt::Key_Touroku
176     // Qt::Key_Massyo
177     // Qt::Key_Kana_Lock
178     // Qt::Key_Kana_Shift
179     // Qt::Key_Eisu_Shift
180     // Qt::Key_Eisu_toggle
181     // Qt::Key_Hangul
182     // Qt::Key_Hangul_Start
183     // Qt::Key_Hangul_End
184     // Qt::Key_Hangul_Hanja
185     // Qt::Key_Hangul_Jamo
186     // Qt::Key_Hangul_Romaja
187     // Qt::Key_Hangul_Jeonja
188     // Qt::Key_Hangul_Banja
189     // Qt::Key_Hangul_PreHanja
190     // Qt::Key_Hangul_PostHanja
191     // Qt::Key_Hangul_Special
192     // Qt::Key_Dead_Grave
193     // Qt::Key_Dead_Acute
194     // Qt::Key_Dead_Circumflex
195     // Qt::Key_Dead_Tilde
196     // Qt::Key_Dead_Macron
197     // Qt::Key_Dead_Breve
198     // Qt::Key_Dead_Abovedot
199     // Qt::Key_Dead_Diaeresis
200     // Qt::Key_Dead_Abovering
201     // Qt::Key_Dead_Doubleacute
202     // Qt::Key_Dead_Caron
203     // Qt::Key_Dead_Cedilla
204     // Qt::Key_Dead_Ogonek
205     // Qt::Key_Dead_Iota
206     // Qt::Key_Dead_Voiced_Sound
207     // Qt::Key_Dead_Semivoiced_Sound
208     // Qt::Key_Dead_Belowdot
209     // Qt::Key_Dead_Hook
210     // Qt::Key_Dead_Horn
211     { Qt::Key_Back,                  KEY_BROWSER_BACK },
212     { Qt::Key_Forward,               KEY_BROWSER_FORWARD },
213     { Qt::Key_Stop,                  KEY_BROWSER_STOP },
214     { Qt::Key_Refresh,               KEY_BROWSER_REFRESH },
215     { Qt::Key_VolumeDown,            KEY_VOLUME_DOWN },
216     { Qt::Key_VolumeMute,            KEY_VOLUME_MUTE },
217     { Qt::Key_VolumeUp,              KEY_VOLUME_UP },
218     // Qt::Key_BassBoost
219     // Qt::Key_BassUp
220     // Qt::Key_BassDown
221     // Qt::Key_TrebleUp
222     // Qt::Key_TrebleDown
223     { Qt::Key_MediaPlay,             KEY_MEDIA_PLAY_PAUSE },
224     { Qt::Key_MediaStop,             KEY_MEDIA_STOP },
225     { Qt::Key_MediaPrevious,         KEY_MEDIA_PREV_TRACK },
226     { Qt::Key_MediaNext,             KEY_MEDIA_NEXT_TRACK },
227     // Qt::Key_MediaRecord
228     { Qt::Key_HomePage,              KEY_BROWSER_HOME },
229     { Qt::Key_Favorites,             KEY_BROWSER_FAVORITES },
230     { Qt::Key_Search,                KEY_BROWSER_SEARCH },
231     // Qt::Key_Standby
232     // Qt::Key_OpenUrl
233     // Qt::Key_LaunchMail
234     // Qt::Key_LaunchMedia
235     /* Qt::Key_Launch0 through Qt::Key_LaunchF */
236     // Qt::Key_MediaLast
237 };
238
239 static int keycmp( const void *a, const void *b )
240 {
241     const int *q = (const int *)a;
242     const vlc_qt_key_t *m = (const vlc_qt_key_t *)b;
243
244     return *q - m->qt;
245 }
246
247 int qtEventToVLCKey( QKeyEvent *e )
248 {
249     int qtk = e->key();
250     uint32_t i_vlck = 0;
251
252     if( qtk <= 0xff )
253     {
254         /* VLC and X11 use lowercase whereas Qt uses uppercase, this
255          * method should be equal to towlower in case of latin1 */
256         if( qtk >= 'A' && qtk <= 'Z' ) i_vlck = qtk+32;
257         else if( qtk >= 0xC0 && qtk <= 0xDE && qtk != 0xD7) i_vlck = qtk+32;
258         else i_vlck = qtk;
259     }
260     else
261     {
262         const vlc_qt_key_t *map;
263
264         map = (const vlc_qt_key_t *)
265               bsearch( &qtk, (const void *)keys, sizeof(keys)/sizeof(keys[0]),
266                        sizeof(*keys), keycmp );
267         if( map != NULL )
268             i_vlck = map->vlc;
269     }
270
271     /* Handle modifiers */
272     i_vlck |= qtKeyModifiersToVLC( e );
273     return i_vlck;
274 }
275
276 int qtWheelEventToVLCKey( QWheelEvent *e )
277 {
278     int i_vlck = 0;
279     /* Handle modifiers */
280     i_vlck |= qtKeyModifiersToVLC( e );
281     if ( e->delta() > 0 )
282         i_vlck |= KEY_MOUSEWHEELUP;
283     else
284         i_vlck |= KEY_MOUSEWHEELDOWN;
285     return i_vlck;
286 }
287
288 QString VLCKeyToString( unsigned val )
289 {
290     char *base = vlc_keycode2str (val);
291     if (base == NULL)
292         return qtr( "Unset" );
293
294     QString r = qfu( base );
295
296     free( base );
297     return r;
298 }
299
300
301 /* Animated Icon implementation */
302
303 AnimatedIcon::AnimatedIcon( QWidget *parent )
304     : mTimer( this ), mIdleFrame( NULL )
305 {
306     mCurrentFrame = mRemainingLoops = 0;
307     connect( &mTimer, SIGNAL( timeout() ), this, SLOT( onTimerTick() ) );
308 }
309
310 AnimatedIcon::~AnimatedIcon()
311 {
312     // We don't need to destroy the timer, he's our child
313     delete mIdleFrame;
314     foreach( QPixmap *frame, mFrames )
315         delete frame;
316 }
317
318 void AnimatedIcon::addFrame( const QPixmap &pxm, int index )
319 {
320     if( index == 0 )
321     {
322         // Replace idle frame
323         delete mIdleFrame;
324         mIdleFrame = new QPixmap( pxm );
325         setPixmap( *mIdleFrame );
326         return;
327     }
328     QPixmap *copy = new QPixmap( pxm );
329     mFrames.insert( ( index < 0 || index > mFrames.size() ) ? mFrames.size() :
330                     index, copy );
331     if( !pixmap() )
332         setPixmap( *copy );
333 }
334
335 void AnimatedIcon::play( int loops, int interval )
336 {
337     if( interval < 20 )
338     {
339 #ifndef NDEBUG
340         printf( "AnimatedIcon::play(): interval is too short (%d ms)",
341                 interval );
342 #endif
343         interval = 20;
344     }
345
346     if( !mIdleFrame && ( mFrames.empty() | loops != 0 ) )
347     {
348 #ifndef NDEBUG
349         printf( "AnimatedIcon::play(): no frames to display" );
350 #endif
351         return;
352     }
353
354     if( loops == 0 )
355     {
356         // Stop playback
357         mCurrentFrame = mRemainingLoops = 0;
358         mTimer.stop();
359         setPixmap( mIdleFrame != NULL ? *mIdleFrame : *mFrames.last() );
360         return;
361     }
362
363     if( loops <= -1 )
364         loops = -1;
365
366     mCurrentFrame = 1;
367     mRemainingLoops = loops;
368     mTimer.start( interval );
369     setPixmap( *mFrames.first() );
370 }
371
372 // private slot
373 void AnimatedIcon::onTimerTick()
374 {
375     //assert( !mFrames.empty() );
376     if( ++mCurrentFrame > mFrames.size() )
377     {
378         if( mRemainingLoops != -1 )
379         {
380             if( --mRemainingLoops == 0 )
381             {
382                 mTimer.stop();
383                 setPixmap( mIdleFrame ? *mIdleFrame : *mFrames.last() );
384                 return;
385             }
386         }
387         mCurrentFrame = 1;
388     }
389     //assert( mCurrentFrame >= 1 && mCurrentFrame <= mFrames.size() );
390     setPixmap( *mFrames.at( mCurrentFrame - 1 ) );
391 }
392
393
394 /* SpinningIcon implementation */
395
396 SpinningIcon::SpinningIcon( QWidget *parent, bool noIdleFrame )
397     : AnimatedIcon( parent )
398 {
399     if( noIdleFrame )
400         addFrame( QPixmap(), 0 );
401     else
402         addFrame( QPixmap( ":/util/wait0" ), 0 );
403     addFrame( QPixmap( ":/util/wait1" ) );
404     addFrame( QPixmap( ":/util/wait2" ) );
405     addFrame( QPixmap( ":/util/wait3" ) );
406     addFrame( QPixmap( ":/util/wait4" ) );
407     setScaledContents( true );
408     setFixedSize( 16, 16 );
409 }
410
411 SpinningIcon::~SpinningIcon()
412 {
413 }