Skip to content

Commit 4561d7f

Browse files
committed
[region-editor] Transition to Tcl/Tk for GUI #181
This allows for better control over window events and makes input handling more consistent across platforms. It also allows better customization, for example, the system undo/redo commands are used instead of key binds. There is still much work to do, however this is a good starting point, and has feature parity with the existing editor.
1 parent e4eb41f commit 4561d7f

File tree

6 files changed

+894
-343
lines changed

6 files changed

+894
-343
lines changed

dist/requirements_windows.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
numpy
55
opencv-python==4.10.0.84
66
opencv-contrib-python==4.10.0.84
7+
pillow
78
platformdirs
89
pyinstaller>=6.0
910
pytest

dvr_scan/platform.py

Lines changed: 62 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -13,57 +13,35 @@
1313
Provides logging and platform/operating system compatibility.
1414
"""
1515

16+
import importlib
1617
import logging
1718
import os
19+
import platform
1820
import subprocess
1921
import sys
20-
from contextlib import contextmanager
2122
from typing import AnyStr, Optional
2223

2324
try:
2425
import screeninfo
2526
except ImportError:
2627
screeninfo = None
2728

28-
from scenedetect.platform import get_and_create_path
29+
from scenedetect.platform import get_and_create_path, get_ffmpeg_version, get_mkvmerge_version
2930

3031
try:
3132
import tkinter
3233
except ImportError:
3334
tkinter = None
3435

3536

36-
# TODO(v1.7): Figure out how to make icon work on Linux. Might need a PNG version.
37-
def get_icon_path() -> str:
38-
if getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS"):
39-
app_folder = os.path.abspath(os.path.dirname(sys.executable))
40-
icon_path = os.path.join(app_folder, "dvr-scan.ico")
41-
if os.path.exists(icon_path):
42-
return icon_path
43-
# TODO(v1.7): Figure out how to properly get icon path in the package. The folder will be
44-
# different in the final Windows build, may have to check if this is a frozen instance or not.
45-
# Also need to ensure the icon is included in the package metadata.
46-
# For Python distributions, may have to put dvr-scan.ico with the source files, and use
47-
# os.path.dirname(sys.modules[package].__file__) (or just __file__ here).
48-
for path in ("dvr-scan.ico", "dist/dvr-scan.ico"):
49-
if os.path.exists(path):
50-
return path
51-
return ""
52-
53-
5437
HAS_TKINTER = tkinter is not None
5538

56-
IS_WINDOWS = os.name == "nt"
57-
58-
if IS_WINDOWS:
59-
import ctypes
60-
import ctypes.wintypes
61-
6239

6340
def get_min_screen_bounds():
6441
"""Attempts to get the minimum screen resolution of all monitors using the `screeninfo` package.
6542
Returns the minimum of all monitor's heights and widths with 10% padding, or None if the package
6643
is unavailable."""
44+
# TODO: See if we can replace this with Tkinter (`winfo_screenwidth` / `winfo_screenheight`).
6745
if screeninfo is not None:
6846
try:
6947
monitors = screeninfo.get_monitors()
@@ -157,42 +135,61 @@ def get_filename(path: AnyStr, include_extension: bool) -> AnyStr:
157135
return filename
158136

159137

160-
def set_icon(window_name: str):
161-
icon_path = get_icon_path()
162-
if not icon_path:
163-
return
164-
if not IS_WINDOWS:
165-
# TODO: Set icon on Linux/OSX.
166-
return
167-
SendMessage = ctypes.windll.user32.SendMessageW
168-
FindWindow = ctypes.windll.user32.FindWindowW
169-
LoadImage = ctypes.windll.user32.LoadImageW
170-
SetFocus = ctypes.windll.user32.SetFocus
171-
IMAGE_ICON = 1
172-
ICON_SMALL = 1
173-
ICON_BIG = 1
174-
LR_LOADFROMFILE = 0x00000010
175-
LR_CREATEDIBSECTION = 0x00002000
176-
WM_SETICON = 0x0080
177-
hWnd = FindWindow(None, window_name)
178-
hIcon = LoadImage(None, icon_path, IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION)
179-
SendMessage(hWnd, WM_SETICON, ICON_SMALL, hIcon)
180-
SendMessage(hWnd, WM_SETICON, ICON_BIG, hIcon)
181-
SetFocus(hWnd)
182-
183-
184-
@contextmanager
185-
def temp_tk_window():
186-
"""Used to provide a hidden Tk window as a root for pop-up dialog boxes to return focus to
187-
main region window when destroyed."""
188-
root = tkinter.Tk()
189-
try:
190-
root.withdraw()
191-
# TODO: Set icon on Linux/OSX.
192-
if IS_WINDOWS:
193-
icon_path = get_icon_path()
194-
if icon_path:
195-
root.iconbitmap(os.path.abspath(icon_path))
196-
yield root
197-
finally:
198-
root.destroy()
138+
def get_system_version_info() -> str:
139+
"""Get the system's operating system, Python, packages, and external tool versions.
140+
Useful for debugging or filing bug reports.
141+
142+
Used for the `scenedetect version -a` command.
143+
"""
144+
output_template = "{:<8} {}"
145+
line_separator = "-" * 40
146+
not_found_str = "Not Installed"
147+
out_lines = []
148+
149+
# System (Python, OS)
150+
out_lines += ["System Info", line_separator]
151+
out_lines += [
152+
output_template.format(name, version)
153+
for name, version in (
154+
("OS:", "%s" % platform.platform()),
155+
("Python:", "%s %s" % (platform.python_implementation(), platform.python_version())),
156+
("Arch:", " + ".join(platform.architecture())),
157+
)
158+
]
159+
output_template = "{:<16} {}"
160+
161+
# Third-Party Packages
162+
out_lines += ["", "Packages", line_separator]
163+
third_party_packages = (
164+
"cv2",
165+
"dvr_scan",
166+
"numpy",
167+
"platformdirs",
168+
"scenedetect",
169+
"screeninfo",
170+
"tqdm",
171+
)
172+
for module_name in third_party_packages:
173+
try:
174+
module = importlib.import_module(module_name)
175+
if hasattr(module, "__version__"):
176+
out_lines.append(output_template.format(module_name, module.__version__))
177+
else:
178+
out_lines.append(output_template.format(module_name, not_found_str))
179+
except ModuleNotFoundError:
180+
out_lines.append(output_template.format(module_name, not_found_str))
181+
182+
# External Tools
183+
out_lines += ["", "Tools", line_separator]
184+
185+
tool_version_info = (
186+
("ffmpeg", get_ffmpeg_version()),
187+
("mkvmerge", get_mkvmerge_version()),
188+
)
189+
190+
for tool_name, tool_version in tool_version_info:
191+
out_lines.append(
192+
output_template.format(tool_name, tool_version if tool_version else not_found_str)
193+
)
194+
195+
return "\n".join(out_lines)

0 commit comments

Comments
 (0)