r0x0r / pywebview

Build GUI for your Python program with JavaScript, HTML, and CSS

Home Page:https://pywebview.flowrl.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Modernize folderdialog?

huan1936 opened this issue · comments

commented

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?
Current dialog

Vista-style-dialog

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.

commented

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.

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()

commented

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.