diff --git a/adl2pydm/output_handler.py b/adl2pydm/output_handler.py index 12b4d3e..e3a0d79 100644 --- a/adl2pydm/output_handler.py +++ b/adl2pydm/output_handler.py @@ -1,5 +1,5 @@ """ -write the screen in the new XML protocol +Write the screen in the new XML protocol. Only rely on packages in the standard Python distribution. (rules out lxml) """ @@ -21,6 +21,8 @@ ENV_PYDM_DISPLAYS_PATH = "PYDM_DISPLAYS_PATH" SCREEN_FILE_EXTENSION = ".ui" DEFAULT_NUMBER_OF_POINTS = 1200 +# TOP_LEVEL_WIDGET = "QWidget" +TOP_LEVEL_WIDGET_CLASS = "PyDMAbsoluteGeometry" logger = logging.getLogger(__name__) @@ -67,9 +69,7 @@ def convertDynamicAttribute_to_Rules(attr): for nm, ref in dict(chan="A", chanB="B", chanC="C", chanD="D").items(): if nm in attr: pv = convertMacros(attr[nm]) - channels[ref] = dict( - channel=f"ca://{pv}", trigger=len(pv) > 0, use_enum=False - ) + channels[ref] = dict(channel=f"ca://{pv}", trigger=len(pv) > 0) calc = attr.get("calc") if calc is not None and len(calc) > 0: @@ -284,7 +284,12 @@ def write_font_size(self, qw, block, **kwargs): smallest = 4 largest = 10 margin = 3 - pointsize = int(max(smallest, min(largest, block.geometry.height - 2 * margin))) + pointsize = int( + max( + smallest, + min(largest, block.geometry.height - 2 * margin) + ) + ) propty = self.writer.writeOpenProperty(qw, "font", stdset="0") font = self.writer.writeOpenTag(propty, "font") @@ -292,8 +297,6 @@ def write_font_size(self, qw, block, **kwargs): def write_ui(self, screen, output_path): """main entry point to write the .ui file""" - window_class = "QWidget" - # window_class = "QMainWindow" title = ( screen.title or os.path.split(os.path.splitext(screen.given_filename)[0])[-1] @@ -308,7 +311,9 @@ def write_ui(self, screen, output_path): root = self.writer.openFile(ui_filename) logging.info("writing screen file: %s", ui_filename) self.writer.writeTaggedString(root, "class", "Dialog") - form = self.writer.writeOpenTag(root, "widget", cls=window_class, name="screen") + form = self.writer.writeOpenTag( + root, "widget", cls=TOP_LEVEL_WIDGET_CLASS, name="screen" + ) self.write_geometry(form, screen.geometry) self.write_stylesheet(form, screen) @@ -1050,6 +1055,8 @@ def write_customwidgets(self, parent): # example: PyDMDrawingPie extends PyDMDrawingArc while True: # do..until additions = [] + if TOP_LEVEL_WIDGET_CLASS not in self.custom_widgets: + self.custom_widgets.append(TOP_LEVEL_WIDGET_CLASS) for widget in self.custom_widgets: if widget == "PyDMDrawingPie": logger.debug("breakpoint") diff --git a/adl2pydm/symbols.py b/adl2pydm/symbols.py index 10c950f..fc4a53e 100644 --- a/adl2pydm/symbols.py +++ b/adl2pydm/symbols.py @@ -60,7 +60,8 @@ "byte": dict(type="monitor", pydm_widget="PyDMByteIndicator"), "cartesian plot": dict(type="monitor", pydm_widget="PyDMWaveformPlot"), "choice button": dict(type="controller", pydm_widget="PyDMEnumButton"), - "composite": dict(type="static", pydm_widget="PyDMFrame"), + # "composite": dict(type="static", pydm_widget="PyDMFrame"), + "composite": dict(type="static", pydm_widget="PyDMAbsoluteGeometry"), "embedded display": dict(type="static", pydm_widget="PyDMEmbeddedDisplay"), "image": dict(type="monitor", pydm_widget="PyDMDrawingImage"), "indicator": dict(type="monitor", pydm_widget="PyDMScaleIndicator"), @@ -94,6 +95,9 @@ """ pydm_widgets = dict( + PyDMAbsoluteGeometry=PyDM_CustomWidget( + "PyDMAbsoluteGeometry", "QWidget", "pydm.widgets.absolute_geometry" + ), PyDMTabWidget=PyDM_CustomWidget( "PyDMTabWidget", "QTabWidget", "pydm.widgets.tab_bar" ), diff --git a/adl2pydm/tests/_core.py b/adl2pydm/tests/_core.py index 9e0b1db..71e5e43 100644 --- a/adl2pydm/tests/_core.py +++ b/adl2pydm/tests/_core.py @@ -313,7 +313,7 @@ def assertExpectedDictInRef(ref, doc=None, **kwargs): assert isinstance(kwargs, dict), doc for k, v in kwargs.items(): assert k in ref, f"{doc}, k={k}, v={v}" - assert v == ref[k], f"{doc}, k={k}, v={v}" + assert v == ref[k], f"{doc}, k={k}, v={v}, ref[k]={ref[k]}" def assertGreater(a, b, doc=None): diff --git a/adl2pydm/tests/medm/motorxU.adl b/adl2pydm/tests/medm/motorxU.adl new file mode 100644 index 0000000..210ec52 --- /dev/null +++ b/adl2pydm/tests/medm/motorxU.adl @@ -0,0 +1,721 @@ + +file { + name="/tmp/motor/motorApp/op/adl/motorxU.adl" + version=030114 +} +display { + object { + x=550 + y=29 + width=176 + height=282 + } + clr=14 + bclr=3 + cmap="" + gridSpacing=5 + gridOn=0 + snapToGrid=0 +} +"color map" { + ncolors=65 + colors { + ffffff, + ececec, + dadada, + c8c8c8, + bbbbbb, + aeaeae, + 9e9e9e, + 919191, + 858585, + 787878, + 696969, + 5a5a5a, + 464646, + 2d2d2d, + 000000, + 00d800, + 1ebb00, + 339900, + 2d7f00, + 216c00, + fd0000, + de1309, + be190b, + a01207, + 820400, + 5893ff, + 597ee1, + 4b6ec7, + 3a5eab, + 27548d, + fbf34a, + f9da3c, + eeb62b, + e19015, + cd6100, + ffb0ff, + d67fe2, + ae4ebc, + 8b1a96, + 610a75, + a4aaff, + 8793e2, + 6a73c1, + 4d52a4, + 343386, + c7bb6d, + b79d5c, + a47e3c, + 7d5627, + 58340f, + 99ffff, + 73dfff, + 4ea5f9, + 2a63e4, + 0a00b8, + ebf1b5, + d4db9d, + bbc187, + a6a462, + 8b8239, + 73ff6b, + 52da3b, + 3cb420, + 289315, + 1a7309, + } +} +rectangle { + object { + x=4 + y=130 + width=165 + height=40 + } + "basic attribute" { + clr=14 + width=3 + } +} +"message button" { + object { + x=5 + y=257 + width=170 + height=24 + } + control { + chan="$(P)$(M).STOP" + clr=31 + bclr=20 + } + label="STOP" + press_msg="1" +} +"related display" { + object { + x=4 + y=236 + width=55 + height=18 + } + display[0] { + label="$(M) (Tiny)" + name="motorx_tiny.adl" + args="P=$(P),M=$(M)" + } + display[1] { + label="$(M) (Help)" + name="motorx_help.adl" + args="P=$(P),M=$(M)" + } + display[2] { + label="$(M) (Medium)" + name="motorx_more.adl" + args="P=$(P),M=$(M)" + } + display[3] { + label="$(M) (Setup)" + name="motorx_setup.adl" + args="P=$(P),M=$(M)" + } + display[4] { + label="Scan Parameters" + name="scanParms.adl" + args="P=$(P),Q=$(M),PV=$(M)" + } + display[5] { + label="$(M) (Debug)" + name="motorx_all.adl" + args="P=$(P),M=$(M)" + } + clr=14 + bclr=51 + label="-more" +} +"message button" { + object { + x=62 + y=236 + width=55 + height=18 + } + control { + chan="$(P)$(M).SSET" + clr=14 + bclr=51 + } + label="redefine" + press_msg="1" +} +"message button" { + object { + x=118 + y=236 + width=55 + height=18 + } + control { + chan="$(P)$(M).SUSE" + clr=14 + bclr=51 + } + label="operate" + press_msg="1" +} +rectangle { + object { + x=60 + y=234 + width=115 + height=22 + } + "basic attribute" { + clr=30 + fill="outline" + width=2 + } + "dynamic attribute" { + vis="if not zero" + chan="$(P)$(M).SET" + } +} +rectangle { + object { + x=0 + y=198 + width=174 + height=34 + } + "basic attribute" { + clr=39 + } +} +"text update" { + object { + x=4 + y=202 + width=64 + height=9 + } + monitor { + chan="$(P)$(M).VELO" + clr=1 + bclr=39 + } + align="horiz. centered" + limits { + } +} +text { + object { + x=148 + y=202 + width=20 + height=9 + } + "basic attribute" { + clr=1 + } + textix="/s" +} +"message button" { + object { + x=3 + y=215 + width=80 + height=14 + } + control { + chan="$(P)$(M)_vCh.A" + clr=1 + bclr=38 + } + label="speed x0.1" + press_msg="0.1" +} +"message button" { + object { + x=90 + y=215 + width=80 + height=14 + } + control { + chan="$(P)$(M)_vCh.A" + clr=1 + bclr=38 + } + label="speed x10" + press_msg="10" +} +"text update" { + object { + x=83 + y=202 + width=64 + height=9 + } + monitor { + chan="$(P)$(M).EGU" + clr=1 + bclr=39 + } + align="horiz. right" + format="compact" + limits { + } +} +rectangle { + object { + x=0 + y=126 + width=174 + height=70 + } + "basic attribute" { + clr=46 + } +} +"message button" { + object { + x=3 + y=174 + width=80 + height=20 + } + control { + chan="$(P)$(M)_twCh.A" + clr=14 + bclr=45 + } + label="x0.1" + press_msg="0.1" +} +"message button" { + object { + x=90 + y=174 + width=80 + height=20 + } + control { + chan="$(P)$(M)_twCh.A" + clr=14 + bclr=45 + } + label="x10" + press_msg="10" +} +"message button" { + object { + x=6 + y=132 + width=25 + height=36 + } + control { + chan="$(P)$(M).TWR" + clr=14 + bclr=51 + } + label="-" + press_msg="1" +} +"message button" { + object { + x=141 + y=132 + width=25 + height=36 + } + control { + chan="$(P)$(M).TWF" + clr=14 + bclr=51 + } + label="+" + press_msg="1" +} +text { + object { + x=43 + y=154 + width=84 + height=15 + } + "basic attribute" { + clr=60 + fill="outline" + } + "dynamic attribute" { + vis="if zero" + chan="$(P)$(M).DMOV" + } + textix="Moving" + align="horiz. centered" +} +text { + object { + x=43 + y=160 + width=84 + height=10 + } + "basic attribute" { + clr=30 + fill="outline" + } + "dynamic attribute" { + vis="if not zero" + chan="$(P)$(M).SET" + } + textix="redefine" + align="horiz. centered" +} +"text entry" { + object { + x=36 + y=132 + width=100 + height=20 + } + control { + chan="$(P)$(M).TWV" + clr=14 + bclr=51 + } + limits { + } +} +text { + object { + x=43 + y=152 + width=84 + height=10 + } + "basic attribute" { + clr=30 + fill="outline" + } + "dynamic attribute" { + vis="if not zero" + chan="$(P)$(M).LVIO" + } + textix="Soft limit" + align="horiz. centered" +} +"text update" { + object { + x=5 + y=0 + width=170 + height=20 + } + monitor { + chan="$(P)$(M).DESC" + clr=54 + bclr=0 + } + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=5 + y=32 + width=170 + height=12 + } + monitor { + chan="$(P)$(M).EGU" + clr=54 + bclr=3 + } + align="horiz. centered" + limits { + } +} +rectangle { + object { + x=5 + y=20 + width=170 + height=12 + } + "basic attribute" { + clr=54 + width=2 + } +} +text { + object { + x=5 + y=21 + width=170 + height=10 + } + "basic attribute" { + clr=0 + fill="outline" + } + textix="($(P)$(M))" + align="horiz. centered" +} +rectangle { + object { + x=164 + y=44 + width=6 + height=78 + } + "basic attribute" { + clr=20 + } + "dynamic attribute" { + vis="if not zero" + chan="$(P)$(M).HLS" + } +} +rectangle { + object { + x=5 + y=44 + width=6 + height=78 + } + "basic attribute" { + clr=20 + } + "dynamic attribute" { + vis="if not zero" + chan="$(P)$(M).LLS" + } +} +rectangle { + object { + x=11 + y=81 + width=154 + height=31 + } + "basic attribute" { + clr=60 + width=2 + } + "dynamic attribute" { + vis="if zero" + chan="$(P)$(M).DMOV" + } +} +rectangle { + object { + x=11 + y=81 + width=154 + height=31 + } + "basic attribute" { + clr=30 + width=2 + } + "dynamic attribute" { + vis="if not zero" + chan="$(P)$(M).LVIO" + } +} +rectangle { + object { + x=11 + y=81 + width=154 + height=31 + } + "basic attribute" { + clr=14 + width=2 + } + "dynamic attribute" { + vis="if not zero" + chan="$(P)$(M)_able.VAL" + } +} +"text entry" { + object { + x=16 + y=84 + width=145 + height=25 + } + control { + chan="$(P)$(M).VAL" + clr=14 + bclr=51 + } + limits { + } +} +rectangle { + object { + x=13 + y=56 + width=151 + height=26 + } + "basic attribute" { + clr=14 + fill="outline" + width=2 + } + "dynamic attribute" { + vis="if not zero" + chan="$(P)$(M).SET" + } +} +rectangle { + object { + x=17 + y=58 + width=142 + height=22 + } + "basic attribute" { + clr=30 + fill="outline" + width=2 + } + "dynamic attribute" { + vis="calc" + calc="A!=0||B==7" + chan="$(P)$(M).SET" + chanB="$(P)$(M).STAT" + } +} +"text update" { + object { + x=19 + y=60 + width=139 + height=18 + } + monitor { + chan="$(P)$(M).RBV" + clr=54 + bclr=1 + } + align="horiz. centered" + limits { + } +} +rectangle { + object { + x=11 + y=81 + width=154 + height=31 + } + "basic attribute" { + clr=20 + style="dash" + fill="outline" + width=2 + } + "dynamic attribute" { + vis="if not zero" + chan="$(P)$(M)_able.VAL" + } +} +"text update" { + object { + x=13 + y=44 + width=149 + height=12 + } + monitor { + chan="$(P)$(M).HLM" + clr=4 + bclr=54 + } + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=13 + y=112 + width=149 + height=12 + } + monitor { + chan="$(P)$(M).LLM" + clr=4 + bclr=54 + } + align="horiz. centered" + limits { + } +} +text { + object { + x=43 + y=152 + width=84 + height=10 + } + "basic attribute" { + clr=30 + fill="outline" + } + "dynamic attribute" { + vis="calc" + calc="A==7" + chan="$(P)$(M).STAT" + } + textix="Controller" + align="horiz. centered" +} +text { + object { + x=43 + y=160 + width=84 + height=10 + } + "basic attribute" { + clr=30 + fill="outline" + } + "dynamic attribute" { + vis="calc" + calc="A==7" + chan="$(P)$(M).STAT" + } + textix="Error" + align="horiz. centered" +} diff --git a/adl2pydm/tests/test_output_handler.py b/adl2pydm/tests/test_output_handler.py index caeecb5..e243e11 100644 --- a/adl2pydm/tests/test_output_handler.py +++ b/adl2pydm/tests/test_output_handler.py @@ -20,6 +20,27 @@ def test_write_all_example_files_process(test_file, tempdir): assert os.path.exists(full_uiname), uiname +@pytest.mark.parametrize("test_file", _core.ALL_EXAMPLE_FILES) +def test_write_top_level_widget(test_file, tempdir): + uiname = _core.convertAdlFile("table_setup_SRI.adl", tempdir) + full_uiname = os.path.join(tempdir, uiname) + root = ElementTree.parse(full_uiname).getroot() + + widgets = _core.getSubElement(root, "widget") + assert len(widgets) > 0 + widget_classes = [ + w.attrib.get("class") + for w in widgets + if w.attrib.get("class") is not None + ] + assert output_handler.TOP_LEVEL_WIDGET_CLASS in widget_classes + + customwidgets = _core.getSubElement(root, "customwidgets") + widgets = customwidgets.findall("customwidget") + customs = [_core.getSubElement(w, "class").text for w in widgets] + assert output_handler.TOP_LEVEL_WIDGET_CLASS in customs + + def test_write_extends_customwidget(tempdir): uiname = _core.convertAdlFile("table_setup_SRI.adl", tempdir) full_uiname = os.path.join(tempdir, uiname) @@ -32,6 +53,7 @@ def test_write_extends_customwidget(tempdir): customs = [_core.getSubElement(w, "class").text for w in widgets] assert "PyDMDrawingPie" in customs assert "PyDMDrawingArc" in customs + assert output_handler.TOP_LEVEL_WIDGET_CLASS in customs def test_write_widget_arc(tempdir): @@ -240,7 +262,8 @@ def test_write_widget_composite(tempdir): key = "composite" widget = _core.getNamedWidget(screen, key) - _core.assertEqualClassName(widget, "PyDMFrame", key) + # _core.assertEqualClassName(widget, "PyDMFrame", key) + _core.assertEqualClassName(widget, output_handler.TOP_LEVEL_WIDGET_CLASS, key) _core.assertEqual(len(widget), 6) @@ -420,7 +443,7 @@ def test_write_widget_oval(tempdir): expected = { "name": "visibility", "property": "Visible", - "channels": [{"channel": "ca://demo:bar_RBV", "trigger": True, "use_enum": False}], + "channels": [{"channel": "ca://demo:bar_RBV", "trigger": True}], "expression": "ch[0]>128", } _core.assertEqualRules(w, expected) @@ -428,7 +451,7 @@ def test_write_widget_oval(tempdir): expected = { "name": "visibility", "property": "Visible", - "channels": [{"channel": "ca://demo:bar", "trigger": True, "use_enum": False}], + "channels": [{"channel": "ca://demo:bar", "trigger": True}], "expression": "ch[0]==0", } _core.assertEqualRules(w, expected) @@ -492,7 +515,7 @@ def test_write_widget_polyline_with_rules(tempdir): expected = { "name": "visibility", "property": "Visible", - "channels": [{"channel": "ca://PYDM:visible", "trigger": True, "use_enum": False}], + "channels": [{"channel": "ca://PYDM:visible", "trigger": True}], "expression": "ch[0]!=0", } _core.assertEqualRules(widget, expected) @@ -513,15 +536,17 @@ def test_write_widget_rectangle(tempdir): _core.assertEqual(len(root), 3) screen = _core.getSubElement(root, "widget") - _core.assertEqualClassName(screen, "QWidget", "screen") + _core.assertEqualClassName( + screen, output_handler.TOP_LEVEL_WIDGET_CLASS, "screen" + ) properties = screen.findall("property") _core.assertEqual(len(properties), 3) _core.assertEqualGeometry(screen, 96, 57, 142, 182) expected = ( - "QWidget#screen {\n" - " color: rgb(0, 0, 0);\n" - " background-color: rgb(133, 133, 133);\n" - " }" + f"{output_handler.TOP_LEVEL_WIDGET_CLASS}#screen" + " {\n color: rgb(0, 0, 0);" + "\n background-color: rgb(133, 133, 133);" + "\n }" ) _core.assertEqualStyleSheet(screen, expected) @@ -586,7 +611,7 @@ def test_write_widget_rectangle(tempdir): "name": "visibility", "property": "Visible", "channels": [ - {"channel": "ca://${P}alldone", "trigger": True, "use_enum": False} + {"channel": "ca://${P}alldone", "trigger": True} ], "expression": "ch[0]==0", } @@ -609,8 +634,8 @@ def test_write_widget_rectangle(tempdir): "name": "visibility", "property": "Visible", "channels": [ - {"channel": "ca://${P}${M}.RBV", "trigger": True, "use_enum": False}, - {"channel": "ca://${P}${M}.VAL", "trigger": True, "use_enum": False}, + {"channel": "ca://${P}${M}.RBV", "trigger": True}, + {"channel": "ca://${P}${M}.VAL", "trigger": True}, ], "expression": "ch[0]==ch[1]", } diff --git a/adl2pydm/tests/test_symbols.py b/adl2pydm/tests/test_symbols.py index fdb995b..1377754 100644 --- a/adl2pydm/tests/test_symbols.py +++ b/adl2pydm/tests/test_symbols.py @@ -6,7 +6,7 @@ "widget_set, length", [ [symbols.adl_widgets, 24], - [symbols.pydm_widgets, 34], + [symbols.pydm_widgets, 35], ] ) def test_symbols_dict(widget_set, length):