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

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

The newest version!
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2024 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.event.ActionEvent;
import java.beans.PropertyVetoException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToggleButton;
import javax.swing.KeyStroke;
import javax.swing.OverlayLayout;
import javax.swing.SwingUtilities;
import org.praxislive.ide.model.RootProxy;
import org.praxislive.ide.pxr.spi.RootEditor;

import static org.praxislive.ide.pxr.gui.LayoutAction.Type.*;

import org.openide.actions.DeleteAction;
import org.openide.explorer.ExplorerManager;
import org.openide.explorer.ExplorerUtils;
import org.openide.filesystems.FileObject;
import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.openide.util.Utilities;
import org.openide.util.actions.Presenter;
import org.openide.util.lookup.AbstractLookup;
import org.openide.util.lookup.InstanceContent;
import org.openide.util.lookup.Lookups;
import org.openide.util.lookup.ProxyLookup;
import org.praxislive.ide.model.ContainerProxy;
import org.praxislive.ide.project.api.PraxisProject;
import org.praxislive.ide.pxr.api.ComponentPalette;

/**
 *
 */
public class GuiEditor implements RootEditor {

    private final PraxisProject project;
    private final FileObject file;
    private final RootProxy root;
    private final GuiHelper helper;
    private final JComponent editorComponent;
    private final JLayeredPane layeredPane;
    private final ExplorerManager em;
    private final Lookup lookup;
    private final InstanceContent content;
    private final ComponentPalette palette;

    private EditAction editAction;
    private EditLayer editLayer;
    private Action[] actions;

    GuiEditor(PraxisProject project, FileObject file, RootProxy root) {
        this.project = project;
        this.file = file;
        this.root = root;
        this.helper = project.getLookup().lookup(GuiHelper.class);
        em = new ExplorerManager();
        em.setRootContext(root.getNodeDelegate());
        // init components
        layeredPane = new JLayeredPane();
        layeredPane.setLayout(new OverlayLayout(layeredPane));
        layeredPane.setFocusable(true);
        editorComponent = new JScrollPane(layeredPane);

        initActions(layeredPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT),
                layeredPane.getActionMap());
        content = new InstanceContent();
        palette = ComponentPalette.create(root instanceof ContainerProxy ? (ContainerProxy) root : null);
        lookup = new ProxyLookup(
                ExplorerUtils.createLookup(em, layeredPane.getActionMap()),
                Lookups.fixed(palette.controller()),
                new AbstractLookup(content));
    }

    private void initActions(InputMap inputMap, ActionMap actionMap) {
        actions = new Action[13];
        editAction = new EditAction();
        actions[0] = editAction;
        actions[1] = null;
        actions[2] = new LayoutAction(MoveLeft);
        actions[3] = new LayoutAction(MoveUp);
        actions[4] = new LayoutAction(MoveDown);
        actions[5] = new LayoutAction(MoveRight);
        actions[6] = null;
        actions[7] = new LayoutAction(IncreaseSpanX);
        actions[8] = new LayoutAction(DecreaseSpanX);
        actions[9] = new LayoutAction(IncreaseSpanY);
        actions[10] = new LayoutAction(DecreaseSpanY);
        actions[11] = null;
        actions[12] = DeleteAction.get(DeleteAction.class);
        inputMap.put(Utilities.stringToKey("D-e"), "edit");
        actionMap.put("edit", editAction);
        inputMap.put(KeyStroke.getKeyStroke("LEFT"), "move-left");
        actionMap.put("move-left", actions[2]);
        inputMap.put(KeyStroke.getKeyStroke("UP"), "move-up");
        actionMap.put("move-up", actions[3]);
        inputMap.put(KeyStroke.getKeyStroke("DOWN"), "move-down");
        actionMap.put("move-down", actions[4]);
        inputMap.put(KeyStroke.getKeyStroke("RIGHT"), "move-right");
        actionMap.put("move-right", actions[5]);
        inputMap.put(KeyStroke.getKeyStroke("shift RIGHT"), "increase-span-x");
        actionMap.put("increase-span-x", actions[7]);
        inputMap.put(KeyStroke.getKeyStroke("shift LEFT"), "decrease-span-x");
        actionMap.put("decrease-span-x", actions[8]);
        inputMap.put(KeyStroke.getKeyStroke("shift DOWN"), "increase-span-y");
        actionMap.put("increase-span-y", actions[9]);
        inputMap.put(KeyStroke.getKeyStroke("shift UP"), "decrease-span-y");
        actionMap.put("decrease-span-y", actions[10]);

        actionMap.put(DeleteAction.get(DeleteAction.class).getActionMapKey(),
                ExplorerUtils.actionDelete(em, true));

    }

    @Override
    public JComponent getEditorComponent() {
        return editorComponent;
    }

    @Override
    public Lookup getLookup() {
        return lookup;
    }

    @Override
    public List getActions() {
        return Stream.of(actions).toList();
    }

    RootProxy getRoot() {
        return root;
    }

    GuiHelper getHelper() {
        return helper;
    }

    void setSelected(Node[] nodes) throws Exception {
        em.setSelectedNodes(nodes);
    }

    void performPreferredAction() {
        Node[] nodes = em.getSelectedNodes();
        if (nodes.length == 1) {
            nodes[0].getPreferredAction().actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, ""));
        }
    }

    void addRootPanel(JPanel panel) {
        layeredPane.add(panel, JLayeredPane.DEFAULT_LAYER);
        editLayer = new EditLayer(this, panel);
        layeredPane.add(editLayer, JLayeredPane.PALETTE_LAYER);
        content.add(editLayer);
//        if (((ContainerProxy)root).getChildIDs().length == 0) {
//            editLayer.setVisible(true);
//        }
        editAction.setEnabled(true);
    }

    void removeRootPanel(JPanel panel) {
        layeredPane.remove(panel);
        layeredPane.remove(editLayer);
        content.remove(editLayer);
        editAction.setEnabled(false);
        editLayer = null;
        try {
            em.setSelectedNodes(new Node[0]);
        } catch (PropertyVetoException ex) {
            Logger.getLogger(GuiEditor.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void componentActivated() {
        DockableGuiRoot r = DockableGuiRoot.find(project, root.getAddress().rootID());
        if (r != null) {
            r.requestConnect(this);
        }
    }

    @Override
    public void dispose() {
        palette.dispose();
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                DockableGuiRoot r = DockableGuiRoot.find(project, root.getAddress().rootID());
                if (r != null) {
                    r.requestDisconnect(GuiEditor.this);
                }
            }
        });

    }

    private class EditAction extends AbstractAction implements Presenter.Toolbar {

        private JToggleButton button;

        private EditAction() {
            super("Edit");
            putValue(SELECTED_KEY, Boolean.FALSE);
            setEnabled(false);
        }

        @Override
        public void actionPerformed(ActionEvent ae) {
            if (editLayer.isVisible()) {
                editLayer.setVisible(false);
                putValue(SELECTED_KEY, Boolean.FALSE);
            } else {
                editLayer.setVisible(true);
                putValue(SELECTED_KEY, Boolean.TRUE);
            }
        }

        @Override
        public void setEnabled(boolean enabled) {
            super.setEnabled(enabled);
            if (enabled) {
                putValue(SELECTED_KEY, editLayer.isVisible());
            } else {
                putValue(SELECTED_KEY, Boolean.FALSE);
            }
        }

        @Override
        public Component getToolbarPresenter() {
            if (button == null) {
                button = new JToggleButton(this);
            }
            return button;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy