diff --git a/src/calng/scenes.py b/src/calng/scenes.py index 19759af3c4ae7e967416e18d670ce25c91f9af87..35273dd41f49c90c6dd0ccedc01f7e483911f64d 100644 --- a/src/calng/scenes.py +++ b/src/calng/scenes.py @@ -35,6 +35,15 @@ _type_to_line_editable = { } +def safe_render(obj, x, y): + if hasattr(obj, "render"): + return obj.render(x, y) + else: + obj.x = x + obj.y = y + return [obj] + + class Align(enum.Enum): CENTER = enum.auto() TOP = enum.auto() @@ -120,13 +129,14 @@ class HorizontalLayout: res = [] for child in self.children: if align is Align.TOP: - res.extend(child.render(x, y)) + y_ = y elif align is Align.CENTER: - res.extend(child.render(x, y + (height - child.height) / 2)) + y_ = y + (height - child.height) / 2 elif align is Align.BOTTOM: - res.extend(child.render(x, y + (height - child.height))) + y_ = y + (height - child.height) else: raise ValueError(f"Invalid align {align} for HorizontalLayout") + res.extend(safe_render(child, x, y)) x += child.width + self.padding return res @@ -156,7 +166,7 @@ class VerticalLayout: def render(self, x, y): res = [] for child in self.children: - res.extend(child.render(x, y)) + res.extend(safe_render(child, x, y)) y += child.height + self.padding return res @@ -260,7 +270,7 @@ class ConstantParameterColumn: self.extra_path_prefix = prefix[: prefix.rfind(".") + 1] else: self.extra_path_prefix = "" - self.device_id = device_id + device_id = device_id self.rows = [ MaybeEditableRow( device_id, @@ -270,7 +280,7 @@ class ConstantParameterColumn: for key in schema_hash.get(prefix).getKeys() ] self.load_button = DisplayCommandModel( - keys=[f"{self.device_id}.{self.extra_path_prefix}loadMostRecentConstants"], + keys=[f"{device_id}.{self.extra_path_prefix}loadMostRecentConstants"], width=10 * BASE_INC, height=BASE_INC, ) @@ -428,30 +438,94 @@ class CorrectionStepsColumn: class ConstantLoadedAmpeln: def __init__(self, device_id, schema_hash, prefix="foundConstants"): - self.keys = [ - f"{device_id}.{prefix}.{key}.found" - for key in schema_hash.get(prefix).getKeys() - ] + self.content = HorizontalLayout( + children=[ + ColorBoolModel( + keys=[f"{device_id}.{prefix}.{key}.found"], + height=BASE_INC, + width=BASE_INC, + ) + for key in schema_hash.get(prefix).getKeys() + ], + padding=0, + ) def render(self, x, y): - return [ - ColorBoolModel( - x=x + i * BASE_INC, - y=y, - height=BASE_INC, - width=BASE_INC, - keys=[key], - ) - for i, key in enumerate(self.keys) - ] + return self.content.render(x, y) @property def width(self): - return BASE_INC * len(self.keys) + return self.content.width @property def height(self): - return BASE_INC + return self.content.height + + +@titled("Manager status", width=6) +@boxed +class ManagerDeviceStatus: + def __init__(self, device_id): + self.name = DisplayLabelModel( + keys=[f"{device_id}.deviceId"], + width=14 * BASE_INC, + height=BASE_INC, + ) + self.state = DisplayStateColorModel( + show_string=True, + keys=[f"{device_id}.state"], + width=7 * BASE_INC, + height=BASE_INC, + ) + self.restart_button = DisplayCommandModel( + keys=[f"{device_id}.restartServers"], + width=7 * BASE_INC, + height=BASE_INC, + ) + self.instantiate_button = DisplayCommandModel( + keys=[f"{device_id}.startInstantiate"], + width=7 * BASE_INC, + height=BASE_INC, + ) + self.apply_button = DisplayCommandModel( + keys=[f"{device_id}.applyManagedValues"], + width=7 * BASE_INC, + height=BASE_INC, + ) + self.status_log = DisplayTextLogModel( + keys=[f"{device_id}.status"], + width=14 * BASE_INC, + height=7 * BASE_INC, + ) + self.content = VerticalLayout( + children=[ + self.name, + HorizontalLayout( + children=[ + self.state, + self.restart_button, + ], + padding=0, + ), + HorizontalLayout( + children=[self.instantiate_button, self.apply_button], + padding=0, + ), + self.status_log, + ], + padding=0, + ) + + def render(self, x, y): + return self.content.render(x, y) + + @property + def width(self): + return self.content.width + + @property + def height(self): + return self.content.height @titled("Device status", width=6) @@ -491,31 +565,30 @@ class CorrectionDeviceStatus: width=14 * BASE_INC, height=20 * BASE_INC, ) + self.content = VerticalLayout( + children=[ + self.name, + HorizontalLayout( + children=[ + self.state, + self.tid, + ], + padding=0, + ), + HorizontalLayout( + children=[ + self.rate, + self.processing_time, + ], + padding=0, + ), + self.status_log, + ], + padding=0, + ) def render(self, x, y): - self.name.x = x - self.name.y = y - y += BASE_INC - self.state.x = x - self.state.y = y - self.tid.x = x + 7 * BASE_INC - self.tid.y = y - y += BASE_INC - self.rate.x = x - self.rate.y = y - self.processing_time.x = x + 7 * BASE_INC - self.processing_time.y = y - y += BASE_INC - self.status_log.x = x - self.status_log.y = y - return [ - self.name, - self.state, - self.rate, - self.processing_time, - self.tid, - self.status_log, - ] + return self.content.render(x, y) @property def width(self): @@ -553,21 +626,19 @@ class CompactCorrectionDeviceOverview: height=BASE_INC, ) self.ampeln = ConstantLoadedAmpeln(device_id, schema_hash) + self.content = HorizontalLayout( + children=[ + self.name, + self.status, + self.rate, + self.tid, + self.ampeln, + ], + padding=0, + ) def render(self, x, y): - self.name.x = x - self.name.y = y - x += self.name.width - self.status.x = x - self.status.y = y - x += self.status.width - self.rate.x = x - self.rate.y = y - x += self.rate.width - self.tid.x = x - self.tid.y = y - x += self.tid.width - return [self.name, self.status, self.rate, self.tid] + self.ampeln.render(x, y) + return self.content.render(x, y) @property def width(self): @@ -618,6 +689,7 @@ def manager_device_overview_scene( children=[ HorizontalLayout( children=[ + ManagerDeviceStatus(manager_device_id), ConstantParameterColumn( manager_device_id, mds_hash, prefix="managed.constantParameters" ),