Beispiel #1
0
class Application(ttk.Frame):
    def __init__(self, proxy: bool) -> None:
        super().__init__()
        # load node icons
        NodeUtils.setup()

        # widgets
        self.menubar = None
        self.toolbar = None
        self.right_frame = None
        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()
        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)
        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")
        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)

    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()
Beispiel #2
0
 def draw_status(self) -> None:
     self.statusbar = StatusBar(self.right_frame, self)
     self.statusbar.grid(sticky="ew")
Beispiel #3
0
 def draw_status(self):
     self.statusbar = StatusBar(master=self, app=self)
     self.statusbar.pack(side=tk.BOTTOM, fill=tk.X)
Beispiel #4
0
class Application(tk.Frame):
    def __init__(self, proxy: bool):
        super().__init__(master=None)
        # load node icons
        NodeUtils.setup()

        # widgets
        self.menubar = None
        self.toolbar = None
        self.canvas = None
        self.statusbar = None
        self.validation = None

        # setup
        self.guiconfig = appconfig.read()
        self.style = ttk.Style()
        self.setup_theme()
        self.core = CoreClient(self, proxy)
        self.setup_app()
        self.draw()
        self.core.set_up()

    def setup_theme(self):
        themes.load(self.style)
        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):
        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.pack(fill=tk.BOTH, expand=True)
        self.validation = InputValidation(self)

    def center(self):
        screen_width = self.master.winfo_screenwidth()
        screen_height = self.master.winfo_screenheight()
        x = int((screen_width / 2) - (WIDTH / 2))
        y = int((screen_height / 2) - (HEIGHT / 2))
        self.master.geometry(f"{WIDTH}x{HEIGHT}+{x}+{y}")

    def draw(self):
        self.master.option_add("*tearOff", tk.FALSE)
        self.menubar = Menubar(self.master, self)
        self.toolbar = Toolbar(self, self)
        self.toolbar.pack(side=tk.LEFT, fill=tk.Y, ipadx=2, ipady=2)
        self.draw_canvas()
        self.draw_status()

    def draw_canvas(self):
        width = self.guiconfig["preferences"]["width"]
        height = self.guiconfig["preferences"]["height"]
        self.canvas = CanvasGraph(self, self.core, width, height)
        self.canvas.pack(fill=tk.BOTH, expand=True)
        scroll_x = ttk.Scrollbar(self.canvas,
                                 orient=tk.HORIZONTAL,
                                 command=self.canvas.xview)
        scroll_x.pack(side=tk.BOTTOM, fill=tk.X)
        scroll_y = ttk.Scrollbar(self.canvas, command=self.canvas.yview)
        scroll_y.pack(side=tk.RIGHT, fill=tk.Y)
        self.canvas.configure(xscrollcommand=scroll_x.set)
        self.canvas.configure(yscrollcommand=scroll_y.set)

    def draw_status(self):
        self.statusbar = StatusBar(master=self, app=self)
        self.statusbar.pack(side=tk.BOTTOM, fill=tk.X)

    def on_closing(self):
        menu_action = MenuAction(self, self.master)
        menu_action.on_quit()

    def save_config(self):
        appconfig.save(self.guiconfig)

    def joined_session_update(self):
        self.statusbar.progress_bar.stop()
        if self.core.is_runtime():
            self.toolbar.set_runtime()
        else:
            self.toolbar.set_design()

    def close(self):
        self.master.destroy()
Beispiel #5
0
class Application(ttk.Frame):
    def __init__(self, proxy: bool, session_id: int = None) -> None:
        super().__init__()
        # load node icons
        nutils.setup()

        # widgets
        self.menubar: Optional[Menubar] = None
        self.toolbar: Optional[Toolbar] = None
        self.right_frame: Optional[ttk.Frame] = None
        self.manager: Optional[CanvasManager] = None
        self.statusbar: Optional[StatusBar] = None
        self.progress: Optional[Progressbar] = None
        self.infobar: Optional[ttk.Frame] = None
        self.info_frame: Optional[InfoFrameBase] = None
        self.show_infobar: tk.BooleanVar = tk.BooleanVar(value=False)

        # fonts
        self.fonts_size: Dict[str, int] = {}
        self.icon_text_font: Optional[font.Font] = None
        self.edge_font: Optional[font.Font] = None

        # setup
        self.guiconfig: GuiConfig = appconfig.read()
        self.app_scale: float = self.guiconfig.scale
        self.setup_scaling()
        self.style: ttk.Style = ttk.Style()
        self.setup_theme()
        self.core: CoreClient = CoreClient(self, proxy)
        self.setup_app()
        self.draw()
        self.core.setup(session_id)

    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)
        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.from_enum(ImageEnum.CORE, width=images.DIALOG_SIZE)
        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=tk.NSEW)
        self.toolbar = Toolbar(self)
        self.toolbar.grid(sticky=tk.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=tk.NSEW)
        self.draw_canvas()
        self.draw_infobar()
        self.draw_status()
        self.progress = Progressbar(self.right_frame, mode="indeterminate")
        self.menubar = Menubar(self)
        self.master.config(menu=self.menubar)

    def draw_infobar(self) -> None:
        self.infobar = ttk.Frame(self.right_frame, padding=5, relief=tk.RAISED)
        self.infobar.columnconfigure(0, weight=1)
        self.infobar.rowconfigure(1, weight=1)
        label_font = font.Font(weight=font.BOLD, underline=tk.TRUE)
        label = ttk.Label(self.infobar,
                          text="Details",
                          anchor=tk.CENTER,
                          font=label_font)
        label.grid(sticky=tk.EW, pady=PADY)

    def draw_canvas(self) -> None:
        self.manager = CanvasManager(self.right_frame, self, self.core)
        self.manager.notebook.grid(sticky=tk.NSEW)

    def draw_status(self) -> None:
        self.statusbar = StatusBar(self.right_frame, self)
        self.statusbar.grid(sticky=tk.EW, columnspan=2)

    def display_info(self, frame_class: Type[InfoFrameBase],
                     **kwargs: Any) -> None:
        if not self.show_infobar.get():
            return
        self.clear_info()
        self.info_frame = frame_class(self.infobar, **kwargs)
        self.info_frame.draw()
        self.info_frame.grid(sticky=tk.NSEW)

    def clear_info(self) -> None:
        if self.info_frame:
            self.info_frame.destroy()
            self.info_frame = None

    def default_info(self) -> None:
        self.clear_info()
        self.display_info(DefaultInfoFrame, app=self)

    def show_info(self) -> None:
        self.default_info()
        self.infobar.grid(row=0, column=1, sticky=tk.NSEW)

    def hide_info(self) -> None:
        self.infobar.grid_forget()

    def show_grpc_exception(self,
                            message: str,
                            e: grpc.RpcError,
                            blocking: bool = False) -> None:
        logger.exception("app grpc exception", exc_info=e)
        dialog = ErrorDialog(self, "GRPC Exception", message, e.details())
        if blocking:
            dialog.show()
        else:
            self.after(0, lambda: dialog.show())

    def show_exception(self, message: str, e: Exception) -> None:
        logger.exception("app exception", exc_info=e)
        self.after(
            0,
            lambda: ErrorDialog(self, "App Exception", message, str(e)).show())

    def show_exception_data(self, title: str, message: str,
                            details: str) -> None:
        self.after(0,
                   lambda: ErrorDialog(self, title, message, details).show())

    def show_error(self,
                   title: str,
                   message: str,
                   blocking: bool = False) -> None:
        if blocking:
            messagebox.showerror(title, message, parent=self)
        else:
            self.after(
                0, lambda: messagebox.showerror(title, message, parent=self))

    def on_closing(self) -> None:
        if self.toolbar.picker:
            self.toolbar.picker.destroy()
        self.menubar.prompt_save_running_session(True)

    def save_config(self) -> None:
        appconfig.save(self.guiconfig)

    def joined_session_update(self) -> None:
        if self.core.is_runtime():
            self.menubar.set_state(is_runtime=True)
            self.toolbar.set_runtime()
        else:
            self.menubar.set_state(is_runtime=False)
            self.toolbar.set_design()

    def get_enum_icon(self, image_enum: ImageEnum, *,
                      width: int) -> PhotoImage:
        return images.from_enum(image_enum, width=width, scale=self.app_scale)

    def get_file_icon(self, file_path: str, *, width: int) -> PhotoImage:
        return images.from_file(file_path, width=width, scale=self.app_scale)

    def close(self) -> None:
        self.master.destroy()
Beispiel #6
0
 def draw_status(self) -> None:
     self.statusbar = StatusBar(self.right_frame, self)
     self.statusbar.grid(sticky=tk.EW, columnspan=2)