Deluge Firmware 1.3.0
Build date: 2025.11.04
Loading...
Searching...
No Matches
direction.h
1/*
2 * Copyright (c) 2014-2023 Synthstrom Audible Limited
3 *
4 * This file is part of The Synthstrom Audible Deluge Firmware.
5 *
6 * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software Foundation,
8 * either version 3 of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along with this program.
15 * If not, see <https://www.gnu.org/licenses/>.
16 */
17#pragma once
18#include "definitions_cxx.hpp"
19#include "gui/menu_item/selection.h"
20#include "gui/ui/sound_editor.h"
21#include "gui/views/instrument_clip_view.h"
22#include "hid/display/oled.h"
23#include "model/clip/instrument_clip.h"
24#include "model/instrument/kit.h"
25#include "model/model_stack.h"
26#include "model/note/note_row.h"
27#include "model/song/song.h"
28
29namespace deluge::gui::menu_item::sequence {
30class Direction final : public Selection {
31public:
32 using Selection::Selection;
33
35 if (getCurrentUI() == &soundEditor && soundEditor.inNoteRowEditor() && !isUIModeActive(UI_MODE_AUDITIONING)) {
36 display->displayPopup("Select Row");
37 return false;
38 }
39 return true;
40 }
41
42 ModelStackWithNoteRow* getIndividualNoteRow(ModelStackWithTimelineCounter* modelStack) {
43 auto* clip = static_cast<InstrumentClip*>(modelStack->getTimelineCounter());
44 if (!clip->affectEntire && clip->output->type == OutputType::KIT) {
45 Kit* kit = getCurrentKit();
46 if (kit->selectedDrum != nullptr) {
47 return clip->getNoteRowForDrum(modelStack, kit->selectedDrum); // Still might be NULL;
48 }
49 }
50 else if (clip->output->type != OutputType::KIT) {
51 if (soundEditor.selectedNoteRow) {
52 // get model stack with note row but don't create note row if it doesn't exist
53 ModelStackWithNoteRow* modelStackWithNoteRow =
54 clip->getNoteRowOnScreen(instrumentClipView.lastAuditionedYDisplay, modelStack);
55 if (!modelStackWithNoteRow->getNoteRowAllowNull()) { // if note row doesn't exist yet, create it
56 modelStackWithNoteRow = instrumentClipView.createNoteRowForYDisplay(
57 modelStack, instrumentClipView.lastAuditionedYDisplay);
58 }
59 return modelStackWithNoteRow;
60 }
61 }
62 return modelStack->addNoteRow(0, nullptr);
63 }
64
65 void readCurrentValue() override {
66 char modelStackMemory[MODEL_STACK_MAX_SIZE];
67 ModelStackWithTimelineCounter* modelStack = currentSong->setupModelStackWithCurrentClip(modelStackMemory);
68 ModelStackWithNoteRow* modelStackWithNoteRow = getIndividualNoteRow(modelStack);
69
70 if (modelStackWithNoteRow->getNoteRowAllowNull() != nullptr) {
71 this->setValue(modelStackWithNoteRow->getNoteRow()->sequenceDirectionMode);
72 }
73 else {
74 this->setValue(getCurrentInstrumentClip()->sequenceDirectionMode);
75 }
76 }
77
78 void writeCurrentValue() override {
79 auto current_value = this->getValue<SequenceDirection>();
80 char modelStackMemory[MODEL_STACK_MAX_SIZE];
81 ModelStackWithTimelineCounter* modelStack = currentSong->setupModelStackWithCurrentClip(modelStackMemory);
82 ModelStackWithNoteRow* modelStackWithNoteRow = getIndividualNoteRow(modelStack);
83 if (modelStackWithNoteRow->getNoteRowAllowNull() != nullptr) {
84 modelStackWithNoteRow->getNoteRow()->setSequenceDirectionMode(modelStackWithNoteRow, current_value);
85 }
86 else {
87 getCurrentInstrumentClip()->setSequenceDirectionMode(modelStackWithNoteRow->toWithTimelineCounter(),
88 current_value);
89 }
90 }
91
92 deluge::vector<std::string_view> getOptions(OptType optType) override {
93 (void)optType;
94 deluge::vector<std::string_view> sequenceDirectionOptions = {
95 l10n::getView(l10n::String::STRING_FOR_FORWARD),
96 l10n::getView(l10n::String::STRING_FOR_REVERSED),
97 l10n::getView(l10n::String::STRING_FOR_PING_PONG),
98 };
99
100 char modelStackMemory[MODEL_STACK_MAX_SIZE];
101 ModelStackWithTimelineCounter* modelStack = currentSong->setupModelStackWithCurrentClip(modelStackMemory);
102 ModelStackWithNoteRow* modelStackWithNoteRow = getIndividualNoteRow(modelStack);
103 if (modelStackWithNoteRow->getNoteRowAllowNull() != nullptr) {
104 sequenceDirectionOptions.push_back(l10n::getView(l10n::String::STRING_FOR_NONE));
105 }
106
107 return sequenceDirectionOptions;
108 }
109
110 MenuPermission checkPermissionToBeginSession(ModControllableAudio* modControllable, int32_t whichThing,
111 ::MultiRange** currentRange) override {
112 OutputType outputType = getCurrentOutputType();
113 if (!getCurrentInstrumentClip()->affectEntire && outputType == OutputType::KIT
114 && (getCurrentKit()->selectedDrum == nullptr)) {
115 return MenuPermission::NO;
116 }
117 else if (outputType != OutputType::KIT) {
118 soundEditor.selectedNoteRow = isUIModeActive(UI_MODE_AUDITIONING);
119 }
120 return MenuPermission::YES;
121 }
122
123 void renderInHorizontalMenu(const HorizontalMenuSlotParams& slot) override {
124 using namespace deluge::hid::display;
125 oled_canvas::Canvas& image = OLED::main;
126
127 const auto current_value = this->getValue<SequenceDirection>();
128 if (current_value == SequenceDirection::OBEY_PARENT) {
129 return Selection::renderInHorizontalMenu(slot);
130 }
131
132 const uint8_t icon_y = slot.start_y + kHorizontalMenuSlotYOffset;
133 if (current_value == SequenceDirection::PINGPONG) {
134 image.drawIconCentered(OLED::directionIcon, slot.start_x + 2, slot.width, icon_y);
135 image.drawIconCentered(OLED::directionIcon, slot.start_x - 2, slot.width, icon_y, true);
136 }
137 else {
138 image.drawIconCentered(OLED::directionIcon, slot.start_x, slot.width, icon_y,
139 current_value == SequenceDirection::REVERSE);
140 }
141 }
142};
143} // namespace deluge::gui::menu_item::sequence
Definition instrument_clip.h:47
Definition kit.h:34
Definition model_stack.h:189
Definition model_stack.h:129
Definition selection.h:26
bool shouldEnterSubmenu()
Check if selecting this menu item (with select encoder) should enter a submenu.
Definition direction.h:34
void readCurrentValue() override
Like readValueAgain, but does not redraw.
Definition direction.h:65