core-extra/daemon/core/gui/app.py

173 lines
6.1 KiB
Python
Raw Normal View History

import logging
import math
import tkinter as tk
from tkinter import PhotoImage, font, ttk
from tkinter.ttk import Progressbar
import grpc
2019-12-19 17:30:21 +00:00
from core.gui import appconfig, themes
from core.gui.coreclient import CoreClient
from core.gui.dialogs.error import ErrorDialog
2019-12-19 17:30:21 +00:00
from core.gui.graph.graph import CanvasGraph
from core.gui.images import ImageEnum, Images
from core.gui.menubar import Menubar
from core.gui.nodeutils import NodeUtils
from core.gui.statusbar import StatusBar
from core.gui.toolbar import Toolbar
WIDTH = 1000
HEIGHT = 800
class Application(ttk.Frame):
def __init__(self, proxy: bool) -> None:
super().__init__()
# load node icons
NodeUtils.setup()
# widgets
self.menubar = None
2019-11-07 23:58:02 +00:00
self.toolbar = None
self.right_frame = None
2019-11-08 05:46:40 +00:00
self.canvas = None
self.statusbar = None
self.progress = None
# fonts
self.fonts_size = None
self.icon_text_font = None
self.edge_font = None
# setup
self.guiconfig = appconfig.read()
self.app_scale = self.guiconfig.scale
self.setup_scaling()
self.style = ttk.Style()
self.setup_theme()
self.core = CoreClient(self, proxy)
self.setup_app()
2019-11-07 23:58:02 +00:00
self.draw()
self.core.setup()
def setup_scaling(self) -> None:
self.fonts_size = {name: font.nametofont(name)["size"] for name in font.names()}
text_scale = self.app_scale if self.app_scale < 1 else math.sqrt(self.app_scale)
themes.scale_fonts(self.fonts_size, self.app_scale)
self.icon_text_font = font.Font(family="TkIconFont", size=int(12 * text_scale))
self.edge_font = font.Font(
family="TkDefaultFont", size=int(8 * text_scale), weight=font.BOLD
)
def setup_theme(self) -> None:
themes.load(self.style)
2019-12-16 22:30:38 +00:00
self.master.bind_class("Menu", "<<ThemeChanged>>", themes.theme_change_menu)
self.master.bind("<<ThemeChanged>>", themes.theme_change)
self.style.theme_use(self.guiconfig.preferences.theme)
def setup_app(self) -> None:
self.master.title("CORE")
self.center()
self.master.protocol("WM_DELETE_WINDOW", self.on_closing)
image = Images.get(ImageEnum.CORE, 16)
self.master.tk.call("wm", "iconphoto", self.master._w, image)
self.master.option_add("*tearOff", tk.FALSE)
self.setup_file_dialogs()
def setup_file_dialogs(self) -> None:
"""
Hack code that needs to initialize a bad dialog so that we can apply,
global settings for dialogs to not show hidden files by default and display
the hidden file toggle.
:return: nothing
"""
try:
self.master.tk.call("tk_getOpenFile", "-foobar")
except tk.TclError:
pass
self.master.tk.call("set", "::tk::dialog::file::showHiddenBtn", "1")
self.master.tk.call("set", "::tk::dialog::file::showHiddenVar", "0")
def center(self) -> None:
screen_width = self.master.winfo_screenwidth()
screen_height = self.master.winfo_screenheight()
x = int((screen_width / 2) - (WIDTH * self.app_scale / 2))
y = int((screen_height / 2) - (HEIGHT * self.app_scale / 2))
self.master.geometry(
f"{int(WIDTH * self.app_scale)}x{int(HEIGHT * self.app_scale)}+{x}+{y}"
)
def draw(self) -> None:
self.master.rowconfigure(0, weight=1)
self.master.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
self.columnconfigure(1, weight=1)
self.grid(sticky="nsew")
self.toolbar = Toolbar(self)
self.toolbar.grid(sticky="ns")
self.right_frame = ttk.Frame(self)
self.right_frame.columnconfigure(0, weight=1)
self.right_frame.rowconfigure(0, weight=1)
self.right_frame.grid(row=0, column=1, sticky="nsew")
2019-11-08 05:46:40 +00:00
self.draw_canvas()
self.draw_status()
self.progress = Progressbar(self.right_frame, mode="indeterminate")
self.menubar = Menubar(self)
self.master.config(menu=self.menubar)
def draw_canvas(self) -> None:
canvas_frame = ttk.Frame(self.right_frame)
canvas_frame.rowconfigure(0, weight=1)
canvas_frame.columnconfigure(0, weight=1)
canvas_frame.grid(sticky="nsew", pady=1)
self.canvas = CanvasGraph(canvas_frame, self, self.core)
self.canvas.grid(sticky="nsew")
scroll_y = ttk.Scrollbar(canvas_frame, command=self.canvas.yview)
scroll_y.grid(row=0, column=1, sticky="ns")
scroll_x = ttk.Scrollbar(
canvas_frame, orient=tk.HORIZONTAL, command=self.canvas.xview
)
scroll_x.grid(row=1, column=0, sticky="ew")
self.canvas.configure(xscrollcommand=scroll_x.set)
self.canvas.configure(yscrollcommand=scroll_y.set)
def draw_status(self) -> None:
self.statusbar = StatusBar(self.right_frame, self)
self.statusbar.grid(sticky="ew")
def show_grpc_exception(self, title: str, e: grpc.RpcError) -> None:
logging.exception("app grpc exception", exc_info=e)
message = e.details()
self.show_error(title, message)
def show_exception(self, title: str, e: Exception) -> None:
logging.exception("app exception", exc_info=e)
self.show_error(title, str(e))
def show_error(self, title: str, message: str) -> None:
self.after(0, lambda: ErrorDialog(self, title, message).show())
def on_closing(self) -> None:
if self.toolbar.picker:
self.toolbar.picker.destroy()
self.menubar.prompt_save_running_session(True)
2019-10-19 00:42:00 +01:00
def save_config(self) -> None:
appconfig.save(self.guiconfig)
def joined_session_update(self) -> None:
if self.core.is_runtime():
self.toolbar.set_runtime()
else:
self.toolbar.set_design()
def get_icon(self, image_enum: ImageEnum, width: int) -> PhotoImage:
return Images.get(image_enum, int(width * self.app_scale))
def get_custom_icon(self, image_file: str, width: int) -> PhotoImage:
return Images.get_custom(image_file, int(width * self.app_scale))
def close(self) -> None:
self.master.destroy()