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

org.praxislive.ide.pxr.gui.Utils Maven / Gradle / Ivy

The newest version!
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 2020 Neil C Smith.
 * 
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 3 only, as
 * published by the Free Software Foundation.
 * 
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 3 for more details.
 * 
 * You should have received a copy of the GNU General Public License version 3
 * along with this work; if not, see http://www.gnu.org/licenses/
 * 
 * 
 * Please visit https://www.praxislive.org if you need additional information or
 * have any questions.
 */
package org.praxislive.ide.pxr.gui;

import java.awt.Component;
import java.awt.Rectangle;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JComponent;
import net.miginfocom.layout.CC;
import net.miginfocom.layout.IDEUtil;
import org.praxislive.core.ComponentAddress;
import org.praxislive.gui.Keys;
import org.praxislive.ide.model.ComponentProxy;
import org.praxislive.ide.model.ContainerProxy;
import org.praxislive.ide.model.RootProxy;

/**
 *
 */
class Utils {

    private final static Logger LOG = Logger.getLogger(Utils.class.getName());

    private Utils() {
    }

    static void enableAll(JComponent component) {
        component.setEnabled(true);
        for (Component cmp : component.getComponents()) {
            if (cmp instanceof JComponent) {
                enableAll((JComponent) cmp);
            }
        }
    }

    static void disableAll(JComponent component) {
        component.setEnabled(false);
        for (Component cmp : component.getComponents()) {
            if (cmp instanceof JComponent) {
                disableAll((JComponent) cmp);
            }
        }
    }

    static ComponentProxy findComponentProxy(RootProxy root, ComponentAddress address) {
        if (address.rootID().equals(root.getAddress().rootID())) {
            ComponentProxy comp = root;
            for (int i = 1; i < address.depth(); i++) {
                if (comp instanceof ContainerProxy) {
                    comp = ((ContainerProxy) comp).getChild(address.componentID(i));
                } else {
                    return null;
                }
            }
            return comp;
        }
        return null;
    }

    static ComponentProxy findComponentProxy(RootProxy root, JComponent cmp) {
        Object o = cmp.getClientProperty(Keys.Address);
        if (o instanceof ComponentAddress) {
            return findComponentProxy(root, (ComponentAddress) o);
        }
        return null;
    }

    static JComponent findAddressedComponent(Component cmp) {
        do {
            if (cmp instanceof JComponent
                    && ((JComponent) cmp).getClientProperty(Keys.Address) != null) {
                return (JComponent) cmp;
            }
            cmp = cmp.getParent();
        } while (cmp != null);
        return null;
    }

    static ComponentAddress getComponentAddress(Component cmp) {
        if (cmp instanceof JComponent) {
            Object ad = ((JComponent) cmp).getClientProperty(Keys.Address);
            if (ad instanceof ComponentAddress) {
                return (ComponentAddress) ad;
            }
        }
        return null;
    }

    static JComponent findContainerComponent(RootProxy root, Component cmp) {
        ComponentProxy pxy;
        do {
            cmp = findAddressedComponent(cmp);
            if (cmp instanceof JComponent) {
                pxy = findComponentProxy(root, (JComponent) cmp);
                if (pxy instanceof ContainerProxy) {
                    return (JComponent) cmp;
                }
            }
            cmp = cmp.getParent();
        } while (cmp != null);
        return null;
    }

    static int[] getGridPosition(JComponent container, JComponent component) {
        HashMap gridPositions = IDEUtil.getGridPositions(container);
        if (gridPositions == null) {
            return null;
        }
        int[] result = gridPositions.get(component);
        if (LOG.isLoggable(Level.FINE)) {
            if (result == null) {
                LOG.log(Level.FINE, "getGridPosition() null for {0} in {1}",
                        new Object[]{Utils.getComponentAddress(component),
                            Utils.getComponentAddress(container)});
            } else {
                LOG.log(Level.FINEST, "getGridPosition() is {0} for {1} in {2}",
                        new Object[]{Arrays.toString(result),
                            Utils.getComponentAddress(component),
                            Utils.getComponentAddress(container)});
            }
        }
        return result;
    }

    static int[] getGridPosition(JComponent container, int mouseX, int mouseY) {
        int[] result = new int[]{0, 0};
        int[][] axisSizes = IDEUtil.getColumnSizes(container);
        int[] sizes = axisSizes[1];
        int i = 0;
        int accum = 0;
        for (; i < sizes.length; i++) {
            accum += sizes[i];
            if (accum > mouseX) {
                break;
            }
        }
        i = i / 2;
        if (i < axisSizes[0].length) {
            result[0] = axisSizes[0][i];
        } else {
            result[0] = axisSizes[0][axisSizes[0].length - 1] + 1;
        }

        axisSizes = IDEUtil.getRowSizes(container);
        sizes = axisSizes[1];
        i = 0;
        accum = 0;
        for (; i < sizes.length; i++) {
            accum += sizes[i];
            if (accum > mouseY) {
                break;
            }
        }
        i = i / 2;
        if (i < axisSizes[0].length) {
            result[1] = axisSizes[0][i];
        } else {
            result[1] = axisSizes[0][axisSizes[0].length - 1] + 1;
        }

        return result;

    }

    static CC getConstraints(JComponent cmp) {
        Object val = cmp.getClientProperty(Keys.LayoutConstraint);
        if (val instanceof CC) {
            return (CC) val;
        } else {
            return new CC();
        }
    }

    static void updateConstraints(JComponent cmp, CC cc) {
        cmp.putClientProperty(Keys.LayoutConstraint, null);
        cmp.putClientProperty(Keys.LayoutConstraint, cc);
    }

    static boolean isOccupied(JComponent container, int x, int y, int width, int height, Set ignored) {
        return !requiredSpace(container, x, y, width, height, ignored).isEmpty();
    }

    static void ensureSpace(JComponent container, int x, int y, int width, int height, Set ignored, boolean vertical) {
        Rectangle space = requiredSpace(container, x, y, width, height, ignored);
        if (space.isEmpty()) {
            return;
        }
        if (vertical) {
            moveChildren(container, space.y, (y + height) - space.y, vertical, ignored);
        } else {
            moveChildren(container, space.x, (x + width) - space.x, vertical, ignored);
        }

    }

    static void move(RootProxy root, JComponent cmp, int dx, int dy) {
        changeBounds(root, cmp, dx, dy, 0, 0, Math.abs(dy) > Math.abs(dx));
    }
    
    static void resize(RootProxy root, JComponent cmp, int dSpanX, int dSpanY) {
        changeBounds(root, cmp, 0, 0, dSpanX, dSpanY, Math.abs(dSpanY) > Math.abs(dSpanX));
    }
    
    private static void changeBounds(RootProxy root, JComponent cmp, int dx, int dy, int dSpanX, int dSpanY, boolean vertical) {
        JComponent container = findContainerComponent(root, cmp);
        if (container == cmp) {
            container = findContainerComponent(root, cmp.getParent());
        }
        int[] pos = getGridPosition(container, cmp);
        if (pos == null) {
            LOG.log(Level.FINE, "changeBounds() can't find component {0} in {1}",
                    new Object[]{getComponentAddress(cmp),
                        getComponentAddress(container)});
            return;
        }
        CC cc = getConstraints(cmp);
        Set ignore = Collections.singleton(cmp);

        int x = pos[0] + dx;
        int y = pos[1] + dy;
        int spanX = pos[2] + dSpanX;
        int spanY = pos[3] + dSpanY;
        if (x < 0) {
            x = 0;
        }
        if (y < 0) {
            y = 0;
        }
        if (spanX < 1) {
            spanX = 1;
        }
        if (spanY < 1) {
            spanY = 1;
        }
        ensureSpace(container, x, y, spanX, spanY, ignore, vertical);
        cc.setCellX(x);
        cc.setCellY(y);
        cc.setSpanX(spanX);
        cc.setSpanY(spanY);
        updateConstraints(cmp, cc);
        compactGrid(container);
    }

    private static Rectangle requiredSpace(JComponent container,
            int x, int y, int width, int height,
            Set ignored) {
        HashMap gridPositions = IDEUtil.getGridPositions(container);
        if (gridPositions == null || gridPositions.isEmpty()) {
            return new Rectangle();
        }
        Rectangle space = new Rectangle(x, y, width, height);
        Rectangle intersection = new Rectangle();
        Rectangle cmp = new Rectangle();

        for (Map.Entry entry : gridPositions.entrySet()) {
            if (ignored.contains(entry.getKey())) {
                continue;
            }
            int[] pos = entry.getValue();
            if (pos.length < 4) {
                continue;
            }
            cmp.x = pos[0];
            cmp.y = pos[1];
            cmp.width = pos[2];
            cmp.height = pos[3];
            if (cmp.intersects(space)) {
                if (intersection.isEmpty()) {
                    intersection.setBounds(cmp);
                } else {
                    intersection.add(cmp);
                }
            }
        }
        return intersection;
    }

    static void compactGrid(JComponent container) {
        container.validate();
        compactAxis(container, true);
        compactAxis(container, false);
    }

    private static void compactAxis(JComponent container, boolean vertical) {
        int[] ax = getAxisIndexes(container, vertical);
        int exp = 0;
        int i = 0;
        int overall = 0;
        int cur;

        while (i < ax.length && overall < 50) {
            overall++;
            cur = ax[i];
            if (cur != exp) {
                if (LOG.isLoggable(Level.FINE)) {
                    String orientation = vertical ? "Rows" : "Columns";
                    LOG.fine("Found gap in " + orientation + " , removing " + exp + " -> " + cur);
                }
                moveChildren(container, cur, exp - cur, vertical, Collections.emptySet());
                ax = getAxisIndexes(container, vertical);
                exp = 0;
                i = 0;
            } else {
                i++;
                exp++;
            }
        }

    }

    private static int[] getAxisIndexes(JComponent container, boolean vertical) {
//        int[][] axes = vertical ? IDEUtil.getRowSizes(container) : IDEUtil.getColumnSizes(container);
//        if (axes == null) {
//            if (LOG.isLoggable(Level.FINE)) {
//                String orientation = vertical ? "Rows" : "Columns";
//                LOG.log(Level.FINE, "No {0} found in {1}", new Object[]{
//                            orientation, Utils.getComponentAddress(container)});
//            }
//            return new int[0];
//        } else {
//            if (LOG.isLoggable(Level.FINE)) {
//                String orientation = vertical ? "Rows" : "Columns";
//                LOG.log(Level.FINE, "Found {0} {1} in {2}", new Object[]{
//                            orientation, Arrays.toString(axes[0]), Utils.getComponentAddress(container)});
//            }
//            return axes[0];
//        }
        
        HashMap gridPositions = IDEUtil.getGridPositions(container);
        if (gridPositions == null || gridPositions.isEmpty()) {
            if (LOG.isLoggable(Level.FINE)) {
                String orientation = vertical ? "Rows" : "Columns";
                LOG.log(Level.FINE, "No {0} found in {1}", new Object[]{
                            orientation, Utils.getComponentAddress(container)});
            }
            return new int[0];
        }
        TreeSet axes = new TreeSet();
        int val, span;
        for (Map.Entry entry : gridPositions.entrySet()) {
            int[] pos = entry.getValue();
            if (pos.length < 4) {
                continue;
            }
            
            if (vertical) {
                val = pos[1];
                span = pos[3];
            } else {
                val = pos[0];
                span = pos[2];
            }
            
            axes.add(val);
            while (span > 1) {
                LOG.fine("Adding span");
                val++;
                axes.add(val);
                span--;
            }
        }
        
        int[] result = new int[axes.size()];
        int i = 0;
        for (Integer ax : axes) {
            result[i++] = ax;
        }
        if (LOG.isLoggable(Level.FINE)) {
            String orientation = vertical ? "Rows" : "Columns";
            LOG.log(Level.FINE, "Found {0} {1} in {2}", new Object[]{
                        orientation, Arrays.toString(result), Utils.getComponentAddress(container)});
        }
        return result;
    }

    private static void moveChildren(JComponent container, int from, int diff, boolean vertical, Set ignored) {

        for (Component cmp : container.getComponents()) {
            if (cmp instanceof JComponent) {
                if (ignored.contains(cmp)) {
                    continue;
                }
                JComponent jc = (JComponent) cmp;
                Object val = jc.getClientProperty(Keys.LayoutConstraint);
                if (val instanceof CC) {
                    CC cc = (CC) val;
                    if (vertical) {
                        int y = cc.getCellY();
                        if (y >= from) {
                            cc.setCellY(y + diff);
                        }
                    } else {
                        int x = cc.getCellX();
                        if (x >= from) {
                            cc.setCellX(x + diff);
                        }
                    }
                    jc.putClientProperty(Keys.LayoutConstraint, null);
                    jc.putClientProperty(Keys.LayoutConstraint, cc);
                }
            }
        }
        container.validate();

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy