/******************************************************************************* * Copyright (c) 2016 Alex Shapiro - github.com/shpralex * This program and the accompanying materials * are made available under the terms of the The MIT License (MIT) * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. *******************************************************************************/ package com.sproutlife.panel; import java.awt.BorderLayout; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.io.IOException; import java.net.URL; import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.swing.JComboBox; import javax.swing.JMenuBar; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.JSpinner; import javax.swing.JSplitPane; import javax.swing.JTabbedPane; import javax.swing.ToolTipManager; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.text.DefaultCaret; import com.sproutlife.GameController; import com.sproutlife.Settings; import com.sproutlife.action.ActionManager; import com.sproutlife.model.GameModel; import com.sproutlife.model.seed.SeedFactory.SeedType; import com.sproutlife.panel.gamepanel.ImageManager; import com.sproutlife.panel.gamepanel.ImageManager.LogoStyle; import com.sproutlife.panel.gamepanel.ScrollPanel; import com.sproutlife.panel.gamepanel.ScrollPanelController; import com.sproutlife.panel.gamepanel.handler.DefaultHandlerSet; import com.sproutlife.panel.gamepanel.handler.InteractionHandler; import com.sproutlife.renderer.BoardRenderer; import com.sproutlife.renderer.colors.ColorModel.BackgroundTheme; public class PanelController { GameController gameController; GameFrame gameFrame; JSplitPane splitPane; ActionManager actionManager; DisplayControlPanel displayControlPanel; RulesControlPanel settingsControlPanel; StatsPanel statsPanel; TipsPanel tipsPanel; JMenuBar gameMenu; GameToolbar gameToolbar; BoardRenderer boardRenderer; ScrollPanelController scrollController; ImageManager imageManager; InteractionHandler interactionHandler; BoardSizeHandler boardSizeHandler; public PanelController(GameController gameController) { this.gameController = gameController; this.actionManager = new ActionManager(this); this.interactionHandler = new InteractionHandler(this); interactionHandler.setHandlerSet(new DefaultHandlerSet(this)); this.scrollController = new ScrollPanelController(this); this.imageManager = new ImageManager(this, LogoStyle.Small); this.boardSizeHandler = new BoardSizeHandler(this); buildPanels(); initComponents(); addGeneralListeners(); addToolbarListeners(); addDisplayControlPanelListeners(); addRulesControlPanelListeners(); updateFromSettings(); } public GameController getGameController() { return gameController; }; /** * @return the actionManager */ public ActionManager getActionManager() { return actionManager; } public ScrollPanel getScrollPanel() { return getScrollController().getScrollPanel(); } public ScrollPanelController getScrollController() { return scrollController; } public ImageManager getImageManager() { return imageManager; } public InteractionHandler getInteractionHandler() { return interactionHandler; } public ReentrantReadWriteLock getInteractionLock() { return getGameController().getInteractionLock(); } public BoardRenderer getBoardRenderer() { return boardRenderer; } public GameModel getGameModel() { return getGameController().getGameModel(); } public GameFrame getGameFrame() { return gameFrame; } /** * @return the settingsControlPanel */ public RulesControlPanel getRulesControlPanel() { return settingsControlPanel; } /** * @return the displayControlPanel */ public DisplayControlPanel getDisplayControlPanel() { return displayControlPanel; } /** * @return the statsPanel */ public StatsPanel getStatsPanel() { return statsPanel; } /** * @return the tipsPanel */ public TipsPanel getTipsPanel() { return tipsPanel; } public JMenuBar getGameMenu() { return gameMenu; } public GameToolbar getGameToolbar() { return gameToolbar; } public Settings getSettings() { return getGameController().getSettings(); } public BoardSizeHandler getBoardSizeHandler() { return boardSizeHandler; } public void buildPanels() { gameFrame = new GameFrame(this); gameMenu = new GameMenu(this); gameFrame.setJMenuBar(gameMenu); gameToolbar = new GameToolbar(this); boardRenderer = new BoardRenderer(getGameModel()); displayControlPanel = new DisplayControlPanel(this); settingsControlPanel = new RulesControlPanel(this); statsPanel = new StatsPanel(this); tipsPanel = new TipsPanel(this); ScrollPanel scrollPanel = getScrollPanel(); JTabbedPane rightPane = new JTabbedPane(); rightPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); rightPane.addTab("Display", wrapInScrolPane(displayControlPanel)); rightPane.addTab("Rules", wrapInScrolPane(settingsControlPanel)); rightPane.addTab("Stats", statsPanel); rightPane.addTab("Tips", tipsPanel); JPanel gamePanel = new JPanel(new BorderLayout()); gamePanel.add(scrollPanel, BorderLayout.CENTER); gamePanel.add(gameToolbar, BorderLayout.NORTH); splitPane = new JSplitPane(); splitPane.setResizeWeight(1); splitPane.setOneTouchExpandable(true); splitPane.setLeftComponent(gamePanel); splitPane.setRightComponent(rightPane); gameFrame.add(splitPane); } public JScrollPane wrapInScrolPane(JPanel p) { JScrollPane sp = new JScrollPane(p); sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); sp.setBorder(null); return sp; } private void initComponents() { ToolTipManager.sharedInstance().setInitialDelay(0); gameFrame.setVisible(true); getGameToolbar().getZoomSlider().setValue(-4); getBoardSizeHandler().updateZoomValue(-4); getBoardSizeHandler().updateBoardSizeFromImageSize(getScrollPanel().getViewportSize()); getImageManager().setBackgroundColor(new Color(160,160,160)); initSeedTypeComboBox(); initStatsPanel(); loadTipText(); } private void initStatsPanel() { getStatsPanel().getStatsTextPane().setContentType("text/html"); getStatsPanel().getStatsTextPane().setText(getGameModel().getStats().getDisplayText()); //Fixes scroll issues on setText(), we want to keep the scroll position where it is DefaultCaret caret = (DefaultCaret) getStatsPanel().getStatsTextPane().getCaret(); caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE); } public void addGeneralListeners() { getScrollPanel().enableMouseListeners(); getBoardSizeHandler().addListeners(); } private void addToolbarListeners() { getGameToolbar().getStartPauseButton().setAction( getActionManager().getPlayGameAction()); getGameToolbar().getStepButton().addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { getInteractionLock().writeLock().lock(); getGameModel().performGameStep(); getInteractionLock().writeLock().unlock(); getImageManager().repaintNewImage(); } }); getGameToolbar().getResetButton().setAction( getActionManager().getResetGameAction()); getGameToolbar().getGifStopRecordingButton().setAction(getActionManager().getExportGifAction()); getGameToolbar().getZoomSlider().addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { int value = ((JSlider) e.getSource()).getValue(); getBoardSizeHandler().updateZoomValue(value); } }); getGameToolbar().getSpeedSlider().addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { int value = ((JSlider) e.getSource()).getValue(); updateSpeedValue(value); } }); } public void addDisplayControlPanelListeners() { DisplayControlPanel dcp = getDisplayControlPanel(); dcp.getChckbxCellLayer().addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { getBoardRenderer().setPaintCellLayer(getDisplayControlPanel().getChckbxCellLayer().isSelected()); getImageManager().repaintNewImage(); } }); dcp.getChckbxGenomeLayer().addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { getBoardRenderer().setPaintGenomeLayer(getDisplayControlPanel().getChckbxGenomeLayer().isSelected()); getImageManager().repaintNewImage(); } }); dcp.getChckbxOrgHeadLayer().addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { getBoardRenderer().setPaintHeadLayer(getDisplayControlPanel().getChckbxOrgHeadLayer().isSelected()); getImageManager().repaintNewImage(); } }); dcp.getChckbxOrgTailLayer().addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { getBoardRenderer().setPaintTailLayer(getDisplayControlPanel().getChckbxOrgTailLayer().isSelected()); getImageManager().repaintNewImage(); } }); dcp.getChckbxOutlineSeeds().addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { getBoardRenderer().setOutlineSeeds(getDisplayControlPanel().getChckbxOutlineSeeds().isSelected()); getImageManager().repaintNewImage(); } }); dcp.getSpinnerTailLength().addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent arg0) { int length = (int) ((JSpinner) arg0.getSource()).getValue(); getBoardRenderer().getTailRenderer().setTailLength(length); getImageManager().repaintNewImage(); } }); dcp.getChckbxAutoSplitColors().addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { boolean selected = getDisplayControlPanel().getChckbxAutoSplitColors().isSelected(); getSettings().set(Settings.AUTO_SPLIT_COLORS, selected); } }); ItemListener backgroundThemeListener = new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (dcp.getRdbtnBackgroundWhite().isSelected()) { getSettings().set(Settings.BACKGROUND_THEME, "white"); getBoardRenderer().getColorModel().setBackgroundTheme(BackgroundTheme.white); } else { getSettings().set(Settings.BACKGROUND_THEME, "black"); getBoardRenderer().getColorModel().setBackgroundTheme(BackgroundTheme.black); } getImageManager().repaintNewImage(); } }; dcp.getRdbtnBackgroundBlack().addItemListener(backgroundThemeListener); dcp.getRdbtnBackgroundWhite().addItemListener(backgroundThemeListener); ItemListener colorModeListener = new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (dcp.getRdbtnMultiColorMode().isSelected()) { getSettings().set(Settings.COLOR_MODEL, "AngleColorModel"); } else { getSettings().set(Settings.COLOR_MODEL, "SplitColorModel"); } getImageManager().repaintNewImage(); } }; dcp.getRdbtnMultiColorMode().addItemListener(colorModeListener); dcp.getRdbtnTriColorMode().addItemListener(colorModeListener); dcp.getSpinnerColorScheme().addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent arg0) { int value = (int) ((JSpinner) arg0.getSource()).getValue(); int hue = (value-1)%6*60; int hueRange = ((value-1)/6)*100+100; getSettings().set(Settings.PRIMARY_HUE_DEGREES, hue); getSettings().set(Settings.HUE_RANGE, hueRange); getImageManager().repaintNewImage(); } }); } public void addRulesControlPanelListeners() { ItemListener lifeModeListener = new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (getRulesControlPanel().getRdbtnFriendly().isSelected()) { getSettings().set(Settings.LIFE_MODE, "friendly"); } else if(getRulesControlPanel().getRdbtnCompetitive1().isSelected()) { getSettings().set(Settings.LIFE_MODE, "competitive1"); } else { getSettings().set(Settings.LIFE_MODE, "competitive2"); } } }; getRulesControlPanel().getRdbtnFriendly().addItemListener(lifeModeListener); getRulesControlPanel().getRdbtnCompetitive2().addItemListener(lifeModeListener); getRulesControlPanel().getRdbtnCompetitive1().addItemListener(lifeModeListener); getRulesControlPanel().getSeedTypeComboBox().addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { getSettings().set(Settings.SEED_TYPE, getRulesControlPanel().getSeedTypeComboBox().getSelectedItem().toString()); } }); getRulesControlPanel().getMaxLifespanSpinner().addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent arg0) { getSettings().set(Settings.MAX_LIFESPAN,((JSpinner) arg0.getSource()).getValue()); } }); getRulesControlPanel().getTargetAgeSpinner().addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent arg0) { getSettings().set(Settings.TARGET_LIFESPAN,((JSpinner) arg0.getSource()).getValue()); } }); getRulesControlPanel().getChildOneParentAgeSpinner().addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent arg0) { getSettings().set(Settings.CHILD_ONE_PARENT_AGE,((JSpinner) arg0.getSource()).getValue()); } }); getRulesControlPanel().getChildTwoParentAgeSpinner().addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent arg0) { getSettings().set(Settings.CHILD_TWO_PARENT_AGE,((JSpinner) arg0.getSource()).getValue()); } }); getRulesControlPanel().getChildThreeParentAgeSpinner().addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent arg0) { getSettings().set(Settings.CHILD_THREE_PARENT_AGE,((JSpinner) arg0.getSource()).getValue()); } }); getRulesControlPanel().getMutationRateSpinner().addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent arg0) { getSettings().set(Settings.MUTATION_RATE,((JSpinner) arg0.getSource()).getValue()); } }); ItemListener sproutModeListener = new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (getRulesControlPanel().getRdbtnVisual().isSelected()) { getSettings().set(Settings.SPROUT_DELAYED_MODE, true); } else if(getRulesControlPanel().getRdbtnFunctional().isSelected()) { getSettings().set(Settings.SPROUT_DELAYED_MODE, false); } } }; getRulesControlPanel().getRdbtnVisual().addItemListener(sproutModeListener); getRulesControlPanel().getRdbtnFunctional().addItemListener(sproutModeListener); } public void updateFromSettings() { getRulesControlPanel().getMaxLifespanSpinner().setValue( getSettings().getInt(Settings.MAX_LIFESPAN)); getRulesControlPanel().getTargetAgeSpinner().setValue( getSettings().getInt(Settings.TARGET_LIFESPAN)); getRulesControlPanel().getChildOneParentAgeSpinner().setValue( getSettings().getInt(Settings.CHILD_ONE_PARENT_AGE)); getRulesControlPanel().getChildTwoParentAgeSpinner().setValue( getSettings().getInt(Settings.CHILD_TWO_PARENT_AGE)); getRulesControlPanel().getChildThreeParentAgeSpinner().setValue( getSettings().getInt(Settings.CHILD_THREE_PARENT_AGE)); getRulesControlPanel().getMutationRateSpinner().setValue( getSettings().getInt(Settings.MUTATION_RATE)); getDisplayControlPanel().getSpinnerColorScheme().setValue( 1 + getSettings().getInt(Settings.PRIMARY_HUE_DEGREES)/60 + (getSettings().getInt(Settings.HUE_RANGE)/100-1)%2*6); switch (getSettings().getString(Settings.LIFE_MODE)) { case "friendly": getRulesControlPanel().getRdbtnFriendly().setSelected(true); break; case "competitive1": getRulesControlPanel().getRdbtnCompetitive1().setSelected(true); break; default: getRulesControlPanel().getRdbtnCompetitive2().setSelected(true); } switch (getSettings().getString(Settings.BACKGROUND_THEME)) { case "white": getDisplayControlPanel().getRdbtnBackgroundWhite().setSelected(true); break; default: getDisplayControlPanel().getRdbtnBackgroundBlack().setSelected(true); } switch (getSettings().getString(Settings.COLOR_MODEL)) { case "AngleColorModel": getDisplayControlPanel().getRdbtnMultiColorMode().setSelected(true); break; default: getDisplayControlPanel().getRdbtnTriColorMode().setSelected(true); } SeedType seedType = SeedType.get(getSettings().getString(Settings.SEED_TYPE)); JComboBox<SeedType> seedCb = (JComboBox<SeedType>) getRulesControlPanel().getSeedTypeComboBox(); if (seedType!=null) { seedCb.setSelectedItem(seedType); } if (getSettings().getBoolean(Settings.SPROUT_DELAYED_MODE)) { getRulesControlPanel().getRdbtnVisual().setSelected(true); } else { getRulesControlPanel().getRdbtnFunctional().setSelected(true); } } public void setPlayGame(boolean playGame) { getActionManager().getPlayGameAction().setPlayGame(playGame); } public void loadTipText() { try { URL tipsURL = TipsPanel.class.getResource("/tips/tips.html"); getTipsPanel().getTipsTextPane().setPage(tipsURL); } catch (IOException e) { //This error probably means that /resources/ was not added to the build path e.printStackTrace(); } } public void initSeedTypeComboBox() { JComboBox<SeedType> seedCb = (JComboBox<SeedType>) getRulesControlPanel().getSeedTypeComboBox(); seedCb.addItem(SeedType.Bentline1_RPentomino); seedCb.addItem(SeedType.Bentline1m_RPentomino); seedCb.addItem(SeedType.Bentline_U3x3); seedCb.addItem(SeedType.Bentline1_Plus); seedCb.addItem(SeedType.Square2_RPentomino); seedCb.addItem(SeedType.L2_RPentomino); seedCb.addItem(SeedType.L2B1_RPentomino); seedCb.addItem(SeedType.Boxlid3_RPentomino); seedCb.addItem(SeedType.Boxhat_RPentomino); seedCb.addItem(SeedType.OnebitB1_RPentomino); seedCb.addItem(SeedType.Glider_RPentomino); seedCb.addItem(SeedType.RPentomino_RPentomino); } public void updateSpeedValue(int value) { int sleepDelay = 1; int iterations = 1; switch (value) { case -5 : sleepDelay = 500; break; case -4 : sleepDelay = 100; break; case -3 : sleepDelay = 20; break; case -2 : sleepDelay = 8; break; case -1 : sleepDelay = 4; break; case 0 : break; case 1 : iterations = 2; break; case 2 : iterations = 4; break; case 3 : iterations = 8; break; case 4 : iterations = 16; break; case 5 : iterations = 32; break; } getGameModel().getGameThread().setSleepDelay(sleepDelay); getGameModel().getGameThread().setIterationsPerEvent(iterations); } }