From 4b830f7559cf9894fbff7520cbacb6cc4d572874 Mon Sep 17 00:00:00 2001 From: creme332 <65414576+creme332@users.noreply.github.com> Date: Thu, 27 Jun 2024 21:14:32 +0400 Subject: [PATCH] implement sidebar animation --- .../controller/CanvasConsoleController.java | 106 +++++++++++++++++- .../creme332/controller/FrameController.java | 38 ++++--- .../controller/SideMenuController.java | 17 +-- .../github/creme332/view/CanvasConsole.java | 6 +- .../java/com/github/creme332/view/Frame.java | 2 +- 5 files changed, 132 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/github/creme332/controller/CanvasConsoleController.java b/src/main/java/com/github/creme332/controller/CanvasConsoleController.java index 05b52607..f63b7c7d 100644 --- a/src/main/java/com/github/creme332/controller/CanvasConsoleController.java +++ b/src/main/java/com/github/creme332/controller/CanvasConsoleController.java @@ -1,39 +1,139 @@ package com.github.creme332.controller; +import java.awt.Dimension; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Timer; import java.util.TimerTask; +import java.util.concurrent.TimeUnit; import com.github.creme332.model.AppState; +import com.github.creme332.model.CanvasModel; import com.github.creme332.model.Mode; import com.github.creme332.view.CanvasConsole; +import com.github.creme332.view.SideMenuPanel; import com.github.creme332.view.Toast; public class CanvasConsoleController implements PropertyChangeListener { private Timer timer; private Toast toast; private CanvasConsole console; + private CanvasModel model; public CanvasConsoleController(AppState app, CanvasConsole console) { this.console = console; + this.model = app.getCanvasModel(); toast = console.getToast(); app.addPropertyChangeListener(this); new ToolBarController(console.getToolbar(), app.getCanvasModel()); new SideMenuController(app, console.getSidebar()); new ZoomPanelController(app, console.getZoomPanel()); + + if (!app.getSideBarVisibility()) { + System.out.println(console.getPreferredSize()); + console.setPreferredSize(console.getPreferredSize()); + } } @Override - public void propertyChange(PropertyChangeEvent evt) { - if ("activateToast".equals(evt.getPropertyName())) { - Mode currentMode = (Mode) evt.getNewValue(); + public void propertyChange(PropertyChangeEvent e) { + String propertyName = e.getPropertyName(); + if ("activateToast".equals(propertyName)) { + Mode currentMode = (Mode) e.getNewValue(); toast.setTitleText(currentMode.getTitle()); toast.setInstructionText(currentMode.getInstructions()); showTemporaryToast(); } + + if ("sidebarVisibility".equals(propertyName)) { + boolean openSidebar = (boolean) e.getNewValue(); + if (openSidebar) { + animateSidebarOpen(); + } else { + animateSidebarClose(); + } + } + } + + /** + * Animates sidebar opening. It decreases the width of the canvas console so + * that the sidebar which was initially out of frame becomes visible. + */ + private void animateSidebarOpen() { + /** + * Speed at which sidebar opens in pixels per nanosecond. + */ + final int openingSpeed = 5; + /** + * Initial width of canvas console such that sidebar is hidden. + */ + final int initialWidth = console.getRootPane().getWidth() + SideMenuPanel.PREFERRED_WIDTH; + + /** + * Final width of canvas console such that sidebar is visible. + */ + final int finalWidth = model.getCanvasDimension().width; + + Thread th = new Thread() { + @Override + public void run() { + for (int i = initialWidth; i >= finalWidth; i -= openingSpeed) { + try { + TimeUnit.NANOSECONDS.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + int newWidth = Math.max(finalWidth, i); + console.setSize(new Dimension(newWidth, console.getHeight())); + console.revalidate(); + console.repaint(); + } + + } + }; + th.start(); + } + + /** + * Animates sidebar closing. It increases the width of the canvas console so + * that the sidebar becomes hidden (since sidebar moves out of frame). + */ + private void animateSidebarClose() { + /** + * Speed at which sidebar closes in pixels per nanosecond. + */ + final int closingSpeed = 6; + + /** + * Initial width of canvas console such that sidebar is visible. + */ + final int initialWidth = console.getRootPane().getWidth(); + + /** + * Final width of canvas console such that sidebar is hidden. + */ + final int finalWidth = initialWidth + SideMenuPanel.PREFERRED_WIDTH; + + Thread th = new Thread() { + @Override + public void run() { + for (int i = initialWidth; i <= finalWidth; i += closingSpeed) { + try { + TimeUnit.NANOSECONDS.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + int newWidth = Math.min(finalWidth, i); + console.setSize(new Dimension(newWidth, console.getHeight())); + console.revalidate(); + console.repaint(); + } + } + + }; + th.start(); } private void showTemporaryToast() { diff --git a/src/main/java/com/github/creme332/controller/FrameController.java b/src/main/java/com/github/creme332/controller/FrameController.java index d2c90a8e..8a91eccc 100644 --- a/src/main/java/com/github/creme332/controller/FrameController.java +++ b/src/main/java/com/github/creme332/controller/FrameController.java @@ -76,13 +76,14 @@ public void keyPressed(KeyEvent e) { } /** - * Resizes frame and its components when frame dimensions changes + * Resizes frame and its components when frame dimensions changes. This is the + * function responsible for setting the size of canvas and canvas control. */ private void resizeEverything() { - int frameWidth = frame.getWidth(); - int frameHeight = frame.getHeight(); + final int frameWidth = frame.getWidth(); + final int frameHeight = frame.getHeight(); - Dimension mainDimension = new Dimension(frameWidth, frameHeight - MenuBar.HEIGHT - 60); + Dimension canvasDimension = new Dimension(frameWidth, frameHeight - MenuBar.HEIGHT - 60); if (DesktopApi.getOs() == EnumOS.LINUX) { /** @@ -91,31 +92,40 @@ private void resizeEverything() { * overflowing */ - mainDimension = new Dimension(frameWidth - 80, frameHeight - MenuBar.HEIGHT - 100); + canvasDimension = new Dimension(frameWidth - 80, frameHeight - MenuBar.HEIGHT - 100); } - Rectangle mainBounds = new Rectangle(mainDimension); - JLayeredPane canvasScreen = frame.getCanvasScreen(); CanvasConsole canvasControl = (CanvasConsole) canvasScreen.getComponent(0); Canvas canvas = (Canvas) canvasScreen.getComponent(1); // update canvasScreen dimensions - canvasScreen.setMaximumSize(mainDimension); + canvasScreen.setMaximumSize(canvasDimension); + + // update canvas position + canvas.setMaximumSize(canvasDimension); + canvas.setBounds(new Rectangle(canvasDimension)); + + /** + * Calculate dimensions of canvas control, taking into account whether the + * sidebar is visible. Note: Hiding of the sidebar is made possible by pushing + * it out the frame. This makes sidebar animation easier. + */ + + final boolean sidebarEnabled = app.getSideBarVisibility(); + final Dimension canvasControlDimension = new Dimension( + canvasDimension.width + (sidebarEnabled ? 0 : SideMenuPanel.PREFERRED_WIDTH), + canvasDimension.height); // update canvas control dimensions] - canvasControl.setMaximumSize(mainDimension); - canvasControl.setBounds(mainBounds); + canvasControl.setMaximumSize(canvasControlDimension); + canvasControl.setBounds(new Rectangle(canvasControlDimension)); canvasControl.revalidate(); // update sidebar height frame.getCanvasConsole().getSidebar().setMaximumSize(new Dimension(SideMenuPanel.PREFERRED_WIDTH, frameHeight - MenuBar.HEIGHT)); - // update canvas position - canvas.setMaximumSize(mainDimension); - canvas.setBounds(mainBounds); - frame.repaint(); frame.revalidate(); } diff --git a/src/main/java/com/github/creme332/controller/SideMenuController.java b/src/main/java/com/github/creme332/controller/SideMenuController.java index b3d51e8a..5c953e75 100644 --- a/src/main/java/com/github/creme332/controller/SideMenuController.java +++ b/src/main/java/com/github/creme332/controller/SideMenuController.java @@ -1,9 +1,8 @@ package com.github.creme332.controller; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; import javax.swing.JDialog; import javax.swing.JOptionPane; + import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; @@ -17,7 +16,7 @@ /** * Controller responsible for managing sidebar in CanvasConsole. */ -public class SideMenuController implements PropertyChangeListener { +public class SideMenuController { private static final String PROJECT_INFO = """ Polydraw is an application for drawing rasterized shapes, inspired by Geogebra Classic. @@ -33,10 +32,6 @@ public class SideMenuController implements PropertyChangeListener { public SideMenuController(AppState app, SideMenuPanel sidebar) { this.sidebar = sidebar; - app.addPropertyChangeListener(this); - - sidebar.setVisible(app.getSideBarVisibility()); - // set default values in canvas settings sidebar.getGridLinesCheckBox().setSelected(app.getCanvasModel().isGuidelinesEnabled()); sidebar.getAxesCheckBox().setSelected(app.getCanvasModel().isAxesVisible()); @@ -59,14 +54,6 @@ public void mouseMoved(MouseEvent e) { }); } - @Override - public void propertyChange(PropertyChangeEvent e) { - String propertyName = e.getPropertyName(); - if ("sidebarVisibility".equals(propertyName)) { - sidebar.setVisible((boolean) e.getNewValue()); - } - } - private void initializeButtonListeners(AppState app) { CanvasModel canvasModel = app.getCanvasModel(); diff --git a/src/main/java/com/github/creme332/view/CanvasConsole.java b/src/main/java/com/github/creme332/view/CanvasConsole.java index d4cbfdd8..a89725fd 100644 --- a/src/main/java/com/github/creme332/view/CanvasConsole.java +++ b/src/main/java/com/github/creme332/view/CanvasConsole.java @@ -25,17 +25,15 @@ public class CanvasConsole extends JPanel { transient CanvasModel canvasModel; - public CanvasConsole(CanvasModel canvasModel, boolean isSidebarVisible, Mode defaultMode) { + public CanvasConsole(CanvasModel canvasModel, Mode defaultMode) { this.canvasModel = canvasModel; toast = new Toast(defaultMode); - setOpaque(false); // make panel transparent + setOpaque(false); setLayout(new BorderLayout()); this.add(createMainPanel(), BorderLayout.CENTER); - sideMenu.setVisible(isSidebarVisible); - this.add(sideMenu, BorderLayout.EAST); } diff --git a/src/main/java/com/github/creme332/view/Frame.java b/src/main/java/com/github/creme332/view/Frame.java index d3b6940e..e427798d 100644 --- a/src/main/java/com/github/creme332/view/Frame.java +++ b/src/main/java/com/github/creme332/view/Frame.java @@ -75,7 +75,7 @@ public Frame(AppState app) initFrameProperties(); menubar = new MenuBar(app.getMenuModels()); - canvasConsole = new CanvasConsole(app.getCanvasModel(), app.getSideBarVisibility(), app.getMode()); + canvasConsole = new CanvasConsole(app.getCanvasModel(), app.getMode()); canvas = new Canvas(app.getCanvasModel()); tutorialCenter = new TutorialCenter();