Browse Source

Don't close menu when Ctrl-clicking items. Add argument to MenuItem helpers to disable this behavior.

tags/v2.0.0
Andrew Belt 3 years ago
parent
commit
b605c2c258
7 changed files with 91 additions and 61 deletions
  1. +66
    -21
      include/helpers.hpp
  2. +5
    -2
      include/ui/MenuItem.hpp
  3. +0
    -16
      src/app/MenuBar.cpp
  4. +2
    -3
      src/app/ModuleBrowser.cpp
  5. +1
    -1
      src/app/ModuleWidget.cpp
  6. +8
    -6
      src/app/RackWidget.cpp
  7. +9
    -12
      src/ui/MenuItem.cpp

+ 66
- 21
include/helpers.hpp View File

@@ -204,17 +204,22 @@ Example:
));
*/
template <class TMenuItem = ui::MenuItem>
TMenuItem* createMenuItem(std::string text, std::string rightText, std::function<void()> action, bool disabled = false) {
TMenuItem* createMenuItem(std::string text, std::string rightText, std::function<void()> action, bool disabled = false, bool alwaysConsume = false) {
struct Item : TMenuItem {
std::function<void()> action;
bool alwaysConsume;

void onAction(const event::Action& e) override {
action();
if (alwaysConsume)
e.consume(this);
}
};

Item* item = createMenuItem<Item>(text, rightText);
item->action = action;
item->disabled = disabled;
item->alwaysConsume = alwaysConsume;
return item;
}

@@ -231,17 +236,29 @@ Example:
}
));
*/
inline ui::MenuItem* createCheckMenuItem(std::string text, std::function<bool()> checked, std::function<void()> action) {
struct Item : ui::MenuItem {
template <class TMenuItem = ui::MenuItem>
ui::MenuItem* createCheckMenuItem(std::string text, std::function<bool()> checked, std::function<void()> action, bool disabled = false, bool alwaysConsume = false) {
struct Item : TMenuItem {
std::function<bool()> checked;
std::function<void()> action;
bool alwaysConsume;

void step() override {
this->rightText = CHECKMARK(checked());
TMenuItem::step();
}
void onAction(const event::Action& e) override {
action();
if (alwaysConsume)
e.consume(this);
}
};

Item* item = createMenuItem<Item>(text, CHECKMARK(checked()));
Item* item = createMenuItem<Item>(text);
item->checked = checked;
item->action = action;
item->disabled = disabled;
item->alwaysConsume = alwaysConsume;
return item;
}

@@ -258,20 +275,29 @@ Example:
}
));
*/
inline ui::MenuItem* createBoolMenuItem(std::string text, std::function<bool()> getter, std::function<void(bool state)> setter) {
struct Item : ui::MenuItem {
template <class TMenuItem = ui::MenuItem>
ui::MenuItem* createBoolMenuItem(std::string text, std::function<bool()> getter, std::function<void(bool state)> setter, bool disabled = false, bool alwaysConsume = false) {
struct Item : TMenuItem {
std::function<bool()> getter;
std::function<void(size_t)> setter;
bool val;
bool alwaysConsume;

void step() override {
this->rightText = CHECKMARK(getter());
TMenuItem::step();
}
void onAction(const event::Action& e) override {
setter(val);
setter(!getter());
if (alwaysConsume)
e.consume(this);
}
};

bool currVal = getter();
Item* item = createMenuItem<Item>(text, CHECKMARK(currVal));
Item* item = createMenuItem<Item>(text);
item->getter = getter;
item->setter = setter;
item->val = !currVal;
item->disabled = disabled;
item->alwaysConsume = alwaysConsume;
return item;
}

@@ -300,8 +326,9 @@ Example:
}
));
*/
inline ui::MenuItem* createSubmenuItem(std::string text, std::string rightText, std::function<void(ui::Menu* menu)> createMenu, bool disabled = false) {
struct Item : ui::MenuItem {
template <class TMenuItem = ui::MenuItem>
ui::MenuItem* createSubmenuItem(std::string text, std::string rightText, std::function<void(ui::Menu* menu)> createMenu, bool disabled = false) {
struct Item : TMenuItem {
std::function<void(ui::Menu* menu)> createMenu;

ui::Menu* createChildMenu() override {
@@ -311,7 +338,7 @@ inline ui::MenuItem* createSubmenuItem(std::string text, std::string rightText,
}
};

Item* item = createMenuItem<Item>(text, rightText + (rightText.empty() ? "" : " ") + RIGHT_ARROW);
Item* item = createMenuItem<Item>(text, rightText + (rightText.empty() ? "" : " ") + RIGHT_ARROW);
item->createMenu = createMenu;
item->disabled = disabled;
return item;
@@ -331,40 +358,58 @@ Example:
}
));
*/
inline ui::MenuItem* createIndexSubmenuItem(std::string text, std::vector<std::string> labels, std::function<size_t()> getter, std::function<void(size_t val)> setter) {
template <class TMenuItem = ui::MenuItem>
ui::MenuItem* createIndexSubmenuItem(std::string text, std::vector<std::string> labels, std::function<size_t()> getter, std::function<void(size_t val)> setter, bool disabled = false, bool alwaysConsume = false) {
struct IndexItem : ui::MenuItem {
std::function<size_t()> getter;
std::function<void(size_t)> setter;
size_t index;
bool alwaysConsume;

void step() override {
size_t currIndex = getter();
this->rightText = CHECKMARK(currIndex == index);
MenuItem::step();
}
void onAction(const event::Action& e) override {
setter(index);
if (alwaysConsume)
e.consume(this);
}
};

struct Item : ui::MenuItem {
struct Item : TMenuItem {
std::function<size_t()> getter;
std::function<void(size_t)> setter;
std::vector<std::string> labels;
bool alwaysConsume;

void step() override {
size_t currIndex = getter();
std::string label = (currIndex < labels.size()) ? labels[currIndex] : "";
this->rightText = label + " " + RIGHT_ARROW;
TMenuItem::step();
}
ui::Menu* createChildMenu() override {
ui::Menu* menu = new ui::Menu;
size_t currIndex = getter();
for (size_t i = 0; i < labels.size(); i++) {
IndexItem* item = createMenuItem<IndexItem>(labels[i], CHECKMARK(currIndex == i));
IndexItem* item = createMenuItem<IndexItem>(labels[i]);
item->getter = getter;
item->setter = setter;
item->index = i;
item->alwaysConsume = alwaysConsume;
menu->addChild(item);
}
return menu;
}
};

size_t currIndex = getter();
std::string label = (currIndex < labels.size()) ? labels[currIndex] : "";
Item* item = createMenuItem<Item>(text, label + " " + RIGHT_ARROW);
Item* item = createMenuItem<Item>(text);
item->getter = getter;
item->setter = setter;
item->labels = labels;
item->disabled = disabled;
item->alwaysConsume = alwaysConsume;
return item;
}



+ 5
- 2
include/ui/MenuItem.hpp View File

@@ -13,16 +13,19 @@ struct MenuItem : MenuEntry {
std::string text;
std::string rightText;
bool disabled = false;
bool active = false;

void draw(const DrawArgs& args) override;
void step() override;
void onEnter(const EnterEvent& e) override;
void onDragDrop(const DragDropEvent& e) override;
void doAction();
void doAction(bool consume = true);
virtual Menu* createChildMenu() {
return NULL;
}
/** Override to handle behavior when user clicks the menu item.
Event is consumed by default. Unconsume to prevent the menu from being closed.
If Ctrl (Cmd on Mac) is held, the event is *not* pre-consumed, so if your menu must be closed, always consume the event.
*/
void onAction(const ActionEvent& e) override;
};



+ 0
- 16
src/app/MenuBar.cpp View File

@@ -344,22 +344,6 @@ struct HaloBrightnessSlider : ui::Slider {
}
};

struct FrameRateValueItem : ui::MenuItem {
int frameSwapInterval;
void onAction(const ActionEvent& e) override {
settings::frameSwapInterval = frameSwapInterval;
}
};

struct FrameRateItem : ui::MenuItem {
ui::Menu* createChildMenu() override {
ui::Menu* menu = new ui::Menu;

return menu;
}
};


struct ViewButton : MenuButton {
void onAction(const ActionEvent& e) override {
ui::Menu* menu = createMenu();


+ 2
- 3
src/app/ModuleBrowser.cpp View File

@@ -843,9 +843,8 @@ inline void TagItem::onAction(const ActionEvent& e) {
bool isSelected = (it != browser->tagIds.end());

if (tagId >= 0) {
// Actual tag
int mods = APP->window->getMods();
if ((mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
// Specific tag
if (!e.isConsumed()) {
// Multi select
if (isSelected)
browser->tagIds.erase(tagId);


+ 1
- 1
src/app/ModuleWidget.cpp View File

@@ -1091,7 +1091,7 @@ void ModuleWidget::createContextMenu() {
if (!weakThis)
return;
weakThis->removeAction();
}));
}, false, true));

appendContextMenu(menu);
}


+ 8
- 6
src/app/RackWidget.cpp View File

@@ -1122,15 +1122,17 @@ void RackWidget::appendSelectionContextMenu(ui::Menu* menu) {
int n = getNumSelected();
menu->addChild(createMenuLabel(string::f("%d selected %s", n, n == 1 ? "module" : "modules")));

// Enable alwaysConsume of menu items if the number of selected modules changes

// Select all
menu->addChild(createMenuItem("Select all", RACK_MOD_CTRL_NAME "+A", [=]() {
selectAll();
}));
}, false, true));

// Deselect
menu->addChild(createMenuItem("Deselect", RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME "+A", [=]() {
deselect();
}, n == 0));
}, n == 0, true));

// Copy
menu->addChild(createMenuItem("Copy", RACK_MOD_CTRL_NAME "+C", [=]() {
@@ -1140,12 +1142,12 @@ void RackWidget::appendSelectionContextMenu(ui::Menu* menu) {
// Paste
menu->addChild(createMenuItem("Paste", RACK_MOD_CTRL_NAME "+V", [=]() {
pasteClipboardAction();
}));
}, false, true));

// Load
menu->addChild(createMenuItem("Import selection", "", [=]() {
loadSelectionDialog();
}));
}, false, true));

// Save
menu->addChild(createMenuItem("Save selection as", "", [=]() {
@@ -1174,7 +1176,7 @@ void RackWidget::appendSelectionContextMenu(ui::Menu* menu) {
bypassText += " " CHECKMARK_STRING;
menu->addChild(createMenuItem("Bypass", bypassText, [=]() {
bypassSelectionAction(!bypassed);
}, n == 0));
}, n == 0, true));

// Duplicate
menu->addChild(createMenuItem("Duplicate", RACK_MOD_CTRL_NAME "+D", [=]() {
@@ -1184,7 +1186,7 @@ void RackWidget::appendSelectionContextMenu(ui::Menu* menu) {
// Delete
menu->addChild(createMenuItem("Delete", "Backspace/Delete", [=]() {
deleteSelectionAction();
}, n == 0));
}, n == 0, true));
}

void RackWidget::clearCables() {


+ 9
- 12
src/ui/MenuItem.cpp View File

@@ -17,9 +17,6 @@ void MenuItem::draw(const DrawArgs& args) {
if (parentMenu && parentMenu->activeEntry == this)
state = BND_ACTIVE;

if (active)
state = BND_ACTIVE;

// Main text and background
if (!disabled)
bndMenuItem(args.vg, 0.0, 0.0, box.size.x, box.size.y, state, -1, text.c_str());
@@ -58,24 +55,24 @@ void MenuItem::onEnter(const EnterEvent& e) {
}

void MenuItem::onDragDrop(const DragDropEvent& e) {
if (e.origin != this)
return;
doAction();
if (e.origin == this && !disabled) {
int mods = APP->window->getMods();
doAction((mods & RACK_MOD_MASK) != RACK_MOD_CTRL);
}
}

void MenuItem::doAction() {
if (disabled)
return;

void MenuItem::doAction(bool consume) {
widget::EventContext cAction;
ActionEvent eAction;
eAction.context = &cAction;
// Consume event by default, but allow action to un-consume it to prevent the menu from being removed.
eAction.consume(this);
if (consume) {
eAction.consume(this);
}
onAction(eAction);
if (!cAction.consumed)
return;

// Close menu
MenuOverlay* overlay = getAncestorOfType<MenuOverlay>();
if (overlay) {
overlay->requestDelete();


Loading…
Cancel
Save