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