pygui: toolbar cleanup for buttonbar frames

This commit is contained in:
Blake Harnden 2020-05-15 23:23:07 -07:00
parent 4eaecd6a7b
commit 29fc5acb99
2 changed files with 74 additions and 129 deletions

View file

@ -1,7 +1,7 @@
import logging import logging
import math import math
import tkinter as tk import tkinter as tk
from tkinter import font, ttk from tkinter import PhotoImage, font, ttk
from tkinter.ttk import Progressbar from tkinter.ttk import Progressbar
import grpc import grpc
@ -160,5 +160,8 @@ class Application(ttk.Frame):
else: else:
self.toolbar.set_design() 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 close(self) -> None: def close(self) -> None:
self.master.destroy() self.master.destroy()

View file

@ -37,6 +37,30 @@ def enable_buttons(frame: ttk.Frame, enabled: bool) -> None:
child.configure(state=state) child.configure(state=state)
class ButtonBar(ttk.Frame):
def __init__(self, master: tk.Widget, app: "Application"):
super().__init__(master)
self.app = app
self.radio_buttons = []
def create_button(
self, image_enum: ImageEnum, func: Callable, tooltip: str, radio: bool = False
) -> ttk.Button:
image = self.app.get_icon(image_enum, TOOLBAR_SIZE)
button = ttk.Button(self, image=image, command=func)
button.image = image
button.grid(sticky="ew")
Tooltip(button, tooltip)
if radio:
self.radio_buttons.append(button)
return button
def select_radio(self, selected: ttk.Button) -> None:
for button in self.radio_buttons:
button.state(["!pressed"])
selected.state(["pressed"])
class Toolbar(ttk.Frame): class Toolbar(ttk.Frame):
""" """
Core toolbar class Core toolbar class
@ -82,9 +106,6 @@ class Toolbar(ttk.Frame):
# draw components # draw components
self.draw() self.draw()
def get_icon(self, image_enum: ImageEnum, width: int) -> PhotoImage:
return Images.get(image_enum, int(width * self.app.app_scale))
def draw(self) -> None: def draw(self) -> None:
self.columnconfigure(0, weight=1) self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1) self.rowconfigure(0, weight=1)
@ -93,84 +114,59 @@ class Toolbar(ttk.Frame):
self.design_frame.tkraise() self.design_frame.tkraise()
def draw_design_frame(self) -> None: def draw_design_frame(self) -> None:
self.design_frame = ttk.Frame(self) self.design_frame = ButtonBar(self, self.app)
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.play_button = self.create_button( self.play_button = self.design_frame.create_button(
self.design_frame, ImageEnum.START, self.click_start, "Start Session"
self.get_icon(ImageEnum.START, TOOLBAR_SIZE),
self.click_start,
"start the session",
) )
self.select_button = self.create_button( self.select_button = self.design_frame.create_button(
self.design_frame, ImageEnum.SELECT, self.click_selection, "Selection Tool", radio=True
self.get_icon(ImageEnum.SELECT, TOOLBAR_SIZE),
self.click_selection,
"selection tool",
) )
self.link_button = self.create_button( self.link_button = self.design_frame.create_button(
self.design_frame, ImageEnum.LINK, self.click_link, "Link Tool", radio=True
self.get_icon(ImageEnum.LINK, TOOLBAR_SIZE), )
self.click_link, self.node_enum = ImageEnum.ROUTER
"link tool", self.node_button = self.design_frame.create_button(
self.node_enum, self.draw_node_picker, "Container Nodes", radio=True
)
self.network_enum = ImageEnum.HUB
self.network_button = self.design_frame.create_button(
self.network_enum, self.draw_network_picker, "Link Layer Nodes", radio=True
)
self.annotation_enum = ImageEnum.MARKER
self.annotation_button = self.design_frame.create_button(
self.annotation_enum,
self.draw_annotation_picker,
"Annotation Tools",
radio=True,
) )
self.create_node_button()
self.create_network_button()
self.create_annotation_button()
def design_select(self, button: ttk.Button) -> None:
logging.debug("selecting design button: %s", button)
self.select_button.state(["!pressed"])
self.link_button.state(["!pressed"])
self.node_button.state(["!pressed"])
self.network_button.state(["!pressed"])
self.annotation_button.state(["!pressed"])
button.state(["pressed"])
def runtime_select(self, button: ttk.Button) -> None:
logging.debug("selecting runtime button: %s", button)
self.runtime_select_button.state(["!pressed"])
self.stop_button.state(["!pressed"])
self.runtime_marker_button.state(["!pressed"])
self.run_command_button.state(["!pressed"])
button.state(["pressed"])
def draw_runtime_frame(self) -> None: def draw_runtime_frame(self) -> None:
self.runtime_frame = ttk.Frame(self) self.runtime_frame = ButtonBar(self, self.app)
self.runtime_frame.grid(row=0, column=0, sticky="nsew") self.runtime_frame.grid(row=0, column=0, sticky="nsew")
self.runtime_frame.columnconfigure(0, weight=1) self.runtime_frame.columnconfigure(0, weight=1)
self.stop_button = self.create_button( self.stop_button = self.runtime_frame.create_button(
self.runtime_frame, ImageEnum.STOP, self.click_stop, "Stop Session"
self.get_icon(ImageEnum.STOP, TOOLBAR_SIZE),
self.click_stop,
"stop the session",
) )
self.runtime_select_button = self.create_button( self.runtime_select_button = self.runtime_frame.create_button(
self.runtime_frame, ImageEnum.SELECT, self.click_runtime_selection, "Selection Tool", radio=True
self.get_icon(ImageEnum.SELECT, TOOLBAR_SIZE),
self.click_runtime_selection,
"selection tool",
) )
self.runtime_marker_button = self.create_button( self.runtime_marker_button = self.runtime_frame.create_button(
self.runtime_frame, ImageEnum.MARKER, self.click_marker_button, "Marker Tool", radio=True
self.get_icon(ImageEnum.MARKER, TOOLBAR_SIZE),
self.click_marker_button,
"marker",
) )
self.run_command_button = self.create_button( self.run_command_button = self.runtime_frame.create_button(
self.runtime_frame, ImageEnum.RUN, self.click_run_button, "Run Tool"
self.get_icon(ImageEnum.RUN, TOOLBAR_SIZE),
self.click_run_button,
"run",
) )
def draw_node_picker(self) -> None: def draw_node_picker(self) -> None:
self.design_frame.select_radio(self.node_button)
self.hide_pickers() self.hide_pickers()
self.node_picker = ttk.Frame(self.master) self.node_picker = ttk.Frame(self.master)
# draw default nodes # draw default nodes
for node_draw in NodeUtils.NODES: for node_draw in NodeUtils.NODES:
toolbar_image = self.get_icon(node_draw.image_enum, TOOLBAR_SIZE) toolbar_image = self.app.get_icon(node_draw.image_enum, TOOLBAR_SIZE)
image = self.get_icon(node_draw.image_enum, PICKER_SIZE) image = self.app.get_icon(node_draw.image_enum, PICKER_SIZE)
func = partial( func = partial(
self.update_button, self.update_button,
self.node_button, self.node_button,
@ -198,7 +194,6 @@ class Toolbar(ttk.Frame):
node_draw.image_file, node_draw.image_file,
) )
self.create_picker_button(image, func, self.node_picker, name) self.create_picker_button(image, func, self.node_picker, name)
self.design_select(self.node_button)
self.node_button.after( self.node_button.after(
0, lambda: self.show_picker(self.node_button, self.node_picker) 0, lambda: self.show_picker(self.node_button, self.node_picker)
) )
@ -231,23 +226,12 @@ class Toolbar(ttk.Frame):
button.bind("<ButtonRelease-1>", lambda e: func()) button.bind("<ButtonRelease-1>", lambda e: func())
button.grid(pady=1) button.grid(pady=1)
def create_button(
self, frame: ttk.Frame, image: PhotoImage, func: Callable, tooltip: str
) -> ttk.Button:
button = ttk.Button(frame, image=image, command=func)
button.image = image
button.grid(sticky="ew")
Tooltip(button, tooltip)
return button
def click_selection(self) -> None: def click_selection(self) -> None:
logging.debug("clicked selection tool") self.design_frame.select_radio(self.select_button)
self.design_select(self.select_button)
self.app.canvas.mode = GraphMode.SELECT self.app.canvas.mode = GraphMode.SELECT
def click_runtime_selection(self) -> None: def click_runtime_selection(self) -> None:
logging.debug("clicked selection tool") self.runtime_frame.select_radio(self.runtime_select_button)
self.runtime_select(self.runtime_select_button)
self.app.canvas.mode = GraphMode.SELECT self.app.canvas.mode = GraphMode.SELECT
def click_start(self) -> None: def click_start(self) -> None:
@ -284,8 +268,7 @@ class Toolbar(ttk.Frame):
self.click_selection() self.click_selection()
def click_link(self) -> None: def click_link(self) -> None:
logging.debug("Click LINK button") self.design_frame.select_radio(self.link_button)
self.design_select(self.link_button)
self.app.canvas.mode = GraphMode.EDGE self.app.canvas.mode = GraphMode.EDGE
def update_button( def update_button(
@ -319,28 +302,16 @@ class Toolbar(ttk.Frame):
self.annotation_picker.destroy() self.annotation_picker.destroy()
self.annotation_picker = None self.annotation_picker = None
def create_node_button(self) -> None:
"""
Create network layer button
"""
image = self.get_icon(ImageEnum.ROUTER, TOOLBAR_SIZE)
self.node_button = ttk.Button(
self.design_frame, image=image, command=self.draw_node_picker
)
self.node_button.image = image
self.node_button.grid(sticky="ew")
Tooltip(self.node_button, "Network-layer virtual nodes")
self.node_enum = ImageEnum.ROUTER
def draw_network_picker(self) -> None: def draw_network_picker(self) -> None:
""" """
Draw the options for link-layer button. Draw the options for link-layer button.
""" """
self.design_frame.select_radio(self.network_button)
self.hide_pickers() self.hide_pickers()
self.network_picker = ttk.Frame(self.master) self.network_picker = ttk.Frame(self.master)
for node_draw in NodeUtils.NETWORK_NODES: for node_draw in NodeUtils.NETWORK_NODES:
toolbar_image = self.get_icon(node_draw.image_enum, TOOLBAR_SIZE) toolbar_image = self.app.get_icon(node_draw.image_enum, TOOLBAR_SIZE)
image = self.get_icon(node_draw.image_enum, PICKER_SIZE) image = self.app.get_icon(node_draw.image_enum, PICKER_SIZE)
self.create_picker_button( self.create_picker_button(
image, image,
partial( partial(
@ -354,29 +325,15 @@ class Toolbar(ttk.Frame):
self.network_picker, self.network_picker,
node_draw.label, node_draw.label,
) )
self.design_select(self.network_button)
self.network_button.after( self.network_button.after(
0, lambda: self.show_picker(self.network_button, self.network_picker) 0, lambda: self.show_picker(self.network_button, self.network_picker)
) )
def create_network_button(self) -> None:
"""
Create link-layer node button and the options that represent different
link-layer node types.
"""
image = self.get_icon(ImageEnum.HUB, TOOLBAR_SIZE)
self.network_button = ttk.Button(
self.design_frame, image=image, command=self.draw_network_picker
)
self.network_button.image = image
self.network_button.grid(sticky="ew")
Tooltip(self.network_button, "link-layer nodes")
self.network_enum = ImageEnum.HUB
def draw_annotation_picker(self) -> None: def draw_annotation_picker(self) -> None:
""" """
Draw the options for marker button. Draw the options for marker button.
""" """
self.design_frame.select_radio(self.annotation_button)
self.hide_pickers() self.hide_pickers()
self.annotation_picker = ttk.Frame(self.master) self.annotation_picker = ttk.Frame(self.master)
nodes = [ nodes = [
@ -386,34 +343,20 @@ class Toolbar(ttk.Frame):
(ImageEnum.TEXT, ShapeType.TEXT), (ImageEnum.TEXT, ShapeType.TEXT),
] ]
for image_enum, shape_type in nodes: for image_enum, shape_type in nodes:
toolbar_image = self.get_icon(image_enum, TOOLBAR_SIZE) toolbar_image = self.app.get_icon(image_enum, TOOLBAR_SIZE)
image = self.get_icon(image_enum, PICKER_SIZE) image = self.app.get_icon(image_enum, PICKER_SIZE)
self.create_picker_button( self.create_picker_button(
image, image,
partial(self.update_annotation, toolbar_image, shape_type, image_enum), partial(self.update_annotation, toolbar_image, shape_type, image_enum),
self.annotation_picker, self.annotation_picker,
shape_type.value, shape_type.value,
) )
self.design_select(self.annotation_button)
self.annotation_button.after( self.annotation_button.after(
0, lambda: self.show_picker(self.annotation_button, self.annotation_picker) 0, lambda: self.show_picker(self.annotation_button, self.annotation_picker)
) )
def create_annotation_button(self) -> None:
"""
Create marker button and options that represent different marker types
"""
image = self.get_icon(ImageEnum.MARKER, TOOLBAR_SIZE)
self.annotation_button = ttk.Button(
self.design_frame, image=image, command=self.draw_annotation_picker
)
self.annotation_button.image = image
self.annotation_button.grid(sticky="ew")
Tooltip(self.annotation_button, "background annotation tools")
self.annotation_enum = ImageEnum.MARKER
def create_observe_button(self) -> None: def create_observe_button(self) -> None:
image = self.get_icon(ImageEnum.OBSERVE, TOOLBAR_SIZE) image = self.app.get_icon(ImageEnum.OBSERVE, TOOLBAR_SIZE)
menu_button = ttk.Menubutton( menu_button = ttk.Menubutton(
self.runtime_frame, image=image, direction=tk.RIGHT self.runtime_frame, image=image, direction=tk.RIGHT
) )
@ -476,8 +419,7 @@ class Toolbar(ttk.Frame):
dialog.show() dialog.show()
def click_marker_button(self) -> None: def click_marker_button(self) -> None:
logging.debug("Click on marker button") self.runtime_frame.select_radio(self.runtime_marker_button)
self.runtime_select(self.runtime_marker_button)
self.app.canvas.mode = GraphMode.ANNOTATION self.app.canvas.mode = GraphMode.ANNOTATION
self.app.canvas.annotation_type = ShapeType.MARKER self.app.canvas.annotation_type = ShapeType.MARKER
if self.marker_tool: if self.marker_tool:
@ -486,7 +428,7 @@ class Toolbar(ttk.Frame):
self.marker_tool.show() self.marker_tool.show()
def scale_button(self, button, image_enum) -> None: def scale_button(self, button, image_enum) -> None:
image = self.get_icon(image_enum, TOOLBAR_SIZE) image = self.app.get_icon(image_enum, TOOLBAR_SIZE)
button.config(image=image) button.config(image=image)
button.image = image button.image = image