listitem.cpp (5371B)
1 #include "listitem.h" 2 3 #include "listmodel.h" 4 #include "patchmanager.h" 5 #include "savepatchdesc.h" 6 7 #include "synthLib/buildconfig.h" 8 9 #include "../pluginEditor.h" 10 11 namespace jucePluginEditorLib::patchManager 12 { 13 // Juce is funny: 14 // Having mouse clicks enabled prevents the list from getting mouse events, i.e. list entry selection is broken. 15 // However, by disabling mouse clicks, we also disable the ability to D&D onto these entries, even though D&D are not clicks... 16 // We solve both by overwriting hitTest() and return true as long as a D&D is in progress, false otherwise 17 18 ListItem::ListItem(ListModel& _list, const int _row) : m_list(_list), m_row(_row) 19 { 20 // setInterceptsMouseClicks(false, false); 21 } 22 23 void ListItem::paint(juce::Graphics& g) 24 { 25 Component::paint(g); 26 27 g.setColour(juce::Colour(0xff00ff00)); 28 29 if(m_drag == DragType::Above || m_drag == DragType::Over) 30 g.drawRect(0, 0, getWidth(), 3, 3); 31 if(m_drag == DragType::Below || m_drag == DragType::Over) 32 g.drawRect(0, getHeight()-3, getWidth(), 3, 3); 33 if(m_drag == DragType::Over) 34 { 35 g.drawRect(0, 0, 3, getHeight(), 3); 36 g.drawRect(getWidth() - 3, 0, 3, getHeight(), 3); 37 } 38 } 39 40 void ListItem::itemDragEnter(const SourceDetails& dragSourceDetails) 41 { 42 DragAndDropTarget::itemDragEnter(dragSourceDetails); 43 updateDragTypeFromPosition(dragSourceDetails); 44 } 45 46 void ListItem::itemDragExit(const SourceDetails& dragSourceDetails) 47 { 48 DragAndDropTarget::itemDragExit(dragSourceDetails); 49 m_drag = DragType::Off; 50 repaint(); 51 } 52 53 void ListItem::itemDragMove(const SourceDetails& dragSourceDetails) 54 { 55 updateDragTypeFromPosition(dragSourceDetails); 56 } 57 58 bool ListItem::isInterestedInDragSource(const SourceDetails& dragSourceDetails) 59 { 60 if(m_list.getSourceType() != pluginLib::patchDB::SourceType::LocalStorage) 61 return false; 62 63 const auto* list = dynamic_cast<const ListModel*>(dragSourceDetails.sourceComponent.get()); 64 65 if(list && list == &m_list && m_list.canReorderPatches()) 66 return true; 67 68 const auto* savePatchDesc = SavePatchDesc::fromDragSource(dragSourceDetails); 69 70 if(!savePatchDesc) 71 return false; 72 return true; 73 } 74 75 void ListItem::itemDropped(const SourceDetails& dragSourceDetails) 76 { 77 if(m_drag == DragType::Off) 78 return; 79 80 auto& pm = m_list.getPatchManager(); 81 82 const auto drag = m_drag; 83 m_drag = DragType::Off; 84 85 repaint(); 86 87 const auto row = drag == DragType::Above ? m_row : m_row + 1; 88 89 const auto patches = SavePatchDesc::getPatchesFromDragSource(dragSourceDetails); 90 91 if(patches.empty()) 92 return; 93 94 const auto* savePatchDesc = SavePatchDesc::fromDragSource(dragSourceDetails); 95 assert(savePatchDesc); 96 97 if(dynamic_cast<const ListModel*>(dragSourceDetails.sourceComponent.get())) 98 { 99 if(!patches.empty() && pm.movePatchesTo(row, patches)) 100 m_list.refreshContent(); 101 } 102 else if(patches.size() == 1 && savePatchDesc->isPartValid()) 103 { 104 const auto& source = m_list.getDataSource(); 105 if(!source) 106 return; 107 108 if(drag == DragType::Over) 109 { 110 repaint(); 111 112 const auto existingPatch = m_list.getPatch(m_row); 113 114 if(existingPatch) 115 { 116 genericUI::MessageBox::showYesNo(juce::MessageBoxIconType::QuestionIcon, 117 "Replace Patch", 118 "Do you want to replace the existing patch '" + existingPatch->name + "' with contents of part " + std::to_string(savePatchDesc->getPart() + 1) + "?", 119 [this, existingPatch, patches](genericUI::MessageBox::Result _result) 120 { 121 if (_result == genericUI::MessageBox::Result::Yes) 122 { 123 m_list.getPatchManager().replacePatch(existingPatch, patches.front()); 124 } 125 }); 126 return; 127 } 128 } 129 130 #if SYNTHLIB_DEMO_MODE 131 pm.getEditor().showDemoRestrictionMessageBox(); 132 #else 133 const auto part = savePatchDesc->getPart(); 134 135 pm.copyPatchesTo(source, patches, row, [this, part](const std::vector<pluginLib::patchDB::PatchPtr>& _patches) 136 { 137 juce::MessageManager::callAsync([this, part, _patches] 138 { 139 m_list.getPatchManager().setSelectedPatch(part, _patches.front()); 140 }); 141 }); 142 #endif 143 144 repaint(); 145 } 146 147 } 148 149 void ListItem::mouseDown(const juce::MouseEvent& event) 150 { 151 // m_list.mouseDown(event); 152 } 153 154 bool ListItem::hitTest(int x, int y) 155 { 156 if (const juce::DragAndDropContainer* container = juce::DragAndDropContainer::findParentDragContainerFor(this)) 157 { 158 if (container->isDragAndDropActive()) 159 return true; 160 } 161 162 return false; 163 } 164 165 void ListItem::updateDragTypeFromPosition(const SourceDetails& dragSourceDetails) 166 { 167 const auto prev = m_drag; 168 169 const auto* list = dynamic_cast<const ListModel*>(dragSourceDetails.sourceComponent.get()); 170 171 if(list && list == &m_list) 172 { 173 // list is being sorted 174 if (dragSourceDetails.localPosition.y < (getHeight() >> 1)) 175 m_drag = DragType::Above; 176 else 177 m_drag = DragType::Below; 178 } 179 else 180 { 181 const auto* savePatchDesc = SavePatchDesc::fromDragSource(dragSourceDetails); 182 183 if(savePatchDesc) 184 { 185 // a patch wants to be saved 186 187 if(m_list.hasFilters()) 188 { 189 // only allow to replace 190 m_drag = DragType::Over; 191 } 192 else 193 { 194 if (dragSourceDetails.localPosition.y < (getHeight() / 3)) 195 m_drag = DragType::Above; 196 else if (dragSourceDetails.localPosition.y >= (getHeight() * 2 / 3)) 197 m_drag = DragType::Below; 198 else 199 m_drag = DragType::Over; 200 } 201 } 202 } 203 204 if (prev != m_drag) 205 repaint(); 206 } 207 }