@@ -10,6 +10,9 @@ namespace app { | |||||
/** Implements vertical dragging behavior for ParamWidgets */ | /** Implements vertical dragging behavior for ParamWidgets */ | ||||
struct Knob : ParamWidget { | struct Knob : ParamWidget { | ||||
struct Internal; | |||||
Internal* internal; | |||||
/** Multiplier for mouse movement to adjust knob value */ | /** Multiplier for mouse movement to adjust knob value */ | ||||
float speed = 1.0; | float speed = 1.0; | ||||
/** Drag horizontally instead of vertically. */ | /** Drag horizontally instead of vertically. */ | ||||
@@ -19,11 +22,8 @@ struct Knob : ParamWidget { | |||||
/** DEPRECATED. Use `ParamQuantity::snapEnabled`. */ | /** DEPRECATED. Use `ParamQuantity::snapEnabled`. */ | ||||
bool snap = false; | bool snap = false; | ||||
/** Value of the knob before dragging. */ | |||||
float oldValue = 0.f; | |||||
/** Fractional value between the param's value and the dragged knob position. */ | |||||
float snapDelta = 0.f; | |||||
Knob(); | |||||
~Knob(); | |||||
void initParamQuantity() override; | void initParamQuantity() override; | ||||
void onHover(const event::Hover& e) override; | void onHover(const event::Hover& e) override; | ||||
void onButton(const event::Button& e) override; | void onButton(const event::Button& e) override; | ||||
@@ -27,7 +27,15 @@ extern float zoom; | |||||
extern bool invertZoom; | extern bool invertZoom; | ||||
extern float cableOpacity; | extern float cableOpacity; | ||||
extern float cableTension; | extern float cableTension; | ||||
extern bool allowCursorLock; | |||||
enum KnobMode { | |||||
KNOB_MODE_LINEAR, | |||||
KNOB_MODE_LINEAR_UNLOCKED, | |||||
KNOB_MODE_LINEAR_SPEED, | |||||
KNOB_MODE_LINEAR_SPEED_UNLOCKED, | |||||
KNOB_MODE_CIRCULAR_ABSOLUTE, | |||||
KNOB_MODE_CIRCULAR_RELATIVE, | |||||
}; | |||||
extern KnobMode knobMode; | |||||
extern float sampleRate; | extern float sampleRate; | ||||
extern int threadCount; | extern int threadCount; | ||||
extern bool paramTooltip; | extern bool paramTooltip; | ||||
@@ -12,6 +12,22 @@ namespace app { | |||||
static const float KNOB_SENSITIVITY = 0.0015f; | static const float KNOB_SENSITIVITY = 0.0015f; | ||||
struct Knob::Internal { | |||||
/** Value of the knob before dragging. */ | |||||
float oldValue = 0.f; | |||||
/** Fractional value between the param's value and the dragged knob position. */ | |||||
float snapDelta = 0.f; | |||||
}; | |||||
Knob::Knob() { | |||||
internal = new Internal; | |||||
} | |||||
Knob::~Knob() { | |||||
delete internal; | |||||
} | |||||
void Knob::initParamQuantity() { | void Knob::initParamQuantity() { | ||||
ParamWidget::initParamQuantity(); | ParamWidget::initParamQuantity(); | ||||
engine::ParamQuantity* pq = getParamQuantity(); | engine::ParamQuantity* pq = getParamQuantity(); | ||||
@@ -43,8 +59,8 @@ void Knob::onDragStart(const event::DragStart& e) { | |||||
engine::ParamQuantity* pq = getParamQuantity(); | engine::ParamQuantity* pq = getParamQuantity(); | ||||
if (pq) { | if (pq) { | ||||
oldValue = pq->getSmoothValue(); | |||||
snapDelta = 0.f; | |||||
internal->oldValue = pq->getSmoothValue(); | |||||
internal->snapDelta = 0.f; | |||||
} | } | ||||
APP->window->cursorLock(); | APP->window->cursorLock(); | ||||
@@ -59,13 +75,13 @@ void Knob::onDragEnd(const event::DragEnd& e) { | |||||
engine::ParamQuantity* pq = getParamQuantity(); | engine::ParamQuantity* pq = getParamQuantity(); | ||||
if (pq) { | if (pq) { | ||||
float newValue = pq->getSmoothValue(); | float newValue = pq->getSmoothValue(); | ||||
if (oldValue != newValue) { | |||||
if (internal->oldValue != newValue) { | |||||
// Push ParamChange history action | // Push ParamChange history action | ||||
history::ParamChange* h = new history::ParamChange; | history::ParamChange* h = new history::ParamChange; | ||||
h->name = "move knob"; | h->name = "move knob"; | ||||
h->moduleId = module->id; | h->moduleId = module->id; | ||||
h->paramId = paramId; | h->paramId = paramId; | ||||
h->oldValue = oldValue; | |||||
h->oldValue = internal->oldValue; | |||||
h->newValue = newValue; | h->newValue = newValue; | ||||
APP->history->push(h); | APP->history->push(h); | ||||
} | } | ||||
@@ -103,9 +119,9 @@ void Knob::onDragMove(const event::DragMove& e) { | |||||
if (pq->snapEnabled) { | if (pq->snapEnabled) { | ||||
// Replace delta with an accumulated delta since the last integer knob. | // Replace delta with an accumulated delta since the last integer knob. | ||||
snapDelta += delta; | |||||
delta = std::trunc(snapDelta); | |||||
snapDelta -= delta; | |||||
internal->snapDelta += delta; | |||||
delta = std::trunc(internal->snapDelta); | |||||
internal->snapDelta -= delta; | |||||
} | } | ||||
// Set value | // Set value | ||||
@@ -316,15 +316,39 @@ struct ParamTooltipItem : ui::MenuItem { | |||||
} | } | ||||
}; | }; | ||||
struct LockModulesItem : ui::MenuItem { | |||||
struct KnobModeValueItem : ui::MenuItem { | |||||
settings::KnobMode knobMode; | |||||
void onAction(const event::Action& e) override { | void onAction(const event::Action& e) override { | ||||
settings::lockModules ^= true; | |||||
settings::knobMode = knobMode; | |||||
} | } | ||||
}; | }; | ||||
struct CursorLockItem : ui::MenuItem { | |||||
struct KnobModeItem : ui::MenuItem { | |||||
ui::Menu* createChildMenu() override { | |||||
ui::Menu* menu = new ui::Menu; | |||||
static const std::string knobModeNames[] = { | |||||
"Linear (locked cursor)", | |||||
"Linear", | |||||
"Adjustable linear (locked cursor)", | |||||
"Adjustable linear", | |||||
"Absolute rotary", | |||||
"Relative rotary", | |||||
}; | |||||
for (int i = 0; i < (int) LENGTHOF(knobModeNames); i++) { | |||||
KnobModeValueItem* item = new KnobModeValueItem; | |||||
item->knobMode = (settings::KnobMode) i; | |||||
item->text = knobModeNames[i]; | |||||
item->rightText = CHECKMARK(settings::knobMode == i); | |||||
menu->addChild(item); | |||||
} | |||||
return menu; | |||||
} | |||||
}; | |||||
struct LockModulesItem : ui::MenuItem { | |||||
void onAction(const event::Action& e) override { | void onAction(const event::Action& e) override { | ||||
settings::allowCursorLock ^= true; | |||||
settings::lockModules ^= true; | |||||
} | } | ||||
}; | }; | ||||
@@ -365,20 +389,20 @@ struct ViewButton : MenuButton { | |||||
menu->box.size.x = box.size.x; | menu->box.size.x = box.size.x; | ||||
ParamTooltipItem* paramTooltipItem = new ParamTooltipItem; | ParamTooltipItem* paramTooltipItem = new ParamTooltipItem; | ||||
paramTooltipItem->text = "Parameter tooltips"; | |||||
paramTooltipItem->text = "Show tooltips"; | |||||
paramTooltipItem->rightText = CHECKMARK(settings::paramTooltip); | paramTooltipItem->rightText = CHECKMARK(settings::paramTooltip); | ||||
menu->addChild(paramTooltipItem); | menu->addChild(paramTooltipItem); | ||||
KnobModeItem* knobModeItem = new KnobModeItem; | |||||
knobModeItem->text = "Knob mode"; | |||||
knobModeItem->rightText = RIGHT_ARROW; | |||||
menu->addChild(knobModeItem); | |||||
LockModulesItem* lockModulesItem = new LockModulesItem; | LockModulesItem* lockModulesItem = new LockModulesItem; | ||||
lockModulesItem->text = "Lock modules"; | lockModulesItem->text = "Lock modules"; | ||||
lockModulesItem->rightText = CHECKMARK(settings::lockModules); | lockModulesItem->rightText = CHECKMARK(settings::lockModules); | ||||
menu->addChild(lockModulesItem); | menu->addChild(lockModulesItem); | ||||
CursorLockItem* cursorLockItem = new CursorLockItem; | |||||
cursorLockItem->text = "Lock cursor while dragging"; | |||||
cursorLockItem->rightText = CHECKMARK(settings::allowCursorLock); | |||||
menu->addChild(cursorLockItem); | |||||
ZoomSlider* zoomSlider = new ZoomSlider; | ZoomSlider* zoomSlider = new ZoomSlider; | ||||
zoomSlider->box.size.x = 200.0; | zoomSlider->box.size.x = 200.0; | ||||
menu->addChild(zoomSlider); | menu->addChild(zoomSlider); | ||||
@@ -393,6 +417,7 @@ struct ViewButton : MenuButton { | |||||
FrameRateItem* frameRateItem = new FrameRateItem; | FrameRateItem* frameRateItem = new FrameRateItem; | ||||
frameRateItem->text = "Frame rate"; | frameRateItem->text = "Frame rate"; | ||||
frameRateItem->rightText = RIGHT_ARROW; | |||||
menu->addChild(frameRateItem); | menu->addChild(frameRateItem); | ||||
FullscreenItem* fullscreenItem = new FullscreenItem; | FullscreenItem* fullscreenItem = new FullscreenItem; | ||||
@@ -22,7 +22,7 @@ float zoom = 0.0; | |||||
bool invertZoom = false; | bool invertZoom = false; | ||||
float cableOpacity = 0.5; | float cableOpacity = 0.5; | ||||
float cableTension = 0.5; | float cableTension = 0.5; | ||||
bool allowCursorLock = true; | |||||
KnobMode knobMode = KNOB_MODE_LINEAR; | |||||
float sampleRate = 44100.0; | float sampleRate = 44100.0; | ||||
int threadCount = 1; | int threadCount = 1; | ||||
bool paramTooltip = false; | bool paramTooltip = false; | ||||
@@ -65,7 +65,7 @@ json_t* toJson() { | |||||
json_object_set_new(rootJ, "cableTension", json_real(cableTension)); | json_object_set_new(rootJ, "cableTension", json_real(cableTension)); | ||||
json_object_set_new(rootJ, "allowCursorLock", json_boolean(allowCursorLock)); | |||||
json_object_set_new(rootJ, "knobMode", json_integer((int) knobMode)); | |||||
json_object_set_new(rootJ, "sampleRate", json_real(sampleRate)); | json_object_set_new(rootJ, "sampleRate", json_real(sampleRate)); | ||||
@@ -141,9 +141,16 @@ void fromJson(json_t* rootJ) { | |||||
if (tensionJ) | if (tensionJ) | ||||
cableTension = json_number_value(tensionJ); | cableTension = json_number_value(tensionJ); | ||||
// legacy v1 | |||||
json_t* allowCursorLockJ = json_object_get(rootJ, "allowCursorLock"); | json_t* allowCursorLockJ = json_object_get(rootJ, "allowCursorLock"); | ||||
if (allowCursorLockJ) | |||||
allowCursorLock = json_is_true(allowCursorLockJ); | |||||
if (allowCursorLockJ) { | |||||
if (json_is_false(allowCursorLockJ)) | |||||
knobMode = KNOB_MODE_LINEAR_UNLOCKED; | |||||
} | |||||
json_t* knobModeJ = json_object_get(rootJ, "knobMode"); | |||||
if (knobModeJ) | |||||
knobMode = (KnobMode) json_integer_value(knobModeJ); | |||||
json_t* sampleRateJ = json_object_get(rootJ, "sampleRate"); | json_t* sampleRateJ = json_object_get(rootJ, "sampleRate"); | ||||
if (sampleRateJ) | if (sampleRateJ) | ||||
@@ -478,21 +478,17 @@ void Window::close() { | |||||
} | } | ||||
void Window::cursorLock() { | void Window::cursorLock() { | ||||
if (settings::allowCursorLock) { | |||||
#if defined ARCH_MAC | #if defined ARCH_MAC | ||||
glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); | |||||
glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); | |||||
#else | #else | ||||
glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_DISABLED); | |||||
glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_DISABLED); | |||||
#endif | #endif | ||||
internal->ignoreNextMouseDelta = true; | |||||
} | |||||
internal->ignoreNextMouseDelta = true; | |||||
} | } | ||||
void Window::cursorUnlock() { | void Window::cursorUnlock() { | ||||
if (settings::allowCursorLock) { | |||||
glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_NORMAL); | |||||
internal->ignoreNextMouseDelta = true; | |||||
} | |||||
glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_NORMAL); | |||||
internal->ignoreNextMouseDelta = true; | |||||
} | } | ||||
bool Window::isCursorLocked() { | bool Window::isCursorLocked() { | ||||