reload custom node image when open xml, if the gui doesn't know about the custom image, use a default one

This commit is contained in:
Huy Pham 2020-01-27 16:27:21 -08:00
parent b4b71eda0e
commit 4c0254ec10
3 changed files with 57 additions and 11 deletions

View file

@ -12,6 +12,7 @@ from core.gui.graph.enums import GraphMode, ScaleOption
from core.gui.graph.node import CanvasNode from core.gui.graph.node import CanvasNode
from core.gui.graph.shape import Shape from core.gui.graph.shape import Shape
from core.gui.graph.shapeutils import ShapeType, is_draw_shape, is_marker from core.gui.graph.shapeutils import ShapeType, is_draw_shape, is_marker
from core.gui.images import ImageEnum, Images
from core.gui.nodeutils import EdgeUtils, NodeUtils from core.gui.nodeutils import EdgeUtils, NodeUtils
if TYPE_CHECKING: if TYPE_CHECKING:
@ -20,6 +21,7 @@ if TYPE_CHECKING:
ZOOM_IN = 1.1 ZOOM_IN = 1.1
ZOOM_OUT = 0.9 ZOOM_OUT = 0.9
ICON_SIZE = 48
class CanvasGraph(tk.Canvas): class CanvasGraph(tk.Canvas):
@ -217,7 +219,10 @@ class CanvasGraph(tk.Canvas):
# peer to peer node is not drawn on the GUI # peer to peer node is not drawn on the GUI
if NodeUtils.is_ignore_node(core_node.type): if NodeUtils.is_ignore_node(core_node.type):
continue continue
image = NodeUtils.node_image(core_node) image = NodeUtils.node_image(core_node, self.app.guiconfig)
# if the gui can't find node's image, default to the "edit-node" image
if not image:
image = Images.get(ImageEnum.EDITNODE, ICON_SIZE)
x = core_node.position.x x = core_node.position.x
y = core_node.position.y y = core_node.position.y
node = CanvasNode(self.master, x, y, core_node, image) node = CanvasNode(self.master, x, y, core_node, image)

View file

@ -1,4 +1,5 @@
from enum import Enum from enum import Enum
from tkinter import messagebox
from PIL import Image, ImageTk from PIL import Image, ImageTk
@ -22,15 +23,32 @@ class Images:
cls.images[image.stem] = str(image) cls.images[image.stem] = str(image)
@classmethod @classmethod
def get(cls, image_enum: Enum, width: int, height: int = None): def get(
cls, image_enum: Enum, width: int, height: int = None
) -> ImageTk.PhotoImage:
file_path = cls.images[image_enum.value] file_path = cls.images[image_enum.value]
return cls.create(file_path, width, height) return cls.create(file_path, width, height)
@classmethod @classmethod
def get_custom(cls, name: str, width: int, height: int = None): def get_with_image_file(
file_path = cls.images[name] cls, stem: str, width: int, height: int = None
) -> ImageTk.PhotoImage:
file_path = cls.images[stem]
return cls.create(file_path, width, height) return cls.create(file_path, width, height)
@classmethod
def get_custom(
cls, name: str, width: int, height: int = None
) -> ImageTk.PhotoImage:
try:
file_path = cls.images[name]
return cls.create(file_path, width, height)
except KeyError:
messagebox.showwarning(
"Missing image file",
f"{name}.png is missing at daemon/core/gui/data/icons, drop image file at daemon/core/gui/data/icons and restart the gui",
)
class ImageEnum(Enum): class ImageEnum(Enum):
SWITCH = "lanswitch" SWITCH = "lanswitch"

View file

@ -1,5 +1,5 @@
import logging import logging
from typing import TYPE_CHECKING, Optional, Set, Tuple from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, Union
from core.api.grpc.core_pb2 import NodeType from core.api.grpc.core_pb2 import NodeType
from core.gui.images import ImageEnum, Images from core.gui.images import ImageEnum, Images
@ -91,14 +91,27 @@ class NodeUtils:
return node_type in cls.RJ45_NODES return node_type in cls.RJ45_NODES
@classmethod @classmethod
def node_icon(cls, node_type: NodeType, model: str) -> "ImageTk.PhotoImage": def node_icon(
cls,
node_type: NodeType,
model: str,
gui_config: Dict[str, List[Dict[str, str]]],
) -> "ImageTk.PhotoImage":
if model == "": if model == "":
model = None model = None
return cls.NODE_ICONS[(node_type, model)] try:
image = cls.NODE_ICONS[(node_type, model)]
return image
except KeyError:
image_stem = cls.get_image_file(gui_config, model)
if image_stem:
return Images.get_with_image_file(image_stem, ICON_SIZE)
@classmethod @classmethod
def node_image(cls, core_node: "core_pb2.Node") -> "ImageTk.PhotoImage": def node_image(
image = cls.node_icon(core_node.type, core_node.model) cls, core_node: "core_pb2.Node", gui_config: Dict[str, List[Dict[str, str]]]
) -> "ImageTk.PhotoImage":
image = cls.node_icon(core_node.type, core_node.model, gui_config)
if core_node.icon: if core_node.icon:
try: try:
image = Images.create(core_node.icon, ICON_SIZE) image = Images.create(core_node.icon, ICON_SIZE)
@ -107,16 +120,26 @@ class NodeUtils:
return image return image
@classmethod @classmethod
def is_custom(cls, model): def is_custom(cls, model: str) -> bool:
return model not in cls.NODE_MODELS return model not in cls.NODE_MODELS
@classmethod @classmethod
def get_custom_node_services(cls, gui_config, name): def get_custom_node_services(
cls, gui_config: Dict[str, List[Dict[str, str]]], name: str
) -> List[str]:
for m in gui_config["nodes"]: for m in gui_config["nodes"]:
if m["name"] == name: if m["name"] == name:
return m["services"] return m["services"]
return [] return []
@classmethod
def get_image_file(cls, gui_config, name: str) -> Union[str, None]:
if "nodes" in gui_config:
for m in gui_config["nodes"]:
if m["name"] == name:
return m["image"]
return None
@classmethod @classmethod
def setup(cls): def setup(cls):
nodes = [ nodes = [