1 //=========================================================
2 //  MusE
3 //  Linux Music Editor
4 //
5 //  rasterizer.h
6 //  Copyright (C) 2020 Tim E. Real (terminator356 on users dot sourceforge dot net)
7 //
8 //  This program is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU General Public License
10 //  as published by the Free Software Foundation; version 2 of
11 //  the License, or (at your option) any later version.
12 //
13 //  This program is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 //  GNU General Public License for more details.
17 //
18 //  You should have received a copy of the GNU General Public License
19 //  along with this program; if not, write to the Free Software
20 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 //
22 //=========================================================
23 
24 #ifndef __RASTERIZER_H__
25 #define __RASTERIZER_H__
26 
27 #include <QAbstractTableModel>
28 #include <QModelIndex>
29 #include <QVariant>
30 #include <QString>
31 #include <QObject>
32 #include <QMetaObject>
33 #include <QList>
34 #include <QMap>
35 #include <QSize>
36 
37 namespace MusEGui {
38 
39 class Rasterizer : public QObject {
40   private:
41         Q_OBJECT
42 
43   public:
44       enum Column {
45         InvalidColumn = -1,
46         TripletColumn =  0,
47         NormalColumn  =  1,
48         DottedColumn  =  2
49         };
50 
51       enum CommonRasters {
52          CommonRasterBar, CommonRasterOff, CommonRaster1, CommonRaster2, CommonRaster4,
53          CommonRaster8, CommonRaster16, CommonRaster32, CommonRaster64
54         };
55 
56   private:
57       int _division;          // System midi division (ticks per quarter note) setting.
58       int _rows;              // Current number of rows in the raster array.
59       int *_rasterArray;      // Two-dimensional array of raster values. -1 = invalid. 0 = Snap to bar. 1 = 'off'.
60 
61       void updateColumn(Column col);
62 
63   signals:
64       // This signal is emitted just before the data will be rebuilt.
65       void dataAboutToBeReset();
66       // This signal is emitted just after the data has been rebuilt.
67       void dataReset();
68 
69   public:
70       Rasterizer(int division, QObject *parent = nullptr);
71       ~Rasterizer();
72 
division()73       int division() const { return _division; }
74       void setDivision(int div);
75 
rowCount()76       int rowCount() const { return _rows; }
77 
78       // Returns the number of columns.
79       int columnCount() const;
80 
81       // Rebuilds the raster array.
82       void updateRasterizer();
83 
84       // Returns the given raster, or returns 1 division (1 quarter note) if no suitable raster could be found.
85       int checkRaster(int val) const;
86 
87       // Returns the index into the array of the given raster value, or -1 if raster not found.
88       int indexOf(int val) const;
89       // Returns raster value at given row and column, or -1 if no raster
90       //  at that location, or row or column are out of range.
91       int rasterAt(int row, int col) const;
92 
93       // Returns true if the raster at the given row and column is 0 (snap to bar).
94       bool isBarRaster(int row, int col) const;
95       // Returns true if the raster at the given row and column is 1 ('off').
96       bool isOffRaster(int row, int col) const;
97       // Returns the row number of the 'bar' row.
98       int barRow() const;
99       // Returns the row number of the 'off' row.
100       int offRow() const;
101       // Returns the raster value of some often-used denominator values.
102       // Returns -1 if the raster is not available.
103       int commonRaster(CommonRasters commonRast) const;
104       // Returns true if the raster at the given row and column is less than
105       //  a triple, normal, or dotted version of the given normal raster value.
106       bool isLessThanNormalRaster(int row, int col, int normalRaster) const;
107       // Returns a denominator value for the row, suitable for display (1 2 4 8 16 32 etc.)
108       // Returns zero if the row is a 'bar' row.
109       int rasterDenomAt(int row) const;
110 };
111 
112 class RasterizerModel : public QAbstractTableModel
113 {
114   private:
115     Q_OBJECT
116 
117   public:
118     enum Roles { RasterTextRole = Qt::DisplayRole, RasterValueRole = Qt::UserRole};
119     enum DisplayFormat { FractionFormat, DenominatorFormat };
120     enum RasterPick { NoPick,
121       ToggleTriple, ToggleDotted, ToggleHigherDotted,
122       GotoBar, GotoOff, Goto1, Goto2, Goto4, Goto8, Goto16, Goto32, Goto64 };
123 
124   private:
125     // The external rasterizer array used in this model.
126     const Rasterizer *_rasterizer;
127     // Maximum number of rows. If set to -1, all rows are included.
128     int _maxRows = 0;
129     // How text is displayed.
130     DisplayFormat _displayFormat;
131 
132     // Lookup lists for model <> raster rows and columns.
133     QList<int /*rasterRow*/> _modelToRasterRowList;
134     QMap<int /*rasterRow*/, int /*modelRow*/> _rasterToModelRowMap;
135     QList<Rasterizer::Column> _modelToRasterColumnList;
136     QMap<Rasterizer::Column, int /*modelColumn*/> _rasterToModelColumnMap;
137 
138     QMetaObject::Connection _dataAboutToBeResetConnection;
139     QMetaObject::Connection _dataResetConnection;
140 
141     void updateRows();
142 
143     // Converts model row to rasterizer row. Returns -1 if row out of bounds.
144     int modelToRasterRow(int row) const;
145     // Converts model column to rasterizer column.
146     // Returns Rasterizer::InvalidColumn if column out of bounds.
147     Rasterizer::Column modelToRasterCol(int col) const;
148 
149     // Returns raster text at given row and column, or empty string if no raster
150     //  at that location, or row or column are out of range.
151     QString textAt(int row, int col) const;
152     // Returns raster value at given row and column, or -1 if no raster
153     //  at that location, or row or column are out of range.
154     int rasterAt(int row, int col) const;
155 
156   protected slots:
157     void endResetModelHandler();
158 
159   public:
160     RasterizerModel(
161       Rasterizer *rasterizer, QObject *parent = nullptr, int max_rows = -1,
162       QList<Rasterizer::Column> visible_columns = QList<Rasterizer::Column>(),
163       DisplayFormat displayFormat = DenominatorFormat);
164     virtual ~RasterizerModel();
165 
166     // Required overrides for QAbstractTableModel.
167     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
168     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
169     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
170 
171     // Returns the external Rasterizer array used in this model.
rasterizer()172     const Rasterizer *rasterizer() { return _rasterizer; }
173     // Sets the external Rasterizer array used in this model.
174     void setRasterizer(const Rasterizer *r);
175 
176     // Returns the system midi division that the rasterizer is using.
177     int division() const;
178     // Returns maximum number of rows. If -1, all rows are included.
179     int maxRows() const;
180     // Sets maximum number of rows. If set to -1, all rows are included.
181     void setMaxRows(int rows);
182     // Returns a model-to-raster row list, ie. which raster rows are included in the model.
183     QList<int /*rasterRow*/> visibleRows() const;
184     // Returns the model-to-raster column list, ie. which raster columns are included in the model.
185     QList<Rasterizer::Column> visibleColumns() const;
186     // Sets the model-to-raster column list, ie. which raster columns are included in the model.
187     void setVisibleColumns(const QList<Rasterizer::Column>& cols);
188     // How text is displayed.
189     DisplayFormat displayFormat() const;
190     // Sets how text is displayed.
191     void setDisplayFormat(DisplayFormat format);
192 
193     // Returns the model row number of the 'bar' row.
194     int barRow() const;
195     // Returns the model row number of the 'off' row.
196     int offRow() const;
197     // Returns true if the raster at the given row and column is 0 (snap to bar).
198     bool isBarRaster(int row, int col) const;
199     // Returns true if the raster at the given row and column is 1 ('off').
200     bool isOffRaster(int row, int col) const;
201     // Returns the raster value of some often-used denominator values.
202     // Returns -1 if the raster is not available.
203     int commonRaster(Rasterizer::CommonRasters commonRast) const;
204     // Returns the index into the model of the given raster value, or -1 if raster not found.
205     int indexOfRaster(int val) const;
206     // Returns the model index of the given raster value, or invalid model index if raster not found.
207     QModelIndex modelIndexOfRaster(int val) const;
208     // Returns the given raster, or returns 1 division (1 quarter note) if no suitable raster could be found.
209     int checkRaster(int val) const;
210     // Given a raster, picks another raster based on the RasterPick, for example toggle the triple or dotted
211     //  version of raster, or pick a raster from the same column that raster is in.
212     int pickRaster(int raster, RasterPick pick) const;
213 };
214 
215 } // namespace MusEGui
216 
217 #endif
218