pygui: further refactoring around retrieving icon images
This commit is contained in:
parent
a6fadb76cc
commit
93813358b5
9 changed files with 67 additions and 81 deletions
|
@ -196,10 +196,10 @@ class Application(ttk.Frame):
|
|||
self.menubar.set_state(is_runtime=False)
|
||||
self.toolbar.set_design()
|
||||
|
||||
def get_icon(self, image_enum: ImageEnum, width: int) -> PhotoImage:
|
||||
def get_icon(self, image_enum: ImageEnum, *, width: int) -> PhotoImage:
|
||||
return images.from_enum(image_enum, width=width, scale=self.app_scale)
|
||||
|
||||
def get_custom_icon(self, image_file: str, width: int) -> PhotoImage:
|
||||
def get_custom_icon(self, image_file: str, *, width: int) -> PhotoImage:
|
||||
return images.from_name(image_file, width=width, scale=self.app_scale)
|
||||
|
||||
def close(self) -> None:
|
||||
|
|
|
@ -84,17 +84,17 @@ class MobilityPlayerDialog(Dialog):
|
|||
for i in range(3):
|
||||
frame.columnconfigure(i, weight=1)
|
||||
|
||||
image = self.app.get_icon(ImageEnum.START, ICON_SIZE)
|
||||
image = self.app.get_icon(ImageEnum.START, width=ICON_SIZE)
|
||||
self.play_button = ttk.Button(frame, image=image, command=self.click_play)
|
||||
self.play_button.image = image
|
||||
self.play_button.grid(row=0, column=0, sticky=tk.EW, padx=PADX)
|
||||
|
||||
image = self.app.get_icon(ImageEnum.PAUSE, ICON_SIZE)
|
||||
image = self.app.get_icon(ImageEnum.PAUSE, width=ICON_SIZE)
|
||||
self.pause_button = ttk.Button(frame, image=image, command=self.click_pause)
|
||||
self.pause_button.image = image
|
||||
self.pause_button.grid(row=0, column=1, sticky=tk.EW, padx=PADX)
|
||||
|
||||
image = self.app.get_icon(ImageEnum.STOP, ICON_SIZE)
|
||||
image = self.app.get_icon(ImageEnum.STOP, width=ICON_SIZE)
|
||||
self.stop_button = ttk.Button(frame, image=image, command=self.click_stop)
|
||||
self.stop_button.image = image
|
||||
self.stop_button.grid(row=0, column=2, sticky=tk.EW, padx=PADX)
|
||||
|
|
|
@ -49,10 +49,10 @@ class ServiceConfigDialog(Dialog):
|
|||
self.default_directories: List[str] = []
|
||||
self.temp_directories: List[str] = []
|
||||
self.documentnew_img: PhotoImage = self.app.get_icon(
|
||||
ImageEnum.DOCUMENTNEW, ICON_SIZE
|
||||
ImageEnum.DOCUMENTNEW, width=ICON_SIZE
|
||||
)
|
||||
self.editdelete_img: PhotoImage = self.app.get_icon(
|
||||
ImageEnum.EDITDELETE, ICON_SIZE
|
||||
ImageEnum.EDITDELETE, width=ICON_SIZE
|
||||
)
|
||||
self.notebook: Optional[ttk.Notebook] = None
|
||||
self.metadata_entry: Optional[ttk.Entry] = None
|
||||
|
|
|
@ -17,7 +17,6 @@ from core.gui.graph.enums import GraphMode, ScaleOption
|
|||
from core.gui.graph.node import CanvasNode, ShadowNode
|
||||
from core.gui.graph.shape import Shape
|
||||
from core.gui.graph.shapeutils import ShapeType, is_draw_shape, is_marker
|
||||
from core.gui.images import TypeToImage
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.gui.app import Application
|
||||
|
@ -26,7 +25,6 @@ if TYPE_CHECKING:
|
|||
|
||||
ZOOM_IN: float = 1.1
|
||||
ZOOM_OUT: float = 0.9
|
||||
ICON_SIZE: int = 48
|
||||
MOVE_NODE_MODES: Set[GraphMode] = {GraphMode.NODE, GraphMode.SELECT}
|
||||
MOVE_SHAPE_MODES: Set[GraphMode] = {GraphMode.ANNOTATION, GraphMode.SELECT}
|
||||
BACKGROUND_COLOR: str = "#cccccc"
|
||||
|
@ -518,14 +516,6 @@ class CanvasGraph(tk.Canvas):
|
|||
if not core_node:
|
||||
return
|
||||
core_node.canvas = self.id
|
||||
try:
|
||||
image_enum = self.manager.node_draw.image_enum
|
||||
self.manager.node_draw.image = self.app.get_icon(image_enum, ICON_SIZE)
|
||||
except AttributeError:
|
||||
image_file = self.manager.node_draw.image_file
|
||||
self.manager.node_draw.image = self.app.get_custom_icon(
|
||||
image_file, ICON_SIZE
|
||||
)
|
||||
node = CanvasNode(self.app, self, x, y, core_node, self.manager.node_draw.image)
|
||||
self.nodes[node.id] = node
|
||||
self.core.set_canvas_node(core_node, node)
|
||||
|
@ -801,25 +791,14 @@ class CanvasGraph(tk.Canvas):
|
|||
self.tag_raise(tags.NODE)
|
||||
|
||||
def scale_graph(self) -> None:
|
||||
for nid, canvas_node in self.nodes.items():
|
||||
img = None
|
||||
if nutils.is_custom(canvas_node.core_node):
|
||||
for custom_node in self.app.guiconfig.nodes:
|
||||
if custom_node.name == canvas_node.core_node.model:
|
||||
img = self.app.get_custom_icon(custom_node.image, ICON_SIZE)
|
||||
else:
|
||||
image_enum = TypeToImage.get(
|
||||
canvas_node.core_node.type, canvas_node.core_node.model
|
||||
)
|
||||
img = self.app.get_icon(image_enum, ICON_SIZE)
|
||||
|
||||
self.itemconfig(nid, image=img)
|
||||
canvas_node.image = img
|
||||
for node_id, canvas_node in self.nodes.items():
|
||||
image = nutils.get_icon(canvas_node.core_node, self.app)
|
||||
self.itemconfig(node_id, image=image)
|
||||
canvas_node.image = image
|
||||
canvas_node.scale_text()
|
||||
canvas_node.scale_antennas()
|
||||
|
||||
for edge_id in self.find_withtag(tags.EDGE):
|
||||
self.itemconfig(edge_id, width=int(EDGE_WIDTH * self.app.app_scale))
|
||||
for edge_id in self.find_withtag(tags.EDGE):
|
||||
self.itemconfig(edge_id, width=int(EDGE_WIDTH * self.app.app_scale))
|
||||
|
||||
def get_metadata(self) -> Dict[str, Any]:
|
||||
wallpaper_path = None
|
||||
|
|
|
@ -5,7 +5,6 @@ from tkinter import BooleanVar, messagebox, ttk
|
|||
from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, ValuesView
|
||||
|
||||
from core.api.grpc.wrappers import Link, LinkType, Node, Session, ThroughputsEvent
|
||||
from core.gui import images
|
||||
from core.gui import nodeutils as nutils
|
||||
from core.gui.graph import tags
|
||||
from core.gui.graph.edges import (
|
||||
|
@ -18,7 +17,6 @@ from core.gui.graph.enums import GraphMode
|
|||
from core.gui.graph.graph import CanvasGraph
|
||||
from core.gui.graph.node import CanvasNode
|
||||
from core.gui.graph.shapeutils import ShapeType
|
||||
from core.gui.images import ImageEnum
|
||||
from core.gui.nodeutils import NodeDraw
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
@ -301,10 +299,7 @@ class CanvasManager:
|
|||
canvas_id = core_node.canvas if core_node.canvas > 0 else 1
|
||||
logging.info("adding core node canvas(%s): %s", core_node.name, canvas_id)
|
||||
canvas = self.get(canvas_id)
|
||||
# if the gui can't find node's image, default to the "edit-node" image
|
||||
image = nutils.get_icon(core_node, self.app.guiconfig, self.app.app_scale)
|
||||
if not image:
|
||||
image = self.app.get_icon(ImageEnum.EDITNODE, images.NODE_SIZE)
|
||||
image = nutils.get_icon(core_node, self.app)
|
||||
x = core_node.position.x
|
||||
y = core_node.position.y
|
||||
node = CanvasNode(self.app, canvas, x, y, core_node, image)
|
||||
|
|
|
@ -95,7 +95,7 @@ class CanvasNode:
|
|||
def add_antenna(self) -> None:
|
||||
x, y = self.position()
|
||||
offset = len(self.antennas) * 8 * self.app.app_scale
|
||||
img = self.app.get_icon(ImageEnum.ANTENNA, images.ANTENNA_SIZE)
|
||||
img = self.app.get_icon(ImageEnum.ANTENNA, width=images.ANTENNA_SIZE)
|
||||
antenna_id = self.canvas.create_image(
|
||||
x - 16 + offset,
|
||||
y - int(23 * self.app.app_scale),
|
||||
|
@ -389,7 +389,7 @@ class CanvasNode:
|
|||
def scale_antennas(self) -> None:
|
||||
for i in range(len(self.antennas)):
|
||||
antenna_id = self.antennas[i]
|
||||
image = self.app.get_icon(ImageEnum.ANTENNA, images.ANTENNA_SIZE)
|
||||
image = self.app.get_icon(ImageEnum.ANTENNA, width=images.ANTENNA_SIZE)
|
||||
self.canvas.itemconfig(antenna_id, image=image)
|
||||
self.antenna_images[antenna_id] = image
|
||||
node_x, node_y = self.canvas.coords(self.id)
|
||||
|
@ -492,7 +492,9 @@ class ShadowNode:
|
|||
self.node: "CanvasNode" = node
|
||||
self.id: Optional[int] = None
|
||||
self.text_id: Optional[int] = None
|
||||
self.image: PhotoImage = self.app.get_icon(ImageEnum.SHADOW, images.NODE_SIZE)
|
||||
self.image: PhotoImage = self.app.get_icon(
|
||||
ImageEnum.SHADOW, width=images.NODE_SIZE
|
||||
)
|
||||
self.draw()
|
||||
self.setup_bindings()
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ from typing import Dict, Optional, Tuple
|
|||
from PIL import Image
|
||||
from PIL.ImageTk import PhotoImage
|
||||
|
||||
from core.api.grpc.wrappers import NodeType
|
||||
from core.api.grpc.wrappers import Node, NodeType
|
||||
from core.gui.appconfig import LOCAL_ICONS_PATH
|
||||
|
||||
NODE_SIZE: int = 48
|
||||
|
@ -89,23 +89,26 @@ class ImageEnum(Enum):
|
|||
SHADOW = "shadow"
|
||||
|
||||
|
||||
class TypeToImage:
|
||||
type_to_image: Dict[Tuple[NodeType, str], ImageEnum] = {
|
||||
(NodeType.DEFAULT, "router"): ImageEnum.ROUTER,
|
||||
(NodeType.DEFAULT, "PC"): ImageEnum.PC,
|
||||
(NodeType.DEFAULT, "host"): ImageEnum.HOST,
|
||||
(NodeType.DEFAULT, "mdr"): ImageEnum.MDR,
|
||||
(NodeType.DEFAULT, "prouter"): ImageEnum.PROUTER,
|
||||
(NodeType.HUB, ""): ImageEnum.HUB,
|
||||
(NodeType.SWITCH, ""): ImageEnum.SWITCH,
|
||||
(NodeType.WIRELESS_LAN, ""): ImageEnum.WLAN,
|
||||
(NodeType.EMANE, ""): ImageEnum.EMANE,
|
||||
(NodeType.RJ45, ""): ImageEnum.RJ45,
|
||||
(NodeType.TUNNEL, ""): ImageEnum.TUNNEL,
|
||||
(NodeType.DOCKER, ""): ImageEnum.DOCKER,
|
||||
(NodeType.LXC, ""): ImageEnum.LXC,
|
||||
}
|
||||
TYPE_MAP: Dict[Tuple[NodeType, str], ImageEnum] = {
|
||||
(NodeType.DEFAULT, "router"): ImageEnum.ROUTER,
|
||||
(NodeType.DEFAULT, "PC"): ImageEnum.PC,
|
||||
(NodeType.DEFAULT, "host"): ImageEnum.HOST,
|
||||
(NodeType.DEFAULT, "mdr"): ImageEnum.MDR,
|
||||
(NodeType.DEFAULT, "prouter"): ImageEnum.PROUTER,
|
||||
(NodeType.HUB, ""): ImageEnum.HUB,
|
||||
(NodeType.SWITCH, ""): ImageEnum.SWITCH,
|
||||
(NodeType.WIRELESS_LAN, ""): ImageEnum.WLAN,
|
||||
(NodeType.EMANE, ""): ImageEnum.EMANE,
|
||||
(NodeType.RJ45, ""): ImageEnum.RJ45,
|
||||
(NodeType.TUNNEL, ""): ImageEnum.TUNNEL,
|
||||
(NodeType.DOCKER, ""): ImageEnum.DOCKER,
|
||||
(NodeType.LXC, ""): ImageEnum.LXC,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get(cls, node_type, model) -> Optional[ImageEnum]:
|
||||
return cls.type_to_image.get((node_type, model))
|
||||
|
||||
def from_node(node: Node, *, scale: float) -> Optional[PhotoImage]:
|
||||
image = None
|
||||
image_enum = TYPE_MAP.get((node.type, node.model))
|
||||
if image_enum:
|
||||
image = from_enum(image_enum, width=NODE_SIZE, scale=scale)
|
||||
return image
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
import logging
|
||||
from typing import List, Optional, Set
|
||||
from typing import TYPE_CHECKING, List, Optional, Set
|
||||
|
||||
from PIL.ImageTk import PhotoImage
|
||||
|
||||
from core.api.grpc.wrappers import Node, NodeType
|
||||
from core.gui import images
|
||||
from core.gui.appconfig import CustomNode, GuiConfig
|
||||
from core.gui.images import ImageEnum, TypeToImage
|
||||
from core.gui.images import ImageEnum
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.gui.app import Application
|
||||
|
||||
NODES: List["NodeDraw"] = []
|
||||
NETWORK_NODES: List["NodeDraw"] = []
|
||||
|
@ -100,14 +103,15 @@ def get_custom_services(gui_config: GuiConfig, name: str) -> List[str]:
|
|||
return []
|
||||
|
||||
|
||||
def _get_image_file(config: GuiConfig, name: str) -> Optional[str]:
|
||||
def _get_custom_file(config: GuiConfig, name: str) -> Optional[str]:
|
||||
for custom_node in config.nodes:
|
||||
if custom_node.name == name:
|
||||
return custom_node.image
|
||||
return None
|
||||
|
||||
|
||||
def get_icon(node: Node, config: GuiConfig, scale: float) -> Optional[PhotoImage]:
|
||||
def get_icon(node: Node, app: "Application") -> PhotoImage:
|
||||
scale = app.app_scale
|
||||
image = None
|
||||
# node has defined a custom icon
|
||||
if node.icon:
|
||||
|
@ -117,16 +121,19 @@ def get_icon(node: Node, config: GuiConfig, scale: float) -> Optional[PhotoImage
|
|||
logging.error("invalid icon: %s", node.icon)
|
||||
else:
|
||||
# attempt to find default type/model image
|
||||
image_enum = TypeToImage.get(node.type, node.model)
|
||||
if image_enum:
|
||||
image = images.from_enum(image_enum, width=images.NODE_SIZE, scale=scale)
|
||||
image = images.from_node(node, scale=scale)
|
||||
# attempt to find custom image file
|
||||
else:
|
||||
image_file = _get_image_file(config, node.model)
|
||||
if not image:
|
||||
image_file = _get_custom_file(app.guiconfig, node.model)
|
||||
if image_file:
|
||||
image = images.from_name(
|
||||
image_file, width=images.NODE_SIZE, scale=scale
|
||||
)
|
||||
# default image, if everything above fails
|
||||
if not image:
|
||||
image = images.from_enum(
|
||||
ImageEnum.EDITNODE, width=images.NODE_SIZE, scale=scale
|
||||
)
|
||||
return image
|
||||
|
||||
|
||||
|
|
|
@ -58,11 +58,11 @@ class PickerFrame(ttk.Frame):
|
|||
image_file: str = None,
|
||||
) -> None:
|
||||
if image_enum:
|
||||
bar_image = self.app.get_icon(image_enum, TOOLBAR_SIZE)
|
||||
image = self.app.get_icon(image_enum, PICKER_SIZE)
|
||||
bar_image = self.app.get_icon(image_enum, width=TOOLBAR_SIZE)
|
||||
image = self.app.get_icon(image_enum, width=PICKER_SIZE)
|
||||
else:
|
||||
bar_image = self.app.get_custom_icon(image_file, TOOLBAR_SIZE)
|
||||
image = self.app.get_custom_icon(image_file, PICKER_SIZE)
|
||||
bar_image = self.app.get_custom_icon(image_file, width=TOOLBAR_SIZE)
|
||||
image = self.app.get_custom_icon(image_file, width=PICKER_SIZE)
|
||||
button = ttk.Button(
|
||||
self, image=image, text=label, compound=tk.TOP, style=Styles.picker_button
|
||||
)
|
||||
|
@ -93,7 +93,7 @@ class ButtonBar(ttk.Frame):
|
|||
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)
|
||||
image = self.app.get_icon(image_enum, width=TOOLBAR_SIZE)
|
||||
button = ttk.Button(self, image=image, command=func)
|
||||
button.image = image
|
||||
button.grid(sticky=tk.EW)
|
||||
|
@ -122,7 +122,7 @@ class MarkerFrame(ttk.Frame):
|
|||
def draw(self) -> None:
|
||||
self.columnconfigure(0, weight=1)
|
||||
|
||||
image = self.app.get_icon(ImageEnum.DELETE, 16)
|
||||
image = self.app.get_icon(ImageEnum.DELETE, width=16)
|
||||
button = ttk.Button(self, image=image, width=2, command=self.click_clear)
|
||||
button.image = image
|
||||
button.grid(sticky=tk.EW, pady=self.PAD)
|
||||
|
@ -384,7 +384,7 @@ class Toolbar(ttk.Frame):
|
|||
self.picker.show()
|
||||
|
||||
def create_observe_button(self) -> None:
|
||||
image = self.app.get_icon(ImageEnum.OBSERVE, TOOLBAR_SIZE)
|
||||
image = self.app.get_icon(ImageEnum.OBSERVE, width=TOOLBAR_SIZE)
|
||||
menu_button = ttk.Menubutton(
|
||||
self.runtime_frame, image=image, direction=tk.RIGHT
|
||||
)
|
||||
|
@ -446,9 +446,9 @@ class Toolbar(ttk.Frame):
|
|||
) -> None:
|
||||
image = None
|
||||
if image_enum:
|
||||
image = self.app.get_icon(image_enum, TOOLBAR_SIZE)
|
||||
image = self.app.get_icon(image_enum, width=TOOLBAR_SIZE)
|
||||
elif image_file:
|
||||
image = self.app.get_custom_icon(image_file, TOOLBAR_SIZE)
|
||||
image = self.app.get_custom_icon(image_file, width=TOOLBAR_SIZE)
|
||||
if image:
|
||||
button.config(image=image)
|
||||
button.image = image
|
||||
|
|
Loading…
Reference in a new issue