113 lines
3.8 KiB
Python
113 lines
3.8 KiB
Python
import asyncio
|
|
from unittest.mock import Mock
|
|
|
|
from System.Windows.Forms import Form, FormBorderStyle, FormWindowState
|
|
|
|
from .probe import BaseProbe
|
|
|
|
|
|
class WindowProbe(BaseProbe):
|
|
# Disabling the close button requires overriding a protected method
|
|
# (https://stackoverflow.com/a/7301828), which Python.NET doesn't support
|
|
# (https://github.com/pythonnet/pythonnet/issues/2192).
|
|
supports_closable = False
|
|
supports_minimizable = True
|
|
supports_move_while_hidden = True
|
|
supports_multiple_select_folder = False
|
|
supports_unminimize = True
|
|
|
|
def __init__(self, app, window):
|
|
super().__init__()
|
|
self.app = app
|
|
self.window = window
|
|
self.impl = window._impl
|
|
self.native = window._impl.native
|
|
assert isinstance(self.native, Form)
|
|
|
|
async def wait_for_window(self, message, minimize=False, full_screen=False):
|
|
await self.redraw(message)
|
|
|
|
def close(self):
|
|
self.native.Close()
|
|
|
|
@property
|
|
def content_size(self):
|
|
return (
|
|
self.native.ClientSize.Width / self.scale_factor,
|
|
self.native.ClientSize.Height / self.scale_factor,
|
|
)
|
|
|
|
@property
|
|
def is_full_screen(self):
|
|
return (
|
|
self.native.FormBorderStyle == getattr(FormBorderStyle, "None")
|
|
and self.native.WindowState == FormWindowState.Maximized
|
|
)
|
|
|
|
@property
|
|
def is_resizable(self):
|
|
return self.native.FormBorderStyle == FormBorderStyle.Sizable
|
|
|
|
@property
|
|
def is_minimizable(self):
|
|
return self.native.MinimizeBox
|
|
|
|
@property
|
|
def is_minimized(self):
|
|
return self.native.WindowState == FormWindowState.Minimized
|
|
|
|
def minimize(self):
|
|
if self.native.MinimizeBox:
|
|
self.native.WindowState = FormWindowState.Minimized
|
|
|
|
def unminimize(self):
|
|
self.native.WindowState = FormWindowState.Normal
|
|
|
|
async def _close_dialog(self, *args, **kwargs):
|
|
# Give the inner event loop a chance to start. The MessageBox dialogs work with
|
|
# sleep(0), but the file dialogs require it to be positive for some reason.
|
|
await asyncio.sleep(0.001)
|
|
|
|
await self.type_character(*args, **kwargs)
|
|
|
|
async def close_info_dialog(self, dialog):
|
|
await self._close_dialog("\n")
|
|
|
|
async def close_question_dialog(self, dialog, result):
|
|
await self._close_dialog("y" if result else "n")
|
|
|
|
async def close_confirm_dialog(self, dialog, result):
|
|
await self._close_dialog("\n" if result else "<esc>")
|
|
|
|
async def close_error_dialog(self, dialog):
|
|
await self._close_dialog("\n")
|
|
|
|
async def close_stack_trace_dialog(self, dialog, result):
|
|
await self._close_dialog(
|
|
{None: "o", True: "r", False: "q"}[result],
|
|
alt=True,
|
|
)
|
|
|
|
async def close_save_file_dialog(self, dialog, result):
|
|
await self._close_dialog("\n" if result else "<esc>")
|
|
|
|
async def close_open_file_dialog(self, dialog, result, multiple_select):
|
|
if result is None:
|
|
await self._close_dialog("<esc>")
|
|
else:
|
|
if multiple_select:
|
|
# native.FileNames is read-only, and a .NET property can't be replaced
|
|
# with a mock, so we have to mock the entire native dialog.
|
|
dialog.native.FileName = str(result[0]) # Enable the OK button
|
|
dialog.native = Mock()
|
|
dialog.native.FileNames = [str(path) for path in result]
|
|
else:
|
|
dialog.native.FileName = str(result)
|
|
await self._close_dialog("\n")
|
|
|
|
async def close_select_folder_dialog(self, dialog, result, multiple_select):
|
|
if result is None:
|
|
await self._close_dialog("<esc>")
|
|
else:
|
|
dialog.native.SelectedPath = str(result[-1] if multiple_select else result)
|
|
await self._close_dialog("\n")
|