diff --git a/negstation/README.md b/negstation/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/negstation/image_pipeline.py b/negstation/image_pipeline.py index 95e0b11..bd36724 100644 --- a/negstation/image_pipeline.py +++ b/negstation/image_pipeline.py @@ -11,6 +11,16 @@ class ImagePipeline: self.stagedata = {} self.stagedata_full = {} + def load_stages(self, stages:dict): + self.stages = stages + self.stagedata.clear() + self.stagedata_full.clear() + self.id_counter = len(stages) + for id, stage in self.stages.items(): + print(id, stage) + self.stagedata[id] = None + self.stagedata_full[id] = None + def register_stage(self, name: str): self.stages[self.id_counter] = name self.stagedata[self.id_counter] = None @@ -37,13 +47,19 @@ class ImagePipeline: "pipeline_stage", (id, self.stagedata[id])) def get_stage_data(self, id: int): - if id >= 0 and id < len(self.stages): + if id in self.stagedata: return self.stagedata[id] else: return None + + def get_stage_data_full(self, id: int): + if id in self.stagedata_full: + return self.stagedata_full[id] + else: + return None def get_stage_name(self, id: int): - if id >= 0 and id < len(self.stages): + if id in self.stages: return self.stages[id] else: return None diff --git a/negstation/layout_manager.py b/negstation/layout_manager.py index 095e758..6509c04 100644 --- a/negstation/layout_manager.py +++ b/negstation/layout_manager.py @@ -20,12 +20,15 @@ class LayoutManager: def save_layout(self): self.logger.info("Saving layout...") dpg.save_init_file(self.INI_PATH) - widget_data = [ - {"widget_type": type(w).__name__, "config": w.get_config()} - for w in self.manager.widgets - ] + layout_data = { + "pipeline_order" : { k:v for k, v in self.manager.pipeline.stages.items() }, + "widgets": [ + {"widget_type": type(w).__name__, "config": w.get_config()} + for w in self.manager.widgets + ] + } with open(self.WIDGET_DATA_PATH, "w") as f: - json.dump(widget_data, f, indent=4) + json.dump(layout_data, f, indent=4) self.logger.info("Layout saved successfully.") def load_layout(self): @@ -33,10 +36,17 @@ class LayoutManager: if not os.path.exists(self.WIDGET_DATA_PATH): return with open(self.WIDGET_DATA_PATH, "r") as f: - widget_data = json.load(f) + layout_data = json.load(f) + + # Load all widgets + widget_data = layout_data["widgets"] for data in widget_data: if data.get("widget_type") in self.manager.widget_classes: - self.manager._add_widget(widget_type=data.get("widget_type")) + self.manager._add_widget(widget_type=data.get("widget_type"), config=data.get("config")) + + # Reset the image pipeline and reload it + pipelinestages = { int(k):v for k, v in layout_data["pipeline_order"].items() } + self.manager.pipeline.load_stages(pipelinestages) if os.path.exists(self.INI_PATH): dpg.configure_app(init_file=self.INI_PATH) diff --git a/negstation/negstation.py b/negstation/negstation.py index f3be9bc..9e170f7 100644 --- a/negstation/negstation.py +++ b/negstation/negstation.py @@ -74,12 +74,13 @@ class EditorManager: f"Widget '{name}' is already registered. Overwriting.") self.widget_classes[name] = widget_class - def _add_widget(self, widget_type: str): + def _add_widget(self, widget_type: str, config:dict = {}): WidgetClass = self.widget_classes[widget_type] instance = WidgetClass(self, logger) logger.info(f'Created instance: {str(instance)}') self.widgets.append(instance) instance.create() + instance.set_config(config) def setup(self): self._discover_and_register_widgets( diff --git a/negstation/widgets/base_widget.py b/negstation/widgets/base_widget.py index 3d16df2..e1fe6eb 100644 --- a/negstation/widgets/base_widget.py +++ b/negstation/widgets/base_widget.py @@ -63,6 +63,10 @@ class BaseWidget: def get_config(self): """Caled by negstation itself, returns the saved widget config""" return self.config + + def set_config(self, config): + """Called by negstation itself but can be overridden by a widget""" + self.config = config # Callbacks diff --git a/negstation/widgets/open_raw_widget.py b/negstation/widgets/open_raw_widget.py index 4e9d14a..5356b7c 100644 --- a/negstation/widgets/open_raw_widget.py +++ b/negstation/widgets/open_raw_widget.py @@ -21,7 +21,7 @@ class OpenRawWidget(PipelineStageWidget): self.raw_path = None self.img = None self.img_full = None - self.config = { + self.rawconfig = { # Demosaic algorithm "demosaic_algorithm": rawpy.DemosaicAlgorithm.AHD, # Output color space @@ -45,9 +45,6 @@ class OpenRawWidget(PipelineStageWidget): self.manager.bus.subscribe( "process_full_res", self._on_process_full_res, True) - def get_config(self): - return {} - def create_pipeline_stage_content(self): with dpg.file_dialog( directory_selector=False, @@ -73,79 +70,79 @@ class OpenRawWidget(PipelineStageWidget): label="Demosaic", items=[alg.name for alg in rawpy.DemosaicAlgorithm], default_value=rawpy.DemosaicAlgorithm.AHD.name, - callback=lambda s, a, u: self.config.__setitem__( + callback=lambda s, a, u: self.rawconfig.__setitem__( "demosaic_algorithm", rawpy.DemosaicAlgorithm[a]) ) dpg.add_combo( label="Color Space", items=[cs.name for cs in rawpy.ColorSpace], default_value=rawpy.ColorSpace.sRGB.name, - callback=lambda s, a, u: self.config.__setitem__( + callback=lambda s, a, u: self.rawconfig.__setitem__( "output_color", rawpy.ColorSpace[a]) ) dpg.add_combo( label="Output Bits", items=["8", "16"], default_value="16", - callback=lambda s, a, u: self.config.__setitem__( + callback=lambda s, a, u: self.rawconfig.__setitem__( "output_bps", int(a)) ) dpg.add_checkbox( label="Use Camera WB", default_value=True, - callback=lambda s, a, u: self.config.__setitem__( + callback=lambda s, a, u: self.rawconfig.__setitem__( "use_camera_wb", a) ) dpg.add_checkbox( label="Auto WB", default_value=False, - callback=lambda s, a, u: self.config.__setitem__( + callback=lambda s, a, u: self.rawconfig.__setitem__( "use_auto_wb", a) ) dpg.add_slider_float( label="Manual WB R Gain", default_value=1.0, min_value=0.1, max_value=4.0, callback=lambda s, a, u: self.config.__setitem__( - "user_wb", (a, self.config["user_wb"][1], self.config["user_wb"][2], self.config["user_wb"][3])) + "user_wb", (a, self.rawconfig["user_wb"][1], self.rawconfig["user_wb"][2], self.rawconfig["user_wb"][3])) ) dpg.add_slider_float( label="Manual WB G Gain", default_value=1.0, min_value=0.1, max_value=4.0, callback=lambda s, a, u: self.config.__setitem__( - "user_wb", (self.config["user_wb"][0], a, a, self.config["user_wb"][3])) + "user_wb", (self.rawconfig["user_wb"][0], a, a, self.rawconfig["user_wb"][3])) ) dpg.add_slider_float( label="Manual WB B Gain", default_value=1.0, min_value=0.1, max_value=4.0, callback=lambda s, a, u: self.config.__setitem__( - "user_wb", (self.config["user_wb"][0], self.config["user_wb"][1], self.config["user_wb"][2], a)) + "user_wb", (self.rawconfig["user_wb"][0], self.rawconfig["user_wb"][1], self.rawconfig["user_wb"][2], a)) ) dpg.add_slider_float( label="Bright", default_value=1.0, min_value=0.1, max_value=4.0, - callback=lambda s, a, u: self.config.__setitem__("bright", a) + callback=lambda s, a, u: self.rawconfig.__setitem__("bright", a) ) dpg.add_checkbox( label="No Auto Bright", default_value=False, - callback=lambda s, a, u: self.config.__setitem__( + callback=lambda s, a, u: self.rawconfig.__setitem__( "no_auto_bright", a) ) dpg.add_slider_float( label="Gamma", default_value=1.0, min_value=0.1, max_value=3.0, - callback=lambda s, a, u: self.config.__setitem__("gamma", a) + callback=lambda s, a, u: self.rawconfig.__setitem__("gamma", a) ) dpg.add_checkbox( label="Half-size", default_value=False, - callback=lambda s, a, u: self.config.__setitem__( + callback=lambda s, a, u: self.rawconfig.__setitem__( "half_size", a) ) dpg.add_checkbox( label="4-color RGB", default_value=False, - callback=lambda s, a, u: self.config.__setitem__( + callback=lambda s, a, u: self.rawconfig.__setitem__( "four_color_rgb", a) ) @@ -179,28 +176,28 @@ class OpenRawWidget(PipelineStageWidget): with rawpy.imread(self.raw_path) as raw: # Prepare postprocess kwargs from config postprocess_args = { - 'demosaic_algorithm': self.config["demosaic_algorithm"], - 'output_color': self.config["output_color"], - 'output_bps': self.config["output_bps"], - 'bright': self.config["bright"], - 'no_auto_bright': self.config["no_auto_bright"], - 'gamma': (1.0, self.config["gamma"]), - 'half_size': self.config["half_size"], - 'four_color_rgb': self.config["four_color_rgb"], + 'demosaic_algorithm': self.rawconfig["demosaic_algorithm"], + 'output_color': self.rawconfig["output_color"], + 'output_bps': self.rawconfig["output_bps"], + 'bright': self.rawconfig["bright"], + 'no_auto_bright': self.rawconfig["no_auto_bright"], + 'gamma': (1.0, self.rawconfig["gamma"]), + 'half_size': self.rawconfig["half_size"], + 'four_color_rgb': self.rawconfig["four_color_rgb"], } - if self.config["use_camera_wb"]: + if self.rawconfig["use_camera_wb"]: postprocess_args['use_camera_wb'] = True - elif self.config["use_auto_wb"]: + elif self.rawconfig["use_auto_wb"]: postprocess_args['use_auto_wb'] = True else: - postprocess_args['user_wb'] = self.config["user_wb"] + postprocess_args['user_wb'] = self.rawconfig["user_wb"] # Postprocess into RGB rgb = raw.postprocess(**postprocess_args) # Normalize to float32 in 0.0-1.0 range depending on output_bps - max_val = (2 ** self.config["output_bps"]) - 1 + max_val = (2 ** self.rawconfig["output_bps"]) - 1 rgb_float = rgb.astype(np.float32) / max_val # Add alpha channel (fully opaque) diff --git a/negstation/widgets/pipeline_stage_widget.py b/negstation/widgets/pipeline_stage_widget.py index 9724235..9a5bb12 100644 --- a/negstation/widgets/pipeline_stage_widget.py +++ b/negstation/widgets/pipeline_stage_widget.py @@ -23,6 +23,7 @@ class PipelineStageWidget(BaseWidget): self.pipeline_stage_out_id = None self.pipeline_config_group_tag = dpg.generate_uuid() self.stage_in_combo = dpg.generate_uuid() + self.stage_out_input = dpg.generate_uuid() self._last_full = False if self.has_pipeline_out: @@ -30,14 +31,13 @@ class PipelineStageWidget(BaseWidget): default_stage_out ) - self.manager.bus.subscribe( - "pipeline_stages", self._on_stage_list, True) + self.manager.bus.subscribe("pipeline_stages", self._on_stage_list, True) if self.has_pipeline_in: self.pipeline_stage_in_id = 0 + self.manager.bus.subscribe("pipeline_stage", self._on_stage_data, True) self.manager.bus.subscribe( - "pipeline_stage", self._on_stage_data, True) - self.manager.bus.subscribe( - "pipeline_stage_full", self._on_stage_data_full, True) + "pipeline_stage_full", self._on_stage_data_full, True + ) # force getting all available pipeline stages self.manager.pipeline.republish_stages() @@ -50,7 +50,7 @@ class PipelineStageWidget(BaseWidget): callback=self._on_stage_in_select, default_value=f"{ self.manager.pipeline.get_stage_name(0)} : 0", - tag=self.stage_in_combo + tag=self.stage_in_combo, ) if self.has_pipeline_out: dpg.add_input_text( @@ -61,6 +61,7 @@ class PipelineStageWidget(BaseWidget): callback=lambda s, a, u: self.manager.pipeline.rename_stage( self.pipeline_stage_out_id, a ), + tag=self.stage_out_input, ) dpg.add_separator() self.create_pipeline_stage_content() @@ -77,7 +78,58 @@ class PipelineStageWidget(BaseWidget): """Publishes an image to output stage""" if self.has_pipeline_out: self.manager.pipeline.publish( - self.pipeline_stage_out_id, img, full_res=self._last_full) + self.pipeline_stage_out_id, img, full_res=self._last_full + ) + + def get_config(self): + return { + "pipeline_config": { + "stage_in": self.pipeline_stage_in_id, + "stage_out": self.pipeline_stage_out_id, + } + } + + def set_config(self, config): + # Set pipelinedata + if "pipeline_config" in config: + if self.has_pipeline_in: + self.pipeline_stage_in_id = config["pipeline_config"]["stage_in"] + if self.has_pipeline_out: + self.pipeline_stage_out_id = config["pipeline_config"]["stage_out"] + self._update_ui_from_state() + + def _update_ui_from_state(self): + """ + Refresh the ‘Stage In’ combo (and ‘Stage Out’ input) so + that: + 1. its items list matches the current pipeline stages, and + 2. its displayed value matches the saved ID. + """ + # --- Build the ordered list of "name : id" labels --- + ordered = sorted(self.manager.pipeline.stages.items(), key=lambda kv: kv[0]) + labels = [f"{name} : {sid}" for sid, name in ordered] + + # --- Update Stage In combo --- + if self.has_pipeline_in: + dpg.configure_item(self.stage_in_combo, items=labels) + # set the combo's value if the saved ID still exists + sid = self.pipeline_stage_in_id + if sid in self.manager.pipeline.stages: + name = self.manager.pipeline.get_stage_name(sid) + dpg.set_value(self.stage_in_combo, f"{name} : {sid}") + else: + # clear if it no longer exists + dpg.set_value(self.stage_in_combo, "") + + # --- Update Stage Out input text --- + if self.has_pipeline_out: + # show the stage name (without ID) or blank if missing + sid = self.pipeline_stage_out_id + if sid in self.manager.pipeline.stages: + name = self.manager.pipeline.get_stage_name(sid) + dpg.set_value(self.stage_out_input, name) + else: + dpg.set_value(self.stage_out_input, "") # Callbacks @@ -88,8 +140,7 @@ class PipelineStageWidget(BaseWidget): def _on_stage_list(self, stagelist): if self.has_pipeline_in: - stages = [f"{stage} : {id}" for id, stage in stagelist.items()] - dpg.configure_item(self.stage_in_combo, items=stages) + self._update_ui_from_state() def _on_stage_in_select(self, sender, selected_stage: str): d = selected_stage.split(" : ") @@ -121,8 +172,7 @@ class PipelineStageWidget(BaseWidget): def _on_window_resize(self, data): win_w, win_h = dpg.get_item_rect_size(self.window_tag) - group_w, group_h = dpg.get_item_rect_size( - self.pipeline_config_group_tag) + group_w, group_h = dpg.get_item_rect_size(self.pipeline_config_group_tag) group_x, group_y = dpg.get_item_pos(self.pipeline_config_group_tag) self.window_height = win_h - group_h - group_y - 12 self.window_width = win_w - 7 diff --git a/negstation_layout.ini b/negstation_layout.ini index de2a8bf..26be5e0 100644 --- a/negstation_layout.ini +++ b/negstation_layout.ini @@ -19,7 +19,7 @@ DockId=0x00000007,0 Pos=0,19 Size=270,469 Collapsed=0 -DockId=0x0000001F,1 +DockId=0x00000035,1 [Window][###59] Pos=0,494 @@ -46,9 +46,9 @@ DockId=0x0000000E,0 [Window][###23] Pos=0,19 -Size=270,469 +Size=270,567 Collapsed=0 -DockId=0x0000001F,0 +DockId=0x00000035,0 [Window][###29] Pos=0,19 @@ -60,7 +60,7 @@ DockId=0x00000012,0 Pos=198,19 Size=602,425 Collapsed=0 -DockId=0x0000000F,0 +DockId=0x00000033,0 [Window][###49] Pos=0,495 @@ -72,7 +72,7 @@ DockId=0x0000000C,0 Pos=246,19 Size=554,379 Collapsed=0 -DockId=0x0000000F,0 +DockId=0x00000033,0 [Window][###60] Pos=0,19 @@ -88,9 +88,9 @@ DockId=0x00000011,0 [Window][###35] Pos=272,19 -Size=710,625 +Size=710,580 Collapsed=0 -DockId=0x0000000F,0 +DockId=0x00000033,0 [Window][###43] Pos=0,490 @@ -170,50 +170,96 @@ Size=261,245 Collapsed=0 DockId=0x00000016,0 -[Docking][Data] -DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,19 Size=1200,781 Split=X - DockNode ID=0x0000002B Parent=0x7C6B3D9B SizeRef=937,781 Split=X - DockNode ID=0x00000027 Parent=0x0000002B SizeRef=982,781 Split=X - DockNode ID=0x00000023 Parent=0x00000027 SizeRef=982,781 Split=X - DockNode ID=0x0000001B Parent=0x00000023 SizeRef=982,781 Split=X - DockNode ID=0x00000017 Parent=0x0000001B SizeRef=898,781 Split=X - DockNode ID=0x00000009 Parent=0x00000017 SizeRef=270,581 Split=Y Selected=0x3BEDC6B0 - DockNode ID=0x0000000B Parent=0x00000009 SizeRef=196,474 Split=Y Selected=0x3BEDC6B0 - DockNode ID=0x0000000D Parent=0x0000000B SizeRef=196,99 Split=Y Selected=0x99D84869 - DockNode ID=0x00000012 Parent=0x0000000D SizeRef=196,423 Selected=0x0F59680E - DockNode ID=0x00000013 Parent=0x0000000D SizeRef=196,156 Split=Y Selected=0xB4AD3310 - DockNode ID=0x00000014 Parent=0x00000013 SizeRef=244,625 Split=Y Selected=0xB4AD3310 - DockNode ID=0x0000001F Parent=0x00000014 SizeRef=270,469 Selected=0xB4AD3310 - DockNode ID=0x00000020 Parent=0x00000014 SizeRef=270,154 Selected=0x0531B3D5 - DockNode ID=0x00000015 Parent=0x00000013 SizeRef=244,154 Selected=0x8773D56E - DockNode ID=0x0000000E Parent=0x0000000B SizeRef=196,373 Selected=0x3BEDC6B0 - DockNode ID=0x0000000C Parent=0x00000009 SizeRef=196,105 Selected=0x4F81AB74 - DockNode ID=0x0000000A Parent=0x00000017 SizeRef=665,581 Split=X - DockNode ID=0x00000003 Parent=0x0000000A SizeRef=299,581 Split=Y Selected=0x52849BCC - DockNode ID=0x00000005 Parent=0x00000003 SizeRef=299,473 Split=Y Selected=0x52849BCC - DockNode ID=0x00000007 Parent=0x00000005 SizeRef=299,86 Selected=0x52849BCC - DockNode ID=0x00000008 Parent=0x00000005 SizeRef=299,385 Selected=0xBD79B41E - DockNode ID=0x00000006 Parent=0x00000003 SizeRef=299,106 Selected=0x84DD78D1 - DockNode ID=0x00000004 Parent=0x0000000A SizeRef=499,581 Split=Y - DockNode ID=0x00000001 Parent=0x00000004 SizeRef=800,379 Split=Y Selected=0x7FF1E0B5 - DockNode ID=0x0000000F Parent=0x00000001 SizeRef=602,425 CentralNode=1 Selected=0x977476CD - DockNode ID=0x00000010 Parent=0x00000001 SizeRef=602,154 Selected=0x083320CE - DockNode ID=0x00000002 Parent=0x00000004 SizeRef=800,200 Selected=0x1834836D - DockNode ID=0x00000018 Parent=0x0000001B SizeRef=300,781 Selected=0x7E9438EA - DockNode ID=0x0000001C Parent=0x00000023 SizeRef=216,781 Split=Y Selected=0x714F2F7B - DockNode ID=0x0000001D Parent=0x0000001C SizeRef=216,344 Split=Y Selected=0x714F2F7B - DockNode ID=0x00000021 Parent=0x0000001D SizeRef=216,579 Split=Y Selected=0x714F2F7B - DockNode ID=0x00000019 Parent=0x00000021 SizeRef=216,391 Selected=0x714F2F7B - DockNode ID=0x0000001A Parent=0x00000021 SizeRef=216,388 Selected=0x7E9438EA - DockNode ID=0x00000022 Parent=0x0000001D SizeRef=216,200 Selected=0x0D80EC84 - DockNode ID=0x0000001E Parent=0x0000001C SizeRef=216,435 Selected=0x7740BFE4 - DockNode ID=0x00000024 Parent=0x00000027 SizeRef=216,781 Split=Y Selected=0xCF08B82F - DockNode ID=0x00000025 Parent=0x00000024 SizeRef=216,579 Selected=0xCF08B82F - DockNode ID=0x00000026 Parent=0x00000024 SizeRef=216,200 Selected=0x032CD220 - DockNode ID=0x00000028 Parent=0x0000002B SizeRef=216,781 Split=Y Selected=0xB5C8EB4F - DockNode ID=0x00000029 Parent=0x00000028 SizeRef=216,609 Selected=0xB5C8EB4F - DockNode ID=0x0000002A Parent=0x00000028 SizeRef=216,170 Selected=0xF8004A44 - DockNode ID=0x0000002C Parent=0x7C6B3D9B SizeRef=261,781 Split=Y Selected=0xC8700185 - DockNode ID=0x00000011 Parent=0x0000002C SizeRef=142,534 Selected=0x3A881EEF - DockNode ID=0x00000016 Parent=0x0000002C SizeRef=142,245 Selected=0xC8700185 +[Window][###97] +Pos=984,19 +Size=216,560 +Collapsed=0 +DockId=0x0000002F,0 + +[Window][###113] +Pos=984,581 +Size=216,219 +Collapsed=0 +DockId=0x00000030,0 + +[Window][###44] +Pos=0,588 +Size=270,105 +Collapsed=0 +DockId=0x00000036,0 + +[Window][###52] +Pos=0,19 +Size=270,567 +Collapsed=0 +DockId=0x00000035,1 + +[Window][###82] +Pos=272,601 +Size=710,199 +Collapsed=0 +DockId=0x00000034,0 + +[Window][###88] +Pos=0,695 +Size=270,105 +Collapsed=0 +DockId=0x00000032,0 + +[Docking][Data] +DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,19 Size=1200,781 Split=X + DockNode ID=0x0000002D Parent=0x7C6B3D9B SizeRef=982,781 Split=X + DockNode ID=0x0000002B Parent=0x0000002D SizeRef=937,781 Split=X + DockNode ID=0x00000027 Parent=0x0000002B SizeRef=982,781 Split=X + DockNode ID=0x00000023 Parent=0x00000027 SizeRef=982,781 Split=X + DockNode ID=0x0000001B Parent=0x00000023 SizeRef=982,781 Split=X + DockNode ID=0x00000017 Parent=0x0000001B SizeRef=898,781 Split=X + DockNode ID=0x00000009 Parent=0x00000017 SizeRef=270,581 Split=Y Selected=0x3BEDC6B0 + DockNode ID=0x0000000B Parent=0x00000009 SizeRef=196,474 Split=Y Selected=0x3BEDC6B0 + DockNode ID=0x0000000D Parent=0x0000000B SizeRef=196,99 Split=Y Selected=0x99D84869 + DockNode ID=0x00000012 Parent=0x0000000D SizeRef=196,423 Selected=0x0F59680E + DockNode ID=0x00000013 Parent=0x0000000D SizeRef=196,156 Split=Y Selected=0xB4AD3310 + DockNode ID=0x00000014 Parent=0x00000013 SizeRef=244,625 Split=Y Selected=0xB4AD3310 + DockNode ID=0x0000001F Parent=0x00000014 SizeRef=270,469 Split=Y Selected=0xD36850C8 + DockNode ID=0x00000031 Parent=0x0000001F SizeRef=270,674 Split=Y Selected=0xF30D49C0 + DockNode ID=0x00000035 Parent=0x00000031 SizeRef=270,567 Selected=0xF30D49C0 + DockNode ID=0x00000036 Parent=0x00000031 SizeRef=270,105 Selected=0xB7116FC5 + DockNode ID=0x00000032 Parent=0x0000001F SizeRef=270,105 Selected=0x052342BF + DockNode ID=0x00000020 Parent=0x00000014 SizeRef=270,154 Selected=0x0531B3D5 + DockNode ID=0x00000015 Parent=0x00000013 SizeRef=244,154 Selected=0x8773D56E + DockNode ID=0x0000000E Parent=0x0000000B SizeRef=196,373 Selected=0x3BEDC6B0 + DockNode ID=0x0000000C Parent=0x00000009 SizeRef=196,105 Selected=0x4F81AB74 + DockNode ID=0x0000000A Parent=0x00000017 SizeRef=665,581 Split=X + DockNode ID=0x00000003 Parent=0x0000000A SizeRef=299,581 Split=Y Selected=0x52849BCC + DockNode ID=0x00000005 Parent=0x00000003 SizeRef=299,473 Split=Y Selected=0x52849BCC + DockNode ID=0x00000007 Parent=0x00000005 SizeRef=299,86 Selected=0x52849BCC + DockNode ID=0x00000008 Parent=0x00000005 SizeRef=299,385 Selected=0xBD79B41E + DockNode ID=0x00000006 Parent=0x00000003 SizeRef=299,106 Selected=0x84DD78D1 + DockNode ID=0x00000004 Parent=0x0000000A SizeRef=499,581 Split=Y + DockNode ID=0x00000001 Parent=0x00000004 SizeRef=800,379 Split=Y Selected=0x7FF1E0B5 + DockNode ID=0x0000000F Parent=0x00000001 SizeRef=602,425 Split=Y Selected=0x977476CD + DockNode ID=0x00000033 Parent=0x0000000F SizeRef=710,580 CentralNode=1 Selected=0x977476CD + DockNode ID=0x00000034 Parent=0x0000000F SizeRef=710,199 Selected=0x4F935A1E + DockNode ID=0x00000010 Parent=0x00000001 SizeRef=602,154 Selected=0x083320CE + DockNode ID=0x00000002 Parent=0x00000004 SizeRef=800,200 Selected=0x1834836D + DockNode ID=0x00000018 Parent=0x0000001B SizeRef=300,781 Selected=0x7E9438EA + DockNode ID=0x0000001C Parent=0x00000023 SizeRef=216,781 Split=Y Selected=0x714F2F7B + DockNode ID=0x0000001D Parent=0x0000001C SizeRef=216,344 Split=Y Selected=0x714F2F7B + DockNode ID=0x00000021 Parent=0x0000001D SizeRef=216,579 Split=Y Selected=0x714F2F7B + DockNode ID=0x00000019 Parent=0x00000021 SizeRef=216,391 Selected=0x714F2F7B + DockNode ID=0x0000001A Parent=0x00000021 SizeRef=216,388 Selected=0x7E9438EA + DockNode ID=0x00000022 Parent=0x0000001D SizeRef=216,200 Selected=0x0D80EC84 + DockNode ID=0x0000001E Parent=0x0000001C SizeRef=216,435 Selected=0x7740BFE4 + DockNode ID=0x00000024 Parent=0x00000027 SizeRef=216,781 Split=Y Selected=0xCF08B82F + DockNode ID=0x00000025 Parent=0x00000024 SizeRef=216,579 Selected=0xCF08B82F + DockNode ID=0x00000026 Parent=0x00000024 SizeRef=216,200 Selected=0x032CD220 + DockNode ID=0x00000028 Parent=0x0000002B SizeRef=216,781 Split=Y Selected=0xB5C8EB4F + DockNode ID=0x00000029 Parent=0x00000028 SizeRef=216,609 Selected=0xB5C8EB4F + DockNode ID=0x0000002A Parent=0x00000028 SizeRef=216,170 Selected=0xF8004A44 + DockNode ID=0x0000002C Parent=0x0000002D SizeRef=261,781 Split=Y Selected=0xC8700185 + DockNode ID=0x00000011 Parent=0x0000002C SizeRef=142,534 Selected=0x3A881EEF + DockNode ID=0x00000016 Parent=0x0000002C SizeRef=142,245 Selected=0xC8700185 + DockNode ID=0x0000002E Parent=0x7C6B3D9B SizeRef=216,781 Split=Y Selected=0x4C2F06CB + DockNode ID=0x0000002F Parent=0x0000002E SizeRef=216,560 Selected=0x4C2F06CB + DockNode ID=0x00000030 Parent=0x0000002E SizeRef=216,219 Selected=0x04546B8A diff --git a/negstation_widgets.json b/negstation_widgets.json index 4403a32..192203c 100644 --- a/negstation_widgets.json +++ b/negstation_widgets.json @@ -1,34 +1,77 @@ -[ - { - "widget_type": "OpenImageWidget", - "config": {} +{ + "pipeline_order": { + "0": "opened_image", + "1": "inverted_image", + "2": "opened_raw", + "3": "monochrome" }, - { - "widget_type": "PipelineStageViewer", - "config": {} - }, - { - "widget_type": "InvertStage", - "config": {} - }, - { - "widget_type": "OpenRawWidget", - "config": {} - }, - { - "widget_type": "LogWindowWidget", - "config": {} - }, - { - "widget_type": "MonochromeStage", - "config": {} - }, - { - "widget_type": "HistogramWidget", - "config": {} - }, - { - "widget_type": "ExportStage", - "config": {} - } -] \ No newline at end of file + "widgets": [ + { + "widget_type": "OpenImageWidget", + "config": { + "pipeline_config": { + "stage_in": null, + "stage_out": 0 + } + } + }, + { + "widget_type": "PipelineStageViewer", + "config": { + "pipeline_config": { + "stage_in": 3, + "stage_out": null + } + } + }, + { + "widget_type": "InvertStage", + "config": { + "pipeline_config": { + "stage_in": 2, + "stage_out": 1 + } + } + }, + { + "widget_type": "OpenRawWidget", + "config": { + "pipeline_config": { + "stage_in": null, + "stage_out": 2 + } + } + }, + { + "widget_type": "LogWindowWidget", + "config": {} + }, + { + "widget_type": "MonochromeStage", + "config": { + "pipeline_config": { + "stage_in": 1, + "stage_out": 3 + } + } + }, + { + "widget_type": "HistogramWidget", + "config": { + "pipeline_config": { + "stage_in": 3, + "stage_out": null + } + } + }, + { + "widget_type": "ExportStage", + "config": { + "pipeline_config": { + "stage_in": 3, + "stage_out": null + } + } + } + ] +} \ No newline at end of file