Modernize folderdialog?
huan1936 opened this issue · comments
Specification
- pywebview version: 5.1
- operating system: Windows 10
- web renderer: edgechromium
Description
Could we possibly implement a more modern folder dialogue box? The one currently in use, originating from System.Windows.Forms, is notably cumbersome. Is it feasible to introduce a dialogue box styled after Vista?
Winforms does not provide modern dialogs, but it seems to be doable by implementing dialogs on top of IFileDialog https://learn.microsoft.com/en-us/windows/win32/shell/common-file-dialog
Microsoft.Win32.OpenFileDialog
namespace looks like a promising candidate as well https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.openfiledialog?view=windowsdesktop-8.0&viewFallbackFrom=net-5.0
Contributions welcomed.
Winforms does not provide modern dialogs, but it seems to be doable by implementing dialogs on top of IFileDialog https://learn.microsoft.com/en-us/windows/win32/shell/common-file-dialog
Microsoft.Win32.OpenFileDialog
namespace looks like a promising candidate as well https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.openfiledialog?view=windowsdesktop-8.0&viewFallbackFrom=net-5.0Contributions welcomed.
I implemented a VistaFolderDialog using IFileDialog and it worked successfully
Although he still has a little problem and can't unadvise
import threading
import clr
clr.AddReference('System.Windows.Forms')
clr.AddReference('System.Threading')
clr.AddReference('System.Reflection')
import System.Windows.Forms as WinForms
from System.Threading import ApartmentState, Thread, ThreadStart
from System.Reflection import Assembly, BindingFlags
from System import UInt32
class VistaDialog:
foldersFilter = "Folders|\n"
flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
windowsFormsAssembly = Assembly.LoadWithPartialName("System.Windows.Forms")
iFileDialogType = windowsFormsAssembly.GetType("System.Windows.Forms.FileDialogNative+IFileDialog")
OpenFileDialogType = windowsFormsAssembly.GetType("System.Windows.Forms.OpenFileDialog")
FileDialogType = windowsFormsAssembly.GetType("System.Windows.Forms.FileDialog")
createVistaDialogMethodInfo = OpenFileDialogType.GetMethod("CreateVistaDialog", flags)
onBeforeVistaDialogMethodInfo = OpenFileDialogType.GetMethod("OnBeforeVistaDialog", flags)
getOptionsMethodInfo = FileDialogType.GetMethod("GetOptions", flags)
setOptionsMethodInfo = iFileDialogType.GetMethod("SetOptions", flags)
fosPickFoldersBitFlag = windowsFormsAssembly.GetType(
"System.Windows.Forms.FileDialogNative+FOS").GetField("FOS_PICKFOLDERS").GetValue(None)
vistaDialogEventsConstructorInfo = windowsFormsAssembly.GetType(
"System.Windows.Forms.FileDialog+VistaDialogEvents").GetConstructor(flags, None, [FileDialogType], [])
adviseMethodInfo = iFileDialogType.GetMethod("Advise")
unadviseMethodInfo = iFileDialogType.GetMethod("Unadvise")
showMethodInfo = iFileDialogType.GetMethod("Show")
def show(self, initialDirectory=None, title=None):
openFileDialog = WinForms.OpenFileDialog()
openFileDialog.InitialDirectory = initialDirectory
openFileDialog.Title = title
openFileDialog.Filter = self.foldersFilter
openFileDialog.AddExtension = False
openFileDialog.CheckFileExists = False
openFileDialog.DereferenceLinks = True
openFileDialog.Multiselect = False
iFileDialog = VistaDialog.createVistaDialogMethodInfo.Invoke(openFileDialog, [])
VistaDialog.onBeforeVistaDialogMethodInfo.Invoke(openFileDialog, [iFileDialog])
options = VistaDialog.getOptionsMethodInfo.Invoke(openFileDialog, [])
options = options.op_BitwiseOr(VistaDialog.fosPickFoldersBitFlag)
VistaDialog.setOptionsMethodInfo.Invoke(iFileDialog, [options])
adviseParametersWithOutputConnectionToken = [
VistaDialog.vistaDialogEventsConstructorInfo.Invoke([openFileDialog]),
UInt32(0),
]
VistaDialog.adviseMethodInfo.Invoke(iFileDialog, adviseParametersWithOutputConnectionToken)
result = VistaDialog.showMethodInfo.Invoke(iFileDialog, [None])
if result == 0:
return openFileDialog.FileName
# Unable to unadvise because dwCookie is not updated
# VistaDialog.unadviseMethodInfo.Invoke(iFileDialog, [adviseParametersWithOutputConnectionToken[1]])
return ""
def show():
d = VistaDialog()
res = d.show()
print(res)
def create():
w = WinForms.Form()
w.Title = "Displaying"
threading.Thread(target=show).start()
WinForms.Application().Run(w)
thread = Thread(ThreadStart(create))
thread.SetApartmentState(ApartmentState.STA)
thread.Start()
thread.Join()
Originally advise should have returned dwCookie, but it did not, so unadvise could not be executed.
If you can clean it up, feel free to submit a PR.