mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-20 13:31:28 +07:00
IDEA-354490 floating action fixes
GitOrigin-RevId: 16f9b4b6fbebc22793bd98cf87152e651adbfc8c
This commit is contained in:
committed by
intellij-monorepo-bot
parent
76fbc266dc
commit
20c62c2d7e
@@ -0,0 +1,38 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.actionSystem
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
/**
|
||||
* Actions which can behave as a group if they > 1 or as one action if action is only one
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
class MergeableActions(
|
||||
private val originalGroup: ActionGroup,
|
||||
): ActionGroup() {
|
||||
|
||||
override fun getActionUpdateThread(): ActionUpdateThread {
|
||||
return ActionUpdateThread.BGT
|
||||
}
|
||||
|
||||
override fun update(e: AnActionEvent) {
|
||||
val children = originalGroup.getChildren(e)
|
||||
var visibleChildrenCount = 0
|
||||
for (child in children) {
|
||||
child.update(e)
|
||||
if (e.presentation.isVisible) {
|
||||
visibleChildrenCount++
|
||||
if (visibleChildrenCount > 1) break
|
||||
}
|
||||
}
|
||||
e.presentation.isPopupGroup = visibleChildrenCount > 1
|
||||
e.presentation.isEnabledAndVisible = visibleChildrenCount > 0
|
||||
e.presentation.icon = AllIcons.Actions.More
|
||||
}
|
||||
|
||||
override fun getChildren(e: AnActionEvent?): Array<AnAction> {
|
||||
return originalGroup.getChildren(e)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import com.intellij.ide.structureView.customRegions.CustomRegionTreeElement;
|
||||
import com.intellij.ide.structureView.impl.StructureViewFactoryImpl;
|
||||
import com.intellij.ide.structureView.impl.common.PsiTreeElementBase;
|
||||
import com.intellij.ide.structureView.logical.LogicalStructureDataKeys;
|
||||
import com.intellij.ide.structureView.logical.impl.LogicalStructureViewModel;
|
||||
import com.intellij.ide.structureView.logical.impl.LogicalStructureViewTreeElement;
|
||||
import com.intellij.ide.structureView.symbol.DelegatingPsiElementWithSymbolPointer;
|
||||
import com.intellij.ide.ui.UISettingsListener;
|
||||
@@ -24,7 +25,6 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.toolbar.floating.FloatingToolbar;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.fileEditor.TextEditor;
|
||||
@@ -79,8 +79,6 @@ import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import javax.swing.tree.TreeSelectionModel;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ComponentAdapter;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
@@ -124,7 +122,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
|
||||
// written from EDT only
|
||||
private volatile @Nullable CancellablePromise<?> myLastAutoscrollPromise;
|
||||
|
||||
private final FloatingToolbar floatingToolbar;
|
||||
private StructureViewFloatingToolbar floatingToolbar;
|
||||
|
||||
|
||||
public StructureViewComponent(@Nullable FileEditor editor,
|
||||
@@ -183,22 +181,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
|
||||
});
|
||||
|
||||
JScrollPane content = ScrollPaneFactory.createScrollPane(myTree);
|
||||
MyLayeredPane layeredPane = new MyLayeredPane(content);
|
||||
floatingToolbar = new FloatingToolbar(
|
||||
layeredPane,
|
||||
(ActionGroup) ActionManager.getInstance().getAction(ActionPlaces.STRUCTURE_VIEW_FLOATING_TOOLBAR),
|
||||
this
|
||||
);
|
||||
layeredPane.add(content, JLayeredPane.DEFAULT_LAYER);
|
||||
layeredPane.add(floatingToolbar, JLayeredPane.POPUP_LAYER);
|
||||
setContent(layeredPane);
|
||||
content.getVerticalScrollBar().addAdjustmentListener(event -> floatingToolbar.setScrollingDy(event.getValue()));
|
||||
addComponentListener(new ComponentAdapter() {
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
floatingToolbar.setX(getBounds().width - 50);
|
||||
}
|
||||
});
|
||||
setContent(new MyLayeredPane(content, structureViewModel instanceof LogicalStructureViewModel));
|
||||
|
||||
myAutoScrollToSourceHandler = new MyAutoScrollToSourceHandler();
|
||||
myAutoScrollFromSourceHandler = new MyAutoScrollFromSourceHandler(myProject, this);
|
||||
@@ -1012,21 +995,13 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
|
||||
if (event.getClickCount() != 1 || event.getID() != MouseEvent.MOUSE_PRESSED) return;
|
||||
Optional.ofNullable(getClosestPathForLocation(event.getX(), event.getY()))
|
||||
.map(path -> getPathBounds(path))
|
||||
.filter(bounds -> event.getX() >= bounds.x)
|
||||
.filter(bounds -> event.getX() >= bounds.x && event.getY() < bounds.y + bounds.height)
|
||||
.ifPresent(pathBounds -> {
|
||||
int scrollDy = 0;
|
||||
if (getParent().getParent() instanceof JBScrollPane scrollParent) {
|
||||
scrollDy = scrollParent.getVerticalScrollBar().getValue();
|
||||
}
|
||||
floatingToolbar.hideImmediately();
|
||||
floatingToolbar.setBoundsWithScrollingDy(
|
||||
getParent().getBounds().width - 50,
|
||||
pathBounds.y - 5,
|
||||
40,
|
||||
pathBounds.height + 5,
|
||||
scrollDy
|
||||
);
|
||||
floatingToolbar.scheduleShow();
|
||||
floatingToolbar.repaintOnYWithDy(pathBounds.y, scrollDy);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1218,12 +1193,19 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyLayeredPane extends JBLayeredPane {
|
||||
private class MyLayeredPane extends JBLayeredPane {
|
||||
|
||||
private final JComponent mainComponent;
|
||||
private final boolean isLogical;
|
||||
|
||||
MyLayeredPane(JComponent mainComponent) {
|
||||
MyLayeredPane(JScrollPane mainComponent, boolean isLogical) {
|
||||
this.mainComponent = mainComponent;
|
||||
this.isLogical = isLogical;
|
||||
|
||||
floatingToolbar = new StructureViewFloatingToolbar(this, StructureViewComponent.this);
|
||||
add(mainComponent, DEFAULT_LAYER);
|
||||
add(floatingToolbar, POPUP_LAYER);
|
||||
mainComponent.getVerticalScrollBar().addAdjustmentListener(event -> floatingToolbar.setScrollingDy(event.getValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1231,7 +1213,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
|
||||
Rectangle bounds = getBounds();
|
||||
for (Component component : getComponents()) {
|
||||
if (component == mainComponent) {
|
||||
component.setBounds(0, 0, bounds.width, bounds.height);
|
||||
component.setBounds(isLogical ? 12 : 0, 0, bounds.width, bounds.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.structureView.newStructureView
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.actionSystem.*
|
||||
import com.intellij.openapi.editor.toolbar.floating.AbstractFloatingToolbarComponent
|
||||
import com.intellij.openapi.observable.util.whenMouseMoved
|
||||
import com.intellij.openapi.ui.isComponentUnderMouse
|
||||
import com.intellij.openapi.ui.isFocusAncestor
|
||||
import java.awt.Rectangle
|
||||
import javax.swing.BorderFactory
|
||||
import javax.swing.JComponent
|
||||
|
||||
internal class StructureViewFloatingToolbar(
|
||||
private val ownerComponent: JComponent,
|
||||
private val parentDisposable: Disposable,
|
||||
) : AbstractFloatingToolbarComponent(
|
||||
DefaultActionGroup(MergeableActions((ActionManager.getInstance().getAction(ActionPlaces.STRUCTURE_VIEW_FLOATING_TOOLBAR) as ActionGroup))),
|
||||
parentDisposable
|
||||
) {
|
||||
|
||||
override val autoHideable: Boolean = true
|
||||
|
||||
private var boundsWithoutScrolling: Rectangle? = null
|
||||
|
||||
override fun isComponentOnHold(): Boolean {
|
||||
return isComponentUnderMouse() || isFocusAncestor()
|
||||
}
|
||||
|
||||
override fun installMouseMotionWatcher() {
|
||||
ownerComponent.whenMouseMoved(parentDisposable) {
|
||||
scheduleShow()
|
||||
}
|
||||
}
|
||||
|
||||
fun repaintOnYWithDy(y: Int, scrollingDy: Int) {
|
||||
hideImmediately()
|
||||
boundsWithoutScrolling = bounds
|
||||
boundsWithoutScrolling = Rectangle(0, y, minimumButtonSize.width, minimumButtonSize.height)
|
||||
if (scrollingDy <= 0)
|
||||
bounds = boundsWithoutScrolling!!
|
||||
else
|
||||
setBounds(0, y - scrollingDy, minimumButtonSize.width, minimumButtonSize.height)
|
||||
scheduleShow()
|
||||
}
|
||||
|
||||
fun setScrollingDy(scrollingDy: Int) {
|
||||
val bounds = boundsWithoutScrolling ?: bounds
|
||||
setBounds(bounds.x, bounds.y - scrollingDy, bounds.width, bounds.height)
|
||||
}
|
||||
|
||||
init {
|
||||
init(ownerComponent)
|
||||
showingTime = 150
|
||||
hidingTime = 50
|
||||
border = BorderFactory.createEmptyBorder()
|
||||
}
|
||||
}
|
||||
@@ -6,20 +6,16 @@ import com.intellij.openapi.actionSystem.ActionGroup
|
||||
import com.intellij.openapi.observable.util.whenMouseMoved
|
||||
import com.intellij.openapi.ui.isComponentUnderMouse
|
||||
import com.intellij.openapi.ui.isFocusAncestor
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import java.awt.Rectangle
|
||||
import javax.swing.JComponent
|
||||
|
||||
class FloatingToolbar(
|
||||
private val ownerComponent: JComponent,
|
||||
actionGroup: ActionGroup,
|
||||
private val parentDisposable: Disposable,
|
||||
private val parentDisposable: Disposable
|
||||
) : AbstractFloatingToolbarComponent(actionGroup, parentDisposable) {
|
||||
|
||||
override val autoHideable: Boolean = true
|
||||
|
||||
private var boundsWithoutScrolling: Rectangle? = null
|
||||
|
||||
override fun isComponentOnHold(): Boolean {
|
||||
return isComponentUnderMouse() || isFocusAncestor()
|
||||
}
|
||||
@@ -30,38 +26,7 @@ class FloatingToolbar(
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
fun setBoundsWithScrollingDy(x: Int, y: Int, width: Int, height: Int, scrollingDy: Int) {
|
||||
boundsWithoutScrolling = bounds
|
||||
boundsWithoutScrolling = Rectangle(x, y, width, height)
|
||||
if (scrollingDy <= 0)
|
||||
bounds = boundsWithoutScrolling!!
|
||||
else
|
||||
setBounds(x, y - scrollingDy, width, height)
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
fun setScrollingDy(scrollingDy: Int) {
|
||||
val bounds = boundsWithoutScrolling ?: bounds
|
||||
setBounds(bounds.x, bounds.y - scrollingDy, bounds.width, bounds.height)
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
fun setX(x: Int) {
|
||||
val oldBounds = boundsWithoutScrolling ?: bounds
|
||||
setBoundsWithScrollingDy(
|
||||
x,
|
||||
oldBounds.getY().toInt(),
|
||||
oldBounds.getWidth().toInt(),
|
||||
oldBounds.getHeight().toInt(),
|
||||
oldBounds.getY().toInt() - bounds.getY().toInt()
|
||||
)
|
||||
}
|
||||
|
||||
init {
|
||||
init(ownerComponent)
|
||||
showingTime = 150
|
||||
hidingTime = 50
|
||||
//backgroundAlpha = 1F
|
||||
}
|
||||
}
|
||||
@@ -968,7 +968,7 @@
|
||||
</group>
|
||||
|
||||
<group id="StructureViewToolbar"/>
|
||||
<group id="StructureViewFloatingToolbar"/>
|
||||
<group id="StructureViewFloatingToolbar" popup="true"/>
|
||||
|
||||
<group id="StructureViewPopupMenu">
|
||||
<reference ref="EditSource"/>
|
||||
|
||||
@@ -22,10 +22,12 @@ import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiTarget
|
||||
import com.intellij.ui.SimpleTextAttributes
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import javax.swing.Icon
|
||||
|
||||
internal class LogicalStructureViewModel private constructor(psiFile: PsiFile, editor: Editor?, assembledModel: LogicalStructureAssembledModel<*>, elementBuilder: ElementsBuilder)
|
||||
@ApiStatus.Internal
|
||||
class LogicalStructureViewModel private constructor(psiFile: PsiFile, editor: Editor?, assembledModel: LogicalStructureAssembledModel<*>, elementBuilder: ElementsBuilder)
|
||||
: StructureViewModelBase(psiFile, editor, elementBuilder.createViewTreeElement(assembledModel)),
|
||||
StructureViewModel.ElementInfoProvider, StructureViewModel.ExpandInfoProvider, StructureViewModel.ActionHandler {
|
||||
|
||||
@@ -67,6 +69,12 @@ interface LogicalStructureViewTreeElement<T> : StructureViewTreeElement {
|
||||
|
||||
fun getLogicalAssembledModel(): LogicalStructureAssembledModel<T>
|
||||
|
||||
/**
|
||||
* Means that the element is not the node for logical object itself but it's a child which has no own logical object
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
fun isHasNoOwnLogicalModel(): Boolean = false
|
||||
|
||||
}
|
||||
|
||||
private class ElementsBuilder {
|
||||
@@ -275,6 +283,8 @@ private class ElementsBuilder {
|
||||
|
||||
override fun getLogicalAssembledModel(): LogicalStructureAssembledModel<T> = parentAssembledModel
|
||||
|
||||
override fun isHasNoOwnLogicalModel(): Boolean = true
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is LogicalGroupStructureElement<*>) return false
|
||||
return parentAssembledModel == other.parentAssembledModel && grouper == other.grouper
|
||||
|
||||
Reference in New Issue
Block a user