PyImageLabeling 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- PyImageLabeling/__init__.py +22 -0
- PyImageLabeling/config.json +289 -0
- PyImageLabeling/controller/Controller.py +25 -0
- PyImageLabeling/controller/Events.py +147 -0
- PyImageLabeling/controller/FileEvents.py +69 -0
- PyImageLabeling/controller/ImageEvents.py +32 -0
- PyImageLabeling/controller/LabelEvents.py +219 -0
- PyImageLabeling/controller/LabelingEvents.py +123 -0
- PyImageLabeling/controller/settings/ContourFillinSetting.py +93 -0
- PyImageLabeling/controller/settings/CoutourFillingApplyCancel.py +37 -0
- PyImageLabeling/controller/settings/EraserSetting.py +73 -0
- PyImageLabeling/controller/settings/LabelSetting.py +91 -0
- PyImageLabeling/controller/settings/MagicPenSetting.py +125 -0
- PyImageLabeling/controller/settings/OpacitySetting.py +66 -0
- PyImageLabeling/controller/settings/PaintBrushSetting.py +66 -0
- PyImageLabeling/icons/apply.png +0 -0
- PyImageLabeling/icons/asterisk-green.png +0 -0
- PyImageLabeling/icons/asterisk-red.png +0 -0
- PyImageLabeling/icons/back.png +0 -0
- PyImageLabeling/icons/border.png +0 -0
- PyImageLabeling/icons/cancel.png +0 -0
- PyImageLabeling/icons/cleaner.png +0 -0
- PyImageLabeling/icons/close.png +0 -0
- PyImageLabeling/icons/down.png +0 -0
- PyImageLabeling/icons/ellipse.png +0 -0
- PyImageLabeling/icons/eraser.png +0 -0
- PyImageLabeling/icons/filling.png +0 -0
- PyImageLabeling/icons/logoMAIA.png +0 -0
- PyImageLabeling/icons/magic.png +0 -0
- PyImageLabeling/icons/maia.png +0 -0
- PyImageLabeling/icons/maia1.png +0 -0
- PyImageLabeling/icons/maia3.ico +0 -0
- PyImageLabeling/icons/maia_icon.png +0 -0
- PyImageLabeling/icons/move.png +0 -0
- PyImageLabeling/icons/opacity.png +0 -0
- PyImageLabeling/icons/open_image.png +0 -0
- PyImageLabeling/icons/open_layer.png +0 -0
- PyImageLabeling/icons/paint.png +0 -0
- PyImageLabeling/icons/plus.png +0 -0
- PyImageLabeling/icons/polygon.png +0 -0
- PyImageLabeling/icons/rectangle.png +0 -0
- PyImageLabeling/icons/reset.png +0 -0
- PyImageLabeling/icons/save.png +0 -0
- PyImageLabeling/icons/setting.png +0 -0
- PyImageLabeling/icons/transparency.png:Zone.Identifier +4 -0
- PyImageLabeling/icons/up.png +0 -0
- PyImageLabeling/icons/visibility.png +0 -0
- PyImageLabeling/icons/zoom_minus.png +0 -0
- PyImageLabeling/icons/zoom_plus.png +0 -0
- PyImageLabeling/model/Core.py +795 -0
- PyImageLabeling/model/File/Files.py +166 -0
- PyImageLabeling/model/File/NextImage.py +36 -0
- PyImageLabeling/model/File/PreviousImage.py +19 -0
- PyImageLabeling/model/Image/MoveImage.py +32 -0
- PyImageLabeling/model/Image/ResetMoveZoomImage.py +16 -0
- PyImageLabeling/model/Image/ZoomMinus.py +25 -0
- PyImageLabeling/model/Image/ZoomPlus.py +16 -0
- PyImageLabeling/model/Labeling/ClearAll.py +22 -0
- PyImageLabeling/model/Labeling/ContourFilling.py +135 -0
- PyImageLabeling/model/Labeling/Ellipse.py +350 -0
- PyImageLabeling/model/Labeling/Eraser.py +131 -0
- PyImageLabeling/model/Labeling/MagicPen.py +131 -0
- PyImageLabeling/model/Labeling/PaintBrush.py +207 -0
- PyImageLabeling/model/Labeling/Polygon.py +279 -0
- PyImageLabeling/model/Labeling/Rectangle.py +248 -0
- PyImageLabeling/model/Labeling/Undo.py +12 -0
- PyImageLabeling/model/Model.py +40 -0
- PyImageLabeling/model/Utils.py +40 -0
- PyImageLabeling/old_version/label_rectangle_properties.json +6 -0
- PyImageLabeling/old_version/main.py +2073 -0
- PyImageLabeling/old_version/models/EraseSettingsDialog.py +51 -0
- PyImageLabeling/old_version/models/LabeledRectangle.py +80 -0
- PyImageLabeling/old_version/models/MagicSettingsDialog.py +119 -0
- PyImageLabeling/old_version/models/OverlayOpacityDialog.py +63 -0
- PyImageLabeling/old_version/models/PaintSettingsDialog.py +289 -0
- PyImageLabeling/old_version/models/PointItem.py +66 -0
- PyImageLabeling/old_version/models/ProcessWorker.py +52 -0
- PyImageLabeling/old_version/models/ZoomableGraphicsView.py +1214 -0
- PyImageLabeling/old_version/models/tools/ContourTool.py +279 -0
- PyImageLabeling/old_version/models/tools/EraserTool.py +290 -0
- PyImageLabeling/old_version/models/tools/MagicPenTool.py +199 -0
- PyImageLabeling/old_version/models/tools/OverlayTool.py +179 -0
- PyImageLabeling/old_version/models/tools/PaintTool.py +68 -0
- PyImageLabeling/old_version/models/tools/PolygonTool.py +786 -0
- PyImageLabeling/old_version/models/tools/RectangleTool.py +1036 -0
- PyImageLabeling/parameters.json +1 -0
- PyImageLabeling/style.css +611 -0
- PyImageLabeling/view/Builder.py +333 -0
- PyImageLabeling/view/QBackgroundItem.py +30 -0
- PyImageLabeling/view/QWidgets.py +10 -0
- PyImageLabeling/view/View.py +226 -0
- PyImageLabeling/view/ZoomableGraphicsView.py +91 -0
- PyImageLabeling/view/__init__.py +0 -0
- pyimagelabeling-1.0.0.dist-info/METADATA +55 -0
- pyimagelabeling-1.0.0.dist-info/RECORD +99 -0
- pyimagelabeling-1.0.0.dist-info/WHEEL +5 -0
- pyimagelabeling-1.0.0.dist-info/licenses/LICENCE +22 -0
- pyimagelabeling-1.0.0.dist-info/top_level.txt +2 -0
- pypi/publish_pypi.py +18 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
from PyImageLabeling.model.Core import Core
|
|
2
|
+
from PyQt6.QtWidgets import QGraphicsRectItem
|
|
3
|
+
from PyQt6.QtGui import QPen, QCursor, QBrush
|
|
4
|
+
from PyQt6.QtCore import Qt, QPointF, QRectF, QSizeF
|
|
5
|
+
import math
|
|
6
|
+
|
|
7
|
+
HANDLE_SIZE = 8
|
|
8
|
+
HANDLE_DETECTION_DISTANCE = 15
|
|
9
|
+
MIN_RECT_SIZE = 10
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class RectangleItem(QGraphicsRectItem):
|
|
13
|
+
HANDLE_TYPES = {
|
|
14
|
+
'top_left': Qt.CursorShape.SizeFDiagCursor,
|
|
15
|
+
'top_right': Qt.CursorShape.SizeBDiagCursor,
|
|
16
|
+
'bottom_left': Qt.CursorShape.SizeBDiagCursor,
|
|
17
|
+
'bottom_right': Qt.CursorShape.SizeFDiagCursor,
|
|
18
|
+
'rotation': Qt.CursorShape.OpenHandCursor,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
def __init__(self, x, y, width, height, color=Qt.GlobalColor.red):
|
|
22
|
+
super().__init__(x, y, width, height)
|
|
23
|
+
|
|
24
|
+
pen = QPen(color, 2, Qt.PenStyle.SolidLine)
|
|
25
|
+
self.setPen(pen)
|
|
26
|
+
|
|
27
|
+
self.setFlags(
|
|
28
|
+
QGraphicsRectItem.GraphicsItemFlag.ItemIsSelectable
|
|
29
|
+
| QGraphicsRectItem.GraphicsItemFlag.ItemIsMovable
|
|
30
|
+
| QGraphicsRectItem.GraphicsItemFlag.ItemSendsGeometryChanges
|
|
31
|
+
)
|
|
32
|
+
self.setAcceptHoverEvents(True)
|
|
33
|
+
|
|
34
|
+
self.handles = {}
|
|
35
|
+
self.handle_selected = None
|
|
36
|
+
self.handles_visible = False
|
|
37
|
+
self.initial_rotation = 0
|
|
38
|
+
self.initial_angle = 0
|
|
39
|
+
|
|
40
|
+
self.update_handles()
|
|
41
|
+
|
|
42
|
+
def update_handles(self):
|
|
43
|
+
rect = self.rect()
|
|
44
|
+
self.handles = {
|
|
45
|
+
'top_left': QRectF(rect.topLeft() - QPointF(HANDLE_SIZE / 2, HANDLE_SIZE / 2), QSizeF(HANDLE_SIZE, HANDLE_SIZE)),
|
|
46
|
+
'top_right': QRectF(rect.topRight() - QPointF(HANDLE_SIZE / 2, HANDLE_SIZE / 2), QSizeF(HANDLE_SIZE, HANDLE_SIZE)),
|
|
47
|
+
'bottom_left': QRectF(rect.bottomLeft() - QPointF(HANDLE_SIZE / 2, HANDLE_SIZE / 2), QSizeF(HANDLE_SIZE, HANDLE_SIZE)),
|
|
48
|
+
'bottom_right': QRectF(rect.bottomRight() - QPointF(HANDLE_SIZE / 2, HANDLE_SIZE / 2), QSizeF(HANDLE_SIZE, HANDLE_SIZE)),
|
|
49
|
+
'rotation': QRectF(rect.center() - QPointF(HANDLE_SIZE / 2, HANDLE_SIZE / 2), QSizeF(HANDLE_SIZE, HANDLE_SIZE)),
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
def check_handle_proximity(self, pos):
|
|
53
|
+
near_handle = any(
|
|
54
|
+
self.distance_to_rect(pos, rect) < HANDLE_DETECTION_DISTANCE
|
|
55
|
+
for rect in self.handles.values()
|
|
56
|
+
)
|
|
57
|
+
if self.isSelected():
|
|
58
|
+
near_handle = True
|
|
59
|
+
|
|
60
|
+
if near_handle != self.handles_visible:
|
|
61
|
+
self.handles_visible = near_handle
|
|
62
|
+
self.update()
|
|
63
|
+
|
|
64
|
+
@staticmethod
|
|
65
|
+
def distance_to_rect(point, rect):
|
|
66
|
+
center = rect.center()
|
|
67
|
+
return math.hypot(point.x() - center.x(), point.y() - center.y())
|
|
68
|
+
|
|
69
|
+
def update_cursor(self, pos):
|
|
70
|
+
if not self.handles_visible:
|
|
71
|
+
return
|
|
72
|
+
for name, rect in self.handles.items():
|
|
73
|
+
if rect.contains(pos):
|
|
74
|
+
self.setCursor(self.HANDLE_TYPES.get(name, Qt.CursorShape.ArrowCursor))
|
|
75
|
+
return
|
|
76
|
+
self.setCursor(Qt.CursorShape.SizeAllCursor)
|
|
77
|
+
|
|
78
|
+
def hoverEnterEvent(self, event):
|
|
79
|
+
self.check_handle_proximity(event.pos())
|
|
80
|
+
super().hoverEnterEvent(event)
|
|
81
|
+
|
|
82
|
+
def hoverMoveEvent(self, event):
|
|
83
|
+
self.check_handle_proximity(event.pos())
|
|
84
|
+
self.update_cursor(event.pos())
|
|
85
|
+
super().hoverMoveEvent(event)
|
|
86
|
+
|
|
87
|
+
def hoverLeaveEvent(self, event):
|
|
88
|
+
self.handles_visible = False
|
|
89
|
+
self.setCursor(Qt.CursorShape.ArrowCursor)
|
|
90
|
+
self.update()
|
|
91
|
+
super().hoverLeaveEvent(event)
|
|
92
|
+
|
|
93
|
+
def paint(self, painter, option, widget=None):
|
|
94
|
+
super().paint(painter, option, widget)
|
|
95
|
+
if not self.handles_visible:
|
|
96
|
+
return
|
|
97
|
+
|
|
98
|
+
# Draw resize handles
|
|
99
|
+
painter.setPen(QPen(Qt.GlobalColor.black, 1))
|
|
100
|
+
painter.setBrush(QBrush(Qt.GlobalColor.white))
|
|
101
|
+
for name, handle in self.handles.items():
|
|
102
|
+
if name == "rotation":
|
|
103
|
+
painter.setPen(QPen(Qt.GlobalColor.blue, 2))
|
|
104
|
+
painter.setBrush(QBrush(Qt.GlobalColor.blue))
|
|
105
|
+
painter.drawEllipse(handle)
|
|
106
|
+
else:
|
|
107
|
+
painter.drawRect(handle)
|
|
108
|
+
|
|
109
|
+
def mousePressEvent(self, event):
|
|
110
|
+
self.handle_selected = None
|
|
111
|
+
for name, rect in self.handles.items():
|
|
112
|
+
if rect.contains(event.pos()):
|
|
113
|
+
self.handle_selected = name
|
|
114
|
+
if name == "rotation":
|
|
115
|
+
rect_center = self.rect().center()
|
|
116
|
+
self.setTransformOriginPoint(rect_center)
|
|
117
|
+
|
|
118
|
+
# Save starting angle
|
|
119
|
+
rect_center_scene = self.mapToScene(rect_center)
|
|
120
|
+
mouse_scene_pos = self.mapToScene(event.pos())
|
|
121
|
+
self.initial_rotation = math.atan2(
|
|
122
|
+
mouse_scene_pos.y() - rect_center_scene.y(),
|
|
123
|
+
mouse_scene_pos.x() - rect_center_scene.x(),
|
|
124
|
+
)
|
|
125
|
+
self.initial_angle = self.rotation()
|
|
126
|
+
break
|
|
127
|
+
super().mousePressEvent(event)
|
|
128
|
+
|
|
129
|
+
def mouseMoveEvent(self, event):
|
|
130
|
+
if self.handle_selected == 'rotation':
|
|
131
|
+
self.rotate_item(event)
|
|
132
|
+
elif self.handle_selected:
|
|
133
|
+
self.resize_item(event)
|
|
134
|
+
else:
|
|
135
|
+
super().mouseMoveEvent(event)
|
|
136
|
+
|
|
137
|
+
def mouseReleaseEvent(self, event):
|
|
138
|
+
if self.handle_selected == 'rotation':
|
|
139
|
+
self.setCursor(Qt.CursorShape.OpenHandCursor)
|
|
140
|
+
event.accept()
|
|
141
|
+
self.handle_selected = None
|
|
142
|
+
self.handles_visible = True
|
|
143
|
+
self.update()
|
|
144
|
+
if not event.isAccepted():
|
|
145
|
+
super().mouseReleaseEvent(event)
|
|
146
|
+
|
|
147
|
+
def rotate_item(self, event):
|
|
148
|
+
self.setCursor(Qt.CursorShape.ClosedHandCursor)
|
|
149
|
+
rect_center_scene = self.mapToScene(self.rect().center())
|
|
150
|
+
mouse_scene_pos = self.mapToScene(event.pos())
|
|
151
|
+
|
|
152
|
+
current_angle = math.atan2(
|
|
153
|
+
mouse_scene_pos.y() - rect_center_scene.y(),
|
|
154
|
+
mouse_scene_pos.x() - rect_center_scene.x(),
|
|
155
|
+
)
|
|
156
|
+
angle_diff = math.degrees(current_angle - self.initial_rotation)
|
|
157
|
+
self.setRotation(self.initial_angle + angle_diff)
|
|
158
|
+
|
|
159
|
+
self.update_handles()
|
|
160
|
+
self.update()
|
|
161
|
+
|
|
162
|
+
def resize_item(self, event):
|
|
163
|
+
rect = self.rect()
|
|
164
|
+
pos = event.pos()
|
|
165
|
+
|
|
166
|
+
if self.handle_selected == 'top_left':
|
|
167
|
+
rect.setTopLeft(pos)
|
|
168
|
+
elif self.handle_selected == 'top_right':
|
|
169
|
+
rect.setTopRight(pos)
|
|
170
|
+
elif self.handle_selected == 'bottom_left':
|
|
171
|
+
rect.setBottomLeft(pos)
|
|
172
|
+
elif self.handle_selected == 'bottom_right':
|
|
173
|
+
rect.setBottomRight(pos)
|
|
174
|
+
|
|
175
|
+
# Enforce minimum size
|
|
176
|
+
if rect.width() < MIN_RECT_SIZE:
|
|
177
|
+
rect.setWidth(MIN_RECT_SIZE)
|
|
178
|
+
if rect.height() < MIN_RECT_SIZE:
|
|
179
|
+
rect.setHeight(MIN_RECT_SIZE)
|
|
180
|
+
|
|
181
|
+
self.setRect(rect)
|
|
182
|
+
self.update_handles()
|
|
183
|
+
self.update()
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class Rectangle(Core):
|
|
187
|
+
def __init__(self):
|
|
188
|
+
super().__init__()
|
|
189
|
+
self.first_click_pos = None
|
|
190
|
+
self.current_rectangle = None
|
|
191
|
+
self.is_drawing = False
|
|
192
|
+
self.selected_rectangle = None
|
|
193
|
+
|
|
194
|
+
def rectangle(self):
|
|
195
|
+
self.checked_button = self.rectangle.__name__
|
|
196
|
+
self.zoomable_graphics_view.scene.selectionChanged.connect(self.update_selected_rectangle)
|
|
197
|
+
|
|
198
|
+
def cleanup_temporary_rectangles(self):
|
|
199
|
+
if self.current_rectangle and self.current_rectangle in self.zoomable_graphics_view.scene.items():
|
|
200
|
+
self.zoomable_graphics_view.scene.removeItem(self.current_rectangle)
|
|
201
|
+
self.current_rectangle = None
|
|
202
|
+
|
|
203
|
+
def start_rectangle_tool(self, current_position):
|
|
204
|
+
self.zoomable_graphics_view.change_cursor("rectangle")
|
|
205
|
+
self.cleanup_temporary_rectangles()
|
|
206
|
+
|
|
207
|
+
self.first_click_pos = QPointF(current_position)
|
|
208
|
+
self.color = self.get_labeling_overlay().get_color()
|
|
209
|
+
self.is_drawing = True
|
|
210
|
+
|
|
211
|
+
self.current_rectangle = QGraphicsRectItem(self.first_click_pos.x(), self.first_click_pos.y(), 1, 1)
|
|
212
|
+
self.current_rectangle.setPen(QPen(self.color, 2, Qt.PenStyle.DashLine))
|
|
213
|
+
self.current_rectangle.setZValue(2)
|
|
214
|
+
self.zoomable_graphics_view.scene.addItem(self.current_rectangle)
|
|
215
|
+
|
|
216
|
+
def move_rectangle_tool(self, current_position):
|
|
217
|
+
if not (self.is_drawing and self.current_rectangle):
|
|
218
|
+
return
|
|
219
|
+
current_pos = QPointF(current_position)
|
|
220
|
+
x, y = min(self.first_click_pos.x(), current_pos.x()), min(self.first_click_pos.y(), current_pos.y())
|
|
221
|
+
w, h = abs(current_pos.x() - self.first_click_pos.x()), abs(current_pos.y() - self.first_click_pos.y())
|
|
222
|
+
self.current_rectangle.setRect(x, y, w, h)
|
|
223
|
+
|
|
224
|
+
def end_rectangle_tool(self):
|
|
225
|
+
if not (self.is_drawing and self.current_rectangle):
|
|
226
|
+
return
|
|
227
|
+
|
|
228
|
+
rect = self.current_rectangle.rect()
|
|
229
|
+
self.cleanup_temporary_rectangles()
|
|
230
|
+
|
|
231
|
+
if rect.width() > 5 and rect.height() > 5:
|
|
232
|
+
final_rectangle = RectangleItem(rect.x(), rect.y(), rect.width(), rect.height(), self.color)
|
|
233
|
+
final_rectangle.setZValue(2)
|
|
234
|
+
final_rectangle.setFlag(QGraphicsRectItem.GraphicsItemFlag.ItemIsSelectable, True)
|
|
235
|
+
self.zoomable_graphics_view.scene.addItem(final_rectangle)
|
|
236
|
+
self.selected_rectangle = final_rectangle
|
|
237
|
+
|
|
238
|
+
self.first_click_pos = None
|
|
239
|
+
self.is_drawing = False
|
|
240
|
+
|
|
241
|
+
def update_selected_rectangle(self):
|
|
242
|
+
items = self.zoomable_graphics_view.scene.selectedItems()
|
|
243
|
+
self.selected_rectangle = next((i for i in reversed(items) if isinstance(i, RectangleItem)), None)
|
|
244
|
+
|
|
245
|
+
def clear_rectangle(self):
|
|
246
|
+
if self.selected_rectangle and self.selected_rectangle in self.zoomable_graphics_view.scene.items():
|
|
247
|
+
self.zoomable_graphics_view.scene.removeItem(self.selected_rectangle)
|
|
248
|
+
self.selected_rectangle = None
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from PyQt6.QtGui import QPainter, QBitmap, QImage, QPixmap, QPen
|
|
2
|
+
from PyQt6.QtCore import Qt, QSize
|
|
3
|
+
from PyImageLabeling.model.Core import Core
|
|
4
|
+
|
|
5
|
+
class Undo(Core):
|
|
6
|
+
def __init__(self):
|
|
7
|
+
super().__init__()
|
|
8
|
+
|
|
9
|
+
def undo(self):
|
|
10
|
+
self.get_current_image_item().get_labeling_overlay().undo()
|
|
11
|
+
|
|
12
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Model
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from PyImageLabeling.model.File.Files import Files
|
|
5
|
+
from PyImageLabeling.model.File.NextImage import NextImage
|
|
6
|
+
from PyImageLabeling.model.File.PreviousImage import PreviousImage
|
|
7
|
+
|
|
8
|
+
from PyImageLabeling.model.Labeling.ContourFilling import ContourFilling
|
|
9
|
+
from PyImageLabeling.model.Labeling.MagicPen import MagicPen
|
|
10
|
+
from PyImageLabeling.model.Labeling.PaintBrush import PaintBrush
|
|
11
|
+
from PyImageLabeling.model.Labeling.Polygon import Polygon
|
|
12
|
+
from PyImageLabeling.model.Labeling.Rectangle import Rectangle
|
|
13
|
+
from PyImageLabeling.model.Labeling.ClearAll import ClearAll
|
|
14
|
+
from PyImageLabeling.model.Labeling.Eraser import Eraser
|
|
15
|
+
from PyImageLabeling.model.Labeling.Undo import Undo
|
|
16
|
+
from PyImageLabeling.model.Labeling.Ellipse import Ellipse
|
|
17
|
+
|
|
18
|
+
from PyImageLabeling.model.Image.MoveImage import MoveImage
|
|
19
|
+
from PyImageLabeling.model.Image.ZoomMinus import ZoomMinus
|
|
20
|
+
from PyImageLabeling.model.Image.ZoomPlus import ZoomPlus
|
|
21
|
+
from PyImageLabeling.model.Image.ResetMoveZoomImage import ResetMoveZoomImage
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Model(Files, NextImage, PreviousImage, ClearAll, Eraser, Undo, ContourFilling, MagicPen, PaintBrush, Polygon, Rectangle, Ellipse, MoveImage, ZoomMinus, ZoomPlus, ResetMoveZoomImage):
|
|
25
|
+
def __init__(self, view, controller, config):
|
|
26
|
+
super().__init__()
|
|
27
|
+
self.config = config
|
|
28
|
+
self.set_view(view)
|
|
29
|
+
self.set_controller(controller)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def set_view(self, view):
|
|
33
|
+
super().set_view(view)
|
|
34
|
+
self.view = view
|
|
35
|
+
|
|
36
|
+
def set_controller(self, controller):
|
|
37
|
+
super().set_controller(controller)
|
|
38
|
+
self.controller = controller
|
|
39
|
+
|
|
40
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
|
|
2
|
+
import os
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
class Utils():
|
|
6
|
+
|
|
7
|
+
def __init__(self):
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
def get_icon_path(icon_name):
|
|
11
|
+
# Assuming icons are stored in an 'icons' folder next to the script
|
|
12
|
+
icon_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'+os.sep+'icons')
|
|
13
|
+
icon_path = os.path.join(icon_dir, f"{icon_name}.png")
|
|
14
|
+
if not os.path.exists(icon_path):
|
|
15
|
+
raise FileNotFoundError("The icon is not found: ", icon_path)
|
|
16
|
+
return icon_path
|
|
17
|
+
|
|
18
|
+
def get_style_css():
|
|
19
|
+
return open(os.path.dirname(os.path.abspath(__file__))+os.sep+".."+os.sep+"style.css").read()
|
|
20
|
+
|
|
21
|
+
def get_config():
|
|
22
|
+
with open(os.path.dirname(os.path.abspath(__file__))+os.sep+".."+os.sep+"config.json", 'r', encoding='utf-8') as file:
|
|
23
|
+
data = json.load(file)
|
|
24
|
+
return data
|
|
25
|
+
|
|
26
|
+
def load_parameters():
|
|
27
|
+
with open(os.path.dirname(os.path.abspath(__file__))+os.sep+".."+os.sep+"parameters.json", 'r', encoding='utf-8') as file:
|
|
28
|
+
data = json.load(file)
|
|
29
|
+
return data
|
|
30
|
+
|
|
31
|
+
def save_parameters(data):
|
|
32
|
+
with open(os.path.dirname(os.path.abspath(__file__))+os.sep+".."+os.sep+"parameters.json", 'w') as fp:
|
|
33
|
+
json.dump(data, fp)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def color_to_stylesheet(color):
|
|
37
|
+
return f"background-color: rgb({color.red()}, {color.green()}, {color.blue()}); color: {'white' if color.lightness() < 128 else 'black'};"
|
|
38
|
+
|
|
39
|
+
def compute_diagonal(x_1, y_1, x_2, y_2):
|
|
40
|
+
return ((x_1 - x_2) ** 2 + (y_1 - y_2) ** 2) ** 0.5
|