batoolset-gui 0.2.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.
Files changed (74) hide show
  1. batoolset/GUI/__init__.py +0 -0
  2. batoolset/GUI/customdialog.py +136 -0
  3. batoolset/GUI/exception_handler.py +74 -0
  4. batoolset/GUI/list_gui.py +514 -0
  5. batoolset/GUI/multi_image_display.py +1038 -0
  6. batoolset/GUI/open.py +325 -0
  7. batoolset/GUI/overlay_hints.py +45 -0
  8. batoolset/GUI/paint2.py +1369 -0
  9. batoolset/GUI/scrollablepaint.py +1165 -0
  10. batoolset/dialogs/__init__.py +0 -0
  11. batoolset/dialogs/opensave.py +228 -0
  12. batoolset/drawings/__init__.py +0 -0
  13. batoolset/drawings/math_text.py +294 -0
  14. batoolset/drawings/pdf_svg_renderer.py +376 -0
  15. batoolset/drawings/shapes/Position.py +183 -0
  16. batoolset/drawings/shapes/__init__.py +0 -0
  17. batoolset/drawings/shapes/automated_alignment_drawing_refactored.py +346 -0
  18. batoolset/drawings/shapes/circle2d.py +99 -0
  19. batoolset/drawings/shapes/compute_optimal_size_all_merged.py +328 -0
  20. batoolset/drawings/shapes/ellipse2d.py +336 -0
  21. batoolset/drawings/shapes/freehand2d.py +235 -0
  22. batoolset/drawings/shapes/group.py +1985 -0
  23. batoolset/drawings/shapes/image2d.py +3157 -0
  24. batoolset/drawings/shapes/line2d.py +579 -0
  25. batoolset/drawings/shapes/point2d.py +257 -0
  26. batoolset/drawings/shapes/polygon2d.py +357 -0
  27. batoolset/drawings/shapes/polyline2d.py +235 -0
  28. batoolset/drawings/shapes/rect2d.py +388 -0
  29. batoolset/drawings/shapes/rectangle2d.py +601 -0
  30. batoolset/drawings/shapes/scalebar.py +310 -0
  31. batoolset/drawings/shapes/serializablefont.py +133 -0
  32. batoolset/drawings/shapes/serializableguiparams.py +14 -0
  33. batoolset/drawings/shapes/square2d.py +102 -0
  34. batoolset/drawings/shapes/test_publication_style.py +220 -0
  35. batoolset/drawings/shapes/textorientation.py +45 -0
  36. batoolset/drawings/shapes/tools.py +467 -0
  37. batoolset/drawings/shapes/transform2D.py +350 -0
  38. batoolset/drawings/shapes/txt2d.py +615 -0
  39. batoolset/drawings/svg_clip_renderer.py +247 -0
  40. batoolset/drawings/svg_embed.py +165 -0
  41. batoolset/drawings/svg_text_renderer.py +183 -0
  42. batoolset/drawings/widgets/__init__.py +0 -0
  43. batoolset/drawings/widgets/col.py +343 -0
  44. batoolset/drawings/widgets/image_group.py +248 -0
  45. batoolset/drawings/widgets/image_organizer.py +96 -0
  46. batoolset/drawings/widgets/paint.py +184 -0
  47. batoolset/drawings/widgets/vectorial.py +256 -0
  48. batoolset/figure/__init__.py +0 -0
  49. batoolset/figure/alignment.py +822 -0
  50. batoolset/figure/column.py +1117 -0
  51. batoolset/figure/fig_tools.py +285 -0
  52. batoolset/figure/minimal_debugger_scale_etc.py +139 -0
  53. batoolset/figure/panel.py +697 -0
  54. batoolset/figure/row.py +852 -0
  55. batoolset/figure/user_selection.py +287 -0
  56. batoolset/icons/__init__.py +0 -0
  57. batoolset/icons/tools.py +248 -0
  58. batoolset/luts/__init__.py +0 -0
  59. batoolset/luts/lut_minimal_test.py +1308 -0
  60. batoolset/luts/lutcreatorfromformula.py +209 -0
  61. batoolset/luts/luteditor.py +243 -0
  62. batoolset/pyqts/__init__.py +0 -0
  63. batoolset/pyqts/pleasewaitdialog.py +14 -0
  64. batoolset/pyqts/tools.py +760 -0
  65. batoolset/serializations/__init__.py +0 -0
  66. batoolset/serializations/tools.py +1338 -0
  67. batoolset/theme.py +647 -0
  68. batoolset/uis/__init__.py +0 -0
  69. batoolset/uis/blinker.py +56 -0
  70. batoolset_gui-0.2.0.dist-info/METADATA +54 -0
  71. batoolset_gui-0.2.0.dist-info/RECORD +74 -0
  72. batoolset_gui-0.2.0.dist-info/WHEEL +5 -0
  73. batoolset_gui-0.2.0.dist-info/licenses/LICENSE +24 -0
  74. batoolset_gui-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,615 @@
1
+ # TODO allow text for be written at an angle and determine it size then
2
+ from batoolset.settings.global_settings import set_UI # set the UI to qtpy
3
+ set_UI()
4
+ from batoolset.pyqts.tools import get_painter_transform_and_rotation
5
+ from batoolset.drawings.shapes.textorientation import get_angle
6
+ from batoolset.drawings.shapes.Position import Position
7
+ from qtpy import QtCore
8
+ from qtpy.QtCore import QRect
9
+ from qtpy.QtGui import QTextDocument, QTextOption
10
+ from qtpy.QtGui import QPainter, QImage, QColor, QFont, QBrush, QTransform
11
+ from qtpy.QtCore import QRectF, QPointF
12
+ import sys
13
+ from qtpy import QtGui
14
+ from qtpy.QtCore import Qt
15
+ from qtpy.QtWidgets import QApplication
16
+ from batoolset.drawings.shapes.rectangle2d import Rectangle2D
17
+ # log errors
18
+ from batoolset.tools.logger import TA_logger
19
+ logger = TA_logger()
20
+
21
+
22
+ def draw_document(doc, painter):
23
+ """doc.drawContents(painter), but text with no colour of its own is black:
24
+ drawContents takes it from the application palette, so on a dark UI theme
25
+ (or Windows in dark mode) figure labels came out light grey on a white
26
+ page, in exports too. A figure must not depend on the UI theme."""
27
+ from qtpy.QtGui import QAbstractTextDocumentLayout, QPalette
28
+ ctx = QAbstractTextDocumentLayout.PaintContext()
29
+ palette = QPalette(ctx.palette)
30
+ palette.setColor(QPalette.ColorRole.Text, QColor(0, 0, 0))
31
+ ctx.palette = palette
32
+ doc.documentLayout().draw(painter, ctx)
33
+
34
+
35
+ class TAText2D(Rectangle2D):
36
+
37
+ # TODO add bg to it so that it can be drawn
38
+ def __init__(self, text=None, doc=None, opacity=1.,x=None, y=None, fill_color=None, color=None, text_orientation='X',placement=Position(),range=None, is_letter=False,__version=1.0,*args, **kwargs):
39
+ if doc is not None and isinstance(doc, QTextDocument):
40
+ self.doc = doc
41
+ self.doc.setDocumentMargin(0) # important so that the square is properly placed
42
+ # self.text = self.doc.toHtml()
43
+ else:
44
+ self.doc = QTextDocument()
45
+ self.doc.setDocumentMargin(0) # important so that the square is properly placed
46
+
47
+ textOption = self.doc.defaultTextOption()
48
+ textOption.setWrapMode(QTextOption.NoWrap)
49
+ self.doc.setDefaultTextOption(textOption)
50
+
51
+ if text is not None:
52
+ self.doc.setHtml(text)
53
+ # self.setText(text)
54
+ # else:
55
+ # self.setText('')
56
+ # self.text = text
57
+ # self.isSet = True
58
+ self.doc.adjustSize()
59
+ size = self.getSize()
60
+
61
+ super(TAText2D, self).__init__(x if x is not None else 0, y if y is not None else 0, size.width(), size.height())
62
+ self.opacity = opacity
63
+ self.immutable=True
64
+ self.line_style = None # useless just for compat with other shapes
65
+ if placement is not None:
66
+ if not isinstance(placement, Position):
67
+ placement = Position(placement)
68
+ self.placement = placement
69
+ self.fill_color = fill_color
70
+ self.color = color
71
+ self.text_orientation = text_orientation
72
+ self.range = range # this will contain the spanning of text over several elements only used and useful for text rows
73
+ self.__version = __version
74
+ self.is_letter = is_letter
75
+ # if x is not None:
76
+ # self.setX(x)
77
+ # if y is not None:
78
+ # self.setY(y)
79
+
80
+ def _layout_doc(self):
81
+ """The document that is drawn and measured: self.doc with its $…$
82
+ typeset as maths (batoolset.drawings.math_text), or self.doc itself.
83
+ self.doc keeps the raw text: it is what is saved and edited."""
84
+ # (cached in math_text, never on self: self is saved and copied)
85
+ try:
86
+ from batoolset.drawings.math_text import typeset_for
87
+ return typeset_for(self, self.doc)
88
+ except Exception:
89
+ logger.error('could not typeset the maths in "' + self.doc.toPlainText() + '"')
90
+ return self.doc
91
+
92
+ def _letter_ink_shift(self):
93
+ """How far up a plain top letter is drawn so that its ink top is the top
94
+ of its box: the line box leaves room above every letter (more above
95
+ 'a', 'c', 'e'... than above 'b'), so letters sat low in the corner and
96
+ not all at the same height. The gap to the panel edge is then
97
+ image2d.EDGE_MARGIN, as on the left. 0 for other texts, letters on a
98
+ box (centred in it) and bottom letters (aligned on the baseline)."""
99
+ if not getattr(self, 'is_letter', False) or self.fill_color is not None:
100
+ return 0.
101
+ if self.placement is None or not self.placement.check_position('top'):
102
+ return 0.
103
+ if (self.text_orientation is not None and 'X' not in self.text_orientation) or self.theta:
104
+ return 0.
105
+ doc = self._layout_doc()
106
+ text = doc.toPlainText().strip()
107
+ if not text:
108
+ return 0.
109
+ from qtpy.QtGui import QFontMetricsF, QTextCursor
110
+ cursor = QTextCursor(doc)
111
+ cursor.setPosition(1)
112
+ font = cursor.charFormat().font()
113
+ key = (text, font.toString())
114
+ cache = TAText2D._ink_shift_cache
115
+ if key not in cache:
116
+ fm = QFontMetricsF(font)
117
+ # ink top below the line top (the baseline is fm.ascent() down)
118
+ shift = fm.tightBoundingRect(text).top() + fm.ascent()
119
+ # in line-box units: the document is laid out at its own resolution
120
+ cache[key] = max(0., shift) / fm.height() if fm.height() else 0.
121
+ line = doc.documentLayout().blockBoundingRect(doc.firstBlock()).height()
122
+ return cache[key] * line
123
+
124
+ _ink_shift_cache = {}
125
+
126
+ def set_range(self, range):
127
+ # this is the range of labels in text rows
128
+ self.range = range
129
+
130
+ def set_opacity(self, opacity):
131
+ self.opacity = opacity
132
+
133
+ def setText(self, html):
134
+ self.doc.setHtml(html)
135
+ # self.doc.adjustSize()
136
+ # size = self.getSize()
137
+ # self.setWidth(size.width())
138
+ # self.setHeight(size.height())
139
+ self.setDoc(self.doc)
140
+ # self.text = html
141
+
142
+ def setDoc(self, doc):
143
+ self.doc = doc
144
+ self.doc.setDocumentMargin(0)
145
+ self.doc.adjustSize()
146
+ size = self.getSize()
147
+ self.setWidth(size.width())
148
+ self.setHeight( size.height())
149
+ # self.text = self.getHtmlText()
150
+
151
+ def draw(self, painter, draw=True, parent=None):
152
+ if draw:
153
+ self.scale=1 # TODO FIX THIS BETTER TATEXT SHOULD NEVER BE RESCALED just a hack so that the scale is always preserved (importantly the square is properly positioned but the text is not (probably needs be cntered on the rect center) no big deal I guess
154
+ # LaTeX "PDF+LaTeX" export renders the graphics with text suppressed so
155
+ # the text can be typeset by LaTeX; the rect/size is left untouched so the
156
+ # parent's placement is unaffected and the overlay coordinates stay correct
157
+ if getattr(self, '_latex_hide', False):
158
+ return
159
+ painter.save()
160
+
161
+ # transform = QTransform()
162
+ # transform.rotate(0) # Rotate 45 degrees clockwise
163
+ # painter.setWorldTransform(transform)
164
+
165
+
166
+ # Get the rotation angle of the transform
167
+ # Get the current transformation and rotation
168
+
169
+ # transform, rotation_angle = get_painter_transform_and_rotation(painter) # this is ok --> this is 0
170
+ # print(f"Current transformation matrix: {transform}")
171
+ # print(f"Current rotation angle: {rotation_angle:.2f} degrees")
172
+
173
+ painter.setPen(Qt.NoPen)
174
+ painter.setBrush(Qt.NoBrush)
175
+
176
+ # Get the current clip rect of the painter
177
+ # current_clip_rect = painter.clipBoundingRect()
178
+ # print('current_clip_rect',current_clip_rect)
179
+
180
+ # print('self.placement, self.placement.isEmpty()',self.placement, self.placement.isEmpty())
181
+
182
+ rect_to_plot = self.getRect(scale=True)
183
+ if self.placement is None or self.placement.isEmpty():
184
+ # if True:
185
+ # painter.setClipRect(self.getRect(scale=True)) # in fact this is needed to get text to work!!! # DO NOT DO THIS OTHERWISE THE TEXT IS NOT CLIPPED WHICH IS NOT WHAT I WANT!!!!
186
+ # if text --> need center v or h --> TODO
187
+ # else:
188
+ rect_to_plot = self.getRect(scale=True)
189
+
190
+ if parent is not None and parent.scale is not None and parent.scale != 1:
191
+ rect_to_plot = QRectF(rect_to_plot.x() / parent.scale, rect_to_plot.y() / parent.scale, rect_to_plot.width() / parent.scale,rect_to_plot.height() / parent.scale)
192
+ # neo
193
+ # rect_to_plot = self.getRect(scale=True)
194
+ # rect_to_plot.setX(rect_to_plot.x()/parent.scale)
195
+ # rect_to_plot.setY(rect_to_plot.y()/parent.scale) # now this shit is huge
196
+ # somehow this is required for text but why ????
197
+
198
+ # print('rect_to_plot', rect_to_plot)
199
+ if parent is not None:
200
+ rect_to_plot = rect_to_plot.translated(parent.topLeft())
201
+ # print('rect_to_plot2',rect_to_plot)
202
+
203
+ #DEBUG
204
+ if False:
205
+ painter.setPen(QtCore.Qt.red)
206
+ painter.drawRect(rect_to_plot)
207
+
208
+ # do not move this, this is where the fill color should be applied
209
+ if self.fill_color is not None:
210
+ # if isinstance(self.fill_color, QColor):
211
+ # self.fill_color = self.fill_color.rgb() & 0xFFFFFF
212
+
213
+ # print(self, self.fill_color, 'inside drawing')
214
+
215
+ # somehow the rect pos is completely wrong
216
+
217
+ # painter.setPen(QtCore.Qt.red)
218
+ painter.setBrush(QBrush(QColor(self.fill_color)))
219
+ painter.save()
220
+
221
+ # all seems to be fixed now but allI do here is totally crazy -−> DO A CLEAN FIX OF THE STUFF SOME DAY
222
+ rect2 =QRectF(rect_to_plot.x(), rect_to_plot.y(), rect_to_plot.width(), rect_to_plot.height())
223
+ text_width = self._layout_doc().documentLayout().documentSize().width()
224
+ text_height = self._layout_doc().documentLayout().documentSize().height()
225
+ # very dirty fix I have to fix all more poperly some day this is totally abnormal that I have to do all of this !!! --< now that fixes the size but not the position --> somehow I am missing something still
226
+ rect2.setWidth(text_width)
227
+ rect2.setHeight(text_height)
228
+
229
+
230
+
231
+
232
+
233
+ # this is not totally ok
234
+ if self.text_orientation is not None and not 'X' in self.text_orientation:
235
+ # painter.translate(rect_to_plot.center())
236
+ # painter.rotate(90)
237
+ # painter.translate(-(rect_to_plot.center()))
238
+ # painter.translate(-)
239
+ painter.translate(rect_to_plot.topLeft())
240
+ painter.translate(rect_to_plot.height(), 0)
241
+ painter.rotate(get_angle(self.text_orientation))
242
+ painter.translate(-rect_to_plot.topLeft()) # presque -−> doit etre aligne au coin gaughe
243
+
244
+
245
+ # else:
246
+ painter.translate(rect_to_plot.center() - rect2.center())
247
+
248
+
249
+ painter.drawRect(rect2)
250
+ painter.restore()
251
+ # self.doc.drawContents(painter)
252
+
253
+ # this is positioned properly so why isn't text positioned there too!!! ???
254
+
255
+ # self.doc.drawContents(painter)
256
+
257
+ # if self.theta is not None and self.theta != 0:
258
+ if self.theta is not None and self.theta != 0:
259
+ # I have added support for rotation to that maybe I will need something smarter if rotation 90 degrees or flips and images no same width and height
260
+ painter.translate(rect_to_plot.center())
261
+ painter.rotate(self.theta)
262
+ painter.translate(-rect_to_plot.center())
263
+
264
+ if self.text_orientation is not None and not 'X' in self.text_orientation: # self.text_orientation is not None: # and not 'X' in self.text_orientation
265
+ # very good -> that does the job --> the only thing is that of course it selection is not correct --> need fix it
266
+ painter.translate(rect_to_plot.topLeft())
267
+ painter.translate(rect_to_plot.height(), 0)
268
+ painter.rotate(get_angle(self.text_orientation))
269
+ painter.translate(-rect_to_plot.topLeft()) # presque -−> doit etre aligne au coin gaughe
270
+ # painter.translate(rect_to_plot.height(),0) # presque -−> doit etre aligne au coin gaughe
271
+
272
+ # self.doc.drawContents(painter)
273
+ # if True: #TODO remove that debug only
274
+ # painter.drawRect(rect_to_plot)
275
+
276
+ # if self.opacity is not None:
277
+ # painter.setOpacity(self.opacity)
278
+
279
+ # if False:
280
+ painter.translate(rect_to_plot.x(), rect_to_plot.y())
281
+
282
+
283
+
284
+ if False:
285
+ text_width = self.doc.documentLayout().documentSize().width()
286
+ text_height = self.doc.documentLayout().documentSize().height()
287
+ # rect_of_doc = self.doc.documentRect()
288
+ painter.setClipRect(QRectF(rect_to_plot.x(), rect_to_plot.y(),min(text_width, rect_to_plot.width()),min(text_height, rect_to_plot.height())))
289
+
290
+
291
+
292
+ if True:
293
+ text_width = self._layout_doc().documentLayout().documentSize().width()
294
+ text_height = self._layout_doc().documentLayout().documentSize().height()
295
+ # print('text_width, text_height',text_width, text_height, rect_to_plot, 'BINGO BINGO2')
296
+ painter.translate((rect_to_plot.width()-text_width)/2, (rect_to_plot.height()-text_height)/2) # le bug est bien ici --> somehow the rect is still not correct and wrongly scaled --> what is the bug ?
297
+
298
+
299
+ # with that the rect size is ok but the position is completely crap
300
+ # if self.fill_color:
301
+ # text_width = self.doc.documentLayout().documentSize().width()
302
+ # text_height = self.doc.documentLayout().documentSize().height()
303
+ # # very dirty fix I have to fix all more poperly some day this is totally abnormal that I have to do all of this !!! --< now that fixes the size but not the position --> somehow I am missing something still
304
+ # rect_to_plot.setWidth(text_width)
305
+ # rect_to_plot.setHeight(text_height)
306
+ # painter.setBrush(QBrush(QColor(self.fill_color)))
307
+ # painter.drawRect(rect_to_plot)
308
+
309
+ # painter.translate(self.x()+self.width()/2., self.y()+self.height()/2.) # if I do that the square and the
310
+
311
+ # here I need a cliprect of just the size of the stuff and not even that but the intersection with the parent
312
+ # painter.translate(-rect_to_plot.center())
313
+
314
+ # shall I get the rect of the doc and see if it fits the other otherwise probably I need to center it at least I can check that
315
+
316
+
317
+ # not 'X' in self.text_orientation
318
+ if self.text_orientation and '-' in self.text_orientation:# self.text_orientation and '-' in self.text_orientation:
319
+ painter.rotate(180) # ok but the pb is then I need to shift it back again
320
+ painter.translate(-rect_to_plot.width(), -rect_to_plot.height())
321
+
322
+ # painter.setWorldTransform(QTransform())
323
+ #
324
+ # transform, rotation_angle = get_painter_transform_and_rotation(painter) # this is ok --> this is 0
325
+ # print(f"DEBUG Current transformation matrix: {transform}")
326
+ # print(f"Current rotation angle: {rotation_angle:.2f} degrees")
327
+ # print(self.text_orientation, '-->',get_angle(self.text_orientation)) # NO BUG IS THERE YET RANDOM ....
328
+ # painter.resetTransform()
329
+ painter.translate(0, -self._letter_ink_shift())
330
+ draw_document(self._layout_doc(), painter)
331
+
332
+
333
+
334
+
335
+
336
+
337
+
338
+
339
+ painter.restore()
340
+ # maybe activate this upon debug
341
+ # painter.save()
342
+ # painter.setPen(QtCore.Qt.red)
343
+ # painter.drawRect(self)
344
+ # painter.restore()
345
+
346
+ # def set_to_scale(self, factor): # this object should not be rescalable
347
+ # raise Exception('this should not be called --> this creates a bug because the size fo this object is immutable')
348
+ # self.scale = 1
349
+
350
+ def boundingRect(self): # is that ok also
351
+ return self
352
+
353
+ def getSize(self): # is that ok ???
354
+ return self._layout_doc().size()
355
+
356
+ def getWidth(self):
357
+ return self.boundingRect().width()
358
+
359
+ def getHeight(self):
360
+ return self.boundingRect().height()
361
+
362
+ def setText(self, text):
363
+ self.doc.setHtml(text)
364
+ # size = self.size()
365
+ # self.setWidth(size.width(), size.height())
366
+ self.setDoc(self.doc)
367
+
368
+ # def sync_text(self): # TODO always make sure to call this whenever a change to the text is made -−> will ease the serialization
369
+ # self.text = self.getHtmlText()
370
+
371
+ def getRect(self,*args, **kwargs):
372
+ # print('self.scale of the text', self.scale)
373
+
374
+ text_width = self._layout_doc().documentLayout().documentSize().width()
375
+ text_height = self._layout_doc().documentLayout().documentSize().height()
376
+ # if args:
377
+ if args or kwargs:
378
+ rect = QRectF(self.x()*self.scale, self.y()*self.scale, text_width, text_height)
379
+ if self.text_orientation is not None and not 'X' in self.text_orientation and 'all' in kwargs:
380
+ # turned 90° about its top-left then moved right by its height:
381
+ # the same corner, width and height swapped. (Mapping rect.toRect()
382
+ # rounded to whole pixels at its current position, so one label
383
+ # measured 15 or 16 px depending on where it was: undo/redo and
384
+ # reopening changed the row — monkey seed 149.)
385
+ rect = QRectF(rect.x(), rect.y(), text_height, text_width)
386
+ return rect
387
+ else:
388
+ # if args or kwargs:
389
+ return QRectF(self.x(), self.y(), text_width, text_height)
390
+
391
+ def width(self, *args, **kwargs):
392
+ return self.getRect(*args, **kwargs).width()
393
+
394
+ def height(self, *args, **kwargs):
395
+ return self.getRect(*args, **kwargs).height()
396
+
397
+ # def getRect(self,*args, **kwargs):
398
+ # if args or kwargs:
399
+ # if 'all' in kwargs:
400
+ # # print('in there!')
401
+ # # rect_to_plot = QRectF(*super().getRect())#QRectF(self.x(), self.y(), self.width() / self.scale, self.height() / self.scale)
402
+ # rect_to_plot = QRectF(self.x(), self.y(), self.width() / self.scale, self.height() / self.scale)
403
+ # center = rect_to_plot.center()
404
+ # if self.theta:
405
+ # # t = QTransform().translate(center.x(), center.y()).rotate(self.theta).translate(-center.x(),-center.y())
406
+ # # rotatedRect = t.mapToPolygon(rect_to_plot.toRect()) # // mapRect() returns the bounding rect
407
+ # t = QTransform().translate(center.x(), center.y()).rotate(self.theta).translate(-center.x(),
408
+ # -center.y())
409
+ # rotatedPolygon = t.mapToPolygon(rect_to_plot.toRect()) # Map the rectangle to a rotated polygon
410
+ #
411
+ # # Create a QRectF from the bounding rectangle of the rotated polygon
412
+ # rotatedRect = QRectF(rotatedPolygon.boundingRect())
413
+ # else:
414
+ # return rect_to_plot
415
+ # try:
416
+ # return QRectF(rotatedRect.boundingRect())
417
+ # except:
418
+ # return rotatedRect
419
+ # # return QRectF(self.x(), self.y(), self.width() / self.scale, self.height() / self.scale)
420
+ # else:
421
+ # # default to scaled object
422
+ # return QRectF(self.x(), self.y(), self.width()/self.scale, self.height()/self.scale)
423
+
424
+ # def __getstate__(self):
425
+ # # Return a dictionary containing the state of the object
426
+ # return {'text': self.getHtmlText()}
427
+ #
428
+ # def __setstate__(self, state):
429
+ # # Set the state of the object from the dictionary
430
+ # self.setText(state['text'])
431
+
432
+ # shall I rather compute its size including the roitation so that it never gets truncated --> that does make sense -−> need compute the bounds of the rotated stuff
433
+ # and the incompressible size should also depend on that
434
+
435
+ # def getIncompressibleWidth(self):
436
+ # # TODO in fact take the rotated size --> much smarter here --> see how I can do
437
+ # return self.width()
438
+ #
439
+ # def getIncompressibleHeight(self):
440
+ # return self.height()
441
+ #
442
+ # def get_incompressible_size(self, axis=None):
443
+ # # if True:
444
+ # # return self.width()
445
+ # # if self.theta is not None:
446
+ # # get width and or height
447
+ # if axis:
448
+ # if axis == 'X':
449
+ # return self.getIncompressibleWidth()
450
+ # else:
451
+ # return self.getIncompressibleHeight()
452
+
453
+ def setTopLeft(self, *args):
454
+ if args:
455
+ # cur_top_left = self.topLeft()
456
+ # print('cur_top_left', cur_top_left, args)
457
+ if len(args)==1:
458
+ # # assume a QpointF
459
+ self.moveTo(args[0].x(), args[0].y())
460
+ elif len(args) == 2:
461
+ self.moveTo(QPointF(args[0], args[1]))
462
+ # self.update_bounds()
463
+ # elif len(args)==2:
464
+ # for img in self.content:
465
+ # img.moveTopLeft(QPointF(args[0], args[1]))
466
+ # else:
467
+ # # logger.error('invalid args for top left')
468
+ # print('invalid args for top left')
469
+
470
+
471
+ # def set_P1(self, *args):
472
+ # if not args:
473
+ # logger.error("no coordinate set...")
474
+ # return
475
+ # if len(args) == 1:
476
+ # self.moveTo(args[0].x(), args[0].y())
477
+ # else:
478
+ # self.moveTo(QPointF(args[0], args[1]))
479
+ #
480
+ # def get_P1(self):
481
+ # return QPointF(self.x(), self.y())
482
+
483
+ def getPlainText(self):
484
+ return self.doc.toPlainText()
485
+
486
+ def getHtmlText(self):
487
+ return self.doc.toHtml()
488
+
489
+ def __repr__(self):
490
+ class_name = type(self).__name__
491
+ memory_address = hex(id(self))
492
+ return f"{class_name}-{memory_address}"
493
+
494
+ def to_dict(self):
495
+ x = self.x()
496
+ y = self.y()
497
+ # width = self.width()
498
+ # height = self.height()
499
+
500
+ # Create a dictionary representation of the values of the super object
501
+ output_dict = {
502
+ 'x': x,
503
+ 'y': y,
504
+ 'text': self.getHtmlText(),
505
+
506
+ # 'width': width,
507
+ # 'height': height,
508
+ # 'args':self.filename,
509
+ # 'filename':self.filename,
510
+ }
511
+
512
+ # print(output_dict)
513
+ # Update the dictionary with the __dict__ of Rectangle2D
514
+ output_dict.update(self.__dict__) # not smart because overrides the outputdict
515
+
516
+ output_dict['range']=self.range if self.range is None else str(self.range) # force convert it to text]
517
+
518
+
519
+ return output_dict
520
+
521
+ if __name__ == '__main__':
522
+ # this could be a pb ...
523
+ app = QApplication(sys.argv)# IMPORTANT KEEP !!!!!!!!!!!
524
+
525
+ # window = MyWidget()
526
+ # window.show()
527
+
528
+ # ça marche car ça override la couleur par defaut du truc
529
+ # c'est parfait et 2000X plus facile que ds java --> cool
530
+
531
+ html = '''
532
+ <!DOCTYPE html>
533
+ <html>
534
+ <head>
535
+ <title>Font Face</title>
536
+ </head>
537
+ <body>
538
+ <font color="red">
539
+ <font face="Symbol" size="5">Symbol</font><br />
540
+ <font face="Times New Roman" size="5">Times New Roman</font><br />
541
+ <font face="Verdana" size="5">Verdana</font><br />
542
+ <font face="Comic Sans MS" size="5">Comic Sans MS</font><br />
543
+ <font face="WildWest" size="5">WildWest</font><br />
544
+ <font face="Bedrock" size="5">Bedrock</font><br />
545
+ </font>
546
+ </body>
547
+ </html>
548
+ '''
549
+
550
+ # html = "<font color=blue size=24>this is a test<sup>2</sup><br></font><font color=green size=12>continued<sub>1</sub><br></font><font color=white size=12>test greek <font face='Symbol' size=32>a</font> another &alpha;<font face='Arial' color='Orange'>I am a sentence!</font>"
551
+ text = TAText2D(html)
552
+
553
+ # hexagon.append(QPointF(10, 20))
554
+ print(text)
555
+
556
+ # print(hexagon.translate(10, 20)) # why none ???
557
+ # translate and so on can all be saved...
558
+
559
+ image = QImage('/E/Sample_images/sample_images_PA/mini/focused_Series012/handCorrection.png')
560
+ # image = QImage(QSize(400, 300), QImage.Format_RGB32)
561
+ painter = QPainter()
562
+ painter.begin(image)
563
+ # painter.setOpacity(0.3);
564
+ painter.drawImage(0, 0, image)
565
+ painter.setPen(QtCore.Qt.blue)
566
+ text.opacity = 0.7
567
+ painter.translate(10, 20)
568
+ painter.setPen(QColor(168, 34, 3))
569
+
570
+ text.draw(painter) # ça marche pourrait overloader ça avec du svg
571
+
572
+ painter.drawRect(text)# try to draw the bounds
573
+
574
+ # painter.setPen(QtCore.Qt.green)
575
+ # painter.setFont(QFont('SansSerif', 50))
576
+
577
+
578
+ painter.setFont(QFont('Decorative', 10))
579
+ painter.drawText(256, 256, "this is a test")
580
+
581
+ # nothing works it just doesn't draw for unknown reason ????
582
+ # painter.drawText(QRect(60,60,256,256), Qt.AlignCenter, "this is a test")
583
+
584
+ painter.setPen(QtGui.QColor(0, 255, 255)) # colors are weird !!!
585
+ # painter.drawText(20, 20, "MetaGenerator") # fait planter le soft --> pkoi exit(139) ...
586
+ painter.drawText(QRect(60,60,256,256), Qt.AlignCenter, "Text centerd in the drawing area")
587
+
588
+ # painter.drawText(QRect(100, 100, 200, 100), "Text you want to draw...");
589
+ print('here')
590
+ painter.end()
591
+
592
+ # image = QImage(QSize(400, 300), QImage::Format_RGB32);
593
+ # QPainter
594
+ # painter( & image);
595
+ # painter.setBrush(QBrush(Qt::green));
596
+ # painter.fillRect(QRectF(0, 0, 400, 300), Qt::green);
597
+ # painter.fillRect(QRectF(100, 100, 200, 100), Qt::white);
598
+ # painter.setPen(QPen(Qt::black));
599
+
600
+
601
+ # painter.save()
602
+ # painter.setCompositionMode(QtGui.QPainter.CompositionMode_Clear)
603
+ # painter.eraseRect(r)
604
+ # painter.restore()
605
+ print('saving', '/E/trash//test_pyQT_draw_text.png')
606
+ image.save('/E/trash/test_pyQT_draw_text.png', "PNG")
607
+
608
+
609
+ # split text and find bounding rect of the stuff --> so that it is well positioned
610
+ # or do everything in svg and just show what's needed ???
611
+
612
+ #pas mal TODO faire une classe drawsmthg qui dessine n'importe quelle forme que l'on lui passe avec des parametres de couleur, transparence, ...
613
+
614
+ # tt marche aps mal ça va très vite
615
+ sys.exit(0)