From 899915396066db6775ef2b5257f01da60df20572 Mon Sep 17 00:00:00 2001 From: Thomas McCullough Date: Wed, 10 Nov 2021 22:12:36 -0500 Subject: [PATCH 1/6] Creating a messagebox with copyable text, and using that for coordinate and measure tool feedback --- tk_builder/widgets/derived_widgets.py | 33 ++++++++++++++++++++++++- tk_builder/widgets/image_canvas_tool.py | 7 +++--- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/tk_builder/widgets/derived_widgets.py b/tk_builder/widgets/derived_widgets.py index 1fcbea1..b98b2bb 100644 --- a/tk_builder/widgets/derived_widgets.py +++ b/tk_builder/widgets/derived_widgets.py @@ -6,7 +6,9 @@ __author__ = "Thomas McCullough" import tkinter -from tk_builder.widgets.basic_widgets import Frame, Scrollbar, Treeview, Text +from tkinter.simpledialog import Dialog + +from tk_builder.widgets.basic_widgets import Frame, Scrollbar, Treeview, Text, Button from tk_builder.widgets.widget_descriptors import TypedDescriptor @@ -115,3 +117,32 @@ def get_value(self): def __str__(self): return str(self.frame) + + +class CopyableMessageBox(Dialog): + """ + A messagebox with copyable text + """ + + def __init__(self, title, message=None, parent=None): + self.message = message + if parent is None: + # noinspection PyProtectedMember + parent = tkinter._default_root + Dialog.__init__(self, parent, title=title) + + def body(self, parent): + self.text = Text(self, width=40, height=4) + self.text.pack(fill="both", expand=True) + self.text.insert("1.0", self.message) + self.text.configure(state='disabled') + return self.text + + def buttonbox(self): + box = Frame(self) + + w = Button(box, text="OK", width=10, command=self.cancel, default=tkinter.ACTIVE) + w.pack(side=tkinter.LEFT, padx=5, pady=5) + self.bind("", self.cancel) + self.bind("", self.cancel) + box.pack() diff --git a/tk_builder/widgets/image_canvas_tool.py b/tk_builder/widgets/image_canvas_tool.py index 5abd0de..a31d124 100644 --- a/tk_builder/widgets/image_canvas_tool.py +++ b/tk_builder/widgets/image_canvas_tool.py @@ -10,7 +10,8 @@ from collections import OrderedDict import numpy from typing import Tuple, List -from tkinter.messagebox import showinfo + +from tk_builder.widgets.derived_widgets import CopyableMessageBox from sarpy.geometry.geometry_elements import LinearRing from sarpy.geometry.geocoords import geodetic_to_ecf, ecf_to_ned @@ -1321,7 +1322,7 @@ def on_left_mouse_click(self, event): def show_coordinate_details(self): self.coordinate_string_formatting_function() if self.coordinate_string is not None: - showinfo('Coordinate Details', message=self.coordinate_string) + CopyableMessageBox('Coordinate Details', message=self.coordinate_string) def coordinate_string_formatting_function(self): self.coordinate_string = 'Row/Column: ({0:0.1f}, {1:0.1f})'.format(*self.image_coords) @@ -1474,7 +1475,7 @@ def on_mouse_wheel(self, event): def show_measurement_details(self, event): self.image_coords = self.vector_object.image_coords self.coordinate_string_formatting_function() - showinfo('Measurement Details', message=self.coordinate_string) + CopyableMessageBox('Measurement Details', message=self.coordinate_string) def coordinate_string_formatting_function(self): crd = self.image_coords From 011d45dbb24aa2a7a48a6b3a01948cf24d35a649 Mon Sep 17 00:00:00 2001 From: Thomas McCullough Date: Wed, 10 Nov 2021 22:28:15 -0500 Subject: [PATCH 2/6] Refining copyable message box --- tk_builder/widgets/derived_widgets.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tk_builder/widgets/derived_widgets.py b/tk_builder/widgets/derived_widgets.py index b98b2bb..630b39a 100644 --- a/tk_builder/widgets/derived_widgets.py +++ b/tk_builder/widgets/derived_widgets.py @@ -124,15 +124,18 @@ class CopyableMessageBox(Dialog): A messagebox with copyable text """ - def __init__(self, title, message=None, parent=None): + def __init__(self, title, message=None, width=60, height=10, parent=None): self.message = message + self.width = width + self.height = height + self.text = None if parent is None: # noinspection PyProtectedMember parent = tkinter._default_root Dialog.__init__(self, parent, title=title) def body(self, parent): - self.text = Text(self, width=40, height=4) + self.text = Text(self, width=self.width, height=self.height) self.text.pack(fill="both", expand=True) self.text.insert("1.0", self.message) self.text.configure(state='disabled') From 300a3b2d5c9f1f3a1d980b9e8c5e1c026e7554f8 Mon Sep 17 00:00:00 2001 From: Thomas McCullough Date: Wed, 10 Nov 2021 22:35:08 -0500 Subject: [PATCH 3/6] Refining copyable message box --- tk_builder/widgets/image_canvas_tool.py | 29 +++++++------------------ 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/tk_builder/widgets/image_canvas_tool.py b/tk_builder/widgets/image_canvas_tool.py index a31d124..5ecc57e 100644 --- a/tk_builder/widgets/image_canvas_tool.py +++ b/tk_builder/widgets/image_canvas_tool.py @@ -1322,7 +1322,7 @@ def on_left_mouse_click(self, event): def show_coordinate_details(self): self.coordinate_string_formatting_function() if self.coordinate_string is not None: - CopyableMessageBox('Coordinate Details', message=self.coordinate_string) + CopyableMessageBox('Coordinate Details', message=self.coordinate_string, width=60, height=8) def coordinate_string_formatting_function(self): self.coordinate_string = 'Row/Column: ({0:0.1f}, {1:0.1f})'.format(*self.image_coords) @@ -1396,24 +1396,11 @@ def on_left_mouse_click(self, event): return canvas_event = _get_canvas_event_coords(self.image_canvas, event) - if self.mode == "init": - new_coords = (canvas_event[0], canvas_event[1], canvas_event[0], canvas_event[1]) - self.image_canvas.modify_existing_shape_using_canvas_coords( - self.shape_id, new_coords, update_pixel_coords=True) - self.mode = "normal" - self.insert_at_index = 1 - else: - if self.insert_at_index > 1: - self.insert_at_index = 1 - if self.insert_at_index < 0: - self.insert_at_index = 0 - old_coords = self.image_canvas.get_shape_canvas_coords(self.shape_id) - new_coords, _ = _modify_coords( - self.image_canvas, self.shape_id, old_coords, - canvas_event[0], canvas_event[1], - self.insert_at_index, insert=False) - self.image_canvas.modify_existing_shape_using_canvas_coords( - self.shape_id, new_coords, update_pixel_coords=True) + new_coords = (canvas_event[0], canvas_event[1], canvas_event[0], canvas_event[1]) + self.image_canvas.modify_existing_shape_using_canvas_coords( + self.shape_id, new_coords, update_pixel_coords=True) + self.mode = "normal" + self.insert_at_index = 1 def on_left_mouse_motion(self, event): self.mouse_moved = True @@ -1475,7 +1462,7 @@ def on_mouse_wheel(self, event): def show_measurement_details(self, event): self.image_coords = self.vector_object.image_coords self.coordinate_string_formatting_function() - CopyableMessageBox('Measurement Details', message=self.coordinate_string) + CopyableMessageBox('Measurement Details', message=self.coordinate_string, width=90, height=10) def coordinate_string_formatting_function(self): crd = self.image_coords @@ -1490,7 +1477,7 @@ def coordinate_string_formatting_function(self): self.coordinate_string += '\n-----------------\n{}: '.format(trans_string) if trans_string.startswith('LLH'): - self.coordinate_string += '({0:0.8f}, {1:0.8f}, {2:0.2f}) ->\n '.format(*transformed_coords[0, :]) + self.coordinate_string += '({0:0.8f}, {1:0.8f}, {2:0.2f}) -> '.format(*transformed_coords[0, :]) self.coordinate_string += '({0:0.8f}, {1:0.8f}, {2:0.2f})\n'.format(*transformed_coords[1, :]) ecf_coords = geodetic_to_ecf(transformed_coords) bearing_vector_ned = ecf_to_ned(ecf_coords[1, :] - ecf_coords[0, :], ecf_coords[0, :], absolute_coords=False) From 8f3a188566bbae9585ac0060f9231cc8ee334640 Mon Sep 17 00:00:00 2001 From: Thomas McCullough Date: Fri, 12 Nov 2021 12:00:31 -0500 Subject: [PATCH 4/6] Enabling valid data view --- tk_builder/widgets/image_canvas.py | 34 ++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/tk_builder/widgets/image_canvas.py b/tk_builder/widgets/image_canvas.py index 07ffa71..7458422 100644 --- a/tk_builder/widgets/image_canvas.py +++ b/tk_builder/widgets/image_canvas.py @@ -606,9 +606,13 @@ def _validate_kwargs(self): self.highlight_args['width'] = self.regular_args['width'] + 2 # perform color validation - if self._type in [ShapeTypeConstants.LINE, ShapeTypeConstants.ARROW, ShapeTypeConstants.POINT, ShapeTypeConstants.TEXT]: + if self._type in [ + ShapeTypeConstants.LINE, ShapeTypeConstants.ARROW, + ShapeTypeConstants.POINT, ShapeTypeConstants.TEXT]: attr = 'fill' - elif self._type in [ShapeTypeConstants.RECT, ShapeTypeConstants.POLYGON, ShapeTypeConstants.ELLIPSE]: + elif self._type in [ + ShapeTypeConstants.RECT, ShapeTypeConstants.POLYGON, + ShapeTypeConstants.ELLIPSE]: attr = 'outline' else: attr = None @@ -719,7 +723,6 @@ def highlight_args(self): return self._highlight_args - def replicate(self): """ Replicate the vector object, leaving the name and id unassigned. @@ -939,7 +942,7 @@ def remove_shape_from_tracking(self, the_id): """ if the_id not in self._vector_objects: - return None # nothing to be done + return None # nothing to be done vector_object = self._vector_objects[the_id] if vector_object.is_tool: @@ -2839,6 +2842,29 @@ def create_new_polygon(self, coords, make_current=True, increment_color=True, is return self.create_shape_from_vector_object(vector_obj, coords, make_current=make_current) + def show_valid_data(self, valid_data_coordinates): + """ + Create or edit the valid data polygon. + + Parameters + ---------- + valid_data_coordinates : numpy.ndarray + Of the form [[row, col]]. + """ + + try: + valid_data_id = self.variables.get_tool_shape_id_by_name('VALID_DATA') + except KeyError: + valid_data_id = None + image_coords = valid_data_coordinates.flatten() + if valid_data_id is None: + vector_object = VectorObject( + ShapeTypeConstants.POLYGON, name='VALID_DATA', is_tool=True, color='darkred', + regular_args={'dash': (), 'fill': ''}, highlight_args={'dash': (), 'fill': ''}) + valid_data_id = self.create_shape_from_vector_object(vector_object, (0, 0, 0, 0), make_current=False) + self.modify_existing_shape_using_image_coords(valid_data_id, image_coords) + self.show_shape(valid_data_id) + # shape as geometry methods def get_geometry_for_shape(self, shape_id, coordinate_type='image'): """ From 4105f824bb53402362a27fb3017930706b726f0f Mon Sep 17 00:00:00 2001 From: Thomas McCullough Date: Fri, 12 Nov 2021 14:45:54 -0500 Subject: [PATCH 5/6] valid data display debugging --- tk_builder/widgets/image_canvas.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tk_builder/widgets/image_canvas.py b/tk_builder/widgets/image_canvas.py index 7458422..02b3154 100644 --- a/tk_builder/widgets/image_canvas.py +++ b/tk_builder/widgets/image_canvas.py @@ -2856,6 +2856,7 @@ def show_valid_data(self, valid_data_coordinates): valid_data_id = self.variables.get_tool_shape_id_by_name('VALID_DATA') except KeyError: valid_data_id = None + image_coords = valid_data_coordinates.flatten() if valid_data_id is None: vector_object = VectorObject( From 6fdf164f31848140ed7d367a754947c6e63852a5 Mon Sep 17 00:00:00 2001 From: Thomas McCullough Date: Mon, 15 Nov 2021 09:42:17 -0500 Subject: [PATCH 6/6] Version bump --- changelog/version_1_1 | 1 + tk_builder/__about__.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/changelog/version_1_1 b/changelog/version_1_1 index 8c6d4c5..44034e8 100644 --- a/changelog/version_1_1 +++ b/changelog/version_1_1 @@ -1,6 +1,7 @@ # This details the important differences introduced in tk_builder 1.1 # NB: bump the version number in __about__.py to reflect the below. +* .8 - Adding a messagebox which allows copying of text * .7 - Adding image canvas tools for coordinate inspection and measurement * .6 - Allowing initialization parameters for image canvas tools Enable shift tool to simultaneously handle multiple geometries on the image canvas diff --git a/tk_builder/__about__.py b/tk_builder/__about__.py index 0b1be32..58636bd 100644 --- a/tk_builder/__about__.py +++ b/tk_builder/__about__.py @@ -27,7 +27,7 @@ '__license__', '__copyright__'] -__version__ = "1.1.7" +__version__ = "1.1.8" __classification__ = "UNCLASSIFIED" # This should be set appropriately in any high-side version