~ubuntu-branches/ubuntu/saucy/clementine/saucy

« back to all changes in this revision

Viewing changes to .pc/fix_floating_point_compilation.patch/src/widgets/nowplayingwidget.cpp

  • Committer: Package Import Robot
  • Author(s): Thomas PIERSON
  • Date: 2012-01-01 20:43:39 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20120101204339-lsb6nndwhfy05sde
Tags: 1.0.1+dfsg-1
New upstream release. (Closes: #653926, #651611, #657391)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* This file is part of Clementine.
2
 
   Copyright 2010, David Sansome <me@davidsansome.com>
3
 
 
4
 
   Clementine 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 3 of the License, or
7
 
   (at your option) any later version.
8
 
 
9
 
   Clementine 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 Clementine.  If not, see <http://www.gnu.org/licenses/>.
16
 
*/
17
 
 
18
 
#include "fullscreenhypnotoad.h"
19
 
#include "nowplayingwidget.h"
20
 
#include "core/albumcoverloader.h"
21
 
#include "core/kittenloader.h"
22
 
#include "library/librarybackend.h"
23
 
#include "ui/albumcoverchoicecontroller.h"
24
 
#include "ui/iconloader.h"
25
 
 
26
 
#include <QMenu>
27
 
#include <QMovie>
28
 
#include <QPainter>
29
 
#include <QPaintEvent>
30
 
#include <QSettings>
31
 
#include <QSignalMapper>
32
 
#include <QTextDocument>
33
 
#include <QTimeLine>
34
 
#include <QtDebug>
35
 
 
36
 
const char* NowPlayingWidget::kSettingsGroup = "NowPlayingWidget";
37
 
 
38
 
const char* NowPlayingWidget::kHypnotoadPath = ":/spinner.gif";
39
 
 
40
 
// Space between the cover and the details in small mode
41
 
const int NowPlayingWidget::kPadding = 2;
42
 
 
43
 
// Width of the transparent to black gradient above and below the text in large
44
 
// mode
45
 
const int NowPlayingWidget::kGradientHead = 40;
46
 
const int NowPlayingWidget::kGradientTail = 20;
47
 
 
48
 
// Maximum height of the cover in large mode, and offset between the
49
 
// bottom of the cover and bottom of the widget
50
 
const int NowPlayingWidget::kMaxCoverSize = 260;
51
 
const int NowPlayingWidget::kBottomOffset = 0;
52
 
 
53
 
// Border for large mode
54
 
const int NowPlayingWidget::kTopBorder = 4;
55
 
 
56
 
 
57
 
NowPlayingWidget::NowPlayingWidget(QWidget *parent)
58
 
  : QWidget(parent),
59
 
    album_cover_choice_controller_(new AlbumCoverChoiceController(this)),
60
 
    cover_loader_(new BackgroundThreadImplementation<AlbumCoverLoader, AlbumCoverLoader>(this)),
61
 
    kitten_loader_(NULL),
62
 
    mode_(SmallSongDetails),
63
 
    menu_(new QMenu(this)),
64
 
    above_statusbar_action_(NULL),
65
 
    visible_(false),
66
 
    small_ideal_height_(0),
67
 
    cover_height_(0),
68
 
    show_hide_animation_(new QTimeLine(500, this)),
69
 
    fade_animation_(new QTimeLine(1000, this)),
70
 
    load_cover_id_(0),
71
 
    details_(new QTextDocument(this)),
72
 
    previous_track_opacity_(0.0),
73
 
    bask_in_his_glory_action_(NULL),
74
 
    aww_(false)
75
 
{
76
 
  // Load settings
77
 
  QSettings s;
78
 
  s.beginGroup(kSettingsGroup);
79
 
  mode_ = Mode(s.value("mode", SmallSongDetails).toInt());
80
 
 
81
 
  // Accept drops for setting album art
82
 
  setAcceptDrops(true);
83
 
 
84
 
  // Context menu
85
 
  QActionGroup* mode_group = new QActionGroup(this);
86
 
  QSignalMapper* mode_mapper = new QSignalMapper(this);
87
 
  connect(mode_mapper, SIGNAL(mapped(int)), SLOT(SetMode(int)));
88
 
  CreateModeAction(SmallSongDetails, tr("Small album cover"), mode_group, mode_mapper);
89
 
  CreateModeAction(LargeSongDetails, tr("Large album cover"), mode_group, mode_mapper);
90
 
 
91
 
  menu_->addActions(mode_group->actions());
92
 
  menu_->addSeparator();
93
 
 
94
 
  QList<QAction*> actions = album_cover_choice_controller_->GetAllActions();
95
 
 
96
 
  connect(album_cover_choice_controller_->cover_from_file_action(),
97
 
          SIGNAL(triggered()), this, SLOT(LoadCoverFromFile()));
98
 
  connect(album_cover_choice_controller_->cover_to_file_action(),
99
 
          SIGNAL(triggered()), this, SLOT(SaveCoverToFile()));
100
 
  connect(album_cover_choice_controller_->cover_from_url_action(),
101
 
          SIGNAL(triggered()), this, SLOT(LoadCoverFromURL()));
102
 
  connect(album_cover_choice_controller_->search_for_cover_action(),
103
 
          SIGNAL(triggered()), this, SLOT(SearchForCover()));
104
 
  connect(album_cover_choice_controller_->unset_cover_action(),
105
 
          SIGNAL(triggered()), this, SLOT(UnsetCover()));
106
 
  connect(album_cover_choice_controller_->show_cover_action(),
107
 
          SIGNAL(triggered()), this, SLOT(ShowCover()));
108
 
 
109
 
  menu_->addActions(actions);
110
 
  menu_->addSeparator();
111
 
  above_statusbar_action_ = menu_->addAction(tr("Show above status bar"));
112
 
 
113
 
  above_statusbar_action_->setCheckable(true);
114
 
  connect(above_statusbar_action_, SIGNAL(toggled(bool)), SLOT(ShowAboveStatusBar(bool)));
115
 
  above_statusbar_action_->setChecked(s.value("above_status_bar", false).toBool());
116
 
 
117
 
  bask_in_his_glory_action_ = menu_->addAction(tr("ALL GLORY TO THE HYPNOTOAD"));
118
 
  bask_in_his_glory_action_->setVisible(false);
119
 
  connect(bask_in_his_glory_action_, SIGNAL(triggered()), SLOT(Bask()));
120
 
 
121
 
  // Animations
122
 
  connect(show_hide_animation_, SIGNAL(frameChanged(int)), SLOT(SetHeight(int)));
123
 
  setMaximumHeight(0);
124
 
 
125
 
  connect(fade_animation_, SIGNAL(valueChanged(qreal)), SLOT(FadePreviousTrack(qreal)));
126
 
  fade_animation_->setDirection(QTimeLine::Backward); // 1.0 -> 0.0
127
 
 
128
 
  // Start loading the cover loader thread
129
 
  cover_loader_->Start();
130
 
  connect(cover_loader_, SIGNAL(Initialised()), SLOT(CoverLoaderInitialised()));
131
 
}
132
 
 
133
 
NowPlayingWidget::~NowPlayingWidget() {
134
 
}
135
 
 
136
 
void NowPlayingWidget::CreateModeAction(Mode mode, const QString &text, QActionGroup *group, QSignalMapper* mapper) {
137
 
  QAction* action = new QAction(text, group);
138
 
  action->setCheckable(true);
139
 
  mapper->setMapping(action, mode);
140
 
  connect(action, SIGNAL(triggered()), mapper, SLOT(map()));
141
 
 
142
 
  if (mode == mode_)
143
 
    action->setChecked(true);
144
 
}
145
 
 
146
 
void NowPlayingWidget::set_ideal_height(int height) {
147
 
  small_ideal_height_ = height;
148
 
  UpdateHeight(aww_
149
 
      ? kitten_loader_->Worker().get()
150
 
      : cover_loader_->Worker().get());
151
 
}
152
 
 
153
 
QSize NowPlayingWidget::sizeHint() const {
154
 
  return QSize(cover_height_, total_height_);
155
 
}
156
 
 
157
 
void NowPlayingWidget::CoverLoaderInitialised() {
158
 
  BackgroundThread<AlbumCoverLoader>* loader =
159
 
      static_cast<BackgroundThread<AlbumCoverLoader>*>(sender());
160
 
  UpdateHeight(loader->Worker().get());
161
 
  loader->Worker()->SetPadOutputImage(true);
162
 
  connect(loader->Worker().get(), SIGNAL(ImageLoaded(quint64,QImage,QImage)),
163
 
          SLOT(AlbumArtLoaded(quint64,QImage,QImage)));
164
 
}
165
 
 
166
 
void NowPlayingWidget::UpdateHeight(AlbumCoverLoader* loader) {
167
 
  switch (mode_) {
168
 
  case SmallSongDetails:
169
 
    cover_height_ = small_ideal_height_;
170
 
    total_height_ = small_ideal_height_;
171
 
    break;
172
 
 
173
 
  case LargeSongDetails:
174
 
    cover_height_ = qMin(kMaxCoverSize, width());
175
 
    total_height_ = kTopBorder + cover_height_ + kBottomOffset;
176
 
    break;
177
 
  }
178
 
 
179
 
  // Update the animation settings and resize the widget now if we're visible
180
 
  show_hide_animation_->setFrameRange(0, total_height_);
181
 
  if (visible_ && show_hide_animation_->state() != QTimeLine::Running)
182
 
    setMaximumHeight(total_height_);
183
 
 
184
 
  // Tell the cover loader what size we want the images in
185
 
  loader->SetDesiredHeight(cover_height_);
186
 
  loader->SetDefaultOutputImage(QImage(":nocover.png"));
187
 
 
188
 
  // Re-fetch the current image
189
 
  load_cover_id_ = loader->LoadImageAsync(metadata_);
190
 
 
191
 
  // Tell Qt we've changed size
192
 
  updateGeometry();
193
 
}
194
 
 
195
 
void NowPlayingWidget::NowPlaying(const Song& metadata) {
196
 
  if (visible_) {
197
 
    // Cache the current pixmap so we can fade between them
198
 
    previous_track_ = QPixmap(size());
199
 
    previous_track_.fill(palette().background().color());
200
 
    previous_track_opacity_ = 1.0;
201
 
    QPainter p(&previous_track_);
202
 
    DrawContents(&p);
203
 
    p.end();
204
 
  }
205
 
 
206
 
  metadata_ = metadata;
207
 
  cover_ = QPixmap();
208
 
 
209
 
  // Loads the cover too.
210
 
  UpdateHeight(aww_
211
 
      ? kitten_loader_->Worker().get()
212
 
      : cover_loader_->Worker().get());
213
 
  UpdateDetailsText();
214
 
 
215
 
  SetVisible(true);
216
 
  update();
217
 
}
218
 
 
219
 
void NowPlayingWidget::Stopped() {
220
 
  SetVisible(false);
221
 
}
222
 
 
223
 
void NowPlayingWidget::UpdateDetailsText() {
224
 
  QString html;
225
 
 
226
 
  switch (mode_) {
227
 
    case SmallSongDetails:
228
 
      details_->setTextWidth(-1);
229
 
      details_->setDefaultStyleSheet("");
230
 
      html += "<p>";
231
 
      break;
232
 
 
233
 
    case LargeSongDetails:
234
 
      details_->setTextWidth(cover_height_);
235
 
      details_->setDefaultStyleSheet("p {"
236
 
          "  font-size: small;"
237
 
          "  color: white;"
238
 
          "}");
239
 
      html += "<p align=center>";
240
 
      break;
241
 
  }
242
 
 
243
 
  // TODO: Make this configurable
244
 
  html += QString("<i>%1</i><br/>%2<br/>%3").arg(
245
 
      Qt::escape(metadata_.PrettyTitle()), Qt::escape(metadata_.artist()),
246
 
      Qt::escape(metadata_.album()));
247
 
 
248
 
  html += "</p>";
249
 
  details_->setHtml(html);
250
 
}
251
 
 
252
 
void NowPlayingWidget::AlbumArtLoaded(quint64 id, const QImage& scaled, const QImage& original) {
253
 
  if (id != load_cover_id_)
254
 
    return;
255
 
 
256
 
  cover_ = QPixmap::fromImage(scaled);
257
 
  original_ = original;
258
 
  update();
259
 
 
260
 
  // Were we waiting for this cover to load before we started fading?
261
 
  if (!previous_track_.isNull()) {
262
 
    fade_animation_->start();
263
 
  }
264
 
}
265
 
 
266
 
void NowPlayingWidget::SetHeight(int height) {
267
 
  setMaximumHeight(height);
268
 
}
269
 
 
270
 
void NowPlayingWidget::SetVisible(bool visible) {
271
 
  if (visible == visible_)
272
 
    return;
273
 
  visible_ = visible;
274
 
 
275
 
  show_hide_animation_->setDirection(visible ? QTimeLine::Forward : QTimeLine::Backward);
276
 
  show_hide_animation_->start();
277
 
}
278
 
 
279
 
void NowPlayingWidget::paintEvent(QPaintEvent *e) {
280
 
  QPainter p(this);
281
 
 
282
 
  DrawContents(&p);
283
 
 
284
 
  // Draw the previous track's image if we're fading
285
 
  if (!previous_track_.isNull()) {
286
 
    p.setOpacity(previous_track_opacity_);
287
 
    p.drawPixmap(0, 0, previous_track_);
288
 
  }
289
 
}
290
 
 
291
 
void NowPlayingWidget::DrawContents(QPainter *p) {
292
 
  switch (mode_) {
293
 
  case SmallSongDetails:
294
 
    if (hypnotoad_) {
295
 
      p->drawPixmap(0, 0, small_ideal_height_, small_ideal_height_, hypnotoad_->currentPixmap());
296
 
    } else {
297
 
      // Draw the cover
298
 
      p->drawPixmap(0, 0, small_ideal_height_, small_ideal_height_, cover_);
299
 
    }
300
 
 
301
 
    // Draw the details
302
 
    p->translate(small_ideal_height_ + kPadding, 0);
303
 
    details_->drawContents(p);
304
 
    p->translate(-small_ideal_height_ - kPadding, 0);
305
 
    break;
306
 
 
307
 
  case LargeSongDetails:
308
 
    const int total_size = qMin(kMaxCoverSize, width());
309
 
    const int x_offset = (width() - cover_height_) / 2;
310
 
 
311
 
    // Draw the black background
312
 
    p->fillRect(QRect(0, kTopBorder, width(), height() - kTopBorder), Qt::black);
313
 
 
314
 
    // Draw the cover
315
 
    if (hypnotoad_) {
316
 
      p->drawPixmap(x_offset, kTopBorder, total_size, total_size, hypnotoad_->currentPixmap());
317
 
    } else {
318
 
      p->drawPixmap(x_offset, kTopBorder, total_size, total_size, cover_);
319
 
    }
320
 
 
321
 
    // Work out how high the text is going to be
322
 
    const int text_height = details_->size().height();
323
 
    const int gradient_mid = height() - qMax(text_height, kBottomOffset);
324
 
 
325
 
    // Draw the black fade
326
 
    QLinearGradient gradient(0, gradient_mid - kGradientHead,
327
 
                             0, gradient_mid + kGradientTail);
328
 
    gradient.setColorAt(0, QColor(0, 0, 0, 0));
329
 
    gradient.setColorAt(1, QColor(0, 0, 0, 255));
330
 
 
331
 
    p->fillRect(0, gradient_mid - kGradientHead,
332
 
                width(), height() - (gradient_mid - kGradientHead), gradient);
333
 
 
334
 
    // Draw the text on top
335
 
    p->translate(x_offset, height() - text_height);
336
 
    details_->drawContents(p);
337
 
    p->translate(-x_offset, -height() + text_height);
338
 
    break;
339
 
  }
340
 
}
341
 
 
342
 
void NowPlayingWidget::FadePreviousTrack(qreal value) {
343
 
  previous_track_opacity_ = value;
344
 
  if (qFuzzyCompare(previous_track_opacity_, 0.0)) {
345
 
    previous_track_ = QPixmap();
346
 
  }
347
 
 
348
 
  update();
349
 
}
350
 
 
351
 
void NowPlayingWidget::SetMode(int mode) {
352
 
  mode_ = Mode(mode);
353
 
  UpdateHeight(aww_
354
 
      ? kitten_loader_->Worker().get()
355
 
      : cover_loader_->Worker().get());
356
 
  UpdateDetailsText();
357
 
  update();
358
 
 
359
 
  QSettings s;
360
 
  s.beginGroup(kSettingsGroup);
361
 
  s.setValue("mode", mode_);
362
 
}
363
 
 
364
 
void NowPlayingWidget::resizeEvent(QResizeEvent* e) {
365
 
  if (visible_ && mode_ == LargeSongDetails && e->oldSize().width() != e->size().width()) {
366
 
    UpdateHeight(aww_
367
 
        ? kitten_loader_->Worker().get()
368
 
        : cover_loader_->Worker().get());
369
 
    UpdateDetailsText();
370
 
  }
371
 
}
372
 
 
373
 
void NowPlayingWidget::contextMenuEvent(QContextMenuEvent* e) {
374
 
  // initial 'enabled' values depending on the kitty mode
375
 
  album_cover_choice_controller_->cover_from_file_action()->setEnabled(!aww_);
376
 
  album_cover_choice_controller_->cover_to_file_action()->setEnabled(aww_);
377
 
  album_cover_choice_controller_->cover_from_url_action()->setEnabled(!aww_);
378
 
  album_cover_choice_controller_->search_for_cover_action()->setEnabled(!aww_);
379
 
  album_cover_choice_controller_->unset_cover_action()->setEnabled(!aww_);
380
 
  album_cover_choice_controller_->show_cover_action()->setEnabled(!aww_);
381
 
 
382
 
  // some special cases
383
 
  if (!aww_) {
384
 
  #ifndef HAVE_LIBLASTFM
385
 
    album_cover_choice_controller_->cover_from_file_action()->setEnabled(false);
386
 
    album_cover_choice_controller_->search_for_cover_action()->setEnabled(false);
387
 
  #endif
388
 
 
389
 
    const bool art_is_not_set = metadata_.has_manually_unset_cover()
390
 
        || (metadata_.art_automatic().isEmpty() && metadata_.art_manual().isEmpty());
391
 
 
392
 
    album_cover_choice_controller_->unset_cover_action()->setEnabled(!art_is_not_set);
393
 
    album_cover_choice_controller_->show_cover_action()->setEnabled(!art_is_not_set);
394
 
  }
395
 
 
396
 
  bask_in_his_glory_action_->setVisible(hypnotoad_);
397
 
 
398
 
  // show the menu
399
 
  menu_->popup(mapToGlobal(e->pos()));
400
 
}
401
 
 
402
 
void NowPlayingWidget::ShowAboveStatusBar(bool above) {
403
 
  QSettings s;
404
 
  s.beginGroup(kSettingsGroup);
405
 
  s.setValue("above_status_bar", above);
406
 
 
407
 
  emit ShowAboveStatusBarChanged(above);
408
 
}
409
 
 
410
 
bool NowPlayingWidget::show_above_status_bar() const {
411
 
  return above_statusbar_action_->isChecked();
412
 
}
413
 
 
414
 
void NowPlayingWidget::AllHail(bool hypnotoad) {
415
 
  if (hypnotoad) {
416
 
    hypnotoad_.reset(new QMovie(kHypnotoadPath, QByteArray(), this));
417
 
    connect(hypnotoad_.get(), SIGNAL(updated(const QRect&)), SLOT(update()));
418
 
    hypnotoad_->start();
419
 
    update();
420
 
  } else {
421
 
    hypnotoad_.reset();
422
 
    update();
423
 
  }
424
 
}
425
 
 
426
 
void NowPlayingWidget::EnableKittens(bool aww) {
427
 
  if (!kitten_loader_ && aww) {
428
 
    kitten_loader_ = new BackgroundThreadImplementation<AlbumCoverLoader, KittenLoader>(this);
429
 
    kitten_loader_->Start();
430
 
    connect(kitten_loader_, SIGNAL(Initialised()), SLOT(CoverLoaderInitialised()));
431
 
  } else if (aww) {
432
 
    NowPlaying(metadata_);
433
 
  }
434
 
 
435
 
  aww_ = aww;
436
 
}
437
 
 
438
 
void NowPlayingWidget::LoadCoverFromFile() {
439
 
  QString cover = album_cover_choice_controller_->LoadCoverFromFile(&metadata_);
440
 
 
441
 
  if(!cover.isEmpty())
442
 
    NowPlaying(metadata_);
443
 
}
444
 
 
445
 
void NowPlayingWidget::LoadCoverFromURL() {
446
 
  QString cover = album_cover_choice_controller_->LoadCoverFromURL(&metadata_);
447
 
 
448
 
  if(!cover.isEmpty())
449
 
    NowPlaying(metadata_);
450
 
}
451
 
 
452
 
void NowPlayingWidget::SearchForCover() {
453
 
  QString cover = album_cover_choice_controller_->SearchForCover(&metadata_);
454
 
 
455
 
  if(!cover.isEmpty())
456
 
    NowPlaying(metadata_);
457
 
}
458
 
 
459
 
void NowPlayingWidget::SaveCoverToFile() {
460
 
  album_cover_choice_controller_->SaveCoverToFile(metadata_, original_);
461
 
}
462
 
 
463
 
void NowPlayingWidget::UnsetCover() {
464
 
  album_cover_choice_controller_->UnsetCover(&metadata_);
465
 
  NowPlaying(metadata_);
466
 
}
467
 
 
468
 
void NowPlayingWidget::ShowCover() {
469
 
  album_cover_choice_controller_->ShowCover(metadata_);
470
 
}
471
 
 
472
 
void NowPlayingWidget::SetLibraryBackend(LibraryBackend* backend) {
473
 
  album_cover_choice_controller_->SetLibrary(backend);
474
 
}
475
 
 
476
 
void NowPlayingWidget::Bask() {
477
 
  big_hypnotoad_.reset(new FullscreenHypnotoad);
478
 
  big_hypnotoad_->showFullScreen();
479
 
}
480
 
 
481
 
void NowPlayingWidget::dragEnterEvent(QDragEnterEvent* e) {
482
 
  if (AlbumCoverChoiceController::CanAcceptDrag(e)) {
483
 
    e->acceptProposedAction();
484
 
  }
485
 
 
486
 
  QWidget::dragEnterEvent(e);
487
 
}
488
 
 
489
 
void NowPlayingWidget::dropEvent(QDropEvent* e) {
490
 
  album_cover_choice_controller_->SaveCover(&metadata_, e);
491
 
  NowPlaying(metadata_);
492
 
 
493
 
  QWidget::dropEvent(e);
494
 
}