attempt adding scaling function to the gui

This commit is contained in:
Huy Pham 2020-02-10 15:20:07 -08:00
parent 3d1692fbb3
commit 8734b9f22f
4 changed files with 159 additions and 18 deletions

View file

@ -10,10 +10,14 @@ from core.gui.themes import FRAME_PAD, PADX, PADY
if TYPE_CHECKING: if TYPE_CHECKING:
from core.gui.app import Application from core.gui.app import Application
WIDTH = 1000
HEIGHT = 800
class PreferencesDialog(Dialog): class PreferencesDialog(Dialog):
def __init__(self, master: "Application", app: "Application"): def __init__(self, master: "Application", app: "Application"):
super().__init__(master, app, "Preferences", modal=True) super().__init__(master, app, "Preferences", modal=True)
self.gui_scale = tk.DoubleVar(value=self.app.canvas.app_scale)
preferences = self.app.guiconfig["preferences"] preferences = self.app.guiconfig["preferences"]
self.editor = tk.StringVar(value=preferences["editor"]) self.editor = tk.StringVar(value=preferences["editor"])
self.theme = tk.StringVar(value=preferences["theme"]) self.theme = tk.StringVar(value=preferences["theme"])
@ -64,6 +68,27 @@ class PreferencesDialog(Dialog):
entry = ttk.Entry(frame, textvariable=self.gui3d) entry = ttk.Entry(frame, textvariable=self.gui3d)
entry.grid(row=3, column=1, sticky="ew") entry.grid(row=3, column=1, sticky="ew")
label = ttk.Label(frame, text="Scaling")
label.grid(row=4, column=0, pady=PADY, padx=PADX, sticky="w")
scale_frame = ttk.Frame(frame)
scale_frame.grid(row=4, column=1, sticky="ew")
scale_frame.columnconfigure(0, weight=1)
scale = ttk.Scale(
scale_frame,
from_=0.5,
to=5,
value=1,
orient=tk.HORIZONTAL,
variable=self.gui_scale,
command=self.scale_adjust,
)
scale.grid(row=0, column=0, sticky="ew")
entry = ttk.Entry(
scale_frame, textvariable=self.gui_scale, width=4, state="disabled"
)
entry.grid(row=0, column=1)
def draw_buttons(self): def draw_buttons(self):
frame = ttk.Frame(self.top) frame = ttk.Frame(self.top)
frame.grid(sticky="ew") frame.grid(sticky="ew")
@ -89,3 +114,17 @@ class PreferencesDialog(Dialog):
preferences["theme"] = self.theme.get() preferences["theme"] = self.theme.get()
self.app.save_config() self.app.save_config()
self.destroy() self.destroy()
def scale_adjust(self, scale: str):
self.gui_scale.set(round(self.gui_scale.get(), 2))
app_scale = self.gui_scale.get()
self.app.canvas.app_scale = app_scale
screen_width = self.app.master.winfo_screenwidth()
screen_height = self.app.master.winfo_screenheight()
scaled_width = WIDTH * app_scale
scaled_height = HEIGHT * app_scale
x = int(screen_width / 2 - scaled_width / 2)
y = int(screen_height / 2 - scaled_height / 2)
self.app.master.geometry(f"{int(scaled_width)}x{int(scaled_height)}+{x}+{y}")
self.app.toolbar.scale(app_scale)

View file

@ -53,6 +53,9 @@ class CanvasGraph(tk.Canvas):
self.marker_tool = None self.marker_tool = None
self.to_copy = [] self.to_copy = []
# app's scale, different scale values to support higher resolution display
self.app_scale = 1.0
# background related # background related
self.wallpaper_id = None self.wallpaper_id = None
self.wallpaper = None self.wallpaper = None

View file

@ -29,7 +29,7 @@ class StatusBar(ttk.Frame):
def draw(self): def draw(self):
self.columnconfigure(0, weight=1) self.columnconfigure(0, weight=1)
self.columnconfigure(1, weight=7) self.columnconfigure(1, weight=5)
self.columnconfigure(2, weight=1) self.columnconfigure(2, weight=1)
self.columnconfigure(3, weight=1) self.columnconfigure(3, weight=1)
self.columnconfigure(4, weight=1) self.columnconfigure(4, weight=1)

View file

@ -1,6 +1,7 @@
import logging import logging
import time import time
import tkinter as tk import tkinter as tk
from enum import Enum
from functools import partial from functools import partial
from tkinter import messagebox, ttk from tkinter import messagebox, ttk
from tkinter.font import Font from tkinter.font import Font
@ -25,6 +26,12 @@ TOOLBAR_SIZE = 32
PICKER_SIZE = 24 PICKER_SIZE = 24
class NodeTypeEnum(Enum):
NODE = 0
NETWORK = 1
OTHER = 2
def icon(image_enum, width=TOOLBAR_SIZE): def icon(image_enum, width=TOOLBAR_SIZE):
return Images.get(image_enum, width) return Images.get(image_enum, width)
@ -47,6 +54,7 @@ class Toolbar(ttk.Frame):
self.picker_font = Font(size=8) self.picker_font = Font(size=8)
# design buttons # design buttons
self.play_button = None
self.select_button = None self.select_button = None
self.link_button = None self.link_button = None
self.node_button = None self.node_button = None
@ -71,9 +79,21 @@ class Toolbar(ttk.Frame):
# dialog # dialog
self.marker_tool = None self.marker_tool = None
# these variables help keep track of what images being drawn so that scaling is possible
# since ImageTk.PhotoImage does not have resize method
self.node_enum = None
self.network_enum = None
self.annotation_enum = None
# draw components # draw components
self.draw() self.draw()
def get_icon(self, image_enum, width=TOOLBAR_SIZE):
if not self.app.canvas:
return Images.get(image_enum, width)
else:
return Images.get(image_enum, int(width * self.app.canvas.app_scale))
def draw(self): def draw(self):
self.columnconfigure(0, weight=1) self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1) self.rowconfigure(0, weight=1)
@ -85,20 +105,26 @@ class Toolbar(ttk.Frame):
self.design_frame = ttk.Frame(self) self.design_frame = ttk.Frame(self)
self.design_frame.grid(row=0, column=0, sticky="nsew") self.design_frame.grid(row=0, column=0, sticky="nsew")
self.design_frame.columnconfigure(0, weight=1) self.design_frame.columnconfigure(0, weight=1)
self.create_button( self.play_button = self.create_button(
self.design_frame, self.design_frame,
icon(ImageEnum.START), # icon(ImageEnum.START),
self.get_icon(ImageEnum.START),
self.click_start, self.click_start,
"start the session", "start the session",
) )
self.select_button = self.create_button( self.select_button = self.create_button(
self.design_frame, self.design_frame,
icon(ImageEnum.SELECT), # icon(ImageEnum.SELECT),
self.get_icon(ImageEnum.SELECT),
self.click_selection, self.click_selection,
"selection tool", "selection tool",
) )
self.link_button = self.create_button( self.link_button = self.create_button(
self.design_frame, icon(ImageEnum.LINK), self.click_link, "link tool" self.design_frame,
# icon(ImageEnum.LINK),
self.get_icon(ImageEnum.LINK),
self.click_link,
"link tool",
) )
self.create_node_button() self.create_node_button()
self.create_network_button() self.create_network_button()
@ -130,18 +156,24 @@ class Toolbar(ttk.Frame):
self.stop_button = self.create_button( self.stop_button = self.create_button(
self.runtime_frame, self.runtime_frame,
icon(ImageEnum.STOP), # icon(ImageEnum.STOP),
self.get_icon(ImageEnum.STOP),
self.click_stop, self.click_stop,
"stop the session", "stop the session",
) )
self.runtime_select_button = self.create_button( self.runtime_select_button = self.create_button(
self.runtime_frame, self.runtime_frame,
icon(ImageEnum.SELECT), # icon(ImageEnum.SELECT),
self.get_icon(ImageEnum.SELECT),
self.click_runtime_selection, self.click_runtime_selection,
"selection tool", "selection tool",
) )
self.plot_button = self.create_button( self.plot_button = self.create_button(
self.runtime_frame, icon(ImageEnum.PLOT), self.click_plot_button, "plot" self.runtime_frame,
# icon(ImageEnum.PLOT),
self.get_icon(ImageEnum.PLOT),
self.click_plot_button,
"plot",
) )
self.runtime_marker_button = self.create_button( self.runtime_marker_button = self.create_button(
self.runtime_frame, self.runtime_frame,
@ -165,22 +197,40 @@ class Toolbar(ttk.Frame):
# draw default nodes # draw default nodes
for node_draw in NodeUtils.NODES: for node_draw in NodeUtils.NODES:
toolbar_image = icon(node_draw.image_enum) toolbar_image = icon(node_draw.image_enum)
image = icon(node_draw.image_enum, PICKER_SIZE) # image = icon(node_draw.image_enum, PICKER_SIZE)
image = self.get_icon(
node_draw.image_enum, PICKER_SIZE * self.app.canvas.app_scale
)
func = partial( func = partial(
self.update_button, self.node_button, toolbar_image, node_draw self.update_button,
self.node_button,
toolbar_image,
node_draw,
NodeTypeEnum.NODE,
node_draw.image_enum,
) )
self.create_picker_button(image, func, self.node_picker, node_draw.label) self.create_picker_button(image, func, self.node_picker, node_draw.label)
# draw custom nodes # draw custom nodes
for name in sorted(self.app.core.custom_nodes): for name in sorted(self.app.core.custom_nodes):
node_draw = self.app.core.custom_nodes[name] node_draw = self.app.core.custom_nodes[name]
toolbar_image = Images.get_custom(node_draw.image_file, TOOLBAR_SIZE) toolbar_image = Images.get_custom(node_draw.image_file, TOOLBAR_SIZE)
image = Images.get_custom(node_draw.image_file, PICKER_SIZE) image = Images.get_custom(
node_draw.image_file, int(PICKER_SIZE * self.app.canvas.app_scale)
)
func = partial( func = partial(
self.update_button, self.node_button, toolbar_image, node_draw self.update_button,
self.node_button,
toolbar_image,
node_draw,
NodeTypeEnum,
node_draw.image_file,
) )
self.create_picker_button(image, func, self.node_picker, name) self.create_picker_button(image, func, self.node_picker, name)
# draw edit node # draw edit node
image = icon(ImageEnum.EDITNODE, PICKER_SIZE) # image = icon(ImageEnum.EDITNODE, PICKER_SIZE)
image = self.get_icon(
ImageEnum.EDITNODE, PICKER_SIZE * self.app.canvas.app_scale
)
self.create_picker_button( self.create_picker_button(
image, self.click_edit_node, self.node_picker, "Custom" image, self.click_edit_node, self.node_picker, "Custom"
) )
@ -284,13 +334,24 @@ class Toolbar(ttk.Frame):
dialog = CustomNodesDialog(self.app, self.app) dialog = CustomNodesDialog(self.app, self.app)
dialog.show() dialog.show()
def update_button(self, button: ttk.Button, image: "ImageTk", node_draw: NodeDraw): def update_button(
self,
button: ttk.Button,
image: "ImageTk",
node_draw: NodeDraw,
type_enum,
image_enum,
):
logging.debug("update button(%s): %s", button, node_draw) logging.debug("update button(%s): %s", button, node_draw)
self.hide_pickers() self.hide_pickers()
button.configure(image=image) button.configure(image=image)
button.image = image button.image = image
self.app.canvas.mode = GraphMode.NODE self.app.canvas.mode = GraphMode.NODE
self.app.canvas.node_draw = node_draw self.app.canvas.node_draw = node_draw
if type_enum == NodeTypeEnum.NODE:
self.node_enum = image_enum
elif type_enum == NodeTypeEnum.NETWORK:
self.network_enum = image_enum
def hide_pickers(self): def hide_pickers(self):
logging.debug("hiding pickers") logging.debug("hiding pickers")
@ -308,13 +369,14 @@ class Toolbar(ttk.Frame):
""" """
Create network layer button Create network layer button
""" """
image = icon(ImageEnum.ROUTER) image = icon(ImageEnum.ROUTER, TOOLBAR_SIZE)
self.node_button = ttk.Button( self.node_button = ttk.Button(
self.design_frame, image=image, command=self.draw_node_picker self.design_frame, image=image, command=self.draw_node_picker
) )
self.node_button.image = image self.node_button.image = image
self.node_button.grid(sticky="ew") self.node_button.grid(sticky="ew")
Tooltip(self.node_button, "Network-layer virtual nodes") Tooltip(self.node_button, "Network-layer virtual nodes")
self.node_enum = ImageEnum.ROUTER
def draw_network_picker(self): def draw_network_picker(self):
""" """
@ -328,7 +390,12 @@ class Toolbar(ttk.Frame):
self.create_picker_button( self.create_picker_button(
image, image,
partial( partial(
self.update_button, self.network_button, toolbar_image, node_draw self.update_button,
self.network_button,
toolbar_image,
node_draw,
NodeTypeEnum.NETWORK,
node_draw.image_enum,
), ),
self.network_picker, self.network_picker,
node_draw.label, node_draw.label,
@ -350,6 +417,7 @@ class Toolbar(ttk.Frame):
self.network_button.image = image self.network_button.image = image
self.network_button.grid(sticky="ew") self.network_button.grid(sticky="ew")
Tooltip(self.network_button, "link-layer nodes") Tooltip(self.network_button, "link-layer nodes")
self.network_enum = ImageEnum.HUB
def draw_annotation_picker(self): def draw_annotation_picker(self):
""" """
@ -368,7 +436,7 @@ class Toolbar(ttk.Frame):
image = icon(image_enum, PICKER_SIZE) image = icon(image_enum, PICKER_SIZE)
self.create_picker_button( self.create_picker_button(
image, image,
partial(self.update_annotation, toolbar_image, shape_type), partial(self.update_annotation, toolbar_image, shape_type, image_enum),
self.annotation_picker, self.annotation_picker,
shape_type.value, shape_type.value,
) )
@ -388,6 +456,7 @@ class Toolbar(ttk.Frame):
self.annotation_button.image = image self.annotation_button.image = image
self.annotation_button.grid(sticky="ew") self.annotation_button.grid(sticky="ew")
Tooltip(self.annotation_button, "background annotation tools") Tooltip(self.annotation_button, "background annotation tools")
self.annotation_enum = ImageEnum.MARKER
def create_observe_button(self): def create_observe_button(self):
menu_button = ttk.Menubutton( menu_button = ttk.Menubutton(
@ -434,13 +503,16 @@ class Toolbar(ttk.Frame):
if not response.result: if not response.result:
messagebox.showerror("Stop Error", "Errors stopping session") messagebox.showerror("Stop Error", "Errors stopping session")
def update_annotation(self, image: "ImageTk.PhotoImage", shape_type: ShapeType): def update_annotation(
self, image: "ImageTk.PhotoImage", shape_type: ShapeType, image_enum
):
logging.debug("clicked annotation: ") logging.debug("clicked annotation: ")
self.hide_pickers() self.hide_pickers()
self.annotation_button.configure(image=image) self.annotation_button.configure(image=image)
self.annotation_button.image = image self.annotation_button.image = image
self.app.canvas.mode = GraphMode.ANNOTATION self.app.canvas.mode = GraphMode.ANNOTATION
self.app.canvas.annotation_type = shape_type self.app.canvas.annotation_type = shape_type
self.annotation_enum = image_enum
if is_marker(shape_type): if is_marker(shape_type):
if self.marker_tool: if self.marker_tool:
self.marker_tool.destroy() self.marker_tool.destroy()
@ -465,3 +537,30 @@ class Toolbar(ttk.Frame):
def click_two_node_button(self): def click_two_node_button(self):
logging.debug("Click TWONODE button") logging.debug("Click TWONODE button")
@classmethod
def scale_button(cls, button, image_enum, scale):
image = icon(image_enum, int(TOOLBAR_SIZE * scale))
button.config(image=image)
button.image = image
def scale(self, scale):
self.scale_button(self.play_button, ImageEnum.START, scale)
self.scale_button(self.select_button, ImageEnum.SELECT, scale)
self.scale_button(self.link_button, ImageEnum.LINK, scale)
self.scale_button(self.node_button, self.node_enum, scale)
self.scale_button(self.network_button, self.network_enum, scale)
self.scale_button(self.annotation_button, self.annotation_enum, scale)
self.scale_button(self.runtime_select_button, ImageEnum.SELECT, scale)
self.scale_button(self.stop_button, ImageEnum.STOP, scale)
self.scale_button(self.plot_button, ImageEnum.PLOT, scale)
self.scale_button(self.runtime_marker_button, ImageEnum.MARKER, scale)
self.scale_button(self.node_command_button, ImageEnum.TWONODE, scale)
self.scale_button(self.run_command_button, ImageEnum.RUN, scale)
# self.stop_button = None
# self.plot_button = None
# self.runtime_marker_button = None
# self.node_command_button = None
# self.run_command_button = None