Fix gizmo checkbox contrast; align Texture Displacement styling and panel refresh behavior (#16076)

* Fix gizmo checkbox styling and Texture Displacement resize

Use shared BBL checkboxes in Texture Displacement and restore white toolbar checkmarks so other gizmos keep proper checkbox contrast. Also fix Texture Displacement resizing only after mouse movement by requesting additional frames while its layout is still changing.

* Fix gizmo checkbox styling and Texture Displacement resize

Use shared BBL checkboxes in Texture Displacement and restore white toolbar checkmarks so other gizmos keep proper checkbox contrast. Also fix Texture Displacement resizing only after mouse movement by requesting additional frames while its layout is still changing.

* Update GLGizmoTextureDisplacement.cpp

---------

Co-authored-by: yw4z <ywsyildiz@gmail.com>
This commit is contained in:
Kiss Lorand
2026-10-03 03:12:31 +03:00
committed by GitHub
co-authored by yw4z
parent 1241dd5521
commit c15361097f
2 changed files with 43 additions and 43 deletions
@@ -5151,7 +5151,7 @@ void GLGizmoTextureDisplacement::render_debug_stage_panel(ModelVolume *mv)
m_imgui->scaled(20.f));
ImGui::SameLine();
ImGui::Checkbox(_u8L("Check topology").c_str(), &m_debug_check_topology);
m_imgui->bbl_checkbox(_L("Check topology"), m_debug_check_topology);
if (ImGui::IsItemHovered())
m_imgui->tooltip(_u8L("Count open and non-manifold edges after each stage, which is how a stage "
"that tore the mesh is spotted. It scans every edge, so it adds noticeably "
@@ -5341,6 +5341,8 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
GizmoImguiBegin(get_name(), flags);
ensure_panel_icons();
process_uv_commands(); // clicks from the UV editor pane, run here where the GL context is current
const float previous_body_h = m_panel_body_h;
const float previous_footer_h = m_panel_footer_h;
// Pinned every frame while Standard is active, so what Preview shows is always what Bake will do.
if (!pro_mode() && apply_standard_mode_presets(mv))
@@ -5362,20 +5364,16 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
const float card_pad = std::round(m_imgui->scaled(0.55f));
const float wrap_w = m_imgui->scaled(20.f);
const ImVec4 orca = ImGuiWrapper::COL_ORCA;
const ImVec4 col_link = dark ? ImVec4(0.30f, 0.71f, 0.67f, 1.f) : ImVec4(0.f, 0.47f, 0.42f, 1.f);
const ImVec4 col_frame = dark ? ImVec4(0.212f, 0.212f, 0.235f, 1.f) : ImVec4(0.808f, 0.808f, 0.808f, 1.f);
const ImU32 col_card = dark ? IM_COL32(255, 255, 255, 10) : IM_COL32(0, 0, 0, 12);
const ImU32 col_line = dark ? IM_COL32(255, 255, 255, 18) : IM_COL32(0, 0, 0, 23);
const ImVec4 col_link = ImGuiWrapper::COL_ORCA;
const ImVec4 col_frame = ImGui::GetStyleColorVec4(ImGuiCol_Separator);
const ImU32 col_card = ImGui::GetColorU32(ImGuiCol_Text, dark ? 0.045f : 0.047f);
const ImU32 col_line = ImGui::GetColorU32(ImGuiCol_Text, dark ? 0.08f : 0.09f);
const ImU32 col_sep = ImGui::GetColorU32(ImGuiCol_Separator);
// Combo drop-downs otherwise inherit ImGui's near-black default popup background; under the light
// theme that leaves the dark item text unreadable ("the dropbox is black"). Pushed only around each
// Combo below (never around a tooltip, whose own near-black default is what makes it readable).
const ImVec4 combo_popup_bg = dark ? ImVec4(0.18f, 0.18f, 0.19f, 1.f) : ImVec4(0.93f, 0.93f, 0.93f, 1.f);
const auto scoped_combo = [&](const char *id, int *v, const char *const items[], int n) {
ImGui::PushStyleColor(ImGuiCol_PopupBg, combo_popup_bg);
ImGuiWrapper::push_combo_style(m_parent.get_scale());
const bool changed = ImGui::Combo(id, v, items, n);
ImGui::PopStyleColor();
ImGuiWrapper::pop_combo_style();
return changed;
};
const auto hover_tip = [&](const auto &text) {
@@ -5782,10 +5780,10 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
wf_toggle = true;
const std::string auto_label = _u8L("Auto");
const float auto_w = frame_h + style.ItemInnerSpacing.x + ImGui::CalcTextSize(auto_label.c_str()).x;
const float auto_w = frame_h * 0.78f /*ratio from BBLCheckbox*/ + style.ItemInnerSpacing.x + ImGui::CalcTextSize(auto_label.c_str()).x;
ImGui::SameLine();
ImGui::SetCursorPosX(std::max(ImGui::GetCursorPosX(), ImGui::GetWindowContentRegionMax().x - auto_w));
if (ImGui::Checkbox((auto_label + "##auto_update").c_str(), &m_auto_update) && m_auto_update)
if (m_imgui->bbl_checkbox(wxString::FromUTF8(auto_label) + "##auto_update", m_auto_update) && m_auto_update)
rebuild_preview(); // catch up anything that changed while it was off
hover_tip(_u8L("Rebuilds the preview as soon as anything changes. Turn it off on a heavy model if painting "
"or dragging a slider starts to stutter - the preview then waits until you let go."));
@@ -6020,7 +6018,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
"costs fine detail."));
// Edge fade: the relief flattens toward the boundary of the painted area.
m_preview_params_dirty |= ImGui::Checkbox((_u8L("Edge fade") + "##edge_smoothing").c_str(), &layer.edge_smoothing);
m_preview_params_dirty |= m_imgui->bbl_checkbox(_L("Edge fade") + "##edge_smoothing", layer.edge_smoothing);
hover_tip(_u8L("Flattens the relief as it approaches the edge of the painted area, so it "
"blends into the bare surface instead of stopping at a step."));
ImGui::SameLine();
@@ -6035,7 +6033,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
// Invert and Colours share a row.
{
const float x0 = ImGui::GetCursorPosX();
m_preview_params_dirty |= ImGui::Checkbox(_u8L("Invert").c_str(), &layer.invert);
m_preview_params_dirty |= m_imgui->bbl_checkbox(_L("Invert"), layer.invert);
hover_tip(_u8L("Turns the relief inside out: what stood out is cut in, and the other way "
"round. The same as using a negative of the image."));
ImGui::SameLine();
@@ -6047,7 +6045,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
const bool has_color = decode_height_texture(layer).has_color();
bool color_enabled = layer.color_enabled && has_color;
m_imgui->disabled_begin(!has_color);
if (ImGui::Checkbox(_u8L("Colours").c_str(), &color_enabled)) {
if (m_imgui->bbl_checkbox(_L("Colours"), color_enabled)) {
layer.color_enabled = color_enabled;
m_preview_params_dirty = true;
}
@@ -6065,7 +6063,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
// under whichever layer turned colour on.
if (color_enabled) {
TextureDisplacementOptions &opts = mv->texture_displacement_options;
if (ImGui::Checkbox(_u8L("Mix filaments").c_str(), &opts.color_mix_enabled))
if (m_imgui->bbl_checkbox(_L("Mix filaments"), opts.color_mix_enabled))
m_preview_params_dirty = true;
hover_tip(_u8L("Interleaves two filaments to fake the colours in between, so a handful "
"of filaments can cover a photo or a gradient. An image of flat colours "
@@ -6184,7 +6182,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
"a slide projector. Faces turned away from you stretch, so line the view up with "
"the surface you care about first."));
if (ImGui::Checkbox(_u8L("Project only on visible").c_str(), &m_project_only_visible)) {
if (m_imgui->bbl_checkbox(_L("Project only on visible"), m_project_only_visible)) {
if (m_project_only_visible && select_visible_faces() == 0)
show_error(nullptr, _u8L("Nothing is visible from this angle - turn the model to face the "
"part you want to project onto."));
@@ -6195,7 +6193,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
"behind anything - and projects onto those. Replaces what the layer had painted."));
bool projector_open = m_projector_frame != nullptr && m_projector_frame->IsShown();
if (ImGui::Checkbox(_u8L("Projection frame").c_str(), &projector_open))
if (m_imgui->bbl_checkbox(_L("Projection frame"), projector_open))
show_projector(projector_open);
hover_tip(_u8L("Opens a window you drag over the model. Whatever you can see through it is what "
"gets the texture, and its border becomes the edge of the projection."));
@@ -6236,7 +6234,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
// Tile, and how it repeats.
{
const float x0 = ImGui::GetCursorPosX();
m_preview_params_dirty |= ImGui::Checkbox((_u8L("Tile") + "##tile_enabled").c_str(), &layer.tile_enabled);
m_preview_params_dirty |= m_imgui->bbl_checkbox(_L("Tile") + "##tile_enabled", layer.tile_enabled);
hover_tip(_u8L("Repeats the texture across the painted area. Off places one copy, like a decal, "
"at the size set by Tile size."));
ImGui::SameLine();
@@ -6424,7 +6422,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
const ImVec2 mn(mouse.x - inner - 0.5f * grip_w, mouse.y - 0.5f * row_h);
const ImVec2 mx(mn.x + (content_rx - list_x), mn.y + row_h);
fg->AddRectFilled(ImVec2(mn.x + 2.f, mn.y + 4.f), ImVec2(mx.x + 2.f, mx.y + 4.f), IM_COL32(0, 0, 0, 70), rounding);
fg->AddRectFilled(mn, mx, dark ? IM_COL32(0x3a, 0x3a, 0x40, 245) : IM_COL32(255, 255, 255, 245), rounding);
fg->AddRectFilled(mn, mx, ImGui::GetColorU32(ImGuiCol_WindowBg, 245.f / 255.f), rounding);
fg->AddRect(mn, mx, ImGui::GetColorU32(orca), rounding, 0, 1.5f);
float x = mn.x + inner;
@@ -6463,7 +6461,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
ImGui::Separator();
heading(_L("Subdivision"));
if (ImGui::Checkbox(_u8L("Only painted area (adaptive)").c_str(), &m_subdivide_adaptive)) {
if (m_imgui->bbl_checkbox(_L("Only painted area (adaptive)"), m_subdivide_adaptive)) {
if (m_subdivide_editing)
rebuild_subdivide_preview(); // switch the wireframe between the uniform and adaptive result
m_parent.set_as_dirty();
@@ -6494,7 +6492,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
m_parent.set_as_dirty();
};
if (ImGui::Checkbox(_u8L("Follow texture detail").c_str(), &m_subdivide_feature))
if (m_imgui->bbl_checkbox(_L("Follow texture detail"), m_subdivide_feature))
preview_live();
hover_tip(_u8L("Spends the triangles where the texture actually bends - packed along ridges and edges, "
"sparse over flat ground - instead of spreading them evenly. The same detail for fewer "
@@ -6621,7 +6619,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
hover_tip(_u8L("Triangle size the whole model is rebuilt with, in millimetres. Displacement works best on an "
"even mesh; this is what makes one out of an uneven import."));
ImGui::Checkbox((_u8L("Keep sharp edges") + "##remesh_sharp").c_str(), &m_remesh_keep_sharp_edges);
m_imgui->bbl_checkbox(_L("Keep sharp edges") + "##remesh_sharp", m_remesh_keep_sharp_edges);
hover_tip(_u8L("Holds hard edges and open borders in place while the rest is remeshed. Without it "
"the remesher slides vertices along the surface and rounds every crisp edge off - "
"a cube comes back with wobbly edges."));
@@ -6648,12 +6646,12 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
ImGui::Separator();
heading(_L("Result"));
m_preview_params_dirty |= ImGui::Checkbox(_u8L("Displace up to the border").c_str(), &opts.displace_border);
m_preview_params_dirty |= m_imgui->bbl_checkbox(_L("Displace up to the border"), opts.displace_border);
hover_tip(_u8L("Lets the relief run right to the edge of the painted area. Turn it off to hold that "
"outer ring flat, which keeps the displacement strictly inside your paint but flattens "
"the pattern at the border."));
m_preview_params_dirty |= ImGui::Checkbox(_u8L("Smooth result").c_str(), &opts.smooth_enabled);
m_preview_params_dirty |= m_imgui->bbl_checkbox(_L("Smooth result"), opts.smooth_enabled);
hover_tip(_u8L("Smooths the geometry after the texture has been applied, to take the hard steps out of a "
"low-resolution image. Only what the displacement moved is touched. The Smoothing slider "
"on a layer is a different thing: it blurs the image before it is used."));
@@ -6670,7 +6668,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
hover_tip(_u8L("How many smoothing passes to run. More passes spread the smoothing further across "
"the surface; Strength decides how much each one moves."));
m_preview_params_dirty |= ImGui::Checkbox(_u8L("Ignore outer ring").c_str(), &opts.smooth_skip_border);
m_preview_params_dirty |= m_imgui->bbl_checkbox(_L("Ignore outer ring"), opts.smooth_skip_border);
hover_tip(_u8L("Keeps the outer ring of the painted area out of the smoothing. Its neighbours "
"outside the paint never move, so smoothing it drags the relief down and leaves the "
"pattern half-melted at the border."));
@@ -6695,7 +6693,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
// The classic path is the opt-in: the one-run pipeline is the default, and its resolution
// control lives in the footer next to Bake (see below).
bool classic = !opts.pipeline_v2;
if (ImGui::Checkbox(_u8L("Experimental: classic bake pipeline").c_str(), &classic)) {
if (m_imgui->bbl_checkbox(_L("Experimental: classic bake pipeline"), classic)) {
opts.pipeline_v2 = !classic;
m_preview_params_dirty = true;
}
@@ -6724,13 +6722,13 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
if (SHOW_PIPELINE_DEV_CONTROLS && opts.pipeline_v2) {
// Keeping the relief above the plate is not a checkbox: it is unconditional, in both pipelines
// (see build_texture_displacement()).
m_preview_params_dirty |= ImGui::Checkbox(_u8L("Align mesh to texture edges").c_str(), &opts.v2_relocate);
m_preview_params_dirty |= m_imgui->bbl_checkbox(_L("Align mesh to texture edges"), opts.v2_relocate);
hover_tip(_u8L("Slide vertices sideways onto the edges in the texture before displacing them. "
"Displacement can only move vertices up and down, so without this a sharp step "
"in the image lands wherever the triangles happen to be and comes out as a "
"staircase. Moving the vertices onto the step first gives a straight wall at the "
"same triangle count."));
m_preview_params_dirty |= ImGui::Checkbox(_u8L("Clean up slivers").c_str(), &opts.v2_regularize);
m_preview_params_dirty |= m_imgui->bbl_checkbox(_L("Clean up slivers"), opts.v2_regularize);
hover_tip(_u8L("Collapse the thin triangles refinement inherits from the model's own "
"tessellation, before displacement samples them. A sliver's three corners "
"land on three unrelated parts of the texture, which is what makes the "
@@ -6810,7 +6808,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
// a fixed value, seeded with the recommendation so it starts from something sensible.
bool auto_res = opts.v2_refine_mm <= 0.f;
m_imgui->disabled_begin(busy);
if (ImGui::Checkbox("##v2auto", &auto_res)) {
if (m_imgui->bbl_checkbox(wxString::FromUTF8("##v2auto"), auto_res)) {
if (auto_res) {
opts.v2_refine_mm = 0.f;
opts.v2_max_triangles_k = -1;
@@ -6908,11 +6906,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
const std::string bake_label = m_prepare_in_progress ? _u8L("Preparing...") :
m_bake_in_progress ? _u8L("Baking...") :
into_u8(m_desc.at("bake"));
ImGui::PushStyleColor(ImGuiCol_Button, orca);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGuiWrapper::COL_ORCA_HOVER);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, orca);
ImGui::PushStyleColor(ImGuiCol_Border, orca);
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f));
GLGizmoUtils::push_orca_button_style();
m_imgui->push_bold_font();
m_imgui->disabled_begin(!can_bake);
if (ImGui::Button((bake_label + "##bake").c_str(), ImVec2(x0 + panel_w - ImGui::GetCursorPosX(), button_h))) {
@@ -6925,7 +6919,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
}
m_imgui->disabled_end();
m_imgui->pop_bold_font();
ImGui::PopStyleColor(5);
GLGizmoUtils::pop_orca_button_style();
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
m_imgui->tooltip(mv != nullptr && !mv->is_texture_displacement_painted() ?
(m_seam_edit_mode ? _u8L("Nothing is painted yet. The UV editor's seam tool is on, so "
@@ -6964,7 +6958,17 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
}
}
m_panel_footer_h = ImGui::GetCursorScreenPos().y - footer_top;
constexpr float resize_epsilon = 0.5f;
const float content_bottom = ImGui::GetCursorPosY() - style.ItemSpacing.y;
const float window_bottom = ImGui::GetWindowContentRegionMax().y;
const bool outer_window_needs_fit = content_bottom < window_bottom - resize_epsilon ||
(content_bottom > window_bottom + resize_epsilon &&
ImGui::GetWindowHeight() < ImGui::GetMainViewport()->Size.y -
2.f * style.DisplaySafeAreaPadding.y - resize_epsilon);
if (std::abs(m_panel_body_h - previous_body_h) > resize_epsilon ||
std::abs(m_panel_footer_h - previous_footer_h) > resize_epsilon || outer_window_needs_fit) {
m_parent.request_extra_frame();
}
GizmoImguiEnd();
ImGuiWrapper::pop_toolbar_style();
+1 -5
View File
@@ -2656,11 +2656,7 @@ void ImGuiWrapper::push_toolbar_style(const float scale)
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 1.00f)); // 10
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 0.00f)); // 11
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, COL_GREEN_LIGHT); // 12
// The checkbox/radio frame behind this is drawn fully transparent (see FrameBg above,
// alpha 0), showing the light window background through it - a white check mark there is
// invisible. Dark mode doesn't have this problem (its window background is dark), so only
// this branch needs a check mark color with real contrast against a light background.
ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(0.f, 156 / 255.f, 136 / 255.f, 1.00f));//13
ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.00f, 1.00f, 1.00f, 1.00f));//13
ImGui::PushStyleColor(ImGuiCol_ScrollbarGrab, ImVec4(0.42f, 0.42f, 0.42f, 1.00f));
ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabHovered, ImVec4(0.93f, 0.93f, 0.93f, 1.00f));
ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabActive, ImVec4(0.93f, 0.93f, 0.93f, 1.00f));