1 /*
2  * Copyright (C) 2018-2020 Rerrah
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use,
8  * copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following
11  * conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23  * OTHER DEALINGS IN THE SOFTWARE.
24  */
25 
26 #ifndef PATTERN_EDITOR_PANEL_HPP
27 #define PATTERN_EDITOR_PANEL_HPP
28 
29 #include <QWidget>
30 #include <QPixmap>
31 #include <QFont>
32 #include <QPaintEvent>
33 #include <QResizeEvent>
34 #include <QMouseEvent>
35 #include <QHoverEvent>
36 #include <QWheelEvent>
37 #include <QEvent>
38 #include <QRect>
39 #include <QColor>
40 #include <QUndoStack>
41 #include <QString>
42 #include <QPoint>
43 #include <QShortcut>
44 #include <memory>
45 #include <vector>
46 #include <atomic>
47 #include "bamboo_tracker.hpp"
48 #include "configuration.hpp"
49 #include "song.hpp"
50 #include "gui/pattern_editor/pattern_position.hpp"
51 #include "gui/color_palette.hpp"
52 #include "misc.hpp"
53 
54 class PatternEditorPanel : public QWidget
55 {
56 	Q_OBJECT
57 public:
58 	explicit PatternEditorPanel(QWidget *parent = nullptr);
59 	~PatternEditorPanel() override;
60 	void setCore(std::shared_ptr<BambooTracker> core);
61 	bool isReadyCore() const;
62 	void setCommandStack(std::weak_ptr<QUndoStack> stack);
63 	void setConfiguration(std::shared_ptr<Configuration> config);
64 	void setColorPallete(std::shared_ptr<ColorPalette> palette);
65 
66 	void changeEditable();
67 	int getFullColmunSize() const;
68 	void updatePositionByStepUpdate(bool isFirstUpdate, bool forceJump = false, bool trackChanged = false);
69 	int getScrollableCountByTrack() const;
70 
71 	void changeMarker();
72 
73 	void copySelectedCells();
74 	void cutSelectedCells();
75 
76 	void redrawByPatternChanged(bool patternSizeChanged = false);
77 	void redrawByFocusChanged();
78 	void redrawByHoverChanged();
79 	void redrawByMaskChanged();
80 	void redrawPatterns();
81 	void redrawAll();
82 
83 	void resetEntryCount();
84 
85 	void waitPaintFinish();
86 
87 	QString getHeaderFont() const;
88 	int getHeaderFontSize() const;
89 	QString getRowsFont() const;
90 	int getRowsFontSize() const;
91 	void setFonts(QString headerFont, int headerSize, QString rowsFont, int rowsSize);
92 
93 	void setVisibleTracks(std::vector<int> tracks);
94 	std::vector<int> getVisibleTracks() const;
95 
96 public slots:
97 	void onHScrollBarChanged(int num);
98 	void onVScrollBarChanged(int num);
99 	void onOrderListCurrentTrackChanged(int idx);
100 	void onOrderListCurrentOrderChanged(int num);
101 
102 	void onOrderListEdited();
103 	void onDefaultPatternSizeChanged();
104 	void onShortcutUpdated();
105 
106 	void setPatternHighlight1Count(int count);
107 	void setPatternHighlight2Count(int count);
108 	void setEditableStep(int n);
109 
110 	void onSongLoaded();
111 
112 	void onDeletePressed();
113 	void onPastePressed();
114 	void onPasteMixPressed();
115 	void onPasteOverwritePressed();
116 	void onPasteInsertPressed();
117 	/// 0: None
118 	/// 1: All
119 	/// 2: Row
120 	/// 3: Column
121 	/// 4: Pattern
122 	/// 5: Order
123 	void onSelectPressed(int type);
124 	void onNoteTransposePressed(int seminote);
125 	void onToggleTrackPressed();
126 	void onSoloTrackPressed();
127 	void onUnmuteAllPressed();
128 	void onExpandPressed();
129 	void onShrinkPressed();
130 	void onInterpolatePressed();
131 	void onReversePressed();
132 	void onReplaceInstrumentPressed();
133 	void onExpandEffectColumnPressed(int trackVisIdx);
134 	void onShrinkEffectColumnPressed(int trackVisIdx);
135 	void onFollowModeChanged();
136 	void onChangeValuesPressed(int value);
137 	void onPlayStepPressed();
138 
139 signals:
140 	void hScrollBarChangeRequested(int num);
141 	void vScrollBarChangeRequested(int num, int max);
142 	void currentTrackChanged(int num);
143 	void currentOrderChanged(int num, int max);
144 	void effectColsCompanded(int num, int max);
145 
146 	void selected(bool isSelected);
147 	void instrumentEntered(int num);
148 	void volumeEntered(int volume);
149 	void effectEntered(QString text);
150 
151 protected:
152 	bool event(QEvent *event) override;
153 	bool keyPressed(QKeyEvent* event);
154 	bool keyReleased(QKeyEvent* event);
155 	void paintEvent(QPaintEvent* event) override;
156 	void resizeEvent(QResizeEvent* event) override;
157 	void mousePressEvent(QMouseEvent* event) override;
158 	void mouseMoveEvent(QMouseEvent* event) override;
159 	void mouseReleaseEvent(QMouseEvent* event) override;
160 	void mouseDoubleClickEvent(QMouseEvent* event) override;
161 	bool mouseHoverd(QHoverEvent* event);
162 	void wheelEvent(QWheelEvent* event) override;
163 	void leaveEvent(QEvent* event) override;
164 
165 	// Midi
166 private:
167 	static void midiThreadReceivedEvent(double delay, const uint8_t *msg, size_t len, void *userData);
168 private slots:
169 	void midiKeyEvent(uchar status, uchar key, uchar velocity);
170 
171 private:
172 	QPixmap completePixmap_, backPixmap_, textPixmap_, forePixmap_, headerPixmap_;
173 	std::shared_ptr<BambooTracker> bt_;
174 	std::weak_ptr<QUndoStack> comStack_;
175 	std::shared_ptr<Configuration> config_;
176 	std::shared_ptr<ColorPalette> palette_;
177 
178 	QFont stepFont_, headerFont_;
179 	int stepFontWidth_, stepFontHeight_, stepFontAscent_, stepFontLeading_;
180 	int headerFontAscent_;
181 
182 	int widthSpace_, widthSpaceDbl_;
183 	int stepNumWidthCnt_, stepNumWidth_, stepNumBase_;
184 	int baseTrackWidth_;
185 	int toneNameWidth_, instWidth_;
186 	int volWidth_;
187 	int effWidth_, effIDWidth_, effValWidth_;
188 	int tracksWidthFromLeftToEnd_;
189 	int hdMuteToggleWidth_, hdEffCompandButtonWidth_;
190 	int headerHeight_;
191 	int hdPlusY_, hdMinusY_;
192 	int curRowBaselineY_;
193 	int curRowY_;
194 
195 	std::vector<int> visTracks_, rightEffn_;
196 
197 	int leftTrackVisIdx_;
198 	SongStyle songStyle_;
199 
200 	int curSongNum_;
201 	PatternPosition curPos_, hovPos_;
202 	PatternPosition mousePressPos_, mouseReleasePos_;
203 	PatternPosition selLeftAbovePos_, selRightBelowPos_;
204 	PatternPosition shiftPressedPos_;
205 	PatternPosition doubleClickPos_;
206 	PatternPosition markerPos_;
207 
208 	bool isIgnoreToSlider_, isIgnoreToOrder_;
209 
210 	bool isPressedPlus_, isPressedMinus_;
211 
212 	int entryCnt_;
213 
214 	int selectAllState_;
215 	bool isMuteElse_;
216 
217 	int hl1Cnt_, hl2Cnt_;
218 	int editableStepCnt_;
219 
220 	int viewedRowCnt_;
221 	int viewedRegionHeight_;
222 	int viewedRowsHeight_, viewedRowOffset_, viewedCenterY_, viewedCenterBaseY_;
223 	PatternPosition viewedFirstPos_, viewedCenterPos_, viewedLastPos_;
224 
225 	bool backChanged_, textChanged_, foreChanged_, headerChanged_, focusChanged_, followModeChanged_;
226 	bool hasFocussedBefore_;
227 	int stepDownCount_;
228 
229 	std::atomic_bool repaintable_;	// Recurrensive repaint guard
230 	std::atomic_int repaintingCnt_;
231 	std::atomic_bool isInitedFirstMod_;
232 
233 	// Shortcuts
234 	QShortcut upSc_, upWSSc_, dnSc_, dnWSSc_, pgUpSc_, pgUpWSSc_, pgDnSc_, pgDnWSSc_;
235 	QShortcut homeSc_, homeWSSc_, endSc_, endWSSc_, hlUpSc_, hlUpWSSc_, hlDnSc_, hlDnWSSc_;
236 	QShortcut ltSc_, ltWSSc_, rtSc_, rtWSSc_;
237 	QShortcut keyOffSc_, echoBufSc_, stepMvUpSc_, stepMvDnSc_, expandColSc_, shrinkColSc_;
238 
239 	// Meta methods
240 	int midiKeyEventMethod_;
241 
242 	void funcResize();
243 	void updateSizes();
244 	void initDisplay();
245 	void drawPattern(const QRect& rect);
246 	void drawRows(int maxWidth);
247 	void quickDrawRows(int maxWidth);
248 	/// Return:
249 	///		track width
250 	int drawStep(QPainter& forePainter, QPainter& textPainter, QPainter& backPainter, int trackVisIdx, int orderNum, int stepNum, int x, int baseY, int rowY);
251 	void drawHeaders(int maxWidth);
252 	void drawBorders(int maxWidth);
253 	void drawShadow();
254 
255 	// NOTE: Calculated by visible tracks
256 	int calculateTracksWidthWithRowNum(int beginIdx, int endIdx) const;
257 	int calculateColNumInRow(int trackVisIdx, int colNumInTrack, bool isExpanded = false) const;
258 	int calculateColumnDistance(int beginTrackIdx, int beginColumn, int endTrackIdx, int endColumn, bool isExpanded = false) const;
259 	int calculateStepDistance(int beginOrder, int beginStep, int endOrder, int endStep) const;
260 	PatternPosition calculatePositionFrom(int order, int step, int by) const;
261 	QPoint calculateCurrentCursorPosition() const;
262 
updateTracksWidthFromLeftToEnd()263 	inline void updateTracksWidthFromLeftToEnd()
264 	{
265 		tracksWidthFromLeftToEnd_ = calculateTracksWidthWithRowNum(
266 										leftTrackVisIdx_, static_cast<int>(visTracks_.size()) - 1);
267 	}
268 
269 	void moveCursorToRight(int n);
270 	void moveViewToRight(int n);
271 	void moveCursorToDown(int n);
272 
checkSelectionByCursorMove(bool isShift)273 	inline void checkSelectionByCursorMove(bool isShift) {
274 		if (isShift) setSelectedRectangle(shiftPressedPos_, curPos_);
275 		else onSelectPressed(0);
276 	}
277 
278 	bool enterToneData(QKeyEvent* event);
279 	void setStepKeyOn(Note note, int octave);
280 	bool enterInstrumentData(int key);
281 	void setStepInstrument(int num);
282 	bool enterVolumeData(int key);
283 	void setStepVolume(int volume);
284 	bool enterEffectID(int key);
285 	void setStepEffectID(QString str);
286 	bool enterEffectValue(int key);
287 	void setStepEffectValue(int value);
288 
updateEntryCount()289 	inline int updateEntryCount()
290 	{
291 		entryCnt_ = (entryCnt_ + 1) % 2;
292 		return entryCnt_;
293 	}
294 
295 	void insertStep();
296 	void deletePreviousStep();
297 
298 	void eraseSelectedCells();
299 	void pasteCopiedCells(const PatternPosition& cursorPos);
300 	void pasteMixCopiedCells(const PatternPosition& cursorPos);
301 	void pasteOverwriteCopiedCells(const PatternPosition& cursorPos);
302 	void pasteInsertCopiedCells(const PatternPosition& cursorPos);
303 	using PatternCells = std::vector<std::vector<std::string>>;
304 	PatternCells decodeCells(QString str, int& startCol);
305 	PatternPosition getPasteLeftAbovePosition(
306 			int pasteCol, const PatternPosition& cursorPos, size_t cellW) const;
307 	PatternCells compandPasteCells(const PatternPosition& laPos, const PatternCells& cells);
308 
309 	void transposeNote(const PatternPosition& startPos, const PatternPosition& endPos, int seminote);
310 	void changeValuesInPattern(const PatternPosition& startPos, const PatternPosition& endPos, int value);
311 
312 	void toggleTrack(int trackIdx);
313 	void soloTrack(int trackIdx);
314 
315 	void setSelectedRectangle(const PatternPosition& start, const PatternPosition& end);
316 	bool isSelectedCell(int trackVisIdx, int colNum, int orderNum, int stepNum);
317 
318 	void showPatternContextMenu(const PatternPosition& pos, const QPoint& point);
319 };
320 
321 #endif // PATTERN_EDITOR_PANEL_HPP
322