Skip to content

Commit

Permalink
Added an image widget
Browse files Browse the repository at this point in the history
Also added progress bar options, and
made it so that if a widget has a height
or width field then it will stretch the group.
In a future PR we should make it so that height and
width are set on the widgets.
  • Loading branch information
evalott100 committed Jan 29, 2024
1 parent 364d632 commit 349a304
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 7 deletions.
80 changes: 80 additions & 0 deletions schemas/pvi.device.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@
"title": "CheckBox",
"type": "object"
},
"ColorMode": {
"const": 3,
"description": "The `color_mode` to use, not to be confused with the `color_map`.\nOther modes have strange results right now.",
"title": "ColorMode"
},
"ComboBox": {
"additionalProperties": false,
"description": "Selection of an enum PV",
Expand Down Expand Up @@ -300,6 +305,61 @@
"const": "ImageRead",
"default": "ImageRead",
"title": "Type"
},
"height": {
"default": 300,
"description": "Height of widget",
"exclusiveMinimum": 0,
"title": "Height",
"type": "integer"
},
"width": {
"default": 300,
"description": "Width of widget",
"exclusiveMinimum": 0,
"title": "Width",
"type": "integer"
},
"color_mode": {
"allOf": [
{
"$ref": "#/$defs/ColorMode"
}
],
"default": 3,
"description": "Color map to use for the image"
},
"use_unsigned_data": {
"default": true,
"description": "If true then the image uses unsigned pixel values",
"title": "Use Unsigned Data",
"type": "boolean"
},
"data_height": {
"default": 300,
"description": "Number of height pixels in the image",
"exclusiveMinimum": 0,
"title": "Data Height",
"type": "integer"
},
"data_width": {
"default": 300,
"description": "Number of width pixels in the image",
"exclusiveMinimum": 0,
"title": "Data Width",
"type": "integer"
},
"show_axes": {
"default": true,
"description": "Show axes on the image",
"title": "Show Axes",
"type": "boolean"
},
"show_colorbar": {
"default": false,
"description": "Show colorbar on the image",
"title": "Show Colorbar",
"type": "boolean"
}
},
"title": "ImageRead",
Expand Down Expand Up @@ -338,6 +398,26 @@
"const": "ProgressBar",
"default": "ProgressBar",
"title": "Type"
},
"use_pv_limits": {
"default": false,
"description": "Use PV limits, if True then maximum and minumum are ignored",
"title": "Use Pv Limits",
"type": "boolean"
},
"minimum": {
"default": 0.0,
"description": "Lower limit of progress bar",
"exclusiveMinimum": 0.0,
"title": "Minimum",
"type": "number"
},
"maximum": {
"default": 1.0,
"description": "Upper limit of progress bar",
"exclusiveMinimum": 0.0,
"title": "Maximum",
"type": "number"
}
},
"title": "ProgressBar",
Expand Down
4 changes: 3 additions & 1 deletion src/pvi/_format/adl.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ def set(
case TextWrite(format=format) | TextRead(format=format) if (
is_text_widget(template) and format is not None
):
template = add_property(template, "format", ADL_TEXT_FORMATS[format])
template = add_property(
template, "format", ADL_TEXT_FORMATS[TextFormat(format)]
)

return template

Expand Down
70 changes: 68 additions & 2 deletions src/pvi/_format/bob.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
from pvi.device import (
LED,
BitField,
ColorMode,
ComboBox,
ImageRead,
ProgressBar,
TableRead,
TableWidgetType,
TableWrite,
Expand Down Expand Up @@ -50,9 +53,15 @@ def set(
properties["y"] = bounds.y
if isinstance(widget, BitField):
properties["width"] = widget.number_of_bits * 20
bounds.w = properties["width"]
elif isinstance(widget, ImageRead):
properties["width"] = widget.width
properties["height"] = widget.height
bounds.w = widget.width
bounds.h = widget.height
else:
properties["height"] = bounds.h
properties["width"] = bounds.w
properties["height"] = bounds.h

widget_type = template.attrib.get("type", "")

Expand Down Expand Up @@ -86,9 +95,24 @@ def set(
("textentry", TextWrite(format=format))
| ("textupdate", TextRead(format=format))
) if format is not None:
add_format(t_copy, BOB_TEXT_FORMATS[format])
add_format(t_copy, BOB_TEXT_FORMATS[TextFormat(format)])
case ("byte_monitor", BitField()):
add_byte_number_of_bits(t_copy, widget.number_of_bits)
case ("image", ImageRead()):
add_data_height_and_width(t_copy, widget.data_height, widget.data_width)
add_color_mode_to_image(t_copy, widget.color_mode)
add_unsigned_to_image(t_copy, widget.use_unsigned_data)
add_axis_and_colorbar(
t_copy,
widget.show_axes,
widget.show_colorbar,
widget.data_height,
widget.data_width,
)
case ("progressbar", ProgressBar()):
add_minimum_and_maximum_progressbar(
t_copy, widget.use_pv_limits, widget.minimum, widget.maximum
)

return t_copy

Expand Down Expand Up @@ -217,6 +241,48 @@ def add_byte_number_of_bits(element: ElementBase, number_of_bits: int):
SubElement(element, "numBits").text = str(number_of_bits)


def add_data_height_and_width(element: ElementBase, data_height: int, data_width: int):
SubElement(element, "data_height").text = str(data_height)
SubElement(element, "data_width").text = str(data_width)


def add_color_mode_to_image(element: ElementBase, color_mode: ColorMode):
SubElement(element, "color_mode").text = str(color_mode.value)


def add_unsigned_to_image(element: ElementBase, use_unsigned_data: bool):
SubElement(element, "unsigned").text = "true" if use_unsigned_data else "false"


def add_axis_and_colorbar(
element: ElementBase,
show_axes: bool,
show_colorbar: bool,
data_height: int,
data_width: int,
):
SubElement(SubElement(element, "color_bar"), "visible").text = (
"true" if show_colorbar else "false"
)
x_axis = SubElement(element, "x_axis")
SubElement(x_axis, "visible").text = "true" if show_axes else "false"
SubElement(x_axis, "minimum").text = "0.0"
SubElement(x_axis, "maximum").text = str(float(data_width))

y_axis = SubElement(element, "y_axis")
SubElement(y_axis, "visible").text = "true" if show_axes else "false"
SubElement(y_axis, "minimum").text = "0.0"
SubElement(y_axis, "maximum").text = str(float(data_height))


def add_minimum_and_maximum_progressbar(
element: ElementBase, use_pv_limits: bool, minimum: float, maximum: float
):
SubElement(element, "limits_from_pv").text = "true" if use_pv_limits else "false"
SubElement(element, "minimum").text = str(minimum)
SubElement(element, "maximum").text = str(maximum)


def find_element(root_element: ElementBase, tag: str, index: int = 0) -> ElementBase:
"""Iterate tree to find tag and replace text.
Expand Down
3 changes: 2 additions & 1 deletion src/pvi/_format/dls.bob
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@
</widget>
<widget type="table" version="2.0.0">
<name>Table</name>
<pv_name>Table</pv_name>
<pv_name>pva://Table</pv_name>
<x>671</x>
<y>670</y>
<width>200</width>
Expand Down Expand Up @@ -224,5 +224,6 @@
<x>566</x>
<y>48</y>
<width>300</width>
<height>301</height>
</widget>
</display>
2 changes: 1 addition & 1 deletion src/pvi/_format/edl.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def set(
is_text_widget(template) and format is not None
):
template = add_property(
template, "displayMode", EDL_TEXT_FORMATS[format]
template, "displayMode", EDL_TEXT_FORMATS[TextFormat(format)]
)

return template
Expand Down
5 changes: 5 additions & 0 deletions src/pvi/_format/screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,11 @@ def generate_component_formatters(
add_label = False # Do not add row labels for Tables
component_bounds.w = 100 * len(c.widget.widgets)
component_bounds.h *= 10 # TODO: How do we know the number of rows?
elif hasattr(c, "widget"):
if hasattr(c.widget, "height"):
component_bounds.h = c.widget.height + self.layout.spacing
if hasattr(c.widget, "width"):
component_bounds.w = c.widget.width + self.layout.spacing

if add_label:
# Insert label and reduce width for widget
Expand Down
34 changes: 32 additions & 2 deletions src/pvi/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import json
import re
from enum import IntEnum
from enum import Enum
from pathlib import Path
from typing import (
Annotated,
Expand Down Expand Up @@ -60,7 +60,7 @@ def enforce_pascal_case(s: str) -> str:
return s[0].upper() + s[1:]


class TextFormat(IntEnum):
class TextFormat(Enum):
"""Format to use for display of Text{Read,Write} widgets on a UI"""

decimal = 0
Expand Down Expand Up @@ -97,6 +97,12 @@ class ProgressBar(ReadWidget):
"""Progress bar from lower to upper limit of a float PV"""

type: Literal["ProgressBar"] = "ProgressBar"
use_pv_limits: bool = Field(
default=False,
description="Use PV limits, if True then maximum and minumum are ignored",
)
minimum: float = Field(default=0.0, description="Lower limit of progress bar", gt=0)
maximum: float = Field(default=1.0, description="Upper limit of progress bar", gt=0)


class TextRead(ReadWidget):
Expand Down Expand Up @@ -136,11 +142,35 @@ class TableRead(ReadWidget):
)


class ColorMode(Enum):
"""The `color_mode` to use, not to be confused with the `color_map`.
Other modes have strange results right now."""

RBG = 3


class ImageRead(ReadWidget):
"""2D Image view of an NTNDArray"""

type: Literal["ImageRead"] = "ImageRead"

height: int = Field(default=300, description="Height of widget", gt=0)
width: int = Field(default=300, description="Width of widget", gt=0)
color_mode: ColorMode = Field(
default=ColorMode.RBG, description="Color map to use for the image"
)
use_unsigned_data: bool = Field(
default=True, description="If true then the image uses unsigned pixel values"
)
data_height: int = Field(
default=300, description="Number of height pixels in the image", gt=0
)
data_width: int = Field(
default=300, description="Number of width pixels in the image", gt=0
)
show_axes: bool = Field(default=True, description="Show axes on the image")
show_colorbar: bool = Field(default=False, description="Show colorbar on the image")


class WriteWidget(BaseSettings):
"""Widget that controls a PV"""
Expand Down
3 changes: 3 additions & 0 deletions tests/format/output/mixedWidgets.bob
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,9 @@
<y>144</y>
<width>124</width>
<height>20</height>
<limits_from_pv>false</limits_from_pv>
<minimum>0.0</minimum>
<maximum>1.0</maximum>
</widget>
</widget>
</display>

0 comments on commit 349a304

Please sign in to comment.