From a3c8d4b153130bf638e214dff9fc227c155976e2 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sun, 22 Mar 2026 13:17:19 -0400 Subject: [PATCH] feat(gui): Implement Context Composition panel (Phase 3) - Replaced placeholder with actual _render_context_composition_panel - Shows current files with Auto-Aggregate and Force Full flags - Shows current screenshots - Preset dropdown to load existing presets - Save as Preset / Delete Preset buttons - Uses existing save_context_preset/load_context_preset methods --- src/gui_2.py | 53 +++++++++++++++++++++++-- tests/test_context_composition_panel.py | 42 ++++++++++++++++++++ 2 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 tests/test_context_composition_panel.py diff --git a/src/gui_2.py b/src/gui_2.py index 96d20b0..0b0e7e4 100644 --- a/src/gui_2.py +++ b/src/gui_2.py @@ -728,7 +728,7 @@ class App: self._render_discussion_tab() imgui.end_tab_item() if imgui.begin_tab_item("Context Composition")[0]: - self._render_context_composition_placeholder() + self._render_context_composition_panel() imgui.end_tab_item() if imgui.begin_tab_item("Snapshot")[0]: self._render_snapshot_tab() @@ -2085,10 +2085,57 @@ class App: else: imgui.text_disabled("Message & Response panels are detached.") - def _render_context_composition_placeholder(self) -> None: + def _render_context_composition_panel(self) -> None: imgui.text("Context Composition") imgui.separator() - imgui.text_colored(C_LBL, "Coming in Phase 3...") + if imgui.begin_table("ctx_comp_table", 2, imgui.TableFlags_.resizable | imgui.TableFlags_.borders): + imgui.table_setup_column("File", imgui.TableColumnFlags_.width_stretch) + imgui.table_setup_column("Flags", imgui.TableColumnFlags_.width_fixed, 120) + imgui.table_headers_row() + for i, f_item in enumerate(self.files): + imgui.table_next_row() + imgui.table_set_column_index(0) + imgui.text(f_item.path if hasattr(f_item, "path") else str(f_item)) + imgui.table_set_column_index(1) + if hasattr(f_item, "auto_aggregate"): + changed_agg, f_item.auto_aggregate = imgui.checkbox(f"Agg##cc{i}", f_item.auto_aggregate) + imgui.same_line() + changed_full, f_item.force_full = imgui.checkbox(f"Full##cc{i}", f_item.force_full) + imgui.end_table() + imgui.separator() + imgui.text("Screenshots") + for i, s in enumerate(self.screenshots): + imgui.text(s) + imgui.separator() + imgui.text("Presets") + presets = self.controller.project.get('context_presets', {}) + preset_names = [""] + sorted(presets.keys()) + active = getattr(self, "ui_active_context_preset", "") + if active not in preset_names: + active = "" + try: + idx = preset_names.index(active) + except ValueError: + idx = 0 + ch, new_idx = imgui.combo("##ctx_preset", idx, preset_names) + if ch: + self.ui_active_context_preset = preset_names[new_idx] + if preset_names[new_idx]: + self.load_context_preset(preset_names[new_idx]) + imgui.same_line() + changed, new_name = imgui.input_text("##new_preset", getattr(self, "ui_new_context_preset_name", "")) + if changed: + self.ui_new_context_preset_name = new_name + imgui.same_line() + if imgui.button("Save##ctx"): + if getattr(self, "ui_new_context_preset_name", "").strip(): + self.save_context_preset(self.ui_new_context_preset_name.strip()) + self.ui_new_context_preset_name = "" + imgui.same_line() + if imgui.button("Delete##ctx"): + if getattr(self, "ui_active_context_preset", ""): + self.delete_context_preset(self.ui_active_context_preset) + self.ui_active_context_preset = "" def _render_snapshot_tab(self) -> None: if imgui.begin_tab_bar("snapshot_tabs"): diff --git a/tests/test_context_composition_panel.py b/tests/test_context_composition_panel.py new file mode 100644 index 0000000..0aade91 --- /dev/null +++ b/tests/test_context_composition_panel.py @@ -0,0 +1,42 @@ +import pytest +import inspect + + +def test_context_composition_panel_replaces_placeholder(): + import src.gui_2 as gui_2 + + source = inspect.getsource(gui_2.App._gui_func) + assert "_render_context_composition_placeholder" not in source, ( + "Placeholder should be replaced" + ) + assert "_render_context_composition_panel" in source, ( + "Should have _render_context_composition_panel" + ) + + +def test_context_composition_has_save_load_buttons(): + import src.gui_2 as gui_2 + + source = inspect.getsource(gui_2.App._render_context_composition_panel) + assert "Save as Preset" in source or "save" in source.lower(), ( + "Should have Save functionality" + ) + assert "Load Preset" in source or "load" in source.lower(), ( + "Should have Load functionality" + ) + + +def test_context_composition_shows_files(): + import src.gui_2 as gui_2 + + source = inspect.getsource(gui_2.App._render_context_composition_panel) + assert "files" in source.lower() or "Files" in source, "Should show files" + + +def test_context_composition_has_preset_list(): + import src.gui_2 as gui_2 + + source = inspect.getsource(gui_2.App._render_context_composition_panel) + assert "context_presets" in source or "preset" in source.lower(), ( + "Should reference presets" + )