summaryrefslogtreecommitdiffstats
path: root/src/base/SnapGrid.h
blob: e0c9ec5af153bb808cab0956bc12f8b4ec25951b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// -*- c-basic-offset: 4 -*-

/*
    Rosegarden
    A sequencer and musical notation editor.

    This program is Copyright 2000-2008
        Guillaume Laurent   <glaurent@telegraph-road.org>,
        Chris Cannam        <cannam@all-day-breakfast.com>,
        Richard Bown        <bownie@bownie.com>

    The moral right of the authors to claim authorship of this work
    has been asserted.

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.  See the file
    COPYING included with this distribution for more information.
*/

#ifndef _SNAP_GRID_H_
#define _SNAP_GRID_H_

#include "RulerScale.h"

#include <map>

namespace Rosegarden {

/**
 * SnapGrid is a class that maps x-coordinate onto time, using a
 * RulerScale to get the mapping but constraining the results to a
 * discrete set of suitable times.
 *
 * (It also snaps y-coordinates, but that bit isn't very interesting.)
 */

class SnapGrid
{
public:
    /**
     * Construct a SnapGrid that uses the given RulerScale for
     * x-coordinate mappings and the given ysnap for y-coords.
     * If ysnap is zero, y-coords are not snapped at all.
     */
    SnapGrid(RulerScale *rulerScale, int ysnap = 0);

    static const timeT NoSnap;
    static const timeT SnapToBar;
    static const timeT SnapToBeat;
    static const timeT SnapToUnit;

    enum SnapDirection { SnapEither, SnapLeft, SnapRight };

    /**
     * Set the snap size of the grid to the given time.
     * The snap time must be positive, or else one of the
     * special constants NoSnap, SnapToBar, SnapToBeat or
     * SnapToUnit.
     * The default is SnapToBeat.
     */
    void setSnapTime(timeT snap);

    /**
     * Return the snap size of the grid, at the given x-coordinate.
     * (The x-coordinate is required in case the built-in snap size is
     * SnapToBar, SnapToBeat or SnapToUnit, in which case we need to
     * know the current time signature.)  Returns zero for NoSnap.
     */
    timeT getSnapTime(double x) const;

    /**
     * Return the snap setting -- the argument that was passed to
     * setSnapTime.  This differs from getSnapTime, which interprets
     * the NoSnap, SnapToBar, SnapToBeat and SnapToUnit settings to
     * return actual timeT values; instead this function returns those
     * actual constants if set.
     */
    timeT getSnapSetting() const;

    /**
     * Return the snap size of the grid, at the given time.  (The time
     * is required in case the built-in snap size is SnapToBar,
     * SnapToBeat or SnapToUnit, in which case we need to know the
     * current time signature.)  Returns zero for NoSnap.
     */
    timeT getSnapTime(timeT t) const;

    /**
     * Snap a given x-coordinate to the nearest time on the grid.  Of
     * course this also does x-to-time conversion, so it's useful even
     * in NoSnap mode.  If the snap time is greater than the bar
     * duration at this point, the bar duration will be used instead.
     *
     * If d is SnapLeft or SnapRight, a time to the left or right
     * respectively of the given coordinate will be returned;
     * otherwise the nearest time on either side will be returned.
     */
    timeT snapX(double x, SnapDirection d = SnapEither) const;

    /**
     * Snap a given time to the nearest time on the grid.  Unlike
     * snapX, this is not useful in NoSnap mode.  If the snap time is
     * greater than the bar duration at this point, the bar duration
     * will be used instead.
     *
     * If d is SnapLeft or SnapRight, a time to the left or right
     * respectively of the given coordinate will be returned;
     * otherwise the nearest time on either side will be returned.
     */
    timeT snapTime(timeT t, SnapDirection d = SnapEither) const;

    /**
     * Snap a given y-coordinate to the nearest lower bin coordinate.
     */
    int snapY(int y) const {
        if (m_ysnap == 0) return y;
	return getYBinCoordinate(getYBin(y));
    }

    /**
     * Return the bin number for the given y-coordinate.
     */
    int getYBin(int y) const;

    /**
     * Return the y-coordinate of the grid line at the start of the
     * given bin.
     */
    int getYBinCoordinate(int bin) const;

    /**
     * Set the default vertical step.  This is used as the height for
     * bins that have no specific height multiple set, and the base
     * height for bins that have a multiple.  Setting the Y snap here
     * is equivalent to specifying it in the constructor.
     */
    void setYSnap(int ysnap) {
	m_ysnap = ysnap;
    }

    /**
     * Retrieve the default vertical step.
     */
    int getYSnap() const {
        return m_ysnap;
    }

    /**
     * Set the height multiple for a specific bin.  The bin will be
     * multiple * ysnap high.  The default is 1 for all bins.
     */
    void setBinHeightMultiple(int bin, int multiple) {
	m_ymultiple[bin] = multiple;
    }
    
    /**
     * Retrieve the height multiple for a bin.
     */
    int getBinHeightMultiple(int bin) {
	if (m_ymultiple.find(bin) == m_ymultiple.end()) return 1;
	return m_ymultiple[bin];
    }

    RulerScale *getRulerScale() {
        return m_rulerScale;
    }

    const RulerScale *getRulerScale() const {
        return m_rulerScale;
    }

protected:
    RulerScale *m_rulerScale; // I don't own this
    timeT m_snapTime;
    int m_ysnap;
    std::map<int, int> m_ymultiple;
};

}

#endif