pygui: toolbar cleanup for buttonbar frames
This commit is contained in:
parent
4eaecd6a7b
commit
29fc5acb99
2 changed files with 74 additions and 129 deletions
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue