#!/usr/bin/env python
# -*- coding: utf-8 -*-
# File: items.py
#
# Copyright 2021 Vincent Schouten
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
"""
Main code for various tkinter canvas items.
.. _Google Python Style Guide:
http://google.github.io/styleguide/pyguide.html
"""
import uuid
import re
from time import sleep
from itertools import cycle
from abc import ABC, abstractmethod
__author__ = '''Vincent Schouten <powermole@protonmail.com>'''
__docformat__ = '''google'''
__date__ = '''06-12-2019'''
__copyright__ = '''Copyright 2021, Vincent Schouten'''
__credits__ = ["Vincent Schouten"]
__license__ = '''MIT'''
__maintainer__ = '''Vincent Schouten'''
__email__ = '''<powermole@protonmail.com>'''
__status__ = '''Development''' # "Prototype", "Development", "Production".
# Constants
FONT_SIZE = 10
THICKNESS_LINE_CLIENT = 2
THICKNESS_LINE_HOST = 2
THICKNESS_LINE_AGENT = 2
THICKNESS_LINE_TUNNEL = 1
THICKNESS_LINE_PACKET = 1
THICKNESS_PACKET = 2
WIDTH_PACKET = 20
BACKGROUND_CANVAS = '#232729'
LABEL_FONT_COLOUR = 'white'
PACKET_OUTLINE_COLOUR = '#c0c0c0'
PACKET_FILL_COLOUR = '#232729'
NON_OPERATION = 'white'
OK_COLOUR = 'green'
NOK_COLOUR = 'red'
[docs]class CanvasItem(ABC):
"""Enforces methods to be implemented for the subclassed objects."""
def __init__(self, main_window):
"""Instantiates the CanvasItem object.
Args:
main_window (MainWindow): An instantiated MainWindow object.
"""
# self.scale = main_window.scale # IN DEVELOPMENT
self.item_name = self._determine_item_name()
self.item_tag = f"{self.item_name}-{self._uuid}"
self._main_window = main_window
self._canvas_landscape = main_window.main_frame.canvas_frame.canvas_landscape
self._canvas_status = main_window.main_frame.canvas_frame.canvas_status
self._item_label = 0
@property
def _uuid(self):
uuid_ = f'{uuid.uuid4().hex}'
return uuid_
def _determine_item_name(self):
return re.findall(r'[A-Z](?:[a-z]+|[A-Z]*(?=[A-Z]|$))', type(self).__name__)[0] # split words at CamelCase
def _add_label(self, item_name):
coord_x1, coord_y1, coord_x2, _ = self._canvas_landscape.coords(self.item_tag)
distance = coord_x2 - coord_x1
pos_x = coord_x1 + (distance / 2) # to determine the coordinates of the center of the shape (host/client)
pos_y = coord_y1 - 10 # put the label a few pixels above the shape
self._item_label = self._canvas_landscape.create_text(pos_x,
pos_y,
text=item_name,
font=('', FONT_SIZE, 'normal'),
fill=LABEL_FONT_COLOUR)
[docs] @abstractmethod
def create(self):
"""Creates the canvas item."""
[docs] @abstractmethod
def show(self):
"""Shows the canvas item."""
[docs] @abstractmethod
def hide(self):
"""Hides the canvas item."""
[docs] @abstractmethod
def setup_ok(self):
"""Colours the canvas item in accordance with an OK state."""
[docs] @abstractmethod
def setup_nok(self):
"""Colours the canvas item in accordance with an NOK state."""
[docs] @abstractmethod
def dim(self):
"""Colours the canvas item representing a non-operational state."""
[docs]class Effect:
"""Applies effects to the canvas item.
This class provides methods to colour the canvas item in accordance with the
operational state and provide a method to make the canvas item flicker.
"""
def __init__(self, main_window, canvas_item, filling_type):
"""Instantiates the Effect object.
Args:
main_window (MainWindow): An instantiated MainWindow object.
canvas_item (str): The ID of the canvas item on the canvas.
filling_type (str): Either 'fill' or 'outline' depending what part of the canvas item should be coloured.
"""
self._canvas_landscape = main_window.main_frame.canvas_frame.canvas_landscape
self._canvas_status = main_window.main_frame.canvas_frame.canvas_status
self._flicker_index = 0
self._canvas_item = canvas_item
self._filling_type = filling_type
[docs] def flicker(self):
"""Changes the brightness of the canvas item irregularly appearing as a fluctuating light.
The after function is threaded, so it doesn't block.
"""
self._canvas_landscape.itemconfig(self._canvas_item, state='normal')
colours = ['#b2b2b2', '#b2b2b2', '#7f7f7f', '#b2b2b2', 'white']
colour_cycle = cycle(colours)
max_elements = len(colours)
def _flicker():
self._flicker_index += 1
selected_colour = next(colour_cycle)
if self._filling_type == 'outline':
self._canvas_landscape.itemconfig(self._canvas_item, outline=selected_colour)
self._canvas_status.itemconfig(self._canvas_item, outline=selected_colour)
elif self._filling_type == 'fill':
self._canvas_landscape.itemconfig(self._canvas_item, fill=selected_colour)
self._canvas_status.itemconfig(self._canvas_item, fill=selected_colour)
if self._flicker_index == max_elements:
return
self._canvas_landscape.after(120, _flicker)
_flicker()
[docs] def setup_ok(self):
"""Colours the canvas item to state OK (green)."""
arguments = {self._filling_type: OK_COLOUR}
self._canvas_landscape.itemconfig(self._canvas_item, **arguments)
self._canvas_status.itemconfig(self._canvas_item, **arguments)
[docs] def setup_nok(self):
"""Colours the canvas item to state NOK (red)."""
arguments = {self._filling_type: NOK_COLOUR}
self._canvas_landscape.itemconfig(self._canvas_item, **arguments)
self._canvas_status.itemconfig(self._canvas_item, **arguments)
[docs] def dim(self):
"""Colours the canvas item to a non-operational state (white).
To colour the outline of 'rectangles', the outline has to be configured.
To colour the items made of 'lines', the fill has to be configured.
"""
arguments = {self._filling_type: NON_OPERATION}
self._canvas_landscape.itemconfig(self._canvas_item, **arguments)
self._canvas_status.itemconfig(self._canvas_item, **arguments)
[docs]class ConnectionCalculator:
"""Calculates all properties that is needed to render a connection between two canvas items."""
def __init__(self, main_window, canvas_item_1, canvas_item_2):
"""Instantiates the ConnectionCalculator object.
Note: canvas.bbox doesn't return values when the item's state is 'hidden'.
Args:
main_window (MainWindow): An instantiated MainWindow object.
canvas_item_1 (CanvasItem): An instantiated CanvasItem object.
canvas_item_2 (CanvasItem): An instantiated CanvasItem object.
"""
self._canvas_landscape = main_window.main_frame.canvas_frame.canvas_landscape
self._component_a = self._canvas_landscape.bbox(canvas_item_1.item_tag)
self._component_b = self._canvas_landscape.bbox(canvas_item_2.item_tag)
self._factor = 0.05 # why is this?
[docs] def get_connection_length_inner(self):
"""Returns the distance between two items starting from right side first item to left side second item."""
_, _, ax2, _ = self._component_a
bx1, _, _, _ = self._component_b
distance = bx1 - ax2
return distance
[docs] def get_connection_length_outer(self):
"""Returns the distance between two items starting from right side first item to left side second item."""
ax1, _, _, _ = self._component_a
_, _, bx2, _ = self._component_b
distance = bx2 - ax1
return distance
[docs] def get_connection_height(self):
"""Returns the height of a connection based on the height of the item."""
_, by1, _, by2 = self._component_b
return (by2 - by1) * self._factor # use bbox to return the bounding box for client & host == more sophisticated
[docs] def get_x_pos_connection_right_side(self):
"""Returns the starting position on the X-axis of the connection item."""
_, _, ax2, _ = self._component_a
return ax2
[docs] def get_x_pos_connection_left_side(self):
"""Returns the starting position on the X-axis of the connection item."""
ax1, _, _, _ = self._component_a
return ax1
[docs] def get_y_pos_connection(self):
"""Returns the first position on the Y-axis of the connection item."""
_, by1, _, by2 = self._component_b
return by1 + ((by2 - by1) / 2)
[docs]class ClientCanvasItem(CanvasItem):
"""Creates a canvas item representing a client."""
def __init__(self, main_window, start_pos_x, start_pos_y):
"""Instantiates the ClientCanvasItem object.
Args:
main_window (MainWindow): An instantiated MainWindow object.
start_pos_x (int): The position on the X-axis of the canvas item's top left corner.
start_pos_y (int): The position on the Y-axis of the canvas item's top left corner.
"""
super().__init__(main_window)
self._client_effect = Effect(main_window, self.item_tag, 'outline')
self._start_pos_x = start_pos_x
self._start_pos_y = start_pos_y
self._width = 90
self._height = self._width * 0.7
self._components = []
[docs] def create(self):
self._draw_outer_screen()
self._draw_inner_screen()
self._draw_keyboard()
self._draw_spacebar()
[docs] def show(self):
self._client_effect.flicker()
self._add_label(self.item_name)
def _draw_outer_screen(self):
component = self._canvas_landscape.create_rectangle(self._start_pos_x,
self._start_pos_y,
self._start_pos_x + self._width,
self._start_pos_y + self._height,
width=THICKNESS_LINE_CLIENT,
outline=NON_OPERATION,
tags=self.item_tag
# state='hidden'
)
self._components.append(component)
def _draw_inner_screen(self):
coord_x1, coord_y1, coord_x2, coord_y2 = self._canvas_landscape.coords(self._components[0])
total_width = coord_x2 - coord_x1
total_height = coord_y2 - coord_y1
width = (coord_x2 - coord_x1) * 0.9
height = (coord_y2 - coord_y1) * 0.9
start_pos_x = coord_x1 + ((total_width - width) / 2)
start_pos_y = coord_y1 + ((total_height - height) / 2)
component = self._canvas_landscape.create_rectangle(start_pos_x,
start_pos_y,
start_pos_x + width,
start_pos_y + height,
width=1,
outline=NON_OPERATION,
tags=self.item_tag
# state='hidden'
)
self._components.append(component)
def _draw_keyboard(self):
coord_x1, coord_y1, coord_x2, coord_y2 = self._canvas_landscape.coords(self._components[0])
width = coord_x2 - coord_x1
total_height = coord_y2 - coord_y1
height = (coord_y2 - coord_y1) * 0.7
start_pos_x = coord_x1
start_pos_y = coord_y2 + (total_height * 0.05) # value should not be hardcoded, but calculated
component = self._canvas_landscape.create_rectangle(start_pos_x,
start_pos_y,
start_pos_x + width,
start_pos_y + height,
width=THICKNESS_LINE_CLIENT,
outline=NON_OPERATION,
tags=self.item_tag
# state='hidden'
)
self._components.append(component)
def _draw_spacebar(self):
coord_x1, coord_y1, coord_x2, coord_y2 = self._canvas_landscape.coords(self._components[2])
total_width = coord_x2 - coord_x1
total_height = coord_y2 - coord_y1
width = total_width * 0.5
height = total_height * 0.2
start_pos_x = coord_x1 + ((total_width - width) * 0.5)
start_pos_y = coord_y1 + ((total_height - height) * 0.8)
component = self._canvas_landscape.create_rectangle(start_pos_x,
start_pos_y,
start_pos_x + width,
start_pos_y + height,
fill='',
width=1,
outline=NON_OPERATION,
tags=self.item_tag
# state='hidden'
)
self._components.append(component)
[docs] def setup_ok(self):
self._client_effect.setup_ok()
[docs] def setup_nok(self):
self._client_effect.setup_nok()
[docs] def dim(self):
self._client_effect.dim()
[docs]class HostCanvasItem(CanvasItem):
"""Creates a canvas item representing a host."""
def __init__(self, main_window, start_pos_x, start_pos_y, host_ip):
"""Instantiates the HostCanvasItem object.
Args:
main_window (MainWindow): An instantiated MainWindow object.
start_pos_x (int): The position on the X-axis of the canvas item's top left corner.
start_pos_y (int): The position on the Y-axis of the canvas item's top left corner.
host_ip (str): The IP address of the Host.
"""
super().__init__(main_window)
self._host_effect = Effect(main_window, self.item_tag, 'outline')
self._start_pos_x = start_pos_x
self._start_pos_y = start_pos_y
self._width = 90
self._height = self._width * 1.4
self._host_ip = host_ip
[docs] def create(self):
host_x1 = self._start_pos_x
host_y1 = self._start_pos_y
host_x2 = self._start_pos_x + self._width
host_y2 = self._start_pos_y + self._height
self._canvas_landscape.create_rectangle(host_x1,
host_y1,
host_x2,
host_y2,
width=THICKNESS_LINE_HOST,
outline=NON_OPERATION,
tags=self.item_tag,
# state='hidden'
)
[docs] def show(self):
self._host_effect.flicker()
self._add_label(self._host_ip)
[docs] def setup_ok(self):
self._host_effect.setup_ok()
[docs] def setup_nok(self):
self._host_effect.setup_nok()
[docs] def dim(self):
self._host_effect.dim()
[docs]class AgentCanvasItem(CanvasItem):
"""Creates a canvas item representing an Agent."""
def __init__(self, main_window, client_canvas_item, host_canvas_items):
"""Instantiates the AgentCanvasItem object.
Args:
main_window (MainWindow): An instantiated MainWindow object.
client_canvas_item (CanvasItem): An instantiated CanvasItem that represents a Client.
host_canvas_items (list): All instantiated CanvasItems that represents a Host.
"""
super().__init__(main_window)
self._agent_effect = Effect(main_window, self.item_tag, 'outline')
self._coords_client = self._canvas_landscape.coords(client_canvas_item.item_tag)
self._coords_destination_host = self._canvas_landscape.coords(host_canvas_items[-1].item_tag)
self._coords_agent_start_pos = None # position of Agent next to Client
self._coords_agent_end_pos = None # position of Agent inside Host
self._number_of_hosts = len(host_canvas_items)
self._width = 0
self._distance_index = 0
self._distance_between_hosts = 0
[docs] def create(self):
self._coords_agent_end_pos = self._create_agent_derived_from_host()
self._width = self._determine_width()
self._coords_agent_start_pos = self._place_agent_in_client()
self._distance_between_hosts = self._calculate_distances()
[docs] def show(self):
self._canvas_landscape.itemconfig(self.item_tag, dash=(9, 9), width=1, state='normal')
def _create_agent_derived_from_host(self):
hx1, hy1, hx2, hy2 = self._coords_destination_host
nx1 = hx1 + 25
ny1 = hy1 + 45
nx2 = hx2 - 25
ny2 = hy2 - 25
self._canvas_landscape.create_rectangle(nx1,
ny1,
nx2,
ny2,
fill=BACKGROUND_CANVAS,
width=THICKNESS_LINE_AGENT,
outline=NON_OPERATION,
tags=self.item_tag,
# state='hidden'
)
return nx1, ny1, nx2, ny2
def _determine_width(self):
ax1, _, ax2, _ = self._canvas_landscape.coords(self.item_tag)
return ax2 - ax1
def _place_agent_in_client(self):
_, ay1, _, ay2 = self._coords_agent_end_pos
cx1, _, cx2, _ = self._coords_client
center = cx1 + ((cx2 - cx1) / 2)
nx1 = center - (self._width / 2)
nx2 = center + (self._width / 2)
self._canvas_landscape.coords(self.item_tag,
nx1,
ay1,
nx2,
ay2)
return nx1, ay1, nx2, ay2
def _calculate_distances(self):
start_x2 = self._coords_agent_start_pos[0] # retrieve top left position on x-axis
end_x1 = self._coords_agent_end_pos[2] # retrieve right bottom position on x-axis
return (end_x1 - start_x2 - self._width) / self._number_of_hosts
[docs] def move(self):
"""Moves the Agent item from Client item to destination Host item."""
def _animate():
stepper = self._distance_index / 10
while self._distance_index > 0:
self._canvas_landscape.move(self.item_tag, stepper, 0)
self._distance_index -= stepper
sleep(.02)
self._distance_index = self._distance_between_hosts
_animate()
[docs] def transfer_ok(self):
"""Colours the outline white and changes the outline into a solid pattern."""
self._canvas_landscape.itemconfig(self.item_tag,
dash=(1, 1), # default to normal, it was dash=(5, 5)
outline=NON_OPERATION,
width=THICKNESS_LINE_AGENT)
self._add_label(self.item_name)
[docs] def transfer_nok(self):
"""Colours the outline red and changes the outline to have a dashed pattern."""
self._canvas_landscape.itemconfig(self.item_tag, dash=(5, 5), outline=NOK_COLOUR, width=THICKNESS_LINE_AGENT)
[docs] def setup_ok(self):
self._agent_effect.setup_ok()
[docs] def setup_nok(self):
self._agent_effect.setup_nok()
[docs] def dim(self):
self._agent_effect.dim()
[docs]class ConnectionCanvasItem(CanvasItem):
"""Creates a canvas item representing a connection."""
def __init__(self, main_window, canvas_item_1, canvas_item_2):
"""Instantiates the ConnectionCanvasItem object.
Args:
main_window (MainWindow): An instantiated MainWindow object.
canvas_item_1 (CanvasItem): An instantiated CanvasItem object, representing either an Agent or a Host.
canvas_item_2 (CanvasItem): An instantiated CanvasItem object, representing a Host.
"""
super().__init__(main_window)
self._connection_calculator = ConnectionCalculator(main_window, canvas_item_1, canvas_item_2) # composition
self._connection_effect = Effect(main_window, self.item_tag, 'fill')
self._start_pos_x = self._connection_calculator.get_x_pos_connection_right_side()
self._pos_y_1 = self._connection_calculator.get_y_pos_connection() - 8
self._pos_y_2 = self._connection_calculator.get_y_pos_connection() + 8
self._distance = self._connection_calculator.get_connection_length_inner()
self._terminate = False
self._distance_index = 0
self._components = []
[docs] def create(self):
top_line = self._canvas_landscape.create_line(self._start_pos_x,
self._pos_y_1,
self._start_pos_x + self._distance,
self._pos_y_1,
fill=NON_OPERATION,
width=THICKNESS_LINE_TUNNEL,
tags=self.item_tag,
# state='hidden'
)
self._components.append(top_line)
bottom_line = self._canvas_landscape.create_line(self._start_pos_x,
self._pos_y_2,
self._start_pos_x + self._distance,
self._pos_y_2,
fill=NON_OPERATION,
width=THICKNESS_LINE_TUNNEL,
tags=self.item_tag,
# state='hidden'
)
self._components.append(bottom_line)
[docs] def show(self):
self._canvas_landscape.itemconfig(self.item_tag, state='normal')
def animate(): # blocking
self._distance_index = self._distance
pos_x_stepper = self._start_pos_x
stepper = self._distance / 8
while self._distance_index >= 0:
self._canvas_landscape.coords(self._components[0],
self._start_pos_x,
self._pos_y_1,
pos_x_stepper,
self._pos_y_1)
self._canvas_landscape.coords(self._components[1],
self._start_pos_x,
self._pos_y_2,
pos_x_stepper,
self._pos_y_2)
self._distance_index -= stepper
pos_x_stepper += stepper
sleep(.01)
self._add_label(self.item_name)
animate()
[docs] def hide(self):
self._canvas_landscape.itemconfig(self.item_tag, state='hidden')
self._canvas_landscape.itemconfig(self._item_label, state='hidden')
[docs] def setup_ok(self):
self._connection_effect.setup_ok()
[docs] def setup_nok(self):
self._connection_effect.setup_nok()
[docs]class StatusBannerCanvasItem(CanvasItem):
"""Creates a status banner."""
def __init__(self, main_window):
"""Instantiates the StatusBannerCanvasItem object.
Args:
main_window (MainWindow): An instantiated MainWindow object.
"""
super().__init__(main_window)
self._tag_text_item = f"{self.item_tag}-1"
self._tag_box_item = f"{self.item_tag}-2"
self._text_effect = Effect(main_window, self._tag_text_item, 'fill')
self._box_effect = Effect(main_window, self._tag_box_item, 'outline')
[docs] def create(self):
self._create_text()
self._create_box()
def _create_text(self):
width = self._canvas_status.winfo_width()
pos_x = width / 2
status_height = self._canvas_status.winfo_height()
pos_y = status_height / 2
text = 'NO TUNNEL'.center(30)
self._canvas_status.create_text(pos_x,
pos_y,
text=text,
font=('', 20, 'normal'),
# anchor=N,
fill=NON_OPERATION,
tags=self._tag_text_item)
def _create_box(self):
ax1, ay1, ax2, ay2 = self._canvas_status.bbox(self._tag_text_item)
ax1 -= 20 # horizontal padding
ax2 += 20 # horizontal padding
ay1 -= 10 # horizontal padding
ay2 += 10 # horizontal padding
self._canvas_status.create_rectangle(ax1,
ay1,
ax2,
ay2,
outline=NON_OPERATION,
width=THICKNESS_PACKET,
tags=self._tag_box_item)
def _show_text(self, state=None):
if state is None:
self._canvas_status.itemconfig(self._tag_text_item, state='normal')
self._text_effect.flicker()
elif state == 'opened':
text = 'TUNNEL OPENED'.center(30)
self._canvas_status.itemconfig(self._tag_text_item, text=text, fill=OK_COLOUR)
elif state == 'broken':
text = 'TUNNEL BROKEN'.center(30)
self._canvas_status.itemconfig(self._tag_text_item, text=text, fill=NOK_COLOUR)
elif state == 'restored':
text = 'TUNNEL RESTORED'.center(30)
self._canvas_status.itemconfig(self._tag_text_item, text=text, fill=OK_COLOUR)
def _show_box(self, state=None):
if state is None:
self._canvas_status.itemconfig(self._tag_box_item, state='normal')
self._box_effect.flicker()
if state == 'opened':
self._canvas_status.itemconfig(self._tag_box_item, outline=OK_COLOUR)
elif state == 'broken':
self._canvas_status.itemconfig(self._tag_box_item, outline=NOK_COLOUR)
elif state == 'restored':
self._canvas_status.itemconfig(self._tag_box_item, outline=OK_COLOUR)
[docs] def show(self, state=None): # fix pylint eror: arguments-differ / Parameters differ from overridden 'show' method
self._show_text(state)
self._show_box(state)
[docs] def hide(self):
self._canvas_status.itemconfig(self._tag_text_item, state='hidden')
self._canvas_status.itemconfig(self._tag_box_item, state='hidden')
[docs] def setup_ok(self):
self._text_effect.setup_ok()
self._box_effect.setup_ok()
[docs] def setup_nok(self):
pass
[docs] def dim(self):
text = 'TUNNEL CLOSED'.center(26)
self._canvas_status.itemconfig(self._tag_text_item, text=text)
self._text_effect.dim()
self._box_effect.dim()
[docs]class PacketCanvasItem(CanvasItem):
"""Creates a visualised TCP packet."""
def __init__(self, main_window, connection_canvas_items):
"""Instantiates the PacketCanvasItem object.
Args:
main_window (MainWindow): An instantiated MainWindow object.
connection_canvas_items (list): Two instantiated CanvasItems, each representing a Connection.
"""
super().__init__(main_window)
self.connection_calculator = ConnectionCalculator(main_window,
connection_canvas_items[0],
connection_canvas_items[-1])
self.total_width = WIDTH_PACKET + (2 * THICKNESS_LINE_PACKET)
self.start_pos_x = self.connection_calculator.get_x_pos_connection_left_side()
self.pos_y = self.connection_calculator.get_y_pos_connection()
self.distance = self.connection_calculator.get_connection_length_outer()
[docs] def create(self):
self._canvas_landscape.create_rectangle(self.start_pos_x,
self.pos_y - 4,
self.start_pos_x + WIDTH_PACKET,
self.pos_y + 4,
fill=PACKET_FILL_COLOUR,
outline=PACKET_OUTLINE_COLOUR,
width=THICKNESS_LINE_PACKET,
# state='hidden',
tags=self.item_tag)
[docs] def show(self):
self._canvas_landscape.itemconfig(self.item_tag, state='normal')
[docs] def hide(self):
self._canvas_landscape.itemconfig(self.item_tag, state='hidden')
[docs] def setup_ok(self):
pass
[docs] def setup_nok(self):
pass