Skip to content

Commit

Permalink
Floating rework (#119)
Browse files Browse the repository at this point in the history
Floating has been reworked to use JPanels (DockedSimplePanel and DockedTabbedPanel) instead of the dockables directly. This allows the user to float individual dockables or an entire tabbed panel of dockables. In theory this opens up the possibility of floating other types of panels. But there are no plans right now.
  • Loading branch information
andrewauclair authored Nov 15, 2023
1 parent ef2050d commit 8bfaae8
Show file tree
Hide file tree
Showing 10 changed files with 364 additions and 119 deletions.
9 changes: 7 additions & 2 deletions docking-api/src/ModernDocking/api/DockingAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;

/**
* Single instance of the docking framework. Useful when a single JVM is to host multiple instances of an application
Expand Down Expand Up @@ -552,8 +553,12 @@ public void undock(Dockable dockable) {

Window window = DockingComponentUtils.findWindowForDockable(this, dockable);

Objects.requireNonNull(window);

RootDockingPanelAPI root = DockingComponentUtils.rootForWindow(this, window);

Objects.requireNonNull(root);

DockableWrapper wrapper = internals.getWrapper(dockable);

wrapper.setRoot(root);
Expand All @@ -571,15 +576,15 @@ public void undock(Dockable dockable) {
DockingListeners.fireUndockedEvent(dockable);

// make sure that can dispose this window, and we're not floating the last dockable in it
if (window != null && root != null && canDisposeWindow(window) && root.isEmpty() && !FloatListener.isFloating) {
if (canDisposeWindow(window) && root.isEmpty() && !FloatListener.isFloating()) {
deregisterDockingPanel(window);
window.dispose();
}

appState.persist();

// force this dockable to dock again if we're not floating it
if (!dockable.isClosable() && !FloatListener.isFloating && !deregistering) {
if (!dockable.isClosable() && !FloatListener.isFloating() && !deregistering) {
dock(dockable, mainWindow);
}
}
Expand Down
28 changes: 20 additions & 8 deletions docking-api/src/ModernDocking/floating/DockingHandles.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ of this software and associated documentation files (the "Software"), to deal
import ModernDocking.DockableStyle;
import ModernDocking.DockingRegion;
import ModernDocking.api.RootDockingPanelAPI;
import ModernDocking.internal.*;
import ModernDocking.ui.DockingSettings;
import ModernDocking.ui.ToolbarLocation;

Expand Down Expand Up @@ -66,7 +67,7 @@ public class DockingHandles {
private final RootDockingPanelAPI targetRoot;

// the dockable that we're currently trying to dock and is floating in a TempFloatingFrame
private Dockable floating;
private JPanel floating;
// the dockable that the mouse is currently over, can be null
private Dockable targetDockable = null;

Expand Down Expand Up @@ -141,7 +142,7 @@ public void setActive(boolean active) {
*
* @param dockable Dockable that is floating
*/
public void setFloating(Dockable dockable) {
public void setFloating(JPanel dockable) {
floating = dockable;
}

Expand Down Expand Up @@ -222,16 +223,27 @@ public void setTarget(Dockable dockable) {
}

private boolean isRegionAllowed(DockingRegion region) {
if (floating.getStyle() == DockableStyle.BOTH) {
return true;
}
if (region == DockingRegion.NORTH || region == DockingRegion.SOUTH) {
return floating.getStyle() == DockableStyle.HORIZONTAL;
if (floating instanceof DockedSimplePanel) {
DockedSimplePanel panel = (DockedSimplePanel) this.floating;
Dockable floating = panel.getWrapper().getDockable();

if (floating.getStyle() == DockableStyle.BOTH) {
return true;
}
if (region == DockingRegion.NORTH || region == DockingRegion.SOUTH) {
return floating.getStyle() == DockableStyle.HORIZONTAL;
}
return floating.getStyle() == DockableStyle.VERTICAL;
}
return floating.getStyle() == DockableStyle.VERTICAL;
return true;
}

private boolean isPinningRegionAllowed(DockingRegion region) {
if (floating instanceof DockedTabbedPanel) {
return false;
}
Dockable floating = ((DisplayPanel) this.floating).getWrapper().getDockable();

if (!floating.isPinningAllowed()) {
return false;
}
Expand Down
25 changes: 17 additions & 8 deletions docking-api/src/ModernDocking/floating/DockingOverlay.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ of this software and associated documentation files (the "Software"), to deal
import ModernDocking.DockingRegion;
import ModernDocking.api.DockingAPI;
import ModernDocking.api.RootDockingPanelAPI;
import ModernDocking.internal.DisplayPanel;
import ModernDocking.internal.DockedSimplePanel;
import ModernDocking.internal.DockingInternal;
import ModernDocking.internal.DockingPanel;
import ModernDocking.ui.DockingSettings;
import ModernDocking.ui.ToolbarLocation;

Expand All @@ -44,7 +47,7 @@ public class DockingOverlay {
private final RootDockingPanelAPI targetRoot;

// the dockable that is currently floating in its own undecoarted frame
private Dockable floating;
private JPanel floating;

// the target dockable that the mouse is currently over, could be null
private Dockable targetDockable;
Expand Down Expand Up @@ -109,7 +112,7 @@ public void setActive(boolean active) {
*
* @param dockable Current floating dockable
*/
public void setFloating(Dockable dockable) {
public void setFloating(JPanel dockable) {
floating = dockable;
}

Expand All @@ -124,13 +127,19 @@ public void setTargetDockable(Dockable dockable) {

// check if the floating dockable is allowed to dock to this region
private boolean isRegionAllowed(DockingRegion region) {
if (floating.getStyle() == DockableStyle.BOTH) {
return true;
}
if (region == DockingRegion.NORTH || region == DockingRegion.SOUTH) {
return floating.getStyle() == DockableStyle.HORIZONTAL;
if (floating instanceof DisplayPanel) {
DisplayPanel panel = (DisplayPanel) this.floating;
Dockable floating = panel.getWrapper().getDockable();

if (floating.getStyle() == DockableStyle.BOTH) {
return true;
}
if (region == DockingRegion.NORTH || region == DockingRegion.SOUTH) {
return floating.getStyle() == DockableStyle.HORIZONTAL;
}
return floating.getStyle() == DockableStyle.VERTICAL;
}
return floating.getStyle() == DockableStyle.VERTICAL;
return true;
}

public void update(Point screenPos) {
Expand Down
5 changes: 3 additions & 2 deletions docking-api/src/ModernDocking/floating/DockingUtilsFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ of this software and associated documentation files (the "Software"), to deal
import ModernDocking.DockingRegion;
import ModernDocking.api.DockingAPI;
import ModernDocking.api.RootDockingPanelAPI;
import ModernDocking.internal.DockingPanel;
import ModernDocking.ui.ToolbarLocation;

import javax.swing.*;
Expand Down Expand Up @@ -122,15 +123,15 @@ public void setTargetDockable(Dockable target) {
*
* @param floating Floating dockable
*/
public void setFloating(Dockable floating) {
public void setFloating(JPanel floating) {
handles.setFloating(floating);
overlay.setFloating(floating);
}

public void setOverTab(boolean overTab, Rectangle rect, boolean last) {
this.overTab = overTab;

overlay.setTargetDockableRegion(DockingRegion.CENTER);
overlay.setTargetDockableRegion(overTab ? DockingRegion.CENTER : null);
handles.overTab = overTab;
overlay.overTab = overTab;
overlay.targetTab = rect;
Expand Down
62 changes: 62 additions & 0 deletions docking-api/src/ModernDocking/floating/DragListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package ModernDocking.floating;

import ModernDocking.api.DockingAPI;
import ModernDocking.api.RootDockingPanelAPI;
import ModernDocking.internal.DockingPanel;

import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.*;
import java.util.HashMap;
import java.util.Map;

public class DragListener extends DragSourceAdapter implements DragSourceListener, DragSourceMotionListener {
private final DragSource dragSource = new DragSource();
private final Transferable transferable = new StringSelection("");

private DockingUtilsFrame activeUtilsFrame = null;
private static final Map<Window, DockingUtilsFrame> utilFrames = new HashMap<>();

public static void registerDockingWindow(DockingAPI docking, Window window, RootDockingPanelAPI root) {
utilFrames.put(window, new DockingUtilsFrame(docking, window, root));
}

public static void deregisterDockingWindow(Window window) {
utilFrames.remove(window);
}

public DragListener(DockingAPI docking, Component dragSource, DockingPanel panel) {
this.dragSource.addDragSourceMotionListener(DragListener.this);

this.dragSource.createDefaultDragGestureRecognizer(dragSource, DnDConstants.ACTION_MOVE, dge -> {
this.dragSource.startDrag(dge, Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR), transferable, DragListener.this);

// docking.undock(panel);

// activeUtilsFrame = new DockingUtilsFrame();
// mouseDragStarted(dge.getDragOrigin());
//
// if (originalWindow instanceof JDialog) {
// modalityType = ((JDialog) originalWindow).getModalityType();
//
// ((JDialog) originalWindow).setModalityType(Dialog.ModalityType.MODELESS);
//
// // Set all of these as invokeLater to force the order they happen in
// SwingUtilities.invokeLater(() -> {
// // check that the floating frame still exists since we invoked later and time might have passed
// if (floatingFrame != null) {
// floatingFrame.toFront();
// }
// });
// SwingUtilities.invokeLater(() -> {
// // check that the utils frame still exists since we invoked later and time might have passed
// if (activeUtilsFrame != null) {
// activeUtilsFrame.toFront();
// }
// });
// }
});
}
}
Loading

0 comments on commit 8bfaae8

Please sign in to comment.