From c1f858c8f67f68b580f340d8e3e2c845ac4fccb0 Mon Sep 17 00:00:00 2001 From: A <38586259+aaa1386@users.noreply.github.com> Date: Sun, 19 Oct 2025 17:38:15 +0330 Subject: [PATCH 01/14] =?UTF-8?q?=D8=AD=D8=B0=D9=81=20=D9=BE=D9=86=D9=84?= =?UTF-8?q?=20=D8=A8=D8=A7=D8=B2=D8=B1=D8=B3=20In-place=20Siblings=20Previ?= =?UTF-8?q?ew?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utilityPanels.groovy | 52 ++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/utilityPanels.groovy b/utilityPanels.groovy index f7d5338..86e4f65 100644 --- a/utilityPanels.groovy +++ b/utilityPanels.groovy @@ -1,6 +1,5 @@ /*************************************************************************** - version 1.48: Updated to be compatible with Freeplane 1.12.12. version 1.47: Quick search panel: Lines connecting the results in the quick search panel to the respective nodes. @@ -671,38 +670,49 @@ def boolean checkIfUtilityPanelsIsAlreadyRunning() { } public void manageInspectorsCreation() { - if (shouldFreeze()) return - if(panelsInMasterPanels.contains(currentSourcePanel)) expandMasterPanelAndUpdateInspectorsState() - if (activeSiblingPreviewPanels.contains(currentSourcePanel)) clearInspectorsAndPreviewInspectors() - if (!lastMouseLocation) return + if (shouldFreeze()) return; + if (panelsInMasterPanels.contains(currentSourcePanel)) expandMasterPanelAndUpdateInspectorsState(); - int index = currentList.locationToIndex(lastMouseLocation) + // ---------- تغییر داده شده ---------- + if (activeSiblingPreviewPanels.contains(currentSourcePanel)) { + clearInspectorsAndPreviewInspectors(); + return; // جلوگیری از ساخت Inspector هنگام Hover روی پنل‌های Sibling Preview + } + // قبلی (کامنت شده): + // else if (activeSiblingPreviewPanels.contains(currentSourcePanel)) updatePreviewInspectors(subNode); + // ------------------------------------ - if (!validateMousePositionOnList(index)) return + if (!lastMouseLocation) return; - Object hoveredItem = currentListModel.getElementAt(index) + int index = currentList.locationToIndex(lastMouseLocation); - if(hoveredItem instanceof NodeModel) { - NodeModel subNode = currentListModel.getElementAt(index) - hoveredNode = subNode + if (!validateMousePositionOnList(index)) return; - populateAncestorsList(hoveredNode) + Object hoveredItem = currentListModel.getElementAt(index); - if (panelsInMasterPanels.contains(currentSourcePanel) || currentSourcePanel == breadcrumbPanel) cleanAndCreateInspectors(subNode, masterPanel) - else if (activeSiblingPreviewPanels.contains(currentSourcePanel)) updatePreviewInspectors(subNode) - else createSubInspector(hoveredNode, index, subNode) - } - else if(currentSourcePanel == tagsPanel) updateInspectorWithTagsPanel(index) + if (hoveredItem instanceof NodeModel) { + NodeModel subNode = currentListModel.getElementAt(index); + hoveredNode = subNode; + + populateAncestorsList(hoveredNode); + + if (panelsInMasterPanels.contains(currentSourcePanel) || currentSourcePanel == breadcrumbPanel) + cleanAndCreateInspectors(subNode, masterPanel); + else + createSubInspector(hoveredNode, index, subNode); + } + else if (currentSourcePanel == tagsPanel) + updateInspectorWithTagsPanel(index); } public boolean validateMousePositionOnList(int index) { - Rectangle cellBounds = currentList.getCellBounds(index, index) + Rectangle cellBounds = currentList.getCellBounds(index, index); - if (cellBounds == null || !cellBounds.contains(lastMouseLocation)) return false + if (cellBounds == null || !cellBounds.contains(lastMouseLocation)) return false; - if (index < 0 || index >= currentListModel.getSize()) return false + if (index < 0 || index >= currentListModel.getSize()) return false; - return true + return true; } public void createSubInspector(NodeModel hoveredNode, int index, NodeModel subNode) { From 0fef404decd4dc12c1bcacb10b87036633f3ce46 Mon Sep 17 00:00:00 2001 From: A <38586259+aaa1386@users.noreply.github.com> Date: Sun, 19 Oct 2025 17:40:05 +0330 Subject: [PATCH 02/14] =?UTF-8?q?=20=D8=AD=D8=B0=D9=81=20=D9=BE=D9=86?= =?UTF-8?q?=D9=84=20=D8=A8=D8=A7=D8=B2=D8=B1=D8=B3=20=D8=A7=D8=B2=20=20In-?= =?UTF-8?q?place=20Siblings=20Preview?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utilityPanels.groovy | 1 - 1 file changed, 1 deletion(-) diff --git a/utilityPanels.groovy b/utilityPanels.groovy index 86e4f65..a9cf845 100644 --- a/utilityPanels.groovy +++ b/utilityPanels.groovy @@ -1,4 +1,3 @@ - /*************************************************************************** version 1.48: Updated to be compatible with Freeplane 1.12.12. From 37b7128cefa2c73e512bd19d5e148a11af86e54f Mon Sep 17 00:00:00 2001 From: A <38586259+aaa1386@users.noreply.github.com> Date: Sun, 19 Oct 2025 19:39:04 +0330 Subject: [PATCH 03/14] =?UTF-8?q?=D9=BE=D9=86=D9=87=D8=A7=D9=86=20=D8=B4?= =?UTF-8?q?=D8=AF=D9=86=20=D9=BE=D9=86=D9=84=20=D9=87=D8=A7=20=D9=87=D9=86?= =?UTF-8?q?=DA=AF=D8=A7=D9=85=20=D8=A7=D8=B3=DA=A9=D8=B1=D9=88=D9=84=20?= =?UTF-8?q?=DA=A9=D8=B1=D8=AF=D9=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utilityPanels.groovy | 214 ++++++++++++++++++++++++++++++------------- 1 file changed, 150 insertions(+), 64 deletions(-) diff --git a/utilityPanels.groovy b/utilityPanels.groovy index a9cf845..42948c3 100644 --- a/utilityPanels.groovy +++ b/utilityPanels.groovy @@ -1,3 +1,4 @@ + /*************************************************************************** version 1.48: Updated to be compatible with Freeplane 1.12.12. @@ -390,6 +391,8 @@ showAncestorsOnFirstInspector = false @groovy.transform.Field hideInspectorsEvenIfUpdateSelection = true @groovy.transform.Field showInPlaceSiblingsPreview = true +@groovy.transform.Field boolean isScrolling = false +@groovy.transform.Field Timer scrollStopTimer = new Timer(20, null) //↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ User settings ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ @@ -624,6 +627,11 @@ class NodeModelTransferable implements Transferable { */ loadSettings() +scrollStopTimer.setRepeats(false) +scrollStopTimer.addActionListener({ + isScrolling = false + refreshSiblingPreviewPanels() +}) createPanels() createSingleRunListeners() startListeners() @@ -670,15 +678,16 @@ def boolean checkIfUtilityPanelsIsAlreadyRunning() { public void manageInspectorsCreation() { if (shouldFreeze()) return; - if (panelsInMasterPanels.contains(currentSourcePanel)) expandMasterPanelAndUpdateInspectorsState(); + + if (panelsInMasterPanels.contains(currentSourcePanel)) { + expandMasterPanelAndUpdateInspectorsState(); + } // ---------- تغییر داده شده ---------- if (activeSiblingPreviewPanels.contains(currentSourcePanel)) { clearInspectorsAndPreviewInspectors(); return; // جلوگیری از ساخت Inspector هنگام Hover روی پنل‌های Sibling Preview } - // قبلی (کامنت شده): - // else if (activeSiblingPreviewPanels.contains(currentSourcePanel)) updatePreviewInspectors(subNode); // ------------------------------------ if (!lastMouseLocation) return; @@ -695,13 +704,20 @@ public void manageInspectorsCreation() { populateAncestorsList(hoveredNode); - if (panelsInMasterPanels.contains(currentSourcePanel) || currentSourcePanel == breadcrumbPanel) + if (panelsInMasterPanels.contains(currentSourcePanel) || currentSourcePanel == breadcrumbPanel) { cleanAndCreateInspectors(subNode, masterPanel); - else + } else { createSubInspector(hoveredNode, index, subNode); + } } - else if (currentSourcePanel == tagsPanel) + else if (currentSourcePanel == tagsPanel) { updateInspectorWithTagsPanel(index); + } + + // ★★★★ این خط جدید را اضافه کنید: + if (currentList != null) { + currentList.repaint(); // فورس رندر برای نمایش حاشیه بنفش + } } public boolean validateMousePositionOnList(int index) { @@ -2615,6 +2631,20 @@ void configureLabelForNode(JComponent component, NodeModel nodeNotProxy, JPanel } NodeModel storedNode = (NodeModel) sourcePanel.getClientProperty("referenceNode") + boolean isHovered = false + if (hoveredNode == nodeNotProxy && mouseOverList) { + isHovered = true + + } + if (isHovered) { + label.setBorder(BorderFactory.createLineBorder(new Color(160, 32, 240), 3)) // بنفش + } + else if (currentlySelectedNode == nodeNotProxy) { + label.setBorder(BorderFactory.createLineBorder(Color.RED, 4)) + } + else if(!panelsInMasterPanels.contains(sourcePanel) && sourcePanel != breadcrumbPanel) { + // کدهای موجود... + } // if(currentMapView.getNodeView(nodeNotProxy) == null || !isNodeOnScreen(nodeNotProxy)) { // label.setBorder(BorderFactory.createLineBorder(Color.BLUE, 4)) @@ -3198,6 +3228,8 @@ void configureMouseExitListener(JList list) { @Override void mouseExited(MouseEvent e) { mouseOverList = false + hoveredNode = null // ★ پاک کردن هایلایت هاور + list.repaint() // ★ فورس رندر برای حذف حاشیه بنفش hideInspectorTimer.restart() } }) @@ -4394,10 +4426,8 @@ def createComponentChangeListener() { mapView1 = Controller.currentController.MapViewManager.mapView if (mapView1.componentListeners.any { it.getClass().getName().startsWith("UtilityPanels") }) return - mapView1.addComponentListener(new ComponentAdapter() { public void componentMoved(ComponentEvent e) { - ensureOverlayExistsAndRepaint() if(!showPanels) { @@ -4409,18 +4439,35 @@ def createComponentChangeListener() { nv3 = mapView1.getNodeView(currentlySelectedNode) if (Boolean.TRUE.equals(nv3.getMainView().getClientProperty(INLINE_EDITOR_ACTIVE))) { return - } - if (showInPlaceSiblingsPreview) refreshSiblingPreviewPanels() - else if (activeSiblingPreviewPanels.size() != 0) { - activeSiblingPreviewPanels.each { - it.setVisible(false) + // مدیریت پنل‌های siblings هنگام حرکت + if (showInPlaceSiblingsPreview) { + if (!isScrolling) { + isScrolling = true + hideSiblingPreviewPanels() // مخفی کردن پنل‌ها هنگام شروع اسکرول } - activeSiblingPreviewPanels.clear() + scrollStopTimer.restart() } } }) + + // اضافه کردن لیسنر اسکرول به viewport + def viewport = mapView1.getParent() + if (viewport instanceof JViewport) { + viewport.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + if (showInPlaceSiblingsPreview) { + if (!isScrolling) { + isScrolling = true + hideSiblingPreviewPanels() // مخفی کردن پنل‌ها هنگام شروع اسکرول + } + scrollStopTimer.restart() + } + } + }) + } } @@ -4844,7 +4891,6 @@ def static getUserDefinedStylesParentNode(x = null){ return getUserDefinedStylesParentNode((ScriptContext) null) } - def static getUserDefinedStylesParentNode(ScriptContext scriptContext){ MapModel mapa = Controller.getCurrentController().getMap(); return getUserDefinedStylesParentNode(mapa, scriptContext) @@ -4865,8 +4911,16 @@ def static getUserDefinedStylesParentNode(MapModel mapa, ScriptContext scriptCon return userDefinedParentNode } +def hideSiblingPreviewPanels() { + activeSiblingPreviewPanels.each { + it.setVisible(false) + } +} def refreshSiblingPreviewPanels() { + if (isScrolling) { + return + } activeSiblingPreviewPanels.each { it.visible = false @@ -4874,95 +4928,127 @@ def refreshSiblingPreviewPanels() { } activeSiblingPreviewPanels.clear() + if (!showInPlaceSiblingsPreview) return + def mapView = Controller.currentController.MapViewManager.mapView def viewport = mapView.getParent() if (!(viewport instanceof JViewport)) { return } - c.viewRoot.findAll().each { + c.viewRoot.findAll().each { nodeProxy -> + if (nodeProxy == c.viewRoot) return - if (it == c.viewRoot) return + def testedNode = nodeProxy.delegate + if (testedNode == null) return - def testedNode = it - if (testedNode == null) { - return - } - - NodeView testedNodeView = mapView.getNodeView(testedNode.delegate) - if (testedNodeView == null) { - return - } + NodeView testedNodeView = mapView.getNodeView(testedNode) + if (testedNodeView == null) return + Point selectedPointOnMap = mapView.getNodeContentLocation(testedNodeView) Point selectedPointOnScreen = SwingUtilities.convertPoint(mapView, selectedPointOnMap, viewport) referenceNodeScreenX = selectedPointOnScreen.x referenceNodeScreenY = selectedPointOnScreen.y - -// if(referenceNodeScreenX < 0 || referenceNodeScreenX > viewport.getViewRect().width) return - - if(testedNode.parent.children.size() == 1) return - + if (testedNode.parent?.children?.size() == 1) return def parentNode = testedNode.parent def siblings = parentNode.children int selectedIndex = siblings.indexOf(testedNode) - if (selectedIndex < 0) { - return - } + if (selectedIndex < 0) return NodeModel offScreenSiblingAbove = null - - - if(selectedIndex > 0 && !isNodeVisibleInViewport(siblings[selectedIndex - 1].delegate)) offScreenSiblingAbove = siblings[selectedIndex - 1].delegate + if (selectedIndex > 0 && !isNodeVisibleInViewport(siblings[selectedIndex - 1])) { + offScreenSiblingAbove = siblings[selectedIndex - 1] + } if (offScreenSiblingAbove != null) { - NodeView offScreenSiblingAboveNodeView = mapView.getNodeView(offScreenSiblingAbove) Point offScreenSiblingAboveSelectedPointOnMap = mapView.getNodeContentLocation(offScreenSiblingAboveNodeView) Point offScreenSiblingAboveSelectedPointOnScreen = SwingUtilities.convertPoint(mapView, offScreenSiblingAboveSelectedPointOnMap, viewport) - offScreenSiblingAboveXPoint = offScreenSiblingAboveSelectedPointOnScreen.x - offScreenSiblingAboveYPoint = offScreenSiblingAboveSelectedPointOnScreen.y - - - if (referenceNodeScreenY >= 0 && offScreenSiblingAboveYPoint <= 0 && referenceNodeScreenX > 0 && referenceNodeScreenX < viewport.getWidth()) { - - siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode.delegate, false, referenceNodeScreenX as int, referenceNodeScreenY as int) - - activeSiblingPreviewPanels << siblingsPreviewPanelCreated - + + if (selectedPointOnScreen.y >= 0 && offScreenSiblingAboveSelectedPointOnScreen.y <= 0 && + selectedPointOnScreen.x > 0 && selectedPointOnScreen.x < viewport.getWidth()) { + + def siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode, false, selectedPointOnScreen.x as int, selectedPointOnScreen.y as int) + if (siblingsPreviewPanelCreated) { + activeSiblingPreviewPanels.add(siblingsPreviewPanelCreated) + } } - - - } else { } - NodeModel offScreenSiblingBelow = null - - if(selectedIndex + 1 < siblings.size() && !isNodeVisibleInViewport(siblings[selectedIndex + 1].delegate)) offScreenSiblingBelow = siblings[selectedIndex + 1].delegate - + if (selectedIndex + 1 < siblings.size() && !isNodeVisibleInViewport(siblings[selectedIndex + 1])) { + offScreenSiblingBelow = siblings[selectedIndex + 1] + } if (offScreenSiblingBelow != null) { - NodeView offScreenSiblingBelowNodeView = mapView.getNodeView(offScreenSiblingBelow) Point offScreenSiblingBelowSelectedPointOnMap = mapView.getNodeContentLocation(offScreenSiblingBelowNodeView) Point offScreenSiblingBelowSelectedPointOnScreen = SwingUtilities.convertPoint(mapView, offScreenSiblingBelowSelectedPointOnMap, viewport) - offScreenSiblingBelowXPoint = offScreenSiblingBelowSelectedPointOnScreen.x - offScreenSiblingBelowYPoint = offScreenSiblingBelowSelectedPointOnScreen.y + + if (selectedPointOnScreen.y < viewport.getHeight() && + offScreenSiblingBelowSelectedPointOnScreen.y >= viewport.getHeight() && + selectedPointOnScreen.x > 0 && selectedPointOnScreen.x < viewport.getWidth()) { + + def siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode, true, selectedPointOnScreen.x as int, selectedPointOnScreen.y as int) + if (siblingsPreviewPanelCreated) { + activeSiblingPreviewPanels.add(siblingsPreviewPanelCreated) + } + } + } + } + + mapView.repaint() +} - if (referenceNodeScreenY < viewport.getHeight() && offScreenSiblingBelowYPoint >= viewport.getHeight() && referenceNodeScreenX > 0 && referenceNodeScreenX < viewport.getWidth()) { +// if(referenceNodeScreenX < 0 || referenceNodeScreenX > viewport.getViewRect().width) return - siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode.delegate, true, referenceNodeScreenX as int, referenceNodeScreenY as int) +if(testedNode.parent.children.size() == 1) return - activeSiblingPreviewPanels << siblingsPreviewPanelCreated +def parentNode = testedNode.parent +def siblings = parentNode.children +int selectedIndex = siblings.indexOf(testedNode) +if (selectedIndex < 0) { + return +} - } +NodeModel offScreenSiblingAbove = null +if(selectedIndex > 0 && !isNodeVisibleInViewport(siblings[selectedIndex - 1].delegate)) { + offScreenSiblingAbove = siblings[selectedIndex - 1].delegate +} - } else { - } +if (offScreenSiblingAbove != null) { + NodeView offScreenSiblingAboveNodeView = mapView.getNodeView(offScreenSiblingAbove) + Point offScreenSiblingAboveSelectedPointOnMap = mapView.getNodeContentLocation(offScreenSiblingAboveNodeView) + Point offScreenSiblingAboveSelectedPointOnScreen = SwingUtilities.convertPoint(mapView, offScreenSiblingAboveSelectedPointOnMap, viewport) + offScreenSiblingAboveXPoint = offScreenSiblingAboveSelectedPointOnScreen.x + offScreenSiblingAboveYPoint = offScreenSiblingAboveSelectedPointOnScreen.y + + if (referenceNodeScreenY >= 0 && offScreenSiblingAboveYPoint <= 0 && referenceNodeScreenX > 0 && referenceNodeScreenX < viewport.getWidth()) { + siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode.delegate, false, referenceNodeScreenX as int, referenceNodeScreenY as int) + activeSiblingPreviewPanels << siblingsPreviewPanelCreated + } +} + +NodeModel offScreenSiblingBelow = null + +if(selectedIndex + 1 < siblings.size() && !isNodeVisibleInViewport(siblings[selectedIndex + 1].delegate)) { + offScreenSiblingBelow = siblings[selectedIndex + 1].delegate +} + +if (offScreenSiblingBelow != null) { + NodeView offScreenSiblingBelowNodeView = mapView.getNodeView(offScreenSiblingBelow) + Point offScreenSiblingBelowSelectedPointOnMap = mapView.getNodeContentLocation(offScreenSiblingBelowNodeView) + Point offScreenSiblingBelowSelectedPointOnScreen = SwingUtilities.convertPoint(mapView, offScreenSiblingBelowSelectedPointOnMap, viewport) + offScreenSiblingBelowXPoint = offScreenSiblingBelowSelectedPointOnScreen.x + offScreenSiblingBelowYPoint = offScreenSiblingBelowSelectedPointOnScreen.y + + if (referenceNodeScreenY < viewport.getHeight() && offScreenSiblingBelowYPoint >= viewport.getHeight() && referenceNodeScreenX > 0 && referenceNodeScreenX < viewport.getWidth()) { + siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode.delegate, true, referenceNodeScreenX as int, referenceNodeScreenY as int) + activeSiblingPreviewPanels << siblingsPreviewPanelCreated } } From dececfe08b8b29725fef5a7cd71584750b079805 Mon Sep 17 00:00:00 2001 From: A <38586259+aaa1386@users.noreply.github.com> Date: Mon, 20 Oct 2025 10:34:38 +0330 Subject: [PATCH 04/14] =?UTF-8?q?=D8=A7=DB=8C=D8=AC=D8=A7=D8=AF=20=DB=8C?= =?UTF-8?q?=DA=A9=20=DA=AF=D8=B2=DB=8C=D9=86=D9=87=20=D8=A8=D8=B1=D8=A7?= =?UTF-8?q?=DB=8C=20=D9=86=D9=85=D8=A7=DB=8C=D8=B4=20=DB=8C=D8=A7=20=D8=B9?= =?UTF-8?q?=D8=AF=D9=85=20=D9=86=D9=85=D8=A7=DB=8C=D8=B4=20=D9=BE=D9=86?= =?UTF-8?q?=D9=84=20=D8=A8=D8=A7=D8=B2=D8=B1=D8=B3=20=D9=88=D9=82=D8=AA?= =?UTF-8?q?=DB=8C=20=DA=A9=D9=87=20=DA=AF=D8=B2=DB=8C=D9=86=D9=87=20In-pla?= =?UTF-8?q?ce=20Siblings=20Preview=20=D9=81=D8=B9=D8=A7=D9=84=20=D8=A7?= =?UTF-8?q?=D8=B3=D8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utilityPanels.groovy | 275 +++++++++++++++++-------------------------- 1 file changed, 108 insertions(+), 167 deletions(-) diff --git a/utilityPanels.groovy b/utilityPanels.groovy index 42948c3..c21199b 100644 --- a/utilityPanels.groovy +++ b/utilityPanels.groovy @@ -1,5 +1,5 @@ - /*************************************************************************** + version 1.48: Updated to be compatible with Freeplane 1.12.12. version 1.47: Quick search panel: Lines connecting the results in the quick search panel to the respective nodes. @@ -391,10 +391,10 @@ showAncestorsOnFirstInspector = false @groovy.transform.Field hideInspectorsEvenIfUpdateSelection = true @groovy.transform.Field showInPlaceSiblingsPreview = true -@groovy.transform.Field boolean isScrolling = false -@groovy.transform.Field Timer scrollStopTimer = new Timer(20, null) -//↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ User settings ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ +@groovy.transform.Field showInspectorsOnSiblingsPreviewHover = true + +//↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ User settings ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ @@ -627,11 +627,6 @@ class NodeModelTransferable implements Transferable { */ loadSettings() -scrollStopTimer.setRepeats(false) -scrollStopTimer.addActionListener({ - isScrolling = false - refreshSiblingPreviewPanels() -}) createPanels() createSingleRunListeners() startListeners() @@ -682,52 +677,50 @@ public void manageInspectorsCreation() { if (panelsInMasterPanels.contains(currentSourcePanel)) { expandMasterPanelAndUpdateInspectorsState(); } - - // ---------- تغییر داده شده ---------- + if (activeSiblingPreviewPanels.contains(currentSourcePanel)) { clearInspectorsAndPreviewInspectors(); - return; // جلوگیری از ساخت Inspector هنگام Hover روی پنل‌های Sibling Preview } - // ------------------------------------ - + if (!lastMouseLocation) return; - + int index = currentList.locationToIndex(lastMouseLocation); - + if (!validateMousePositionOnList(index)) return; - + Object hoveredItem = currentListModel.getElementAt(index); - + if (hoveredItem instanceof NodeModel) { - NodeModel subNode = currentListModel.getElementAt(index); + NodeModel subNode = (NodeModel) hoveredItem; hoveredNode = subNode; - + populateAncestorsList(hoveredNode); - + if (panelsInMasterPanels.contains(currentSourcePanel) || currentSourcePanel == breadcrumbPanel) { cleanAndCreateInspectors(subNode, masterPanel); + } else if (activeSiblingPreviewPanels.contains(currentSourcePanel)) { + // فقط اگر تنظیم فعال باشد، پنل‌های بازرس نمایش داده می‌شوند + if (showInspectorsOnSiblingsPreviewHover) { + updatePreviewInspectors(subNode); + } + currentList.repaint(); } else { + // شرایط دیگر createSubInspector(hoveredNode, index, subNode); } - } - else if (currentSourcePanel == tagsPanel) { + } else if (currentSourcePanel == tagsPanel) { updateInspectorWithTagsPanel(index); } - - // ★★★★ این خط جدید را اضافه کنید: - if (currentList != null) { - currentList.repaint(); // فورس رندر برای نمایش حاشیه بنفش - } } public boolean validateMousePositionOnList(int index) { - Rectangle cellBounds = currentList.getCellBounds(index, index); + Rectangle cellBounds = currentList.getCellBounds(index, index) - if (cellBounds == null || !cellBounds.contains(lastMouseLocation)) return false; + if (cellBounds == null || !cellBounds.contains(lastMouseLocation)) return false - if (index < 0 || index >= currentListModel.getSize()) return false; + if (index < 0 || index >= currentListModel.getSize()) return false - return true; + return true } public void createSubInspector(NodeModel hoveredNode, int index, NodeModel subNode) { @@ -2631,20 +2624,6 @@ void configureLabelForNode(JComponent component, NodeModel nodeNotProxy, JPanel } NodeModel storedNode = (NodeModel) sourcePanel.getClientProperty("referenceNode") - boolean isHovered = false - if (hoveredNode == nodeNotProxy && mouseOverList) { - isHovered = true - - } - if (isHovered) { - label.setBorder(BorderFactory.createLineBorder(new Color(160, 32, 240), 3)) // بنفش - } - else if (currentlySelectedNode == nodeNotProxy) { - label.setBorder(BorderFactory.createLineBorder(Color.RED, 4)) - } - else if(!panelsInMasterPanels.contains(sourcePanel) && sourcePanel != breadcrumbPanel) { - // کدهای موجود... - } // if(currentMapView.getNodeView(nodeNotProxy) == null || !isNodeOnScreen(nodeNotProxy)) { // label.setBorder(BorderFactory.createLineBorder(Color.BLUE, 4)) @@ -2671,10 +2650,18 @@ void configureLabelForNode(JComponent component, NodeModel nodeNotProxy, JPanel } else if(!panelsInMasterPanels.contains(sourcePanel) && sourcePanel != breadcrumbPanel) { - if (visibleInspectors.size() != 0 && visibleInspectors.any { it.getClientProperty("referenceNode") == nodeNotProxy }) { - label.setBorder(BorderFactory.createLineBorder((new Color(160, 32, 240, 255)), 4)) - } + // فقط برای پنل‌های In-place Siblings Preview و پنل‌های بازرس مربوط به آنها + if (activeSiblingPreviewPanels.contains(sourcePanel) || visiblePreviewInspectors.contains(sourcePanel)) { + // اگر این گره هاور شده است، خط بنفش نشان بده + if (hoveredNode == nodeNotProxy) { + label.setBorder(BorderFactory.createLineBorder((new Color(160, 32, 240, 255)), 4)) } + } + // برای پنل‌های بازرس معمولی (اگر لازم است) + else if (visibleInspectors.size() != 0 && visibleInspectors.any { it.getClientProperty("referenceNode") == nodeNotProxy }) { + label.setBorder(BorderFactory.createLineBorder((new Color(160, 32, 240, 255)), 4)) + } +} if(sourcePanel == quickSearchPanel) { Color mapBackgroundColor = Controller.currentController.MapViewManager.mapView.getBackground() @@ -3228,8 +3215,6 @@ void configureMouseExitListener(JList list) { @Override void mouseExited(MouseEvent e) { mouseOverList = false - hoveredNode = null // ★ پاک کردن هایلایت هاور - list.repaint() // ★ فورس رندر برای حذف حاشیه بنفش hideInspectorTimer.restart() } }) @@ -3459,7 +3444,8 @@ def saveSettings() { rtlOrientation: rtlOrientation, keyStrokeToShowPanels: keyStrokeToShowPanels.toString(), hideInspectorsEvenIfUpdateSelection: hideInspectorsEvenIfUpdateSelection, - showInPlaceSiblingsPreview: showInPlaceSiblingsPreview + showInPlaceSiblingsPreview: showInPlaceSiblingsPreview, + showInspectorsOnSiblingsPreviewHover: showInspectorsOnSiblingsPreviewHover ] ]).toPrettyString() @@ -3538,6 +3524,7 @@ private void loadSettings() { keyStrokeToShowPanels = KeyStroke.getKeyStroke(settings.userSettings.keyStrokeToShowPanels as String) hideInspectorsEvenIfUpdateSelection = settings.userSettings.hideInspectorsEvenIfUpdateSelection ?: hideInspectorsEvenIfUpdateSelection showInPlaceSiblingsPreview = settings.userSettings.showInPlaceSiblingsPreview ?: showInPlaceSiblingsPreview + showInspectorsOnSiblingsPreviewHover = settings.userSettings.showInspectorsOnSiblingsPreviewHover ?: showInspectorsOnSiblingsPreviewHover } } catch (Exception e) { @@ -4040,6 +4027,10 @@ def cleanPreviousScriptExecution() { // listenersToRemove3.each { listenerToRemove -> // Controller.currentController.mapViewManager.removeMapViewChangeListener(listenerToRemove) // } + + listenersToRemove3.each { listenerToRemove -> + Controller.currentController.mapViewManager.removeMapViewChangeListener(listenerToRemove) + } listenersToRemove4 = [] @@ -4208,6 +4199,12 @@ def showSettingsDialog() { JCheckBox showInPlaceSiblingsPreviewCheck = new JCheckBox("", showInPlaceSiblingsPreview) settingsPanel.add(showInPlaceSiblingsPreviewCheck) + // Show Inspectors on Siblings Preview Hover (Boolean) + settingsPanel.add(new JLabel("Show Inspectors on Siblings Preview Hover:")) + JCheckBox showInspectorsOnSiblingsPreviewHoverCheck = new JCheckBox("", showInspectorsOnSiblingsPreviewHover) + showInspectorsOnSiblingsPreviewHoverCheck.setToolTipText("Show inspector panels when hovering over nodes in In-place Siblings Preview panels") + settingsPanel.add(showInspectorsOnSiblingsPreviewHoverCheck) + // Hotkey to Show Panels (KeyStroke) settingsPanel.add(new JLabel("Hotkey to Show Panels:")) JTextField showPanelsHotkeyField = new JTextField(keyStrokeToShowPanels.toString()) @@ -4231,22 +4228,20 @@ def showSettingsDialog() { try { retractedWidthFactorForMasterPanel = Integer.parseInt(retractedFactorField.getText()) } catch(Exception ex) {} try { expandedWidthFactorForMasterPanel = Integer.parseInt(expandedFactorField.getText()) } catch(Exception ex) {} try { widthFactorForInspector = Integer.parseInt(inspectorWidthFactorField.getText()) } catch(Exception ex) {} -// try { selectionDelay = Integer.parseInt(selectionDelayField.getText()) } catch(Exception ex) {} reverseAncestorsList = reverseAncestorsCheck.isSelected() try { paddingBeforeHorizontalScrollBar = Integer.parseInt(paddingField.getText()) } catch(Exception ex) {} try { additionalInspectorDistanceToTheBottomOfTheScreen = Integer.parseInt(additionalDistanceField.getText()) } catch(Exception ex) {} try { widthOfTheClearButtonOnQuickSearchPanel = Integer.parseInt(clearButtonWidthField.getText()) } catch(Exception ex) {} try { keyStrokeToQuickSearch = KeyStroke.getKeyStroke(quickSearchHotkeyField.getText()) -// reloadPanels() } catch(Exception ex) {} showOnlyBreadcrumbs = showOnlyBreadcrumbsCheck.isSelected() showAncestorsOnFirstInspector = showAncestorsCheck.isSelected() rtlOrientation = rtlOrientationCheck.isSelected() showInPlaceSiblingsPreview = showInPlaceSiblingsPreviewCheck.isSelected() + showInspectorsOnSiblingsPreviewHover = showInspectorsOnSiblingsPreviewHoverCheck.isSelected() try { keyStrokeToShowPanels = KeyStroke.getKeyStroke(showPanelsHotkeyField.getText()) -// reloadPanels() } catch(Exception ex) {} hideInspectorsEvenIfUpdateSelection = hideInspectorsCheck.isSelected() @@ -4426,8 +4421,10 @@ def createComponentChangeListener() { mapView1 = Controller.currentController.MapViewManager.mapView if (mapView1.componentListeners.any { it.getClass().getName().startsWith("UtilityPanels") }) return + mapView1.addComponentListener(new ComponentAdapter() { public void componentMoved(ComponentEvent e) { + ensureOverlayExistsAndRepaint() if(!showPanels) { @@ -4439,35 +4436,18 @@ def createComponentChangeListener() { nv3 = mapView1.getNodeView(currentlySelectedNode) if (Boolean.TRUE.equals(nv3.getMainView().getClientProperty(INLINE_EDITOR_ACTIVE))) { return + } - // مدیریت پنل‌های siblings هنگام حرکت - if (showInPlaceSiblingsPreview) { - if (!isScrolling) { - isScrolling = true - hideSiblingPreviewPanels() // مخفی کردن پنل‌ها هنگام شروع اسکرول + if (showInPlaceSiblingsPreview) refreshSiblingPreviewPanels() + else if (activeSiblingPreviewPanels.size() != 0) { + activeSiblingPreviewPanels.each { + it.setVisible(false) } - scrollStopTimer.restart() + activeSiblingPreviewPanels.clear() } } }) - - // اضافه کردن لیسنر اسکرول به viewport - def viewport = mapView1.getParent() - if (viewport instanceof JViewport) { - viewport.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - if (showInPlaceSiblingsPreview) { - if (!isScrolling) { - isScrolling = true - hideSiblingPreviewPanels() // مخفی کردن پنل‌ها هنگام شروع اسکرول - } - scrollStopTimer.restart() - } - } - }) - } } @@ -4891,6 +4871,7 @@ def static getUserDefinedStylesParentNode(x = null){ return getUserDefinedStylesParentNode((ScriptContext) null) } + def static getUserDefinedStylesParentNode(ScriptContext scriptContext){ MapModel mapa = Controller.getCurrentController().getMap(); return getUserDefinedStylesParentNode(mapa, scriptContext) @@ -4911,16 +4892,8 @@ def static getUserDefinedStylesParentNode(MapModel mapa, ScriptContext scriptCon return userDefinedParentNode } -def hideSiblingPreviewPanels() { - activeSiblingPreviewPanels.each { - it.setVisible(false) - } -} def refreshSiblingPreviewPanels() { - if (isScrolling) { - return - } activeSiblingPreviewPanels.each { it.visible = false @@ -4928,127 +4901,95 @@ def refreshSiblingPreviewPanels() { } activeSiblingPreviewPanels.clear() - if (!showInPlaceSiblingsPreview) return - def mapView = Controller.currentController.MapViewManager.mapView def viewport = mapView.getParent() if (!(viewport instanceof JViewport)) { return } - c.viewRoot.findAll().each { nodeProxy -> - if (nodeProxy == c.viewRoot) return + c.viewRoot.findAll().each { - def testedNode = nodeProxy.delegate - if (testedNode == null) return + if (it == c.viewRoot) return - NodeView testedNodeView = mapView.getNodeView(testedNode) - if (testedNodeView == null) return - + def testedNode = it + if (testedNode == null) { + return + } + + NodeView testedNodeView = mapView.getNodeView(testedNode.delegate) + if (testedNodeView == null) { + return + } Point selectedPointOnMap = mapView.getNodeContentLocation(testedNodeView) Point selectedPointOnScreen = SwingUtilities.convertPoint(mapView, selectedPointOnMap, viewport) referenceNodeScreenX = selectedPointOnScreen.x referenceNodeScreenY = selectedPointOnScreen.y - if (testedNode.parent?.children?.size() == 1) return + +// if(referenceNodeScreenX < 0 || referenceNodeScreenX > viewport.getViewRect().width) return + + if(testedNode.parent.children.size() == 1) return + def parentNode = testedNode.parent def siblings = parentNode.children int selectedIndex = siblings.indexOf(testedNode) - if (selectedIndex < 0) return + if (selectedIndex < 0) { + return + } NodeModel offScreenSiblingAbove = null - if (selectedIndex > 0 && !isNodeVisibleInViewport(siblings[selectedIndex - 1])) { - offScreenSiblingAbove = siblings[selectedIndex - 1] - } + + + if(selectedIndex > 0 && !isNodeVisibleInViewport(siblings[selectedIndex - 1].delegate)) offScreenSiblingAbove = siblings[selectedIndex - 1].delegate if (offScreenSiblingAbove != null) { + NodeView offScreenSiblingAboveNodeView = mapView.getNodeView(offScreenSiblingAbove) Point offScreenSiblingAboveSelectedPointOnMap = mapView.getNodeContentLocation(offScreenSiblingAboveNodeView) Point offScreenSiblingAboveSelectedPointOnScreen = SwingUtilities.convertPoint(mapView, offScreenSiblingAboveSelectedPointOnMap, viewport) - - if (selectedPointOnScreen.y >= 0 && offScreenSiblingAboveSelectedPointOnScreen.y <= 0 && - selectedPointOnScreen.x > 0 && selectedPointOnScreen.x < viewport.getWidth()) { - - def siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode, false, selectedPointOnScreen.x as int, selectedPointOnScreen.y as int) - if (siblingsPreviewPanelCreated) { - activeSiblingPreviewPanels.add(siblingsPreviewPanelCreated) - } - } - } + offScreenSiblingAboveXPoint = offScreenSiblingAboveSelectedPointOnScreen.x + offScreenSiblingAboveYPoint = offScreenSiblingAboveSelectedPointOnScreen.y - NodeModel offScreenSiblingBelow = null - if (selectedIndex + 1 < siblings.size() && !isNodeVisibleInViewport(siblings[selectedIndex + 1])) { - offScreenSiblingBelow = siblings[selectedIndex + 1] - } - if (offScreenSiblingBelow != null) { - NodeView offScreenSiblingBelowNodeView = mapView.getNodeView(offScreenSiblingBelow) - Point offScreenSiblingBelowSelectedPointOnMap = mapView.getNodeContentLocation(offScreenSiblingBelowNodeView) - Point offScreenSiblingBelowSelectedPointOnScreen = SwingUtilities.convertPoint(mapView, offScreenSiblingBelowSelectedPointOnMap, viewport) - - if (selectedPointOnScreen.y < viewport.getHeight() && - offScreenSiblingBelowSelectedPointOnScreen.y >= viewport.getHeight() && - selectedPointOnScreen.x > 0 && selectedPointOnScreen.x < viewport.getWidth()) { - - def siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode, true, selectedPointOnScreen.x as int, selectedPointOnScreen.y as int) - if (siblingsPreviewPanelCreated) { - activeSiblingPreviewPanels.add(siblingsPreviewPanelCreated) - } + if (referenceNodeScreenY >= 0 && offScreenSiblingAboveYPoint <= 0 && referenceNodeScreenX > 0 && referenceNodeScreenX < viewport.getWidth()) { + + siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode.delegate, false, referenceNodeScreenX as int, referenceNodeScreenY as int) + + activeSiblingPreviewPanels << siblingsPreviewPanelCreated + } + + + } else { } - } - - mapView.repaint() -} -// if(referenceNodeScreenX < 0 || referenceNodeScreenX > viewport.getViewRect().width) return + NodeModel offScreenSiblingBelow = null -if(testedNode.parent.children.size() == 1) return + if(selectedIndex + 1 < siblings.size() && !isNodeVisibleInViewport(siblings[selectedIndex + 1].delegate)) offScreenSiblingBelow = siblings[selectedIndex + 1].delegate -def parentNode = testedNode.parent -def siblings = parentNode.children -int selectedIndex = siblings.indexOf(testedNode) -if (selectedIndex < 0) { - return -} -NodeModel offScreenSiblingAbove = null + if (offScreenSiblingBelow != null) { -if(selectedIndex > 0 && !isNodeVisibleInViewport(siblings[selectedIndex - 1].delegate)) { - offScreenSiblingAbove = siblings[selectedIndex - 1].delegate -} + NodeView offScreenSiblingBelowNodeView = mapView.getNodeView(offScreenSiblingBelow) + Point offScreenSiblingBelowSelectedPointOnMap = mapView.getNodeContentLocation(offScreenSiblingBelowNodeView) + Point offScreenSiblingBelowSelectedPointOnScreen = SwingUtilities.convertPoint(mapView, offScreenSiblingBelowSelectedPointOnMap, viewport) + offScreenSiblingBelowXPoint = offScreenSiblingBelowSelectedPointOnScreen.x + offScreenSiblingBelowYPoint = offScreenSiblingBelowSelectedPointOnScreen.y -if (offScreenSiblingAbove != null) { - NodeView offScreenSiblingAboveNodeView = mapView.getNodeView(offScreenSiblingAbove) - Point offScreenSiblingAboveSelectedPointOnMap = mapView.getNodeContentLocation(offScreenSiblingAboveNodeView) - Point offScreenSiblingAboveSelectedPointOnScreen = SwingUtilities.convertPoint(mapView, offScreenSiblingAboveSelectedPointOnMap, viewport) - offScreenSiblingAboveXPoint = offScreenSiblingAboveSelectedPointOnScreen.x - offScreenSiblingAboveYPoint = offScreenSiblingAboveSelectedPointOnScreen.y - if (referenceNodeScreenY >= 0 && offScreenSiblingAboveYPoint <= 0 && referenceNodeScreenX > 0 && referenceNodeScreenX < viewport.getWidth()) { - siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode.delegate, false, referenceNodeScreenX as int, referenceNodeScreenY as int) - activeSiblingPreviewPanels << siblingsPreviewPanelCreated - } -} + if (referenceNodeScreenY < viewport.getHeight() && offScreenSiblingBelowYPoint >= viewport.getHeight() && referenceNodeScreenX > 0 && referenceNodeScreenX < viewport.getWidth()) { -NodeModel offScreenSiblingBelow = null + siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode.delegate, true, referenceNodeScreenX as int, referenceNodeScreenY as int) -if(selectedIndex + 1 < siblings.size() && !isNodeVisibleInViewport(siblings[selectedIndex + 1].delegate)) { - offScreenSiblingBelow = siblings[selectedIndex + 1].delegate -} + activeSiblingPreviewPanels << siblingsPreviewPanelCreated + + } -if (offScreenSiblingBelow != null) { - NodeView offScreenSiblingBelowNodeView = mapView.getNodeView(offScreenSiblingBelow) - Point offScreenSiblingBelowSelectedPointOnMap = mapView.getNodeContentLocation(offScreenSiblingBelowNodeView) - Point offScreenSiblingBelowSelectedPointOnScreen = SwingUtilities.convertPoint(mapView, offScreenSiblingBelowSelectedPointOnMap, viewport) - offScreenSiblingBelowXPoint = offScreenSiblingBelowSelectedPointOnScreen.x - offScreenSiblingBelowYPoint = offScreenSiblingBelowSelectedPointOnScreen.y - if (referenceNodeScreenY < viewport.getHeight() && offScreenSiblingBelowYPoint >= viewport.getHeight() && referenceNodeScreenX > 0 && referenceNodeScreenX < viewport.getWidth()) { - siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode.delegate, true, referenceNodeScreenX as int, referenceNodeScreenY as int) - activeSiblingPreviewPanels << siblingsPreviewPanelCreated + } else { + } } } From 60193e2802f739b2a84063c45ad8b4fa4722b4bd Mon Sep 17 00:00:00 2001 From: A <38586259+aaa1386@users.noreply.github.com> Date: Mon, 20 Oct 2025 12:06:28 +0330 Subject: [PATCH 05/14] =?UTF-8?q?=D8=AA=D8=BA=DB=8C=DB=8C=D8=B1=20=D8=B3?= =?UTF-8?q?=DB=8C=D8=A7=D8=B3=DB=8C=D8=AA=20=D8=A2=D9=BE=D8=AF=DB=8C=D8=AA?= =?UTF-8?q?=20=D9=BE=D9=86=D9=84=20=D9=87=D8=A7=20=D9=87=D9=86=DA=AF=D8=A7?= =?UTF-8?q?=D9=85=20=D8=A7=D8=B3=DA=A9=D8=B1=D9=88=D9=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utilityPanels.groovy | 264 ++++++++++++++++++++++++++++++------------- 1 file changed, 188 insertions(+), 76 deletions(-) diff --git a/utilityPanels.groovy b/utilityPanels.groovy index c21199b..0ca0a54 100644 --- a/utilityPanels.groovy +++ b/utilityPanels.groovy @@ -394,6 +394,10 @@ showAncestorsOnFirstInspector = false @groovy.transform.Field showInspectorsOnSiblingsPreviewHover = true +@groovy.transform.Field Timer scrollStopTimer = new Timer(80, null) + +@groovy.transform.Field boolean isScrolling = false + //↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ User settings ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ @@ -609,8 +613,6 @@ class NodeModelTransferable implements Transferable { - - /* 888b d888 d8b .d8888b. 888 @@ -4439,7 +4441,10 @@ def createComponentChangeListener() { } - if (showInPlaceSiblingsPreview) refreshSiblingPreviewPanels() + + if (showInPlaceSiblingsPreview) { + updatePanelPositions() + } else if (activeSiblingPreviewPanels.size() != 0) { activeSiblingPreviewPanels.each { it.setVisible(false) @@ -4894,105 +4899,101 @@ def static getUserDefinedStylesParentNode(MapModel mapa, ScriptContext scriptCon def refreshSiblingPreviewPanels() { - - activeSiblingPreviewPanels.each { - it.visible = false - parentPanel.remove(it) - } - activeSiblingPreviewPanels.clear() + if (!showInPlaceSiblingsPreview) return def mapView = Controller.currentController.MapViewManager.mapView def viewport = mapView.getParent() - if (!(viewport instanceof JViewport)) { - return - } - - c.viewRoot.findAll().each { + if (!(viewport instanceof JViewport)) return - if (it == c.viewRoot) return - - def testedNode = it - if (testedNode == null) { - return + def c = ScriptUtils.c() + def panelsToKeep = [] // پنل‌هایی که هنوز نیاز هستن + def nodesProcessed = [] // نودهایی که پردازش شدند + + // مرحله ۱: بررسی پنل‌های موجود + activeSiblingPreviewPanels.each { panel -> + def nodeData = panel.getClientProperty("nodeData") + if (nodeData != null) { + def nodeNotProxy = nodeData.node + def positionAtBottom = nodeData.positionAtBottom + + // بررسی کن آیا این پنل هنوز لازمه + if (shouldKeepSiblingPanel(nodeNotProxy, positionAtBottom)) { + panelsToKeep << panel + nodesProcessed << nodeNotProxy + } else { + // پنل دیگه لازم نیست + panel.setVisible(false) + panel.getParent()?.remove(panel) + } } + } + + // مرحله ۲: پنل‌های جدید برای نودهای لازم ایجاد کن + c.viewRoot.findAll().each { nodeProxy -> + if (nodeProxy == c.viewRoot) return - NodeView testedNodeView = mapView.getNodeView(testedNode.delegate) - if (testedNodeView == null) { - return - } + def testedNode = nodeProxy.delegate + if (testedNode == null || nodesProcessed.contains(testedNode)) return + + NodeView testedNodeView = mapView.getNodeView(testedNode) + if (testedNodeView == null) return + Point selectedPointOnMap = mapView.getNodeContentLocation(testedNodeView) Point selectedPointOnScreen = SwingUtilities.convertPoint(mapView, selectedPointOnMap, viewport) - referenceNodeScreenX = selectedPointOnScreen.x - referenceNodeScreenY = selectedPointOnScreen.y - - -// if(referenceNodeScreenX < 0 || referenceNodeScreenX > viewport.getViewRect().width) return - - if(testedNode.parent.children.size() == 1) return + if (testedNode.parent?.children?.size() == 1) return def parentNode = testedNode.parent def siblings = parentNode.children int selectedIndex = siblings.indexOf(testedNode) - if (selectedIndex < 0) { - return - } - - NodeModel offScreenSiblingAbove = null - - - if(selectedIndex > 0 && !isNodeVisibleInViewport(siblings[selectedIndex - 1].delegate)) offScreenSiblingAbove = siblings[selectedIndex - 1].delegate - - if (offScreenSiblingAbove != null) { + if (selectedIndex < 0) return + // بررسی برای پنل بالا + if (selectedIndex > 0 && !isNodeVisibleInViewport(siblings[selectedIndex - 1])) { + NodeModel offScreenSiblingAbove = siblings[selectedIndex - 1] NodeView offScreenSiblingAboveNodeView = mapView.getNodeView(offScreenSiblingAbove) Point offScreenSiblingAboveSelectedPointOnMap = mapView.getNodeContentLocation(offScreenSiblingAboveNodeView) Point offScreenSiblingAboveSelectedPointOnScreen = SwingUtilities.convertPoint(mapView, offScreenSiblingAboveSelectedPointOnMap, viewport) - offScreenSiblingAboveXPoint = offScreenSiblingAboveSelectedPointOnScreen.x - offScreenSiblingAboveYPoint = offScreenSiblingAboveSelectedPointOnScreen.y - - - if (referenceNodeScreenY >= 0 && offScreenSiblingAboveYPoint <= 0 && referenceNodeScreenX > 0 && referenceNodeScreenX < viewport.getWidth()) { - - siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode.delegate, false, referenceNodeScreenX as int, referenceNodeScreenY as int) - - activeSiblingPreviewPanels << siblingsPreviewPanelCreated - + + if (selectedPointOnScreen.y >= 0 && offScreenSiblingAboveSelectedPointOnScreen.y <= 0 && + selectedPointOnScreen.x > 0 && selectedPointOnScreen.x < viewport.getWidth()) { + + def siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode, false, selectedPointOnScreen.x as int, selectedPointOnScreen.y as int) + if (siblingsPreviewPanelCreated) { + def nodeData = [node: testedNode, positionAtBottom: false] + siblingsPreviewPanelCreated.putClientProperty("nodeData", nodeData) + panelsToKeep << siblingsPreviewPanelCreated + } } - - - } else { } - - NodeModel offScreenSiblingBelow = null - - if(selectedIndex + 1 < siblings.size() && !isNodeVisibleInViewport(siblings[selectedIndex + 1].delegate)) offScreenSiblingBelow = siblings[selectedIndex + 1].delegate - - - if (offScreenSiblingBelow != null) { - + // بررسی برای پنل پایین + if (selectedIndex + 1 < siblings.size() && !isNodeVisibleInViewport(siblings[selectedIndex + 1])) { + NodeModel offScreenSiblingBelow = siblings[selectedIndex + 1] NodeView offScreenSiblingBelowNodeView = mapView.getNodeView(offScreenSiblingBelow) Point offScreenSiblingBelowSelectedPointOnMap = mapView.getNodeContentLocation(offScreenSiblingBelowNodeView) Point offScreenSiblingBelowSelectedPointOnScreen = SwingUtilities.convertPoint(mapView, offScreenSiblingBelowSelectedPointOnMap, viewport) - offScreenSiblingBelowXPoint = offScreenSiblingBelowSelectedPointOnScreen.x - offScreenSiblingBelowYPoint = offScreenSiblingBelowSelectedPointOnScreen.y - - - if (referenceNodeScreenY < viewport.getHeight() && offScreenSiblingBelowYPoint >= viewport.getHeight() && referenceNodeScreenX > 0 && referenceNodeScreenX < viewport.getWidth()) { - - siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode.delegate, true, referenceNodeScreenX as int, referenceNodeScreenY as int) - - activeSiblingPreviewPanels << siblingsPreviewPanelCreated - + + if (selectedPointOnScreen.y < viewport.getHeight() && + offScreenSiblingBelowSelectedPointOnScreen.y >= viewport.getHeight() && + selectedPointOnScreen.x > 0 && selectedPointOnScreen.x < viewport.getWidth()) { + + def siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode, true, selectedPointOnScreen.x as int, selectedPointOnScreen.y as int) + if (siblingsPreviewPanelCreated) { + def nodeData = [node: testedNode, positionAtBottom: true] + siblingsPreviewPanelCreated.putClientProperty("nodeData", nodeData) + panelsToKeep << siblingsPreviewPanelCreated + } } - - - } else { } } + + // آپدیت لیست پنل‌های فعال + activeSiblingPreviewPanels.clear() + activeSiblingPreviewPanels.addAll(panelsToKeep) + + mapView.repaint() } - public void createSingleRunListeners() { String searchText IMapViewChangeListener myMapViewChangeListener = new IMapViewChangeListener() { @@ -5045,6 +5046,10 @@ def startListeners() { createComponentChangeListener() + if (showInPlaceSiblingsPreview) { + initializeSiblingsPreview() + } + INodeSelectionListener mySelectionListener = new INodeSelectionListener() { @Override public void onDeselect(NodeModel node) { @@ -5172,7 +5177,7 @@ def startListeners() { // inPlaceInspector.setBounds((int) x, 500, 300, 300) // inPlaceInspector.setVisible(true) - //////////////////////// + /تاندا/////////////////////// } @@ -5427,3 +5432,110 @@ def refreshHighlighterCache() { def refreshHighlighterCacheTags() { cachedHighlightedNodesTags.clear() } + +// ★★★★ توابع جدید برای مدیریت پویای موقعیت پنل‌ها ★★★★ +def initializeSiblingsPreview() { + scrollStopTimer.setRepeats(false) + scrollStopTimer.addActionListener({ + isScrolling = false + refreshSiblingPreviewPanels() // بازسازی کامل پنل‌ها پس از توقف اسکرول + }) + + addScrollAndMoveListeners() +} + +def addScrollAndMoveListeners() { + def mapView = Controller.currentController.MapViewManager.mapView + + // لیسنر حرکت + mapView.addComponentListener(new ComponentAdapter() { + public void componentMoved(ComponentEvent e) { + if (showInPlaceSiblingsPreview) { + updatePanelPositions() // به‌روزرسانی موقعیت پنل‌های موجود + } + } + }) + + // لیسنر اسکرول + def viewport = mapView.getParent() + if (viewport instanceof JViewport) { + viewport.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + if (showInPlaceSiblingsPreview) { + if (!isScrolling) { + isScrolling = true + } + updatePanelPositions() // به‌روزرسانی موقعیت در حین اسکرول + scrollStopTimer.restart() + } + } + }) + } +} + +// تابع جدید: به‌روزرسانی موقعیت پنل‌ها بدون مخفی کردن +def updatePanelPositions() { + if (!showInPlaceSiblingsPreview || activeSiblingPreviewPanels.isEmpty()) return + + def mapView = Controller.currentController.MapViewManager.mapView + def viewport = mapView.getParent() + if (!(viewport instanceof JViewport)) return + + activeSiblingPreviewPanels.each { panel -> + def nodeData = panel.getClientProperty("nodeData") + if (nodeData != null) { + def nodeNotProxy = nodeData.node + def positionAtBottom = nodeData.positionAtBottom + + NodeView nodeView = mapView.getNodeView(nodeNotProxy) + if (nodeView != null) { + Point nodePoint = mapView.getNodeContentLocation(nodeView) + Point nodeScreen = SwingUtilities.convertPoint(mapView, nodePoint, viewport) + + int referenceNodeScreenX = nodeScreen.x + int referenceNodeScreenY = nodeScreen.y + + if (!positionAtBottom) { + panel.setLocation(referenceNodeScreenX, referenceNodeScreenY - panel.getHeight()) + } else { + panel.setLocation(referenceNodeScreenX, referenceNodeScreenY + nodeView.getContentPane().height) + } + } + } + } + + mapView.repaint() +} +// تابع کمکی: بررسی کن آیا پنل باید نگه داشته بشه +def shouldKeepSiblingPanel(NodeModel nodeNotProxy, boolean positionAtBottom) { + def mapView = Controller.currentController.MapViewManager.mapView + def viewport = mapView.getParent() + if (!(viewport instanceof JViewport)) return false + + NodeView nodeView = mapView.getNodeView(nodeNotProxy) + if (nodeView == null) return false + + Point nodePoint = mapView.getNodeContentLocation(nodeView) + Point nodeScreen = SwingUtilities.convertPoint(mapView, nodePoint, viewport) + + def parentNode = nodeNotProxy.parent + def siblings = parentNode.children + int selectedIndex = siblings.indexOf(nodeNotProxy) + if (selectedIndex < 0) return false + + if (!positionAtBottom) { + // پنل بالا - بررسی کن آیا هنوز siblingهای بالایی خارج از viewport هستن + if (selectedIndex > 0 && !isNodeVisibleInViewport(siblings[selectedIndex - 1])) { + return nodeScreen.y >= 0 && nodeScreen.x > 0 && nodeScreen.x < viewport.getWidth() + } + } else { + // پنل پایین - بررسی کن آیا هنوز siblingهای پایینی خارج از viewport هستن + if (selectedIndex + 1 < siblings.size() && !isNodeVisibleInViewport(siblings[selectedIndex + 1])) { + return nodeScreen.y < viewport.getHeight() && nodeScreen.x > 0 && nodeScreen.x < viewport.getWidth() + } + } + + return false +} +return From d9ac98af8350fde1eee0a6f7d41dd29c131b3960 Mon Sep 17 00:00:00 2001 From: A <38586259+aaa1386@users.noreply.github.com> Date: Mon, 20 Oct 2025 12:45:17 +0330 Subject: [PATCH 06/14] =?UTF-8?q?=DA=A9=D9=85=20=DA=A9=D8=B1=D8=AF=D9=86?= =?UTF-8?q?=20=D8=B2=D9=85=D8=A7=D9=86=20=D8=B3=D9=86=D8=AC=20=D8=A8=D8=B1?= =?UTF-8?q?=D8=A7=DB=8C=20=D9=85=DA=A9=D8=AB=20=D8=A8=D8=B9=D8=AF=20=D8=A7?= =?UTF-8?q?=D8=B2=20=D8=A7=D8=B3=DA=A9=D8=B1=D9=88=D9=84=20=D9=88=20=D8=A2?= =?UTF-8?q?=D9=BE=D8=AF=DB=8C=D8=AA=20=D9=BE=D9=86=D9=84=20=D9=87=D8=A7?= =?UTF-8?q?=DB=8C=20=D9=84=D8=A7=D8=B2=D9=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utilityPanels.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utilityPanels.groovy b/utilityPanels.groovy index 0ca0a54..b62a71d 100644 --- a/utilityPanels.groovy +++ b/utilityPanels.groovy @@ -394,7 +394,7 @@ showAncestorsOnFirstInspector = false @groovy.transform.Field showInspectorsOnSiblingsPreviewHover = true -@groovy.transform.Field Timer scrollStopTimer = new Timer(80, null) +@groovy.transform.Field Timer scrollStopTimer = new Timer(1, null) @groovy.transform.Field boolean isScrolling = false From 09d6e48ad2802b52fb02fa2d28e49c3fbcec7c0a Mon Sep 17 00:00:00 2001 From: A <38586259+aaa1386@users.noreply.github.com> Date: Mon, 20 Oct 2025 18:52:53 +0330 Subject: [PATCH 07/14] =?UTF-8?q?=D8=B1=D9=81=D8=B9=20=D8=AE=D8=B7=D8=A7?= =?UTF-8?q?=DB=8C=20=D8=A2=D9=BE=D8=AF=DB=8C=D8=AA=20=DA=A9=D8=A7=D9=85?= =?UTF-8?q?=D9=84=20=D9=BE=D9=86=D9=84=20=D9=87=D8=A7=20-=20=D8=A7=D9=84?= =?UTF-8?q?=D8=A7=D9=86=20=20=D9=BE=D9=86=D9=84=20=20=20=D9=87=D8=A7=20?= =?UTF-8?q?=D8=A2=D9=BE=D8=AF=DB=8C=D8=AA=20=D9=85=DB=8C=20=D8=B4=D9=88?= =?UTF-8?q?=D9=86=D8=AF=20=D9=88=20=D8=A8=D9=87=20=D8=AE=D9=88=D8=A8=DB=8C?= =?UTF-8?q?=20=D8=A7=D8=B3=DA=A9=D8=B1=D9=88=D9=84=20=D9=85=DB=8C=20=D8=B4?= =?UTF-8?q?=D9=88=D9=86=D8=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utilityPanels.groovy | 441 ++++++++++++++++++++++++------------------- 1 file changed, 246 insertions(+), 195 deletions(-) diff --git a/utilityPanels.groovy b/utilityPanels.groovy index b62a71d..568aee7 100644 --- a/utilityPanels.groovy +++ b/utilityPanels.groovy @@ -318,14 +318,16 @@ import javax.swing.event.ChangeEvent @groovy.transform.Field uniqueIdForScript = 999 +// تایمر جدید برای مدیریت اسکرول +@groovy.transform.Field Timer scrollCompletionTimer = new Timer(100, null) if(checkIfUtilityPanelsIsAlreadyRunning()) return - - - - - +// تنظیمات تایمر اسکرول +scrollCompletionTimer.setRepeats(false) +scrollCompletionTimer.addActionListener(e -> { + updatePanelsAfterScroll() +}) /* @@ -394,10 +396,6 @@ showAncestorsOnFirstInspector = false @groovy.transform.Field showInspectorsOnSiblingsPreviewHover = true -@groovy.transform.Field Timer scrollStopTimer = new Timer(1, null) - -@groovy.transform.Field boolean isScrolling = false - //↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ User settings ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ @@ -613,6 +611,8 @@ class NodeModelTransferable implements Transferable { + + /* 888b d888 d8b .d8888b. 888 @@ -673,6 +673,162 @@ def boolean checkIfUtilityPanelsIsAlreadyRunning() { } } +// ==================== متدهای جدید برای مدیریت اسکرول ==================== + +def addScrollListener() { + def mapView = Controller.currentController.MapViewManager.mapView + def viewport = mapView.parent + + if (viewport instanceof JViewport) { + viewport.addChangeListener(new ChangeListener() { + @Override + void stateChanged(ChangeEvent e) { + // هنگام اسکرول، پنل‌ها را همراه با نقشه حرکت دهید + movePanelsWithMap() + + // تایمر برای به‌روزرسانی پس از پایان اسکرول + restartScrollCompletionTimer() + } + }) + } +} + +def movePanelsWithMap() { + def mapView = Controller.currentController.MapViewManager.mapView + def viewport = mapView.parent as JViewport + + if (!viewport) return + + Rectangle viewRect = viewport.getViewRect() + + // حرکت دادن breadcrumbPanel + if (breadcrumbPanel?.isVisible()) { + breadcrumbPanel.setLocation(0, 0) + breadcrumbPanel.setSize(viewport.width, breadcrumbPanel.height) + } + + // حرکت دادن masterPanel + if (masterPanel?.isVisible()) { + int masterPanelWidth = calculateRetractedWidthForMasterPanel() + if (isMasterPanelExpanded) { + masterPanelWidth = calculateExpandedWidthForMasterPanel() + } + + masterPanel.setLocation(0, breadcrumbPanel?.height ?: 0) + masterPanel.setSize(masterPanelWidth, viewport.height - (breadcrumbPanel?.height ?: 0)) + } + + // حرکت دادن inspector پنل‌ها + visibleInspectors.each { inspector -> + if (inspector.isVisible()) { + updateInspectorPositionDuringScroll(inspector) + } + } + + // حرکت دادن preview پنل‌ها + visiblePreviewInspectors.each { preview -> + if (preview.isVisible()) { + updatePreviewPositionDuringScroll(preview) + } + } + + // حرکت دادن sibling preview پنل‌ها + activeSiblingPreviewPanels.each { siblingPanel -> + if (siblingPanel.isVisible()) { + updateSiblingPreviewPositionDuringScroll(siblingPanel) + } + } + + // به‌روزرسانی خطوط اتصال + ensureOverlayExistsAndRepaint() +} + +def updateInspectorPositionDuringScroll(JPanel inspector) { + def sourcePanel = findSourcePanelForInspector(inspector) + if (sourcePanel) { + setInspectorLocation(inspector, sourcePanel) + } +} + +def updatePreviewPositionDuringScroll(JPanel preview) { + def sourcePanel = findSourcePanelForInspector(preview) + if (sourcePanel) { + setInspectorLocation(preview, sourcePanel) + } +} + +def updateSiblingPreviewPositionDuringScroll(JPanel siblingPanel) { + NodeModel referenceNode = siblingPanel.getClientProperty("referenceNode") + boolean positionAtBottom = siblingPanel.getClientProperty("positionAtBottom") ?: false + + if (referenceNode) { + def mapView = Controller.currentController.MapViewManager.mapView + def viewport = mapView.parent as JViewport + + NodeView nodeView = mapView.getNodeView(referenceNode) + if (nodeView) { + Point nodePoint = mapView.getNodeContentLocation(nodeView) + Point screenPoint = SwingUtilities.convertPoint(mapView, nodePoint, viewport) + + int referenceX = screenPoint.x + int referenceY = screenPoint.y + + // محاسبه موقعیت جدید + if (!positionAtBottom) { + siblingPanel.setLocation(referenceX, (referenceY - siblingPanel.height) as int) + } else { + siblingPanel.setLocation(referenceX, (referenceY + nodeView.contentPane.height) as int) + } + } + } +} + +def updatePanelsAfterScroll() { + // به‌روزرسانی وضعیت پنل‌ها بر اساس موقعیت جدید + if (inspectorUpdateSelection) { + smartCreateInspectors(currentlySelectedNode) + } + + // به‌روزرسانی پنل‌های پیش‌نمایش siblings + if (showInPlaceSiblingsPreview) { + refreshSiblingPreviewPanels() + } else { + activeSiblingPreviewPanels.each { it.setVisible(false) } + activeSiblingPreviewPanels.clear() + } + + // به‌روزرسانی breadcrumb + updateBreadcrumbPanel() + + // اعتبارسنجی و ترسیم مجدد + parentPanel.revalidate() + parentPanel.repaint() +} + +def restartScrollCompletionTimer() { + scrollCompletionTimer.stop() + scrollCompletionTimer.start() +} + +def findSourcePanelForInspector(JPanel inspector) { + // این متد پنل منبع اینسپکتور را پیدا می‌کند + if (visibleInspectors.contains(inspector)) { + int index = visibleInspectors.indexOf(inspector) + if (index == 0) return masterPanel + if (index > 0) return visibleInspectors[index - 1] + } + + if (visiblePreviewInspectors.contains(inspector)) { + int index = visiblePreviewInspectors.indexOf(inspector) + if (index == 0) return currentSourcePanel + if (index > 0) return visiblePreviewInspectors[index - 1] + } + + return masterPanel +} + +// ==================== پایان متدهای جدید برای مدیریت اسکرول ==================== + public void manageInspectorsCreation() { if (shouldFreeze()) return; @@ -919,6 +1075,9 @@ def createPanels() { assembleMasterPanel(breadcrumbPanel, quickSearchPanel, recentSelectedNodesPanel, pinnedItemsPanel, stylesPanel, tagsPanel, innerPanelInQuickSearchPanel) } + // افزودن Listener اسکرول + addScrollListener() + parentPanel.revalidate() parentPanel.repaint() } @@ -3661,10 +3820,11 @@ def cleanAndCreateInspectors(NodeModel nodeNotProxy, JPanel somePanel, String du dummyPanel = "no" break } - visibleInspectors.each { - it.setVisible(false) + it.setVisible(false) } + + visibleInspectors visibleInspectors.clear() JPanel subInspectorPanel if (dummyPanel == "siblings") { @@ -4441,10 +4601,7 @@ def createComponentChangeListener() { } - - if (showInPlaceSiblingsPreview) { - updatePanelPositions() - } + if (showInPlaceSiblingsPreview) refreshSiblingPreviewPanels() else if (activeSiblingPreviewPanels.size() != 0) { activeSiblingPreviewPanels.each { it.setVisible(false) @@ -4899,107 +5056,112 @@ def static getUserDefinedStylesParentNode(MapModel mapa, ScriptContext scriptCon def refreshSiblingPreviewPanels() { - if (!showInPlaceSiblingsPreview) return + + activeSiblingPreviewPanels.each { + it.visible = false + parentPanel.remove(it) + } + activeSiblingPreviewPanels.clear() def mapView = Controller.currentController.MapViewManager.mapView def viewport = mapView.getParent() - if (!(viewport instanceof JViewport)) return - - def c = ScriptUtils.c() - def panelsToKeep = [] // پنل‌هایی که هنوز نیاز هستن - def nodesProcessed = [] // نودهایی که پردازش شدند - - // مرحله ۱: بررسی پنل‌های موجود - activeSiblingPreviewPanels.each { panel -> - def nodeData = panel.getClientProperty("nodeData") - if (nodeData != null) { - def nodeNotProxy = nodeData.node - def positionAtBottom = nodeData.positionAtBottom - - // بررسی کن آیا این پنل هنوز لازمه - if (shouldKeepSiblingPanel(nodeNotProxy, positionAtBottom)) { - panelsToKeep << panel - nodesProcessed << nodeNotProxy - } else { - // پنل دیگه لازم نیست - panel.setVisible(false) - panel.getParent()?.remove(panel) - } - } + if (!(viewport instanceof JViewport)) { + return } - - // مرحله ۲: پنل‌های جدید برای نودهای لازم ایجاد کن - c.viewRoot.findAll().each { nodeProxy -> - if (nodeProxy == c.viewRoot) return - def testedNode = nodeProxy.delegate - if (testedNode == null || nodesProcessed.contains(testedNode)) return + c.viewRoot.findAll().each { + + if (it == c.viewRoot) return - NodeView testedNodeView = mapView.getNodeView(testedNode) - if (testedNodeView == null) return - + def testedNode = it + if (testedNode == null) { + return + } + + NodeView testedNodeView = mapView.getNodeView(testedNode.delegate) + if (testedNodeView == null) { + return + } Point selectedPointOnMap = mapView.getNodeContentLocation(testedNodeView) Point selectedPointOnScreen = SwingUtilities.convertPoint(mapView, selectedPointOnMap, viewport) + referenceNodeScreenX = selectedPointOnScreen.x + referenceNodeScreenY = selectedPointOnScreen.y + + +// if(referenceNodeScreenX < 0 || referenceNodeScreenX > viewport.getViewRect().width) return + + if(testedNode.parent.children.size() == 1) return - if (testedNode.parent?.children?.size() == 1) return def parentNode = testedNode.parent def siblings = parentNode.children int selectedIndex = siblings.indexOf(testedNode) - if (selectedIndex < 0) return + if (selectedIndex < 0) { + return + } + + NodeModel offScreenSiblingAbove = null + + + if(selectedIndex > 0 && !isNodeVisibleInViewport(siblings[selectedIndex - 1].delegate)) offScreenSiblingAbove = siblings[selectedIndex - 1].delegate + + if (offScreenSiblingAbove != null) { - // بررسی برای پنل بالا - if (selectedIndex > 0 && !isNodeVisibleInViewport(siblings[selectedIndex - 1])) { - NodeModel offScreenSiblingAbove = siblings[selectedIndex - 1] NodeView offScreenSiblingAboveNodeView = mapView.getNodeView(offScreenSiblingAbove) Point offScreenSiblingAboveSelectedPointOnMap = mapView.getNodeContentLocation(offScreenSiblingAboveNodeView) Point offScreenSiblingAboveSelectedPointOnScreen = SwingUtilities.convertPoint(mapView, offScreenSiblingAboveSelectedPointOnMap, viewport) - - if (selectedPointOnScreen.y >= 0 && offScreenSiblingAboveSelectedPointOnScreen.y <= 0 && - selectedPointOnScreen.x > 0 && selectedPointOnScreen.x < viewport.getWidth()) { - - def siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode, false, selectedPointOnScreen.x as int, selectedPointOnScreen.y as int) - if (siblingsPreviewPanelCreated) { - def nodeData = [node: testedNode, positionAtBottom: false] - siblingsPreviewPanelCreated.putClientProperty("nodeData", nodeData) - panelsToKeep << siblingsPreviewPanelCreated - } + offScreenSiblingAboveXPoint = offScreenSiblingAboveSelectedPointOnScreen.x + offScreenSiblingAboveYPoint = offScreenSiblingAboveSelectedPointOnScreen.y + + + if (referenceNodeScreenY >= 0 && offScreenSiblingAboveYPoint <= 0 && referenceNodeScreenX > 0 && referenceNodeScreenX < viewport.getWidth()) { + + siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode.delegate, false, referenceNodeScreenX as int, referenceNodeScreenY as int) + + activeSiblingPreviewPanels << siblingsPreviewPanelCreated + } + + + } else { } - // بررسی برای پنل پایین - if (selectedIndex + 1 < siblings.size() && !isNodeVisibleInViewport(siblings[selectedIndex + 1])) { - NodeModel offScreenSiblingBelow = siblings[selectedIndex + 1] + + NodeModel offScreenSiblingBelow = null + + if(selectedIndex + 1 < siblings.size() && !isNodeVisibleInViewport(siblings[selectedIndex + 1].delegate)) offScreenSiblingBelow = siblings[selectedIndex + 1].delegate + + + if (offScreenSiblingBelow != null) { + NodeView offScreenSiblingBelowNodeView = mapView.getNodeView(offScreenSiblingBelow) Point offScreenSiblingBelowSelectedPointOnMap = mapView.getNodeContentLocation(offScreenSiblingBelowNodeView) Point offScreenSiblingBelowSelectedPointOnScreen = SwingUtilities.convertPoint(mapView, offScreenSiblingBelowSelectedPointOnMap, viewport) - - if (selectedPointOnScreen.y < viewport.getHeight() && - offScreenSiblingBelowSelectedPointOnScreen.y >= viewport.getHeight() && - selectedPointOnScreen.x > 0 && selectedPointOnScreen.x < viewport.getWidth()) { - - def siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode, true, selectedPointOnScreen.x as int, selectedPointOnScreen.y as int) - if (siblingsPreviewPanelCreated) { - def nodeData = [node: testedNode, positionAtBottom: true] - siblingsPreviewPanelCreated.putClientProperty("nodeData", nodeData) - panelsToKeep << siblingsPreviewPanelCreated - } + offScreenSiblingBelowXPoint = offScreenSiblingBelowSelectedPointOnScreen.x + offScreenSiblingBelowYPoint = offScreenSiblingBelowSelectedPointOnScreen.y + + + if (referenceNodeScreenY < viewport.getHeight() && offScreenSiblingBelowYPoint >= viewport.getHeight() && referenceNodeScreenX > 0 && referenceNodeScreenX < viewport.getWidth()) { + + siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode.delegate, true, referenceNodeScreenX as int, referenceNodeScreenY as int) + + activeSiblingPreviewPanels << siblingsPreviewPanelCreated + } + + + } else { } } - - // آپدیت لیست پنل‌های فعال - activeSiblingPreviewPanels.clear() - activeSiblingPreviewPanels.addAll(panelsToKeep) - - mapView.repaint() } + public void createSingleRunListeners() { String searchText IMapViewChangeListener myMapViewChangeListener = new IMapViewChangeListener() { public void afterViewChange(final Component oldView, final Component newView) { if (newView == null) { return + addScrollListener() } searchText = "" @@ -5046,10 +5208,6 @@ def startListeners() { createComponentChangeListener() - if (showInPlaceSiblingsPreview) { - initializeSiblingsPreview() - } - INodeSelectionListener mySelectionListener = new INodeSelectionListener() { @Override public void onDeselect(NodeModel node) { @@ -5177,7 +5335,7 @@ def startListeners() { // inPlaceInspector.setBounds((int) x, 500, 300, 300) // inPlaceInspector.setVisible(true) - /تاندا/////////////////////// + //////////////////////// } @@ -5432,110 +5590,3 @@ def refreshHighlighterCache() { def refreshHighlighterCacheTags() { cachedHighlightedNodesTags.clear() } - -// ★★★★ توابع جدید برای مدیریت پویای موقعیت پنل‌ها ★★★★ -def initializeSiblingsPreview() { - scrollStopTimer.setRepeats(false) - scrollStopTimer.addActionListener({ - isScrolling = false - refreshSiblingPreviewPanels() // بازسازی کامل پنل‌ها پس از توقف اسکرول - }) - - addScrollAndMoveListeners() -} - -def addScrollAndMoveListeners() { - def mapView = Controller.currentController.MapViewManager.mapView - - // لیسنر حرکت - mapView.addComponentListener(new ComponentAdapter() { - public void componentMoved(ComponentEvent e) { - if (showInPlaceSiblingsPreview) { - updatePanelPositions() // به‌روزرسانی موقعیت پنل‌های موجود - } - } - }) - - // لیسنر اسکرول - def viewport = mapView.getParent() - if (viewport instanceof JViewport) { - viewport.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - if (showInPlaceSiblingsPreview) { - if (!isScrolling) { - isScrolling = true - } - updatePanelPositions() // به‌روزرسانی موقعیت در حین اسکرول - scrollStopTimer.restart() - } - } - }) - } -} - -// تابع جدید: به‌روزرسانی موقعیت پنل‌ها بدون مخفی کردن -def updatePanelPositions() { - if (!showInPlaceSiblingsPreview || activeSiblingPreviewPanels.isEmpty()) return - - def mapView = Controller.currentController.MapViewManager.mapView - def viewport = mapView.getParent() - if (!(viewport instanceof JViewport)) return - - activeSiblingPreviewPanels.each { panel -> - def nodeData = panel.getClientProperty("nodeData") - if (nodeData != null) { - def nodeNotProxy = nodeData.node - def positionAtBottom = nodeData.positionAtBottom - - NodeView nodeView = mapView.getNodeView(nodeNotProxy) - if (nodeView != null) { - Point nodePoint = mapView.getNodeContentLocation(nodeView) - Point nodeScreen = SwingUtilities.convertPoint(mapView, nodePoint, viewport) - - int referenceNodeScreenX = nodeScreen.x - int referenceNodeScreenY = nodeScreen.y - - if (!positionAtBottom) { - panel.setLocation(referenceNodeScreenX, referenceNodeScreenY - panel.getHeight()) - } else { - panel.setLocation(referenceNodeScreenX, referenceNodeScreenY + nodeView.getContentPane().height) - } - } - } - } - - mapView.repaint() -} -// تابع کمکی: بررسی کن آیا پنل باید نگه داشته بشه -def shouldKeepSiblingPanel(NodeModel nodeNotProxy, boolean positionAtBottom) { - def mapView = Controller.currentController.MapViewManager.mapView - def viewport = mapView.getParent() - if (!(viewport instanceof JViewport)) return false - - NodeView nodeView = mapView.getNodeView(nodeNotProxy) - if (nodeView == null) return false - - Point nodePoint = mapView.getNodeContentLocation(nodeView) - Point nodeScreen = SwingUtilities.convertPoint(mapView, nodePoint, viewport) - - def parentNode = nodeNotProxy.parent - def siblings = parentNode.children - int selectedIndex = siblings.indexOf(nodeNotProxy) - if (selectedIndex < 0) return false - - if (!positionAtBottom) { - // پنل بالا - بررسی کن آیا هنوز siblingهای بالایی خارج از viewport هستن - if (selectedIndex > 0 && !isNodeVisibleInViewport(siblings[selectedIndex - 1])) { - return nodeScreen.y >= 0 && nodeScreen.x > 0 && nodeScreen.x < viewport.getWidth() - } - } else { - // پنل پایین - بررسی کن آیا هنوز siblingهای پایینی خارج از viewport هستن - if (selectedIndex + 1 < siblings.size() && !isNodeVisibleInViewport(siblings[selectedIndex + 1])) { - return nodeScreen.y < viewport.getHeight() && nodeScreen.x > 0 && nodeScreen.x < viewport.getWidth() - } - } - - return false -} -return From 4b2b80bf1f7b0010e4c834cacd808e67bbf8037d Mon Sep 17 00:00:00 2001 From: A <38586259+aaa1386@users.noreply.github.com> Date: Mon, 20 Oct 2025 23:08:59 +0330 Subject: [PATCH 08/14] =?UTF-8?q?=D8=B1=D9=81=D8=B9=20=D8=AE=D8=B7=D8=A7?= =?UTF-8?q?=20=D8=A7=D8=B2=20=D9=87=D9=85=D8=A7=D9=87=D9=86=DA=AF=DB=8C=20?= =?UTF-8?q?=D8=A2=D9=BE=D8=AF=DB=8C=D8=AA=20=D9=BE=D9=86=D9=84=20=D9=87?= =?UTF-8?q?=D8=A7=20=D9=88=20=D8=A7=D8=B3=DA=A9=D8=B1=D9=88=D9=84=20=D9=86?= =?UTF-8?q?=D9=82=D8=B4=D9=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utilityPanels.groovy | 368 +++++++++++++++++++++---------------------- 1 file changed, 182 insertions(+), 186 deletions(-) diff --git a/utilityPanels.groovy b/utilityPanels.groovy index 568aee7..51ced0a 100644 --- a/utilityPanels.groovy +++ b/utilityPanels.groovy @@ -317,17 +317,17 @@ import javax.swing.event.ChangeListener import javax.swing.event.ChangeEvent @groovy.transform.Field uniqueIdForScript = 999 +@groovy.transform.Field boolean isScrolling = false + -// تایمر جدید برای مدیریت اسکرول -@groovy.transform.Field Timer scrollCompletionTimer = new Timer(100, null) if(checkIfUtilityPanelsIsAlreadyRunning()) return -// تنظیمات تایمر اسکرول -scrollCompletionTimer.setRepeats(false) -scrollCompletionTimer.addActionListener(e -> { - updatePanelsAfterScroll() -}) + + + + + /* @@ -555,6 +555,13 @@ hideInspectorTimer.addActionListener(e -> { hideInspectorPanelIfNeeded() }) +@groovy.transform.Field Timer scrollEndTimer = new Timer(300, null) +scrollEndTimer.setRepeats(false) +scrollEndTimer.addActionListener(e -> { + isScrolling = false + updateAllPanelsAfterScroll() +}) + @groovy.transform.Field MouseListener sharedMouseListener @groovy.transform.Field Timer hoverTimer = new Timer(selectionDelay, null) @@ -627,6 +634,156 @@ class NodeModelTransferable implements Transferable { ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */ +//↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ Scroll Management Methods ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ + +def createScrollListener() { + JScrollBar verticalScrollBar = parentPanel.getVerticalScrollBar() + JScrollBar horizontalScrollBar = parentPanel.getHorizontalScrollBar() + + AdjustmentListener scrollListener = new AdjustmentListener() { + @Override + void adjustmentValueChanged(AdjustmentEvent e) { + if (!isScrolling) { + isScrolling = true + } + scrollEndTimer.restart() + + // حرکت دادن پنل‌های In-place Siblings Preview همراه با نقشه + moveSiblingPreviewPanelsWithMap() + } + } + + verticalScrollBar.addAdjustmentListener(scrollListener) + horizontalScrollBar.addAdjustmentListener(scrollListener) +} + +//↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ Scroll Management Methods ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ + +def moveSiblingPreviewPanelsWithMap() { + if (!showInPlaceSiblingsPreview || activeSiblingPreviewPanels.isEmpty()) return + + def mapView = Controller.currentController.MapViewManager.mapView + def viewport = mapView.getParent() + if (!(viewport instanceof JViewport)) return + + activeSiblingPreviewPanels.each { previewPanel -> + NodeModel referenceNode = previewPanel.getClientProperty("referenceNode") + if (referenceNode) { + NodeView nodeView = mapView.getNodeView(referenceNode) + if (nodeView) { + Point nodePointOnMap = mapView.getNodeContentLocation(nodeView) + Point nodePointOnScreen = SwingUtilities.convertPoint(mapView, nodePointOnMap, viewport) + + boolean positionAtBottom = previewPanel.getClientProperty("positionAtBottom") ?: false + + int newX = nodePointOnScreen.x + int newY + + if (!positionAtBottom) { + newY = (nodePointOnScreen.y - previewPanel.getHeight()) as int + } else { + newY = (nodePointOnScreen.y + nodeView.getContentPane().height) as int + } + + // به روزرسانی موقعیت پنل بدون ایجاد پنل جدید + previewPanel.setLocation(newX, newY) + } + } + } + + // به روزرسانی موقعیت پنل‌های بازرس پیش‌نمایش + movePreviewInspectorsWithMap() +} + +def movePreviewInspectorsWithMap() { + if (visiblePreviewInspectors.isEmpty()) return + + visiblePreviewInspectors.each { previewInspector -> + JPanel sourcePanel = findSourcePanelForInspector(previewInspector) + if (sourcePanel && (activeSiblingPreviewPanels.contains(sourcePanel) || visiblePreviewInspectors.contains(sourcePanel))) { + setInspectorLocation(previewInspector, sourcePanel) + } + } +} + +def findSourcePanelForInspector(JPanel inspector) { + // این متد باید پنل منبع مربوط به این بازرس را پیدا کند + for (panel in activeSiblingPreviewPanels + visiblePreviewInspectors) { + if (panel != inspector) { + return panel + } + } + return null +} + +def updateAllPanelsAfterScroll() { + // به روزرسانی پنل‌های Siblings Preview + if (showInPlaceSiblingsPreview) { + refreshSiblingPreviewPanels() + } + + // به روزرسانی پنل‌های بازرس + if (inspectorUpdateSelection) { + smartCreateInspectors(currentlySelectedNode) + } + + // فعال کردن اسکرول‌بارها + updateScrollBars() + + // به روزرسانی اتصالات + ensureOverlayExistsAndRepaint() + + parentPanel.revalidate() + parentPanel.repaint() +} + +def updateScrollBars() { + // اطمینان از فعال بودن اسکرول‌بارهای مورد نیاز + panelsInMasterPanels.each { panel -> + JScrollPane scrollPane = findScrollPaneInPanel(panel) + if (scrollPane) { + updateScrollBarVisibility(scrollPane) + } + } + + activeSiblingPreviewPanels.each { previewPanel -> + JScrollPane scrollPane = findScrollPaneInPanel(previewPanel) + if (scrollPane) { + updateScrollBarVisibility(scrollPane) + } + } + + visiblePreviewInspectors.each { inspector -> + JScrollPane scrollPane = findScrollPaneInPanel(inspector) + if (scrollPane) { + updateScrollBarVisibility(scrollPane) + } + } +} + +def findScrollPaneInPanel(JPanel panel) { + for (Component comp : panel.getComponents()) { + if (comp instanceof JScrollPane) { + return (JScrollPane) comp + } + } + return null +} + +def updateScrollBarVisibility(JScrollPane scrollPane) { + // این منطق را بر اساس نیاز خود برای نمایش/مخفی کردن اسکرول‌بارها تطبیق دهید + Component view = scrollPane.getViewport().getView() + if (view instanceof JList) { + JList list = (JList) view + boolean needsVerticalScroll = list.getPreferredSize().height > scrollPane.getViewport().getHeight() + boolean needsHorizontalScroll = list.getPreferredSize().width > scrollPane.getViewport().getWidth() + + scrollPane.setVerticalScrollBarPolicy(needsVerticalScroll ? + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED : JScrollPane.VERTICAL_SCROLLBAR_NEVER) + scrollPane.setHorizontalScrollBarPolicy(needsHorizontalScroll ? + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED : JScrollPane.HORIZONTAL_SCROLLBAR_NEVER) + } +} loadSettings() createPanels() @@ -673,162 +830,6 @@ def boolean checkIfUtilityPanelsIsAlreadyRunning() { } } -// ==================== متدهای جدید برای مدیریت اسکرول ==================== - -def addScrollListener() { - def mapView = Controller.currentController.MapViewManager.mapView - def viewport = mapView.parent - - if (viewport instanceof JViewport) { - viewport.addChangeListener(new ChangeListener() { - @Override - void stateChanged(ChangeEvent e) { - // هنگام اسکرول، پنل‌ها را همراه با نقشه حرکت دهید - movePanelsWithMap() - - // تایمر برای به‌روزرسانی پس از پایان اسکرول - restartScrollCompletionTimer() - } - }) - } -} - -def movePanelsWithMap() { - def mapView = Controller.currentController.MapViewManager.mapView - def viewport = mapView.parent as JViewport - - if (!viewport) return - - Rectangle viewRect = viewport.getViewRect() - - // حرکت دادن breadcrumbPanel - if (breadcrumbPanel?.isVisible()) { - breadcrumbPanel.setLocation(0, 0) - breadcrumbPanel.setSize(viewport.width, breadcrumbPanel.height) - } - - // حرکت دادن masterPanel - if (masterPanel?.isVisible()) { - int masterPanelWidth = calculateRetractedWidthForMasterPanel() - if (isMasterPanelExpanded) { - masterPanelWidth = calculateExpandedWidthForMasterPanel() - } - - masterPanel.setLocation(0, breadcrumbPanel?.height ?: 0) - masterPanel.setSize(masterPanelWidth, viewport.height - (breadcrumbPanel?.height ?: 0)) - } - - // حرکت دادن inspector پنل‌ها - visibleInspectors.each { inspector -> - if (inspector.isVisible()) { - updateInspectorPositionDuringScroll(inspector) - } - } - - // حرکت دادن preview پنل‌ها - visiblePreviewInspectors.each { preview -> - if (preview.isVisible()) { - updatePreviewPositionDuringScroll(preview) - } - } - - // حرکت دادن sibling preview پنل‌ها - activeSiblingPreviewPanels.each { siblingPanel -> - if (siblingPanel.isVisible()) { - updateSiblingPreviewPositionDuringScroll(siblingPanel) - } - } - - // به‌روزرسانی خطوط اتصال - ensureOverlayExistsAndRepaint() -} - -def updateInspectorPositionDuringScroll(JPanel inspector) { - def sourcePanel = findSourcePanelForInspector(inspector) - if (sourcePanel) { - setInspectorLocation(inspector, sourcePanel) - } -} - -def updatePreviewPositionDuringScroll(JPanel preview) { - def sourcePanel = findSourcePanelForInspector(preview) - if (sourcePanel) { - setInspectorLocation(preview, sourcePanel) - } -} - -def updateSiblingPreviewPositionDuringScroll(JPanel siblingPanel) { - NodeModel referenceNode = siblingPanel.getClientProperty("referenceNode") - boolean positionAtBottom = siblingPanel.getClientProperty("positionAtBottom") ?: false - - if (referenceNode) { - def mapView = Controller.currentController.MapViewManager.mapView - def viewport = mapView.parent as JViewport - - NodeView nodeView = mapView.getNodeView(referenceNode) - if (nodeView) { - Point nodePoint = mapView.getNodeContentLocation(nodeView) - Point screenPoint = SwingUtilities.convertPoint(mapView, nodePoint, viewport) - - int referenceX = screenPoint.x - int referenceY = screenPoint.y - - // محاسبه موقعیت جدید - if (!positionAtBottom) { - siblingPanel.setLocation(referenceX, (referenceY - siblingPanel.height) as int) - } else { - siblingPanel.setLocation(referenceX, (referenceY + nodeView.contentPane.height) as int) - } - } - } -} - -def updatePanelsAfterScroll() { - // به‌روزرسانی وضعیت پنل‌ها بر اساس موقعیت جدید - if (inspectorUpdateSelection) { - smartCreateInspectors(currentlySelectedNode) - } - - // به‌روزرسانی پنل‌های پیش‌نمایش siblings - if (showInPlaceSiblingsPreview) { - refreshSiblingPreviewPanels() - } else { - activeSiblingPreviewPanels.each { it.setVisible(false) } - activeSiblingPreviewPanels.clear() - } - - // به‌روزرسانی breadcrumb - updateBreadcrumbPanel() - - // اعتبارسنجی و ترسیم مجدد - parentPanel.revalidate() - parentPanel.repaint() -} - -def restartScrollCompletionTimer() { - scrollCompletionTimer.stop() - scrollCompletionTimer.start() -} - -def findSourcePanelForInspector(JPanel inspector) { - // این متد پنل منبع اینسپکتور را پیدا می‌کند - if (visibleInspectors.contains(inspector)) { - int index = visibleInspectors.indexOf(inspector) - if (index == 0) return masterPanel - if (index > 0) return visibleInspectors[index - 1] - } - - if (visiblePreviewInspectors.contains(inspector)) { - int index = visiblePreviewInspectors.indexOf(inspector) - if (index == 0) return currentSourcePanel - if (index > 0) return visiblePreviewInspectors[index - 1] - } - - return masterPanel -} - -// ==================== پایان متدهای جدید برای مدیریت اسکرول ==================== - public void manageInspectorsCreation() { if (shouldFreeze()) return; @@ -1063,7 +1064,8 @@ private Rectangle getInspectorReservedArea() { def createPanels() { setupParentPanel() - + createScrollListener() + recentSelectedNodesPanel = createRecentNodesPanel() pinnedItemsPanel = createPinnedItemsPanel() tagsPanel = createTagsPanel() @@ -1075,9 +1077,6 @@ def createPanels() { assembleMasterPanel(breadcrumbPanel, quickSearchPanel, recentSelectedNodesPanel, pinnedItemsPanel, stylesPanel, tagsPanel, innerPanelInQuickSearchPanel) } - // افزودن Listener اسکرول - addScrollListener() - parentPanel.revalidate() parentPanel.repaint() } @@ -3820,11 +3819,10 @@ def cleanAndCreateInspectors(NodeModel nodeNotProxy, JPanel somePanel, String du dummyPanel = "no" break } + visibleInspectors.each { - it.setVisible(false) + it.setVisible(false) } - - visibleInspectors visibleInspectors.clear() JPanel subInspectorPanel if (dummyPanel == "siblings") { @@ -4583,10 +4581,8 @@ def createComponentChangeListener() { mapView1 = Controller.currentController.MapViewManager.mapView if (mapView1.componentListeners.any { it.getClass().getName().startsWith("UtilityPanels") }) return - mapView1.addComponentListener(new ComponentAdapter() { public void componentMoved(ComponentEvent e) { - ensureOverlayExistsAndRepaint() if(!showPanels) { @@ -4598,10 +4594,15 @@ def createComponentChangeListener() { nv3 = mapView1.getNodeView(currentlySelectedNode) if (Boolean.TRUE.equals(nv3.getMainView().getClientProperty(INLINE_EDITOR_ACTIVE))) { return - } - if (showInPlaceSiblingsPreview) refreshSiblingPreviewPanels() + if (showInPlaceSiblingsPreview) { + if (isScrolling) { + moveSiblingPreviewPanelsWithMap() // حرکت دادن پنل‌ها بدون ایجاد جدید + } else { + refreshSiblingPreviewPanels() // ایجاد پنل‌های جدید + } + } else if (activeSiblingPreviewPanels.size() != 0) { activeSiblingPreviewPanels.each { it.setVisible(false) @@ -5054,9 +5055,14 @@ def static getUserDefinedStylesParentNode(MapModel mapa, ScriptContext scriptCon return userDefinedParentNode } - def refreshSiblingPreviewPanels() { - + // اگر در حال اسکرول هستیم، فقط موقعیت پنل‌های موجود را به روز کنیم + if (isScrolling) { + moveSiblingPreviewPanelsWithMap() + return + } + + // غیر این صورت، منطق عادی ایجاد/حذف پنل‌ها activeSiblingPreviewPanels.each { it.visible = false parentPanel.remove(it) @@ -5087,12 +5093,10 @@ def refreshSiblingPreviewPanels() { referenceNodeScreenX = selectedPointOnScreen.x referenceNodeScreenY = selectedPointOnScreen.y - // if(referenceNodeScreenX < 0 || referenceNodeScreenX > viewport.getViewRect().width) return if(testedNode.parent.children.size() == 1) return - def parentNode = testedNode.parent def siblings = parentNode.children int selectedIndex = siblings.indexOf(testedNode) @@ -5102,7 +5106,6 @@ def refreshSiblingPreviewPanels() { NodeModel offScreenSiblingAbove = null - if(selectedIndex > 0 && !isNodeVisibleInViewport(siblings[selectedIndex - 1].delegate)) offScreenSiblingAbove = siblings[selectedIndex - 1].delegate if (offScreenSiblingAbove != null) { @@ -5113,7 +5116,6 @@ def refreshSiblingPreviewPanels() { offScreenSiblingAboveXPoint = offScreenSiblingAboveSelectedPointOnScreen.x offScreenSiblingAboveYPoint = offScreenSiblingAboveSelectedPointOnScreen.y - if (referenceNodeScreenY >= 0 && offScreenSiblingAboveYPoint <= 0 && referenceNodeScreenX > 0 && referenceNodeScreenX < viewport.getWidth()) { siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode.delegate, false, referenceNodeScreenX as int, referenceNodeScreenY as int) @@ -5122,16 +5124,13 @@ def refreshSiblingPreviewPanels() { } - } else { } - NodeModel offScreenSiblingBelow = null if(selectedIndex + 1 < siblings.size() && !isNodeVisibleInViewport(siblings[selectedIndex + 1].delegate)) offScreenSiblingBelow = siblings[selectedIndex + 1].delegate - if (offScreenSiblingBelow != null) { NodeView offScreenSiblingBelowNodeView = mapView.getNodeView(offScreenSiblingBelow) @@ -5140,7 +5139,6 @@ def refreshSiblingPreviewPanels() { offScreenSiblingBelowXPoint = offScreenSiblingBelowSelectedPointOnScreen.x offScreenSiblingBelowYPoint = offScreenSiblingBelowSelectedPointOnScreen.y - if (referenceNodeScreenY < viewport.getHeight() && offScreenSiblingBelowYPoint >= viewport.getHeight() && referenceNodeScreenX > 0 && referenceNodeScreenX < viewport.getWidth()) { siblingsPreviewPanelCreated = createSiblingPreviewPanel(testedNode.delegate, true, referenceNodeScreenX as int, referenceNodeScreenY as int) @@ -5149,7 +5147,6 @@ def refreshSiblingPreviewPanels() { } - } else { } } @@ -5161,7 +5158,6 @@ public void createSingleRunListeners() { public void afterViewChange(final Component oldView, final Component newView) { if (newView == null) { return - addScrollListener() } searchText = "" From e24ab159c6fc0a76cfd8dab572756708768220cb Mon Sep 17 00:00:00 2001 From: A <38586259+aaa1386@users.noreply.github.com> Date: Tue, 21 Oct 2025 09:58:05 +0330 Subject: [PATCH 09/14] =?UTF-8?q?=D8=A7=D8=B6=D8=A7=D9=81=D9=87=20=DA=A9?= =?UTF-8?q?=D8=B1=D8=AF=D9=86=20=DA=AF=D8=B2=DB=8C=D9=86=D9=87=20Fast=20Sc?= =?UTF-8?q?roll=20To=20Center?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utilityPanels.groovy | 52 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/utilityPanels.groovy b/utilityPanels.groovy index 51ced0a..76de4b5 100644 --- a/utilityPanels.groovy +++ b/utilityPanels.groovy @@ -396,6 +396,8 @@ showAncestorsOnFirstInspector = false @groovy.transform.Field showInspectorsOnSiblingsPreviewHover = true +@groovy.transform.Field boolean fastScrollToCenter = true + //↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ User settings ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ @@ -2944,13 +2946,52 @@ void configureListSelection(JList list) { flagFreezeInspectorsWasOn = freezeInspectors if(!flagFreezeInspectorsWasOn) freezeInspectors = true currentlySelectedNode = selectedItemNode + + // ★★★ ابتدا همه پنل‌های بازرس را پاک کن ★★★ + hideAllInspectorPanels() + + // سپس گره را انتخاب کن Controller.currentController.mapViewManager.mapView.getMapSelection().selectAsTheOnlyOneSelected(selectedItemNode) + + // ★★★ در نهایت اسکرول کن ★★★ + if (fastScrollToCenter) { + Controller.currentController.mapViewManager.mapView.getMapSelection().scrollNodeToCenter(selectedItemNode, false) + } + freezeInspectors = flagFreezeInspectorsWasOn } } } as ListSelectionListener) } +// ★★★ قدم ۲: اضافه کردن این متد جدید ★★★ +def hideAllInspectorPanels() { + // پاک کردن پنل‌های بازرس پیش‌نمایش + visiblePreviewInspectors.each { + it.setVisible(false) + parentPanel.remove(it) + } + visiblePreviewInspectors.clear() + + // پاک کردن پنل‌های بازرس معمولی (اگر freeze فعال نباشد) + if (!freezeInspectors) { + visibleInspectors.each { + if (it != visibleInspectors[0] && it != visibleInspectors[1]) { + it.setVisible(false) + parentPanel.remove(it) + } + } + visibleInspectors.removeAll { it != visibleInspectors[0] && it != visibleInspectors[1] } + } + + // ریتکت کردن پنل اصلی + retractMasterPanel() + + // به‌روزرسانی رابط + parentPanel.revalidate() + parentPanel.repaint() +} + void configureListContextMenu(JList list) { list.addMouseListener(new MouseAdapter() { @Override @@ -3605,7 +3646,8 @@ def saveSettings() { keyStrokeToShowPanels: keyStrokeToShowPanels.toString(), hideInspectorsEvenIfUpdateSelection: hideInspectorsEvenIfUpdateSelection, showInPlaceSiblingsPreview: showInPlaceSiblingsPreview, - showInspectorsOnSiblingsPreviewHover: showInspectorsOnSiblingsPreviewHover + showInspectorsOnSiblingsPreviewHover: showInspectorsOnSiblingsPreviewHover, + fastScrollToCenter: fastScrollToCenter ] ]).toPrettyString() @@ -3685,6 +3727,7 @@ private void loadSettings() { hideInspectorsEvenIfUpdateSelection = settings.userSettings.hideInspectorsEvenIfUpdateSelection ?: hideInspectorsEvenIfUpdateSelection showInPlaceSiblingsPreview = settings.userSettings.showInPlaceSiblingsPreview ?: showInPlaceSiblingsPreview showInspectorsOnSiblingsPreviewHover = settings.userSettings.showInspectorsOnSiblingsPreviewHover ?: showInspectorsOnSiblingsPreviewHover + fastScrollToCenter = settings.userSettings.fastScrollToCenter != null ? settings.userSettings.fastScrollToCenter : true } } catch (Exception e) { @@ -4375,6 +4418,12 @@ def showSettingsDialog() { JCheckBox hideInspectorsCheck = new JCheckBox("", hideInspectorsEvenIfUpdateSelection) settingsPanel.add(hideInspectorsCheck) + // ★★★ قدم ۵: اضافه کردن این بخش ★★★ + settingsPanel.add(new JLabel("Fast Scroll to Center:")) + JCheckBox fastScrollCheck = new JCheckBox("", fastScrollToCenter) + fastScrollCheck.setToolTipText("When enabled, nodes will scroll to center quickly when clicked in panels") + settingsPanel.add(fastScrollCheck) + settingsDialog.add(new JScrollPane(settingsPanel), BorderLayout.CENTER) JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)) @@ -4404,6 +4453,7 @@ def showSettingsDialog() { keyStrokeToShowPanels = KeyStroke.getKeyStroke(showPanelsHotkeyField.getText()) } catch(Exception ex) {} hideInspectorsEvenIfUpdateSelection = hideInspectorsCheck.isSelected() + fastScrollToCenter = fastScrollCheck.isSelected() saveSettings() reloadPanels() From 015e2475b184f53b7287cfa07bbd179b6bdff3ff Mon Sep 17 00:00:00 2001 From: A <38586259+aaa1386@users.noreply.github.com> Date: Thu, 23 Oct 2025 00:55:33 +0330 Subject: [PATCH 10/14] Right-to-left or vice versa support (right-to-left all panels and text direction) The "Rtl Orientation" option moves all panels to the right. --- utilityPanels.groovy | 72 ++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 42 deletions(-) diff --git a/utilityPanels.groovy b/utilityPanels.groovy index 76de4b5..5577c5b 100644 --- a/utilityPanels.groovy +++ b/utilityPanels.groovy @@ -386,7 +386,7 @@ widthOfTheClearButtonOnQuickSearchPanel = 30 showAncestorsOnFirstInspector = false -@groovy.transform.Field rtlOrientation = false +@groovy.transform.Field rtlOrientation = true @groovy.transform.Field KeyStroke keyStrokeToShowPanels = KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK) @@ -906,20 +906,26 @@ public void createSubInspector(NodeModel hoveredNode, int index, NodeModel subNo public void updateSubInspectorsLocation(JPanel subInspectorPanel) { if (visiblePreviewInspectors.contains(currentSourcePanel)) { visiblePreviewInspectors.add(subInspectorPanel) - locationOfTheInspectorOfTheCurrentPanelUnderMouse = subInspectorPanel.getLocation().x - visiblePreviewInspectors.clone().each { - if (it != subInspectorPanel && it.getLocation().x >= locationOfTheInspectorOfTheCurrentPanelUnderMouse) { - it.setVisible(false) - visiblePreviewInspectors.remove(it) + + // فقط پنل‌هایی که بعد از پنل منبع هستند رو پنهان کن + int sourceIndex = visiblePreviewInspectors.indexOf(currentSourcePanel) + for (int i = visiblePreviewInspectors.size() - 1; i > sourceIndex; i--) { + JPanel panel = visiblePreviewInspectors.get(i) + if (panel != subInspectorPanel) { + panel.setVisible(false) + visiblePreviewInspectors.remove(i) } } } else { visibleInspectors.add(subInspectorPanel) - locationOfTheInspectorOfTheCurrentPanelUnderMouse = subInspectorPanel.getLocation().x - visibleInspectors.clone().each { - if (it != subInspectorPanel && it.getLocation().x >= locationOfTheInspectorOfTheCurrentPanelUnderMouse) { - it.setVisible(false) - visibleInspectors.remove(it) + + // فقط پنل‌هایی که بعد از پنل منبع هستند رو پنهان کن + int sourceIndex = visibleInspectors.indexOf(currentSourcePanel) + for (int i = visibleInspectors.size() - 1; i > sourceIndex; i--) { + JPanel panel = visibleInspectors.get(i) + if (panel != subInspectorPanel) { + panel.setVisible(false) + visibleInspectors.remove(i) } } } @@ -1150,7 +1156,10 @@ public void basicMasterPanelConfigs(JPanel masterPanel, JPanel breadcrumbPanel) masterPanel.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT) } masterPanel.addMouseListener(sharedMouseListener) - masterPanel.setBounds(0, breadcrumbPanel.height, calculateRetractedWidthForMasterPanel(), (int) mapViewWindowForSizeReferences.height - 5) + + // تغییر این خط - پنل اصلی در سمت راست + int xPosition = rtlOrientation ? parentPanel.width - calculateRetractedWidthForMasterPanel() : 0 + masterPanel.setBounds(xPosition, breadcrumbPanel.height, calculateRetractedWidthForMasterPanel(), (int) mapViewWindowForSizeReferences.height - 5) } public JPanel createStylesPanel() { @@ -1279,15 +1288,16 @@ public JPanel createAndAttachBreadcrumbsPanels() { super.paintComponent(g) } } - breadcrumbPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 8, 5)) -// breadcrumbPanel.setLayout(new FlowLayout(rtlOrientation ? FlowLayout.RIGHT : FlowLayout.LEFT, 8, 5)) + + // تغییر این خط - از LEFT به RIGHT برای راست‌چین + breadcrumbPanel.setLayout(new FlowLayout(rtlOrientation ? FlowLayout.RIGHT : FlowLayout.LEFT, 8, 5)) + breadcrumbPanel.setBackground(new Color(0, 0, 0, 0)) -// breadcrumbPanel.setBackground(new Color(220, 220, 220)) breadcrumbPanel.setOpaque(false) breadcrumbPanel.setBounds(0, 0, parentPanel.width, 40) - + // تغییر جهت کامپوننت if (rtlOrientation) { breadcrumbPanel.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT) } else { @@ -1305,15 +1315,8 @@ public JPanel createAndAttachBreadcrumbsPanels() { } } -// 20.times { -// ancestorsOfCurrentNode.addElement(currentlySelectedNode) -// } - createBreadcrumbsJList() -// listeners2 = ancestorsOfCurrentNode.getListDataListeners() -// listeners2.each { ancestorsOfCurrentNode.removeListDataListener(it) } - parentPanel.add(breadcrumbPanel) parentPanel.setComponentZOrder(breadcrumbPanel, 0) breadcrumbPanel @@ -3755,7 +3758,7 @@ def int calculateInspectorWidth(int ammountOfPannelsInInspector) { } def setInspectorLocation(JPanel inspectorPanel, JPanel sourcePanel) { - int x = sourcePanel.getLocation().x + sourcePanel.width + int x = rtlOrientation ? sourcePanel.getLocation().x - inspectorPanel.width : sourcePanel.getLocation().x + sourcePanel.width int y = sourcePanel.getLocation().y if(panelsInMasterPanels.contains(sourcePanel)) { @@ -3787,7 +3790,6 @@ def setInspectorLocation(JPanel inspectorPanel, JPanel sourcePanel) { inspectorPanel.setLocation(x, y) } - def containsTermInAncestors(NodeModel node, String term) { node = node.parent while (node != null) { @@ -4104,17 +4106,6 @@ def JList createJList(DefaultListModel nodes, JPanel jListPanel, JPan } def createBreadcrumbsJList() { -// breadcrumbPanel.removeAll() -// if (!ancestorsOfCurrentNode || ancestorsOfCurrentNode.isEmpty()) { -// breadcrumbPanel.revalidate() -// breadcrumbPanel.repaint() -// return -// } - -// DefaultListModel listModel = new DefaultListModel<>() -// ancestorsOfCurrentNode.each { listModel.addElement(it) } - -// JList jList = new JList<>(ancestorsOfCurrentNode) ancestorsJList.setModel(ancestorsOfCurrentNode) ancestorsJList.setLayoutOrientation(JList.HORIZONTAL_WRAP) ancestorsJList.setVisibleRowCount(1) @@ -4124,22 +4115,19 @@ def createBreadcrumbsJList() { commonJListsConfigs(ancestorsJList, ancestorsOfCurrentNode, breadcrumbPanel) + // تغییر جهت برای راست‌چین if (rtlOrientation) { ancestorsJList.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT) } else { ancestorsJList.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT) } - breadcrumbPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 8, 5)) -// breadcrumbPanel.setLayout(new FlowLayout(rtlOrientation ? FlowLayout.RIGHT : FlowLayout.LEFT, 8, 5)) // RTL Support - breadcrumbPanel.add(ancestorsJList) -// breadcrumbPanel.revalidate() -// breadcrumbPanel.repaint() + // breadcrumbPanel.revalidate() + // breadcrumbPanel.repaint() } - def populateTagsListModel(JList tagsJList) { tagsJList.setModel(listModelForAllTags) From 4216e2b4e5af0188b13ba7c1fc4f0407ed98a46c Mon Sep 17 00:00:00 2001 From: A <38586259+aaa1386@users.noreply.github.com> Date: Thu, 23 Oct 2025 08:20:45 +0330 Subject: [PATCH 11/14] Remove items that are not needed. --- utilityPanels.groovy | 77 +------------------------------------------- 1 file changed, 1 insertion(+), 76 deletions(-) diff --git a/utilityPanels.groovy b/utilityPanels.groovy index 5577c5b..84d2c09 100644 --- a/utilityPanels.groovy +++ b/utilityPanels.groovy @@ -2695,56 +2695,6 @@ JPanel createSiblingPreviewPanel(NodeModel nodeNotProxy, boolean positionAtBotto -void hideInspectorPanelIfNeeded() { - if (shouldFreeze()) return - if (mouseOverList) return - - visiblePreviewInspectors.each { - it.setVisible(false) - parentPanel.remove(it) - } - - visiblePreviewInspectors.clear() - - visibleInspectors.each{ - if(!inspectorUpdateSelection) { - it.setVisible(false) - } - else{ - if(it != visibleInspectors[0] && it != visibleInspectors[1]) { - it.setVisible(false) - } - } - } - - if(!inspectorUpdateSelection) { - visibleInspectors.clear() - } - else { - visibleInspectors.removeAll { it != visibleInspectors[0] && it != visibleInspectors[1]} - if(visibleInspectors.size() != 0) { - setInspectorLocation(visibleInspectors[0], masterPanel) - if(visibleInspectors.size() > 1) { - setInspectorLocation(visibleInspectors[1], visibleInspectors[0]) - } - } - } -// -// if(inspectorUpdateSelection && visibleInspectors.size() > 0) { -// visibleInspectors[0].setVisible(true) -// if(visibleInspectors.size() > 1) { -// visibleInspectors[1].setVisible(true) -// } -// } - - retractMasterPanel() - - - - - return - -} void configureLabelForNode(JComponent component, NodeModel nodeNotProxy, JPanel sourcePanel, int indexOfNode = 0) { Color backgroundColor = NodeStyleController.getController().getBackgroundColor(nodeNotProxy, StyleOption.FOR_UNSELECTED_NODE) @@ -4248,32 +4198,7 @@ def clearQuickSearch() { Controller.getCurrentController().getMapViewManager().getMapViewComponent().repaint() } -def togglePanelsVisibility() { - boolean visible = masterPanel.isVisible() - if (visible) { -// inspectorUpdateSelection = false - masterPanel.setVisible(false) - breadcrumbPanel.setVisible(false) - visibleInspectors.each { it.setVisible(false) } -// visibleInspectors.clear() - visiblePreviewInspectors.each { it.setVisible(false) } -// visiblePreviewInspectors.clear() - clearQuickSearch() - showPanels = false - cleanPreviousScriptExecution() - } else { -// inspectorUpdateSelection = true - startListeners() - loadHistoryWithFPHistory() - currentlySelectedNode = ScriptUtils.node().delegate - showPanels = true - masterPanel.setVisible(true) - breadcrumbPanel.setVisible(true) - visibleInspectors.each { it.setVisible(true) } - } - parentPanel.revalidate() - parentPanel.repaint() -} + def shouldShowInspectors() { // return (showOnlyBreadcrumbs || (!showPanels && hideInspectorsEvenIfUpdateSelection)) From 8c9a48bfb25e3a7edc350d3fbb681f107b595775 Mon Sep 17 00:00:00 2001 From: A <38586259+aaa1386@users.noreply.github.com> Date: Thu, 23 Oct 2025 20:05:27 +0330 Subject: [PATCH 12/14] =?UTF-8?q?=D8=A8=D8=A7=D8=B2=DA=AF=D8=B1=D8=AF?= =?UTF-8?q?=D8=A7=D9=86=D8=AF=D8=A7=D9=86=20=D9=85=D8=AE=D9=81=DB=8C=20?= =?UTF-8?q?=D8=B4=D8=AF=D9=86=20=D9=BE=D9=86=D9=84=20=D9=87=D8=A7=DB=8C=20?= =?UTF-8?q?=D8=A8=D8=A7=D8=B2=D8=B1=D8=B3=20=20=D8=B3=D9=84=D8=B3=D9=84?= =?UTF-8?q?=D9=87=20=D8=A7=D8=AC=D8=AF=D8=A7=D8=AF=20=D9=87=D9=86=DA=AF?= =?UTF-8?q?=D8=A7=D9=85=20=D8=A7=D9=86=D8=AA=D8=AE=D8=A7=D8=A8=20=DA=AF?= =?UTF-8?q?=D8=B1=D9=87=20=DB=8C=D8=A7=20=D8=A2=D9=85=D8=AF=D9=86=20=D9=85?= =?UTF-8?q?=D9=88=D8=B3=20=D8=A8=D9=87=20=D9=85=D8=AD=DB=8C=D8=B7=20=D8=A7?= =?UTF-8?q?=D8=B5=D9=84=DB=8C=20=D9=86=D9=82=D8=B4=D9=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utilityPanels.groovy | 77 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/utilityPanels.groovy b/utilityPanels.groovy index 84d2c09..5577c5b 100644 --- a/utilityPanels.groovy +++ b/utilityPanels.groovy @@ -2695,6 +2695,56 @@ JPanel createSiblingPreviewPanel(NodeModel nodeNotProxy, boolean positionAtBotto +void hideInspectorPanelIfNeeded() { + if (shouldFreeze()) return + if (mouseOverList) return + + visiblePreviewInspectors.each { + it.setVisible(false) + parentPanel.remove(it) + } + + visiblePreviewInspectors.clear() + + visibleInspectors.each{ + if(!inspectorUpdateSelection) { + it.setVisible(false) + } + else{ + if(it != visibleInspectors[0] && it != visibleInspectors[1]) { + it.setVisible(false) + } + } + } + + if(!inspectorUpdateSelection) { + visibleInspectors.clear() + } + else { + visibleInspectors.removeAll { it != visibleInspectors[0] && it != visibleInspectors[1]} + if(visibleInspectors.size() != 0) { + setInspectorLocation(visibleInspectors[0], masterPanel) + if(visibleInspectors.size() > 1) { + setInspectorLocation(visibleInspectors[1], visibleInspectors[0]) + } + } + } +// +// if(inspectorUpdateSelection && visibleInspectors.size() > 0) { +// visibleInspectors[0].setVisible(true) +// if(visibleInspectors.size() > 1) { +// visibleInspectors[1].setVisible(true) +// } +// } + + retractMasterPanel() + + + + + return + +} void configureLabelForNode(JComponent component, NodeModel nodeNotProxy, JPanel sourcePanel, int indexOfNode = 0) { Color backgroundColor = NodeStyleController.getController().getBackgroundColor(nodeNotProxy, StyleOption.FOR_UNSELECTED_NODE) @@ -4198,7 +4248,32 @@ def clearQuickSearch() { Controller.getCurrentController().getMapViewManager().getMapViewComponent().repaint() } - +def togglePanelsVisibility() { + boolean visible = masterPanel.isVisible() + if (visible) { +// inspectorUpdateSelection = false + masterPanel.setVisible(false) + breadcrumbPanel.setVisible(false) + visibleInspectors.each { it.setVisible(false) } +// visibleInspectors.clear() + visiblePreviewInspectors.each { it.setVisible(false) } +// visiblePreviewInspectors.clear() + clearQuickSearch() + showPanels = false + cleanPreviousScriptExecution() + } else { +// inspectorUpdateSelection = true + startListeners() + loadHistoryWithFPHistory() + currentlySelectedNode = ScriptUtils.node().delegate + showPanels = true + masterPanel.setVisible(true) + breadcrumbPanel.setVisible(true) + visibleInspectors.each { it.setVisible(true) } + } + parentPanel.revalidate() + parentPanel.repaint() +} def shouldShowInspectors() { // return (showOnlyBreadcrumbs || (!showPanels && hideInspectorsEvenIfUpdateSelection)) From bf5af33cf079494c5602b7543067afa1eab8ab88 Mon Sep 17 00:00:00 2001 From: A <38586259+aaa1386@users.noreply.github.com> Date: Fri, 24 Oct 2025 22:01:06 +0330 Subject: [PATCH 13/14] =?UTF-8?q?=D8=B9=D9=85=D9=84=DA=A9=D8=B1=D8=AF=20?= =?UTF-8?q?=D8=B6=D8=B1=DB=8C=D8=A8=20=D9=BE=D9=86=D9=84=20=D9=87=D8=A7?= =?UTF-8?q?=DB=8C=20=D8=A7=D8=B5=D9=84=DB=8C=20=D8=AF=D8=B1=20=DA=86=D9=86?= =?UTF-8?q?=D8=AF=20=20=D8=A8=D8=B1=D8=A7=D8=A8=D8=B1=20=D8=B4=D8=AF=D9=86?= =?UTF-8?q?=20=D8=A8=D8=A7=20=D9=88=D8=B1=D9=88=D8=AF=20=D9=85=D9=88=D8=B3?= =?UTF-8?q?=20=20=D8=A8=D9=87=20=D9=86=D8=A7=D8=AD=DB=8C=D9=87=20=D9=BE?= =?UTF-8?q?=D9=86=D9=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utilityPanels.groovy | 76 +++++++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/utilityPanels.groovy b/utilityPanels.groovy index 5577c5b..7af35a4 100644 --- a/utilityPanels.groovy +++ b/utilityPanels.groovy @@ -1158,8 +1158,12 @@ public void basicMasterPanelConfigs(JPanel masterPanel, JPanel breadcrumbPanel) masterPanel.addMouseListener(sharedMouseListener) // تغییر این خط - پنل اصلی در سمت راست - int xPosition = rtlOrientation ? parentPanel.width - calculateRetractedWidthForMasterPanel() : 0 - masterPanel.setBounds(xPosition, breadcrumbPanel.height, calculateRetractedWidthForMasterPanel(), (int) mapViewWindowForSizeReferences.height - 5) + int retractedWidth = calculateRetractedWidthForMasterPanel() + int xPosition = rtlOrientation ? parentPanel.width - retractedWidth : 0 + + masterPanel.setBounds(xPosition, breadcrumbPanel.height, retractedWidth, (int) mapViewWindowForSizeReferences.height - 5) + + println "Master Panel Initial Position: x=${xPosition}, width=${retractedWidth}, RTL=${rtlOrientation}" } public JPanel createStylesPanel() { @@ -3758,36 +3762,30 @@ def int calculateInspectorWidth(int ammountOfPannelsInInspector) { } def setInspectorLocation(JPanel inspectorPanel, JPanel sourcePanel) { - int x = rtlOrientation ? sourcePanel.getLocation().x - inspectorPanel.width : sourcePanel.getLocation().x + sourcePanel.width + int x, y + + if (rtlOrientation) { + // در حالت RTL: بازرس در سمت چپ پنل منبع قرار می‌گیرد + x = sourcePanel.getLocation().x - inspectorPanel.width + println "RTL Inspector Location: sourceX=${sourcePanel.getLocation().x}, inspectorWidth=${inspectorPanel.width}, finalX=${x}" + } else { + // در حالت LTR: بازرس در سمت راست پنل منبع قرار می‌گیرد + x = sourcePanel.getLocation().x + sourcePanel.width + println "LTR Inspector Location: sourceX=${sourcePanel.getLocation().x}, sourceWidth=${sourcePanel.width}, finalX=${x}" + } - int y = sourcePanel.getLocation().y + y = sourcePanel.getLocation().y if(panelsInMasterPanels.contains(sourcePanel)) { y = masterPanel.getLocation().y } if(activeSiblingPreviewPanels.contains(sourcePanel) || visiblePreviewInspectors.contains(sourcePanel)) { -// if(activeSiblingPreviewPanels.contains(sourcePanel) && !sourcePanel.getClientProperty("positionAtBottom")) { -// y = sourcePanel.getLocation().y -// } -// else if(activeSiblingPreviewPanels.contains(sourcePanel) && sourcePanel.getClientProperty("positionAtBottom")) { viewportHeight = parentPanel.height -// y = (viewportHeight - inspectorPanel.height) as int -// } - - - -// y = sourcePanel.getLocation().y as int y = Math.min(sourcePanel.getLocation().y, (viewportHeight - inspectorPanel.height) as int) - -// Point sourcePanelLocation = new Point(sourcePanel.getLocation().x as int, sourcePanel.getLocation().y as int) -// UITools.convertPointToAncestor(sourcePanel.parent, sourcePanelLocation, parentPanel) -// sourcepanelY = sourcePanelLocation.y - -// y = (viewportHeight - (inspectorPanel.height - (viewportHeight - sourcepanelY))) as int - } inspectorPanel.setLocation(x, y) + println "Final Inspector Position: x=${x}, y=${y}" } def containsTermInAncestors(NodeModel node, String term) { @@ -3930,7 +3928,23 @@ public class RoundedCornerBorder implements Border { def expandMasterPanel() { bounds = masterPanel.getBounds() - bounds.width = calculateExpandedWidthForMasterPanel() + + if (rtlOrientation) { + // در حالت RTL: پنل به سمت چپ گسترش می‌یابد + int expandedWidth = calculateExpandedWidthForMasterPanel() + int widthDifference = expandedWidth - bounds.width + + // موقعیت X را به اندازه اختلاف عرض به چپ منتقل کن + bounds.x = bounds.x - widthDifference + bounds.width = expandedWidth + + println "RTL Expansion: x=${bounds.x}, width=${bounds.width}, difference=${widthDifference}" + } else { + // در حالت LTR: رفتار قبلی (گسترش به راست) + bounds.width = calculateExpandedWidthForMasterPanel() + println "LTR Expansion: x=${bounds.x}, width=${bounds.width}" + } + masterPanel.setBounds(bounds) panelsInMasterPanels.each { if(it != currentSourcePanel) { @@ -3944,11 +3958,24 @@ def expandMasterPanel() { parentPanel.repaint() isMasterPanelExpanded = true } - def retractMasterPanel() { // if(!searchEditor.text.equals("") || quickSearchResults.size() > 0) return bounds = masterPanel.getBounds() - bounds.width = calculateRetractedWidthForMasterPanel() + int retractedWidth = calculateRetractedWidthForMasterPanel() + + if (rtlOrientation) { + // در حالت RTL: موقعیت پنل به حالت اول برگردد + int widthDifference = bounds.width - retractedWidth + bounds.x = bounds.x + widthDifference // موقعیت X را به راست برگردان + bounds.width = retractedWidth + + println "RTL Retraction: x=${bounds.x}, width=${bounds.width}, difference=${widthDifference}" + } else { + // در حالت LTR: رفتار قبلی + bounds.width = retractedWidth + println "LTR Retraction: x=${bounds.x}, width=${bounds.width}" + } + masterPanel.setBounds(bounds) panelsInMasterPanels.each { it.setVisible(true) @@ -3972,7 +3999,6 @@ def retractMasterPanel() { } - def isCtrlPressed() { return (lastMouseModifiers & InputEvent.CTRL_DOWN_MASK) != 0 } From d7fe7285dce998313765cba07cc5b5740050e59a Mon Sep 17 00:00:00 2001 From: A <38586259+aaa1386@users.noreply.github.com> Date: Fri, 24 Oct 2025 22:06:47 +0330 Subject: [PATCH 14/14] =?UTF-8?q?=D8=A8=D9=87=D8=AA=D8=B1=20=D8=B4=D8=AF?= =?UTF-8?q?=D9=86=20=D9=86=D9=85=D8=A7=DB=8C=D8=B4=20=D9=BE=D9=86=D9=84=20?= =?UTF-8?q?=C2=AB=D8=A8=D8=B1=D9=88=D8=B2=20=D8=B1=D8=B3=D8=A7=D9=86=DB=8C?= =?UTF-8?q?=20=D8=A7=D9=86=D8=AA=D8=AE=D8=A7=D8=A8=20=C2=BB=20=D9=87=D9=86?= =?UTF-8?q?=DA=AF=D8=A7=D9=85=20=D8=A7=D9=86=D8=AA=D8=AE=D8=A7=D8=A8=20?= =?UTF-8?q?=DA=AF=D8=B1=D9=87=20=D9=87=D8=A7=20=D8=A7=D8=B2=20=D9=BE=D9=86?= =?UTF-8?q?=D9=84=20=D8=B3=D9=84=D8=B3=D8=B3=D9=87=20=D8=A7=D8=AC=D8=AF?= =?UTF-8?q?=D8=A7=D8=AF=20=D9=88=20=D9=BE=D9=86=D9=84=20=D9=87=D8=A7=DB=8C?= =?UTF-8?q?=20=D8=AF=DB=8C=DA=AF=D8=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utilityPanels.groovy | 84 +++++++++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 24 deletions(-) diff --git a/utilityPanels.groovy b/utilityPanels.groovy index 7af35a4..b199eff 100644 --- a/utilityPanels.groovy +++ b/utilityPanels.groovy @@ -872,6 +872,11 @@ public void manageInspectorsCreation() { } else if (currentSourcePanel == tagsPanel) { updateInspectorWithTagsPanel(index); } + + // دیباگ برای ردیابی + println "Inspector Creation - Source: ${currentSourcePanel?.getClass()?.simpleName}, " + + "In-place: ${activeSiblingPreviewPanels.contains(currentSourcePanel)}, " + + "Preview: ${visiblePreviewInspectors.contains(currentSourcePanel)}" } public boolean validateMousePositionOnList(int index) { @@ -932,17 +937,30 @@ public void updateSubInspectorsLocation(JPanel subInspectorPanel) { } public void updatePreviewInspectors(NodeModel subNode) { + // ابتدا پنل‌های بازرس قبلی را پاک کنید visiblePreviewInspectors.each { it.setVisible(false) parentPanel.remove(it) } visiblePreviewInspectors.clear() + // ایجاد پنل بازرس اول previewInspector = createInspectorPanel(subNode, currentSourcePanel) - visiblePreviewInspectors.add(previewInspector) - - previewInspector2 = createInspectorPanel(subNode, previewInspector) - visiblePreviewInspectors.add(previewInspector2) + if (previewInspector != null) { + visiblePreviewInspectors.add(previewInspector) + + // ایجاد پنل بازرس دوم (فرزندان) + previewInspector2 = createInspectorPanel(subNode, previewInspector) + if (previewInspector2 != null) { + visiblePreviewInspectors.add(previewInspector2) + } + } + + // اطمینان از نمایش پنل Update Selection + if (inspectorUpdateSelection && visibleInspectors.size() >= 2) { + visibleInspectors[0].setVisible(true) + visibleInspectors[1].setVisible(true) + } } public void updateInspectorWithTagsPanel(int index) { @@ -1893,8 +1911,31 @@ JPanel createInspectorPanel(NodeModel nodeNotProxy, JPanel sourcePanel, boolean inspectorPanel.putClientProperty("referenceNode", nodeNotProxy) - if (!shouldShowInspectors() && !activeSiblingPreviewPanels.contains(sourcePanel) && !visiblePreviewInspectors.contains(sourcePanel)) return inspectorPanel + // ★★★ تغییر اصلی: شرط ساده‌تر برای نمایش پنل‌ها ★★★ + boolean shouldCreateInspector = true + + if (!showPanels && hideInspectorsEvenIfUpdateSelection) { + // فقط برای پنل‌های خاص اجازه نمایش بده + if (!activeSiblingPreviewPanels.contains(sourcePanel) && + !visiblePreviewInspectors.contains(sourcePanel) && + sourcePanel != masterPanel) { + shouldCreateInspector = false + } + } + + if (showOnlyBreadcrumbs) { + if (!activeSiblingPreviewPanels.contains(sourcePanel) && + !visiblePreviewInspectors.contains(sourcePanel)) { + shouldCreateInspector = false + } + } + + if (!shouldCreateInspector) { + println "Inspector creation blocked for: ${sourcePanel?.getClass()?.simpleName}" + return inspectorPanel + } + // ★★★ اگر به اینجا رسیدیم، پنل را ایجاد کن ★★★ inspectorPanel.setLayout(new BorderLayout()) // if (currentlySelectedNode == nodeNotProxy) { // inspectorPanel.setBorder(BorderFactory.createLineBorder(Color.RED, 5)) @@ -2493,10 +2534,12 @@ JPanel createInspectorPanel(NodeModel nodeNotProxy, JPanel sourcePanel, boolean // parentPanel.repaint() parentPanel.addViewportReservedAreaSupplier(this::getInspectorReservedArea) + // دیباگ نهایی + println "Inspector created successfully for: ${nodeNotProxy.text.take(20)}..." + return inspectorPanel } - JPanel createSiblingPreviewPanel(NodeModel nodeNotProxy, boolean positionAtBottom = false, int referenceNodeScreenX, int referenceNodeScreenY) { @@ -2703,13 +2746,18 @@ void hideInspectorPanelIfNeeded() { if (shouldFreeze()) return if (mouseOverList) return + // پنل‌های پیش‌نمایش را مخفی نکن اگر مربوط به In-place Siblings Preview هستند + def previewToRemove = [] visiblePreviewInspectors.each { - it.setVisible(false) - parentPanel.remove(it) + if (!activeSiblingPreviewPanels.contains(currentSourcePanel)) { + it.setVisible(false) + parentPanel.remove(it) + previewToRemove.add(it) + } } + visiblePreviewInspectors.removeAll(previewToRemove) - visiblePreviewInspectors.clear() - + // پنل‌های بازرس اصلی را مدیریت کن visibleInspectors.each{ if(!inspectorUpdateSelection) { it.setVisible(false) @@ -2725,7 +2773,7 @@ void hideInspectorPanelIfNeeded() { visibleInspectors.clear() } else { - visibleInspectors.removeAll { it != visibleInspectors[0] && it != visibleInspectors[1]} + visibleInspectors.removeAll { it != visibleInspectors[0] && it != visibleInspectors[1] } if(visibleInspectors.size() != 0) { setInspectorLocation(visibleInspectors[0], masterPanel) if(visibleInspectors.size() > 1) { @@ -2733,21 +2781,8 @@ void hideInspectorPanelIfNeeded() { } } } -// -// if(inspectorUpdateSelection && visibleInspectors.size() > 0) { -// visibleInspectors[0].setVisible(true) -// if(visibleInspectors.size() > 1) { -// visibleInspectors[1].setVisible(true) -// } -// } retractMasterPanel() - - - - - return - } void configureLabelForNode(JComponent component, NodeModel nodeNotProxy, JPanel sourcePanel, int indexOfNode = 0) { @@ -4301,6 +4336,7 @@ def togglePanelsVisibility() { parentPanel.repaint() } + def shouldShowInspectors() { // return (showOnlyBreadcrumbs || (!showPanels && hideInspectorsEvenIfUpdateSelection)) shouldShowInspectors = true