fix: Carousel preview near completion

This commit is contained in:
lantzelot-swe 2023-12-01 15:06:08 +01:00
parent 14a22f0921
commit a91dfd9f8c
15 changed files with 229 additions and 67 deletions

View File

@ -389,6 +389,9 @@ public class ListPanel extends JPanel
public void setSelectedGameInGameList(String gameId)
{
//Called from Carousel, make sure no filtering is active
getFilterTextField().setText("");
List<GameListData> currentGameList = uiModel.getGameListModel().getCurrentGameList();
for (int i = 0; i < currentGameList.size(); i++)
{

View File

@ -162,6 +162,7 @@ public class MenuManager
private ScummVMModeInstallManager installScummVMManager;
private MainWindow mainWindow;
private int currentFavoritesCount = 10;
private CarouselPreviewDialog carouselPreviewDialog;
public MenuManager(final MainViewModel uiModel, MainWindow mainWindow)
{
@ -362,6 +363,7 @@ public class MenuManager
runGameItem.setEnabled(!uiModel.getInfoModel().getGamesFile().isEmpty());
refreshItem.setEnabled(okToEnable);
preferencesItem.setEnabled(okToEnable);
carouselPreviewItem.setEnabled(!uiModel.isNewGameSelected());
});
}
@ -445,8 +447,10 @@ public class MenuManager
JMenuItem getCarouselPreviewMenuItem()
{
carouselPreviewItem = new JMenuItem("Carousel preview...");
carouselPreviewItem = new JMenuItem("Carousel preview");
KeyStroke keyStrokeCarouselPreview = KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.CTRL_DOWN_MASK);
carouselPreviewItem.setAccelerator(keyStrokeCarouselPreview);
carouselPreviewItem.setMnemonic('W');
carouselPreviewItem.addActionListener(e -> showCarouselPreview());
return carouselPreviewItem;
}
@ -1724,11 +1728,24 @@ public class MenuManager
private void showCarouselPreview()
{
//TEST
CarouselPreviewDialog prefDialog = new CarouselPreviewDialog(this.mainWindow, this.uiModel);
prefDialog.pack();
prefDialog.setLocationRelativeTo(MainWindow.getInstance());
prefDialog.showDialog();
if (this.uiModel.getCurrentGameViewGameCount() < 10)
{
String message = "You can only preview the Carousel for gamelists that contain a minimum of 10 games.";
JOptionPane.showMessageDialog(this.mainWindow, message, "Carousel preview", JOptionPane.INFORMATION_MESSAGE);
}
else
{
if (carouselPreviewDialog == null || !carouselPreviewDialog.isShowing())
{
carouselPreviewDialog = new CarouselPreviewDialog(this.mainWindow, this.uiModel);
carouselPreviewDialog.pack();
carouselPreviewDialog.setLocationRelativeTo(MainWindow.getInstance());
carouselPreviewDialog.showDialog();
}
else
{
carouselPreviewDialog.requestFocus();
}
}
}
}

View File

@ -55,7 +55,7 @@ public class BackgroundPanel extends JPanel
gbc_coverPanel.gridy = 1;
add(getCoverPanel(), gbc_coverPanel);
GridBagConstraints gbc_panel = new GridBagConstraints();
gbc_panel.insets = new Insets(27, 37, 22, 10);
gbc_panel.insets = new Insets(29, 37, 22, 10);
gbc_panel.fill = GridBagConstraints.BOTH;
gbc_panel.anchor = GridBagConstraints.NORTHWEST;
gbc_panel.gridx = 0;
@ -69,7 +69,7 @@ public class BackgroundPanel extends JPanel
gbc_textPanel.gridy = 0;
add(getTextPanel(), gbc_textPanel);
setBackground("/se/lantz/carousel/Carousel1400x788-modified.png");
setBackground("/se/lantz/carousel/Carousel1400x788.png");
if (!Beans.isDesignTime())
{
@ -150,7 +150,7 @@ public class BackgroundPanel extends JPanel
try
{
image = ImageIO.read(imagefile);
Image newImage = image.getScaledInstance(694, 401, Image.SCALE_SMOOTH);
Image newImage = image.getScaledInstance(695, 402, Image.SCALE_SMOOTH);
getScreenshotLabel().setIcon(new ImageIcon(newImage));
}
catch (IOException e)

View File

@ -42,19 +42,18 @@ public class CarouselPreviewDialog extends BaseDialog
modelChanged();
}
}
private JButton getRunGameButton()
{
if (runGameButton == null)
{
runGameButton = new JButton("Run selected game");
runGameButton.setPreferredSize(null);
}
return runGameButton;
}
private void modelChanged()
{
setTitle("Carousel preview - " + uiModel.getSelectedGameView().getName());
@ -68,7 +67,7 @@ public class CarouselPreviewDialog extends BaseDialog
}
return panel;
}
@Override
public void setVisible(boolean visible)
{
@ -78,4 +77,12 @@ public class CarouselPreviewDialog extends BaseDialog
getBackgroundPanel().initialScroll();
}
}
@Override
public void dispose()
{
model.dispose();
super.dispose();
}
}

View File

@ -2,6 +2,7 @@ package se.lantz.gui.carousel;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
@ -73,6 +74,10 @@ public class CoverPanel extends JPanel
reloadScreens();
updateSelectedBorder();
});
model.addPropertyChangeListener(CarouselPreviewModel.CLEAR_SELECTION, e -> {
clearSelectedBorder();
});
//trigger once at startup
reloadScreens();
}
@ -242,11 +247,20 @@ public class CoverPanel extends JPanel
{
if (games.indexOf(model.getSelectedGame()) == i)
{
// logger.debug("Setting selected border to cover nr " + i);
((JLabel) panel.getComponent(i)).setBorder(BorderFactory.createLineBorder(Color.YELLOW, 5));
JLabel selectedLabel = (JLabel) panel.getComponent(i);
selectedLabel.setBorder(BorderFactory.createLineBorder(Color.YELLOW, 5));
loadScreenForBorder(selectedLabel, games.get(i));
}
}
}
private void clearSelectedBorder()
{
for (int i = 0; i < panel.getComponentCount(); i++)
{
((JLabel) panel.getComponent(i)).setBorder(null);
}
}
private void loadScreen(JLabel label, GameDetails game)
{
@ -263,6 +277,26 @@ public class CoverPanel extends JPanel
(label).setIcon(null);
}
}
private void loadScreenForBorder(JLabel label, GameDetails game)
{
String filename = game.getCover();
File imagefile = new File("./covers/" + filename);
try
{
BufferedImage image = ImageIO.read(imagefile);
Image newImage = image.getScaledInstance(125, 175, Image.SCALE_SMOOTH);
BufferedImage copyOfImage =
new BufferedImage(125, 175, BufferedImage.TYPE_INT_ARGB);
Graphics g = copyOfImage.createGraphics();
g.drawImage(newImage, 0, 0, null);
label.setIcon(new ImageIcon(copyOfImage.getSubimage(5, 5, 115, 165)));
}
catch (IOException e)
{
(label).setIcon(null);
}
}
public void scrollToPosition()
{

View File

@ -3,18 +3,16 @@ package se.lantz.gui.carousel;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.beans.Beans;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.border.LineBorder;
import javax.swing.SwingUtilities;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
@ -44,7 +42,7 @@ public class TextPanel extends JPanel
GridBagConstraints gbc_titleLabel = new GridBagConstraints();
gbc_titleLabel.gridwidth = 2;
gbc_titleLabel.weightx = 1.0;
gbc_titleLabel.insets = new Insets(17, 20, 5, 0);
gbc_titleLabel.insets = new Insets(17, 20, 6, 5);
gbc_titleLabel.anchor = GridBagConstraints.NORTHWEST;
gbc_titleLabel.fill = GridBagConstraints.HORIZONTAL;
gbc_titleLabel.gridx = 0;
@ -93,28 +91,55 @@ public class TextPanel extends JPanel
selectedGameChanged();
}
}
private void selectedGameChanged()
{
GameDetails selectedGame = model.getSelectedGame();
if (selectedGame != null)
{
getTitleLabel().setText(selectedGame.getTitle());
getTextPane().setText(selectedGame.getDescription());
getAuthorLabel().setText(selectedGame.getAuthor().isEmpty() ? "-" : selectedGame.getAuthor());
getComposerLabel().setText(selectedGame.getComposer().isEmpty() ? "-" : selectedGame.getComposer());
getGenreLabel().setText(genreMap.get(selectedGame.getGenre()));
getYearLabel().setText(selectedGame.getYear() + "");
SwingUtilities.invokeLater(() -> {
getTitleLabel().setText(truncateText(getTitleLabel(), selectedGame.getTitle(), 600));
getTextPane().setText(selectedGame.getDescription());
getAuthorLabel().setText(selectedGame.getAuthor().isEmpty()
? "-"
: truncateText(getAuthorLabel(), selectedGame.getAuthor(), 460));
getComposerLabel().setText(selectedGame.getComposer().isEmpty()
? "-"
: truncateText(getComposerLabel(), selectedGame.getComposer(), 460));
getGenreLabel().setText(genreMap.get(selectedGame.getGenre()));
getYearLabel().setText(selectedGame.getYear() + "");
});
}
}
private String truncateText(JLabel label, String text, int width)
{
String returnText = text;
Graphics graphics = label.getGraphics();
if (graphics != null)
{
int length = graphics.getFontMetrics().stringWidth(text);
while (length > width)
{
returnText = returnText.substring(0, returnText.length() - 1);
length = graphics.getFontMetrics().stringWidth(returnText + "...");
if (length <= (width))
{
returnText = returnText + "...";
}
}
}
return returnText;
}
private JLabel getTitleLabel()
{
if (titleLabel == null)
{
titleLabel = new JLabel("California Games");
titleLabel = new JLabel(" ");
titleLabel.setBackground(Color.ORANGE);
titleLabel.setFont(new Font("Microsoft Sans Serif", Font.BOLD, 37));
titleLabel.setFont(new Font("Microsoft Sans Serif", Font.BOLD, 36));
}
return titleLabel;
}
@ -127,10 +152,9 @@ public class TextPanel extends JPanel
textPane.setForeground(Color.WHITE);
textPane.setFont(new Font("Verdana", Font.PLAIN, 21));
textPane.setOpaque(false);
String text512 = "In Monty on the run the intrepid coal thief Monty Mole fled to the rocky island of Gibraltar. However, the Intermole agency is on to him, and his only hope of escape is to trek across Europe, collecting enough cash to buy the Greek island of Montos and live there in luxury.This is Monty's third game, and the structure is similar to the previous three. There are 80 screens each representing some area of Europe.There are many items to collect, the most important are Eurocheques for money and airplane tickets.";
String textCalGames = "Welcome to California. Hit the beaches, parks and streets, and go for trophies in half-pipe skateboarding, footbag, roller skating, surfing, BMX, bike racing and flying disk throwing. Read the full online instructions on how to compete in the most totally awesome games in the world.";
textPane
.setText(text512);
// String text512 = "In Monty on the run the intrepid coal thief Monty Mole fled to the rocky island of Gibraltar. However, the Intermole agency is on to him, and his only hope of escape is to trek across Europe, collecting enough cash to buy the Greek island of Montos and live there in luxury.This is Monty's third game, and the structure is similar to the previous three. There are 80 screens each representing some area of Europe.There are many items to collect, the most important are Eurocheques for money and airplane tickets.";
// String textCalGames = "Welcome to California. Hit the beaches, parks and streets, and go for trophies in half-pipe skateboarding, footbag, roller skating, surfing, BMX, bike racing and flying disk throwing. Read the full online instructions on how to compete in the most totally awesome games in the world.";
textPane.setText(" ");
changeLineSpacing(textPane, -0.12f, true);
textPane.setEditable(false);
textPane.setFocusable(false);
@ -138,44 +162,59 @@ public class TextPanel extends JPanel
}
return textPane;
}
/**
* Select all the text of a <code>JTextPane</code> first and then set the line spacing.
*
* @param the <code>JTextPane</code> to apply the change
* @param factor the factor of line spacing. For example, <code>1.0f</code>.
* @param replace whether the new <code>AttributeSet</code> should replace the old set. If set to <code>false</code>, will merge with the old one.
* @param replace whether the new <code>AttributeSet</code> should replace the old set. If set to <code>false</code>,
* will merge with the old one.
*/
private void changeLineSpacing(JTextPane pane, float factor, boolean replace) {
pane.selectAll();
MutableAttributeSet set = new SimpleAttributeSet(pane.getParagraphAttributes());
StyleConstants.setLineSpacing(set, factor);
pane.setParagraphAttributes(set, replace);
private void changeLineSpacing(JTextPane pane, float factor, boolean replace)
{
pane.selectAll();
MutableAttributeSet set = new SimpleAttributeSet(pane.getParagraphAttributes());
StyleConstants.setLineSpacing(set, factor);
pane.setParagraphAttributes(set, replace);
}
private JLabel getAuthorLabel() {
if (authorLabel == null) {
authorLabel = new JLabel("Epyx Games");
authorLabel.setFont(new Font("Microsoft Sans Serif", Font.BOLD, 22));
private JLabel getAuthorLabel()
{
if (authorLabel == null)
{
authorLabel = new JLabel();
authorLabel.setFont(new Font("Microsoft Sans Serif", Font.BOLD, 22));
}
return authorLabel;
}
private JLabel getComposerLabel() {
if (composerLabel == null) {
composerLabel = new JLabel("Epyx Games testing testing!");
composerLabel.setFont(new Font("Microsoft Sans Serif", Font.BOLD, 22));
private JLabel getComposerLabel()
{
if (composerLabel == null)
{
composerLabel = new JLabel(" ");
composerLabel.setFont(new Font("Microsoft Sans Serif", Font.BOLD, 22));
}
return composerLabel;
}
private JLabel getGenreLabel() {
if (genreLabel == null) {
genreLabel = new JLabel("Shoot'em Up");
genreLabel.setFont(new Font("Microsoft Sans Serif", Font.BOLD, 22));
private JLabel getGenreLabel()
{
if (genreLabel == null)
{
genreLabel = new JLabel(" ");
genreLabel.setFont(new Font("Microsoft Sans Serif", Font.BOLD, 22));
}
return genreLabel;
}
private JLabel getYearLabel() {
if (yearLabel == null) {
yearLabel = new JLabel("1987");
yearLabel.setFont(new Font("Microsoft Sans Serif", Font.BOLD, 22));
private JLabel getYearLabel()
{
if (yearLabel == null)
{
yearLabel = new JLabel(" ");
yearLabel.setFont(new Font("Microsoft Sans Serif", Font.BOLD, 22));
}
return yearLabel;
}

View File

@ -32,6 +32,11 @@ public abstract class AbstractModel
{
propertyChangeSupport.removePropertyChangeListener(listener);
}
public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener)
{
propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
}
protected void notifyChange()
{

View File

@ -88,6 +88,20 @@ public class GameListModel extends DefaultListModel<GameListData>
notifyChange();
}
@Override
public void addElement(GameListData gameData)
{
currentGameList.add(gameData);
super.addElement(gameData);
}
@Override
public GameListData remove(int index)
{
currentGameList.remove(index);
return super.remove(index);
}
public List<GameListData> getCurrentGameList()
{
return currentGameList;

View File

@ -349,6 +349,11 @@ public class MainViewModel extends AbstractModel
List<GameListData> gamesList = dbConnector.fetchGamesByView(gameView);
return readGameDetailsForExport(worker, gamesList);
}
public int getCurrentGameViewGameCount()
{
return dbConnector.fetchGamesByView(getSelectedGameView()).size();
}
public List<GameDetails> readGameDetailsForCarouselPreview()
{
@ -784,6 +789,11 @@ public class MainViewModel extends AbstractModel
//Update db title once done
infoModel.setTitleFromDb(infoModel.getTitle());
//Update currentGameDetails
this.currentGameDetails = dbConnector.getGameDetails(selectedData.getGameId());
//Update data in list model
// this.gameListModel.updateSavedGame(selectedData);
this.notifyChange("gameSaved");
return true;
}
return false;
@ -1082,6 +1092,10 @@ public class MainViewModel extends AbstractModel
favoritesView.setGameCount(--favoritesCount);
}
gameListModel.notifyChange();
if (gameViewModel.getSelectedItem().equals(favoritesView)) {
this.reloadCurrentGameView();
}
}
return favoritesCount;
}

View File

@ -1,5 +1,6 @@
package se.lantz.model.carousel;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
@ -18,18 +19,24 @@ public class CarouselPreviewModel extends AbstractModel
public static final String CLOSE_PREVIEW = "closePreview";
public static final String SELECTED_GAME = "selectedGame";
public static final String RELOAD_CAROUSEL = "reloadCarousel";
public static final String CLEAR_SELECTION = "clearSelection";
private MainViewModel mainModel;
//Keep track of 10 games as "scroll window" and update when scrolling or a new game is selected
private List<GameDetails> dataList = new ArrayList<>();
private GameDetails selectedGame = null;
private PropertyChangeListener selectedGameListViewListener = e -> SwingUtilities.invokeLater(() -> reloadCarousel());
private PropertyChangeListener selectedGameListener = e -> setSelectedGame(mainModel.getCurrentGameDetails());
private PropertyChangeListener gameSavedListener = e -> gameSaved();
public CarouselPreviewModel(MainViewModel mainModel)
{
this.mainModel = mainModel;
mainModel.addPropertyChangeListener("selectedGamelistView",
e -> SwingUtilities.invokeLater(() -> reloadCarousel()));
mainModel.addPropertyChangeListener("gameSelected", e -> setSelectedGame(mainModel.getCurrentGameDetails()));
mainModel.addPropertyChangeListener("selectedGamelistView", selectedGameListViewListener);
mainModel.addPropertyChangeListener("gameSelected", selectedGameListener);
mainModel.addPropertyChangeListener("gameSaved", gameSavedListener);
dataList = mainModel.readGameDetailsForCarouselPreview();
if (dataList.size() < 10)
{
@ -44,13 +51,14 @@ public class CarouselPreviewModel extends AbstractModel
private void reloadCarousel()
{
this.dataList = mainModel.readGameDetailsForCarouselPreview();
if (dataList.size() < 10)
if (mainModel.getCurrentGameViewGameCount() < 10)
{
this.notifyChange(CLOSE_PREVIEW);
}
else
{
this.dataList = mainModel.readGameDetailsForCarouselPreview();
this.notifyChange(RELOAD_CAROUSEL);
}
}
@ -76,13 +84,13 @@ public class CarouselPreviewModel extends AbstractModel
int index = dataList.indexOf(selectedGame) - 1;
return dataList.get(index).getGameId();
}
public String getGameIdForPageUp()
{
int index = dataList.indexOf(selectedGame) - 4;
return dataList.get(index).getGameId();
}
public String getGameIdForPageDown()
{
int index = dataList.indexOf(selectedGame) + 4;
@ -92,6 +100,13 @@ public class CarouselPreviewModel extends AbstractModel
public void setSelectedGame(GameDetails selectedGame)
{
logger.debug("setSelectedGame: " + selectedGame);
//A new game is added
if (selectedGame.getGameId().isEmpty())
{
this.notifyChange(CLEAR_SELECTION);
return;
}
//Update the entire data list
dataList = mainModel.readGameDetailsForCarouselPreview();
if (dataList.size() < 10)
@ -104,4 +119,18 @@ public class CarouselPreviewModel extends AbstractModel
this.notifyChange(SELECTED_GAME);
}
}
private void gameSaved()
{
GameDetails details = mainModel.getCurrentGameDetails();
setSelectedGame(details);
}
public void dispose()
{
mainModel.removePropertyChangeListener("selectedGamelistView", selectedGameListViewListener);
mainModel.removePropertyChangeListener("gameSelected", selectedGameListener);
mainModel.removePropertyChangeListener("gameSaved", gameSavedListener);
}
}

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 814 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB