Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add graphics capabilities to handle new features in Inspector.py #1267

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 64 additions & 22 deletions nion/swift/model/Graphics.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
class DrawingContextLike(typing.Protocol):
fill_style: typing.Optional[typing.Union[str, _LinearGradientLike]]
font: typing.Optional[str]
line_width: float
line_width: typing.Optional[float]
line_dash: typing.Optional[int]
stroke_style: typing.Optional[str]
text_align: typing.Optional[str]
Expand Down Expand Up @@ -461,7 +461,7 @@ def draw_rect_marker(ctx: DrawingContextLike, r: Geometry.FloatRect, fill_style:
draw_marker(ctx, r.bottom_left, fill_style)


def draw_ellipse_graphic(ctx: DrawingContextLike, center: Geometry.FloatPoint, size: Geometry.FloatSize, rotation: float, is_selected: bool, stroke_style: typing.Optional[str], fill_style: typing.Optional[str]) -> None:
def draw_ellipse_graphic(ctx: DrawingContextLike, center: Geometry.FloatPoint, size: Geometry.FloatSize, rotation: float, is_selected: bool, stroke_style: typing.Optional[str],stroke_width:typing.Optional[float], fill_style: typing.Optional[str]) -> None:
rect = Geometry.FloatRect.from_center_and_size(center, size)
origin = rect.origin
top_left = rect.top_left
Expand All @@ -474,14 +474,14 @@ def draw_ellipse_graphic(ctx: DrawingContextLike, center: Geometry.FloatPoint, s
ctx.translate(center.x, center.y)
ctx.rotate(-rotation)
ctx.translate(-center.x, -center.y)
ctx.line_width = 1
ctx.line_width = stroke_width or 1
draw_ellipse(ctx, origin + size / 2, size, stroke_style, fill_style)
ctx.begin_path()
ctx.move_to(center.x, rect.top + 10)
ctx.line_to(center.x, rect.top + 2)
draw_arrow(ctx, Geometry.FloatPoint(y=rect.top + 10, x=center.x), Geometry.FloatPoint(y=rect.top + 2, x=center.x), arrow_size=4)
ctx.move_to(center.x, rect.top + 10 + (.5 * int(stroke_width or 1)))
ctx.line_to(center.x, rect.top + 2 + (.5 * int(stroke_width or 1)))
draw_arrow(ctx, Geometry.FloatPoint(y=rect.top + 10 + (.5 * int(stroke_width or 1)), x=center.x), Geometry.FloatPoint(y=rect.top + 2 + (.5 * int(stroke_width or 1)) , x=center.x), arrow_size=4)
ctx.close_path()
ctx.line_width = 1
ctx.line_width = 1
ctx.stroke_style = stroke_style
ctx.stroke()
ctx.fill_style = fill_style
Expand Down Expand Up @@ -638,8 +638,11 @@ def __init__(self, type: str) -> None:
self.define_property("graphic_id", None, changed=self._property_changed, validate=lambda s: str(s) if s else None, hidden=True)
self.define_property("source_specifier", changed=self.__source_specifier_changed, key="source_uuid", hidden=True)
self.define_property("stroke_color", None, changed=self._property_changed, hidden=True)
self.define_property("stroke_width", None, changed=self._property_changed, hidden=True)
self.define_property("fill_color", None, changed=self._property_changed, hidden=True)
self.define_property("label", changed=self._property_changed, validate=lambda s: str(s) if s else None, hidden=True)
self.define_property("is_stroke_enabled", True, changed=self._property_changed, hidden=True)
self.define_property("is_fill_enabled", True, changed=self._property_changed, hidden=True)
self.define_property("is_position_locked", False, changed=self._property_changed, hidden=True)
self.define_property("is_shape_locked", False, changed=self._property_changed, hidden=True)
self.define_property("is_bounds_constrained", False, changed=self._property_changed, hidden=True)
Expand Down Expand Up @@ -679,6 +682,14 @@ def stroke_color(self) -> typing.Optional[str]:
def stroke_color(self, value: typing.Optional[str]) -> None:
self._set_persistent_property_value("stroke_color", value)

@property
def stroke_width(self) -> typing.Optional[float]:
return typing.cast(typing.Optional[float], self._get_persistent_property_value("stroke_width"))

@stroke_width.setter
def stroke_width(self, value: typing.Optional[float]) -> None:
self._set_persistent_property_value("stroke_width", value)

@property
def fill_color(self) -> typing.Optional[str]:
return typing.cast(typing.Optional[str], self._get_persistent_property_value("fill_color"))
Expand All @@ -695,6 +706,22 @@ def label(self) -> typing.Optional[str]:
def label(self, value: typing.Optional[str]) -> None:
self._set_persistent_property_value("label", value)

@property
def is_stroke_enabled(self) -> bool:
return typing.cast(bool, self._get_persistent_property_value("is_stroke_enabled"))

@is_stroke_enabled.setter
def is_stroke_enabled(self, value: bool) -> None:
self._set_persistent_property_value("is_stroke_enabled", value)

@property
def is_fill_enabled(self) -> bool:
return typing.cast(bool, self._get_persistent_property_value("is_fill_enabled"))

@is_fill_enabled.setter
def is_fill_enabled(self, value: bool) -> None:
self._set_persistent_property_value("is_fill_enabled", value)

@property
def is_position_locked(self) -> bool:
return typing.cast(bool, self._get_persistent_property_value("is_position_locked"))
Expand Down Expand Up @@ -753,9 +780,12 @@ def mime_data_dict(self) -> Persistence.PersistentDictType:
return {
"type": self.type,
"stroke_color": self.stroke_color,
"stroke_width": self.stroke_width,
"fill_color": self.fill_color,
"label": self.label,
"is_position_locked": self.is_position_locked,
"is_stroke_enabled": self.is_stroke_enabled,
"is_fill_enabled": self.is_fill_enabled,
"is_shape_locked": self.is_shape_locked,
"is_bounds_constrained": self.is_bounds_constrained,
}
Expand All @@ -770,8 +800,11 @@ def write_to_dict(self) -> Persistence.PersistentDictType:

def read_from_mime_data(self, graphic_dict: Persistence.PersistentDictType) -> None:
self.stroke_color = graphic_dict.get("stroke_color", self.stroke_color)
self.stroke_color = graphic_dict.get("stroke_width", self.stroke_width)
self.fill_color = graphic_dict.get("fill_color", self.fill_color)
self.label = graphic_dict.get("label", self.label)
self.is_stroke_enabled = graphic_dict.get("stroke_enabled",self.is_stroke_enabled)
self.is_stroke_enabled = graphic_dict.get("stroke_enabled", self.is_fill_enabled)
self.is_position_locked = graphic_dict.get("is_position_locked", self.is_position_locked)
self.is_shape_locked = graphic_dict.get("is_shape_locked", self.is_shape_locked)
self.is_bounds_constrained = graphic_dict.get("is_bounds_constrained", self.is_bounds_constrained)
Expand Down Expand Up @@ -804,6 +837,11 @@ def used_role(self) -> typing.Optional[str]:

@property
def used_stroke_style(self) -> typing.Optional[str]:
if not self.is_stroke_enabled:
if not self.is_fill_enabled:
return self._default_stroke_color
else:
return None
if self.stroke_color:
return self.stroke_color
if self.used_role == "fourier_mask":
Expand All @@ -814,6 +852,8 @@ def used_stroke_style(self) -> typing.Optional[str]:

@property
def used_fill_style(self) -> typing.Optional[str]:
if not self.is_fill_enabled:
return None
if self.fill_color:
return self.fill_color
if self.used_role == "fourier_mask":
Expand Down Expand Up @@ -1151,7 +1191,7 @@ def _draw(self, ctx: DrawingContextLike, ui_settings: UISettings.UISettings, map
ctx.line_to(center.x, rect.top + 2)
draw_arrow(ctx, Geometry.FloatPoint(y=rect.top + 10, x=center.x), Geometry.FloatPoint(y=rect.top + 2, x=center.x), arrow_size=4)
ctx.close_path()
ctx.line_width = 1
ctx.line_width = self.stroke_width or 1
ctx.stroke_style = self.used_stroke_style
ctx.stroke()
ctx.fill_style = self.used_fill_style
Expand Down Expand Up @@ -1232,10 +1272,11 @@ def _draw(self, ctx: DrawingContextLike, ui_settings: UISettings.UISettings, map
rotation = self.rotation
stroke_style = self.used_stroke_style
fill_style = self.used_fill_style
stroke_width= self.stroke_width or 1
bounds = Geometry.FloatRect.make(self.bounds)
center = mapping.map_point_image_norm_to_widget(bounds.center)
size = mapping.map_size_image_norm_to_widget(bounds.size)
draw_ellipse_graphic(ctx, center, size, rotation, is_selected, stroke_style, fill_style)
draw_ellipse_graphic(ctx, center, size, rotation, is_selected, stroke_style, stroke_width, fill_style)
self.draw_label(ctx, ui_settings, mapping)

def label_position(self, mapping: CoordinateMappingLike, font_metrics: UISettings.FontMetrics, padding: float) -> typing.Optional[Geometry.FloatPoint]:
Expand Down Expand Up @@ -1542,7 +1583,7 @@ def _draw(self, ctx: DrawingContextLike, ui_settings: UISettings.UISettings, map
draw_arrow(ctx, p2, p1)
if self.end_arrow_enabled:
draw_arrow(ctx, p1, p2)
ctx.line_width = 1
ctx.line_width = self.stroke_width or 1
ctx.stroke_style = self.used_stroke_style
ctx.stroke()
if is_selected:
Expand Down Expand Up @@ -1600,7 +1641,7 @@ def _draw(self, ctx: DrawingContextLike, ui_settings: UISettings.UISettings, map
draw_arrow(ctx, p2, p1)
if self.end_arrow_enabled:
draw_arrow(ctx, p1, p2)
ctx.line_width = 1
ctx.line_width = self.stroke_width or 1
ctx.stroke_style = self.used_stroke_style
ctx.stroke()
length = math.sqrt(math.pow(p2[0] - p1[0],2) + math.pow(p2[1] - p1[1], 2))
Expand All @@ -1615,7 +1656,7 @@ def _draw(self, ctx: DrawingContextLike, ui_settings: UISettings.UISettings, map
ctx.line_to(p2[1] - dy * half_width, p2[0] + dx * half_width)
ctx.line_to(p1[1] - dy * half_width, p1[0] + dx * half_width)
ctx.close_path()
ctx.line_width = 1
ctx.line_width = self.stroke_width or 1
ctx.line_dash = 2
ctx.stroke_style = self.used_stroke_style
ctx.stroke()
Expand All @@ -1632,7 +1673,7 @@ def _draw(self, ctx: DrawingContextLike, ui_settings: UISettings.UISettings, map
ctx.line_to(pa[0] - dy * interval_marker_half_width, pa[1] + dx * interval_marker_half_width)
ctx.move_to(pb[0] + dy * interval_marker_half_width, pb[1] - dx * interval_marker_half_width)
ctx.line_to(pb[0] - dy * interval_marker_half_width, pb[1] + dx * interval_marker_half_width)
ctx.line_width = 1
ctx.line_width = self.stroke_width or 1
ctx.stroke_style = color
ctx.stroke()
if is_selected:
Expand Down Expand Up @@ -1758,7 +1799,7 @@ def _draw(self, ctx: DrawingContextLike, ui_settings: UISettings.UISettings, map
ctx.line_to(p.x, p.y - inner_size)
ctx.move_to(p.x, p.y + inner_size)
ctx.line_to(p.x, p.y + cross_hair_size)
ctx.line_width = 1
ctx.line_width = self.stroke_width or 1
ctx.stroke_style = self.used_stroke_style
ctx.stroke()
self.draw_label(ctx, ui_settings, mapping)
Expand Down Expand Up @@ -2150,16 +2191,17 @@ def _draw(self, ctx: DrawingContextLike, ui_settings: UISettings.UISettings, map
stroke_style = self.used_stroke_style
fill_style = self.used_fill_style
rotation = self.rotation
stroke_width = self.stroke_width or 1
bounds = Geometry.FloatRect.make(self.bounds)
origin = mapping.calibrated_origin_widget
center = origin + mapping.map_size_image_norm_to_widget(bounds.center.as_size())
size = mapping.map_size_image_norm_to_widget(bounds.size)
draw_ellipse_graphic(ctx, center, size, rotation, is_selected, stroke_style, fill_style)
draw_ellipse_graphic(ctx, center, size, rotation, is_selected, stroke_style, stroke_width, fill_style)
with ctx.saver():
ctx.translate(origin.x, origin.y)
ctx.rotate(math.pi)
ctx.translate(-origin.x, -origin.y)
draw_ellipse_graphic(ctx, center, size, rotation, is_selected, stroke_style, fill_style)
draw_ellipse_graphic(ctx, center, size, rotation, is_selected, stroke_style, stroke_width, fill_style)
self.draw_label(ctx, ui_settings, mapping)

def label_position(self, mapping: CoordinateMappingLike, font_metrics: UISettings.FontMetrics, padding: float) -> typing.Optional[Geometry.FloatPoint]:
Expand Down Expand Up @@ -2389,7 +2431,7 @@ def draw_mask(sign: float) -> None:
ctx.line_to(corner.x, corner.y)
ctx.line_to(pt2.x, pt2.y)
ctx.close_path()
ctx.line_width = 1
ctx.line_width = self.stroke_width or 1
ctx.stroke_style = self.used_stroke_style
ctx.fill_style = self.used_fill_style
ctx.fill()
Expand Down Expand Up @@ -2553,7 +2595,7 @@ def _draw(self, ctx: DrawingContextLike, ui_settings: UISettings.UISettings, map
radius_1_widget = mapping.map_size_image_norm_to_widget(Geometry.FloatSize(self.radius_1, self.radius_1))
radius_2_widget = mapping.map_size_image_norm_to_widget(Geometry.FloatSize(self.radius_2, self.radius_2))
with ctx.saver():
ctx.line_width = 1
ctx.line_width = self.stroke_width or 1
ctx.stroke_style = self.used_stroke_style
draw_ellipse(ctx, center, Geometry.FloatSize(width=radius_1_widget[1] * 2, height=radius_1_widget[0] * 2), self.used_stroke_style, None)
if is_selected:
Expand All @@ -2562,7 +2604,7 @@ def _draw(self, ctx: DrawingContextLike, ui_settings: UISettings.UISettings, map
draw_marker(ctx, Geometry.FloatPoint(center.y, center.x + radius_1_widget[1]))
draw_marker(ctx, Geometry.FloatPoint(center.y, center.x - radius_1_widget[1]))
if not self.mode == "low-pass" and not self.mode == "high-pass":
ctx.line_width = 1
ctx.line_width = self.stroke_width or 1
ctx.stroke_style = self.used_stroke_style
draw_ellipse(ctx, center, Geometry.FloatSize(width=radius_2_widget[1] * 2, height=radius_2_widget[0] * 2), self.used_stroke_style, None)
if is_selected:
Expand Down Expand Up @@ -2899,7 +2941,7 @@ def _draw(self, ctx: DrawingContextLike, ui_settings: UISettings.UISettings, map
ctx.move_to(start_widget[1], start_widget[0])
ctx.line_to(u_pos_widget[1], u_pos_widget[0])
draw_arrow(ctx, start_widget, u_pos_widget)
ctx.line_width = 1
ctx.line_width = self.stroke_width or 1
ctx.stroke_style = self.used_stroke_style
ctx.stroke()
ctx.fill_style = self.used_fill_style
Expand All @@ -2909,7 +2951,7 @@ def _draw(self, ctx: DrawingContextLike, ui_settings: UISettings.UISettings, map
ctx.move_to(start_widget[1], start_widget[0])
ctx.line_to(v_pos_widget[1], v_pos_widget[0])
draw_arrow(ctx, start_widget, v_pos_widget)
ctx.line_width = 1
ctx.line_width = self.stroke_width or 1
ctx.stroke_style = self.used_stroke_style
ctx.stroke()
ctx.fill_style = self.used_fill_style
Expand All @@ -2928,7 +2970,7 @@ def _draw(self, ctx: DrawingContextLike, ui_settings: UISettings.UISettings, map

bounds = Geometry.FloatRect.from_tlbr(0, 0, 1, 1).inset(-radius, -radius)
with ctx.saver():
ctx.line_width = 1
ctx.line_width = self.stroke_width or 1
ctx.stroke_style = self.used_stroke_style
ctx.fill_style = self.used_fill_style
mx = 0
Expand Down
Loading