gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

treeitem.cpp (7847B)


      1 #include "treeitem.h"
      2 
      3 #include "listmodel.h"
      4 #include "patchmanager.h"
      5 #include "savepatchdesc.h"
      6 #include "tree.h"
      7 
      8 #include "jucePluginLib/patchdb/patchdbtypes.h"
      9 #include "juceUiLib/treeViewStyle.h"
     10 
     11 namespace jucePluginEditorLib::patchManager
     12 {
     13 	TreeItem::TreeItem(PatchManager& _patchManager, const std::string& _title, const uint32_t _count/* = g_invalidCount*/) : m_patchManager(_patchManager), m_count(_count)
     14 	{
     15 		setTitle(_title);
     16 	}
     17 
     18 	TreeItem::~TreeItem()
     19 	{
     20 		getPatchManager().removeSelectedItem(getTree(), this);
     21 
     22 		if(m_searchHandle != pluginLib::patchDB::g_invalidSearchHandle)
     23 		{
     24 			getPatchManager().cancelSearch(m_searchHandle);
     25 			m_searchHandle = pluginLib::patchDB::g_invalidSearchHandle;
     26 		}
     27 	}
     28 
     29 	void TreeItem::setTitle(const std::string& _title)
     30 	{
     31 		if (m_title == _title)
     32 			return;
     33 		m_title = _title;
     34 		updateText();
     35 	}
     36 
     37 	void TreeItem::setCount(const uint32_t _count)
     38 	{
     39 		if (m_count == _count)
     40 			return;
     41 		m_count = _count;
     42 		updateText();
     43 	}
     44 
     45 	void TreeItem::processDirty(const std::set<pluginLib::patchDB::SearchHandle>& _dirtySearches)
     46 	{
     47 		if (_dirtySearches.find(m_searchHandle) == _dirtySearches.end())
     48 			return;
     49 
     50 		const auto search = getPatchManager().getSearch(m_searchHandle);
     51 		if (!search)
     52 			return;
     53 
     54 		processSearchUpdated(*search);
     55 	}
     56 
     57 	bool TreeItem::beginEdit(const std::string& _initialText, FinishedEditingCallback&& _callback)
     58 	{
     59 		auto pos = getItemPosition(true);
     60 		pos.setHeight(getItemHeight());
     61 
     62 		return Editable::beginEdit(getOwnerView(), pos, _initialText, std::move(_callback));
     63 	}
     64 
     65 	bool TreeItem::hasSearch() const
     66 	{
     67 		return m_searchHandle != pluginLib::patchDB::g_invalidSearchHandle;
     68 	}
     69 
     70 	Tree* TreeItem::getTree() const
     71 	{
     72 		return dynamic_cast<Tree*>(getOwnerView());
     73 	}
     74 
     75 	void TreeItem::removeFromParent(const bool _destroy) const
     76 	{
     77 		auto* parent = getParentItem();
     78 		if (!parent)
     79 		{
     80 			if (_destroy)
     81 				delete this;
     82 			return;
     83 		}
     84 		const auto idx = getIndexInParent();
     85 		parent->removeSubItem(idx, _destroy);
     86 	}
     87 
     88 	void TreeItem::setParent(TreeViewItem* _parent, const bool _sorted/* = false*/)
     89 	{
     90 		const auto* parentExisting = getParentItem();
     91 
     92 		if (_parent == parentExisting)
     93 			return;
     94 
     95 		removeFromParent(false);
     96 
     97 		if (_parent)
     98 		{
     99 			if(_sorted)
    100 				_parent->addSubItemSorted(*this, this);
    101 			else
    102 				_parent->addSubItem(this);
    103 		}
    104 	}
    105 
    106 	void TreeItem::itemSelectionChanged(const bool _isNowSelected)
    107 	{
    108 		if(_isNowSelected && m_forceDeselect)
    109 		{
    110 			m_forceDeselect = false;
    111 
    112 			juce::MessageManager::callAsync([this]()
    113 			{
    114 				setSelected(false, false);
    115 			});
    116 			return;
    117 		}
    118 
    119 		m_selectedWasChanged = true;
    120 
    121 		TreeViewItem::itemSelectionChanged(_isNowSelected);
    122 
    123 		if(getTree()->isMultiSelectEnabled())
    124 		{
    125 			if (_isNowSelected)
    126 				getPatchManager().addSelectedItem(getTree(), this);
    127 			else
    128 				getPatchManager().removeSelectedItem(getTree(), this);
    129 		}
    130 		else
    131 		{
    132 			if (_isNowSelected)
    133 				getPatchManager().setSelectedItem(getTree(), this);
    134 		}
    135 	}
    136 
    137 	void TreeItem::itemDropped(const juce::DragAndDropTarget::SourceDetails& dragSourceDetails, int insertIndex)
    138 	{
    139 		const auto patches = SavePatchDesc::getPatchesFromDragSource(dragSourceDetails);
    140 
    141 		if(!patches.empty())
    142 			patchesDropped(patches);
    143 	}
    144 
    145 	bool TreeItem::isInterestedInDragSource(const juce::DragAndDropTarget::SourceDetails& _dragSourceDetails)
    146 	{
    147 		const auto* list = dynamic_cast<ListModel*>(_dragSourceDetails.sourceComponent.get());
    148 
    149 		const auto& patches = SavePatchDesc::getPatchesFromDragSource(_dragSourceDetails);
    150 
    151 		return isInterestedInPatchList(list, patches);
    152 	}
    153 
    154 	void TreeItem::search(pluginLib::patchDB::SearchRequest&& _request)
    155 	{
    156 		cancelSearch();
    157 		setCount(g_unknownCount);
    158 		m_searchRequest = _request;
    159 		m_searchHandle = getPatchManager().search(std::move(_request));
    160 	}
    161 
    162 	void TreeItem::processSearchUpdated(const pluginLib::patchDB::Search& _search)
    163 	{
    164 		setCount(static_cast<uint32_t>(_search.getResultSize()));
    165 	}
    166 
    167 	const pluginLib::patchDB::SearchRequest& TreeItem::getParentSearchRequest() const
    168 	{
    169 		return m_parentSearchRequest;
    170 	}
    171 
    172 	void TreeItem::setText(const std::string& _text)
    173 	{
    174 		if (m_text == _text)
    175 			return;
    176 		m_text = _text;
    177 		repaintItem();
    178 	}
    179 
    180 	void TreeItem::updateText()
    181 	{
    182 		if (m_count == g_invalidCount)
    183 			setText(m_title);
    184 		else if (m_count == g_unknownCount)
    185 			setText(m_title + " (?)");
    186 		else
    187 			setText(m_title + " (" + std::to_string(m_count) + ')');
    188 	}
    189 
    190 	void TreeItem::paintItem(juce::Graphics& _g, const int _width, const int _height)
    191 	{
    192 		getTree()->setColour(juce::TreeView::dragAndDropIndicatorColourId, juce::Colour(juce::ModifierKeys::currentModifiers.isShiftDown() ? 0xffff0000 : 0xff00ff00));
    193 
    194 		const auto* style = dynamic_cast<const genericUI::TreeViewStyle*>(&getOwnerView()->getLookAndFeel());
    195 
    196 		const auto color = getColor();
    197 
    198 		_g.setColour(color != pluginLib::patchDB::g_invalidColor ? juce::Colour(color) : style ? style->getColor() : juce::Colour(0xffffffff));
    199 
    200 		bool haveFont = false;
    201 		bool antialias = true;
    202 
    203 		if(style)
    204 		{
    205 			if (auto f = style->getFont())
    206 			{
    207 				if (style->boldRootItems() && getParentItem() == getTree()->getRootItem())
    208 					f = f->boldened();
    209 				_g.setFont(*f);
    210 				haveFont = true;
    211 			}
    212 			antialias = style->getAntialiasing();
    213 		}
    214 
    215 		if(!haveFont)
    216 		{
    217 			auto fnt = _g.getCurrentFont();
    218 			if (getParentItem() == getTree()->getRootItem())
    219 				fnt = fnt.boldened();
    220 			_g.setFont(fnt);
    221 		}
    222 
    223 		_g.setImageResamplingQuality(antialias ? juce::Graphics::highResamplingQuality : juce::Graphics::lowResamplingQuality);
    224 
    225 		const juce::String t = juce::String::fromUTF8(m_text.c_str());
    226 		_g.drawText(t, 0, 0, _width, _height, style ? style->getAlign() : juce::Justification(juce::Justification::centredLeft));
    227 		TreeViewItem::paintItem(_g, _width, _height);
    228 	}
    229 
    230 	bool TreeItem::isInterestedInFileDrag(const juce::StringArray& _files)
    231 	{
    232 		return TreeViewItem::isInterestedInFileDrag(_files);
    233 	}
    234 
    235 	void TreeItem::filesDropped(const juce::StringArray& _files, const int _insertIndex)
    236 	{
    237 		const auto patches = m_patchManager.loadPatchesFromFiles(_files);
    238 
    239 		if(!patches.empty())
    240 			patchesDropped(patches);
    241 		else
    242 			TreeViewItem::filesDropped(_files, _insertIndex);
    243 	}
    244 
    245 	int TreeItem::compareElements(const TreeViewItem* _a, const TreeViewItem* _b)
    246 	{
    247 		const auto* a = dynamic_cast<const TreeItem*>(_a);
    248 		const auto* b = dynamic_cast<const TreeItem*>(_b);
    249 
    250 		if(a && b)
    251 			return a->getText().compare(b->getText());
    252 
    253 		if (_a < _b)
    254 			return -1;
    255 		if (_a > _b)
    256 			return 1;
    257 		return 0;
    258 	}
    259 
    260 	void TreeItem::setParentSearchRequest(const pluginLib::patchDB::SearchRequest& _parentSearch)
    261 	{
    262 		if(_parentSearch == m_parentSearchRequest)
    263 			return;
    264 		m_parentSearchRequest = _parentSearch;
    265 		onParentSearchChanged(m_parentSearchRequest);
    266 	}
    267 
    268 	void TreeItem::itemClicked(const juce::MouseEvent& _mouseEvent)
    269 	{
    270 		if(_mouseEvent.mods.isPopupMenu())
    271 		{
    272 			TreeViewItem::itemClicked(_mouseEvent);
    273 			return;
    274 		}
    275 
    276 		if(!m_deselectOnSecondClick)
    277 		{
    278 			TreeViewItem::itemClicked(_mouseEvent);
    279 			return;
    280 		}
    281 
    282 		// we have the (for Juce) overly complex task to deselect a tree item on left click
    283 		// Juce does not let us though, this click is sent on mouse down and it reselects the item
    284 		// again on mouse up.
    285 		const auto selectedWasChanged = m_selectedWasChanged;
    286 		m_selectedWasChanged = false;
    287 
    288 		if(!selectedWasChanged && isSelected() && getOwnerView()->isMultiSelectEnabled())
    289 		{
    290 			m_forceDeselect = true;
    291 			setSelected(false, false);
    292 		}
    293 	}
    294 
    295 	void TreeItem::cancelSearch()
    296 	{
    297 		if(m_searchHandle == pluginLib::patchDB::g_invalidSearchHandle)
    298 			return;
    299 
    300 		getPatchManager().cancelSearch(m_searchHandle);
    301 		m_searchHandle = pluginLib::patchDB::g_invalidSearchHandle;
    302 	}
    303 
    304 	void TreeItem::patchesDropped(const std::vector<pluginLib::patchDB::PatchPtr>& _patches, const SavePatchDesc* _savePatchDesc/* = nullptr*/)
    305 	{
    306 		for (const auto& patch : _patches)
    307 			patchDropped(patch);
    308 	}
    309 }