1 /*************************************************************************** 2 SignalView.h - base class for widgets for views to a signal 3 ------------------- 4 begin : Mon Jan 18 2010 5 copyright : (C) 2010 by Thomas Eschenbacher 6 email : Thomas.Eschenbacher@gmx.de 7 ***************************************************************************/ 8 9 /*************************************************************************** 10 * * 11 * This program is free software; you can redistribute it and/or modify * 12 * it under the terms of the GNU General Public License as published by * 13 * the Free Software Foundation; either version 2 of the License, or * 14 * (at your option) any later version. * 15 * * 16 ***************************************************************************/ 17 18 #ifndef SIGNAL_VIEW_H 19 #define SIGNAL_VIEW_H 20 21 #include "config.h" 22 23 #include <QtGlobal> 24 #include <QLabel> 25 #include <QList> 26 #include <QObject> 27 #include <QPointer> 28 #include <QPolygon> 29 #include <QSharedPointer> 30 #include <QSize> 31 #include <QString> 32 #include <QTimer> 33 #include <QWidget> 34 35 #include "libkwave/Sample.h" 36 37 #include "libgui/MouseMark.h" 38 #include "libgui/ViewItem.h" 39 40 class QEvent; 41 class QMouseEvent; 42 class QPaintEvent; 43 class QPoint; 44 45 namespace Kwave 46 { 47 48 class SignalManager; // forward declaration 49 50 class Q_DECL_EXPORT SignalView: public QWidget 51 { 52 Q_OBJECT 53 public: 54 55 /** preferred location of the SignalView */ 56 typedef enum { 57 UpperDockTop, /**< upper dock area, top */ 58 UpperDockBottom, /**< upper dock area, bottom */ 59 Top, /**< above all others */ 60 AboveTrackTop, /**< above the associated track, top */ 61 AboveTrackBottom, /**< above the associated track, bottom */ 62 BelowTrackTop, /**< below the associated track, top */ 63 BelowTrackBottom, /**< below the associated track, bottom */ 64 Bottom, /**< below all others */ 65 LowerDockTop, /**< lower dock area, top */ 66 LowerDockBottom /**< lower dock area, bottom */ 67 } Location; 68 69 /** 70 * Constructor 71 * @param parent pointer to the parent widget 72 * @param controls container widget for associated controls 73 * @param signal_manager the signal manager 74 * @param preferred_location the location where to insert the view 75 * @param track (optional) index of the associated track or -1 if 76 * not related to a specific track (default) 77 */ 78 SignalView(QWidget *parent, QWidget *controls, 79 Kwave::SignalManager *signal_manager, 80 Location preferred_location, 81 int track = -1); 82 83 /** Destructor */ 84 virtual ~SignalView() Q_DECL_OVERRIDE; 85 86 /** 87 * refresh the content of the view. 88 * The default implementation calls repaint(). 89 * Can be overwritten to trigger more complex refresh scenarios. 90 * @see TrackView::refresh() for an example 91 */ 92 virtual void refresh(); 93 94 /** returns the preferred location */ preferredLocation()95 Location preferredLocation() const { 96 return m_preferred_location; 97 } 98 99 /** returns the associated signal manager */ signalManager()100 inline Kwave::SignalManager *signalManager() const { 101 return m_signal_manager; 102 } 103 104 /** returns the index of the associated track (or -1) */ track()105 inline int track() const { 106 return m_track_index; 107 } 108 109 /** returns the current start position */ offset()110 inline sample_index_t offset() const { 111 return m_offset; 112 } 113 114 /** returns the current zoom [pixels/sample] */ zoom()115 inline double zoom() const { 116 return m_zoom; 117 } 118 119 /** returns the current vertical zoom factor */ verticalZoom()120 inline double verticalZoom() const { 121 return m_vertical_zoom; 122 } 123 124 /** returns the index of the first visible sample */ firstVisible()125 inline sample_index_t firstVisible() const { 126 return m_offset; 127 } 128 129 /** returns the index of the last visible sample */ lastVisible()130 inline sample_index_t lastVisible() const { 131 const sample_index_t w = pixels2samples(width()); 132 return m_offset + ((w) ? (w - 1) : 0); 133 } 134 135 /** 136 * converts a number of samples into a number of pixels, 137 * based on the current zoom factor 138 * @param samples a small number of samples (must be positive) 139 * @return number of pixels 140 */ 141 int samples2pixels(sample_index_t samples) const; 142 143 /** 144 * Converts a number of pixels into a number of samples, 145 * based on the current zoom factor 146 * @param pixels number of pixels (should be positive) 147 * @return number of samples 148 */ 149 sample_index_t pixels2samples(int pixels) const; 150 151 /** 152 * Converts a number of samples to a time in milliseconds, based on the 153 * current signal rate. 154 * @param samples number of samples 155 * @return time in milliseconds 156 */ 157 double samples2ms(sample_index_t samples); 158 159 /** 160 * Should be overwritten by subclasses that can display the currently 161 * selected range and allow the user to change the selection by mouse. 162 * @return true if mouse selection is handled 163 */ canHandleSelection()164 virtual bool canHandleSelection() const { return false; } 165 166 /** 167 * Tries to find the nearest item that is visible in this view 168 * at a given position 169 * 170 * @param pos position to look at, relative to view [pixels] 171 * @return the nearest ViewObject in range 172 * or a null pointer if nothing found 173 */ 174 virtual QSharedPointer<Kwave::ViewItem> findItem(const QPoint &pos); 175 176 /** slot for mouse moves, used for selection and drag&drop */ 177 virtual void mouseMoveEvent(QMouseEvent *e) Q_DECL_OVERRIDE; 178 179 /** slot for mouse press, used for selection and drag&drop */ 180 virtual void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE; 181 182 /** slot for mouse release, used for selection and drag&drop */ 183 virtual void mouseReleaseEvent(QMouseEvent *e) Q_DECL_OVERRIDE; 184 185 /** slot when the mouse leaves the widget */ 186 virtual void leaveEvent(QEvent *e) Q_DECL_OVERRIDE; 187 188 /** handles key press events (e.g. the Escape key) */ 189 virtual void keyPressEvent(QKeyEvent *e) Q_DECL_OVERRIDE; 190 191 /** 192 * tolerance in pixel for snapping to a label or selection border 193 * @return number of pixels 194 */ 195 virtual int selectionTolerance() const; 196 197 /** 198 * Called when the context menu has been activated over this view 199 * @param pos a position in pixel within this widget 200 * @param menu pointer to the context menu 201 */ 202 virtual void handleContextMenu(const QPoint &pos, QMenu *menu); 203 204 /** 205 * Adds a widget to the list of associated widgets 206 * @param widget a QWidget that is associated to this view 207 */ 208 virtual void addSibling(QWidget *widget); 209 210 signals: 211 212 /** emitted whenever the size of the content has changed */ 213 void contentSizeChanged(); 214 215 /** emitted to request update of the cursor */ 216 void sigCursorChanged(sample_index_t pos); 217 218 /** 219 * Can be emitted to signal that this view needs to be repainted, 220 * probably after synchronizing with other views and additionally 221 * throttled to reduce GUI load 222 * @param view pointer to the view that needs to be repainted 223 */ 224 void sigNeedRepaint(Kwave::SignalView *view); 225 226 /** forward a sigCommand to the next layer */ 227 void sigCommand(const QString &command); 228 229 public slots: 230 231 /** 232 * changes the association to a track 233 * @param track the new track index, or -1 if not associated 234 */ 235 virtual void setTrack(int track); 236 237 /** 238 * sets new zoom factor and offset 239 * @param zoom the new zoom factor in pixels/sample 240 * @param offset the index of the first visible sample 241 */ 242 virtual void setZoomAndOffset(double zoom, sample_index_t offset); 243 244 /** 245 * sets new vertical zoom factor 246 * @param zoom vertical zoom factor 247 */ 248 virtual void setVerticalZoom(double zoom); 249 250 /** 251 * shows the cursor at a given position 252 * @param pos current position of the cursor 253 */ 254 virtual void showCursor(sample_index_t pos = SAMPLE_INDEX_MAX); 255 256 protected slots: 257 258 /** 259 * Shows the current cursor position as a tooltip 260 * @param text description of the position 261 * @param pos marker position [samples] 262 * @param mouse the coordinates of the mouse cursor, 263 * relative to this widget [pixel] 264 */ 265 virtual void showPosition(const QString &text, sample_index_t pos, 266 const QPoint &mouse); 267 268 /** 269 * Hide the current position marker 270 * @see showPosition 271 */ hidePosition()272 virtual void hidePosition() { 273 showPosition(QString(), 0, QPoint(-1,-1)); 274 } 275 276 protected: 277 278 /** @see Qt XDND documentation */ 279 virtual void dragEnterEvent(QDragEnterEvent *event) Q_DECL_OVERRIDE; 280 281 /** @see Qt XDND documentation */ 282 virtual void dragLeaveEvent(QDragLeaveEvent *event) Q_DECL_OVERRIDE; 283 284 /** @see Qt XDND documentation */ 285 virtual void dropEvent(QDropEvent *event) Q_DECL_OVERRIDE; 286 287 /** @see Qt XDND documentation */ 288 virtual void dragMoveEvent(QDragMoveEvent *event) Q_DECL_OVERRIDE; 289 290 protected: 291 292 /** 293 * Relationship between a screen position and the current selection. 294 */ 295 enum SelectionPosEnum { 296 None = 0x0000, /**< not near a border */ 297 LeftBorder = 0x0001, /**< close to start of selection */ 298 RightBorder = 0x0002, /**< close to end of selection */ 299 Selection = 0x8000 /**< within the selection */ 300 }; 301 Q_DECLARE_FLAGS(SelectionPos, SelectionPosEnum) 302 303 /** 304 * Determines the relationship between a screen position and 305 * the current selection. 306 * @param x screen position 307 * @return a SelectionPos 308 */ 309 SelectionPos selectionPosition(int x); 310 311 /** 312 * Checks if a pixel position is within the left and right border 313 * of a selection. The tolerance is 2% of the currently 314 * visible area. 315 * @param x pixel position to be tested 316 * @return true if the position is within range 317 */ 318 bool isInSelection(int x); 319 320 /** 321 * Tries to find the nearest item that is visible in this view 322 * at a given position and show or hide the corresponding tool tip. 323 * 324 * @param mouse_pos position to look at, relative to view [pixels] 325 * @param active if true an operation (move or drag&drop) is active, 326 * otherwise it is only a hover over an item 327 */ 328 void findNewItem(const QPoint &mouse_pos, bool active); 329 330 protected: 331 332 /** widget for displaying associated controls */ 333 QWidget *m_controls; 334 335 /** the signal manager */ 336 Kwave::SignalManager *m_signal_manager; 337 338 /** the preferred location, as per construction */ 339 Location m_preferred_location; 340 341 /** index of the associated track or -1 if no relation to a track */ 342 int m_track_index; 343 344 /** 345 * Offset from which signal is being displayed. This is equal to 346 * the index of the first visible sample. 347 */ 348 sample_index_t m_offset; 349 350 /** number of samples per pixel */ 351 double m_zoom; 352 353 private: 354 355 class PositionWidget: public QWidget 356 { 357 public: 358 /** Constructor */ 359 explicit PositionWidget(QWidget *parent); 360 361 /** Destructor */ 362 virtual ~PositionWidget() Q_DECL_OVERRIDE; 363 364 /** 365 * set a new label text and alignment 366 * @param text the text of the label, can be multiline and rtf/html 367 * @param alignment the alignment of the label and the widget, 368 * can be Qt::AlignLeft, Qt::AlignRight or Qt::AlignHCenter 369 */ 370 virtual void setText(const QString &text, Qt::Alignment alignment); 371 372 protected: 373 374 /** paint event: draws the text and the arrow */ 375 virtual void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE; 376 377 /** 378 * re-creates the mask and the polygon when 379 * size/alignment has changed 380 */ 381 virtual void updateMask(); 382 383 private: 384 385 /** the label that contains the text */ 386 QLabel *m_label; 387 388 /** alignment of the label / text */ 389 Qt::Alignment m_alignment; 390 391 /** the radius of the corners [pixel] */ 392 int m_radius; 393 394 /** the length of the arrows [pixel] */ 395 int m_arrow_length; 396 397 /** for detecting changes: previous width */ 398 Qt::Alignment m_last_alignment; 399 400 /** for detecting changes: previous size */ 401 QSize m_last_size; 402 403 /** polygon used as widget outline */ 404 QPolygon m_polygon; 405 }; 406 407 private: 408 409 /** zoom factor for vertical size */ 410 double m_vertical_zoom; 411 412 /** mode of the mouse cursor */ 413 enum { 414 MouseNormal = 0, /**< over the signal [default] */ 415 MouseMoveItem, /**< while moving an item */ 416 MouseDragItem /**< while dragging an item */ 417 } m_mouse_mode; 418 419 /** selection handler */ 420 Kwave::MouseMark m_mouse_selection; 421 422 /** 423 * x position where the user clicked the last time, needed for 424 * finding out where to start a drag&drop operation [pixel] 425 */ 426 int m_mouse_down_x; 427 428 /** small widget for showing the mouse cursor position */ 429 PositionWidget m_position_widget; 430 431 /** timer for automatic hiding */ 432 QTimer m_position_widget_timer; 433 434 /** list of associated widgets, e.g. controls etc */ 435 QList<QPointer<QWidget> > m_siblings; 436 437 /** currently selected view item or null */ 438 QSharedPointer<Kwave::ViewItem> m_selected_item; 439 }; 440 441 } 442 443 #endif /* SIGNAL_VIEW_H */ 444 445 //*************************************************************************** 446 //*************************************************************************** 447