// This file is part of VSTGUI. It is subject to the license terms // in the LICENSE file found in the top-level directory of this // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE #pragma once #include "../iuidescription.h" #if VSTGUI_LIVE_EDITING #include "../uiattributes.h" #include "../uidescriptionlistener.h" #include "../../lib/cdatabrowser.h" #include "../../lib/genericstringlistdatabrowsersource.h" #include "../../lib/controls/csearchtextedit.h" #include "../../lib/controls/cscrollbar.h" #include #include namespace VSTGUI { //---------------------------------------------------------------------------------------------------- class UIBaseDataSource : public GenericStringListDataBrowserSource, public IControlListener, public UIDescriptionListenerAdapter { public: using StringVector = GenericStringListDataBrowserSource::StringVector; UIBaseDataSource (UIDescription* description, IActionPerformer* actionPerformer, GenericStringListDataBrowserSourceSelectionChanged* delegate = nullptr) : GenericStringListDataBrowserSource (0, delegate) , description (description), actionPerformer (actionPerformer) { description->registerListener (this); textInset.x = 4; } ~UIBaseDataSource () override { description->unregisterListener (this); } void setSearchFieldControl (CSearchTextEdit* searchControl) { searchField = searchControl; searchField->setListener (this); } virtual bool add () { if (dataBrowser && actionPerformer) { std::string newName (filterString.empty () ? "New" : filterString.data ()); if (createUniqueName (newName)) { addItem (newName.data ()); int32_t row = selectName (newName.data ()); if (row != -1) { dbOnMouseDown (CPoint (0, 0), CButtonState (kLButton|kDoubleClick), row, 0, dataBrowser); return true; } } } return false; } virtual bool remove () { if (dataBrowser && actionPerformer) { int32_t selectedRow = dataBrowser->getSelectedRow (); if (selectedRow != CDataBrowser::kNoSelection) { removeItem (names.at (static_cast (selectedRow)).data ()); dbSelectionChanged (dataBrowser); dataBrowser->setSelectedRow (selectedRow); return true; } } return false; } virtual void setFilter (const UTF8String& filter) { if (filterString != filter) { filterString = filter; int32_t selectedRow = dataBrowser ? dataBrowser->getSelectedRow () : CDataBrowser::kNoSelection; std::string selectedName; if (selectedRow != CDataBrowser::kNoSelection) selectedName = names.at (static_cast (selectedRow)); update (); if (selectedRow != CDataBrowser::kNoSelection) selectName (selectedName.data ()); } } virtual int32_t selectName (UTF8StringPtr name) { int32_t index = 0; for (auto& it : names) { if (it == name) { dataBrowser->setSelectedRow (index, true); if (delegate) delegate->dbSelectionChanged (index, this); return index; } ++index; } return -1; } protected: virtual void getNames (std::list& names) = 0; virtual bool addItem (UTF8StringPtr name) = 0; virtual bool removeItem (UTF8StringPtr name) = 0; virtual bool performNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) = 0; virtual UTF8StringPtr getDefaultsName () = 0; virtual void update () { if (textEditControl) textEditControl->looseFocus (); names.clear (); std::list tmpNames; getNames (tmpNames); std::string filter = filterString.getString (); std::transform (filter.begin (), filter.end (), filter.begin (), ::tolower); for (auto& name : tmpNames) { if (!filter.empty ()) { std::string tmp (*name); std::transform (tmp.begin (), tmp.end (), tmp.begin (), ::tolower); if (tmp.find (filter) == std::string::npos) continue; } if (name->find ("~ ") == 0) continue; // don't show static items names.emplace_back (UTF8String (*name)); } bool vsbIsVisible = false; if (dataBrowser) { if (auto vsb = dataBrowser->getVerticalScrollbar ()) vsbIsVisible = vsb->isVisible (); } setStringList (&names); if (dataBrowser) { if (auto vsb = dataBrowser->getVerticalScrollbar ()) { if (vsb->isVisible() != vsbIsVisible) dataBrowser->recalculateLayout (); } } } void beforeUIDescSave (UIDescription* desc) override { saveDefaults (); }; void onUIDescriptionUpdate () { int32_t selectedRow = dataBrowser ? dataBrowser->getSelectedRow () : CDataBrowser::kNoSelection; std::string selectedName; if (selectedRow != CDataBrowser::kNoSelection) selectedName = names.at (static_cast (selectedRow)); update (); if (selectedRow != CDataBrowser::kNoSelection) selectName (selectedName.data ()); } virtual void saveDefaults () { UTF8StringPtr name = getDefaultsName (); if (name) { auto attributes = description->getCustomAttributes (name, true); if (attributes) { attributes->setAttribute ("FilterString", filterString.getString ()); if (dataBrowser) { int32_t selectedRow = dataBrowser->getSelectedRow (); attributes->setIntegerAttribute ("SelectedRow", selectedRow); } } } } virtual void loadDefaults () { UTF8StringPtr name = getDefaultsName (); if (name) { auto attributes = description->getCustomAttributes (name, true); if (attributes) { const std::string* str = attributes->getAttributeValue ("FilterString"); if (str) setFilter (str->data ()); if (dataBrowser) { int32_t selectedRow; if (attributes->getIntegerAttribute("SelectedRow", selectedRow)) dataBrowser->setSelectedRow (selectedRow, true); } } } } void dbAttached (CDataBrowser* browser) override { GenericStringListDataBrowserSource::dbAttached (browser); update (); loadDefaults (); if (searchField) searchField->setText (filterString); } void dbRemoved (CDataBrowser* browser) override { saveDefaults (); GenericStringListDataBrowserSource::dbRemoved (browser); } void valueChanged (CControl* control) override { CTextEdit* edit = dynamic_cast(control); if (edit) setFilter (edit->getText ()); } bool createUniqueName (std::string& name, int32_t count = 0) { std::stringstream str; str << name; if (count) { str << ' '; str << count; } for (auto& it : names) { if (it == str.str ()) return createUniqueName (name, count+1); } name = str.str (); return true; } CMouseEventResult dbOnMouseDown (const CPoint& where, const CButtonState& buttons, int32_t row, int32_t column, CDataBrowser* browser) override { if (buttons.isLeftButton () && buttons.isDoubleClick ()) { browser->beginTextEdit (CDataBrowser::Cell (row, column), names.at (static_cast (row)).data ()); } return kMouseDownEventHandledButDontNeedMovedOrUpEvents; } void dbCellTextChanged (int32_t _row, int32_t column, UTF8StringPtr newText, CDataBrowser* browser) override { textEditControl = nullptr; if (_row < 0 || _row >= static_cast (names.size ())) return; auto row = static_cast (_row); for (auto& name : names) { if (name == newText) return; } auto& currentName = names.at (row); if (performNameChange (currentName.data (), newText)) { if (selectName (newText) == -1 && row < names.size ()) selectName (names.at (row).data ()); } } void dbCellSetupTextEdit (int32_t row, int32_t column, CTextEdit* control, CDataBrowser* browser) override { textEditControl = control; textEditControl->setBackColor (kWhiteCColor); textEditControl->setFontColor (fontColor); textEditControl->setFont (drawFont); textEditControl->setHoriAlign (textAlignment); textEditControl->setTextInset (textInset); } SharedPointer description; SharedPointer searchField; SharedPointer textEditControl; IActionPerformer* actionPerformer; StringVector names; UTF8String filterString; }; } // VSTGUI #endif // VSTGUI_LIVE_EDITING