#include "buttonmanageritems.h" #include #include #include "editbutton.h" #include "editsample.h" #include "keysequencevalidator.h" ButtonManagerItem::ButtonManagerItem(QTreeWidgetItem* parent, int type, uint8_t pos) : QTreeWidgetItem(parent, type), mparent(parent), pos(pos) { } ButtonManagerItem::~ButtonManagerItem() {} bool ButtonManagerItem::hasEdit() const { return false; } bool ButtonManagerItem::hasRemove() const { return false; } bool ButtonManagerItem::hasMoveUp() const { return false; } bool ButtonManagerItem::hasMoveDown() const { return false; } void ButtonManagerItem::edit() {} void ButtonManagerItem::remove() {} void ButtonManagerItem::moveUp() {} void ButtonManagerItem::moveDown() {} template T* ButtonManagerItem::getParent() const { return dynamic_cast(mparent); } template T* ButtonManagerItem::getChild(int index) const { if(childCount() <= index) return nullptr; return dynamic_cast(child(index)); } template T* ButtonManagerItem::getLastChild() const { return getChild(childCount()-1); } template T* ButtonManagerItem::getSibling(int index) const { if(mparent->childCount() <= index || index < 0) return nullptr; return dynamic_cast(mparent->child(index)); } template T* ButtonManagerItem::getItemAbove() const { return getSibling(pos-1); } template T* ButtonManagerItem::getItemBelow() const { return getSibling(pos+1); } // enforce existence of required templates template RowItem* ButtonManagerItem::getParent() const; template ButtonItem* ButtonManagerItem::getParent() const; template SampleItem* ButtonManagerItem::getParent() const; template RowItem* ButtonManagerItem::getChild(int) const; template ButtonItem* ButtonManagerItem::getChild(int) const; template SampleItem* ButtonManagerItem::getChild(int) const; template RowItem* ButtonManagerItem::getSibling(int) const; template ButtonItem* ButtonManagerItem::getSibling(int) const; template SampleItem* ButtonManagerItem::getSibling(int) const; void ButtonManagerItem::reenumerateAllSiblings() { for(uint8_t i = 0; i < mparent->childCount(); ++i) { ButtonManagerItem* item = getSibling(i); if(item) { item->pos = i; item->updatePosition(); } } } void ButtonManagerItem::expandTree() { ButtonManagerItem* c = this; while(c) { c->setExpanded(true); c = c->getParent(); } } void ButtonManagerItem::updateAllPosBellow(int8_t diff, uint8_t size) { for(uint8_t i = pos+1; i < size; ++i) { ButtonManagerItem* item = getSibling(i); if(item) { item->pos += diff; item->updatePosition(); } } } void ButtonManagerItem::updatePosition() {} RowItem::RowItem(QTreeWidgetItem* parent, uint8_t rownr, Config::RootConfig& conf) : ButtonManagerItem(parent, TYPE, rownr), conf(conf) { const std::vector& btnrow = conf.buttons.at(rownr); updatePosition(); setExpanded(true); // iterate buttons in a row for(uint8_t btnnr = 0; btnnr < btnrow.size(); btnnr++) { ButtonItem* btnItem = new ButtonItem(this, btnnr, conf); // no need to use this var, they add themself to their parent (this) (void) btnItem; } } bool RowItem::hasRemove() const { return true; } bool RowItem::hasMoveUp() const { return pos > 0; } bool RowItem::hasMoveDown() const { return pos < conf.buttons.size()-1; } void RowItem::remove() { conf.buttons.erase(conf.buttons.begin() + pos); updateAllPosBellow(-1, conf.buttons.size()+1); } void RowItem::moveUp() { //apply change to config conf.buttons.at(pos-1).swap(conf.buttons.at(pos)); // apply change in GUI //get Child above RowItem* rowaboveItem = getSibling(pos-1); if(rowaboveItem) { rowaboveItem->pos++; rowaboveItem->updatePosition(); } else { Log::error << "row above could not be updated"; } mparent->removeChild(this); mparent->insertChild(pos-1, this); expandTree(); pos--; updatePosition(); } void RowItem::moveDown() { // moving down is the same as moving the item below up RowItem* rowbelow = getSibling(pos+1); if(rowbelow) { rowbelow->moveUp(); } else { Log::error << "no item below"; } } uint8_t RowItem::getRow() const { return pos; } void RowItem::updatePosition() { setData(0, Qt::ItemDataRole::DisplayRole, QVariant(QString::fromStdString("Row " + std::to_string(pos+1)))); } std::vector& RowItem::getConfig() { return conf.buttons.at(pos); } ButtonItem::ButtonItem(RowItem* parent, uint8_t buttonnr, Config::RootConfig& conf) : ButtonManagerItem(parent, TYPE, buttonnr), conf(conf) { Config::ButtonConfig& btn = getConfig(); setData(0, Qt::ItemDataRole::DisplayRole, QString::fromStdString(btn.name)); setData(1, Qt::ItemDataRole::DisplayRole, (int) btn.samples.size()); setData(2, Qt::ItemDataRole::DisplayRole, QString::fromStdString(btn.key)); setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); // | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled // iterate samples in a button for(uint8_t samplenr = 0; samplenr < btn.samples.size(); ++samplenr) { SampleItem* sample = new SampleItem(this, samplenr, conf); // no need to use this var, they add themself to their parent (this) (void) sample; } } bool ButtonItem::hasEdit() const { return true; } bool ButtonItem::hasRemove() const { return true; } bool ButtonItem::hasMoveUp() const { return pos > 0 || getParent()->hasMoveUp(); } bool ButtonItem::hasMoveDown() const { return pos < getParent()->getConfig().size()-1 || getParent()->hasMoveDown(); } void ButtonItem::edit() { Config::ButtonConfig& buttonConf = getConfig(); EditButton editor; editor.setName(buttonConf.name); editor.setKey(buttonConf.key); editor.setWidth(buttonConf.width); editor.exec(); if(editor.result() == 0) { Log::info << "Dialog failed"; return; } buttonConf.name = editor.getName(); buttonConf.key = editor.getKey(); buttonConf.width = editor.getWidth(); setData(0, Qt::ItemDataRole::DisplayRole, QVariant(QString::fromStdString(buttonConf.name))); } void ButtonItem::remove() { auto& rowconf = getParent()->getConfig(); rowconf.erase(rowconf.begin() + pos); updateAllPosBellow(-1, rowconf.size()+1); } void ButtonItem::moveUp() { if(pos == 0) { moveToRowAbove(); return; } //apply change to config auto& rowconf = getParent()->getConfig(); std::swap(rowconf.at(pos-1), rowconf.at(pos)); // apply change in GUI //get Child above ButtonItem* buttonaboveItem = getSibling(pos-1); if(buttonaboveItem) { buttonaboveItem->pos++; } else { Log::error << "button above could not be updated"; } mparent->removeChild(this); mparent->insertChild(pos-1, this); expandTree(); pos--; } void ButtonItem::moveDown() { if(pos == getParent()->getConfig().size()-1) { moveToRowBelow(); return; } // moving down is the same as moving the item below up ButtonItem* buttonbelow = getSibling(pos+1); if(buttonbelow) { buttonbelow->moveUp(); } else { Log::error << "no item below"; } } void ButtonItem::nameWasChanged() { std::string newName = data(0, Qt::ItemDataRole::DisplayRole).toString().toStdString(); getConfig().name = newName; } void ButtonItem::keyWasChanged() { QString newShortcut = data(2, Qt::ItemDataRole::DisplayRole).toString(); KeysequenceValidator validator; int pos; Config::ButtonConfig& btn = getConfig(); if(validator.validate(newShortcut, pos) == QValidator::Acceptable) { btn.key = newShortcut.toStdString(); } else { //reset to old setData(2, Qt::ItemDataRole::DisplayRole, QString::fromStdString(btn.key)); } } Config::ButtonConfig& ButtonItem::getConfig() { return getParent()->getConfig().at(pos); } void ButtonItem::moveToRowAbove() { // get row above RowItem* rowabove = getParent()->getItemAbove(); if(!rowabove) { Log::error << "no row above!"; return; } // apply change in config auto& rowconf = getParent()->getConfig(); auto& newrowconf = rowabove->getConfig(); newrowconf.push_back(rowconf.front()); rowconf.erase(rowconf.begin()); // update buttons in old row // updateAllPosBellow(-1, rowconf.size()+1); // remove button from this row and attach to other getParent()->removeChild(this); reenumerateAllSiblings(); // depends on mparent beeing set to the old row rowabove->addChild(this); //update local parent mparent = rowabove; //update local pos pos = newrowconf.size()-1; expandTree(); } void ButtonItem::moveToRowBelow() { // get row below RowItem* rowbelow = getParent()->getItemBelow(); if(!rowbelow) { Log::error << "no row below!"; return; } // apply change in config auto& rowconf = getParent()->getConfig(); auto& newrowconf = rowbelow->getConfig(); newrowconf.insert(newrowconf.begin(), rowconf.back()); rowconf.erase(rowconf.end()); // remove button from this row and attach to other getParent()->removeChild(this); rowbelow->insertChild(0, this); //update local parent mparent = rowbelow; //update local pos pos = 0; //update new buttons below updateAllPosBellow(1, newrowconf.size()); expandTree(); } SampleItem::SampleItem(ButtonItem* parent, uint8_t samplenr, Config::RootConfig& conf) : ButtonManagerItem(parent, TYPE, samplenr), conf(conf) { const Config::SampleConfig& sample = getConfig(); updatePosition(); setText(1, QString::fromStdString(sample.file)); setToolTip(0, "Doubleclick to play"); setToolTip(1, "Doubleclick to play"); } bool SampleItem::hasEdit() const { return true; } bool SampleItem::hasRemove() const { return true; } bool SampleItem::hasMoveUp() const { return pos > 0 || getParent()->hasMoveUp(); } bool SampleItem::hasMoveDown() const { return pos < getParent()->getConfig().samples.size()-1 || getParent()->hasMoveDown(); } void SampleItem::edit() { Config::SampleConfig& sammpleConf = getConfig(); EditSample editor(sammpleConf.file); editor.setStartTime(sammpleConf.offset); editor.setLength(sammpleConf.length); editor.exec(); if(editor.result() == 0) { Log::info << "Dialog failed"; return; } sammpleConf.offset = editor.getStartTime(); sammpleConf.length = editor.getLength(); } void SampleItem::remove() { auto& btnconf = getParent()->getConfig().samples; btnconf.erase(btnconf.begin() + pos); updateAllPosBellow(-1, btnconf.size()); } void SampleItem::moveUp() { if(pos == 0) { moveToButtonAbove(); return; } //apply change to config auto& rowconf = getParent()->getConfig().samples; std::swap(rowconf.at(pos-1), rowconf.at(pos)); // apply change in GUI //get Child above SampleItem* sampleAboveItem = getSibling(pos-1); if(sampleAboveItem) { sampleAboveItem->pos++; } else { Log::error << "button above could not be updated"; } mparent->removeChild(this); mparent->insertChild(pos-1, this); expandTree(); pos--; updatePosition(); } void SampleItem::moveDown() { if(pos == getParent()->getConfig().samples.size()-1) { moveToButtonBelow(); return; } // moving down is the same as moving the item below up SampleItem* samplebelow = getSibling(pos+1); if(samplebelow) { samplebelow->moveUp(); } else { Log::error << "no item below"; } } Config::SampleConfig& SampleItem::getConfig() { return getParent()->getConfig().samples.at(pos); } void SampleItem::updatePosition() { setData(0, Qt::ItemDataRole::DisplayRole, QVariant((int) pos+1)); } void SampleItem::moveToButtonAbove() { ButtonItem* buttonabove = getParent()->getItemAbove(); if(!buttonabove) { buttonabove = getParent()->getParent()->getItemAbove()->getLastChild(); } // apply change in config auto& buttonconf = getParent()->getConfig().samples; auto& newbuttonconf = buttonabove->getConfig().samples; newbuttonconf.push_back(buttonconf.front()); buttonconf.erase(buttonconf.begin()); // update buttons in old row // updateAllPosBellow(-1, rowconf.size()+1); // remove button from this row and attach to other getParent()->removeChild(this); reenumerateAllSiblings(); // depends on mparent beeing set to the old row buttonabove->addChild(this); //update local parent mparent = buttonabove; //update local pos pos = newbuttonconf.size()-1; expandTree(); updatePosition(); } void SampleItem::moveToButtonBelow() { ButtonItem* buttonbelow = getParent()->getItemBelow(); if(!buttonbelow) { buttonbelow = getParent()->getParent()->getItemBelow()->getChild(0); } // apply change in config auto& buttonConf = getParent()->getConfig().samples; auto& newButtonconf = buttonbelow->getConfig().samples; newButtonconf.insert(newButtonconf.begin(), buttonConf.back()); buttonConf.erase(buttonConf.end()); // remove button from this row and attach to other getParent()->removeChild(this); buttonbelow->insertChild(0, this); //update local parent mparent = buttonbelow; //update local pos pos = 0; //update new buttons below reenumerateAllSiblings(); expandTree(); }