Skip to content

Instantly share code, notes, and snippets.

@markusbkk
Last active August 11, 2024 12:19
Show Gist options
  • Select an option

  • Save markusbkk/2b72f616f6e0f6b77af818d2d82e2954 to your computer and use it in GitHub Desktop.

Select an option

Save markusbkk/2b72f616f6e0f6b77af818d2d82e2954 to your computer and use it in GitHub Desktop.

Revisions

  1. markusbkk renamed this gist Aug 11, 2024. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. markusbkk revised this gist Aug 11, 2024. 4 changed files with 407 additions and 0 deletions.
    136 changes: 136 additions & 0 deletions MainMenu.xaml
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,136 @@
    <ContentDialog
    x:Class="NScumm.MonoGame.Pages.MainMenu"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:NScumm.MonoGame.Pages"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local1="using:NScumm.MonoGame.ViewModels"
    mc:Ignorable="d" x:Uid="MainMenu"
    Title="Main Menu">
    <ContentDialog.DataContext>
    <local1:MenuViewModel/>
    </ContentDialog.DataContext>
    <ContentDialog.Template>
    <ControlTemplate TargetType="ContentDialog">
    <Border x:Name="Container">
    <Grid x:Name="LayoutRoot" Padding="20,5,20,0">
    <Grid.RowDefinitions>
    <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
    <Border x:Name="BackgroundElement"
    Background="{TemplateBinding Background}"
    FlowDirection="{TemplateBinding FlowDirection}"
    BorderThickness="{ThemeResource ContentDialogBorderWidth}"
    BorderBrush="{ThemeResource SystemControlForegroundAccentBrush}"
    MaxWidth="{TemplateBinding MaxWidth}"
    MaxHeight="{TemplateBinding MaxHeight}"
    MinWidth="{TemplateBinding MinWidth}"
    MinHeight="{TemplateBinding MinHeight}" >
    <Grid x:Name="DialogSpace" Padding="20,10,20,0" VerticalAlignment="Stretch">
    <Grid.RowDefinitions>
    <RowDefinition Height="*" />
    <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <ScrollViewer x:Name="ContentScrollViewer" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch"
    HorizontalScrollBarVisibility="Disabled"
    VerticalScrollBarVisibility="Disabled"
    ZoomMode="Disabled"
    Margin="{ThemeResource ContentDialogContentScrollViewerMargin}"
    IsTabStop="False">
    <Grid>
    <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <ContentControl x:Name="Title"
    Margin="{ThemeResource ContentDialogTitleMargin}"
    Content="{TemplateBinding Title}"
    ContentTemplate="{TemplateBinding TitleTemplate}"
    FontSize="20"
    FontFamily="Segoe UI"
    FontWeight="Normal"
    Foreground="{TemplateBinding Foreground}"
    HorizontalAlignment="Left"
    VerticalAlignment="Top"
    IsTabStop="False"
    MaxHeight="{ThemeResource ContentDialogTitleMaxHeight}" >
    <ContentControl.Template>
    <ControlTemplate TargetType="ContentControl">
    <ContentPresenter
    Content="{TemplateBinding Content}"
    MaxLines="2"
    TextWrapping="Wrap"
    ContentTemplate="{TemplateBinding ContentTemplate}"
    Margin="{TemplateBinding Padding}"
    ContentTransitions="{TemplateBinding ContentTransitions}"
    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
    VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
    </ControlTemplate>
    </ContentControl.Template>
    </ContentControl>
    <ContentPresenter x:Name="Content"
    ContentTemplate="{TemplateBinding ContentTemplate}"
    Content="{TemplateBinding Content}"
    FontSize="{ThemeResource ControlContentThemeFontSize}"
    FontFamily="{ThemeResource ContentControlThemeFontFamily}"
    Margin="{ThemeResource ContentDialogContentMargin}"
    Foreground="{TemplateBinding Foreground}"
    Grid.Row="1"
    TextWrapping="Wrap" />
    </Grid>
    </ScrollViewer>
    <Grid x:Name="CommandSpace" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Bottom">
    <Grid.ColumnDefinitions>
    <ColumnDefinition/>
    <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Border x:Name="Button1Host"
    Margin="{ThemeResource ContentDialogButton1HostMargin}"
    MinWidth="{ThemeResource ContentDialogButtonMinWidth}"
    MaxWidth="{ThemeResource ContentDialogButtonMaxWidth}"
    Height="{ThemeResource ContentDialogButtonHeight}"
    HorizontalAlignment="Stretch" />
    <Border x:Name="Button2Host"
    Margin="{ThemeResource ContentDialogButton2HostMargin}"
    MinWidth="{ThemeResource ContentDialogButtonMinWidth}"
    MaxWidth="{ThemeResource ContentDialogButtonMaxWidth}"
    Height="{ThemeResource ContentDialogButtonHeight}"
    Grid.Column="1"
    HorizontalAlignment="Stretch" />
    </Grid>
    </Grid>
    </Border>
    </Grid>
    </Border>
    </ControlTemplate>
    </ContentDialog.Template>
    <Grid>
    <StackPanel x:Name="MainStackPanel" Margin="0 20 0 0" Visibility="Visible">
    <Button x:Uid="MainMenuSaveButton" HorizontalAlignment="Stretch" Margin="5" Click="OnSave">Save</Button>
    <Button x:Uid="MainMenuLoadButton" HorizontalAlignment="Stretch" Margin="5" Click="OnLoad">Load</Button>
    <Button x:Uid="MainMenuResumeButton" HorizontalAlignment="Stretch" Margin="5" Click="OnResume">Resume</Button>
    <Button x:Uid="MainMenuExitButton" HorizontalAlignment="Stretch" Margin="5 20 5 5" Click="OnExit">Exit</Button>
    <MenuFlyoutSeparator></MenuFlyoutSeparator>
    <CheckBox x:Name="ShowFPScheckBox" Margin="5" IsChecked="{Binding ShowFPS, Mode=TwoWay}">FPS Counter</CheckBox>
    </StackPanel>
    <Grid x:Name="LoadStackPanel" Margin="0 20 0 0" Visibility="Collapsed">
    <Grid.RowDefinitions>
    <RowDefinition Height="*" />
    <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <ListView x:Name="LoadGameList" MinWidth="150" ItemClick="OnLoadGame" IsItemClickEnabled="True" />
    <Button x:Uid="MainMenuBackButton" Grid.Row="1" Margin="5 10 5 5" HorizontalAlignment="Stretch" Click="OnBack">Back</Button>
    </Grid>
    <Grid x:Name="SaveStackPanel" Margin="0 20 0 0" Visibility="Collapsed">
    <Grid.RowDefinitions>
    <RowDefinition Height="*" />
    <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <ListView x:Name="SaveGameList" ItemClick="OnSaveGame" MinWidth="150" IsItemClickEnabled="True" ScrollViewer.VerticalScrollBarVisibility="Auto" />
    <Button x:Uid="MainMenuBackButton" Grid.Row="1" Margin="5 10 5 5" HorizontalAlignment="Stretch" Click="OnBack">Back</Button>
    </Grid>
    </Grid>
    </ContentDialog>
    245 changes: 245 additions & 0 deletions MainMenuViewModel.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,245 @@
    using NScumm.Core;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using Windows.UI.Xaml.Controls;
    using Windows.ApplicationModel.Resources;
    using Windows.UI.Core;
    using System;
    using Windows.UI.Popups;
    using System.Threading.Tasks;
    using Windows.UI.Xaml.Media;
    using Windows.UI;
    using Windows.Storage;
    using Windows.UI.Xaml.Data;
    using Windows.UI.Xaml;
    using NScumm.MonoGame.ViewModels;
    using NScumm.MonoGame.Converters;

    namespace NScumm.MonoGame.Pages
    {
    public sealed partial class MainMenu : ContentDialog
    {
    public MenuViewModel ViewModel
    {
    get { return DataContext as MenuViewModel; }
    set { DataContext = value; }
    }

    private ResourceLoader _loader;

    internal ScummGame Game { get; set; }

    private IEngine Engine
    {
    get
    {
    var engine = Game.Services.GetService<IEngine>();
    return engine;
    }
    }

    public MainMenu()
    {
    InitializeComponent();

    _loader = ResourceLoader.GetForViewIndependentUse();
    }

    private void OnResume(object sender, Windows.UI.Xaml.RoutedEventArgs e)
    {
    Hide();
    }

    private void OnBack(object sender, Windows.UI.Xaml.RoutedEventArgs e)
    {
    Title = _loader.GetString("MainMenu_Title");
    MainStackPanel.Visibility = Windows.UI.Xaml.Visibility.Visible;
    LoadStackPanel.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
    SaveStackPanel.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
    }

    private async void OnLoad(object sender, Windows.UI.Xaml.RoutedEventArgs e)
    {
    Title = _loader.GetString("MainMenu_LoadTitle");
    LoadGameList.Items.Clear();
    var savegames = await GetSavegames();
    savegames.ForEach(LoadGameList.Items.Add);

    MainStackPanel.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
    LoadStackPanel.Visibility = Windows.UI.Xaml.Visibility.Visible;
    }

    private async void OnSave(object sender, Windows.UI.Xaml.RoutedEventArgs e)
    {
    Title = _loader.GetString("MainMenu_SaveTitle");
    SaveGameList.Items.Clear();
    var savegames = await GetSavegames();
    savegames.ForEach(SaveGameList.Items.Add);
    ListViewItem NewEntry = new ListViewItem();
    NewEntry.Content = _loader.GetString("New Entry");
    NewEntry.Background = new SolidColorBrush(Colors.DodgerBlue);
    NewEntry.Foreground = new SolidColorBrush(Colors.White);

    SaveGameList.Items.Add(NewEntry);

    MainStackPanel.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
    SaveStackPanel.Visibility = Windows.UI.Xaml.Visibility.Visible;
    }

    private void OnExit(object sender, Windows.UI.Xaml.RoutedEventArgs e)
    {
    ExitGame_Click();
    Hide();

    }
    private async void ExitGame_Click()
    {
    try
    {
    var messageDialog = new MessageDialog("Do you want to exit?");
    messageDialog.Commands.Add(new UICommand("Exit", new UICommandInvokedHandler(this.CommandInvokedHandler)));
    messageDialog.Commands.Add(new UICommand("Dismiss"));
    await messageDialog.ShowAsync();
    }
    catch (Exception ex)
    {

    }
    }
    private void CommandInvokedHandler(IUICommand command)
    {
    Engine.IsPaused = false;
    Engine.HasToQuit = true;
    App.isGameStarted = false;
    }
    private void OnLoadGame(object sender, ItemClickEventArgs e)
    {
    //string ObjectType = e.ClickedItem.GetType().Name;
    var index = ((ListView)sender).Items.IndexOf(e.ClickedItem);
    LoadGame(index);
    Hide();
    }

    private void OnSaveGame(object sender, ItemClickEventArgs e)
    {
    var index = ((ListView)sender).Items.IndexOf(e.ClickedItem);
    if(index == -1)
    {
    index = ((ListView)sender).Items.Count - 1;
    }
    SaveGame(index);
    Hide();
    }


    private async Task<List<string>> GetSavegames()
    {
    var local = Windows.Storage.ApplicationData.Current.LocalFolder;
    var spec = await local.CreateFolderAsync(Game.Settings.Game.Id, Windows.Storage.CreationCollisionOption.OpenIfExists);
    if (spec != null)
    {
    var dir = spec.Path;
    var pattern = string.Format("{0}*.sav", Game.Settings.Game.Id);
    return ServiceLocator.FileStorage.EnumerateFiles(dir, pattern).Select(Path.GetFileNameWithoutExtension).ToList();
    }
    return new List<string>();
    }

    private async Task<string> GetSaveGamePath(int index)
    {
    var local = Windows.Storage.ApplicationData.Current.LocalFolder;
    var spec = await local.CreateFolderAsync(Game.Settings.Game.Id, Windows.Storage.CreationCollisionOption.OpenIfExists);
    if (spec != null)
    {
    var indexResolve = "00";
    if(index > 9)
    {
    indexResolve = "0";
    }else if (index > 99)
    {
    indexResolve = "";
    }
    var dir = spec.Path;
    var filename = Path.Combine(dir, string.Format("{0} ({1}{2}).sav", Game.Settings.Game.Id, indexResolve ,(index + 1)));
    return filename;
    }
    return "";
    }

    private async void LoadGame(int index)
    {
    try
    {
    var filename = await GetSaveGamePath(index);
    if (filename.Length > 0)
    {
    Engine.Load(filename);

    GamePage.ShowTileHandler.Invoke(new string[] { "Load State", "State loaded successfully", $"Name: { Path.GetFileNameWithoutExtension(filename) }"}, EventArgs.Empty);
    }
    }catch(Exception ex)
    {
    ShowDialog(ex);
    }
    }

    private async void SaveGame(int index)
    {
    try
    {
    var filename = await GetSaveGamePath(index);
    if (filename.Length > 0)
    {
    Engine.Save(filename);
    GamePage.ShowTileHandler.Invoke(new string[] { "Save State", "Save state done", $"Name: { Path.GetFileNameWithoutExtension(filename) }" }, EventArgs.Empty);
    }
    }catch(Exception ex)
    {
    ShowDialog(ex);
    }
    }
    private async void ShowDialog(Exception message, bool log = false)
    {
    try
    {
    if (log)
    {
    var logFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("log.txt", CreationCollisionOption.OpenIfExists);
    await FileIO.AppendTextAsync(logFile, message.Message);
    }
    }
    catch (Exception ex)
    {

    }
    var messageDialog = new MessageDialog(message.Message);
    messageDialog.Commands.Add(new UICommand(
    "Close"));
    await messageDialog.ShowAsync();
    }
    private async void ShowDialog(string message, bool log = false)
    {
    try
    {
    if (log)
    {
    var logFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("log.txt", CreationCollisionOption.OpenIfExists);
    await FileIO.AppendTextAsync(logFile, message);
    }
    }
    catch (Exception ex)
    {

    }
    var messageDialog = new MessageDialog(message);
    messageDialog.Commands.Add(new UICommand(
    "Close"));
    await messageDialog.ShowAsync();
    }

    private void ShowFPS_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
    {
    }
    }
    }
    File renamed without changes.
    26 changes: 26 additions & 0 deletions ViewModel.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,26 @@
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;

    namespace NScumm.MonoGame.ViewModels
    {
    public abstract class ViewModel : INotifyPropertyChanged
    {
    public event PropertyChangedEventHandler PropertyChanged;

    public virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
    var eh = PropertyChanged;
    eh?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public virtual void RaiseAndSetIfChanged<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
    if (!EqualityComparer<T>.Default.Equals(field, value))
    {
    field = value;
    OnPropertyChanged(propertyName);
    }
    }
    }
    }
  3. markusbkk created this gist Aug 11, 2024.
    20 changes: 20 additions & 0 deletions MainMenuViewModel
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@
    namespace NScumm.MonoGame.ViewModels
    {
    public interface IMenuViewModel
    {
    void UpdateShowFPS();
    }
    public class MenuViewModel : ViewModel, IMenuViewModel
    {
    private bool _showFPS;

    public bool ShowFPS
    {
    get { return _showFPS; }
    set
    {
    RaiseAndSetIfChanged(ref _showFPS, value);
    }
    }
    }
    }