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 #ifndef PLAYLISTVIEW_H 19 #define PLAYLISTVIEW_H 20 21 #include <memory> 22 23 #include <QBasicTimer> 24 #include <QProxyStyle> 25 #include <QTreeView> 26 27 #include "playlist.h" 28 29 class QCommonStyle; 30 31 class Application; 32 class DynamicPlaylistControls; 33 class LibraryBackend; 34 class PlaylistHeader; 35 class RadioLoadingIndicator; 36 class RatingItemDelegate; 37 class QTimeLine; 38 39 // This proxy style works around a bug/feature introduced in Qt 4.7's QGtkStyle 40 // that uses Gtk to paint row backgrounds, ignoring any custom brush or palette 41 // the caller set in the QStyleOption. That breaks our currently playing track 42 // animation, which relies on the background painted by Qt to be transparent. 43 // This proxy style uses QCommonStyle to paint the affected elements. 44 // This class is used by the global search view as well. 45 class PlaylistProxyStyle : public QProxyStyle { 46 public: 47 PlaylistProxyStyle(); 48 void drawControl(ControlElement element, const QStyleOption* option, 49 QPainter* painter, const QWidget* widget) const; 50 void drawPrimitive(PrimitiveElement element, const QStyleOption* option, 51 QPainter* painter, const QWidget* widget) const; 52 53 private: 54 std::unique_ptr<QCommonStyle> common_style_; 55 }; 56 57 class PlaylistView : public QTreeView { 58 Q_OBJECT 59 public: 60 ~PlaylistView(); 61 62 enum BackgroundImageType { Default, None, Custom, AlbumCover }; 63 64 PlaylistView(QWidget* parent = nullptr); 65 66 static const int kStateVersion; 67 // Constants for settings: are persistent, values should not be changed 68 static const char* kSettingBackgroundImageType; 69 static const char* kSettingBackgroundImageFilename; 70 71 static const int kDefaultBlurRadius; 72 static const int kDefaultOpacityLevel; 73 74 static ColumnAlignmentMap DefaultColumnAlignment(); 75 76 void SetApplication(Application* app); 77 void SetItemDelegates(LibraryBackend* backend); 78 void SetPlaylist(Playlist* playlist); 79 void RemoveSelected(bool deleting_from_disk); 80 SetReadOnlySettings(bool read_only)81 void SetReadOnlySettings(bool read_only) { read_only_settings_ = read_only; } 82 playlist()83 Playlist* playlist() const { return playlist_; } background_image_type()84 BackgroundImageType background_image_type() const { 85 return background_image_type_; 86 } 87 Qt::Alignment column_alignment(int section) const; 88 89 // QTreeView 90 void drawTree(QPainter* painter, const QRegion& region) const; 91 void drawRow(QPainter* painter, const QStyleOptionViewItem& option, 92 const QModelIndex& index) const; 93 void setModel(QAbstractItemModel* model); 94 95 public slots: 96 void ReloadSettings(); 97 void StopGlowing(); 98 void StartGlowing(); 99 void JumpToCurrentlyPlayingTrack(); 100 void JumpToLastPlayedTrack(); 101 void closeEditor(QWidget* editor, QAbstractItemDelegate::EndEditHint hint); 102 void DynamicModeChanged(bool dynamic); 103 void SetColumnAlignment(int section, Qt::Alignment alignment); 104 105 void CopyCurrentSongToClipboard() const; 106 void CurrentSongChanged(const Song& new_song, const QString& uri, 107 const QImage& cover_art); 108 void PlayerStopped(); 109 110 signals: 111 void PlayItem(const QModelIndex& index); 112 void PlayPause(); 113 void RightClicked(const QPoint& global_pos, const QModelIndex& index); 114 void SeekForward(); 115 void SeekBackward(); 116 void FocusOnFilterSignal(QKeyEvent* event); 117 void BackgroundPropertyChanged(); 118 void ColumnAlignmentChanged(const ColumnAlignmentMap& alignment); 119 120 protected: 121 // QWidget 122 void keyPressEvent(QKeyEvent* event); 123 void contextMenuEvent(QContextMenuEvent* e); 124 void hideEvent(QHideEvent* event); 125 void showEvent(QShowEvent* event); 126 void timerEvent(QTimerEvent* event); 127 void mouseMoveEvent(QMouseEvent* event); 128 void mousePressEvent(QMouseEvent* event); 129 void leaveEvent(QEvent*); 130 void paintEvent(QPaintEvent* event); 131 void dragMoveEvent(QDragMoveEvent* event); 132 void dragEnterEvent(QDragEnterEvent* event); 133 void dragLeaveEvent(QDragLeaveEvent* event); 134 void dropEvent(QDropEvent* event); 135 void resizeEvent(QResizeEvent* event); 136 bool eventFilter(QObject* object, QEvent* event); 137 void focusInEvent(QFocusEvent* event); 138 139 // QAbstractScrollArea 140 void scrollContentsBy(int dx, int dy); 141 142 // QAbstractItemView 143 void rowsInserted(const QModelIndex& parent, int start, int end); 144 145 private slots: 146 void LoadGeometry(); 147 void LoadRatingLockStatus(); 148 void DirtyGeometry(); 149 void DirtySettings(); 150 void SaveGeometry(QSettings* settings); 151 void SetRatingLockStatus(bool state); 152 void GlowIntensityChanged(); 153 void InhibitAutoscrollTimeout(); 154 void MaybeAutoscroll(); 155 void InvalidateCachedCurrentPixmap(); 156 void PlaylistDestroyed(); 157 158 void SaveSettings(QSettings* s); 159 void StretchChanged(bool stretch); 160 161 void RatingHoverIn(const QModelIndex& index, const QPoint& pos); 162 void RatingHoverOut(); 163 164 void FadePreviousBackgroundImage(qreal value); 165 166 private: 167 void ReloadBarPixmaps(); 168 QList<QPixmap> LoadBarPixmap(const QString& filename); 169 void UpdateCachedCurrentRowPixmap(QStyleOptionViewItem option, 170 const QModelIndex& index); 171 set_background_image_type(BackgroundImageType bg)172 void set_background_image_type(BackgroundImageType bg) { 173 background_image_type_ = bg; 174 emit BackgroundPropertyChanged(); 175 } 176 // Save image as the background_image_ after applying some modifications 177 // (opacity, ...). 178 // Should be used instead of modifying background_image_ directly 179 void set_background_image(const QImage& image); 180 181 private: 182 static const int kGlowIntensitySteps; 183 static const int kAutoscrollGraceTimeout; 184 static const int kDropIndicatorWidth; 185 static const int kDropIndicatorGradientWidth; 186 187 QList<int> GetEditableColumns(); 188 QModelIndex NextEditableIndex(const QModelIndex& current); 189 QModelIndex PrevEditableIndex(const QModelIndex& current); 190 191 void RepositionDynamicControls(); 192 193 Application* app_; 194 PlaylistProxyStyle* style_; 195 Playlist* playlist_; 196 PlaylistHeader* header_; 197 bool setting_initial_header_layout_; 198 bool upgrading_from_qheaderview_; 199 bool read_only_settings_; 200 int upgrading_from_version_; 201 bool header_loaded_; 202 203 bool background_initialized_; 204 BackgroundImageType background_image_type_; 205 // Used if background image is a filemane 206 QString background_image_filename_; 207 // Stores the background image to be displayed. As we want this image to be 208 // particular (in terms of format, opacity), you should probably use 209 // set_background_image_type instead of modifying background_image_ directly 210 QImage background_image_; 211 int blur_radius_; 212 int opacity_level_; 213 214 QImage current_song_cover_art_; 215 QPixmap cached_scaled_background_image_; 216 217 // For fading when image change 218 QPixmap previous_background_image_; 219 qreal previous_background_image_opacity_; 220 QTimeLine* fade_animation_; 221 222 // To know if we should redraw the background or not 223 int last_height_; 224 int last_width_; 225 bool force_background_redraw_; 226 227 bool glow_enabled_; 228 bool currently_glowing_; 229 QBasicTimer glow_timer_; 230 int glow_intensity_step_; 231 QModelIndex last_current_item_; 232 QRect last_glow_rect_; 233 234 RatingItemDelegate* rating_delegate_; 235 236 QTimer* inhibit_autoscroll_timer_; 237 bool inhibit_autoscroll_; 238 bool currently_autoscrolling_; 239 240 int row_height_; // Used to invalidate the currenttrack_bar pixmaps 241 QList<QPixmap> currenttrack_bar_left_; 242 QList<QPixmap> currenttrack_bar_mid_; 243 QList<QPixmap> currenttrack_bar_right_; 244 QPixmap currenttrack_play_; 245 QPixmap currenttrack_pause_; 246 247 QRegion current_paint_region_; 248 QPixmap cached_current_row_; 249 QRect cached_current_row_rect_; 250 int cached_current_row_row_; 251 252 QPixmap cached_tree_; 253 int drop_indicator_row_; 254 bool drag_over_; 255 256 bool dirty_geometry_; 257 bool dirty_settings_; 258 259 bool ratings_locked_; // To store Ratings section lock status 260 261 DynamicPlaylistControls* dynamic_controls_; 262 263 ColumnAlignmentMap column_alignment_; 264 }; 265 266 #endif // PLAYLISTVIEW_H 267