de.cadoculus.javafx.minidockfx.MiniDockFXPane Maven / Gradle / Ivy
/*
* BSD 3-Clause License
*
* Copyright (c) 2020, Carsten Zerbst
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package de.cadoculus.javafx.minidockfx;
import com.jfoenix.controls.JFXRippler;
import javafx.animation.FadeTransition;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Bounds;
import javafx.geometry.Point2D;
import javafx.scene.Cursor;
import javafx.scene.control.Label;
import javafx.scene.control.SplitPane;
import javafx.scene.input.MouseDragEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.transform.Transform;
import javafx.util.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.*;
import java.util.prefs.Preferences;
/**
* The MiniDockFXPane is a simple docking control.
*
* It allows to add and remove individual views to different docking places and move them around.
* The dock places are called LEFT,CENTER,RIGHT,BOTTOM and are arranged as in the BorderLayout.
* Unless {@link DockableView#closeable} is false, it is possible to close views.
* Unless {@link DockableView#moveable} is false, it is possible to move views from one dock by another using dragging (left MB pressed).
*
*
* The views lifecycle is as follows:
*
*
* - Create your view as extension of {@link AbstractDockableView} class. You need to provide the views content in the content variable.
* - Add the view for display using {@link MiniDockFXPane#add(DockableView, MiniDockViewPosition...)}.
* If you provide no position is given, it will be placed to CENTER. If you give a dock position, it will be placed in that dock.
* If you provide PREFERENCES and another value, it will be placed in the same place as stored in preferences
*
*
*/
public class MiniDockFXPane extends AnchorPane {
public static final String VIEW_LABEL_STYLE = "minidockfx-view-label";
public static final String VIEW_BOX_STYLE = "minidockfx-view-box";
public static final String VIEW_LABEL_TT_STYLE = "minidockfx-view-label-tooltip";
public static final String CLOSE_BUTTON_STYLE = "minidockfx-tab-close";
public static final String TAB_HEADER_STYLE = "minidockfx-tab-header";
public static final String ACTIVE_DRAG_TRGT_STYLE = "minidockfx-drag-sub-target_active";
private static final String LAST_VERT_SPLIT_KEY = "lastVerticalSplit";
private static final String LAST_HOR_SPLIT0_KEY = "lastHorizontalSplit0";
private static final String LAST_HOR_SPLIT1_KEY = "lastHorizontalSplit1";
private static final Logger LOG = LoggerFactory.getLogger(MiniDockFXPane.class);
// It is late in the night and I do not want to program something giving me all possibile combinations :-)
private final static List POSITION_KEYS = Collections.unmodifiableList(List.of(
"[LEFT]", "[LEFT,CENTER]", "[LEFT,CENTER,RIGHT]", "[LEFT,CENTER,RIGHT,BOTTOM]", "[LEFT,RIGHT]", "[LEFT,BOTTOM]",
"[CENTER]", "[CENTER,RIGHT]", "[CENTER,RIGHT,BOTTOM]", "[CENTER,BOTTOM]",
"[RIGHT]", "[RIGHT,BOTTOM]",
"[BOTTOM]"));
private final static double[][] DEFAULTS_SPLITS = {
{1.0, 0.0, 1.0}, {1.0, 1.0 / 3, 1}, {1.0, 1.0 / 4, 3.0 / 4}, {3.0 / 4, 1.0 / 4, 3.0 / 4}, {1.0, 0.5, 1.0}, {3.0 / 4, 1.0, 1.0},
{1.0, 0.0, 1.0}, {1.0, 3.0 / 4, 1}, {3.0 / 4, 3.0 / 4, 1.0}, {3.0 / 4, 1.0, 1.0},
{1.0, 0.0, 1.0}, {3.0 / 4, 1.0, 1.0},
{1.0, 0.0, 1.0}
};
@FXML
private AnchorPane top;
@FXML
private SplitPane verticalSplit;
@FXML
private SplitPane horizontalSplit;
@FXML
private AnchorPane left;
@FXML
private TabbedDockController leftController;
@FXML
private AnchorPane center;
@FXML
private TabbedDockController centerController;
@FXML
private AnchorPane right;
@FXML
private TabbedDockController rightController;
@FXML
private AnchorPane bottom;
@FXML
private TabbedDockController bottomController;
@FXML
private BorderPane dragTarget;
@FXML
private Label leftDragTarget;
@FXML
private Label centerDragTarget;
@FXML
private Label rightDragTarget;
@FXML
private Label bottomDragTarget;
private final Preferences prefs = Preferences.userRoot().node(MiniDockFXPane.class.getName() + "." + getId());
private DockableView draggedView;
private String currentDocks = "";
private TabbedDockController[] controllers;
private ResourceBundle bundle;
private AnchorPane maximisedView;
private TabbedDockController maximisedController;
/**
* The default creator.
*/
public MiniDockFXPane() {
LOG.info("construct");
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("DefaultDock.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
LOG.error("an error occured loading components fxml", exception);
throw new RuntimeException(exception);
}
LOG.info("locale {}", Locale.getDefault());
bundle = ResourceBundle.getBundle("de/cadoculus/javafx/minidockfx/messages", Locale.getDefault(), MiniDockFXPane.class.getClassLoader());
LOG.info("bundle {}", bundle);
}
@FXML
public void initialize() {
LOG.error("initialize");
leftController.setDock(this);
centerController.setDock(this);
rightController.setDock(this);
bottomController.setDock(this);
controllers = new TabbedDockController[]{leftController, centerController, rightController, bottomController};
for (SplitPane.Divider divider : verticalSplit.getDividers()) {
divider.positionProperty().addListener((v, o, n) -> dividersChanged());
}
for (SplitPane.Divider divider : horizontalSplit.getDividers()) {
divider.positionProperty().addListener((v, o, n) -> dividersChanged());
}
for (Label trgt : List.of(leftDragTarget, centerDragTarget, rightDragTarget, bottomDragTarget)) {
trgt.setOnMouseDragEntered(mouseDragEvent -> dragEnd(trgt, mouseDragEvent));
trgt.setOnMouseDragOver(mouseDragEvent -> dragEnd(trgt, mouseDragEvent));
trgt.setOnMouseDragReleased(mouseDragEvent -> dragEnd(trgt, mouseDragEvent));
trgt.setOnMouseDragExited(mouseDragEvent -> dragEnd(trgt, mouseDragEvent));
}
LOG.info("bundle {}", bundle);
}
ResourceBundle getResourceBundle() {
return bundle;
}
/**
* Add a view to the docking panel
*
* @param view the view to add
* @param positions the desired positions. If no positon is given puts view to CENTER
* @throws IllegalArgumentException in case of null view or if view was already added
*/
public void add(DockableView view, MiniDockViewPosition... positions) {
if (view == null) {
throw new IllegalArgumentException("expect none null view");
}
if (view.getContent() == null) {
throw new IllegalArgumentException("no content found in view, you need to provide a content in " + view.getClass());
}
if (leftController.views.contains(view)) {
throw new IllegalArgumentException("found view " + view + " already docked on left side");
} else if (centerController.views.contains(view)) {
throw new IllegalArgumentException("found view " + view + " already docked on center");
} else if (rightController.views.contains(view)) {
throw new IllegalArgumentException("found view " + view + " already docked on right side");
} else if (bottomController.views.contains(view)) {
throw new IllegalArgumentException("found view " + view + " already docked on bottom");
}
MiniDockViewPosition pos = MiniDockViewPosition.CENTER;
if (positions != null) {
for (int i = 0; i < positions.length; i++) {
MiniDockViewPosition check = positions[i];
switch (check) {
case LEFT:
case CENTER:
case RIGHT:
case BOTTOM:
pos = check;
break;
default:
LOG.error("got unsupported position value {}", check);
}
}
}
TabbedDockController tbc = null;
switch (pos) {
case LEFT:
tbc = leftController;
break;
case CENTER:
tbc = centerController;
break;
case RIGHT:
tbc = rightController;
break;
case BOTTOM:
tbc = bottomController;
break;
}
tbc.add(view);
tbc.raise(view);
}
/**
* Remove the given view from the docking panel.
*
* @param view the view to remove
* @throws IllegalArgumentException in case of a null view or one which is not managed by the dock
*/
public void remove(DockableView view) {
if (view == null) {
throw new IllegalArgumentException("expect none null view");
}
if (leftController.views.contains(view)) {
leftController.remove(view);
if ( leftController.equals(maximisedController) && leftController.views.isEmpty()) {
maximize(leftController);
}
} else if (centerController.views.contains(view)) {
centerController.remove(view);
if ( centerController.equals(maximisedController) && centerController.views.isEmpty()) {
maximize(centerController);
}
} else if (rightController.views.contains(view)) {
rightController.remove(view);
if ( rightController.equals(maximisedController) && rightController.views.isEmpty()) {
maximize(rightController);
}
} else if (bottomController.views.contains(view)) {
bottomController.remove(view);
if ( bottomController.equals(maximisedController) && bottomController.views.isEmpty()) {
maximize(bottomController);
}
} else {
throw new IllegalArgumentException("view " + view + " is not managed in docking panel");
}
}
/**
* Move the given view from the current position to a new one
*
* @param view the view to move
* @param position the target position
* @throws IllegalArgumentException in case of a null view or one which is not managed by the dock
*/
public void move(DockableView view, MiniDockViewPosition position) {
if (view == null) {
throw new IllegalArgumentException("expect none null view");
}
TabbedDockController tbc = null;
switch (position) {
case LEFT:
tbc = leftController;
break;
case CENTER:
tbc = centerController;
break;
case RIGHT:
tbc = rightController;
break;
case BOTTOM:
tbc = bottomController;
break;
default:
LOG.error("got unsupported position value {}, skip moving", position);
return;
}
if (tbc.views.contains(view)) {
// nothing to do
} else {
remove(view);
add(view, position);
}
}
/**
* Raise the given view
*/
public void raise(DockableView view) {
for (TabbedDockController ctrl : controllers) {
if (ctrl.contains(view)) {
ctrl.raise(view);
}
}
}
/**
* This is used in a listener and stores the position of the dividers in the preferences.
*/
private void dividersChanged() {
double vSplit = 1.0;
double[] pos = verticalSplit.getDividerPositions();
if (pos.length > 0) {
// ensure,that we have at least 50px
vSplit = pos[0];
}
double hSplit0 = 0.0;
double hSplit1 = 1.0;
pos = horizontalSplit.getDividerPositions();
if (pos.length > 0) {
hSplit0 = pos[0];
if (pos.length > 1) {
hSplit1 = pos[1];
}
}
final double height = getHeight();
final double width = getWidth();
// ensure we have at least 100 height and 200px width
final double minHeight = 100;
final double minWidth = 100;
if (verticalSplit.getItems().size() > 1) {
double h0 = vSplit * height;
double h1 = (1 - vSplit) * height;
LOG.info("v {}", h0, h1);
if (height < 2 * minHeight) {
// Split evenly
vSplit = 0.5;
verticalSplit.setDividerPositions(vSplit);
} else {
if (h0 < minHeight) {
vSplit = minHeight / height;
verticalSplit.setDividerPositions(vSplit);
} else if (h1 < minHeight) {
vSplit = 1 - (minHeight / height);
verticalSplit.setDividerPositions(vSplit);
} else {
// nothing to do
}
}
}
if (horizontalSplit.getItems().size() > 1) {
double w0 = hSplit0 * width;
double w1 = (hSplit1 - hSplit0) * width;
double w2 = (1 - hSplit1) * width;
LOG.info("w {} {} {}", w0, w1, w2);
double minSplitD = minWidth / width;
if (horizontalSplit.getItems().size() == 2) {
if (width < 2 * minWidth) {
// Split evenly
hSplit0 = 0.5;
} else {
if (w0 < minWidth) {
hSplit0 = minSplitD;
}
if (w1 < minWidth) {
hSplit0 = 1 - minSplitD;
}
}
horizontalSplit.setDividerPositions(hSplit0);
} else if (horizontalSplit.getItems().size() == 3) {
if (width < 3 * minWidth) {
// Split evenly
hSplit0 = hSplit1 = 1 / 3.0;
} else {
if (w0 < minWidth) {
hSplit0 = minWidth / width;
}
w1 = (hSplit1 - hSplit0) * width;
if (w1 < minWidth) {
double curSplitD = hSplit1 - hSplit0;
double deltaSplitD = (minSplitD - curSplitD) / 2.0;
hSplit0 = Math.max(minSplitD, hSplit0 - deltaSplitD);
curSplitD = hSplit1 - hSplit0;
double remainingDeltaSplitD = (minSplitD - curSplitD);
hSplit1 = Math.min(hSplit1, hSplit0 + remainingDeltaSplitD);
}
w2 = (1 - hSplit1) * width;
if (w2 < minWidth) {
hSplit1 = 1 - minSplitD;
}
}
horizontalSplit.setDividerPositions(hSplit0, hSplit1);
}
}
// store to preferences
double[] splits = {vSplit, hSplit0, hSplit1};
prefs.put(currentDocks, Arrays.toString(splits));
LOG.info("current split {} {}", currentDocks, splits);
LOG.info("save split {} '{}'", currentDocks, prefs.get(currentDocks, ""));
}
private void debugInfo(String msg) {
if (LOG.isDebugEnabled()) {
LOG.debug(msg);
LOG.debug("left #{}, center #{}, right #{}, bottom #{}",
leftController.views.size(),
centerController.views.size(),
rightController.views.size(),
bottomController.views.size());
LOG.debug("verticalSplit {}", verticalSplit.getItems());
LOG.debug("horizontalSplit {}", horizontalSplit.getItems());
LOG.debug("maximizedController {}", maximisedController);
}
}
void updateLayout() {
debugInfo("updateLayout ");
final String currentDockName = currentDocks;
// check what sub controls are needed
List nextDockEnums = new ArrayList<>();
boolean needLeft = false;
if (!leftController.views.isEmpty()) {
needLeft = true;
nextDockEnums.add(MiniDockViewPosition.LEFT);
}
boolean needCenter = false;
if (!centerController.views.isEmpty()) {
needCenter = true;
nextDockEnums.add(MiniDockViewPosition.CENTER);
}
boolean needRight = false;
if (!rightController.views.isEmpty()) {
needRight = true;
nextDockEnums.add(MiniDockViewPosition.RIGHT);
}
boolean needFirstRow = needLeft || needCenter || needRight;
boolean needSecondRow = false;
if (!bottomController.views.isEmpty()) {
needSecondRow = true;
nextDockEnums.add(MiniDockViewPosition.BOTTOM);
}
nextDockEnums.sort(Comparator.naturalOrder());
boolean needMaximised = false;
// override for the maximised case
if (maximisedController != null) {
needMaximised = true;
needFirstRow = needSecondRow = needLeft = needCenter = needRight = false;
}
final String nextDocksName = needMaximised ? "maximised" : nextDockEnums.toString();
if (currentDocks.equals(nextDocksName)) {
// no update of layout needed
return;
}
currentDocks = nextDocksName;
// OK, something in the layout has changed, so we need
// to add/remove the needed docks and set new divider positions
// Care about layout
verticalSplit.getItems().clear();
if (needMaximised) {
verticalSplit.getItems().add(maximisedView);
verticalSplit.setDividerPositions(1.0);
return;
}
if (needFirstRow) {
verticalSplit.getItems().add(top);
}
if (needSecondRow) {
verticalSplit.getItems().add(bottom);
}
horizontalSplit.getItems().clear();
if (needLeft) {
horizontalSplit.getItems().add(left);
}
if (needCenter) {
horizontalSplit.getItems().add(center);
}
if (needRight) {
horizontalSplit.getItems().add(right);
}
// load previous or start splits
double[] previousSplits = loadSplitFromPrefs(nextDocksName);
double tvpos = previousSplits[0];
double thpos0 = previousSplits[1];
double thpos1 = previousSplits[2];
// cap the values
if (needFirstRow && needSecondRow) {
// Cap the value somehow
tvpos = Math.max(0.15, tvpos);
tvpos = Math.min(0.85, tvpos);
} else if (needFirstRow) {
tvpos = 1.0;
} else if (needSecondRow) {
tvpos = 0.0;
}
// and set the splitting
verticalSplit.setDividerPositions(tvpos);
horizontalSplit.setDividerPositions(thpos0, thpos1);
for (SplitPane.Divider divider : verticalSplit.getDividers()) {
divider.positionProperty().addListener((v, o, n) -> dividersChanged());
}
for (SplitPane.Divider divider : horizontalSplit.getDividers()) {
divider.positionProperty().addListener((v, o, n) -> dividersChanged());
}
dividersChanged();
}
private double[] loadSplitFromPrefs(String nextDocksName) {
double[] retval = {0.5, 0.5, 1.0};
String splitS = prefs.get(nextDocksName, null);
while (splitS != null) {
// TODO: this is ugly, replace by regular expression
// expect something like [1.0, 0.7327586206896551, 0.9]
splitS = splitS.replace("[", "");
splitS = splitS.replace("]", "");
String[] splitted = splitS.split(",");
if (splitted.length != 3) {
LOG.warn("found invalid value in preferences for key {}:{}", nextDocksName, prefs.get(nextDocksName, ""));
splitS = null;
break;
}
try {
NumberFormat dec = DecimalFormat.getNumberInstance(Locale.ENGLISH);
retval = new double[]{dec.parse(splitted[0].trim()).doubleValue(), dec.parse(splitted[1].trim()).doubleValue(), dec.parse(splitted[2].trim()).doubleValue()};
} catch (NumberFormatException | ParseException exp) {
LOG.error("failed to parse position from preferences ({})", prefs.get(nextDocksName, ""), exp);
splitS = null;
break;
}
break;
}
if (splitS == null) {
final int i = POSITION_KEYS.indexOf(nextDocksName);
if (i < 0) {
LOG.error("could not find key '{}' in {}", nextDocksName, POSITION_KEYS);
} else {
retval = DEFAULTS_SPLITS[i];
}
}
//LOG.info("loadSplitFromPrefs {} {}", nextDocksName, Arrays.toString(retval));
return retval;
}
/**
* Called in all kind of drag start events. See mouse listener in {@link de.cadoculus.javafx.minidockfx.TabbedDockController}
*/
void dragStart(DockableView view, MouseEvent event) {
draggedView = view;
LOG.info("dragStart {}", event.getEventType());
if (MouseEvent.MOUSE_PRESSED == event.getEventType()) {
leftDragTarget.setText(bundle.getString("label_left"));
centerDragTarget.setText(bundle.getString("label_center"));
rightDragTarget.setText(bundle.getString("label_right"));
bottomDragTarget.setText(bundle.getString("label_bottom"));
// make the drag target visible
dragTarget.setVisible(true);
dragTarget.toFront();
setCursor(Cursor.MOVE);
// and position it in the vicinity of the mouse
// 1. fallback position in the middle of the dock
final Bounds dtBounds = dragTarget.getBoundsInLocal();
final Bounds dkBounds = getBoundsInLocal();
//LOG.info(" bounds {} {}", dkBounds, dtBounds);
double lx = (dkBounds.getWidth() - dtBounds.getWidth()) / 2.0;
double ly = (dkBounds.getHeight() - dtBounds.getHeight()) / 2.0;
double dy = 50;
// 2. if possible better place in the vicinity of the mouse
try {
final Transform localToSceneTransform = getLocalToSceneTransform();
final Point2D mouseInLocal = localToSceneTransform.inverseTransform(event.getSceneX(), event.getSceneY());
// Horizontal
// place the drag target middle where the mouse it,
// but keep at lest 10px distance to the edge of the dock
lx = Math.max(30, mouseInLocal.getX() - dtBounds.getWidth() / 2.0);
lx = Math.min(lx, dkBounds.getWidth() - 30 - dtBounds.getWidth());
// Vertical
// place the drag target below the mouse unless there is not enough space
ly = mouseInLocal.getY() + dy;
if ((ly + dtBounds.getHeight() +dy) > dkBounds.getHeight()) {
ly = mouseInLocal.getY() - dy - dtBounds.getHeight();
}
} catch (Exception exp) {
LOG.warn("failed to apply conversion, use fallback postion", exp);
}
dragTarget.setLayoutX(lx);
dragTarget.setLayoutY(ly);
} else if (MouseEvent.MOUSE_RELEASED == event.getEventType()) {
finishDragging();
}
event.consume();
}
/**
* Called in all kind of drag end events. Used as listener on the drag target
*/
private void dragEnd(Label trgt, MouseDragEvent mouseDragEvent) {
LOG.debug("dragEnd {} {}", trgt.getId(), mouseDragEvent.getEventType());
if (draggedView == null) {
//LOG.error("something is wrong, got dragEnd, but have no draggedView value ???");
return;
}
if (MouseDragEvent.MOUSE_DRAG_ENTERED == mouseDragEvent.getEventType()) {
setCursor(Cursor.HAND);
trgt.getStyleClass().add(ACTIVE_DRAG_TRGT_STYLE);
if (trgt.getParent() instanceof JFXRippler) {
((JFXRippler) trgt.getParent()).createManualRipple().run();
}
} else if (MouseDragEvent.MOUSE_DRAG_EXITED == mouseDragEvent.getEventType()) {
setCursor(Cursor.MOVE);
trgt.getStyleClass().remove(ACTIVE_DRAG_TRGT_STYLE);
} else if (MouseDragEvent.MOUSE_DRAG_RELEASED == mouseDragEvent.getEventType()) {
// we should move the source view
LOG.info("move view '{}' to {}", draggedView, trgt.getId());
trgt.getStyleClass().remove(ACTIVE_DRAG_TRGT_STYLE);
finishDragging();
move(draggedView, MiniDockViewPosition.parseFromId(trgt.getId()));
draggedView = null;
}
mouseDragEvent.consume();
}
/**
* Call whenever dragging is finished. Used to hide the drag target
*/
private void finishDragging() {
// have a nice fade out for the drag target panel
FadeTransition fade = new FadeTransition();
fade.setNode(dragTarget);
fade.setDuration(Duration.millis(250));
fade.setFromValue(10);
fade.setToValue(0.1);
fade.setCycleCount(1);
fade.setAutoReverse(false);
fade.setOnFinished(actionEvent -> {
dragTarget.setVisible(false);
dragTarget.toBack();
dragTarget.setOpacity(1);
setCursor(Cursor.DEFAULT);
});
fade.play();
setCursor(Cursor.DEFAULT);
}
/**
* Get the maximised controller
*
* @return the controller or null
*/
TabbedDockController getMaximisedController() {
return maximisedController;
}
/**
* THis is called to maximize / unmaximize a single dock
*
* @param tabbedDockController
*/
void maximize(TabbedDockController tabbedDockController) {
maximisedController = maximisedController == tabbedDockController ? null : tabbedDockController;
if (leftController.equals(maximisedController)) {
maximisedView = left;
} else if (centerController.equals(maximisedController)) {
maximisedView = center;
} else if (rightController.equals(maximisedController)) {
maximisedView = center;
} else if (bottomController.equals(maximisedController)) {
maximisedView = center;
} else {
maximisedView = null;
}
updateLayout();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy