1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 2 3 /* 4 Rosegarden 5 A sequencer and musical notation editor. 6 Copyright 2000-2021 the Rosegarden development team. 7 See the AUTHORS file for more details. 8 9 This program is free software; you can redistribute it and/or 10 modify it under the terms of the GNU General Public License as 11 published by the Free Software Foundation; either version 2 of the 12 License, or (at your option) any later version. See the file 13 COPYING included with this distribution for more information. 14 */ 15 16 #ifndef RG_SNAP_GRID_H 17 #define RG_SNAP_GRID_H 18 19 #include "RulerScale.h" 20 21 #include <map> 22 23 namespace Rosegarden { 24 25 /** 26 * SnapGrid is a class that maps x-coordinate onto time, using a 27 * RulerScale to get the mapping but constraining the results to a 28 * discrete set of suitable times. 29 * 30 * (It also snaps y-coordinates, but that bit isn't very interesting.) 31 */ 32 33 class SnapGrid 34 { 35 public: 36 /** 37 * Construct a SnapGrid that uses the given RulerScale for 38 * x-coordinate mappings and the given ysnap for y-coords. 39 * If ysnap is zero, y-coords are not snapped at all. 40 */ 41 SnapGrid(const RulerScale *rulerScale, int ysnap = 0); 42 43 static const timeT NoSnap; 44 static const timeT SnapToBar; 45 static const timeT SnapToBeat; 46 static const timeT SnapToUnit; 47 48 enum SnapDirection { SnapEither, SnapLeft, SnapRight }; 49 50 /** 51 * Set the snap size of the grid to the given time. 52 * The snap time must be positive, or else one of the 53 * special constants NoSnap, SnapToBar, SnapToBeat or 54 * SnapToUnit. 55 * The default is SnapToBeat. 56 */ 57 void setSnapTime(timeT snap); 58 59 /** 60 * Return the snap size of the grid, at the given x-coordinate. 61 * (The x-coordinate is required in case the built-in snap size is 62 * SnapToBar, SnapToBeat or SnapToUnit, in which case we need to 63 * know the current time signature.) Returns zero for NoSnap. 64 */ 65 timeT getSnapTime(double x) const; 66 67 /** 68 * Return the snap setting -- the argument that was passed to 69 * setSnapTime. This differs from getSnapTime, which interprets 70 * the NoSnap, SnapToBar, SnapToBeat and SnapToUnit settings to 71 * return actual timeT values; instead this function returns those 72 * actual constants if set. 73 */ 74 timeT getSnapSetting() const; 75 76 /** 77 * Return the snap size of the grid, at the given time. (The time ~AbstractSet()78 * is required in case the built-in snap size is SnapToBar, 79 * SnapToBeat or SnapToUnit, in which case we need to know the 80 * current time signature.) Returns zero for NoSnap. 81 */ 82 timeT getSnapTime(timeT t) const; 83 84 /** getInitialElement()85 * Snap a given x-coordinate to the nearest time on the grid. Of 86 * course this also does x-to-time conversion, so it's useful even 87 * in NoSnap mode. If the snap time is greater than the bar 88 * duration at this point, the bar duration will be used instead. 89 * 90 * If d is SnapLeft or SnapRight, a time to the left or right 91 * respectively of the given coordinate will be returned; 92 * otherwise the nearest time on either side will be returned. 93 */ 94 timeT snapX(double x, SnapDirection d = SnapEither) const; 95 getLongestElement()96 /** 97 * Snap a given time to the nearest time on the grid. Unlike 98 * snapX, this is not useful in NoSnap mode. If the snap time is 99 * greater than the bar duration at this point, the bar duration 100 * will be used instead. 101 * 102 * If d is SnapLeft or SnapRight, a time to the left or right 103 * respectively of the given coordinate will be returned; 104 * otherwise the nearest time on either side will be returned. 105 */ 106 timeT snapTime(timeT t, SnapDirection d = SnapEither) const; 107 108 /** 109 * Snap a given y-coordinate to the nearest lower bin coordinate. 110 */ 111 int snapY(int y) const { 112 if (m_ysnap == 0) return y; 113 return getYBinCoordinate(getYBin(y)); 114 } 115 116 /** 117 * Return the bin number for the given y-coordinate. 118 */ 119 int getYBin(int y) const; 120 getContainer()121 /** 122 * Return the y-coordinate of the grid line at the start of the 123 * given bin. 124 */ 125 int getYBinCoordinate(int bin) const; 126 127 /** 128 * Set the default vertical step. This is used as the height for 129 * bins that have no specific height multiple set, and the base 130 * height for bins that have a multiple. Setting the Y snap here 131 * is equivalent to specifying it in the constructor. 132 */ 133 void setYSnap(int ysnap) { 134 m_ysnap = ysnap; 135 } 136 137 /** 138 * Retrieve the default vertical step. 139 */ 140 int getYSnap() const { 141 return m_ysnap; 142 } 143 144 /** 145 * Set the height multiple for a specific bin. The bin will be 146 * multiple * ysnap high. The default is 1 for all bins. 147 */ 148 void setBinHeightMultiple(int bin, int multiple) { 149 m_ymultiple[bin] = multiple; 150 } 151 152 /** 153 * Retrieve the height multiple for a bin. 154 */ 155 int getBinHeightMultiple(int bin) { 156 if (m_ymultiple.find(bin) == m_ymultiple.end()) return 1; 157 return m_ymultiple[bin]; 158 } 159 160 const RulerScale *getRulerScale() const { 161 return m_rulerScale; 162 } 163 164 protected: 165 const RulerScale *m_rulerScale; // I don't own this 166 timeT m_snapTime; 167 int m_ysnap; 168 169 /// Number of segments high for each track. 170 std::map<int, int> m_ymultiple; 171 }; 172 173 } 174 175 #endif 176