~ubuntu-branches/ubuntu/lucid/lastfm/lucid

« back to all changes in this revision

Viewing changes to src/libLastFmTools/draglabel.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Pedro Fragoso
  • Date: 2007-12-31 09:49:54 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20071231094954-ix1amvcsj9pk61ya
Tags: 1:1.4.1.57486.dfsg-1ubuntu1
* Merge from Debian unstable (LP: #180254), remaining changes:
  - debian/rules;
    - Added dh_icons
  - Modify Maintainer value to match Debian-Maintainer-Field Spec

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/***************************************************************************
2
 
 *   Copyright (C) 2005 - 2007 by                                          *
3
 
 *      Christian Muehlhaeuser, Last.fm Ltd <chris@last.fm>                *
4
 
 *      Erik Jaelevik, Last.fm Ltd <erik@last.fm>                          *
5
 
 *                                                                         *
6
 
 *   This program is free software; you can redistribute it and/or modify  *
7
 
 *   it under the terms of the GNU General Public License as published by  *
8
 
 *   the Free Software Foundation; either version 2 of the License, or     *
9
 
 *   (at your option) any later version.                                   *
10
 
 *                                                                         *
11
 
 *   This program is distributed in the hope that it will be useful,       *
12
 
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
 
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
 
 *   GNU General Public License for more details.                          *
15
 
 *                                                                         *
16
 
 *   You should have received a copy of the GNU General Public License     *
17
 
 *   along with this program; if not, write to the                         *
18
 
 *   Free Software Foundation, Inc.,                                       *
19
 
 *   51 Franklin Steet, Fifth Floor, Boston, MA  02111-1307, USA.          *
20
 
 ***************************************************************************/
21
 
 
22
 
#include "last.fm.h"
23
 
#include "draglabel.h"
24
 
#include <QApplication>
25
 
#include "browserthread.h"
26
 
#include <QEvent>
27
 
#include <QHelpEvent>
28
 
#include <QPainter>
29
 
#include <QPalette>
30
 
#include <QToolTip>
31
 
#include <QUrl>
32
 
 
33
 
#include <limits.h>
34
 
 
35
 
// Width of the chords at the side ( each of them is chordw / 2 wide )
36
 
static const int chordw = 6;
37
 
static const int chordMargin = int(0.5f * chordw);
38
 
static const int cornerRadius = 4;
39
 
static const float s_lineSpacing = 1.0f;
40
 
static const int afterHeaderSpace = 4;
41
 
 
42
 
DragLabel::DragLabel( QWidget *parent ) :
43
 
    QLabel( parent ),
44
 
    m_itemsStartAt( 0 ),    
45
 
    m_lastWidth( -1 ),
46
 
    m_lastHfwSize( -1, -1 ),
47
 
    m_itemType( -1 ),
48
 
    m_answerRect( QRectF( 0, 0, 0, 0 ) ),
49
 
    m_hoverPoint( QPoint( -1, -1 ) ),
50
 
    m_hoverIndex( -1 ),
51
 
    m_hoverable( true ),
52
 
    m_selectable( false ),
53
 
    m_commas( false ),
54
 
    m_justified( false ),
55
 
    m_uniformLineHeight( -1 )
56
 
{
57
 
    setWordWrap( true );
58
 
    setMouseTracking( true );
59
 
 
60
 
    setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
61
 
    setCursor( QCursor( Qt::ArrowCursor ) );
62
 
 
63
 
    // Repaint only newly visible items on resize
64
 
    setAttribute( Qt::WA_StaticContents );
65
 
}
66
 
 
67
 
void
68
 
DragLabel::append( const QString& text )
69
 
{
70
 
    DragItem d;
71
 
    QString t = m_commas ? text + "," : text + " ";
72
 
    d.m_text = t;
73
 
    calcFontProperties( d );
74
 
    m_items << d;
75
 
    updateDragLabel();
76
 
}
77
 
 
78
 
void
79
 
DragLabel::clear()
80
 
{
81
 
    m_items.erase( m_items.begin() + m_itemsStartAt, m_items.end() );
82
 
    m_hfwLayout.clear();
83
 
    m_lineLayout.clear();
84
 
 
85
 
    updateDragLabel();
86
 
}
87
 
 
88
 
void
89
 
DragLabel::clearText()
90
 
{
91
 
    for ( int i = m_itemsStartAt; i < m_items.count(); ++i )
92
 
    {
93
 
        m_items[i].m_text = "";
94
 
        m_items[i].m_tooltip = "";
95
 
        m_items[i].m_url = "";
96
 
    }
97
 
    updateDragLabel();
98
 
}
99
 
 
100
 
void
101
 
DragLabel::clearSelections()
102
 
{
103
 
    foreach( DragItem d, m_items )
104
 
    {
105
 
        d.m_selected = false;
106
 
    }
107
 
 
108
 
    // No size change so only calling update
109
 
    update();
110
 
}
111
 
 
112
 
void
113
 
DragLabel::setBackground( const QPixmap& pixmap )
114
 
{
115
 
    m_background = pixmap;
116
 
}
117
 
 
118
 
void
119
 
DragLabel::setHeader( const QString& header, const QFont& font )
120
 
{
121
 
    if ( m_itemsStartAt == 0 )
122
 
    {
123
 
        DragItem d;
124
 
        d.m_text = header;
125
 
 
126
 
        //QFont defaultFont = font();
127
 
        //defaultFont.setBold( true );
128
 
        d.m_font = font;
129
 
 
130
 
        calcFontProperties( d, true );
131
 
 
132
 
        m_items.insert( 0, d );
133
 
 
134
 
        m_itemsStartAt = 1;    
135
 
    }
136
 
    else
137
 
    {
138
 
        DragItem& d = m_items[0];
139
 
        d.m_text = header;
140
 
        d.m_font = font;
141
 
        calcFontProperties( d, true );
142
 
    }
143
 
 
144
 
    updateDragLabel();
145
 
}
146
 
 
147
 
 
148
 
void
149
 
DragLabel::setText( const QString& text )
150
 
151
 
    if ( m_items.isEmpty() )
152
 
    {
153
 
        append( text );
154
 
    }
155
 
    else
156
 
    {
157
 
        QString t = m_commas ? text + "," : text + " ";
158
 
        m_items[0].m_text = t;
159
 
        calcFontProperties( m_items[0] );
160
 
        updateDragLabel();
161
 
    }
162
 
}
163
 
 
164
 
QString 
165
 
DragLabel::text() const
166
 
{
167
 
    if ( m_items.count() <= m_itemsStartAt )
168
 
    {
169
 
        return "";
170
 
    }
171
 
    else
172
 
    {
173
 
        QString s = m_items.at( m_itemsStartAt ).m_text;
174
 
        s.chop( 1 );
175
 
        return s;
176
 
    }
177
 
}
178
 
 
179
 
void 
180
 
DragLabel::setURL( QString url )
181
 
{
182
 
    if ( m_items.isEmpty() )
183
 
    {
184
 
        DragItem d;
185
 
        d.m_url = url;
186
 
        m_items << d;
187
 
    }
188
 
    else
189
 
    {
190
 
        m_items[0].m_url = url;
191
 
    }
192
 
}
193
 
 
194
 
void 
195
 
DragLabel::setFont( const QFont& font )
196
 
{
197
 
    if ( m_items.isEmpty() )
198
 
    {
199
 
        DragItem d;
200
 
        d.m_font = font;
201
 
        m_items << d;
202
 
    }
203
 
    else
204
 
    {
205
 
        m_items[0].m_font = font;
206
 
    }
207
 
    
208
 
    calcFontProperties( m_items[0] );
209
 
}
210
 
 
211
 
void
212
 
DragLabel::setItems( const QStringList& list )
213
 
{
214
 
    clear();
215
 
    foreach ( QString s, list )
216
 
    {
217
 
        append( s );
218
 
    }
219
 
    updateDragLabel();
220
 
}
221
 
 
222
 
QStringList
223
 
DragLabel::items()
224
 
{
225
 
    QStringList l;
226
 
    for ( int i = m_itemsStartAt; i < m_items.count(); ++i )
227
 
    {
228
 
        QString s = m_items[i].m_text;
229
 
        s.chop( 1 );
230
 
        l << s;
231
 
    }
232
 
    return l;
233
 
}
234
 
 
235
 
void
236
 
DragLabel::setItemText( int index, const QString& text )
237
 
{
238
 
    Q_ASSERT( index < ( m_items.count() - m_itemsStartAt ) );
239
 
 
240
 
    QString t = m_commas ? text + "," : text + " ";
241
 
    m_items[m_itemsStartAt + index].m_text = t;
242
 
}
243
 
 
244
 
void
245
 
DragLabel::setItemTooltip( int index, const QString& text )
246
 
{
247
 
    Q_ASSERT( index < ( m_items.count() - m_itemsStartAt ) );
248
 
 
249
 
    m_items[m_itemsStartAt + index].m_tooltip = text;
250
 
}
251
 
 
252
 
void
253
 
DragLabel::setItemFont( int index, QFont font )
254
 
{
255
 
    Q_ASSERT( index < ( m_items.count() - m_itemsStartAt ) );
256
 
 
257
 
    m_items[m_itemsStartAt + index].m_font = font;
258
 
    calcFontProperties( m_items[m_itemsStartAt + index] );
259
 
}
260
 
 
261
 
void
262
 
DragLabel::setItemColor( int index, QColor col )
263
 
{
264
 
    Q_ASSERT( index < ( m_items.count() - m_itemsStartAt ) );
265
 
 
266
 
    m_items[m_itemsStartAt + index].m_colour = col;
267
 
}
268
 
 
269
 
void 
270
 
DragLabel::setItemURL( int index, QString url )
271
 
{
272
 
    Q_ASSERT( index < ( m_items.count() - m_itemsStartAt ) );
273
 
 
274
 
    m_items[m_itemsStartAt + index].m_url = url;
275
 
}
276
 
 
277
 
void 
278
 
DragLabel::setItemData( int index, QHash<QString, QString> data )
279
 
{
280
 
    Q_ASSERT( index < ( m_items.count() - m_itemsStartAt ) );
281
 
 
282
 
    m_items[m_itemsStartAt + index].m_dragData = data;
283
 
}
284
 
 
285
 
QHash<QString, QString>
286
 
DragLabel::itemData( int index )
287
 
{
288
 
    Q_ASSERT( index < ( m_items.count() - m_itemsStartAt ) );
289
 
 
290
 
    return m_items[m_itemsStartAt + index].m_dragData;
291
 
}
292
 
 
293
 
void
294
 
DragLabel::setItemType( int type )
295
 
{
296
 
    m_itemType = type;
297
 
}
298
 
 
299
 
int
300
 
DragLabel::itemType()
301
 
{
302
 
    return m_itemType;
303
 
}
304
 
 
305
 
void
306
 
DragLabel::setItemsSelectable( bool selectable )
307
 
{
308
 
    m_selectable = selectable;
309
 
    if ( !selectable )
310
 
        m_hoverPoint = QPoint( -1, -1 );
311
 
}
312
 
 
313
 
void 
314
 
DragLabel::calcFontProperties( DragItem& d, bool isHeader )
315
 
{
316
 
    // This defaults to application's default font if not set
317
 
    QFontMetrics fm( d.m_font ); 
318
 
    
319
 
    QRect rect = fm.boundingRect( d.m_text );
320
 
    
321
 
    // Augment to font height as this particular string might be less tall
322
 
    if ( fm.height() > rect.height() )    
323
 
    {
324
 
        rect.setHeight( fm.height() );
325
 
    }
326
 
 
327
 
    // boundingRect sometimes returns negative values so make sure it's at 0, 0
328
 
    rect.moveTo( 0, 0 );
329
 
 
330
 
    // Move rect to its correct pos and add padding
331
 
    if ( isHeader )
332
 
    {
333
 
        rect.adjust( 0, 0, chordMargin + afterHeaderSpace, 0 );
334
 
    }
335
 
    else
336
 
    {
337
 
        rect.adjust( 0, 0, chordMargin * 2, 0 );
338
 
    }
339
 
    
340
 
    d.m_extent = rect;
341
 
    d.m_ascent = fm.ascent();
342
 
}
343
 
 
344
 
void 
345
 
DragLabel::updateDragLabel()
346
 
{
347
 
    m_lastWidth = -1;
348
 
    m_lastHfwSize.setHeight( -1 );
349
 
    m_lastHfwSize.setWidth( -1 );
350
 
    m_sizeHint.setHeight( -1 );
351
 
    m_sizeHint.setWidth( -1 );
352
 
    
353
 
    // Tell the layout manager to recalculate itself
354
 
    updateGeometry();
355
 
 
356
 
    // Redraw the widget
357
 
    update();
358
 
}
359
 
 
360
 
QSize
361
 
DragLabel::layoutItems( QList<QRect>& layoutOut, int width ) const
362
 
{
363
 
    int x = 0;
364
 
    int y = 0;
365
 
    int lineHeight = 0;
366
 
    int firstIdxOfLine = 0;
367
 
    int widest = 0;
368
 
    
369
 
    int marg = margin();
370
 
    int margLeft, margTop, margRight, margBottom;
371
 
    getContentsMargins( &margLeft, &margTop, &margRight, &margBottom );
372
 
    margLeft += marg;
373
 
    margTop += marg;
374
 
    margRight += marg;
375
 
    margBottom += marg;
376
 
    
377
 
    width = width - margLeft - margRight;
378
 
    y = margTop;
379
 
    x = margLeft;
380
 
 
381
 
    for ( int i = 0; i < m_items.count(); i++ )
382
 
    {
383
 
        // Find out how much space the pill needs
384
 
        QRect textRect = m_items[i].m_extent;
385
 
 
386
 
        // Use the uniform height if we have one, otherwise use the height of the widget font
387
 
        int itemHeight = m_uniformLineHeight > 0 ? m_uniformLineHeight : textRect.height();
388
 
        if ( itemHeight > lineHeight )
389
 
        {
390
 
            lineHeight = itemHeight;
391
 
        }
392
 
 
393
 
        if ( textRect.width() > widest )
394
 
        {
395
 
            widest = textRect.width();
396
 
        }
397
 
 
398
 
        // Move rect to its correct pos
399
 
        textRect.moveTo( x, y );
400
 
        
401
 
        bool tooBigForCurLine = textRect.width() > ( width - x );
402
 
        bool firstThingToBeDrawn = i == 0;
403
 
        
404
 
        // Do we need a newline?
405
 
        if ( tooBigForCurLine && !firstThingToBeDrawn && wordWrap() )
406
 
        {
407
 
            baseAlign( layoutOut, firstIdxOfLine, i - 1, lineHeight );
408
 
            if ( m_justified )
409
 
            {
410
 
                justify( layoutOut, firstIdxOfLine, i - 1, width );
411
 
            }
412
 
 
413
 
            y += lineHeight + int(s_lineSpacing);
414
 
            x = margLeft;
415
 
            textRect.moveTo( x, y );
416
 
            
417
 
            // Reset line height to height of this item
418
 
            lineHeight = itemHeight;
419
 
            
420
 
            firstIdxOfLine = i;
421
 
        }
422
 
 
423
 
        layoutOut << textRect;
424
 
        
425
 
        x += textRect.width();
426
 
    }
427
 
 
428
 
    if ( ( m_items.count() - firstIdxOfLine ) > 0 )
429
 
    {
430
 
        baseAlign( layoutOut, firstIdxOfLine, m_items.count() - 1, lineHeight );
431
 
    }
432
 
    y += lineHeight;
433
 
    y += margBottom;
434
 
    
435
 
    int actualWidth;
436
 
    if ( width == INT_MAX )
437
 
    {
438
 
        x += margRight;
439
 
        actualWidth = x;
440
 
    }
441
 
    else
442
 
    {
443
 
        actualWidth = ( widest > width ) ? widest : width;
444
 
    }
445
 
 
446
 
    QSize ret( actualWidth, y );
447
 
 
448
 
    return ret;
449
 
}
450
 
 
451
 
void
452
 
DragLabel::baseAlign( QList<QRect>& layoutOut, int startIdx, int endIdx, int lineHeight ) const
453
 
{
454
 
    // Find tallest item in line
455
 
    int maxHeight = 0;
456
 
    int tallest = -1;
457
 
    for ( int i = startIdx; i <= endIdx; ++i )
458
 
    {
459
 
        int height = m_items[i].m_extent.height();
460
 
        if ( height > maxHeight )
461
 
        {
462
 
            maxHeight = height;
463
 
            tallest = i;
464
 
        }
465
 
    }
466
 
 
467
 
    int maxAscent = m_items[tallest].m_ascent;
468
 
    int distToBottom = lineHeight - m_items[tallest].m_extent.bottom() - 1;
469
 
 
470
 
    Q_ASSERT( maxAscent != -1 );
471
 
    
472
 
    // Move all items down to align their baseline with the tallest item
473
 
    for ( int j = startIdx; j <= endIdx; ++j )
474
 
    {
475
 
        int pushDist = maxAscent - m_items[j].m_ascent;
476
 
        Q_ASSERT( pushDist >= 0 );
477
 
        
478
 
        pushDist += distToBottom;
479
 
        layoutOut[j].translate( 0, pushDist );
480
 
    }
481
 
}
482
 
 
483
 
void
484
 
DragLabel::justify( QList<QRect>& layoutOut, int startIdx, int endIdx, int width ) const
485
 
{
486
 
    int combinedWidth = 0;
487
 
    for ( int i = startIdx; i <= endIdx; ++i )
488
 
    {
489
 
        combinedWidth += m_items[i].m_extent.width();
490
 
    }
491
 
 
492
 
    int space = width - combinedWidth;
493
 
    int nGaps = qMax( endIdx - startIdx, 1 );
494
 
    int gapSpace = space / nGaps;
495
 
    
496
 
    int cnt = 1;
497
 
    for ( int j = startIdx + 1; j <= endIdx; ++j, ++cnt )
498
 
    {
499
 
        layoutOut[j].translate( gapSpace * cnt, 0 );
500
 
    }
501
 
}
502
 
 
503
 
int
504
 
DragLabel::heightForWidth( int w ) const
505
 
{
506
 
    // This function is called by the layout manager instead of sizeHint when we
507
 
    // have specified that word wrap should be used.
508
 
 
509
 
    // ensurePolished?
510
 
    
511
 
    if ( m_lastWidth == -1 || w != m_lastWidth )
512
 
    {
513
 
        m_lastWidth = w;
514
 
        m_hfwLayout.clear();
515
 
        m_lastHfwSize = layoutItems( m_hfwLayout, w );
516
 
    }
517
 
 
518
 
    return m_lastHfwSize.height();
519
 
}
520
 
 
521
 
QSize
522
 
DragLabel::sizeHint() const
523
 
{
524
 
    // Work out width if all items are put on one line and return that.
525
 
    // Only used as a default when we don't have word wrapping enabled.
526
 
    // This will also be used if specifying Fixed as the size policy.
527
 
 
528
 
    if ( !m_sizeHint.isValid() )
529
 
    {
530
 
        m_lineLayout.clear();
531
 
        m_sizeHint = layoutItems( m_lineLayout, INT_MAX );
532
 
    }
533
 
 
534
 
    return m_sizeHint;
535
 
}
536
 
 
537
 
QSize
538
 
DragLabel::minimumSizeHint() const
539
 
{
540
 
    // A layout will never size us smaller than what we return here
541
 
    if ( !m_sizeHint.isValid() )
542
 
    {
543
 
        m_lineLayout.clear();
544
 
        m_sizeHint = layoutItems( m_lineLayout, INT_MAX );
545
 
    }
546
 
 
547
 
    return QSize( 0, m_sizeHint.height() );
548
 
}
549
 
 
550
 
bool
551
 
DragLabel::event( QEvent* event )
552
 
{
553
 
    if ( event->type() == QEvent::ToolTip )
554
 
    {
555
 
        QHelpEvent* helpEvent = static_cast<QHelpEvent *>( event );
556
 
        QPoint hoverPos = helpEvent->pos();
557
 
 
558
 
        int index = itemAt( hoverPos );
559
 
 
560
 
        if ( index != -1 )
561
 
        {
562
 
            //QToolTip::showText( helpEvent->globalPos(), m_items[index].m_tooltip, this, m_hfwLayout.at( index ) );
563
 
            QToolTip::showText( helpEvent->globalPos(), m_items[index].m_tooltip );
564
 
        }
565
 
        else
566
 
        {
567
 
            QToolTip::hideText();
568
 
        }
569
 
    }
570
 
 
571
 
    return QLabel::event( event );
572
 
}
573
 
 
574
 
void
575
 
DragLabel::paintEvent( QPaintEvent * event )
576
 
{
577
 
    //qDebug() << "paintevent rect: " << event->rect();
578
 
 
579
 
    QPainter painter( this );
580
 
 
581
 
    if ( !m_background.isNull() )
582
 
    {
583
 
        painter.drawTiledPixmap( event->rect(), m_background );
584
 
    }
585
 
 
586
 
    m_answerRect = QRectF( 0, 0, 0, 0 );
587
 
    m_hoverIndex = -1;
588
 
 
589
 
    if ( !anythingToDraw() )
590
 
    {
591
 
        return;
592
 
    }
593
 
 
594
 
    // The space we've been given by the layout system
595
 
    QRect space = contentsRect();
596
 
 
597
 
    // Get us a layout
598
 
    int w = space.width();
599
 
    if ( m_lastWidth == -1 || w != m_lastWidth )
600
 
    {
601
 
        m_lastWidth = w;
602
 
        m_hfwLayout.clear();
603
 
        m_lastHfwSize = layoutItems( m_hfwLayout, w );
604
 
    }
605
 
 
606
 
    for ( int i = 0; i < m_items.count(); ++i )
607
 
    {
608
 
        DragItem& item = m_items[i];
609
 
 
610
 
        painter.setFont( item.m_font );
611
 
        if ( item.m_colour.isValid() )
612
 
        {
613
 
            painter.setPen( item.m_colour );
614
 
            painter.setBrush( item.m_colour );
615
 
        }
616
 
        else
617
 
        {
618
 
            painter.setPen( palette().text().color() );
619
 
            painter.setBrush( palette().text().color() );
620
 
        }
621
 
 
622
 
        QString text = item.m_text;
623
 
 
624
 
        // Remove the trailing comma/space from the last item
625
 
        if ( i == ( m_items.count() - 1 ) )
626
 
        {
627
 
            text.chop( 1 );
628
 
        }
629
 
 
630
 
        QRect itemRect = m_hfwLayout[i];
631
 
 
632
 
        // Crop itemRect to the width of our boundaries
633
 
        bool cropped = false;
634
 
        if ( space.width() < itemRect.width() )
635
 
        {
636
 
            itemRect.setWidth( space.width() );
637
 
            cropped = true;
638
 
        }
639
 
 
640
 
        // According to Alberto Garcia, this fixes the draglabel painting issue on Linux.
641
 
        QRect textRect( itemRect.topLeft() + QPoint( chordMargin, 0 ),
642
 
                        itemRect.bottomRight() ); // - QPoint( chordMargin, 0 ) );
643
 
 
644
 
        if ( cropped )
645
 
        {
646
 
            QFontMetrics fm = painter.fontMetrics();
647
 
            text = fm.elidedText( text, Qt::ElideRight, textRect.width() );
648
 
        }
649
 
 
650
 
        bool isHeader = i == 0 && m_itemsStartAt == 1;
651
 
 
652
 
        // Draw pill if we're hovered or selected
653
 
        if ( ( itemRect.contains( m_hoverPoint ) || item.m_selected ) && !isHeader )
654
 
        {
655
 
            if ( itemRect.contains( m_hoverPoint ) )
656
 
            {
657
 
                m_hoverIndex = i;
658
 
                m_answerRect = itemRect;
659
 
            }
660
 
 
661
 
            #ifdef WIN32
662
 
                // Looks shit on Win with aa on
663
 
                painter.setRenderHint( QPainter::Antialiasing, false );
664
 
            #else
665
 
                // Looks shit on Mac with aa off
666
 
                painter.setRenderHint( QPainter::Antialiasing, true );
667
 
            #endif
668
 
 
669
 
            // On hover, we remove the comma or trailing space
670
 
            if ( i != ( m_items.count() - 1 ) && !cropped )
671
 
            {
672
 
                text.chop( 1 );
673
 
            }
674
 
 
675
 
            QColor highlight( 0xb4, 0xc2, 0xd4 );
676
 
            QColor background( 0xd6, 0xdf, 0xec );
677
 
            
678
 
                        // Hannah doesn't like the anti-aliasing on the Mac
679
 
                        #ifdef Q_WS_MAC
680
 
                                painter.setPen( background );
681
 
                        #else
682
 
                                painter.setPen( highlight );
683
 
                        #endif
684
 
            painter.setBrush( background );
685
 
 
686
 
            // Get new rect for text without comma
687
 
            QRect pillRect = painter.fontMetrics().boundingRect( itemRect, Qt::AlignLeft, text );
688
 
            pillRect.adjust( 0, 0, chordMargin * 2, 0 );
689
 
 
690
 
            // Paint the rectangle
691
 
            QRect r( pillRect.topLeft() + QPoint( 1, 1 ),
692
 
                     pillRect.bottomRight() + QPoint( -1, -1 ) );
693
 
 
694
 
            painter.drawRoundRect( r, roundnessForLength( r.width() ),
695
 
                                      roundnessForLength( r.height() ) );
696
 
 
697
 
            // We want white text on hovering
698
 
            //painter.setPen( Qt::white );
699
 
            //painter.setBrush( Qt::white );
700
 
            painter.setPen( item.m_colour );
701
 
        }
702
 
 
703
 
        // Draw text
704
 
        painter.setRenderHint( QPainter::Antialiasing, true );
705
 
        painter.setRenderHint( QPainter::TextAntialiasing, true );
706
 
        painter.drawText( textRect, text );
707
 
 
708
 
    }
709
 
 
710
 
    // Highly dubious!
711
 
    if ( sizePolicy().verticalPolicy() == QSizePolicy::MinimumExpanding )
712
 
    {
713
 
        setMinimumHeight( m_lastHfwSize.height() );
714
 
    }
715
 
 
716
 
    // set the empty bottom space as our cached answerRect
717
 
    if ( !m_answerRect.width() )
718
 
        m_answerRect = QRectF( 0, m_lastHfwSize.height(), 1, 1 );
719
 
}
720
 
 
721
 
bool
722
 
DragLabel::anythingToDraw()
723
 
{
724
 
    if ( m_items.count() == 0 || ( m_items.count() == 1 && m_itemsStartAt == 1 ) )
725
 
    {
726
 
        return false;
727
 
    }
728
 
 
729
 
    bool haveText = false;
730
 
    foreach( DragItem item, m_items )
731
 
    {
732
 
        if ( item.m_text != "" && item.m_text != " " )
733
 
        {
734
 
            haveText = true;
735
 
            break;
736
 
        }
737
 
    }
738
 
 
739
 
    return haveText;
740
 
}
741
 
 
742
 
int
743
 
DragLabel::roundnessForLength( int len )
744
 
{
745
 
    if ( len == 0 ) return 0;
746
 
 
747
 
    int round = (int)( ( (float)cornerRadius / len ) * 100 );
748
 
    round = qMin( 99, round );
749
 
    round = qMax( 1, round );
750
 
 
751
 
    //qDebug() << len << " -> " << round;
752
 
 
753
 
    return round;
754
 
}
755
 
 
756
 
int
757
 
DragLabel::itemAt( const QPoint& pos )
758
 
{
759
 
    for ( int i = 0; i < m_hfwLayout.size(); ++i )
760
 
    {
761
 
        const QRect& itemRect = m_hfwLayout.at( i );
762
 
        if ( itemRect.contains( pos ) )
763
 
        {
764
 
            return i;
765
 
        }
766
 
    }
767
 
    return -1;
768
 
}
769
 
 
770
 
void
771
 
DragLabel::leaveEvent( QEvent* /*event*/ )
772
 
{
773
 
    m_answerRect = QRectF( 0, 0, 0, 0 );
774
 
    m_hoverPoint = QPoint( -1, -1 );
775
 
    update();
776
 
 
777
 
    emit urlHovered( "" );
778
 
}
779
 
 
780
 
void
781
 
DragLabel::mousePressEvent( QMouseEvent *event )
782
 
{
783
 
    if ( !m_selectable && m_hoverIndex >= 0 )
784
 
        QLabel::mousePressEvent( event );
785
 
 
786
 
    if ( event->button() == Qt::LeftButton )
787
 
    {
788
 
        m_dragStartPosition = event->pos();
789
 
        //setCursor( QCursor( Qt::ClosedHandCursor ) );
790
 
    }
791
 
 
792
 
}
793
 
 
794
 
 
795
 
void
796
 
DragLabel::mouseReleaseEvent( QMouseEvent *event )
797
 
{
798
 
    if ( m_hoverIndex >= 0 )
799
 
    {
800
 
        if ( m_selectable )
801
 
        {
802
 
            m_items[m_hoverIndex].m_selected = !m_items[m_hoverIndex].m_selected;
803
 
            update();
804
 
        }
805
 
        else
806
 
        {
807
 
            if ( ( event->pos() - m_dragStartPosition ).manhattanLength() > QApplication::startDragDistance() )
808
 
                return;
809
 
 
810
 
            if ( !m_items[m_hoverIndex].m_url.isEmpty() )
811
 
            {
812
 
                new BrowserThread( m_items[m_hoverIndex].m_url ); // self-deleting
813
 
            }
814
 
        }
815
 
 
816
 
        //setCursor( QCursor( Qt::ArrowCursor ) );
817
 
 
818
 
        emit clicked( m_hoverIndex );
819
 
    }
820
 
}
821
 
 
822
 
 
823
 
void
824
 
DragLabel::mouseMoveEvent( QMouseEvent *event )
825
 
{
826
 
    QLabel::mouseMoveEvent( event );
827
 
 
828
 
    if ( !m_hoverable )
829
 
        return;
830
 
 
831
 
    if ( !m_answerRect.contains( event->pos() ) )
832
 
    {
833
 
        // We've just moved off/on a pill
834
 
        m_hoverPoint = event->pos();
835
 
        update();
836
 
    }
837
 
 
838
 
    // Stuff from here on is stuff we need to update for each nudge of the mouse
839
 
    if ( m_hoverIndex < 0 )
840
 
    {
841
 
        setCursor( QCursor( Qt::ArrowCursor ) );
842
 
 
843
 
        emit urlHovered( "" );
844
 
    }
845
 
    else
846
 
    {
847
 
        //if ( !( event->buttons() & Qt::LeftButton ) )
848
 
        //{
849
 
        //    setCursor( QCursor( Qt::OpenHandCursor ) );
850
 
        //}
851
 
 
852
 
        setCursor( QCursor( Qt::PointingHandCursor ) );
853
 
 
854
 
        // Emit hovered over url
855
 
        QString url = m_items[m_hoverIndex].m_url;
856
 
        if ( !url.isEmpty() )
857
 
        {
858
 
            emit urlHovered( url );
859
 
        }
860
 
    }
861
 
 
862
 
    // Early out if left button isn't pressed or we're not over a pill
863
 
    if ( !( event->buttons() & Qt::LeftButton ) || m_hoverIndex < 0 )
864
 
        return;
865
 
 
866
 
    // Early out if drag not long enough yet
867
 
    if ( ( event->pos() - m_dragStartPosition ).manhattanLength() < QApplication::startDragDistance() )
868
 
        return;
869
 
 
870
 
    QString anchor = m_items[m_hoverIndex].m_text;
871
 
    
872
 
    anchor = anchor.trimmed();
873
 
    if ( anchor.endsWith( "," ) )
874
 
    {
875
 
        anchor.chop( 1 );
876
 
    }
877
 
 
878
 
    if ( !anchor.isEmpty() )
879
 
    {
880
 
        QDrag* drag = new QDrag( this );
881
 
//         qDebug() << "New drag with type" << itemType();
882
 
 
883
 
        QMimeData *mimeData = new QMimeData();
884
 
        mimeData->setText( anchor );
885
 
        mimeData->setData( "item/type", QByteArray::number( itemType() ) );
886
 
 
887
 
        QHash<QString, QString> data = m_items[m_hoverIndex].m_dragData;
888
 
        if ( data.count() )
889
 
        {
890
 
            for ( int i = 0; i < data.count(); i++ )
891
 
            {
892
 
                //qDebug() << "Setting data" << data.keys().at( i ) << data.values().at( i );
893
 
                mimeData->setData( QString( "item/%1" ).arg( data.keys().at( i ) ), data.values().at( i ).toUtf8() );
894
 
            }
895
 
        }
896
 
        else
897
 
        {
898
 
            switch( itemType() )
899
 
            {
900
 
                case ItemArtist:
901
 
                    mimeData->setData( "item/artist", anchor.toUtf8() );
902
 
                    break;
903
 
 
904
 
                case ItemTag:
905
 
                    mimeData->setData( "item/tag", anchor.toUtf8() );
906
 
                    break;
907
 
 
908
 
                case ItemUser:
909
 
                    mimeData->setData( "item/user", anchor.toUtf8() );
910
 
                    break;
911
 
 
912
 
                case ItemStation:
913
 
                    mimeData->setData( "item/station", anchor.toUtf8() );
914
 
                    break;
915
 
            }
916
 
        }
917
 
 
918
 
        // From the docs: Warning: Unless a widget has the Qt::WA_PaintOutsidePaintEvent
919
 
        // attribute set. A QPainter can only be used on a widget inside a paintEvent()
920
 
        // or a function called by a paintEvent(). On Mac OS X, you can only paint on
921
 
        // a widget in a paintEvent() regardless of this attribute's setting.
922
 
        QPainter painter;
923
 
        QPixmap pixmap( painter.fontMetrics().width( anchor ) + 16, painter.fontMetrics().height() + 4 );
924
 
        QRect rect( 0, 0, pixmap.width() - 1, pixmap.height() - 1 );
925
 
 
926
 
        painter.begin( &pixmap );
927
 
        painter.setBackgroundMode( Qt::OpaqueMode );
928
 
 
929
 
        painter.setBrush( Qt::white );
930
 
        painter.setPen( Qt::black );
931
 
        painter.drawRect( rect );
932
 
 
933
 
        painter.setPen( Qt::black );
934
 
        painter.drawText( rect, Qt::AlignCenter, anchor );
935
 
        painter.end();
936
 
 
937
 
        drag->setMimeData( mimeData );
938
 
        drag->setPixmap( pixmap );
939
 
 
940
 
        Qt::DropAction dropAction = drag->start( Qt::CopyAction );
941
 
        
942
 
        Q_UNUSED( dropAction )
943
 
    }
944
 
}
945
 
 
946
 
 
947
 
void
948
 
DragLabel::setItemSelected( const QString& text, bool selected, bool emitSignal )
949
 
{
950
 
    int index;
951
 
    for( int i = m_itemsStartAt; i < m_items.count(); ++i )
952
 
    {
953
 
        if ( m_items[i].m_text == text )
954
 
        {
955
 
            index = i;
956
 
        }
957
 
    }
958
 
 
959
 
    setItemSelected( index - m_itemsStartAt, selected, emitSignal );
960
 
}
961
 
 
962
 
 
963
 
void
964
 
DragLabel::setItemSelected( int index, bool selected, bool emitSignal )
965
 
{
966
 
    if ( index >= 0 && index < m_items.count() )
967
 
    {
968
 
        m_items[m_itemsStartAt + index].m_selected = selected;
969
 
 
970
 
        update();
971
 
        if ( emitSignal )
972
 
            emit clicked( index );
973
 
    }
974
 
}