All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.pivot.wtk.skin.terra.TerraSheetSkin Maven / Gradle / Ivy

There is a newer version: 2.0.5
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.pivot.wtk.skin.terra;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Toolkit;

import org.apache.pivot.collections.Dictionary;
import org.apache.pivot.util.Vote;
import org.apache.pivot.wtk.Bounds;
import org.apache.pivot.wtk.Component;
import org.apache.pivot.wtk.ComponentListener;
import org.apache.pivot.wtk.Container;
import org.apache.pivot.wtk.ContainerMouseListener;
import org.apache.pivot.wtk.Cursor;
import org.apache.pivot.wtk.Dimensions;
import org.apache.pivot.wtk.Display;
import org.apache.pivot.wtk.GraphicsUtilities;
import org.apache.pivot.wtk.ImageView;
import org.apache.pivot.wtk.Insets;
import org.apache.pivot.wtk.Keyboard;
import org.apache.pivot.wtk.Mouse;
import org.apache.pivot.wtk.Orientation;
import org.apache.pivot.wtk.Point;
import org.apache.pivot.wtk.Sheet;
import org.apache.pivot.wtk.SheetStateListener;
import org.apache.pivot.wtk.Theme;
import org.apache.pivot.wtk.Window;
import org.apache.pivot.wtk.Keyboard.KeyCode;
import org.apache.pivot.wtk.Mouse.Button;
import org.apache.pivot.wtk.effects.DropShadowDecorator;
import org.apache.pivot.wtk.effects.Transition;
import org.apache.pivot.wtk.effects.TransitionListener;
import org.apache.pivot.wtk.effects.TranslationDecorator;
import org.apache.pivot.wtk.effects.easing.Quadratic;
import org.apache.pivot.wtk.media.Image;
import org.apache.pivot.wtk.skin.WindowSkin;

/**
 * Sheet skin class.
 */
public class TerraSheetSkin extends WindowSkin implements SheetStateListener {
    public class OpenTransition extends Transition {
        private int dy = 0;

        public OpenTransition(boolean reversed) {
            super(stateTransitionDuration, stateTransitionRate, false, reversed);
        }

        @Override
        public void start(TransitionListener transitionListener) {
            Sheet sheet = (Sheet)getComponent();
            sheet.getDecorators().add(translationDecorator);

            dy = 0;

            super.start(transitionListener);
        }

        @Override
        public void stop() {
            Sheet sheet = (Sheet)getComponent();
            sheet.getDecorators().remove(translationDecorator);

            super.stop();
        }

        @Override
        public void update() {
            Sheet sheet = (Sheet)getComponent();

            float scale;
            if (isReversed()) {
                scale = easing.easeIn(getElapsedTime(), 1, -1, getDuration());
            } else {
                scale = easing.easeOut(getElapsedTime(), 1, -1, getDuration());
            }

            Display display = sheet.getDisplay();
            if (display != null) {
                Bounds decoratedBounds = sheet.getDecoratedBounds();
                display.repaint(decoratedBounds.x, decoratedBounds.y,
                    decoratedBounds.width, decoratedBounds.height + dy);

                Dimensions size = sheet.getPreferredSize();
                dy = -(int)(size.height * scale);
                translationDecorator.setY(dy);

                display.repaint(decoratedBounds.x, decoratedBounds.y,
                    decoratedBounds.width, decoratedBounds.height + dy);
            }
        }
    }

    /**
     * Resize button image.
     */
    protected class ResizeImage extends Image {
        public static final int ALPHA = 64;

        @Override
        public int getWidth() {
            return 5;
        }

        @Override
        public int getHeight() {
            return 5;
        }

        @Override
        public void paint(Graphics2D graphics) {
            graphics.setPaint(new Color(0, 0, 0, ALPHA));
            graphics.fillRect(3, 0, 2, 1);
            graphics.fillRect(0, 3, 2, 1);
            graphics.fillRect(3, 3, 2, 1);

            graphics.setPaint(new Color(borderColor.getRed(),
                borderColor.getGreen(), borderColor.getBlue(),
                ALPHA));
            graphics.fillRect(3, 1, 2, 1);
            graphics.fillRect(0, 4, 2, 1);
            graphics.fillRect(3, 4, 2, 1);
        }
    }

    private Image resizeImage = new ResizeImage();
    private ImageView resizeHandle = new ImageView(resizeImage);
    private Point resizeOffset = null;
    private Color borderColor;
    private Insets padding;
    private boolean resizable;

    private int stateTransitionDuration = DEFAULT_STATE_TRANSITION_DURATION;
    private int stateTransitionRate = DEFAULT_STATE_TRANSITION_RATE;

    private Color bevelColor;

    private OpenTransition openTransition = null;
    private Quadratic easing = new Quadratic();
    private TranslationDecorator translationDecorator = new TranslationDecorator(true);

    private ComponentListener ownerListener = new ComponentListener.Adapter() {
        @Override
        public void locationChanged(Component component, int previousX, int previousY) {
            alignToOwner();
        }

        @Override
        public void sizeChanged(Component component, int previousWidth, int previousHeight) {
            alignToOwner();
        }
    };

    private ContainerMouseListener displayMouseListener = new ContainerMouseListener() {
        @Override
        public boolean mouseMove(Container display, int x, int y) {
            return isMouseOverOwnerClientArea(display, x, y);
        }

        @Override
        public boolean mouseDown(Container display, Mouse.Button button, int x, int y) {
            boolean consumed = false;

            Sheet sheet = (Sheet)getComponent();
            if (isMouseOverOwnerClientArea(display, x, y)) {
                Window rootOwner = sheet.getRootOwner();
                rootOwner.moveToFront();
                consumed = true;

                Toolkit.getDefaultToolkit().beep();
            }

            return consumed;
        }

        @Override
        public boolean mouseUp(Container display, Mouse.Button button, int x, int y) {
            return isMouseOverOwnerClientArea(display, x, y);
        }

        @Override
        public boolean mouseWheel(Container display, Mouse.ScrollType scrollType,
            int scrollAmount, int wheelRotation, int x, int y) {
            return isMouseOverOwnerClientArea(display, x, y);
        }

        private boolean isMouseOverOwnerClientArea(Container display, int x, int y) {
            boolean mouseOverOwnerClientArea = false;

            Sheet sheet = (Sheet)getComponent();
            Component descendant = display.getDescendantAt(x, y);

            if (descendant != display) {
                Window window = descendant.getWindow();

                if (sheet.getOwner() == window) {
                    Bounds clientArea = window.getClientArea();

                    Point location = window.mapPointFromAncestor(display, x, y);
                    mouseOverOwnerClientArea = clientArea.contains(location);
                }
            }

            return mouseOverOwnerClientArea;
        }
    };

    private DropShadowDecorator dropShadowDecorator = null;

    private static final int DEFAULT_STATE_TRANSITION_DURATION = 300;
    private static final int DEFAULT_STATE_TRANSITION_RATE = 30;

    public TerraSheetSkin() {
        TerraTheme theme = (TerraTheme)Theme.getTheme();

        Color backgroundColor = theme.getColor(11);
        backgroundColor = new Color(backgroundColor.getRed(), backgroundColor.getGreen(),
            backgroundColor.getBlue(), 235);
        setBackgroundColor(backgroundColor);

        borderColor = theme.getColor(7);
        padding = new Insets(8);
        resizable = false;

        // Set the derived colors
        bevelColor = TerraTheme.darken(backgroundColor);
    }

    @Override
    public void install(Component component) {
        super.install(component);

        Sheet sheet = (Sheet)component;
        sheet.getSheetStateListeners().add(this);

        // Attach the drop-shadow decorator
        dropShadowDecorator = new DropShadowDecorator(3, 3, 3);
        sheet.getDecorators().add(dropShadowDecorator);

        sheet.add(resizeHandle);
    }

    @Override
    public int getPreferredWidth(int height) {
        int preferredWidth = 0;

        Sheet sheet = (Sheet)getComponent();
        Component content = sheet.getContent();

        if (content != null) {
            if (height != -1) {
                height = Math.max(height - (padding.top + padding.bottom + 2), 0);
            }

            preferredWidth = content.getPreferredWidth(height);
        }

        preferredWidth += (padding.left + padding.right + 2);

        return preferredWidth;
    }

    @Override
    public int getPreferredHeight(int width) {
        int preferredHeight = 0;

        Sheet sheet = (Sheet)getComponent();
        Component content = sheet.getContent();

        if (content != null) {
            if (width != -1) {
                width = Math.max(width - (padding.left + padding.right + 2), 0);
            }

            preferredHeight = content.getPreferredHeight(width);
        }

        preferredHeight += (padding.top + padding.bottom + 2);

        return preferredHeight;
    }

    @Override
    public Dimensions getPreferredSize() {
        int preferredWidth = 0;
        int preferredHeight = 0;

        Sheet sheet = (Sheet)getComponent();
        Component content = sheet.getContent();

        if (content != null) {
            Dimensions preferredContentSize = content.getPreferredSize();
            preferredWidth = preferredContentSize.width;
            preferredHeight = preferredContentSize.height;
        }

        preferredWidth += (padding.left + padding.right + 2);
        preferredHeight += (padding.top + padding.bottom + 2);

        Dimensions preferredSize = new Dimensions(preferredWidth, preferredHeight);

        return preferredSize;
    }

    @Override
    public void layout() {
        int width = getWidth();
        int height = getHeight();

        Sheet sheet = (Sheet)getComponent();

        // Size/position resize handle
        resizeHandle.setSize(resizeHandle.getPreferredSize());
        resizeHandle.setLocation(width - resizeHandle.getWidth() - 2,
            height - resizeHandle.getHeight() - 2);
        resizeHandle.setVisible(resizable
            && !sheet.isMaximized()
            && (sheet.isPreferredWidthSet()
                || sheet.isPreferredHeightSet()));

        Component content = sheet.getContent();
        if (content != null) {
            content.setLocation(padding.left + 1, padding.top + 1);

            int contentWidth = Math.max(width - (padding.left + padding.right + 2), 0);
            int contentHeight = Math.max(height - (padding.top + padding.bottom + 2), 0);
            content.setSize(contentWidth, contentHeight);
        }
    }

    @Override
    public void paint(Graphics2D graphics) {
        super.paint(graphics);

        int width = getWidth();
        int height = getHeight();

        graphics.setPaint(borderColor);
        GraphicsUtilities.drawRect(graphics, 0, 0, width, height);

        graphics.setPaint(bevelColor);
        GraphicsUtilities.drawLine(graphics, 1, height - 2, width - 2, Orientation.HORIZONTAL);
    }

    @Override
    public void sizeChanged(Component component, int previousWidth, int previousHeight) {
        super.sizeChanged(component, previousWidth, previousHeight);

        alignToOwner();
    }

    @Override
    public boolean mouseMove(Component component, int x, int y) {
        boolean consumed = super.mouseMove(component, x, y);

        if (Mouse.getCapturer() == component) {
            Sheet sheet = (Sheet)getComponent();
            Display display = sheet.getDisplay();

            Point location = sheet.mapPointToAncestor(display, x, y);

            // Pretend that the mouse can't move off screen (off the display)
            location = new Point(Math.min(Math.max(location.x, 0), display.getWidth() - 1),
                Math.min(Math.max(location.y, 0), display.getHeight() - 1));

            if (resizeOffset != null) {
                // Resize the frame
                int preferredWidth = -1;
                int preferredHeight = -1;
                boolean preferredWidthSet = component.isPreferredWidthSet();
                boolean preferredHeightSet = component.isPreferredHeightSet();
                boolean noPreferredSet = !(preferredWidthSet || preferredHeightSet);

                if (preferredWidthSet || noPreferredSet) {
                    preferredWidth = Math.max(location.x - sheet.getX() + resizeOffset.x, 2);
                    preferredWidth = Math.min(preferredWidth, sheet.getMaximumWidth());
                    preferredWidth = Math.max(preferredWidth, sheet.getMinimumWidth());
                }

                if (preferredHeightSet || noPreferredSet) {
                    preferredHeight = Math.max(location.y - sheet.getY() + resizeOffset.y,
                        resizeHandle.getHeight() + 7);
                    preferredHeight = Math.min(preferredHeight, sheet.getMaximumHeight());
                    preferredHeight = Math.max(preferredHeight, sheet.getMinimumHeight());
                }

                sheet.setPreferredSize(preferredWidth, preferredHeight);
            }
        } else {
            Cursor cursor = null;
            Bounds resizeHandleBounds = resizeHandle.getBounds();

            if (resizable && resizeHandleBounds.contains(x, y)) {
                boolean preferredWidthSet = component.isPreferredWidthSet();
                boolean preferredHeightSet = component.isPreferredHeightSet();

                if (preferredWidthSet
                    && preferredHeightSet) {
                    cursor = Cursor.RESIZE_SOUTH_EAST;
                } else if (preferredWidthSet) {
                    cursor = Cursor.RESIZE_EAST;
                } else if (preferredHeightSet) {
                    cursor = Cursor.RESIZE_SOUTH;
                } else {
                    cursor = Cursor.RESIZE_SOUTH_EAST;
                }
            }

            component.setCursor(cursor);
        }

        return consumed;
    }

    @Override
    public boolean mouseDown(Container container, Mouse.Button button, int x, int y) {
        Sheet sheet = (Sheet)container;
        if (!sheet.isTopMost()) {
            Window owner = sheet.getOwner();
            owner.moveToFront();
        }

        boolean consumed = super.mouseDown(container, button, x, y);

        if (resizable && button == Mouse.Button.LEFT) {
            Bounds resizeHandleBounds = resizeHandle.getBounds();

            if (resizeHandleBounds.contains(x, y)) {
                resizeOffset = new Point(getWidth() - x, getHeight() - y);
                Mouse.capture(container);
            }
        }

        return consumed;
    }

    @Override
    public boolean mouseUp(Component component, Button button, int x, int y) {
        boolean consumed = super.mouseUp(component, button, x, y);

        if (Mouse.getCapturer() == component) {
            resizeOffset = null;
            Mouse.release();
        }

        return consumed;
    }

    /**
     * {@link KeyCode#ENTER ENTER} Close the sheet with a 'result' of true.
* {@link KeyCode#ESCAPE ESCAPE} Close the sheet with a 'result' of false. */ @Override public boolean keyPressed(Component component, int keyCode, Keyboard.KeyLocation keyLocation) { boolean consumed = false; Sheet sheet = (Sheet)getComponent(); if (keyCode == Keyboard.KeyCode.ENTER) { sheet.close(true); consumed = true; } else if (keyCode == Keyboard.KeyCode.ESCAPE) { sheet.close(false); consumed = true; } else { consumed = super.keyPressed(component, keyCode, keyLocation); } return consumed; } @Override public void setBackgroundColor(Color backgroundColor) { super.setBackgroundColor(backgroundColor); bevelColor = TerraTheme.darken(backgroundColor); } public Color getBorderColor() { return borderColor; } public void setBorderColor(Color borderColor) { if (borderColor == null) { throw new IllegalArgumentException("borderColor is null."); } this.borderColor = borderColor; repaintComponent(); } public final void setBorderColor(String borderColor) { if (borderColor == null) { throw new IllegalArgumentException("borderColor is null."); } setBorderColor(GraphicsUtilities.decodeColor(borderColor)); } public Insets getPadding() { return padding; } public void setPadding(Insets padding) { if (padding == null) { throw new IllegalArgumentException("padding is null."); } this.padding = padding; invalidateComponent(); } public final void setPadding(Dictionary padding) { if (padding == null) { throw new IllegalArgumentException("padding is null."); } setPadding(new Insets(padding)); } public final void setPadding(int padding) { setPadding(new Insets(padding)); } public final void setPadding(Number padding) { if (padding == null) { throw new IllegalArgumentException("padding is null."); } setPadding(padding.intValue()); } public final void setPadding(String padding) { if (padding == null) { throw new IllegalArgumentException("padding is null."); } setPadding(Insets.decode(padding)); } public boolean isResizable() { return resizable; } public void setResizable(boolean resizable) { this.resizable = resizable; invalidateComponent(); } public int getStateTransitionDuration() { return stateTransitionDuration; } public void setStateTransitionDuration(int stateTransitionDuration) { this.stateTransitionDuration = stateTransitionDuration; } public int getStateTransitionRate() { return stateTransitionRate; } public void setStateTransitionRate(int stateTransitionRate) { this.stateTransitionRate = stateTransitionRate; } @Override public void windowOpened(Window window) { super.windowOpened(window); Display display = window.getDisplay(); display.getContainerMouseListeners().add(displayMouseListener); display.reenterMouse(); dropShadowDecorator.setShadowOpacity(DropShadowDecorator.DEFAULT_SHADOW_OPACITY); alignToOwner(); Window owner = window.getOwner(); owner.getComponentListeners().add(ownerListener); openTransition = new OpenTransition(false); openTransition.start(new TransitionListener() { @Override public void transitionCompleted(Transition transition) { openTransition = null; } }); if (!window.requestFocus()) { Component.clearFocus(); } } @Override public void windowClosed(Window window, Display display, Window owner) { super.windowClosed(window, display, owner); display.getContainerMouseListeners().remove(displayMouseListener); owner.getComponentListeners().remove(ownerListener); } @Override public Vote previewSheetClose(final Sheet sheet, final boolean result) { // Start a close transition, return false, and close the window // when the transition is complete Vote vote = Vote.APPROVE; // Don't start the transition if the sheet is being closed as a result // of the owner closing Window owner = sheet.getOwner(); if (!(owner.isClosing() || owner.isClosed())) { TransitionListener transitionListener = new TransitionListener() { @Override public void transitionCompleted(Transition transition) { sheet.close(result); openTransition = null; } }; if (openTransition == null) { // Start the close transition openTransition = new OpenTransition(true); openTransition.start(transitionListener); } else { // Reverse the open transition if (!openTransition.isReversed() && openTransition.isRunning()) { openTransition.reverse(transitionListener); } } vote = (openTransition != null && openTransition.isRunning()) ? Vote.DEFER : Vote.APPROVE; } return vote; } @Override public void sheetCloseVetoed(Sheet sheet, Vote reason) { if (reason == Vote.DENY && openTransition != null) { openTransition.stop(); openTransition = null; } } @Override public void sheetClosed(Sheet sheet) { // No-op } public void alignToOwner() { Sheet sheet = (Sheet)getComponent(); Window owner = sheet.getOwner(); Bounds clientArea = owner.getClientArea(); Point location = owner.mapPointToAncestor(owner.getDisplay(), clientArea.x, clientArea.y); sheet.setLocation(location.x + (clientArea.width - getWidth()) / 2, location.y); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy