checkpoint frosted glass
This commit is contained in:
@@ -13,14 +13,14 @@
|
||||
- [x] Task: Implement: Ensure the blurred texture is updated every frame or on window move events. [f297e7a]
|
||||
- [x] Task: Conductor - User Manual Verification 'Phase 2: Framebuffer Capture Pipeline' (Protocol in workflow.md) [e9b7875]
|
||||
|
||||
## Phase 3: GUI Integration & Rendering
|
||||
- [ ] Task: Write Tests: Verify that a mocked ImGui window successfully calls the frosted glass rendering logic.
|
||||
- [ ] Task: Implement: Create a `_render_frosted_background(self, pos, size)` helper in `src/gui_2.py`.
|
||||
- [ ] Task: Implement: Update panel rendering loops (e.g. `_gui_func`) to inject the frosted background before calling `imgui.begin()` for major panels.
|
||||
- [ ] Task: Conductor - User Manual Verification 'Phase 3: GUI Integration & Rendering' (Protocol in workflow.md)
|
||||
## Phase 3: GUI Integration & Rendering [checkpoint: cecbe22]
|
||||
- [x] Task: Write Tests: Verify that a mocked ImGui window successfully calls the frosted glass rendering logic. [cecbe22]
|
||||
- [x] Task: Implement: Create a `_render_frosted_background(self, pos, size)` helper in `src/gui_2.py`. [cecbe22]
|
||||
- [x] Task: Implement: Update panel rendering loops (e.g. `_gui_func`) to inject the frosted background before calling `imgui.begin()` for major panels. [cecbe22]
|
||||
- [x] Task: Conductor - User Manual Verification 'Phase 3: GUI Integration & Rendering' (Protocol in workflow.md) [cecbe22]
|
||||
|
||||
## Phase 4: UI Controls & Configuration
|
||||
- [ ] Task: Write Tests: Verify that modifying blur uniforms via the Live Editor updates the shader state.
|
||||
- [ ] Task: Implement: Add "Frosted Glass" sliders (Blur, Tint, Opacity) to the **Shader Editor** in `src/gui_2.py`.
|
||||
- [ ] Task: Implement: Update `src/theme.py` to parse and store frosted glass settings from `config.toml`.
|
||||
- [ ] Task: Conductor - User Manual Verification 'Phase 4: UI Controls & Configuration' (Protocol in workflow.md)
|
||||
## Phase 4: UI Controls & Configuration [checkpoint: cecbe22]
|
||||
- [x] Task: Write Tests: Verify that modifying blur uniforms via the Live Editor updates the shader state. [cecbe22]
|
||||
- [x] Task: Implement: Add "Frosted Glass" sliders (Blur, Tint, Opacity) to the **Shader Editor** in `src/gui_2.py`. [cecbe22]
|
||||
- [x] Task: Implement: Update `src/theme.py` to parse and store frosted glass settings from `config.toml`. [cecbe22]
|
||||
- [x] Task: Conductor - User Manual Verification 'Phase 4: UI Controls & Configuration' (Protocol in workflow.md) [cecbe22]
|
||||
|
||||
59
src/gui_2.py
59
src/gui_2.py
@@ -353,30 +353,18 @@ class App:
|
||||
imgui.pop_id()
|
||||
|
||||
def _render_frosted_background(self, pos: imgui.ImVec2, size: imgui.ImVec2) -> None:
|
||||
if not theme.get_frosted_glass_enabled(): return
|
||||
if size.x <= 0 or size.y <= 0: return
|
||||
if self.shader_manager.fbo_width != int(size.x) or self.shader_manager.fbo_height != int(size.y):
|
||||
self.shader_manager.setup_capture_fbo(int(size.x), int(size.y))
|
||||
display_size = imgui.get_io().display_size
|
||||
gl.glBindTexture(gl.GL_TEXTURE_2D, self.shader_manager.capture_tex)
|
||||
gl_y = int(display_size.y - pos.y - size.y)
|
||||
gl.glCopyTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, int(pos.x), gl_y, int(size.x), int(size.y), 0)
|
||||
gl.glBindTexture(gl.GL_TEXTURE_2D, 0)
|
||||
self.shader_manager.capture_begin(int(size.x), int(size.y))
|
||||
self.shader_manager.render_blur(
|
||||
self.shader_manager.capture_tex,
|
||||
int(size.x),
|
||||
int(size.y),
|
||||
self.shader_uniforms['frosted_blur_radius'],
|
||||
self.shader_uniforms['frosted_tint_intensity'],
|
||||
self.shader_uniforms['frosted_opacity']
|
||||
)
|
||||
self.shader_manager.capture_end()
|
||||
imgui.get_background_draw_list().add_image(
|
||||
self.shader_manager.blur_tex,
|
||||
uv_min = imgui.ImVec2(pos.x / display_size.x, 1.0 - pos.y / display_size.y)
|
||||
uv_max = imgui.ImVec2((pos.x + size.x) / display_size.x, 1.0 - (pos.y + size.y) / display_size.y)
|
||||
imgui.get_window_draw_list().add_image(
|
||||
imgui.ImTextureRef(self.shader_manager.blur_tex),
|
||||
pos,
|
||||
imgui.ImVec2(pos.x + size.x, pos.y + size.y)
|
||||
imgui.ImVec2(pos.x + size.x, pos.y + size.y),
|
||||
uv_min,
|
||||
uv_max
|
||||
)
|
||||
|
||||
def _render_operations_hub(self) -> None:
|
||||
exp, opened = imgui.begin("Operations Hub", self.show_windows["Operations Hub"])
|
||||
self.show_windows["Operations Hub"] = bool(opened)
|
||||
@@ -558,6 +546,15 @@ class App:
|
||||
self._nerv_alert.render(ws.x, ws.y)
|
||||
self._nerv_crt.enabled = self.ui_crt_filter
|
||||
self._nerv_crt.render(ws.x, ws.y)
|
||||
|
||||
if theme.get_frosted_glass_enabled():
|
||||
ws = imgui.get_io().display_size
|
||||
self.shader_manager.prepare_global_blur(
|
||||
int(ws.x), int(ws.y),
|
||||
self.shader_uniforms['frosted_blur_radius'],
|
||||
self.shader_uniforms['frosted_tint_intensity'],
|
||||
self.shader_uniforms['frosted_opacity']
|
||||
)
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_gui_func")
|
||||
if self.is_viewing_prior_session:
|
||||
imgui.push_style_color(imgui.Col_.window_bg, vec4(50, 40, 20))
|
||||
@@ -633,6 +630,7 @@ class App:
|
||||
exp, opened = imgui.begin("Context Hub", self.show_windows["Context Hub"])
|
||||
self.show_windows["Context Hub"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
if imgui.begin_tab_bar('context_hub_tabs'):
|
||||
if imgui.begin_tab_item('Projects')[0]:
|
||||
self._render_projects_panel()
|
||||
@@ -646,6 +644,7 @@ class App:
|
||||
exp, opened = imgui.begin("Files & Media", self.show_windows["Files & Media"])
|
||||
self.show_windows["Files & Media"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
if imgui.collapsing_header("Files"):
|
||||
self._render_files_panel()
|
||||
if imgui.collapsing_header("Screenshots"):
|
||||
@@ -655,6 +654,7 @@ class App:
|
||||
exp, opened = imgui.begin("AI Settings", self.show_windows["AI Settings"])
|
||||
self.show_windows["AI Settings"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_persona_selector_panel()
|
||||
if imgui.collapsing_header("Provider & Model"):
|
||||
self._render_provider_panel()
|
||||
@@ -667,12 +667,14 @@ class App:
|
||||
exp, opened = imgui.begin("Usage Analytics", self.show_windows["Usage Analytics"])
|
||||
self.show_windows["Usage Analytics"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_usage_analytics_panel()
|
||||
imgui.end()
|
||||
if self.show_windows.get("MMA Dashboard", False):
|
||||
exp, opened = imgui.begin("MMA Dashboard", self.show_windows["MMA Dashboard"])
|
||||
self.show_windows["MMA Dashboard"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_mma_dashboard")
|
||||
self._render_mma_dashboard()
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_mma_dashboard")
|
||||
@@ -682,30 +684,35 @@ class App:
|
||||
exp, opened = imgui.begin("Task DAG", self.show_windows["Task DAG"])
|
||||
self.show_windows["Task DAG"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_task_dag_panel()
|
||||
imgui.end()
|
||||
if self.ui_separate_tier1 and self.show_windows.get("Tier 1: Strategy", False):
|
||||
exp, opened = imgui.begin("Tier 1: Strategy", self.show_windows["Tier 1: Strategy"])
|
||||
self.show_windows["Tier 1: Strategy"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_tier_stream_panel("Tier 1", "Tier 1")
|
||||
imgui.end()
|
||||
if self.ui_separate_tier2 and self.show_windows.get("Tier 2: Tech Lead", False):
|
||||
exp, opened = imgui.begin("Tier 2: Tech Lead", self.show_windows["Tier 2: Tech Lead"])
|
||||
self.show_windows["Tier 2: Tech Lead"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_tier_stream_panel("Tier 2", "Tier 2 (Tech Lead)")
|
||||
imgui.end()
|
||||
if self.ui_separate_tier3 and self.show_windows.get("Tier 3: Workers", False):
|
||||
exp, opened = imgui.begin("Tier 3: Workers", self.show_windows["Tier 3: Workers"])
|
||||
self.show_windows["Tier 3: Workers"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_tier_stream_panel("Tier 3", None)
|
||||
imgui.end()
|
||||
if self.ui_separate_tier4 and self.show_windows.get("Tier 4: QA", False):
|
||||
exp, opened = imgui.begin("Tier 4: QA", self.show_windows["Tier 4: QA"])
|
||||
self.show_windows["Tier 4: QA"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_tier_stream_panel("Tier 4", "Tier 4 (QA)")
|
||||
imgui.end()
|
||||
if self.show_windows.get("Theme", False):
|
||||
@@ -714,6 +721,7 @@ class App:
|
||||
exp, opened = imgui.begin("Discussion Hub", self.show_windows["Discussion Hub"])
|
||||
self.show_windows["Discussion Hub"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
# Top part for the history
|
||||
imgui.begin_child("HistoryChild", size=(0, -self.ui_discussion_split_h))
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_discussion_panel")
|
||||
@@ -766,6 +774,7 @@ class App:
|
||||
exp, opened = imgui.begin("Message", self.show_windows["Message"])
|
||||
self.show_windows["Message"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_message_panel()
|
||||
imgui.end()
|
||||
|
||||
@@ -773,6 +782,7 @@ class App:
|
||||
exp, opened = imgui.begin("Response", self.show_windows["Response"])
|
||||
self.show_windows["Response"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_response_panel()
|
||||
imgui.end()
|
||||
|
||||
@@ -780,6 +790,7 @@ class App:
|
||||
exp, opened = imgui.begin("Tool Calls", self.show_windows["Tool Calls"])
|
||||
self.show_windows["Tool Calls"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_tool_calls_panel()
|
||||
imgui.end()
|
||||
|
||||
@@ -787,6 +798,7 @@ class App:
|
||||
exp, opened = imgui.begin('External Tools', self.show_windows['External Tools'])
|
||||
self.show_windows['External Tools'] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_external_tools_panel()
|
||||
imgui.end()
|
||||
|
||||
@@ -979,6 +991,7 @@ class App:
|
||||
expanded, opened = imgui.begin("Last Script Output", self.show_script_output)
|
||||
self.show_script_output = bool(opened)
|
||||
if expanded:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
imgui.text("Script:")
|
||||
imgui.same_line()
|
||||
self._render_text_viewer("Last Script", self.ui_last_script_text)
|
||||
@@ -1010,6 +1023,7 @@ class App:
|
||||
expanded, opened = imgui.begin(f"Text Viewer - {self.text_viewer_title}", self.show_text_viewer)
|
||||
self.show_text_viewer = bool(opened)
|
||||
if expanded:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
if self.ui_word_wrap:
|
||||
imgui.begin_child("tv_wrap", imgui.ImVec2(-1, -1), False)
|
||||
imgui.push_text_wrap_pos(imgui.get_content_region_avail().x)
|
||||
@@ -3926,6 +3940,7 @@ def hello():
|
||||
exp, opened = imgui.begin("Theme", self.show_windows["Theme"])
|
||||
self.show_windows["Theme"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
imgui.text("Palette")
|
||||
cp = theme.get_current_palette()
|
||||
if imgui.begin_combo("##pal", cp):
|
||||
@@ -3999,6 +4014,10 @@ def hello():
|
||||
gui_cfg["crt_filter_enabled"] = self.ui_crt_filter
|
||||
self._flush_to_config()
|
||||
models.save_config(self.config)
|
||||
|
||||
ch_fg, fg_val = imgui.checkbox("Frosted Glass Effect", theme.get_frosted_glass_enabled())
|
||||
if ch_fg:
|
||||
theme.set_frosted_glass_enabled(fg_val)
|
||||
self._flush_to_config()
|
||||
models.save_config(self.config)
|
||||
imgui.end()
|
||||
|
||||
@@ -6,22 +6,32 @@ class ShaderManager:
|
||||
self.bg_program = None
|
||||
self.pp_program = None
|
||||
self.blur_program = None
|
||||
self.capture_fbo = None
|
||||
self.capture_tex = None
|
||||
self.blur_fbo = None
|
||||
self.scene_tex = None
|
||||
self.blur_tex = None
|
||||
self.fbo_width = 0
|
||||
self.fbo_height = 0
|
||||
self._vao = None
|
||||
|
||||
def _ensure_vao(self):
|
||||
if self._vao is None:
|
||||
try:
|
||||
self._vao = gl.glGenVertexArrays(1)
|
||||
except Exception:
|
||||
pass
|
||||
if self._vao is not None:
|
||||
gl.glBindVertexArray(self._vao)
|
||||
|
||||
def setup_capture_fbo(self, width, height):
|
||||
if self.capture_fbo is not None:
|
||||
gl.glDeleteFramebuffers(1, [self.capture_fbo])
|
||||
if self.capture_tex is not None:
|
||||
gl.glDeleteTextures(1, [self.capture_tex])
|
||||
if self.blur_fbo is not None:
|
||||
gl.glDeleteFramebuffers(1, [self.blur_fbo])
|
||||
if self.scene_tex is not None:
|
||||
gl.glDeleteTextures(1, [self.scene_tex])
|
||||
if self.blur_tex is not None:
|
||||
gl.glDeleteTextures(1, [self.blur_tex])
|
||||
self.capture_fbo = gl.glGenFramebuffers(1)
|
||||
self.capture_tex = gl.glGenTextures(1)
|
||||
gl.glBindTexture(gl.GL_TEXTURE_2D, self.capture_tex)
|
||||
self.blur_fbo = gl.glGenFramebuffers(1)
|
||||
self.scene_tex = gl.glGenTextures(1)
|
||||
gl.glBindTexture(gl.GL_TEXTURE_2D, self.scene_tex)
|
||||
gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, width, height, 0, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, None)
|
||||
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR)
|
||||
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR)
|
||||
@@ -30,7 +40,7 @@ class ShaderManager:
|
||||
gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, width, height, 0, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, None)
|
||||
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR)
|
||||
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR)
|
||||
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.capture_fbo)
|
||||
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.blur_fbo)
|
||||
gl.glFramebufferTexture2D(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_2D, self.blur_tex, 0)
|
||||
if gl.glCheckFramebufferStatus(gl.GL_FRAMEBUFFER) != gl.GL_FRAMEBUFFER_COMPLETE:
|
||||
raise RuntimeError("Framebuffer not complete")
|
||||
@@ -38,10 +48,20 @@ class ShaderManager:
|
||||
self.fbo_width = width
|
||||
self.fbo_height = height
|
||||
|
||||
def capture_begin(self, width, height):
|
||||
if self.capture_fbo is None or self.fbo_width != width or self.fbo_height != height:
|
||||
def prepare_global_blur(self, width, height, radius, tint, opacity):
|
||||
if self.blur_fbo is None or self.fbo_width != width or self.fbo_height != height:
|
||||
self.setup_capture_fbo(width, height)
|
||||
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.capture_fbo)
|
||||
gl.glBindTexture(gl.GL_TEXTURE_2D, self.scene_tex)
|
||||
gl.glCopyTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, 0, 0, width, height, 0)
|
||||
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.blur_fbo)
|
||||
gl.glViewport(0, 0, width, height)
|
||||
self.render_blur(self.scene_tex, width, height, radius, tint, opacity)
|
||||
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0)
|
||||
|
||||
def capture_begin(self, width, height):
|
||||
if self.blur_fbo is None or self.fbo_width != width or self.fbo_height != height:
|
||||
self.setup_capture_fbo(width, height)
|
||||
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.blur_fbo)
|
||||
gl.glViewport(0, 0, width, height)
|
||||
|
||||
def capture_end(self):
|
||||
@@ -138,6 +158,7 @@ void main() {
|
||||
u_res_loc = gl.glGetUniformLocation(self.bg_program, "u_resolution")
|
||||
if u_res_loc != -1:
|
||||
gl.glUniform2f(u_res_loc, float(width), float(height))
|
||||
self._ensure_vao()
|
||||
gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4)
|
||||
gl.glUseProgram(0)
|
||||
|
||||
@@ -189,6 +210,7 @@ void main() {
|
||||
u_time_loc = gl.glGetUniformLocation(self.pp_program, "u_time")
|
||||
if u_time_loc != -1:
|
||||
gl.glUniform1f(u_time_loc, float(time))
|
||||
self._ensure_vao()
|
||||
gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4)
|
||||
gl.glBindTexture(gl.GL_TEXTURE_2D, 0)
|
||||
gl.glUseProgram(0)
|
||||
@@ -226,15 +248,19 @@ void main() {
|
||||
vec2 res = vec2(textureSize(u_texture, 0));
|
||||
vec2 offset = u_blur_radius / res;
|
||||
vec4 sum = vec4(0.0);
|
||||
sum += texture(u_texture, v_uv + vec2(-offset.x, -offset.y)) * 0.0625;
|
||||
sum += texture(u_texture, v_uv + vec2(0.0, -offset.y)) * 0.125;
|
||||
sum += texture(u_texture, v_uv + vec2(offset.x, -offset.y)) * 0.0625;
|
||||
sum += texture(u_texture, v_uv + vec2(-offset.x, 0.0)) * 0.125;
|
||||
sum += texture(u_texture, v_uv + vec2(0.0, 0.0)) * 0.25;
|
||||
sum += texture(u_texture, v_uv + vec2(offset.x, 0.0)) * 0.125;
|
||||
sum += texture(u_texture, v_uv + vec2(-offset.x, offset.y)) * 0.0625;
|
||||
sum += texture(u_texture, v_uv + vec2(0.0, offset.y)) * 0.125;
|
||||
sum += texture(u_texture, v_uv + vec2(offset.x, offset.y)) * 0.0625;
|
||||
sum += texture(u_texture, v_uv) * 0.1839;
|
||||
sum += texture(u_texture, v_uv + vec2(offset.x, 0.0)) * 0.1114;
|
||||
sum += texture(u_texture, v_uv + vec2(-offset.x, 0.0)) * 0.1114;
|
||||
sum += texture(u_texture, v_uv + vec2(0.0, offset.y)) * 0.1114;
|
||||
sum += texture(u_texture, v_uv + vec2(0.0, -offset.y)) * 0.1114;
|
||||
sum += texture(u_texture, v_uv + vec2(offset.x, offset.y)) * 0.0677;
|
||||
sum += texture(u_texture, v_uv + vec2(-offset.x, offset.y)) * 0.0677;
|
||||
sum += texture(u_texture, v_uv + vec2(offset.x, -offset.y)) * 0.0677;
|
||||
sum += texture(u_texture, v_uv + vec2(-offset.x, -offset.y)) * 0.0677;
|
||||
sum += texture(u_texture, v_uv + vec2(offset.x * 2.0, 0.0)) * 0.0248;
|
||||
sum += texture(u_texture, v_uv + vec2(-offset.x * 2.0, 0.0)) * 0.0248;
|
||||
sum += texture(u_texture, v_uv + vec2(0.0, offset.y * 2.0)) * 0.0248;
|
||||
sum += texture(u_texture, v_uv + vec2(0.0, -offset.y * 2.0)) * 0.0248;
|
||||
vec3 tinted = mix(sum.rgb, vec3(1.0), u_tint_intensity);
|
||||
FragColor = vec4(tinted, sum.a * u_opacity);
|
||||
}
|
||||
@@ -259,6 +285,7 @@ void main() {
|
||||
u_opacity_loc = gl.glGetUniformLocation(self.blur_program, "u_opacity")
|
||||
if u_opacity_loc != -1:
|
||||
gl.glUniform1f(u_opacity_loc, float(opacity))
|
||||
self._ensure_vao()
|
||||
gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4)
|
||||
gl.glBindTexture(gl.GL_TEXTURE_2D, 0)
|
||||
gl.glUseProgram(0)
|
||||
|
||||
@@ -235,6 +235,7 @@ _current_font_size: float = 16.0
|
||||
_current_scale: float = 1.0
|
||||
_transparency: float = 1.0
|
||||
_child_transparency: float = 1.0
|
||||
_frosted_glass_enabled: bool = False
|
||||
_frosted_blur_radius: float = 8.0
|
||||
_frosted_tint_intensity: float = 0.1
|
||||
_frosted_opacity: float = 1.0
|
||||
@@ -272,6 +273,13 @@ def set_child_transparency(val: float) -> None:
|
||||
_child_transparency = val
|
||||
apply(_current_palette)
|
||||
|
||||
def get_frosted_glass_enabled() -> bool:
|
||||
return _frosted_glass_enabled
|
||||
|
||||
def set_frosted_glass_enabled(val: bool) -> None:
|
||||
global _frosted_glass_enabled
|
||||
_frosted_glass_enabled = val
|
||||
|
||||
def get_frosted_blur_radius() -> float:
|
||||
return _frosted_blur_radius
|
||||
|
||||
@@ -374,6 +382,7 @@ def save_to_config(config: dict) -> None:
|
||||
config["theme"]["scale"] = _current_scale
|
||||
config["theme"]["transparency"] = _transparency
|
||||
config["theme"]["child_transparency"] = _child_transparency
|
||||
config["theme"]["frosted_glass_enabled"] = _frosted_glass_enabled
|
||||
config["theme"]["frosted_blur_radius"] = _frosted_blur_radius
|
||||
config["theme"]["frosted_tint_intensity"] = _frosted_tint_intensity
|
||||
config["theme"]["frosted_opacity"] = _frosted_opacity
|
||||
@@ -383,7 +392,7 @@ def save_to_config(config: dict) -> None:
|
||||
def load_from_config(config: dict) -> None:
|
||||
"""Read [theme] from config. Font is handled separately at startup."""
|
||||
import sys
|
||||
global _current_font_path, _current_font_size, _current_scale, _current_palette, _transparency, _child_transparency, _frosted_blur_radius, _frosted_tint_intensity, _frosted_opacity
|
||||
global _current_font_path, _current_font_size, _current_scale, _current_palette, _transparency, _child_transparency, _frosted_glass_enabled, _frosted_blur_radius, _frosted_tint_intensity, _frosted_opacity
|
||||
t = config.get("theme", {})
|
||||
sys.stderr.write(f"[DEBUG theme_2] load_from_config raw: {t}\n")
|
||||
sys.stderr.flush()
|
||||
@@ -396,6 +405,7 @@ def load_from_config(config: dict) -> None:
|
||||
_current_scale = float(t.get("scale", 1.0))
|
||||
_transparency = float(t.get("transparency", 1.0))
|
||||
_child_transparency = float(t.get("child_transparency", 1.0))
|
||||
_frosted_glass_enabled = bool(t.get("frosted_glass_enabled", False))
|
||||
_frosted_blur_radius = float(t.get("frosted_blur_radius", 8.0))
|
||||
_frosted_tint_intensity = float(t.get("frosted_tint_intensity", 0.1))
|
||||
_frosted_opacity = float(t.get("frosted_opacity", 1.0))
|
||||
|
||||
@@ -3,33 +3,48 @@ from unittest.mock import MagicMock
|
||||
from src import theme_2 as theme
|
||||
|
||||
def test_theme_apply_sets_rounding_and_padding(monkeypatch):
|
||||
# Mock imgui
|
||||
mock_style = MagicMock()
|
||||
mock_imgui = MagicMock()
|
||||
mock_imgui.get_style.return_value = mock_style
|
||||
mock_imgui.ImVec2.side_effect = lambda x, y: (x, y)
|
||||
monkeypatch.setattr(theme, "imgui", mock_imgui)
|
||||
# Mock imgui
|
||||
mock_style = MagicMock()
|
||||
mock_imgui = MagicMock()
|
||||
mock_imgui.get_style.return_value = mock_style
|
||||
mock_imgui.ImVec2.side_effect = lambda x, y: (x, y)
|
||||
monkeypatch.setattr(theme, "imgui", mock_imgui)
|
||||
|
||||
# Call apply with the default palette
|
||||
theme.apply("ImGui Dark")
|
||||
# Call apply with the default palette
|
||||
theme.apply("ImGui Dark")
|
||||
|
||||
# Verify subtle rounding styles
|
||||
assert mock_style.window_rounding == 6.0
|
||||
assert mock_style.child_rounding == 4.0
|
||||
assert mock_style.frame_rounding == 4.0
|
||||
assert mock_style.popup_rounding == 4.0
|
||||
assert mock_style.scrollbar_rounding == 12.0
|
||||
assert mock_style.grab_rounding == 4.0
|
||||
assert mock_style.tab_rounding == 4.0
|
||||
# Verify subtle rounding styles
|
||||
assert mock_style.window_rounding == 6.0
|
||||
assert mock_style.child_rounding == 4.0
|
||||
assert mock_style.frame_rounding == 4.0
|
||||
assert mock_style.popup_rounding == 4.0
|
||||
assert mock_style.scrollbar_rounding == 12.0
|
||||
assert mock_style.grab_rounding == 4.0
|
||||
assert mock_style.tab_rounding == 4.0
|
||||
|
||||
# Verify borders
|
||||
assert mock_style.window_border_size == 1.0
|
||||
assert mock_style.frame_border_size == 1.0
|
||||
assert mock_style.popup_border_size == 1.0
|
||||
# Verify borders
|
||||
assert mock_style.window_border_size == 1.0
|
||||
assert mock_style.frame_border_size == 1.0
|
||||
assert mock_style.popup_border_size == 1.0
|
||||
|
||||
# Verify padding/spacing
|
||||
assert mock_style.window_padding == (8.0, 8.0)
|
||||
assert mock_style.frame_padding == (8.0, 4.0)
|
||||
assert mock_style.item_spacing == (8.0, 4.0)
|
||||
assert mock_style.item_inner_spacing == (4.0, 4.0)
|
||||
assert mock_style.scrollbar_size == 14.0
|
||||
# Verify padding/spacing
|
||||
assert mock_style.window_padding == (8.0, 8.0)
|
||||
assert mock_style.frame_padding == (8.0, 4.0)
|
||||
assert mock_style.item_spacing == (8.0, 4.0)
|
||||
assert mock_style.item_inner_spacing == (4.0, 4.0)
|
||||
assert mock_style.scrollbar_size == 14.0
|
||||
|
||||
def test_frosted_glass_enabled_toggle():
|
||||
theme.set_frosted_glass_enabled(True)
|
||||
assert theme.get_frosted_glass_enabled() is True
|
||||
theme.set_frosted_glass_enabled(False)
|
||||
assert theme.get_frosted_glass_enabled() is False
|
||||
|
||||
def test_theme_config_frosted_glass():
|
||||
config = {"theme": {"frosted_glass_enabled": True}}
|
||||
theme.load_from_config(config)
|
||||
assert theme.get_frosted_glass_enabled() is True
|
||||
|
||||
new_config = {}
|
||||
theme.save_to_config(new_config)
|
||||
assert new_config["theme"]["frosted_glass_enabled"] is True
|
||||
|
||||
Reference in New Issue
Block a user