Skip to content

Commit b41ddd3

Browse files
committed
Add transparency checkerboard and BG override
Configurable transparency checkerboard and image-window background override. Adds UI controls (show transparency, check size, light/dark colors, override background color) in the preview window and a main-menu toggle. Implements drawing of the background and tiled checkerboard (draw_image_window_background) and computes effective background color from style presets or override. Persist/load new preferences (check size, colors, bg override) and add defaults in imiv_style. Clamp validation updated for new fields and transparency colors. Small cleanups: headers/includes and helper accessors. Signed-off-by: Vlad <shaamaan@gmail.com>
1 parent d7a81fa commit b41ddd3

8 files changed

Lines changed: 256 additions & 17 deletions

File tree

src/imiv/imiv_aux_windows.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ namespace {
6868
ui.offset = 0.0f;
6969
}
7070

71+
ImVec4 preview_theme_background_color(const PlaceholderUiState& ui)
72+
{
73+
return default_image_window_background_color(
74+
sanitize_app_style_preset(ui.style_preset));
75+
}
76+
7177
} // namespace
7278

7379
void
@@ -263,6 +269,38 @@ draw_preview_window(PlaceholderUiState& ui, bool& show_window,
263269
ImGui::EndTable();
264270
}
265271

272+
const ImGuiColorEditFlags color_flags
273+
= ImGuiColorEditFlags_Float | ImGuiColorEditFlags_DisplayRGB;
274+
ImGui::Separator();
275+
if (ImGui::CollapsingHeader("Transparency")) {
276+
ImGui::Checkbox("Show checkerboard", &ui.show_transparency);
277+
ImGui::SliderInt("Check size", &ui.transparency_check_size, 4, 128,
278+
"%d px");
279+
ImGui::ColorEdit4("Light checks", &ui.transparency_light_color.x,
280+
color_flags);
281+
ImGui::ColorEdit4("Dark checks", &ui.transparency_dark_color.x,
282+
color_flags);
283+
284+
ImVec4 theme_background_color = preview_theme_background_color(ui);
285+
bool bg_override = ui.image_window_bg_override;
286+
if (ImGui::Checkbox("Override image background", &bg_override)
287+
&& bg_override) {
288+
ui.image_window_bg_color = theme_background_color;
289+
}
290+
ui.image_window_bg_override = bg_override;
291+
292+
ImVec4 background_color = ui.image_window_bg_override
293+
? ui.image_window_bg_color
294+
: theme_background_color;
295+
ImGui::BeginDisabled(!ui.image_window_bg_override);
296+
if (ImGui::ColorEdit4("Image background", &background_color.x,
297+
color_flags)
298+
&& ui.image_window_bg_override) {
299+
ui.image_window_bg_color = background_color;
300+
}
301+
ImGui::EndDisabled();
302+
}
303+
266304
ImGui::EndChild();
267305
clamp_placeholder_ui_state(ui);
268306
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 3.0f);
@@ -579,7 +617,7 @@ namespace {
579617
const char* stored_preference = (requested_backend == BackendKind::Auto)
580618
? "Auto"
581619
: backend_display_name(
582-
requested_backend);
620+
requested_backend);
583621
table_labeled_row("Stored preference");
584622
draw_right_aligned_text(stored_preference);
585623

src/imiv/imiv_image_view.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88
#include "imiv_parse.h"
99
#include "imiv_probe_overlay.h"
1010
#include "imiv_renderer.h"
11+
#include "imiv_style.h"
1112
#include "imiv_test_engine.h"
1213
#include "imiv_ui_metrics.h"
1314

1415
#include <algorithm>
16+
#include <cmath>
1517
#include <cstdlib>
1618
#include <string>
1719
#include <vector>
@@ -67,6 +69,82 @@ namespace {
6769
out_max.y = std::max(out_min.y, out_max.y);
6870
}
6971

72+
ImVec4 effective_image_window_bg_color(const PlaceholderUiState& ui_state)
73+
{
74+
if (ui_state.image_window_bg_override)
75+
return ui_state.image_window_bg_color;
76+
return default_image_window_background_color(
77+
sanitize_app_style_preset(ui_state.style_preset));
78+
}
79+
80+
void draw_image_window_background(ImDrawList* draw_list,
81+
const PlaceholderUiState& ui_state,
82+
const ImageCoordinateMap& coord_map,
83+
const ImVec2& image_rect_min,
84+
const ImVec2& image_rect_max)
85+
{
86+
if (draw_list == nullptr)
87+
return;
88+
89+
draw_list->AddRectFilled(coord_map.viewport_rect_min,
90+
coord_map.viewport_rect_max,
91+
ImGui::ColorConvertFloat4ToU32(
92+
effective_image_window_bg_color(ui_state)));
93+
if (!ui_state.show_transparency)
94+
return;
95+
96+
const ImVec2 checker_min(std::max(coord_map.viewport_rect_min.x,
97+
image_rect_min.x),
98+
std::max(coord_map.viewport_rect_min.y,
99+
image_rect_min.y));
100+
const ImVec2 checker_max(std::min(coord_map.viewport_rect_max.x,
101+
image_rect_max.x),
102+
std::min(coord_map.viewport_rect_max.y,
103+
image_rect_max.y));
104+
if (checker_max.x <= checker_min.x || checker_max.y <= checker_min.y)
105+
return;
106+
107+
const float tile_size = static_cast<float>(
108+
std::max(1, ui_state.transparency_check_size));
109+
const float origin_x = coord_map.viewport_rect_min.x;
110+
const float origin_y = coord_map.viewport_rect_min.y;
111+
const int start_col = static_cast<int>(
112+
std::floor((checker_min.x - origin_x) / tile_size));
113+
const int end_col = static_cast<int>(
114+
std::ceil((checker_max.x - origin_x) / tile_size));
115+
const int start_row = static_cast<int>(
116+
std::floor((checker_min.y - origin_y) / tile_size));
117+
const int end_row = static_cast<int>(
118+
std::ceil((checker_max.y - origin_y) / tile_size));
119+
const ImU32 light_color = ImGui::ColorConvertFloat4ToU32(
120+
ui_state.transparency_light_color);
121+
const ImU32 dark_color = ImGui::ColorConvertFloat4ToU32(
122+
ui_state.transparency_dark_color);
123+
124+
draw_list->AddRectFilled(checker_min, checker_max, light_color);
125+
for (int row = start_row; row < end_row; ++row) {
126+
const float y0 = origin_y + static_cast<float>(row) * tile_size;
127+
const float y1 = y0 + tile_size;
128+
const float clipped_y0 = std::max(y0, checker_min.y);
129+
const float clipped_y1 = std::min(y1, checker_max.y);
130+
if (clipped_y1 <= clipped_y0)
131+
continue;
132+
for (int col = start_col; col < end_col; ++col) {
133+
if (((row + col) & 1) == 0)
134+
continue;
135+
const float x0 = origin_x + static_cast<float>(col) * tile_size;
136+
const float x1 = x0 + tile_size;
137+
const float clipped_x0 = std::max(x0, checker_min.x);
138+
const float clipped_x1 = std::min(x1, checker_max.x);
139+
if (clipped_x1 <= clipped_x0)
140+
continue;
141+
draw_list->AddRectFilled(ImVec2(clipped_x0, clipped_y0),
142+
ImVec2(clipped_x1, clipped_y1),
143+
dark_color);
144+
}
145+
}
146+
}
147+
70148
} // namespace
71149

72150
void
@@ -222,6 +300,9 @@ draw_image_window_contents(ViewerState& viewer, PlaceholderUiState& ui_state,
222300
image_canvas_active = ImGui::IsItemActive();
223301
register_layout_dump_synthetic_item("image", "Image");
224302
ImDrawList* draw_list = ImGui::GetWindowDrawList();
303+
draw_image_window_background(draw_list, ui_state, coord_map,
304+
coord_map.image_rect_min,
305+
coord_map.image_rect_max);
225306
draw_list->PushClipRect(coord_map.viewport_rect_min,
226307
coord_map.viewport_rect_max, true);
227308
draw_list->AddImage(main_texture_ref, coord_map.image_rect_min,

src/imiv/imiv_menu.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ draw_viewer_main_menu(ViewerState& viewer, PlaceholderUiState& ui_state,
297297
actions.toggle_requested = true;
298298
ImGui::MenuItem("Show display/data window borders", nullptr,
299299
&ui_state.show_window_guides);
300+
ImGui::MenuItem("Transparency", nullptr, &ui_state.show_transparency);
300301
ImGui::Separator();
301302

302303
if (ImGui::MenuItem("Zoom In", "Ctrl++", false, has_image))

src/imiv/imiv_persistence.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,10 @@ namespace {
154154
apply_bool_pref(value, ui_state.auto_mipmap);
155155
} else if (key == "fit_image_to_window") {
156156
apply_bool_pref(value, ui_state.fit_image_to_window);
157+
} else if (key == "show_transparency") {
158+
apply_bool_pref(value, ui_state.show_transparency);
159+
} else if (key == "image_window_bg_override") {
160+
apply_bool_pref(value, ui_state.image_window_bg_override);
157161
} else if (key == "show_mouse_mode_selector") {
158162
apply_bool_pref(value, ui_state.show_mouse_mode_selector);
159163
} else if (key == "full_screen_mode") {
@@ -176,6 +180,8 @@ namespace {
176180
apply_int_pref(value, ui_state.closeup_pixels);
177181
} else if (key == "closeup_avg_pixels") {
178182
apply_int_pref(value, ui_state.closeup_avg_pixels);
183+
} else if (key == "transparency_check_size") {
184+
apply_int_pref(value, ui_state.transparency_check_size);
179185
} else if (key == "current_channel") {
180186
apply_int_pref(value, viewer.recipe.current_channel);
181187
} else if (key == "color_mode") {
@@ -192,6 +198,30 @@ namespace {
192198
apply_float_pref(value, viewer.recipe.gamma);
193199
} else if (key == "offset") {
194200
apply_float_pref(value, viewer.recipe.offset);
201+
} else if (key == "transparency_light_r") {
202+
apply_float_pref(value, ui_state.transparency_light_color.x);
203+
} else if (key == "transparency_light_g") {
204+
apply_float_pref(value, ui_state.transparency_light_color.y);
205+
} else if (key == "transparency_light_b") {
206+
apply_float_pref(value, ui_state.transparency_light_color.z);
207+
} else if (key == "transparency_light_a") {
208+
apply_float_pref(value, ui_state.transparency_light_color.w);
209+
} else if (key == "transparency_dark_r") {
210+
apply_float_pref(value, ui_state.transparency_dark_color.x);
211+
} else if (key == "transparency_dark_g") {
212+
apply_float_pref(value, ui_state.transparency_dark_color.y);
213+
} else if (key == "transparency_dark_b") {
214+
apply_float_pref(value, ui_state.transparency_dark_color.z);
215+
} else if (key == "transparency_dark_a") {
216+
apply_float_pref(value, ui_state.transparency_dark_color.w);
217+
} else if (key == "image_window_bg_r") {
218+
apply_float_pref(value, ui_state.image_window_bg_color.x);
219+
} else if (key == "image_window_bg_g") {
220+
apply_float_pref(value, ui_state.image_window_bg_color.y);
221+
} else if (key == "image_window_bg_b") {
222+
apply_float_pref(value, ui_state.image_window_bg_color.z);
223+
} else if (key == "image_window_bg_a") {
224+
apply_float_pref(value, ui_state.image_window_bg_color.w);
195225
} else if (key == "ocio_display") {
196226
viewer.recipe.ocio_display = strip_to_string(value);
197227
} else if (key == "ocio_view") {
@@ -234,6 +264,10 @@ namespace {
234264
output << "auto_mipmap=" << (ui_state.auto_mipmap ? 1 : 0) << "\n";
235265
output << "fit_image_to_window="
236266
<< (ui_state.fit_image_to_window ? 1 : 0) << "\n";
267+
output << "show_transparency=" << (ui_state.show_transparency ? 1 : 0)
268+
<< "\n";
269+
output << "image_window_bg_override="
270+
<< (ui_state.image_window_bg_override ? 1 : 0) << "\n";
237271
output << "show_mouse_mode_selector="
238272
<< (ui_state.show_mouse_mode_selector ? 1 : 0) << "\n";
239273
output << "full_screen_mode=" << (ui_state.full_screen_mode ? 1 : 0)
@@ -250,6 +284,8 @@ namespace {
250284
<< "\n";
251285
output << "closeup_pixels=" << ui_state.closeup_pixels << "\n";
252286
output << "closeup_avg_pixels=" << ui_state.closeup_avg_pixels << "\n";
287+
output << "transparency_check_size=" << ui_state.transparency_check_size
288+
<< "\n";
253289
output << "current_channel=" << viewer.recipe.current_channel << "\n";
254290
output << "color_mode=" << viewer.recipe.color_mode << "\n";
255291
output << "subimage_index=" << ui_state.subimage_index << "\n";
@@ -258,6 +294,30 @@ namespace {
258294
output << "exposure=" << viewer.recipe.exposure << "\n";
259295
output << "gamma=" << viewer.recipe.gamma << "\n";
260296
output << "offset=" << viewer.recipe.offset << "\n";
297+
output << "transparency_light_r=" << ui_state.transparency_light_color.x
298+
<< "\n";
299+
output << "transparency_light_g=" << ui_state.transparency_light_color.y
300+
<< "\n";
301+
output << "transparency_light_b=" << ui_state.transparency_light_color.z
302+
<< "\n";
303+
output << "transparency_light_a=" << ui_state.transparency_light_color.w
304+
<< "\n";
305+
output << "transparency_dark_r=" << ui_state.transparency_dark_color.x
306+
<< "\n";
307+
output << "transparency_dark_g=" << ui_state.transparency_dark_color.y
308+
<< "\n";
309+
output << "transparency_dark_b=" << ui_state.transparency_dark_color.z
310+
<< "\n";
311+
output << "transparency_dark_a=" << ui_state.transparency_dark_color.w
312+
<< "\n";
313+
output << "image_window_bg_r=" << ui_state.image_window_bg_color.x
314+
<< "\n";
315+
output << "image_window_bg_g=" << ui_state.image_window_bg_color.y
316+
<< "\n";
317+
output << "image_window_bg_b=" << ui_state.image_window_bg_color.z
318+
<< "\n";
319+
output << "image_window_bg_a=" << ui_state.image_window_bg_color.w
320+
<< "\n";
261321
output << "ocio_display=" << viewer.recipe.ocio_display << "\n";
262322
output << "ocio_view=" << viewer.recipe.ocio_view << "\n";
263323
output << "ocio_image_color_space="

src/imiv/imiv_style.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,38 @@ apply_imgui_app_style(AppStylePreset preset)
7575
apply_imgui_style_defaults();
7676
}
7777

78+
ImVec4
79+
default_image_window_background_color(AppStylePreset preset)
80+
{
81+
switch (preset) {
82+
case AppStylePreset::IvLight:
83+
case AppStylePreset::ImGuiLight: return ImVec4(0.86f, 0.86f, 0.86f, 1.00f);
84+
case AppStylePreset::IvDark:
85+
case AppStylePreset::ImGuiDark:
86+
case AppStylePreset::ImGuiClassic:
87+
return ImVec4(0.10f, 0.10f, 0.10f, 1.00f);
88+
}
89+
return ImVec4(0.10f, 0.10f, 0.10f, 1.00f);
90+
}
91+
92+
ImVec4
93+
default_image_window_transparency_light_color()
94+
{
95+
return ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
96+
}
97+
98+
ImVec4
99+
default_image_window_transparency_dark_color()
100+
{
101+
return ImVec4(0.18f, 0.18f, 0.18f, 1.00f);
102+
}
103+
104+
int
105+
default_image_window_transparency_check_size()
106+
{
107+
return 16;
108+
}
109+
78110
void
79111
StyleColorsIvDark()
80112
{

src/imiv/imiv_style.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#pragma once
66

7+
#include <imgui.h>
8+
79
namespace Imiv {
810

911
enum class AppStylePreset : int {
@@ -28,5 +30,13 @@ void
2830
StyleColorsIvDark();
2931
void
3032
StyleColorsIvLight();
33+
ImVec4
34+
default_image_window_background_color(AppStylePreset preset);
35+
ImVec4
36+
default_image_window_transparency_light_color();
37+
ImVec4
38+
default_image_window_transparency_dark_color();
39+
int
40+
default_image_window_transparency_check_size();
3141

3242
} // namespace Imiv

src/imiv/imiv_viewer.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,12 @@ clamp_placeholder_ui_state(PlaceholderUiState& ui_state)
185185
}
186186
return std::clamp(clamped, min_value, max_value);
187187
};
188+
auto clamp_color = [](ImVec4& color) {
189+
color.x = std::clamp(color.x, 0.0f, 1.0f);
190+
color.y = std::clamp(color.y, 0.0f, 1.0f);
191+
color.z = std::clamp(color.z, 0.0f, 1.0f);
192+
color.w = std::clamp(color.w, 0.0f, 1.0f);
193+
};
188194

189195
if (ui_state.max_memory_ic_mb < 64)
190196
ui_state.max_memory_ic_mb = 64;
@@ -194,6 +200,8 @@ clamp_placeholder_ui_state(PlaceholderUiState& ui_state)
194200
ui_state.closeup_avg_pixels = clamp_odd(ui_state.closeup_avg_pixels, 3, 25);
195201
if (ui_state.closeup_avg_pixels > ui_state.closeup_pixels)
196202
ui_state.closeup_avg_pixels = ui_state.closeup_pixels;
203+
ui_state.transparency_check_size
204+
= std::clamp(ui_state.transparency_check_size, 4, 128);
197205
if (ui_state.mouse_mode < 0)
198206
ui_state.mouse_mode = 0;
199207
if (ui_state.mouse_mode > 4)
@@ -210,6 +218,9 @@ clamp_placeholder_ui_state(PlaceholderUiState& ui_state)
210218
= std::clamp(ui_state.ocio_config_source,
211219
static_cast<int>(OcioConfigSource::Global),
212220
static_cast<int>(OcioConfigSource::User));
221+
clamp_color(ui_state.transparency_light_color);
222+
clamp_color(ui_state.transparency_dark_color);
223+
clamp_color(ui_state.image_window_bg_color);
213224
}
214225

215226

0 commit comments

Comments
 (0)