1 /* 2 * Strawberry Music Player 3 * This file was part of Clementine. 4 * Copyright 2010, David Sansome <me@davidsansome.com> 5 * Copyright 2018-2021, Jonas Kvinge <jonas@jkvinge.net> 6 * 7 * Strawberry is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * Strawberry is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with Strawberry. If not, see <http://www.gnu.org/licenses/>. 19 * 20 */ 21 22 #ifndef PLAYLISTVIEW_H 23 #define PLAYLISTVIEW_H 24 25 #include "config.h" 26 27 #include <memory> 28 29 #include <QtGlobal> 30 #include <QObject> 31 #include <QAbstractItemDelegate> 32 #include <QAbstractItemModel> 33 #include <QStyleOptionViewItem> 34 #include <QAbstractItemView> 35 #include <QTreeView> 36 #include <QList> 37 #include <QByteArray> 38 #include <QString> 39 #include <QImage> 40 #include <QPixmap> 41 #include <QColor> 42 #include <QRect> 43 #include <QRegion> 44 #include <QStyleOption> 45 #include <QProxyStyle> 46 #include <QPoint> 47 #include <QBasicTimer> 48 #include <QCommonStyle> 49 50 #include "core/song.h" 51 #include "covermanager/albumcoverloaderresult.h" 52 #include "settings/appearancesettingspage.h" 53 #include "playlist.h" 54 55 class QWidget; 56 class QTimer; 57 class QTimeLine; 58 class QPainter; 59 class QEvent; 60 class QShowEvent; 61 class QContextMenuEvent; 62 class QDragEnterEvent; 63 class QDragLeaveEvent; 64 class QDragMoveEvent; 65 class QDropEvent; 66 class QFocusEvent; 67 class QHideEvent; 68 class QKeyEvent; 69 class QMouseEvent; 70 class QPaintEvent; 71 class QTimerEvent; 72 73 class Application; 74 class CollectionBackend; 75 class PlaylistHeader; 76 class DynamicPlaylistControls; 77 class RatingItemDelegate; 78 79 // This proxy style works around a bug/feature introduced in Qt 4.7's QGtkStyle 80 // that uses Gtk to paint row backgrounds, ignoring any custom brush or palette the caller set in the QStyleOption. 81 // That breaks our currently playing track animation, which relies on the background painted by Qt to be transparent. 82 // This proxy style uses QCommonStyle to paint the affected elements. 83 // This class is used by internet search view as well. 84 class PlaylistProxyStyle : public QProxyStyle { 85 Q_OBJECT 86 87 public: 88 explicit PlaylistProxyStyle(QObject *parent = nullptr); 89 90 void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const override; 91 void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const override; 92 93 private: 94 std::unique_ptr<QCommonStyle> common_style_; 95 }; 96 97 class PlaylistView : public QTreeView { 98 Q_OBJECT 99 100 public: 101 explicit PlaylistView(QWidget *parent = nullptr); 102 ~PlaylistView() override; 103 104 static ColumnAlignmentMap DefaultColumnAlignment(); 105 106 void Init(Application *app); 107 void SetItemDelegates(); 108 void SetPlaylist(Playlist *playlist); 109 void RemoveSelected(); 110 SetReadOnlySettings(const bool read_only)111 void SetReadOnlySettings(const bool read_only) { read_only_settings_ = read_only; } 112 playlist()113 Playlist *playlist() const { return playlist_; } background_image_type()114 AppearanceSettingsPage::BackgroundImageType background_image_type() const { return background_image_type_; } 115 Qt::Alignment column_alignment(int section) const; 116 117 void ResetHeaderState(); 118 119 // QTreeView 120 void setModel(QAbstractItemModel *model) override; 121 122 public slots: 123 void ReloadSettings(); 124 void SaveSettings(); 125 void SetColumnAlignment(const int section, const Qt::Alignment alignment); 126 void JumpToCurrentlyPlayingTrack(); edit(const QModelIndex & idx)127 void edit(const QModelIndex &idx) { QAbstractItemView::edit(idx); } 128 129 signals: 130 void PlayItem(QModelIndex idx, Playlist::AutoScroll autoscroll); 131 void PlayPause(const quint64 offset_nanosec = 0, Playlist::AutoScroll autoscroll = Playlist::AutoScroll_Never); 132 void RightClicked(QPoint global_pos, QModelIndex idx); 133 void SeekForward(); 134 void SeekBackward(); 135 void FocusOnFilterSignal(QKeyEvent *event); 136 void BackgroundPropertyChanged(); 137 void ColumnAlignmentChanged(ColumnAlignmentMap alignment); 138 139 protected: 140 // QWidget 141 void keyPressEvent(QKeyEvent *event) override; 142 void contextMenuEvent(QContextMenuEvent *e) override; 143 void hideEvent(QHideEvent *event) override; 144 void showEvent(QShowEvent *event) override; 145 void timerEvent(QTimerEvent *event) override; 146 void mouseMoveEvent(QMouseEvent *event) override; 147 void mousePressEvent(QMouseEvent *event) override; 148 void leaveEvent(QEvent*) override; 149 void paintEvent(QPaintEvent *event) override; 150 void dragMoveEvent(QDragMoveEvent *event) override; 151 void dragEnterEvent(QDragEnterEvent *event) override; 152 void dragLeaveEvent(QDragLeaveEvent *event) override; 153 void dropEvent(QDropEvent *event) override; 154 bool eventFilter(QObject *object, QEvent *event) override; 155 void focusInEvent(QFocusEvent *event) override; 156 void resizeEvent(QResizeEvent *event) override; 157 158 // QTreeView 159 void drawTree(QPainter *painter, const QRegion ®ion) const; 160 void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &idx) const override; 161 162 // QAbstractScrollArea 163 void scrollContentsBy(int dx, int dy) override; 164 165 // QAbstractItemView 166 void rowsInserted(const QModelIndex &parent, int start, int end) override; 167 bool edit(const QModelIndex &idx, QAbstractItemView::EditTrigger trigger, QEvent *event) override; 168 void closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint) override; 169 170 private slots: Update()171 void Update() { update(); } 172 void SetHeaderState(); 173 void InhibitAutoscrollTimeout(); 174 void MaybeAutoscroll(const Playlist::AutoScroll autoscroll); 175 void InvalidateCachedCurrentPixmap(); 176 void PlaylistDestroyed(); 177 void StretchChanged(const bool stretch); 178 void FadePreviousBackgroundImage(const qreal value); 179 void StopGlowing(); 180 void StartGlowing(); 181 void JumpToLastPlayedTrack(); 182 void CopyCurrentSongToClipboard() const; 183 void Playing(); 184 void Stopped(); 185 void SongChanged(const Song &song); 186 void AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &result = AlbumCoverLoaderResult()); 187 void DynamicModeChanged(const bool dynamic); 188 void SetRatingLockStatus(const bool state); 189 void RatingHoverIn(const QModelIndex &idx, const QPoint pos); 190 void RatingHoverOut(); 191 192 private: 193 void LoadHeaderState(); 194 void RestoreHeaderState(); 195 196 void ReloadBarPixmaps(); 197 QList<QPixmap> LoadBarPixmap(const QString &filename); 198 void UpdateCachedCurrentRowPixmap(QStyleOptionViewItem option, const QModelIndex &idx); 199 set_background_image_type(AppearanceSettingsPage::BackgroundImageType bg)200 void set_background_image_type(AppearanceSettingsPage::BackgroundImageType bg) { 201 background_image_type_ = bg; 202 emit BackgroundPropertyChanged(); // clazy:exclude=incorrect-emit 203 } 204 // Save image as the background_image_ after applying some modifications (opacity, ...). 205 // Should be used instead of modifying background_image_ directly 206 void set_background_image(const QImage &image); 207 208 void GlowIntensityChanged(); 209 210 private: 211 static const int kGlowIntensitySteps; 212 static const int kAutoscrollGraceTimeout; 213 static const int kDropIndicatorWidth; 214 static const int kDropIndicatorGradientWidth; 215 216 QList<int> GetEditableColumns(); 217 QModelIndex NextEditableIndex(const QModelIndex ¤t); 218 QModelIndex PrevEditableIndex(const QModelIndex ¤t); 219 220 void RepositionDynamicControls(); 221 222 Application *app_; 223 PlaylistProxyStyle *style_; 224 Playlist *playlist_; 225 PlaylistHeader *header_; 226 227 qreal device_pixel_ratio_; 228 AppearanceSettingsPage::BackgroundImageType background_image_type_; 229 QString background_image_filename_; 230 AppearanceSettingsPage::BackgroundImagePosition background_image_position_; 231 int background_image_maxsize_; 232 bool background_image_stretch_; 233 bool background_image_do_not_cut_; 234 bool background_image_keep_aspect_ratio_; 235 int blur_radius_; 236 int opacity_level_; 237 238 bool background_initialized_; 239 bool set_initial_header_layout_; 240 bool header_state_loaded_; 241 bool header_state_restored_; 242 bool read_only_settings_; 243 244 QImage background_image_; 245 QImage current_song_cover_art_; 246 QPixmap cached_scaled_background_image_; 247 248 // For fading when image change 249 QPixmap previous_background_image_; 250 qreal previous_background_image_opacity_; 251 QTimeLine *fade_animation_; 252 253 // To know if we should redraw the background or not 254 bool force_background_redraw_; 255 int last_height_; 256 int last_width_; 257 int current_background_image_x_; 258 int current_background_image_y_; 259 int previous_background_image_x_; 260 int previous_background_image_y_; 261 262 bool glow_enabled_; 263 bool select_track_; 264 bool auto_sort_; 265 266 bool currently_glowing_; 267 QBasicTimer glow_timer_; 268 int glow_intensity_step_; 269 QModelIndex last_current_item_; 270 QRect last_glow_rect_; 271 272 QTimer *inhibit_autoscroll_timer_; 273 bool inhibit_autoscroll_; 274 bool currently_autoscrolling_; 275 276 int row_height_; // Used to invalidate the currenttrack_bar pixmaps 277 QList<QPixmap> currenttrack_bar_left_; 278 QList<QPixmap> currenttrack_bar_mid_; 279 QList<QPixmap> currenttrack_bar_right_; 280 QPixmap currenttrack_play_; 281 QPixmap currenttrack_pause_; 282 283 QRegion current_paint_region_; 284 QPixmap cached_current_row_; 285 QRect cached_current_row_rect_; 286 int cached_current_row_row_; 287 288 QPixmap cached_tree_; 289 int drop_indicator_row_; 290 bool drag_over_; 291 292 int header_state_version_; 293 QByteArray header_state_; 294 ColumnAlignmentMap column_alignment_; 295 bool rating_locked_; 296 297 Song song_playing_; 298 299 DynamicPlaylistControls *dynamic_controls_; 300 RatingItemDelegate *rating_delegate_; 301 302 QColor playlist_playing_song_color_; 303 304 }; 305 306 #endif // PLAYLISTVIEW_H 307