/*
* This file is part of the Illarion project.
*
* Copyright © 2015 - Illarion e.V.
*
* Illarion is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Illarion 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 for more details.
*/
package illarion.mapedit.gui;
import illarion.common.config.ConfigChangedEvent;
import illarion.mapedit.Lang;
import illarion.mapedit.MapEditor;
import illarion.mapedit.events.HistoryEvent;
import illarion.mapedit.events.map.MapPositionEvent;
import illarion.mapedit.events.menu.MapLoadErrorEvent;
import illarion.mapedit.events.menu.MapSaveEvent;
import illarion.mapedit.events.menu.ShowHelpDialogEvent;
import illarion.mapedit.events.util.ActionEventPublisher;
import illarion.mapedit.gui.actions.BandClickAction;
import illarion.mapedit.gui.menubands.ClipboardBand;
import illarion.mapedit.gui.menubands.ToolBand;
import illarion.mapedit.gui.menubands.ViewBand;
import illarion.mapedit.gui.menubands.ZoomBand;
import illarion.mapedit.gui.util.MapKeyEventPostProcessor;
import illarion.mapedit.render.RendererManager;
import illarion.mapedit.resource.loaders.ImageLoader;
import org.bushe.swing.event.EventBus;
import org.bushe.swing.event.EventSubscriber;
import org.bushe.swing.event.annotation.AnnotationProcessor;
import org.bushe.swing.event.annotation.EventTopicSubscriber;
import org.jdesktop.swingx.JXLabel;
import org.jdesktop.swingx.JXStatusBar;
import org.jdesktop.swingx.JXStatusBar.Constraint;
import org.pushingpixels.flamingo.api.common.AbstractCommandButton;
import org.pushingpixels.flamingo.api.common.JCommandButton;
import org.pushingpixels.flamingo.api.common.JCommandToggleButton;
import org.pushingpixels.flamingo.api.ribbon.JRibbonFrame;
import org.pushingpixels.flamingo.api.ribbon.RibbonTask;
import javax.annotation.Nonnull;
import javax.swing.*;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowListener;
/**
* This class represents the whole gui.
*
* @author Tim
*/
public class MainFrame extends JRibbonFrame {
private static final Dimension WINDOW_SIZE = new Dimension(1000, 700);
private static MainFrame instance;
@Nonnull
private final MapPanel mapPanel;
@Nonnull
private final ToolSettingsPanel settingsPanel;
private final OpenMapPanel filePanel;
public MainFrame(GuiController controller) {
AnnotationProcessor.process(this);
mapPanel = new MapPanel(controller);
settingsPanel = new ToolSettingsPanel();
filePanel = new OpenMapPanel();
instance = this;
}
public void initialize(WindowListener controller) {
addWindowListener(controller);
setTitle(MapEditor.APPLICATION.getApplicationIdentifier());
setSize(getSavedDimension());
getRibbon().setApplicationMenu(new MainMenu());
getRibbon().configureHelp(ImageLoader.getResizableIcon("help"),
new ActionEventPublisher(new ShowHelpDialogEvent()));
JCommandButton saveBtn = getCommandButton("gui.mainmenu.Save", "filesave", KeyEvent.VK_S, "Save");
JCommandButton undoBtn = getCommandButton("gui.history.undo", "undo", KeyEvent.VK_Z, "Undo");
JCommandButton redoBtn = getCommandButton("gui.history.redo", "redo", KeyEvent.VK_Z, "Redo", true);
saveBtn.addActionListener(new ActionEventPublisher(new MapSaveEvent()));
undoBtn.addActionListener(new ActionEventPublisher(new HistoryEvent(true)));
redoBtn.addActionListener(new ActionEventPublisher(new HistoryEvent(false)));
getRibbon().addTaskbarComponent(saveBtn);
getRibbon().addTaskbarComponent(undoBtn);
getRibbon().addTaskbarComponent(redoBtn);
filePanel.init();
add(mapPanel, BorderLayout.CENTER);
add(settingsPanel, BorderLayout.EAST);
add(filePanel, BorderLayout.LINE_START);
RibbonTask task = new RibbonTask(Lang.getMsg("gui.mainframe.ribbon"), new ClipboardBand(),
new ViewBand(getRendererManager()), new ZoomBand(), new ToolBand());
JXStatusBar status = new JXStatusBar();
status.setResizeHandleEnabled(true);
JXLabel mapCoordinates = new JXLabel();
JXLabel worldCoordinates = new JXLabel();
EventBus.subscribeStrongly(MapPositionEvent.class, new EventSubscriber<MapPositionEvent>() {
@Override
public void onEvent(@Nonnull MapPositionEvent event) {
mapCoordinates.setText(Lang.getMsg("gui.mainframe.status.mapCoord") + ": " + event.getMapX() +
',' + event.getMapY());
worldCoordinates.setText(Lang.getMsg("gui.mainframe.status.worldCoord") + ": " + event.getWorldX() +
',' + event.getWorldY() + ',' + event.getWorldZ());
}
});
status.add(mapCoordinates, new Constraint());
status.add(worldCoordinates, new Constraint());
add(status, BorderLayout.SOUTH);
getRibbon().addTask(task);
setApplicationIcon(ImageLoader.getResizableIcon("mapedit64"));
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor(new MapKeyEventPostProcessor());
}
public static MainFrame getInstance() {
return instance;
}
public void exit() {
dispose();
MapEditorConfig.getInstance().setWindowSize(getSize());
}
@Nonnull
public RendererManager getRendererManager() {
return mapPanel.getRenderManager();
}
@Nonnull
private static Dimension getSavedDimension() {
Dimension windowSize = MapEditorConfig.getInstance().getWindowSize();
if ((windowSize.getHeight() == 0) || (windowSize.getWidth() == 0)) {
return WINDOW_SIZE;
}
return windowSize;
}
@Nonnull
public static JCommandToggleButton getToggleButton(
String text, String icon, int key, String action) {
return getToggleButton(text, icon, key, action, false);
}
@Nonnull
public static JCommandToggleButton getToggleButton(
String text, String icon, int key, String action, boolean shift) {
JCommandToggleButton commandButton = new JCommandToggleButton(Lang.getMsg(text),
ImageLoader.getResizableIcon(icon));
setAction(commandButton, key, action, shift);
return commandButton;
}
private static void setAction(
@Nonnull AbstractCommandButton commandButton,
int key,
String action,
boolean shift) {
InputMap input = commandButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
int mask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
if (shift) {
mask |= InputEvent.SHIFT_DOWN_MASK;
}
KeyStroke enter = KeyStroke.getKeyStroke(key, mask);
input.put(enter, action);
commandButton.getActionMap().put(action, new BandClickAction(commandButton));
}
@Nonnull
public static JCommandButton getCommandButton(
String text, String icon, int key, String action) {
return getCommandButton(text, icon, key, action, false);
}
@Nonnull
public static JCommandButton getCommandButton(
String text, String icon, int key, String action, boolean shift) {
JCommandButton commandButton = new JCommandButton(Lang.getMsg(text), ImageLoader.getResizableIcon(icon));
setAction(commandButton, key, action, shift);
return commandButton;
}
@org.bushe.swing.event.annotation.EventSubscriber
public void onMapLoadError(@Nonnull MapLoadErrorEvent e) {
showMessageDialog(e.getMessage());
}
public static void showMessageDialog(String message) {
JOptionPane.showMessageDialog(getInstance(), message, Lang.getMsg("gui.error"), JOptionPane.ERROR_MESSAGE,
ImageLoader.getImageIcon("messagebox_critical"));
}
@EventTopicSubscriber(topic = MapEditorConfig.USED_LANGUAGE)
public void onConfigLanguageChanged(String topic, @Nonnull ConfigChangedEvent event) {
JOptionPane optionPane = new JOptionPane(Lang.getMsg("gui.LocaleChanged"),
JOptionPane.INFORMATION_MESSAGE);
JDialog dialog = optionPane.createDialog(getInstance(), Lang.getMsg("gui.info"));
dialog.setAlwaysOnTop(true);
dialog.setVisible(true);
}
@EventTopicSubscriber(topic = MapEditorConfig.USE_WINDOW_DECO)
public void onConfigWindowDecoChanged(String topic, @Nonnull ConfigChangedEvent event) {
JOptionPane optionPane = new JOptionPane(Lang.getMsg("gui.LocaleChanged"),
JOptionPane.INFORMATION_MESSAGE);
JDialog dialog = optionPane.createDialog(getInstance(), Lang.getMsg("gui.info"));
dialog.setAlwaysOnTop(true);
dialog.setVisible(true);
}
}