cleanup for shapes and creating shapes and storing and restoring shapes from metadata

This commit is contained in:
Blake Harnden 2019-12-06 14:01:03 -08:00
parent c238b5dfc8
commit 742eb2bed6
7 changed files with 190 additions and 137 deletions

View file

@ -5,12 +5,14 @@ import json
import logging
import os
import time
from pathlib import Path
from core.api.grpc import client, core_pb2
from coretk import appconfig
from coretk.dialogs.mobilityplayer import MobilityPlayer
from coretk.dialogs.sessions import SessionsDialog
from coretk.graph.shape import AnnotationData, Shape
from coretk.graph.shapeutils import ShapeType
from coretk.interface import InterfaceManager
from coretk.nodeutils import NodeDraw, NodeUtils
@ -136,7 +138,6 @@ class CoreClient:
self.custom_observers[observer.name] = observer
def handle_events(self, event):
print(event)
if event.HasField("link_event"):
logging.info("link event: %s", event)
self.handle_link_event(event.link_event)
@ -162,7 +163,7 @@ class CoreClient:
elif event.HasField("config_event"):
logging.info("config event: %s", event)
elif event.HasField("throughput_event"):
print("throughput")
logging.info("throughput event: %s", event)
else:
logging.info("unhandled event: %s", event)
@ -301,35 +302,42 @@ class CoreClient:
def parse_metadata(self, config):
# canvas setting
canvas_config = config.get("canvas")
if canvas_config:
logging.info("canvas metadata: %s", canvas_config)
if canvas_config:
canvas_config = json.loads(canvas_config)
wallpaper_style = canvas_config["wallpaper-style"]
self.app.canvas.scale_option.set(wallpaper_style)
wallpaper = canvas_config["wallpaper"]
if wallpaper:
wallpaper = str(appconfig.BACKGROUNDS_PATH.joinpath(wallpaper))
self.app.canvas.set_wallpaper(wallpaper)
for key, annotation_config in config.items():
if "annotation" in key:
annotation_config = json.loads(annotation_config)
config_type = annotation_config["type"]
if config_type in ["rectangle", "oval"]:
coords = tuple(annotation_config["iconcoords"])
# load saved shapes
shapes_config = config.get("shapes")
if shapes_config:
shapes_config = json.loads(shapes_config)
for shape_config in shapes_config:
logging.info("loading shape: %s", shapes_config)
shape_type = shape_config["type"]
try:
shape_type = ShapeType(shape_type)
x1, y1, x2, y2 = shape_config["iconcoords"]
data = AnnotationData(
annotation_config["label"],
annotation_config["fontfamily"],
annotation_config["fontsize"],
annotation_config["labelcolor"],
annotation_config["color"],
annotation_config["border"],
annotation_config["width"],
shape_config["label"],
shape_config["fontfamily"],
shape_config["fontsize"],
shape_config["labelcolor"],
shape_config["color"],
shape_config["border"],
shape_config["width"],
)
shape = Shape(
self.app, self.app.canvas, None, None, coords, data, config_type
self.app, self.app.canvas, shape_type, x1, y1, x2, y2, data
)
self.app.canvas.shapes[shape.id] = shape
else:
logging.debug("not implemented")
except ValueError:
logging.debug("unknown shape: %s", shape_type)
for tag in LIFT_ORDER:
self.app.canvas.tag_raise(tag)
@ -427,6 +435,7 @@ class CoreClient:
service_configs,
file_configs,
)
self.set_metadata()
process_time = time.perf_counter() - start
logging.debug("start session(%s), result: %s", self.session_id, response.result)
self.app.statusbar.start_session_callback(process_time)
@ -447,6 +456,24 @@ class CoreClient:
self.app.statusbar.stop_session_callback(process_time)
logging.debug("stopped session(%s), result: %s", session_id, response.result)
def set_metadata(self):
# create canvas data
canvas_config = {
"wallpaper": Path(self.app.canvas.wallpaper_file).name,
"wallpaper-style": self.app.canvas.scale_option.get(),
}
canvas_config = json.dumps(canvas_config)
# create shapes data
shapes = []
for shape in self.app.canvas.shapes.values():
shapes.append(shape.metadata())
shapes = json.dumps(shapes)
metadata = {"canvas": canvas_config, "shapes": shapes}
response = self.client.set_session_metadata(self.session_id, metadata)
logging.info("set session metadata: %s", response)
def launch_terminal(self, node_id):
response = self.client.get_node_terminal(self.session_id, node_id)
logging.info("get terminal %s", response.terminal)

View file

@ -5,7 +5,7 @@ import tkinter as tk
from tkinter import colorchooser, font, ttk
from coretk.dialogs.dialog import Dialog
from coretk.images import ImageEnum
from coretk.graph.shapeutils import is_draw_shape, is_shape_text
FONT_SIZES = [8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72]
BORDER_WIDTH = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
@ -13,40 +13,34 @@ BORDER_WIDTH = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
class ShapeDialog(Dialog):
def __init__(self, master, app, shape):
self.annotation_type = app.canvas.annotation_type
self.canvas = app.canvas
if self.is_shape():
super().__init__(master, app, "Add a new shape", modal=True)
if is_draw_shape(shape.shape_type):
title = "Add Shape"
self.id = shape.id
else:
title = "Add Text"
self.id = None
self.canvas = app.canvas
super().__init__(master, app, title, modal=True)
self.fill = None
self.border = None
else:
super().__init__(master, app, "Add a new text", modal=True)
self.shape = shape
data = shape.shape_data
self.shape_text = tk.StringVar(value=data.text)
self.font = tk.StringVar(value=data.font)
self.font_size = tk.IntVar(value=data.font_size)
self.text_color = data.text_color
self.fill_color = data.fill_color
fill_color = data.fill_color
if not fill_color:
fill_color = "#CFCFFF"
self.fill_color = fill_color
self.border_color = data.border_color
self.border_width = tk.IntVar(value=data.border_width)
self.border_width = tk.IntVar(value=0)
self.bold = tk.IntVar(value=data.bold)
self.italic = tk.IntVar(value=data.italic)
self.underline = tk.IntVar(value=data.underline)
self.top.columnconfigure(0, weight=1)
self.draw()
def is_shape(self):
return (
self.annotation_type == ImageEnum.OVAL
or self.annotation_type == ImageEnum.RECTANGLE
)
def is_text(self):
return self.annotation_type == ImageEnum.TEXT
def draw(self):
frame = ttk.Frame(self.top)
frame.columnconfigure(0, weight=1)
@ -85,7 +79,7 @@ class ShapeDialog(Dialog):
button.grid(row=0, column=2)
frame.grid(row=2, column=0, sticky="nsew", padx=3, pady=3)
if self.is_shape():
if is_draw_shape(self.shape.shape_type):
frame = ttk.Frame(self.top)
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=1)
@ -152,15 +146,18 @@ class ShapeDialog(Dialog):
self.border.config(background=color[1], text=color[1])
def cancel(self):
if self.is_shape() and not self.canvas.shapes[self.id].created:
if (
is_draw_shape(self.shape.shape_type)
and not self.canvas.shapes[self.id].created
):
self.canvas.delete(self.id)
self.canvas.shapes.pop(self.id)
self.destroy()
def click_add(self):
if self.is_shape():
if is_draw_shape(self.shape.shape_type):
self.add_shape()
elif self.is_text():
elif is_shape_text(self.shape.shape_type):
self.add_text()
self.destroy()
@ -212,8 +209,8 @@ class ShapeDialog(Dialog):
:return: nothing
"""
text = self.shape_text.get()
x = self.shape.x0
y = self.shape.y0
x = self.shape.x1
y = self.shape.y1
text_font = self.make_font()
if self.shape.text_id is None:
tid = self.canvas.create_text(

View file

@ -16,8 +16,3 @@ class ScaleOption(enum.Enum):
CENTERED = 2
SCALED = 3
TILED = 4
class ShapeType(enum.Enum):
OVAL = 0
RECTANGLE = 1

View file

@ -10,7 +10,8 @@ from coretk.graph.enums import GraphMode, ScaleOption
from coretk.graph.linkinfo import LinkInfo, Throughput
from coretk.graph.node import CanvasNode
from coretk.graph.shape import Shape
from coretk.images import ImageEnum, Images
from coretk.graph.shapeutils import is_draw_shape, is_shape_text
from coretk.images import Images
from coretk.nodeutils import NodeUtils
ABOVE_WALLPAPER = ["edge", "linkinfo", "wireless", "antenna", "nodename", "node"]
@ -243,13 +244,13 @@ class CanvasGraph(tk.Canvas):
self.context = None
else:
if self.mode == GraphMode.ANNOTATION:
if self.annotation_type in [ImageEnum.OVAL, ImageEnum.RECTANGLE]:
if is_draw_shape(self.annotation_type):
self.focus_set()
x, y = self.canvas_xy(event)
if self.shape_drawing:
self.shapes[self.selected].shape_complete(x, y)
self.shape_drawing = False
elif self.annotation_type == ImageEnum.TEXT:
elif is_shape_text(self.annotation_type):
self.text.shape_complete(self.text.cursor_x, self.text.cursor_y)
else:
self.focus_set()
@ -401,15 +402,14 @@ class CanvasGraph(tk.Canvas):
self.drawing_edge = CanvasEdge(x, y, x, y, selected, self)
if self.mode == GraphMode.ANNOTATION and selected is None:
if self.annotation_type in [ImageEnum.OVAL, ImageEnum.RECTANGLE]:
x, y = self.canvas_xy(event)
shape = Shape(self.app, self, x, y)
if is_draw_shape(self.annotation_type):
shape = Shape(self.app, self, self.annotation_type, x, y)
self.selected = shape.id
self.shapes[shape.id] = shape
self.shape_drawing = True
elif self.annotation_type == ImageEnum.TEXT:
x, y = self.canvas_xy(event)
self.text = Shape(self.app, self, x, y)
elif is_shape_text(self.annotation_type):
self.text = Shape(self.app, self, self.annotation_type, x, y)
if self.mode == GraphMode.SELECT:
if selected is not None:
@ -446,10 +446,7 @@ class CanvasGraph(tk.Canvas):
x1, y1, _, _ = self.coords(self.drawing_edge.id)
self.coords(self.drawing_edge.id, x1, y1, x2, y2)
if self.mode == GraphMode.ANNOTATION:
if (
self.annotation_type in [ImageEnum.OVAL, ImageEnum.RECTANGLE]
and self.shape_drawing
):
if is_draw_shape(self.annotation_type) and self.shape_drawing:
x, y = self.canvas_xy(event)
self.shapes[self.selected].shape_motion(x, y)
if (

View file

@ -1,8 +1,7 @@
"""
class for shapes
"""
from tkinter.font import Font
from coretk.dialogs.shapemod import ShapeDialog
from coretk.images import ImageEnum
from coretk.graph.shapeutils import ShapeType
ABOVE_COMPONENT = ["gridline", "edge", "linkinfo", "antenna", "node", "nodename"]
@ -14,14 +13,13 @@ class AnnotationData:
font="Arial",
font_size=12,
text_color="#000000",
fill_color="#CFCFFF",
fill_color="",
border_color="#000000",
border_width=0,
border_width=1,
bold=0,
italic=0,
underline=0,
):
self.text = text
self.font = font
self.font_size = font_size
@ -35,72 +33,77 @@ class AnnotationData:
class Shape:
def __init__(
self,
app,
canvas,
top_x=None,
top_y=None,
coords=None,
data=None,
shape_type=None,
):
def __init__(self, app, canvas, shape_type, x1, y1, x2=None, y2=None, data=None):
self.app = app
self.canvas = canvas
if data is None:
self.x0 = top_x
self.y0 = top_y
self.created = False
self.shape_type = shape_type
self.id = None
self.text_id = None
self.x1 = x1
self.y1 = y1
if x2 is None:
x2 = x1
self.x2 = x2
if y2 is None:
y2 = y1
self.y2 = y2
if data is None:
self.created = False
self.shape_data = AnnotationData()
canvas.delete(canvas.find_withtag("selectednodes"))
annotation_type = self.canvas.annotation_type
if annotation_type == ImageEnum.OVAL:
self.id = canvas.create_oval(
top_x, top_y, top_x, top_y, tags="shape", dash="-"
)
elif annotation_type == ImageEnum.RECTANGLE:
self.id = canvas.create_rectangle(
top_x, top_y, top_x, top_y, tags="shape", dash="-"
)
self.cursor_x = x1
self.cursor_y = y1
else:
x0, y0, x1, y1 = coords
self.x0 = x0
self.y0 = y0
self.created = True
if shape_type == "oval":
self.id = self.canvas.create_oval(
x0,
y0,
x1,
y1,
tags="shape",
fill=data.fill_color,
outline=data.border_color,
width=data.border_width,
)
elif shape_type == "rectangle":
self.id = self.canvas.create_rectangle(
x0,
y0,
x1,
y1,
tags="shape",
fill=data.fill_color,
outline=data.border_color,
width=data.border_width,
)
_x = (x0 + x1) / 2
_y = y0 + 1.5 * data.font_size
self.text_id = self.canvas.create_text(
_x, _y, tags="shapetext", text=data.text, fill=data.text_color
)
self.shape_data = data
self.cursor_x = None
self.cursor_y = None
self.draw()
def draw(self):
if self.created:
dash = None
else:
dash = "-"
if self.shape_type == ShapeType.OVAL:
self.id = self.canvas.create_oval(
self.x1,
self.y1,
self.x2,
self.y2,
tags="shape",
dash=dash,
fill=self.shape_data.fill_color,
outline=self.shape_data.border_color,
width=self.shape_data.border_width,
)
elif self.shape_type == ShapeType.RECTANGLE:
self.id = self.canvas.create_rectangle(
self.x1,
self.y1,
self.x2,
self.y2,
tags="shape",
dash=dash,
fill=self.shape_data.fill_color,
outline=self.shape_data.border_color,
width=self.shape_data.border_width,
)
if self.shape_data.text:
x = (self.x1 + self.x2) / 2
y = self.y1 + 1.5 * self.shape_data.font_size
font = Font(family=self.shape_data.font, size=self.shape_data.font_size)
self.text_id = self.canvas.create_text(
x,
y,
tags="shapetext",
text=self.shape_data.text,
fill=self.shape_data.text_color,
font=font,
)
def shape_motion(self, x1, y1):
self.canvas.coords(self.id, self.x0, self.y0, x1, y1)
self.canvas.coords(self.id, self.x1, self.y1, x1, y1)
def shape_complete(self, x, y):
for component in ABOVE_COMPONENT:
@ -122,3 +125,17 @@ class Shape:
def delete(self):
self.canvas.delete(self.id)
self.canvas.delete(self.text_id)
def metadata(self):
coords = self.canvas.coords(self.id)
return {
"type": self.shape_type.value,
"iconcoords": coords,
"label": self.shape_data.text,
"fontfamily": self.shape_data.font,
"fontsize": self.shape_data.font_size,
"labelcolor": self.shape_data.text_color,
"color": self.shape_data.fill_color,
"border": self.shape_data.border_color,
"width": self.shape_data.border_width,
}

View file

@ -0,0 +1,19 @@
import enum
class ShapeType(enum.Enum):
MARKER = "marker"
OVAL = "oval"
RECTANGLE = "rectangle"
TEXT = "text"
SHAPES = {ShapeType.OVAL, ShapeType.RECTANGLE}
def is_draw_shape(shape_type):
return shape_type in SHAPES
def is_shape_text(shape_type):
return shape_type == ShapeType.TEXT

View file

@ -6,6 +6,7 @@ from tkinter import ttk
from coretk.dialogs.customnodes import CustomNodesDialog
from coretk.graph.enums import GraphMode
from coretk.graph.shapeutils import ShapeType
from coretk.images import ImageEnum, Images
from coretk.nodeutils import NodeUtils
from coretk.tooltip import Tooltip
@ -291,18 +292,18 @@ class Toolbar(ttk.Frame):
self.hide_pickers()
self.annotation_picker = ttk.Frame(self.master)
nodes = [
(ImageEnum.MARKER, "marker"),
(ImageEnum.OVAL, "oval"),
(ImageEnum.RECTANGLE, "rectangle"),
(ImageEnum.TEXT, "text"),
(ImageEnum.MARKER, ShapeType.MARKER),
(ImageEnum.OVAL, ShapeType.OVAL),
(ImageEnum.RECTANGLE, ShapeType.RECTANGLE),
(ImageEnum.TEXT, ShapeType.TEXT),
]
for image_enum, tooltip in nodes:
for image_enum, shape_type in nodes:
image = icon(image_enum)
self.create_picker_button(
image,
partial(self.update_annotation, image, image_enum),
partial(self.update_annotation, image, shape_type),
self.annotation_picker,
tooltip,
shape_type.value,
)
self.design_select(self.annotation_button)
self.annotation_button.after(
@ -362,13 +363,13 @@ class Toolbar(ttk.Frame):
self.design_frame.tkraise()
def update_annotation(self, image, image_enum):
def update_annotation(self, image, shape_type):
logging.info("clicked annotation: ")
self.hide_pickers()
self.annotation_button.configure(image=image)
self.annotation_button.image = image
self.app.canvas.mode = GraphMode.ANNOTATION
self.app.canvas.annotation_type = image_enum
self.app.canvas.annotation_type = shape_type
def click_run_button(self):
logging.debug("Click on RUN button")