Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necesary? Use Microsoft.Win32.OpenFolderDialog instead, it's built in and as a bonus it's the new style folder browser, not the old style crappy one.

Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;

namespace BfmeFoundationProject.AllInOneLauncher.Elements.Native;

internal static class FolderPicker
{
public static string? ShowDialog(Window owner, string title = "", string? initialPath = null)
{
IntPtr ownerHandle = new System.Windows.Interop.WindowInteropHelper(owner).Handle;
return InternalShowDialog(ownerHandle, title, initialPath);
}

private static string? InternalShowDialog(IntPtr ownerHandle, string title, string? initialPath)
{
// Constants
const int MAX_PATH = 260;
const uint BIF_RETURNONLYFSDIRS = 0x0001;
const uint BIF_NEWDIALOGSTYLE = 0x0040;
const int BFFM_INITIALIZED = 1;
const int BFFM_SETSELECTIONW = 0x0467; // WM_USER + 103 (Unicode)

BrowseCallbackProc callback = (hwnd, msg, lParam, lpData) =>
{
if (msg == BFFM_INITIALIZED && lpData != IntPtr.Zero)
{
// lpData contains pointer to initial path (Unicode)
SendMessage(hwnd, BFFM_SETSELECTIONW, new IntPtr(1), lpData);
}
return 0;
};

IntPtr pidl = IntPtr.Zero;
IntPtr pszDisplayName = IntPtr.Zero;
IntPtr initialPathPtr = IntPtr.Zero;
try
{
pszDisplayName = Marshal.AllocHGlobal(MAX_PATH * 2);

var bi = new BROWSEINFO
{
hwndOwner = ownerHandle,
pidlRoot = IntPtr.Zero,
pszDisplayName = pszDisplayName,
lpszTitle = title,
ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE,
lpfn = callback,
lParam = IntPtr.Zero,
iImage = 0
};

if (!string.IsNullOrWhiteSpace(initialPath))
{
initialPathPtr = Marshal.StringToHGlobalUni(initialPath);
bi.lParam = initialPathPtr;
}

pidl = SHBrowseForFolder(ref bi);
if (pidl == IntPtr.Zero)
return null;

var sb = new StringBuilder(MAX_PATH);
if (SHGetPathFromIDList(pidl, sb))
{
return sb.ToString();
}

return null;
}
finally
{
if (initialPathPtr != IntPtr.Zero) Marshal.FreeHGlobal(initialPathPtr);
if (pszDisplayName != IntPtr.Zero) Marshal.FreeHGlobal(pszDisplayName);
if (pidl != IntPtr.Zero) CoTaskMemFree(pidl);
}
}

#region Native
private delegate int BrowseCallbackProc(IntPtr hwnd, int msg, IntPtr lParam, IntPtr lpData);

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct BROWSEINFO
{
public IntPtr hwndOwner;
public IntPtr pidlRoot;
public IntPtr pszDisplayName;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpszTitle;
public uint ulFlags;
[MarshalAs(UnmanagedType.FunctionPtr)]
public BrowseCallbackProc lpfn;
public IntPtr lParam;
public int iImage;
}

[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr SHBrowseForFolder([In] ref BROWSEINFO lpbi);

[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
private static extern bool SHGetPathFromIDList(IntPtr pidl, [Out] StringBuilder pszPath);

[DllImport("ole32.dll", CharSet = CharSet.Unicode)]
private static extern void CoTaskMemFree(IntPtr pv);

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
#endregion
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,15 @@ private void OnLaunchGameClicked(object sender, EventArgs e)

private void OnInstallGameClicked(object sender, EventArgs e)
{
PopupVisualizer.ShowPopup(new InstallGamePopup(),
OnPopupSubmited: async (submittedData) => await BfmeSyncManager.InstallGame((BfmeGame)gameTabs.SelectedIndex, submittedData[0], submittedData[1]));
try
{
PopupVisualizer.ShowPopup(new InstallGamePopup(),
OnPopupSubmited: async (submittedData) => await BfmeSyncManager.InstallGame((BfmeGame)gameTabs.SelectedIndex, submittedData[0], submittedData[1]));
}
catch (Exception ex)
{
PopupVisualizer.ShowPopup(new ErrorPopup(ex));
}
}

private async void TabChanged(object sender, EventArgs e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
xmlns:generic="clr-namespace:BfmeFoundationProject.AllInOneLauncher.Elements.Generic"
mc:Ignorable="d"
Width="700" HorizontalAlignment="Center" VerticalAlignment="Center">

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
Expand All @@ -17,7 +18,7 @@
<RowDefinition Height="20"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Name="TextTitleInstall" Grid.Row="0" Text="{DynamicResource InstallGamePopupTitle}" Foreground="White" FontSize="20" FontWeight="Medium" HorizontalAlignment="Left" VerticalAlignment="Center"></TextBlock>
<TextBlock Name="TextTitleInstall" Grid.Row="0" Text="{DynamicResource InstallGamePopupTitle}" Foreground="White" FontSize="20" FontWeight="Medium" HorizontalAlignment="Left" VerticalAlignment="Center" />
<Rectangle Grid.Row="1" Fill="White" Opacity="0.2" Margin="0,10,0,0" VerticalAlignment="Top" Height="1"/>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
Expand Down Expand Up @@ -62,14 +63,36 @@
</elements:DropdownPicker.Options>
</elements:DropdownPicker>
<TextBlock Grid.Row="4" FontSize="14" FontWeight="SemiBold" Text="{DynamicResource InstallGamePopupLocation}" Foreground="white"/>
<generic:SmoothScrollViewer Grid.Row="6">
<StackPanel x:Name="locations"/>
</generic:SmoothScrollViewer>

<TextBlock Grid.Row="6" x:Name="SelectLocationError" FontSize="14" FontWeight="SemiBold" Padding="15,0" Text="{DynamicResource InstallGamePopupNoDrive}" Foreground="red" Visibility="Collapsed" />
<Grid Grid.Row="6" x:Name="SelectLocationArea" Visibility="Visible">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="5"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Margin="15,0,0,0">
<TextBlock Text="{DynamicResource InstallGamePopupLocationAdvanced}" HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="White" FontSize="14" />
<generic:Toggleable x:Name="SelectLocationAdvancedToggle" HorizontalAlignment="Right" VerticalAlignment="Center" OnToggledChanged="OnAdvancedSettingsSwitched" />
</Grid>

<StackPanel Grid.Row="2">
<generic:SmoothScrollViewer x:Name="SelectLocationList" Visibility="Visible">
<StackPanel x:Name="locations" />
</generic:SmoothScrollViewer>
<Button x:Name="SelectFolderButton" Click="OnSelectFolderClicked" HorizontalAlignment="Stretch" VerticalAlignment="Top" HorizontalContentAlignment="Left" Padding="15" Visibility="Collapsed">
<StackPanel>
<TextBlock x:Name="SelectedPathText" Text="" Foreground="White" FontSize="12" TextWrapping="Wrap"/>
<TextBlock x:Name="SelectedFreeSpaceText" Text="" Foreground="White" FontSize="11" Opacity="0.8"/>
</StackPanel>
</Button>
</StackPanel>
</Grid>
</Grid>
</Grid>
</Grid>
<StackPanel Grid.Row="4" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Grid.Column="0" Grid.Row="2" x:Name="ButtonAccept" Style="{StaticResource HiglightButton}" VerticalAlignment="Center" Click="OnInstallClicked" Width="150" Margin="0,0,10,0" Content="{DynamicResource GenericInstall}"/>
<Button Grid.Column="0" Grid.Row="2" x:Name="ButtonAccept" Style="{StaticResource HiglightButton}" VerticalAlignment="Center" Click="OnInstallClicked" Width="150" Margin="0,0,10,0" Content="{DynamicResource GenericInstall}" IsEnabled="false" />
<Button Grid.Column="1" Grid.Row="2" x:Name="ButtonCancel" Content="{DynamicResource GenericCancel}" VerticalAlignment="Center" Click="OnCancelClicked" Width="150"/>
</StackPanel>
</Grid>
Expand Down

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use this naming convention: "_nameOfSomething".
Instead, use: "NameOfSomething" for global values, and "nameOfSomething" for local values.

Original file line number Diff line number Diff line change
@@ -1,48 +1,113 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.IO;
using System.Windows;
using BfmeFoundationProject.AllInOneLauncher.Core.Utils;
using BfmeFoundationProject.AllInOneLauncher.Elements.Disk;
using BfmeFoundationProject.AllInOneLauncher.Elements.Generic;
using BfmeFoundationProject.AllInOneLauncher.Elements.Native;

namespace BfmeFoundationProject.AllInOneLauncher.Popups;

public partial class InstallGamePopup : PopupBody
{
private static readonly Dictionary<string, DriveInfo> Drives = DriveInfo.GetDrives().ToDictionary(x => x.RootDirectory.FullName);
private static readonly List<DriveInfo> _drives = DriveUtils.GetValidDrives();
private string _defaultPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);

public InstallGamePopup()
{
InitializeComponent();

locations.Children.Clear();
foreach (var drive in Drives.Values)
if (_drives.Count <= 0)
{
if (!drive.IsReady)
continue;

try
SelectLocationError.Visibility = Visibility.Visible;
SelectLocationArea.Visibility = Visibility.Collapsed;
}
else
{
locations.Children.Clear();
_drives.ForEach(drive =>
{
locations.Children.Add(new Selectable()
{
Title = new LibraryDriveHeader()
{
LibraryDriveName = string.Concat(drive.VolumeLabel, " (", drive.Name.Replace(@"\", ""), ")"),
LibraryDriveSize = $"{Math.Floor(drive.AvailableFreeSpace / Math.Pow(1024, 3)):N0} GB {App.Current.FindResource("GenericFree")}",
LibraryDriveSize = GetDriveFreeSpaceFormatted(drive),
Mini = true
},
Tag = drive.RootDirectory.FullName,
Tag = DriveUtils.GetDriveRootName(drive),
Margin = new Thickness(0, 0, 0, 5),
UseLayoutRounding = true,
SnapsToDevicePixels = true
});

});

SetSelectedPath(_defaultPath);
}
}

private void SetSelectedPath(string path)
{
string? _selectedPath = null;
var _selectedFreeText = string.Empty;
try
{
_selectedPath = DriveUtils.GetValidPath(path);
var drive = DriveUtils.GetDriveForPath(_drives, _selectedPath);
if (drive == null)
{
_selectedPath = DriveUtils.GetValidPath(_defaultPath);
drive = DriveUtils.GetDriveForPath(_drives, _selectedPath);
}
catch { }

if (drive != null)
{
_selectedFreeText = GetDriveFreeSpaceFormatted(drive);
}
}
catch { /* ignore errors here */ }

SelectedPathText.Text = _selectedPath;
SelectedFreeSpaceText.Text = _selectedFreeText;
ButtonAccept.IsEnabled = !string.IsNullOrWhiteSpace(_selectedPath);
}

private static string GetDriveFreeSpaceFormatted(DriveInfo drive)
{
return $"{Math.Floor(drive.AvailableFreeSpace / Math.Pow(1024, 3)):N0} GB {App.Current.FindResource("GenericFree")}";
}

private void OnSelectFolderClicked(object sender, RoutedEventArgs e)
{
try
{
var ownerWindow = Window.GetWindow(this);
var folderDialogTitle = (string)App.Current.FindResource("InstallGamePopupSelectFolder");
var _selectedPath = SelectedPathText.Text;
var selected = FolderPicker.ShowDialog(ownerWindow, folderDialogTitle, _selectedPath);
if (!string.IsNullOrWhiteSpace(selected))
SetSelectedPath(selected);
}
catch (Exception ex)
{
PopupVisualizer.ShowPopup(new ErrorPopup(ex));
Dismiss();
}
}

private void OnInstallClicked(object sender, RoutedEventArgs e) => Submit(LanguageDropdown.SelectedValue, Selectable.GetSelectedTagInContainer(locations)!.ToString()!);
private void OnAdvancedSettingsSwitched(object sender, EventArgs e)
{
var isActive = SelectLocationAdvancedToggle.IsToggled;
SelectLocationList.Visibility = isActive ? Visibility.Collapsed : Visibility.Visible;
SelectFolderButton.Visibility = isActive ? Visibility.Visible : Visibility.Collapsed;
}

private void OnInstallClicked(object sender, RoutedEventArgs e)
{
var language = LanguageDropdown.SelectedValue;
var path = (SelectLocationAdvancedToggle.IsToggled == true) ? SelectedPathText.Text : Selectable.GetSelectedTagInContainer(locations)!.ToString()!;
Submit(language, path);
}

private void OnCancelClicked(object sender, RoutedEventArgs e) => Dismiss();
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@
<system:String x:Key="InstallGamePopupTitle">تثبيت اللعبة</system:String>
<system:String x:Key="InstallGamePopupLanguage">اللغة</system:String>
<system:String x:Key="InstallGamePopupLocation">الموقع</system:String>
<system:String x:Key="InstallGamePopupLocationAdvanced">متقدم</system:String>
<system:String x:Key="InstallGamePopupSelectFolder">اختر مجلد التثبيت</system:String>
<system:String x:Key="InstallGamePopupNoDrive">لا توجد أقراص متاحة</system:String>

<!--===================== PackagePagePopup =====================-->
<system:String x:Key="PackagePagePopupAddToLibrary">إضافة إلى المكتبة</system:String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
<system:String x:Key="GenericYes">JA</system:String>
<system:String x:Key="GenericNo">NEIN</system:String>



<!--===================== MainWindow =====================-->
<system:String x:Key="MainWindowSingleplayerTab">EINZELSPIELER</system:String>
<system:String x:Key="MainWindowMultiplayerTab">Mehrspieler</system:String>
Expand Down Expand Up @@ -119,6 +117,9 @@
<system:String x:Key="InstallGamePopupTitle">SPIEL INSTALLIEREN</system:String>
<system:String x:Key="InstallGamePopupLanguage">Sprache</system:String>
<system:String x:Key="InstallGamePopupLocation">Standort</system:String>
<system:String x:Key="InstallGamePopupLocationAdvanced">Fortgeschritten</system:String>
<system:String x:Key="InstallGamePopupSelectFolder">Installationsordner wählen</system:String>
<system:String x:Key="InstallGamePopupNoDrive">Keine Laufwerke verfügbar</system:String>

<!--===================== PackagePagePopup =====================-->
<system:String x:Key="PackagePagePopupAddToLibrary">ZUR BIBLIOTHEK HINZUFÜGEN</system:String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
<system:String x:Key="GenericYes">YES</system:String>
<system:String x:Key="GenericNo">NO</system:String>



<!--===================== MainWindow =====================-->
<system:String x:Key="MainWindowSingleplayerTab">SINGLEPLAYER</system:String>
<system:String x:Key="MainWindowMultiplayerTab">MULTIPLAYER</system:String>
Expand Down Expand Up @@ -121,6 +119,9 @@
<system:String x:Key="InstallGamePopupTitle">INSTALL GAME</system:String>
<system:String x:Key="InstallGamePopupLanguage">Language</system:String>
<system:String x:Key="InstallGamePopupLocation">Location</system:String>
<system:String x:Key="InstallGamePopupLocationAdvanced">Advanced</system:String>
<system:String x:Key="InstallGamePopupSelectFolder">Select installation folder</system:String>
<system:String x:Key="InstallGamePopupNoDrive">No drives available</system:String>

<!--===================== PackagePagePopup =====================-->
<system:String x:Key="PackagePagePopupAddToLibrary">ADD TO LIBRARY</system:String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@
<system:String x:Key="InstallGamePopupTitle">INSTALAR JUEGO</system:String>
<system:String x:Key="InstallGamePopupLanguage">Idioma</system:String>
<system:String x:Key="InstallGamePopupLocation">Ubicación</system:String>
<system:String x:Key="InstallGamePopupLocationAdvanced">Avanzado</system:String>
<system:String x:Key="InstallGamePopupSelectFolder">Seleccionar carpeta de instalación</system:String>
<system:String x:Key="InstallGamePopupNoDrive">No hay unidades disponibles</system:String>

<!--===================== PackagePagePopup =====================-->
<system:String x:Key="PackagePagePopupAddToLibrary">AÑADIR A LA BIBLIOTECA</system:String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@
<system:String x:Key="InstallGamePopupTitle">INSTALLER LE JEU</system:String>
<system:String x:Key="InstallGamePopupLanguage">Langue</system:String>
<system:String x:Key="InstallGamePopupLocation">Emplacement</system:String>
<system:String x:Key="InstallGamePopupLocationAdvanced">Avancé</system:String>
<system:String x:Key="InstallGamePopupSelectFolder">Sélectionner le dossier d'installation</system:String>
<system:String x:Key="InstallGamePopupNoDrive">Aucun disque disponible</system:String>

<!--===================== PackagePagePopup =====================-->
<system:String x:Key="PackagePagePopupAddToLibrary">AJOUTER À LA BIBLIOTHÈQUE</system:String>
Expand Down
Loading