From 7bd5b906ee1f8b94fd1d7406c35416e03826e0a7 Mon Sep 17 00:00:00 2001 From: trailcode Date: Wed, 20 May 2026 19:12:18 -0600 Subject: [PATCH 1/5] Shape list right click del. --- CHANGELOG.md | 1 + src/gui.cpp | 25 +++++++++++++------------ src/gui.h | 4 ++++ src/gui_mode.cpp | 15 +++++++++++++++ src/gui_settings.cpp | 6 ++++++ src/occt_view.cpp | 41 +++++++++++++++++++++++++---------------- src/occt_view.h | 3 +++ usage.md | 2 +- 8 files changed, 68 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b1329b..e8a6d1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- **Inspection mode** (Normal): **Options -> Orthographic projection** (under **Selection**) toggles an orthographic camera (persisted as `gui.inspection_orthographic`). Sketch modes still force orthographic as before. - **Settings** (3D view grid) and saved **`occt_view`** JSON: configure Open CASCADE rectangular grid **step** (uniform X/Y), plus **graphic display extent X/Y** and **Z offset** (`V3d_RectangularGrid::SetGraphicValues`). Bundled **`res/ezycad_settings.json`** includes defaults for those keys. - **Keyboard zoom:** **NumPad +** / **NumPad -**, main **-**, and **Shift+=** (US **+**) zoom the 3D view in steps equal to **one mouse wheel tick** at the cursor (same internal scaling as scroll). diff --git a/src/gui.cpp b/src/gui.cpp index 99f1a76..8ac2ec8 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -1785,6 +1785,8 @@ void GUI::shape_list_() const float mat_popup_w = std::min(440.0f, std::max(280.0f, mat_label_w_max + st_mat.WindowPadding.x * 2.0f + st_mat.FramePadding.x * 2.0f + st_mat.ScrollbarSize + 8.0f)); + Shp_ptr shape_to_delete; + std::unordered_set selected_in_viewer; for (const AIS_Shape_ptr& ais : m_view->get_selected()) if (!ais.IsNull()) @@ -1844,15 +1846,11 @@ void GUI::shape_list_() if (ImGui::InputText("", name_buffer, sizeof(name_buffer))) shape->set_name(std::string(name_buffer)); - if (ImGui::BeginPopupContextItem("shape_name_mat")) + if (ImGui::BeginPopupContextItem("shape_name_ctx")) { - if (ImGui::BeginMenu("Material")) - { - for (int i = 0; i < nmat; ++i) - if (ImGui::MenuItem(mat_names[static_cast(i)].c_str(), nullptr, i == mat_idx)) - apply_shape_material(i); - ImGui::EndMenu(); - } + if (ImGui::MenuItem("Delete")) + shape_to_delete = shape; + ImGui::EndPopup(); } @@ -1889,7 +1887,7 @@ void GUI::shape_list_() ImGui::PopStyleVar(); if (m_show_tool_tips && ImGui::IsItemHovered()) - ImGui::SetTooltip("%s\n(right-click name: Material menu)", mat_names[static_cast(mat_idx)].c_str()); + ImGui::SetTooltip("%s\n(click: material; right-click name: Delete)", mat_names[static_cast(mat_idx)].c_str()); ImGui::SetNextWindowSize(ImVec2(mat_popup_w, 0.0f), ImGuiCond_Appearing); if (ImGui::BeginPopup("mat_pick")) @@ -1915,9 +1913,8 @@ void GUI::shape_list_() if (ImGui::BeginPopupContextItem("mat_btn_ctx")) { - for (int i = 0; i < nmat; ++i) - if (ImGui::MenuItem(mat_names[static_cast(i)].c_str(), nullptr, i == mat_idx)) - apply_shape_material(i); + if (ImGui::MenuItem("Delete")) + shape_to_delete = shape; ImGui::EndPopup(); } @@ -1932,6 +1929,10 @@ void GUI::shape_list_() ImGui::SetTooltip("Selected in 3D viewer"); } } + + if (shape_to_delete) + m_view->delete_shapes({shape_to_delete}); + ImGui::EndChild(); ImGui::End(); } diff --git a/src/gui.h b/src/gui.h index 7c9d8e7..69f5ac0 100644 --- a/src/gui.h +++ b/src/gui.h @@ -101,6 +101,9 @@ class GUI float edge_dim_arrow_size() const { return m_edge_dim_arrow_size; } bool get_hide_all_shapes() const { return m_hide_all_shapes; } void set_hide_all_shapes(bool hide) { m_hide_all_shapes = hide; } + /// Orthographic camera in Inspection mode (Mode::Normal); persisted as `gui.inspection_orthographic`. + bool inspection_orthographic() const { return m_inspection_orthographic; } + void set_inspection_orthographic(bool v) { m_inspection_orthographic = v; } bool get_dark_mode() const { return m_dark_mode; } ImVec4 get_clear_color() const; void set_mode(Mode mode); // gui_mode.cpp @@ -283,6 +286,7 @@ class GUI double m_view_roll_step_deg = k_gui_view_roll_step_deg_default; /// Multiplier for `UpdateZoom(Aspect_ScrollDelta(..., int(y * scale)))`; persisted in `gui.view_zoom_scroll_scale`. double m_view_zoom_scroll_scale = k_gui_view_zoom_scroll_scale_default; + bool m_inspection_orthographic = false; std::vector m_toolbar_buttons; // Message status window diff --git a/src/gui_mode.cpp b/src/gui_mode.cpp index 9bb008e..0b3a270 100644 --- a/src/gui_mode.cpp +++ b/src/gui_mode.cpp @@ -556,6 +556,7 @@ void GUI::options_normal_mode_() }; float label_col_w = ImGui::CalcTextSize("Selection Mode").x; + label_col_w = std::max(label_col_w, ImGui::CalcTextSize("Orthographic projection").x); label_col_w += ImGui::GetStyle().CellPadding.x * 2.0f + 8.0f; ImGui::TextUnformatted("Selection"); @@ -589,6 +590,20 @@ void GUI::options_normal_mode_() ImGui::EndTooltip(); } + bool ortho = m_inspection_orthographic; + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + right_aligned_label("Orthographic projection"); + ImGui::TableSetColumnIndex(1); + if (ImGui::Checkbox("##inspection_orthographic", &ortho)) + { + m_inspection_orthographic = ortho; + save_occt_view_settings(); + m_view->apply_camera_projection(); + } + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Use an orthographic camera while in Inspection mode (no perspective foreshortening)."); + ImGui::EndTable(); } diff --git a/src/gui_settings.cpp b/src/gui_settings.cpp index 4fed347..411f541 100644 --- a/src/gui_settings.cpp +++ b/src/gui_settings.cpp @@ -51,6 +51,7 @@ std::string GUI::occt_view_settings_json() const {"edge_dim_arrow_size", m_edge_dim_arrow_size}, {"view_roll_step_deg", m_view_roll_step_deg}, {"view_zoom_scroll_scale", m_view_zoom_scroll_scale}, + {"inspection_orthographic", m_inspection_orthographic}, {"snap_guide_color", [&]() { @@ -99,6 +100,7 @@ void GUI::save_occt_view_settings() {"imgui_rounding_tabs", m_imgui_rounding_tabs}, {"view_roll_step_deg", m_view_roll_step_deg}, {"view_zoom_scroll_scale", m_view_zoom_scroll_scale}, + {"inspection_orthographic", m_inspection_orthographic}, {"snap_guide_color", [&]() { @@ -269,6 +271,10 @@ void GUI::parse_gui_panes_settings_(const std::string& content) ", " + std::to_string(k_gui_view_roll_step_deg_max) + "], got " + std::to_string(v) + "; using default."); } + m_inspection_orthographic = b("inspection_orthographic", false); + if (m_view) + m_view->apply_camera_projection(); + m_view_zoom_scroll_scale = k_gui_view_zoom_scroll_scale_default; if (g.contains("view_zoom_scroll_scale") && g["view_zoom_scroll_scale"].is_number()) { diff --git a/src/occt_view.cpp b/src/occt_view.cpp index 5aeb6aa..a300d57 100644 --- a/src/occt_view.cpp +++ b/src/occt_view.cpp @@ -1048,12 +1048,16 @@ void Occt_view::sketch_face_extrude(const ScreenCoords& screen_coords, bool is_m m_shp_extrude.sketch_face_extrude(screen_coords, is_mouse_move); } -void Occt_view::delete_selected() +void Occt_view::delete_selected() { delete_shapes(get_selected()); } + +void Occt_view::delete_shapes(std::vector to_delete) { + if (to_delete.empty()) + return; + push_undo_snapshot(); remove_selected_length_dimensions_from_sketches_(); - auto selected = get_selected(); - delete_(selected); + delete_(to_delete); cancel(Set_parent_mode::No); // In case we are in the middle of a operation. } @@ -1412,6 +1416,23 @@ bool Occt_view::is_headless() const { return m_headless_view; } // Mode related Mode Occt_view::get_mode() const { return m_gui.get_mode(); } +void Occt_view::apply_camera_projection() +{ + if (is_headless()) + return; + + const bool ortho = is_sketch_mode(get_mode()) || (get_mode() == Mode::Normal && m_gui.inspection_orthographic()); + + Graphic3d_Camera_ptr camera = m_view->Camera(); + if (ortho) + camera->SetProjectionType(Graphic3d_Camera::Projection_Orthographic); + else + camera->SetProjectionType(Graphic3d_Camera::Projection_Perspective); + + m_view->Redraw(); + m_ctx->UpdateCurrentViewer(); +} + void Occt_view::on_mode() { DBG_MSG(c_mode_strs[int(get_mode())]); @@ -1441,10 +1462,8 @@ void Occt_view::on_mode() } }; - bool ortho = false; if (is_sketch_mode(get_mode())) { - ortho = true; for (auto shp : m_shps) shp->set_visible(false); @@ -1486,17 +1505,7 @@ void Occt_view::on_mode() shp->set_visible(true); } - if (!is_headless()) - { - Graphic3d_Camera_ptr camera = m_view->Camera(); - if (ortho) - camera->SetProjectionType(Graphic3d_Camera::Projection_Orthographic); - else - camera->SetProjectionType(Graphic3d_Camera::Projection_Perspective); - - m_view->Redraw(); - m_ctx->UpdateCurrentViewer(); - } + apply_camera_projection(); } void Occt_view::on_chamfer_mode() diff --git a/src/occt_view.h b/src/occt_view.h index 86242ec..d67da04 100644 --- a/src/occt_view.h +++ b/src/occt_view.h @@ -104,6 +104,8 @@ class Occt_view : protected AIS_ViewController // Mode related. void on_mode(); + /// Updates camera perspective/orthographic from current mode and Inspection-mode option. + void apply_camera_projection(); void on_chamfer_mode(); void on_fillet_mode(); Mode get_mode() const; @@ -112,6 +114,7 @@ class Occt_view : protected AIS_ViewController // Delete related. void delete_selected(); + void delete_shapes(std::vector to_delete); void delete_(std::vector& to_delete); // Member function to delete variable arguments diff --git a/usage.md b/usage.md index 16818a5..234c399 100644 --- a/usage.md +++ b/usage.md @@ -58,7 +58,7 @@ EzyCad (Easy CAD) is a CAD application for hobbyist machinists to design and edi 5. **Options Panel** - Adjust tool parameters; related controls are grouped by headings (for example **Sketch options**, **Extrude**, **Selection**, **Material**, **Polar duplicate**), depending on the active tool. - - **Normal** mode: **Selection** is the 3D pick filter. **Material** is the document preset for new solids that do not inherit from a clicked shape (for example toolbar **Box**, **polar duplicate** output). **Face extrude** reads the same preset in its Options **Material** row. + - **Normal** mode (Inspection): **Selection** is the 3D pick filter and **Orthographic projection** toggles the camera (saved in settings). **Material** is the document preset for new solids that do not inherit from a clicked shape (for example toolbar **Box**, **polar duplicate** output). **Face extrude** reads the same preset in its Options **Material** row. - To change material on a solid already in the scene, use the [Shape List](#shape-list). - **Chamfer** and **Fillet**: distance and mode only; the result solid keeps the **source shape's material**. - **Move**, **Rotate**, and **Scale**: transform options only (no material row there). From 814495c41b71d60eebd7c5274d621e981e41882e Mon Sep 17 00:00:00 2001 From: trailcode Date: Wed, 20 May 2026 19:34:45 -0600 Subject: [PATCH 2/5] UI verbosity --- CHANGELOG.md | 1 + res/ezycad_settings.json | 1 + src/gui.cpp | 194 +++++++++++++++++--------------- src/gui.h | 21 +++- src/gui_mode.cpp | 39 ++++--- src/gui_settings.cpp | 232 ++++++++++++++++++++++++--------------- usage-settings.md | 20 ++-- 7 files changed, 303 insertions(+), 205 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8a6d1e..6c2b97a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- **Settings -> UI verbosity** (`gui.ui_verbosity`): cumulative control over optional panes/menus (odd steps) and tooltips/inline help (even steps). Default **6** matches the previous full UI; **0** is minimal. - **Inspection mode** (Normal): **Options -> Orthographic projection** (under **Selection**) toggles an orthographic camera (persisted as `gui.inspection_orthographic`). Sketch modes still force orthographic as before. - **Settings** (3D view grid) and saved **`occt_view`** JSON: configure Open CASCADE rectangular grid **step** (uniform X/Y), plus **graphic display extent X/Y** and **Z offset** (`V3d_RectangularGrid::SetGraphicValues`). Bundled **`res/ezycad_settings.json`** includes defaults for those keys. diff --git a/res/ezycad_settings.json b/res/ezycad_settings.json index 2cc1901..8723e8f 100644 --- a/res/ezycad_settings.json +++ b/res/ezycad_settings.json @@ -13,6 +13,7 @@ "show_lua_console": true, "show_options": true, "show_python_console": true, + "ui_verbosity": 6, "view_roll_step_deg": 45.0, "view_zoom_scroll_scale": 4.0, "show_settings_dialog": true, diff --git a/src/gui.cpp b/src/gui.cpp index 8ac2ec8..e10c7ee 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -201,13 +201,16 @@ void GUI::menu_bar_() save_file_dialog_(); } - if (ImGui::MenuItem("Import")) - import_file_dialog_(); - - if (ImGui::MenuItem("Sketch underlay image...")) + if (ui_show_feature(2)) { - m_underlay_import_sketch_target.reset(); - sketch_underlay_import_dialog_(); + if (ImGui::MenuItem("Import")) + import_file_dialog_(); + + if (ImGui::MenuItem("Sketch underlay image...")) + { + m_underlay_import_sketch_target.reset(); + sketch_underlay_import_dialog_(); + } } if (ImGui::BeginMenu("Export")) @@ -227,7 +230,7 @@ void GUI::menu_bar_() ImGui::EndMenu(); } - if (ImGui::BeginMenu("Examples")) + if (ui_show_feature(2) && ImGui::BeginMenu("Examples")) { for (const Example_file& ex : m_example_files) if (ImGui::MenuItem(ex.label.c_str())) @@ -279,7 +282,7 @@ void GUI::menu_bar_() m_view->add_box(0, 0, 0, scale, scale, scale); } - if (ImGui::MenuItem("Add box_prms")) + if (ui_show_feature(3) && ImGui::MenuItem("Add box_prms")) { m_add_box_origin = glm::dvec3(0.0, 0.0, 0.0); m_add_box_size = glm::dvec3(1.0, 1.0, 1.0); @@ -292,7 +295,7 @@ void GUI::menu_bar_() m_view->add_pyramid(0, 0, 0, scale); } - if (ImGui::MenuItem("Add pyramid_prms")) + if (ui_show_feature(3) && ImGui::MenuItem("Add pyramid_prms")) { m_add_pyramid_origin = glm::dvec3(0.0, 0.0, 0.0); m_add_pyramid_side = 1.0; @@ -305,7 +308,7 @@ void GUI::menu_bar_() m_view->add_sphere(0, 0, 0, scale); } - if (ImGui::MenuItem("Add sphere_prms")) + if (ui_show_feature(3) && ImGui::MenuItem("Add sphere_prms")) { m_add_sphere_origin = glm::dvec3(0.0, 0.0, 0.0); m_add_sphere_radius = 1.0; @@ -318,7 +321,7 @@ void GUI::menu_bar_() m_view->add_cylinder(0, 0, 0, scale, scale); } - if (ImGui::MenuItem("Add cylinder_prms")) + if (ui_show_feature(3) && ImGui::MenuItem("Add cylinder_prms")) { m_add_cylinder_origin = glm::dvec3(0.0, 0.0, 0.0); m_add_cylinder_radius = m_add_cylinder_height = 1.0; @@ -331,7 +334,7 @@ void GUI::menu_bar_() m_view->add_cone(0, 0, 0, scale, 0.0, scale); } - if (ImGui::MenuItem("Add cone_prms")) + if (ui_show_feature(3) && ImGui::MenuItem("Add cone_prms")) { m_add_cone_origin = glm::dvec3(0.0, 0.0, 0.0); m_add_cone_R1 = 1.0; @@ -346,7 +349,7 @@ void GUI::menu_bar_() m_view->add_torus(0, 0, 0, scale, scale / 2.0); } - if (ImGui::MenuItem("Add torus_prms")) + if (ui_show_feature(3) && ImGui::MenuItem("Add torus_prms")) { m_add_torus_origin = glm::dvec3(0.0, 0.0, 0.0); m_add_torus_R1 = 1.0; @@ -366,43 +369,49 @@ void GUI::menu_bar_() save_panes = true; } - if (ImGui::MenuItem("Options", nullptr, m_show_options)) + if (ui_show_feature(1)) { - m_show_options = !m_show_options; - save_panes = true; - } + if (ImGui::MenuItem("Options", nullptr, m_show_options)) + { + m_show_options = !m_show_options; + save_panes = true; + } - if (ImGui::MenuItem("Sketch List", nullptr, m_show_sketch_list)) - { - m_show_sketch_list = !m_show_sketch_list; - save_panes = true; - } + if (ImGui::MenuItem("Sketch List", nullptr, m_show_sketch_list)) + { + m_show_sketch_list = !m_show_sketch_list; + save_panes = true; + } - if (ImGui::MenuItem("Shape List", nullptr, m_show_shape_list)) - { - m_show_shape_list = !m_show_shape_list; - save_panes = true; - } + if (ImGui::MenuItem("Shape List", nullptr, m_show_shape_list)) + { + m_show_shape_list = !m_show_shape_list; + save_panes = true; + } - if (ImGui::MenuItem("Log", nullptr, m_log_window_visible)) - { - m_log_window_visible = !m_log_window_visible; - save_panes = true; + if (ImGui::MenuItem("Log", nullptr, m_log_window_visible)) + { + m_log_window_visible = !m_log_window_visible; + save_panes = true; + } } - if (ImGui::MenuItem("Lua Console", nullptr, m_show_lua_console)) + if (ui_show_feature(2)) { - m_show_lua_console = !m_show_lua_console; - save_panes = true; - } + if (ImGui::MenuItem("Lua Console", nullptr, m_show_lua_console)) + { + m_show_lua_console = !m_show_lua_console; + save_panes = true; + } - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Interactive Lua prompt and res/scripts/lua editors."); + if (ui_show_help(2) && ImGui::IsItemHovered()) + ImGui::SetTooltip("Interactive Lua prompt and res/scripts/lua editors."); - if (ImGui::MenuItem("Python Console", nullptr, m_show_python_console)) - { - m_show_python_console = !m_show_python_console; - save_panes = true; + if (ImGui::MenuItem("Python Console", nullptr, m_show_python_console)) + { + m_show_python_console = !m_show_python_console; + save_panes = true; + } } #ifndef NDEBUG if (ImGui::MenuItem("Debug", nullptr, m_show_dbg)) @@ -680,7 +689,7 @@ void GUI::toolbar_() } } - if (m_show_tool_tips && ImGui::IsItemHovered()) + if (ui_show_help(1) && ImGui::IsItemHovered()) ImGui::SetTooltip("%s", m_toolbar_buttons[i].tooltip); if (was_active) @@ -959,7 +968,7 @@ void GUI::sketch_list_inspector_(Sketch& sketch, int index) ImGui::SetNextItemWidth(86.f); if (ImGui::InputDouble("##dim_offset", &offset, 0.5, 2.0, "%.2f")) sketch.set_dimension_offset(i, offset); - if (m_show_tool_tips && ImGui::IsItemHovered()) + if (ui_show_help(2) && ImGui::IsItemHovered()) ImGui::SetTooltip("Label offset from edge. 0 = automatic."); ImGui::PopID(); @@ -981,7 +990,7 @@ void GUI::sketch_list_inspector_(Sketch& sketch, int index) } void GUI::sketch_list_() { - if (!m_show_sketch_list) + if (!show_sketch_list_effective()) return; const ImGuiStyle& st = ImGui::GetStyle(); @@ -1022,14 +1031,17 @@ void GUI::sketch_list_() const Sketch* sk_key = sketch.get(); bool& expanded = m_sketch_list_expanded[sk_key]; - ImGui::PushID(("expand" + id_suffix).c_str()); - if (ImGui::SmallButton(expanded ? "v" : ">")) - expanded = !expanded; - if (m_show_tool_tips && ImGui::IsItemHovered()) - ImGui::SetTooltip(expanded ? "Collapse details" : "Expand details"); - ImGui::PopID(); + if (ui_show_feature(2)) + { + ImGui::PushID(("expand" + id_suffix).c_str()); + if (ImGui::SmallButton(expanded ? "v" : ">")) + expanded = !expanded; + if (ui_show_help(2) && ImGui::IsItemHovered()) + ImGui::SetTooltip(expanded ? "Collapse details" : "Expand details"); + ImGui::PopID(); - ImGui::SameLine(); + ImGui::SameLine(); + } // Radio button for selection ImGui::PushID(("select" + id_suffix).c_str()); @@ -1039,7 +1051,7 @@ void GUI::sketch_list_() set_mode(Mode::Sketch_inspection_mode); } - if (m_show_tool_tips && ImGui::IsItemHovered()) + if (ui_show_help(2) && ImGui::IsItemHovered()) ImGui::SetTooltip("Sets current"); ImGui::PopID(); @@ -1068,7 +1080,7 @@ void GUI::sketch_list_() if (ImGui::Checkbox("", &visible)) sketch->set_visible(visible); - if (m_show_tool_tips && ImGui::IsItemHovered()) + if (ui_show_help(2) && ImGui::IsItemHovered()) ImGui::SetTooltip("Visibility"); ImGui::PopID(); @@ -1093,25 +1105,28 @@ void GUI::sketch_list_() if (!has_ul) ImGui::EndDisabled(); - if (m_show_tool_tips && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) + if (ui_show_help(2) && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) ImGui::SetTooltip(has_ul ? "Display underlay" : "Import an image in Sketch properties to enable the underlay."); } ImGui::PopID(); - ImGui::SameLine(); - ImGui::PushID(("props" + id_suffix).c_str()); - if (ImGui::SmallButton("[P]")) + if (ui_show_feature(2)) { - m_sketch_properties_sketch = sketch; - m_sketch_properties_open = true; - } + ImGui::SameLine(); + ImGui::PushID(("props" + id_suffix).c_str()); + if (ImGui::SmallButton("[P]")) + { + m_sketch_properties_sketch = sketch; + m_sketch_properties_open = true; + } - if (m_show_tool_tips && ImGui::IsItemHovered()) - ImGui::SetTooltip("Sketch properties"); + if (ui_show_help(2) && ImGui::IsItemHovered()) + ImGui::SetTooltip("Sketch properties"); - ImGui::PopID(); + ImGui::PopID(); + } - if (expanded) + if (expanded && ui_show_feature(2)) sketch_list_inspector_(*sketch, index); ++index; @@ -1260,16 +1275,19 @@ void GUI::sketch_underlay_panel_settings_(const Sketch::sptr& sk) m_underlay_panel_sketch = nullptr; } - ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); - ImGui::TextDisabled("(?)"); - if (ImGui::IsItemHovered()) + if (ui_show_help(2)) { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::TextDisabled("Import PNG/JPEG/BMP as a sketch underlay. Adjust half-width, half-height, center, and rotation " - "to match real dimensions; changes apply in real time."); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextDisabled("Import PNG/JPEG/BMP as a sketch underlay. Adjust half-width, half-height, center, and rotation " + "to match real dimensions; changes apply in real time."); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } } if (!sk->has_underlay()) @@ -1278,14 +1296,14 @@ void GUI::sketch_underlay_panel_settings_(const Sketch::sptr& sk) if (ImGui::Checkbox("White paper -> transparent", &m_underlay_key_white)) sk->underlay_set_key_white_transparent(m_underlay_key_white); - if (m_show_tool_tips && ImGui::IsItemHovered()) + if (ui_show_help(2) && ImGui::IsItemHovered()) ImGui::SetTooltip("Uses brightness: white background becomes clear; dark lines stay visible. " "Turn off for full-color photos. Inverting the image is not needed for typical scans."); if (ImGui::Checkbox("Tint visible lines", &m_underlay_line_tint)) sk->underlay_set_line_tint_enabled(m_underlay_line_tint); - if (m_show_tool_tips && ImGui::IsItemHovered()) + if (ui_show_help(2) && ImGui::IsItemHovered()) ImGui::SetTooltip("Paints non-transparent pixels (after white key) with the line color. " "Default yellow reads well on dark backgrounds."); @@ -1304,7 +1322,7 @@ void GUI::sketch_underlay_panel_settings_(const Sketch::sptr& sk) if (ImGui::SliderFloat("Opacity", &m_underlay_opacity, 0.f, 1.f, "%.2f")) sk->underlay_set_opacity(m_underlay_opacity); - if (m_show_tool_tips && ImGui::IsItemHovered()) + if (ui_show_help(2) && ImGui::IsItemHovered()) ImGui::SetTooltip("Overall opacity of the underlay image (0 = fully transparent, 1 = fully opaque)."); ImGui::Separator(); @@ -1364,7 +1382,7 @@ void GUI::sketch_underlay_panel_settings_(const Sketch::sptr& sk) begin_underlay_calib_set_x_(sk); ImGui::EndDisabled(); - if (m_show_tool_tips && ImGui::IsItemHovered()) + if (ui_show_help(2) && ImGui::IsItemHovered()) ImGui::SetTooltip("Two clicks along width (+U), then type the real drawing distance (same units as sketch dimensions). " "You can use Set Y before or after; until both are set, the other axis still follows default aspect."); @@ -1374,7 +1392,7 @@ void GUI::sketch_underlay_panel_settings_(const Sketch::sptr& sk) begin_underlay_calib_set_y_(sk); ImGui::EndDisabled(); - if (m_show_tool_tips && ImGui::IsItemHovered()) + if (ui_show_help(2) && ImGui::IsItemHovered()) ImGui::SetTooltip( "Two clicks along height (+V), then enter the drawing distance for Y. Order vs. Set X does not matter."); @@ -1383,7 +1401,7 @@ void GUI::sketch_underlay_panel_settings_(const Sketch::sptr& sk) begin_underlay_calib_define_datum_(sk); ImGui::EndDisabled(); - if (m_show_tool_tips && ImGui::IsItemHovered()) + if (ui_show_help(2) && ImGui::IsItemHovered()) ImGui::SetTooltip("Two picks on the sketch plane: first sets bitmap corner (0,0); second sets the +U axis direction. " "Keeps current half width and height; aligns the image to your sketch datum."); } @@ -1392,7 +1410,7 @@ void GUI::sketch_underlay_panel_settings_(const Sketch::sptr& sk) ImGui::TextUnformatted("Transform (sketch plane, vs. current view)"); { const bool ul_ortho = sk->underlay_axes_orthogonal(); - if (!ul_ortho) + if (ui_show_help(3) && !ul_ortho) ImGui::TextWrapped( "Edge calibration produced shear (bitmap U and V are not perpendicular). These sliders only describe an " "orthogonal transform; they stay off so they cannot overwrite your calibrated affine."); @@ -1745,7 +1763,7 @@ bool GUI::try_underlay_calib_click_(const ScreenCoords& screen_coords) } void GUI::shape_list_() { - if (!m_show_shape_list) + if (!show_shape_list_effective()) return; float max_name_text_w = 0.f; @@ -1862,7 +1880,7 @@ void GUI::shape_list_() if (ImGui::Checkbox("", &visible)) shape->set_visible(visible); - if (m_show_tool_tips && ImGui::IsItemHovered()) + if (ui_show_help(2) && ImGui::IsItemHovered()) ImGui::SetTooltip("visibility"); ImGui::PopID(); @@ -1874,7 +1892,7 @@ void GUI::shape_list_() if (ImGui::Checkbox("", &shaded)) shape->set_disp_mode(shaded ? AIS_Shaded : AIS_WireFrame); - if (m_show_tool_tips && ImGui::IsItemHovered()) + if (ui_show_help(2) && ImGui::IsItemHovered()) ImGui::SetTooltip("solid/wire"); ImGui::PopID(); @@ -1886,7 +1904,7 @@ void GUI::shape_list_() ImGui::OpenPopup("mat_pick"); ImGui::PopStyleVar(); - if (m_show_tool_tips && ImGui::IsItemHovered()) + if (ui_show_help(2) && ImGui::IsItemHovered()) ImGui::SetTooltip("%s\n(click: material; right-click name: Delete)", mat_names[static_cast(mat_idx)].c_str()); ImGui::SetNextWindowSize(ImVec2(mat_popup_w, 0.0f), ImGuiCond_Appearing); @@ -1925,7 +1943,7 @@ void GUI::shape_list_() { ImGui::EndGroup(); ImGui::PopStyleColor(4); - if (m_show_tool_tips && ImGui::IsItemHovered()) + if (ui_show_help(2) && ImGui::IsItemHovered()) ImGui::SetTooltip("Selected in 3D viewer"); } } @@ -2037,7 +2055,7 @@ void GUI::log_message(const std::string& message) } void GUI::log_window_() { - if (!m_log_window_visible) + if (!log_window_visible_effective()) return; if (!ImGui::Begin("Log", &m_log_window_visible)) @@ -2063,7 +2081,7 @@ void GUI::log_window_() } void GUI::lua_console_() { - if (!m_show_lua_console) + if (!show_lua_console_effective()) return; if (!m_lua_console) m_lua_console = std::make_unique(this); @@ -2071,7 +2089,7 @@ void GUI::lua_console_() } void GUI::python_console_() { - if (!m_show_python_console) + if (!show_python_console_effective()) return; if (!m_python_console) diff --git a/src/gui.h b/src/gui.h index 69f5ac0..772e2fb 100644 --- a/src/gui.h +++ b/src/gui.h @@ -67,6 +67,11 @@ inline constexpr double k_gui_view_roll_step_deg_default = 45.0; inline constexpr double k_gui_view_zoom_scroll_scale_min = 0.25; inline constexpr double k_gui_view_zoom_scroll_scale_max = 64.0; inline constexpr double k_gui_view_zoom_scroll_scale_default = 4.0; +/// `gui.ui_verbosity`: 0 = minimal UI; odd steps unlock feature tiers; even steps unlock help tiers. +inline constexpr int k_gui_ui_verbosity_min = 0; +inline constexpr int k_gui_ui_verbosity_default = 6; +inline constexpr int k_gui_ui_feature_tier_max = 3; +inline constexpr int k_gui_ui_help_tier_max = 3; class GUI { public: @@ -123,6 +128,20 @@ class GUI void set_show_shape_list(bool v) { m_show_shape_list = v; } void set_log_window_visible(bool v) { m_log_window_visible = v; } void set_show_settings_dialog(bool v) { m_show_settings_dialog = v; } + int ui_verbosity() const { return m_ui_verbosity; } + void set_ui_verbosity(int v); + /// Cumulative feature depth from `gui.ui_verbosity` (F1 at verbosity >= 1). + int ui_feature_tier() const { return (m_ui_verbosity + 1) / 2; } + /// Cumulative help depth from `gui.ui_verbosity` (H1 at verbosity >= 2). + int ui_help_tier() const { return m_ui_verbosity / 2; } + bool ui_show_feature(int tier) const { return tier <= ui_feature_tier(); } + bool ui_show_help(int tier) const { return tier <= ui_help_tier(); } + bool show_options_effective() const { return m_show_options && ui_show_feature(1); } + bool show_sketch_list_effective() const { return m_show_sketch_list && ui_show_feature(1); } + bool show_shape_list_effective() const { return m_show_shape_list && ui_show_feature(1); } + bool log_window_visible_effective() const { return m_log_window_visible && ui_show_feature(1); } + bool show_lua_console_effective() const { return m_show_lua_console && ui_show_feature(2); } + bool show_python_console_effective() const { return m_show_python_console && ui_show_feature(2); } #ifndef NDEBUG void set_show_dbg(bool v) { m_show_dbg = v; } #endif @@ -346,7 +365,7 @@ class GUI int m_new_sketch_plane{0}; // 0=XY, 1=XZ, 2=YZ double m_new_sketch_offset{}; bool m_hide_all_shapes{false}; - bool m_show_tool_tips{true}; + int m_ui_verbosity{k_gui_ui_verbosity_default}; bool m_dark_mode{false}; #ifndef NDEBUG bool m_show_dbg{false}; diff --git a/src/gui_mode.cpp b/src/gui_mode.cpp index 0b3a270..a7d3d47 100644 --- a/src/gui_mode.cpp +++ b/src/gui_mode.cpp @@ -312,7 +312,7 @@ void GUI::on_key(int key, int scancode, int action, int mods) void GUI::options_() { - if (!m_show_options) + if (!show_options_effective()) return; if (!ImGui::Begin("Options", &m_show_options)) @@ -417,7 +417,7 @@ void GUI::options_() Sketch_nodes::set_snap_guide_mode(static_cast(i)); ImGui::EndCombo(); } - if (ImGui::IsItemHovered()) + if (ui_show_help(2) && ImGui::IsItemHovered()) ImGui::SetTooltip("Traditional: compact local snap marker.\n" "Fullscreen: full-view crosshair/axis guides.\n" "Both: show compact marker and fullscreen guides together."); @@ -447,7 +447,7 @@ void GUI::options_() } ImGui::EndCombo(); } - if (ImGui::IsItemHovered()) + if (ui_show_help(2) && ImGui::IsItemHovered()) ImGui::SetTooltip( "Where to place the numeric value along the dimension line (near the first or second end, center, or auto).\n" "This does not flip which side of the edge the dimension sits on.\n" @@ -514,16 +514,20 @@ void GUI::options_() case Mode::Sketch_add_multi_edges: ImGui::Separator(); ImGui::TextUnformatted("Shortcuts"); - ImGui::TextWrapped("TAB: type edge length. Shift+TAB: type angle (degrees, CCW from +X)."); + if (ui_show_help(3)) + ImGui::TextWrapped("TAB: type edge length. Shift+TAB: type angle (degrees, CCW from +X)."); break; case Mode::Sketch_add_node: ImGui::Separator(); ImGui::TextUnformatted("Shortcuts"); - ImGui::TextWrapped("TAB: type length along the rubber band. Shift+TAB: type angle (degrees, CCW from +X)."); - ImGui::TextWrapped( - "Snap the first click to an existing sketch point to start a rubber band, then click to place the node " - "(or press Enter after typing a length). An unsnapped click still places a single node immediately."); + if (ui_show_help(3)) + { + ImGui::TextWrapped("TAB: type length along the rubber band. Shift+TAB: type angle (degrees, CCW from +X)."); + ImGui::TextWrapped( + "Snap the first click to an existing sketch point to start a rubber band, then click to place the node " + "(or press Enter after typing a length). An unsnapped click still places a single node immediately."); + } break; default: @@ -580,14 +584,17 @@ void GUI::options_normal_mode_() ImGui::EndCombo(); } ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); - ImGui::TextDisabled("(?)"); - if (ImGui::IsItemHovered()) + if (ui_show_help(2)) { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::TextDisabled("Hotkeys: 1-9 (Normal mode) set filter when the 3D view has focus, not while typing in UI."); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextDisabled("Hotkeys: 1-9 (Normal mode) set filter when the 3D view has focus, not while typing in UI."); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } } bool ortho = m_inspection_orthographic; @@ -601,7 +608,7 @@ void GUI::options_normal_mode_() save_occt_view_settings(); m_view->apply_camera_projection(); } - if (ImGui::IsItemHovered()) + if (ui_show_help(2) && ImGui::IsItemHovered()) ImGui::SetTooltip("Use an orthographic camera while in Inspection mode (no perspective foreshortening)."); ImGui::EndTable(); diff --git a/src/gui_settings.cpp b/src/gui_settings.cpp index 411f541..0fa09e0 100644 --- a/src/gui_settings.cpp +++ b/src/gui_settings.cpp @@ -39,6 +39,11 @@ nlohmann::json build_occt_view_settings_object(const Occt_view& view) } } // namespace +void GUI::set_ui_verbosity(int v) +{ + m_ui_verbosity = std::max(k_gui_ui_verbosity_min, v); +} + std::string GUI::occt_view_settings_json() const { using nlohmann::json; @@ -60,6 +65,7 @@ std::string GUI::occt_view_settings_json() const return nlohmann::json::array({r, g, b}); }()}, {"snap_guide_mode", static_cast(Sketch_nodes::get_snap_guide_mode())}, + {"ui_verbosity", m_ui_verbosity}, }; return j.dump(2); } @@ -90,6 +96,7 @@ void GUI::save_occt_view_settings() {"dark_mode", m_dark_mode}, {"show_lua_console", m_show_lua_console}, {"show_python_console", m_show_python_console}, + {"ui_verbosity", m_ui_verbosity}, {"edge_dim_label_h", m_edge_dim_label_h}, {"edge_dim_line_width", m_edge_dim_line_width}, {"edge_dim_arrow_size", m_edge_dim_arrow_size}, @@ -210,6 +217,10 @@ void GUI::parse_gui_panes_settings_(const std::string& content) return v.get() != 0; return current; }; + m_ui_verbosity = k_gui_ui_verbosity_default; + if (g.contains("ui_verbosity") && g["ui_verbosity"].is_number_integer()) + m_ui_verbosity = std::max(k_gui_ui_verbosity_min, g["ui_verbosity"].get()); + set_show_options(b("show_options", true)); set_show_sketch_list(b("show_sketch_list", true)); set_show_shape_list(b("show_shape_list", true)); @@ -418,6 +429,14 @@ void GUI::settings_() constexpr float k_label_col_w = 230.f; + if (ImGui::SliderInt("UI verbosity", &m_ui_verbosity, k_gui_ui_verbosity_min, k_gui_ui_verbosity_default + 4, + "%d")) + save_occt_view_settings(); + m_ui_verbosity = std::max(k_gui_ui_verbosity_min, m_ui_verbosity); + if (ui_show_help(3)) + ImGui::TextWrapped("0 = minimal UI. Odd values add more controls and panes; even values add more help (tooltips and " + "hints). Higher values are reserved for future tiers."); + if (ImGui::Checkbox("Dark mode", &m_dark_mode)) save_occt_view_settings(); @@ -440,16 +459,19 @@ void GUI::settings_() save_occt_view_settings(); m_view_roll_step_deg = std::clamp(m_view_roll_step_deg, k_gui_view_roll_step_deg_min, k_gui_view_roll_step_deg_max); - if (ImGui::IsItemHovered()) + if (ui_show_help(2) && ImGui::IsItemHovered()) ImGui::SetTooltip("Degrees per key press: NumPad 8/2/4/6 orbit (like LMB drag), Shift+NumPad 4/6, Shift+4/6, or " "Shift+Left/Right roll. " "Ctrl+click the slider to type a value."); - ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); - if (ImGui::SmallButton("?##view_roll_help")) - open_url_("https://ezycad.readthedocs.io/en/latest/usage.html#view-roll"); - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Help: view roll (opens the online usage guide)."); + if (ui_show_help(3)) + { + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + if (ImGui::SmallButton("?##view_roll_help")) + open_url_("https://ezycad.readthedocs.io/en/latest/usage.html#view-roll"); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Help: view roll (opens the online usage guide)."); + } ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); @@ -470,21 +492,22 @@ void GUI::settings_() m_view_zoom_scroll_scale = std::clamp(m_view_zoom_scroll_scale, k_gui_view_zoom_scroll_scale_min, k_gui_view_zoom_scroll_scale_max); - if (ImGui::IsItemHovered()) + if (ui_show_help(2) && ImGui::IsItemHovered()) ImGui::SetTooltip("Multiplier for mouse wheel and +/- zoom (same as UpdateZoom scroll delta). " "Hold Shift while zooming for Blender-style finer steps (x0.1). Ctrl+click to type a value."); ImGui::EndTable(); } - ImGui::TextWrapped( - "NumPad 8 / 2 / 4 / 6 orbit the view (same axes as left-drag orbit). Hold Shift and press NumPad 4 or NumPad 6, " - "main 4 / 6, or Left / Right arrow for Blender-style roll around the screen Z axis (hold to repeat). " - "Num Lock off is recommended for numpad shortcuts (see usage.md View navigation). " - "Hold Shift while scrolling or pressing +/- for finer zoom."); + if (ui_show_help(3)) + ImGui::TextWrapped( + "NumPad 8 / 2 / 4 / 6 orbit the view (same axes as left-drag orbit). Hold Shift and press NumPad 4 or NumPad 6, " + "main 4 / 6, or Left / Right arrow for Blender-style roll around the screen Z axis (hold to repeat). " + "Num Lock off is recommended for numpad shortcuts (see usage.md View navigation). " + "Hold Shift while scrolling or pressing +/- for finer zoom."); } - if (ImGui::CollapsingHeader("UI corner rounding")) + if (ui_show_feature(3) && ImGui::CollapsingHeader("UI corner rounding")) { bool r_changed = false; if (ImGui::BeginTable("settings_rounding", 2, ImGuiTableFlags_SizingStretchProp)) @@ -506,14 +529,17 @@ void GUI::settings_() ImGui::TableSetColumnIndex(1); r_changed |= ImGui::SliderFloat("##round_scr", &m_imgui_rounding_scroll, 0.f, 16.f, "%.0f"); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); - ImGui::TextDisabled("(?)"); - if (ImGui::IsItemHovered()) + if (ui_show_help(2)) { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::TextDisabled("Scrollbars and sliders applies the same radius to scrollbar tracks and slider grabs."); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextDisabled("Scrollbars and sliders applies the same radius to scrollbar tracks and slider grabs."); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } } ImGui::TableNextRow(); @@ -578,7 +604,7 @@ void GUI::settings_() } } - if (ImGui::CollapsingHeader("3D view grid")) + if (ui_show_feature(3) && ImGui::CollapsingHeader("3D view grid")) { float g1[3], g2[3]; m_view->get_grid_colors(g1, g2); @@ -630,16 +656,19 @@ void GUI::settings_() ImGui::AlignTextToFramePadding(); ImGui::TextUnformatted("Grid extent X"); ImGui::SameLine(0.f, ImGui::GetStyle().ItemInnerSpacing.x); - ImGui::TextDisabled("(?)"); - if (ImGui::IsItemHovered()) + if (ui_show_help(2)) { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::TextUnformatted( - "Full width of the drawn grid on X (edge to edge through the center). Same length scale as sketch dimensions. " - "OCCT uses half this value internally."); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted( + "Full width of the drawn grid on X (edge to edge through the center). Same length scale as sketch dimensions. " + "OCCT uses half this value internally."); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } } ImGui::TableSetColumnIndex(1); if (ImGui::DragScalar("##ggx", ImGuiDataType_Double, &graphic_x_ui, spd_extent, nullptr, nullptr, "%.8g")) @@ -649,16 +678,19 @@ void GUI::settings_() ImGui::TableSetColumnIndex(0); ImGui::AlignTextToFramePadding(); ImGui::TextUnformatted("Grid extent Y"); - ImGui::SameLine(0.f, ImGui::GetStyle().ItemInnerSpacing.x); - ImGui::TextDisabled("(?)"); - if (ImGui::IsItemHovered()) + if (ui_show_help(2)) { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::TextUnformatted( - "Full height of the drawn grid on Y (edge to edge through the center). OCCT uses half this value internally."); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); + ImGui::SameLine(0.f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted( + "Full height of the drawn grid on Y (edge to edge through the center). OCCT uses half this value internally."); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } } ImGui::TableSetColumnIndex(1); if (ImGui::DragScalar("##ggy", ImGuiDataType_Double, &graphic_y_ui, spd_extent, nullptr, nullptr, "%.8g")) @@ -710,15 +742,18 @@ void GUI::settings_() m_edge_dim_line_width = lw; dim_lw_changed = true; } - ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); - ImGui::TextDisabled("(?)"); - if (ImGui::IsItemHovered()) + if (ui_show_help(2)) { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::TextDisabled("Thickness of sketch edge length dimensions (Open CASCADE line width scale; 1.0 = default)."); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextDisabled("Thickness of sketch edge length dimensions (Open CASCADE line width scale; 1.0 = default)."); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } } } @@ -734,15 +769,18 @@ void GUI::settings_() m_edge_dim_arrow_size = arrow; dim_arrow_changed = true; } - ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); - ImGui::TextDisabled("(?)"); - if (ImGui::IsItemHovered()) + if (ui_show_help(2)) { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::TextDisabled("Arrow head length for sketch and extrude length dimensions (Open CASCADE display units)."); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextDisabled("Arrow head length for sketch and extrude length dimensions (Open CASCADE display units)."); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } } } @@ -752,16 +790,19 @@ void GUI::settings_() ImGui::TextUnformatted("Underlay highlight color"); ImGui::TableSetColumnIndex(1); ul_changed |= ImGui::ColorEdit4("##underlay_hi", &m_underlay_highlight_color[0], ImGuiColorEditFlags_Float); - ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); - ImGui::TextDisabled("(?)"); - if (ImGui::IsItemHovered()) + if (ui_show_help(2)) { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::TextDisabled("Updates all sketch underlays immediately. Also used as the default when you import a new image. " - "Per-sketch overrides in Sketch List if needed."); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextDisabled("Updates all sketch underlays immediately. Also used as the default when you import a new image. " + "Per-sketch overrides in Sketch List if needed."); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } } ImGui::TableNextRow(); @@ -777,15 +818,18 @@ void GUI::settings_() Sketch_nodes::set_snap_guide_color(snap_col[0], snap_col[1], snap_col[2]); save_occt_view_settings(); } - ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); - ImGui::TextDisabled("(?)"); - if (ImGui::IsItemHovered()) + if (ui_show_help(2)) { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::TextDisabled("Color used by fullscreen snap guides and snap markers in sketch mode."); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextDisabled("Color used by fullscreen snap guides and snap markers in sketch mode."); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } } } @@ -844,7 +888,7 @@ void GUI::settings_() } } - if (ImGui::CollapsingHeader("Startup project")) + if (ui_show_feature(3) && ImGui::CollapsingHeader("Startup project")) { #ifndef __EMSCRIPTEN__ if (ImGui::BeginTable("settings_startup_native", 2, ImGuiTableFlags_SizingStretchProp)) @@ -858,19 +902,22 @@ void GUI::settings_() ImGui::TableSetColumnIndex(1); if (ImGui::Checkbox("##load_last", &m_load_last_opened_on_startup)) save_occt_view_settings(); - ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); - ImGui::TextDisabled("(?)"); - if (ImGui::IsItemHovered()) + if (ui_show_help(2)) { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::TextDisabled("When enabled, EzyCad opens the last .ezy file you opened (path is stored in settings)."); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextDisabled("When enabled, EzyCad opens the last .ezy file you opened (path is stored in settings)."); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } } ImGui::EndTable(); } - if (!m_last_opened_project_path.empty()) + if (ui_show_help(3) && !m_last_opened_project_path.empty()) ImGui::TextWrapped("Last opened path: %s", m_last_opened_project_path.c_str()); else ImGui::TextDisabled("(No path saved yet.)"); @@ -881,16 +928,19 @@ void GUI::settings_() ImGui::SameLine(); if (ImGui::Button("Clear saved startup")) clear_saved_startup_project_(); - ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); - ImGui::TextDisabled("(?)"); - if (ImGui::IsItemHovered()) + if (ui_show_help(2)) { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::TextDisabled("Save the current document (geometry, view, and tool mode) as what loads when EzyCad starts. " - "If none is saved, the install default (res/default.ezy) is used."); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextDisabled("Save the current document (geometry, view, and tool mode) as what loads when EzyCad starts. " + "If none is saved, the install default (res/default.ezy) is used."); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } } } diff --git a/usage-settings.md b/usage-settings.md index 9486d96..b9c2204 100644 --- a/usage-settings.md +++ b/usage-settings.md @@ -35,22 +35,23 @@ Visibility of these panes (and related flags) is persisted with the rest of your Open **View -> Settings**. The window title is **Settings**. -- **Dark mode** — checkbox at the top (not inside a collapsible section). +- **UI verbosity** — integer at the top (default **6**, full UI). **0** keeps a minimal layout (toolbar and 3D view, core **File**/**Edit**/**Help**, essential settings only). Each **odd** step unlocks more panes and menu items; each **even** step unlocks more tooltips and inline help. Values above **6** are stored for future tiers. Persisted as **`gui.ui_verbosity`**. +- **Dark mode** — checkbox below verbosity (not inside a collapsible section). - At the bottom: **Defaults** — reloads bundled defaults from the app `res/` tree (including ImGui layout from that file). -Between those, the pane has **six** collapsible sections. Expand a section to see its controls; when collapsed, only the section title bar is visible. +Between those, the pane has up to **six** collapsible sections (some appear only when **UI verbosity** is high enough). Expand a section to see its controls; when collapsed, only the section title bar is visible. -1. **3D view navigation** — **View rotation step** (degrees per key press for **NumPad 8**/**2**/**4**/**6** orbit and **Shift+NumPad 4**/**6** roll; default **45**; **`?`** opens [view roll](https://ezycad.readthedocs.io/en/latest/usage.html#view-roll) on Read the Docs). **Zoom scroll scale** (multiplier for wheel and **+**/**-** zoom; default **4**). Hold **Shift** while zooming for a Blender-style finer step (multiply by **0.1**). Numpad shortcuts are documented with **Num Lock off**; with **Num Lock on**, use main-row alternatives in [usage.md -> View navigation](usage.md#view-navigation). Stored as **`gui.view_roll_step_deg`** and **`gui.view_zoom_scroll_scale`**. See **[usage-occt-view.md](usage-occt-view.md)**. +1. **3D view navigation** (always at verbosity **0** and above) — **View rotation step** (degrees per key press for **NumPad 8**/**2**/**4**/**6** orbit and **Shift+NumPad 4**/**6** roll; default **45**; **`?`** opens [view roll](https://ezycad.readthedocs.io/en/latest/usage.html#view-roll) on Read the Docs). **Zoom scroll scale** (multiplier for wheel and **+**/**-** zoom; default **4**). Hold **Shift** while zooming for a Blender-style finer step (multiply by **0.1**). Numpad shortcuts are documented with **Num Lock off**; with **Num Lock on**, use main-row alternatives in [usage.md -> View navigation](usage.md#view-navigation). Stored as **`gui.view_roll_step_deg`** and **`gui.view_zoom_scroll_scale`**. See **[usage-occt-view.md](usage-occt-view.md)**. -2. **UI corner rounding** — Sliders **0** to **16** for **Windows, frames, popups**; **Scrollbars and sliders** (has `(?)`); **Tabs**. +2. **UI corner rounding** (verbosity **5**+) — Sliders **0** to **16** for **Windows, frames, popups**; **Scrollbars and sliders** (has `(?)` at higher help levels); **Tabs**. -3. **3D view background** — **Background color 1** and **Background color 2** (float RGB fields and swatches). **Gradient blend** — combo: **Horizontal**, **Vertical**, **Diagonal 1**, **Diagonal 2**, **Corner 1** … **Corner 4**. +3. **3D view background** (always) — **Background color 1** and **Background color 2** (float RGB fields and swatches). **Gradient blend** — combo: **Horizontal**, **Vertical**, **Diagonal 1**, **Diagonal 2**, **Corner 1** … **Corner 4**. -4. **3D view grid** — **Fine grid lines** and **Major grid lines** (passed to Open CASCADE `Aspect_Grid::SetColors`: dense lines vs every-tenth emphasis lines). **Grid step**, **Grid extent X / Y** (full span edge-to-edge), and **Grid display Z offset** in the Settings pane use the **same length scale as sketch length dimensions** (display value = model value / internal `dimension_scale`, default **100**). Saved JSON (`occt_view`) stores **half-extent** in model units for OCCT (`grid_graphic_*`); Settings shows **full** extent (twice the stored half-extent). +4. **3D view grid** (verbosity **5**+) — **Fine grid lines** and **Major grid lines** (passed to Open CASCADE `Aspect_Grid::SetColors`: dense lines vs every-tenth emphasis lines). **Grid step**, **Grid extent X / Y** (full span edge-to-edge), and **Grid display Z offset** in the Settings pane use the **same length scale as sketch length dimensions** (display value = model value / internal `dimension_scale`, default **100**). Saved JSON (`occt_view`) stores **half-extent** in model units for OCCT (`grid_graphic_*`); Settings shows **full** extent (twice the stored half-extent). -5. **Sketch** — **Dimension line width** — slider **0.5** to **8.0** (has `(?)`). **Underlay highlight color** — RGB (has `(?)`). +5. **Sketch** (always) — **Dimension line width** — slider **0.5** to **8.0** (has `(?)`). **Underlay highlight color** — RGB (has `(?)`). -6. **Startup project** — **Desktop only:** **Load last opened on startup** (checkbox, with `(?)`), then **Last opened path:** … or **(No path saved yet.)** Then **Save current as startup project**, **Clear saved startup** (with `(?)`). **WebAssembly:** no load-last row; only the two buttons and `(?)`. See [Startup project](#startup-project). +6. **Startup project** (verbosity **5**+; **Desktop only:** **Load last opened on startup** (checkbox, with `(?)`), then **Last opened path:** … or **(No path saved yet.)** Then **Save current as startup project**, **Clear saved startup** (with `(?)`). **WebAssembly:** no load-last row; only the two buttons and `(?)`. See [Startup project](#startup-project). **Not in this pane** @@ -134,6 +135,7 @@ String: ImGui `.ini` text for window positions and docking saved with **SaveIniS | `show_settings_dialog` | boolean | Whether the Settings pane was open when last saved (usually false). | | `show_lua_console` | boolean | Lua console pane visible. | | `show_python_console` | boolean | Python console pane visible (native builds with Python). | +| `ui_verbosity` | integer | UI depth: **0** = minimal; odd values add features (panes, menus); even values add help (tooltips, hints). Default **6**. Negative values are clamped to **0** on load. | | `show_dbg` | boolean | Debug pane visible (debug builds only). | | `edge_dim_label_h` | integer | Length dimension label placement: **0** to **3** (see [Options panel (sketch)](#options-panel-sketch)). Values outside this range are ignored. | | `edge_dim_line_width` | number | Sketch length dimension line width (allowed range **0.5** to **8.0** in code). | @@ -146,7 +148,7 @@ String: ImGui `.ini` text for window positions and docking saved with **SaveIniS | `load_last_opened_on_startup` | boolean | Desktop: open the last `.ezy` on launch. **Legacy:** `load_last_saved_on_startup` is read as a fallback if the newer key is absent. | | `last_opened_project_path` | string | Path of the last opened project for the option above. **Legacy:** `last_saved_project_path` is accepted if the newer key is missing. | -Scripting API **`ezy.occt_view_settings_json()`** returns a JSON string with **`occt_view`** plus selected **`gui`** keys (including **`gui.edge_dim_label_h`**, **`gui.edge_dim_line_width`**, **`gui.view_roll_step_deg`**, **`gui.view_zoom_scroll_scale`** when saved). See [scripting.md](scripting.md). +Scripting API **`ezy.occt_view_settings_json()`** returns a JSON string with **`occt_view`** plus selected **`gui`** keys (including **`gui.ui_verbosity`**, **`gui.edge_dim_label_h`**, **`gui.edge_dim_line_width`**, **`gui.view_roll_step_deg`**, **`gui.view_zoom_scroll_scale`** when saved). See [scripting.md](scripting.md). --- From 4e8fa86692c3d735f17cb4aa59a45845d4ae5b1f Mon Sep 17 00:00:00 2001 From: trailcode Date: Wed, 20 May 2026 19:50:20 -0600 Subject: [PATCH 3/5] Good feature. --- src/gui.cpp | 29 +++++++++++++++++-------- src/gui.h | 4 ++++ src/gui_settings.cpp | 41 ++++++++++++++++++++++++++++++++---- usage-settings.md | 2 +- usage.md | 50 ++++++++++++++++++++++++++++++++++++++------ 5 files changed, 106 insertions(+), 20 deletions(-) diff --git a/src/gui.cpp b/src/gui.cpp index e10c7ee..4ddd95a 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -1031,7 +1031,7 @@ void GUI::sketch_list_() const Sketch* sk_key = sketch.get(); bool& expanded = m_sketch_list_expanded[sk_key]; - if (ui_show_feature(2)) + if (ui_show_sketch_list_expand()) { ImGui::PushID(("expand" + id_suffix).c_str()); if (ImGui::SmallButton(expanded ? "v" : ">")) @@ -1110,23 +1110,34 @@ void GUI::sketch_list_() } ImGui::PopID(); - if (ui_show_feature(2)) + if (ui_show_sketch_list_props_slot()) { ImGui::SameLine(); ImGui::PushID(("props" + id_suffix).c_str()); - if (ImGui::SmallButton("[P]")) + if (ui_show_sketch_list_props_button()) { - m_sketch_properties_sketch = sketch; - m_sketch_properties_open = true; - } + if (ImGui::SmallButton("[P]")) + { + m_sketch_properties_sketch = sketch; + m_sketch_properties_open = true; + } - if (ui_show_help(2) && ImGui::IsItemHovered()) - ImGui::SetTooltip("Sketch properties"); + if (ui_show_help(2) && ImGui::IsItemHovered()) + ImGui::SetTooltip("Sketch properties"); + } + else + { + ImGui::BeginDisabled(); + ImGui::SmallButton("[P]"); + ImGui::EndDisabled(); + if (ui_show_help(2) && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) + ImGui::SetTooltip("Sketch properties ([P]) unlocks at UI verbosity 3."); + } ImGui::PopID(); } - if (expanded && ui_show_feature(2)) + if (expanded && ui_show_sketch_list_expand()) sketch_list_inspector_(*sketch, index); ++index; diff --git a/src/gui.h b/src/gui.h index 772e2fb..4b0be26 100644 --- a/src/gui.h +++ b/src/gui.h @@ -136,6 +136,10 @@ class GUI int ui_help_tier() const { return m_ui_verbosity / 2; } bool ui_show_feature(int tier) const { return tier <= ui_feature_tier(); } bool ui_show_help(int tier) const { return tier <= ui_help_tier(); } + /// Sketch list: reserved [P] column at verbosity >= 2; active button at feature tier 2 (verbosity >= 3). + bool ui_show_sketch_list_props_slot() const { return m_ui_verbosity >= 2; } + bool ui_show_sketch_list_props_button() const { return ui_show_feature(2); } + bool ui_show_sketch_list_expand() const { return ui_show_feature(2); } bool show_options_effective() const { return m_show_options && ui_show_feature(1); } bool show_sketch_list_effective() const { return m_show_sketch_list && ui_show_feature(1); } bool show_shape_list_effective() const { return m_show_shape_list && ui_show_feature(1); } diff --git a/src/gui_settings.cpp b/src/gui_settings.cpp index 0fa09e0..3333d17 100644 --- a/src/gui_settings.cpp +++ b/src/gui_settings.cpp @@ -429,10 +429,43 @@ void GUI::settings_() constexpr float k_label_col_w = 230.f; - if (ImGui::SliderInt("UI verbosity", &m_ui_verbosity, k_gui_ui_verbosity_min, k_gui_ui_verbosity_default + 4, - "%d")) - save_occt_view_settings(); - m_ui_verbosity = std::max(k_gui_ui_verbosity_min, m_ui_verbosity); + { + bool verb_changed = false; + if (ImGui::BeginTable("settings_ui_verbosity", 2, ImGuiTableFlags_SizingStretchProp)) + { + ImGui::TableSetupColumn("label", ImGuiTableColumnFlags_WidthFixed, k_label_col_w); + ImGui::TableSetupColumn("control", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGui::AlignTextToFramePadding(); + ImGui::TextUnformatted("UI verbosity"); + ImGui::TableSetColumnIndex(1); + ImGui::BeginDisabled(m_ui_verbosity <= k_gui_ui_verbosity_min); + if (ImGui::ArrowButton("##ui_verbosity_dec", ImGuiDir_Left)) + { + --m_ui_verbosity; + verb_changed = true; + } + ImGui::EndDisabled(); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::SetNextItemWidth(56.0f); + int verb_edit = m_ui_verbosity; + if (ImGui::InputInt("##ui_verbosity_val", &verb_edit, 0, 0)) + { + m_ui_verbosity = std::max(k_gui_ui_verbosity_min, verb_edit); + verb_changed = true; + } + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + if (ImGui::ArrowButton("##ui_verbosity_inc", ImGuiDir_Right)) + { + ++m_ui_verbosity; + verb_changed = true; + } + ImGui::EndTable(); + } + if (verb_changed) + save_occt_view_settings(); + } if (ui_show_help(3)) ImGui::TextWrapped("0 = minimal UI. Odd values add more controls and panes; even values add more help (tooltips and " "hints). Higher values are reserved for future tiers."); diff --git a/usage-settings.md b/usage-settings.md index b9c2204..3f3a2ca 100644 --- a/usage-settings.md +++ b/usage-settings.md @@ -35,7 +35,7 @@ Visibility of these panes (and related flags) is persisted with the rest of your Open **View -> Settings**. The window title is **Settings**. -- **UI verbosity** — integer at the top (default **6**, full UI). **0** keeps a minimal layout (toolbar and 3D view, core **File**/**Edit**/**Help**, essential settings only). Each **odd** step unlocks more panes and menu items; each **even** step unlocks more tooltips and inline help. Values above **6** are stored for future tiers. Persisted as **`gui.ui_verbosity`**. +- **UI verbosity** — value at the top with **left** / **right** step buttons (default **6**, full UI); you can also type a number. **0** keeps a minimal layout (toolbar and 3D view, core **File**/**Edit**/**Help**, essential settings only). Each **odd** step unlocks more panes and menu items; each **even** step unlocks more tooltips and inline help. **2** reserves the Sketch List **[P]** column (disabled slot); **3** enables **[P]**, row expand, and other feature-tier-2 items. Values above **6** are stored for future tiers. Persisted as **`gui.ui_verbosity`**. - **Dark mode** — checkbox below verbosity (not inside a collapsible section). - At the bottom: **Defaults** — reloads bundled defaults from the app `res/` tree (including ImGui layout from that file). diff --git a/usage.md b/usage.md index 234c399..e1f02fb 100644 --- a/usage.md +++ b/usage.md @@ -5,7 +5,7 @@ ## Table of Contents 1. [Introduction](#introduction) 2. [Getting Started](#getting-started) -3. [User Interface](#user-interface) +3. [User Interface](#user-interface) ([UI verbosity](#ui-verbosity)) 4. [File Operations](#file-operations) 5. [Edit Operations](#edit-operations) 6. [Modeling Tools](#modeling-tools) @@ -40,7 +40,7 @@ EzyCad (Easy CAD) is a CAD application for hobbyist machinists to design and edi 1. **Menu Bar** - **File** - [New](#new-project), [Open](#open-project), [Save](#save-project), Save as, [Import](#importing-3d-geometries), [Export](#exporting-3d-geometries), Examples, Exit - **Edit** - [Undo](#edit-operations), [Redo](#edit-operations) - - **View** - [Settings, panes, Lua/Python consoles](usage-settings.md#view-menu) + - **View** - [Settings, panes, Lua/Python consoles](usage-settings.md#view-menu); pane depth also depends on [UI verbosity](#ui-verbosity) - **Help** - [About](#help-menu), [Usage Guide](#help-menu), and the separate **[Settings guide](usage-settings.md)** 2. **Toolbar** @@ -76,21 +76,59 @@ EzyCad (Easy CAD) is a CAD application for hobbyist machinists to design and edi For **View** (Settings, pane toggles, consoles), saving preferences, and the **Settings** pane sections, see **[usage-settings.md](usage-settings.md)**. +### UI verbosity + +**UI verbosity** is an integer in **View -> Settings** (stored as **`gui.ui_verbosity`**; default **6**). It controls how much chrome and guidance EzyCad shows. Use the **left** / **right** arrows next to the value to step it, or type a number directly. Negative values are treated as **0** on load; values above **6** are saved but do not unlock more until future releases add higher tiers. + +#### How stepping works + +Verbosity is **cumulative**: everything unlocked at a lower value stays available at higher values. + +- **Even** steps (**2**, **4**, **6**, ...) add **help**: tooltips, `(?)` hints, and short wrapped notes. +- **Odd** steps (**1**, **3**, **5**, ...) add **features**: extra panes, menus, and controls. + +There is one deliberate **split between 2 and 3** in the [Sketch List](#sketch-list): at **2** the **[P]** column appears but the button is disabled (layout preview); at **3** **[P]** works and row **expand** (`>`) is enabled. That way help (step 2) can appear before the properties workflow (step 3). + +**Pane visibility** (Options, Sketch List, and so on) is still saved in your settings file. Lowering verbosity hides panes without clearing those flags; raising verbosity shows them again if they were on before. + +#### Why it exists + +A lower verbosity keeps the screen focused on the 3D view and core modeling actions, which helps on small displays or while learning the toolbar. Higher values expose lists, scripting consoles, import paths, and inline documentation for day-to-day work. You can raise verbosity temporarily when you need a control, then lower it again. + +#### What each value enables + +The table lists what **first becomes available** at each step (not everything repeated at every row). + +| Value | Step type | Newly available | +| --- | --- | --- | +| **0** | Minimal | **Toolbar** and **3D view**. **File**: New, Open, Save, Save as, Export, Exit. **Edit**: Undo, Redo, New sketch, quick **Add** primitives (box, pyramid, sphere, cylinder, cone, torus at default size, no `*_prms` dialogs). **View**: **Settings** only. **Help**: About, Usage Guide. **Settings**: UI verbosity, Dark mode, **3D view navigation**, **3D view background**, **Sketch** (dimension width, underlay tint, snap guides). No Options, Sketch List, Shape List, or Log panes. No toolbar tooltips. | +| **1** | Features | **Options**, **Sketch List**, **Shape List**, and **Log** panes (when enabled under **View**). Matching **View** menu entries to toggle them. | +| **2** | Help | **Toolbar** button tooltips. Sketch List: disabled **[P]** placeholder (column reserved, not clickable). | +| **3** | Features | **File**: Import, Sketch underlay image, **Examples**. **Lua** / **Python** consoles (**View** menu). Sketch List: active **[P]** (sketch properties), **`>`** expand and per-sketch inspector. | +| **4** | Help | Hover tooltips on Options, sketch/shape lists, sketch properties, and most Settings controls; `(?)` markers on Settings rows (for example grid extent, dimension width). | +| **5** | Features | **Edit**: **Add box_prms**, **Add pyramid_prms**, and other `*_prms` entries (parameter dialogs). **Settings**: **UI corner rounding**, **3D view grid**, **Startup project**. | +| **6** | Help | Longer wrapped hints (for example Options **Shortcuts**, Settings view-navigation paragraph). Settings **`?`** links to the online usage guide. Extra sketch-properties help (for example underlay shear note). | +| **7+** | Reserved | Same as **6** until a future version defines more tiers. | + +**Always on** (at any verbosity): project save/open, toolbar modes, **Export**, and the essential **Settings** sections listed for **0**. **Import** and scripting require at least **3**. + +For the control itself and the JSON key, see **[usage-settings.md](usage-settings.md#settings-pane)**. + ### Sketch List -The **Sketch List** pane lists all 2D sketches in the current document. Open it from **View -> Sketch List**. +The **Sketch List** pane lists all 2D sketches in the current document. Open it from **View -> Sketch List** (requires [UI verbosity](#ui-verbosity) **1** or higher). Each row is laid out left to right: -- **Expand** - Click **`>`** / **`v`** to show or hide details for that sketch (tooltip *Expand details* / *Collapse details*). +- **Expand** - At verbosity **3+**, click **`>`** / **`v`** to show or hide details for that sketch (tooltip *Expand details* / *Collapse details* when help tier 2+ is on). Not shown below **3**. - **Set current** - Radio button (circle). The current sketch is used for editing and for operations such as [extrude](#extrude-sketch-face-tool-e). - **Rename** - Click the name field and type a new name. - **Visibility** - Checkbox to show or hide the sketch in the 3D view. - **Underlay** - Checkbox to show or hide an [image underlay](usage-sketch.md#image-underlay) when one is imported (disabled until an underlay exists; tooltip *Display underlay*). -- **Sketch properties** - **`[P]`** opens the **Sketch properties** window (import/remove underlay, calibration, transform). See [Image underlay](usage-sketch.md#image-underlay). +- **Sketch properties** - **`[P]`** column at verbosity **2+**; the button is active at **3+** and opens **Sketch properties** (import/remove underlay, calibration, transform). At **2** the control is visible but disabled as a preview. See [Image underlay](usage-sketch.md#image-underlay). - **Delete** - Right-click the name and choose **Delete**. -When expanded, the row shows: +When expanded (verbosity **3+**), the row shows: - **Dimensions** - Table of length dimensions: visibility, editable name, and **offset** (label distance from the edge; **0** = automatic). - **Nodes**, **Edges**, **Faces** - Collapsible lists of element labels for inspection (read-only names). From 345a54f9f0100fa35eb0a1d3bbee1a4e6a742cd4 Mon Sep 17 00:00:00 2001 From: trailcode Date: Thu, 21 May 2026 16:46:37 -0600 Subject: [PATCH 4/5] Options horizontal scroll. --- src/gui_mode.cpp | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/gui_mode.cpp b/src/gui_mode.cpp index a7d3d47..08f1e0d 100644 --- a/src/gui_mode.cpp +++ b/src/gui_mode.cpp @@ -24,6 +24,16 @@ using namespace glm; namespace { +constexpr ImGuiTableFlags k_options_table_flags = ImGuiTableFlags_SizingFixedFit; +constexpr float k_options_control_col_w = 148.f; +constexpr float k_options_sketch_control_col_w = 176.f; + +void options_table_setup_columns_(float label_col_w, float control_col_w) +{ + ImGui::TableSetupColumn("label", ImGuiTableColumnFlags_WidthFixed, label_col_w); + ImGui::TableSetupColumn("control", ImGuiTableColumnFlags_WidthFixed, control_col_w); +} + // Up to `max_frac` digits after the decimal, strip trailing zeros (and a trailing '.'). void format_double_trim_fraction(char* dst, std::size_t dst_sz, double v, int max_frac) { @@ -321,6 +331,8 @@ void GUI::options_() return; } + ImGui::BeginChild("##options_scroll", ImVec2(0.f, 0.f), false, ImGuiWindowFlags_HorizontalScrollbar); + // clang-format off switch (get_mode()) { @@ -385,10 +397,9 @@ void GUI::options_() sketch_label_col_w += ImGui::GetStyle().CellPadding.x * 2.0f + 8.0f; ImGui::TextUnformatted("Sketch options"); - if (ImGui::BeginTable("options_sketch_sketch", 2, ImGuiTableFlags_SizingStretchProp)) + if (ImGui::BeginTable("options_sketch_sketch", 2, k_options_table_flags)) { - ImGui::TableSetupColumn("label", ImGuiTableColumnFlags_WidthFixed, sketch_label_col_w); - ImGui::TableSetupColumn("control", ImGuiTableColumnFlags_WidthStretch); + options_table_setup_columns_(sketch_label_col_w, k_options_sketch_control_col_w); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); @@ -463,10 +474,9 @@ void GUI::options_() { ImGui::Separator(); ImGui::TextUnformatted("Extrude"); - if (ImGui::BeginTable("options_sketch_extrude", 2, ImGuiTableFlags_SizingStretchProp)) + if (ImGui::BeginTable("options_sketch_extrude", 2, k_options_table_flags)) { - ImGui::TableSetupColumn("label", ImGuiTableColumnFlags_WidthFixed, sketch_label_col_w); - ImGui::TableSetupColumn("control", ImGuiTableColumnFlags_WidthStretch); + options_table_setup_columns_(sketch_label_col_w, k_options_sketch_control_col_w); bool extrude_both_sides = m_view->shp_extrude().get_both_sides(); ImGui::TableNextRow(); @@ -543,6 +553,7 @@ void GUI::options_() material_combo_only_("##default_material"); } + ImGui::EndChild(); ImGui::End(); } @@ -564,10 +575,9 @@ void GUI::options_normal_mode_() label_col_w += ImGui::GetStyle().CellPadding.x * 2.0f + 8.0f; ImGui::TextUnformatted("Selection"); - if (ImGui::BeginTable("options_normal_selection", 2, ImGuiTableFlags_SizingStretchProp)) + if (ImGui::BeginTable("options_normal_selection", 2, k_options_table_flags)) { - ImGui::TableSetupColumn("label", ImGuiTableColumnFlags_WidthFixed, label_col_w); - ImGui::TableSetupColumn("control", ImGuiTableColumnFlags_WidthStretch); + options_table_setup_columns_(label_col_w, k_options_control_col_w); int current_item = static_cast(m_view->get_shp_selection_mode()); ImGui::TableNextRow(); @@ -620,7 +630,8 @@ void GUI::options_normal_mode_() int current_mat = int(m_view->get_default_material().Name()); if (current_mat < 0 || current_mat >= static_cast(material_names.size())) current_mat = 0; - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + const float material_row_w = label_col_w + k_options_control_col_w; + ImGui::SetNextItemWidth(std::max(ImGui::GetContentRegionAvail().x, material_row_w)); if (ImGui::BeginCombo("##default_material_normal", material_names[static_cast(current_mat)].data(), ImGuiComboFlags_HeightSmall)) { @@ -711,10 +722,9 @@ void GUI::options_shape_chamfer_mode_() label_col_w += ImGui::GetStyle().CellPadding.x * 2.0f + 8.0f; ImGui::TextUnformatted("Chamfer"); - if (ImGui::BeginTable("options_chamfer_tool", 2, ImGuiTableFlags_SizingStretchProp)) + if (ImGui::BeginTable("options_chamfer_tool", 2, k_options_table_flags)) { - ImGui::TableSetupColumn("label", ImGuiTableColumnFlags_WidthFixed, label_col_w); - ImGui::TableSetupColumn("control", ImGuiTableColumnFlags_WidthStretch); + options_table_setup_columns_(label_col_w, k_options_control_col_w); int current_mode = static_cast(m_chamfer_mode); ImGui::TableNextRow(); @@ -779,10 +789,9 @@ void GUI::options_shape_fillet_mode_() label_col_w += ImGui::GetStyle().CellPadding.x * 2.0f + 8.0f; ImGui::TextUnformatted("Fillet"); - if (ImGui::BeginTable("options_fillet_tool", 2, ImGuiTableFlags_SizingStretchProp)) + if (ImGui::BeginTable("options_fillet_tool", 2, k_options_table_flags)) { - ImGui::TableSetupColumn("label", ImGuiTableColumnFlags_WidthFixed, label_col_w); - ImGui::TableSetupColumn("control", ImGuiTableColumnFlags_WidthStretch); + options_table_setup_columns_(label_col_w, k_options_control_col_w); int current_mode = static_cast(m_fillet_mode); ImGui::TableNextRow(); @@ -857,10 +866,9 @@ void GUI::options_shape_polar_duplicate_mode_() label_col_w += ImGui::GetStyle().CellPadding.x * 2.0f + 8.0f; ImGui::TextUnformatted("Polar duplicate"); - if (ImGui::BeginTable("options_polar_dup_tool", 2, ImGuiTableFlags_SizingStretchProp)) + if (ImGui::BeginTable("options_polar_dup_tool", 2, k_options_table_flags)) { - ImGui::TableSetupColumn("label", ImGuiTableColumnFlags_WidthFixed, label_col_w); - ImGui::TableSetupColumn("control", ImGuiTableColumnFlags_WidthStretch); + options_table_setup_columns_(label_col_w, k_options_control_col_w); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); From 45ffb13952c2aae6ebe6fa708d91083b8e20cc02 Mon Sep 17 00:00:00 2001 From: trailcode Date: Thu, 21 May 2026 16:56:28 -0600 Subject: [PATCH 5/5] Doc revert. --- CHANGELOG.md | 3 ++- usage-settings.md | 52 ++++++++++++++++++++++++++-------------- usage.md | 61 ++++++++++------------------------------------- 3 files changed, 48 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c2b97a..16eba46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- **Settings -> UI verbosity** (`gui.ui_verbosity`): cumulative control over optional panes/menus (odd steps) and tooltips/inline help (even steps). Default **6** matches the previous full UI; **0** is minimal. - **Inspection mode** (Normal): **Options -> Orthographic projection** (under **Selection**) toggles an orthographic camera (persisted as `gui.inspection_orthographic`). Sketch modes still force orthographic as before. +- **Options** pane: horizontal scrollbar when the window is resized narrower than its controls. +- **Shape List**: right-click a shape **name** to **Delete**; right-click the **M** button for **Delete** as well (click **M** for the material popup). - **Settings** (3D view grid) and saved **`occt_view`** JSON: configure Open CASCADE rectangular grid **step** (uniform X/Y), plus **graphic display extent X/Y** and **Z offset** (`V3d_RectangularGrid::SetGraphicValues`). Bundled **`res/ezycad_settings.json`** includes defaults for those keys. - **Keyboard zoom:** **NumPad +** / **NumPad -**, main **-**, and **Shift+=** (US **+**) zoom the 3D view in steps equal to **one mouse wheel tick** at the cursor (same internal scaling as scroll). diff --git a/usage-settings.md b/usage-settings.md index 3f3a2ca..d2b7669 100644 --- a/usage-settings.md +++ b/usage-settings.md @@ -6,7 +6,7 @@ This guide covers the **Settings** pane (what is on screen), the **View** menu ( 1. [View menu](#view-menu) 2. [Settings pane](#settings-pane) -3. [Options panel (sketch)](#options-panel-sketch) +3. [Options panel](#options-panel) 4. [Where settings are stored](#where-settings-are-stored) 5. [Startup project](#startup-project) 6. [Settings file reference](#settings-file-reference) @@ -35,34 +35,52 @@ Visibility of these panes (and related flags) is persisted with the rest of your Open **View -> Settings**. The window title is **Settings**. -- **UI verbosity** — value at the top with **left** / **right** step buttons (default **6**, full UI); you can also type a number. **0** keeps a minimal layout (toolbar and 3D view, core **File**/**Edit**/**Help**, essential settings only). Each **odd** step unlocks more panes and menu items; each **even** step unlocks more tooltips and inline help. **2** reserves the Sketch List **[P]** column (disabled slot); **3** enables **[P]**, row expand, and other feature-tier-2 items. Values above **6** are stored for future tiers. Persisted as **`gui.ui_verbosity`**. -- **Dark mode** — checkbox below verbosity (not inside a collapsible section). +- **Dark mode** — checkbox at the top (not inside a collapsible section). - At the bottom: **Defaults** — reloads bundled defaults from the app `res/` tree (including ImGui layout from that file). -Between those, the pane has up to **six** collapsible sections (some appear only when **UI verbosity** is high enough). Expand a section to see its controls; when collapsed, only the section title bar is visible. +Between those, the pane has **six** collapsible sections. Expand a section to see its controls; when collapsed, only the section title bar is visible. -1. **3D view navigation** (always at verbosity **0** and above) — **View rotation step** (degrees per key press for **NumPad 8**/**2**/**4**/**6** orbit and **Shift+NumPad 4**/**6** roll; default **45**; **`?`** opens [view roll](https://ezycad.readthedocs.io/en/latest/usage.html#view-roll) on Read the Docs). **Zoom scroll scale** (multiplier for wheel and **+**/**-** zoom; default **4**). Hold **Shift** while zooming for a Blender-style finer step (multiply by **0.1**). Numpad shortcuts are documented with **Num Lock off**; with **Num Lock on**, use main-row alternatives in [usage.md -> View navigation](usage.md#view-navigation). Stored as **`gui.view_roll_step_deg`** and **`gui.view_zoom_scroll_scale`**. See **[usage-occt-view.md](usage-occt-view.md)**. +1. **3D view navigation** — **View rotation step** (degrees per key press for **NumPad 8**/**2**/**4**/**6** orbit and **Shift+NumPad 4**/**6** roll; default **45**; **`?`** opens [view roll](https://ezycad.readthedocs.io/en/latest/usage.html#view-roll) on Read the Docs). **Zoom scroll scale** (multiplier for wheel and **+**/**-** zoom; default **4**). Hold **Shift** while zooming for a Blender-style finer step (multiply by **0.1**). Numpad shortcuts are documented with **Num Lock off**; with **Num Lock on**, use main-row alternatives in [usage.md -> View navigation](usage.md#view-navigation). Stored as **`gui.view_roll_step_deg`** and **`gui.view_zoom_scroll_scale`**. See **[usage-occt-view.md](usage-occt-view.md)**. -2. **UI corner rounding** (verbosity **5**+) — Sliders **0** to **16** for **Windows, frames, popups**; **Scrollbars and sliders** (has `(?)` at higher help levels); **Tabs**. +2. **UI corner rounding** — Sliders **0** to **16** for **Windows, frames, popups**; **Scrollbars and sliders** (has `(?)`); **Tabs**. -3. **3D view background** (always) — **Background color 1** and **Background color 2** (float RGB fields and swatches). **Gradient blend** — combo: **Horizontal**, **Vertical**, **Diagonal 1**, **Diagonal 2**, **Corner 1** … **Corner 4**. +3. **3D view background** — **Background color 1** and **Background color 2** (float RGB fields and swatches). **Gradient blend** — combo: **Horizontal**, **Vertical**, **Diagonal 1**, **Diagonal 2**, **Corner 1** … **Corner 4**. -4. **3D view grid** (verbosity **5**+) — **Fine grid lines** and **Major grid lines** (passed to Open CASCADE `Aspect_Grid::SetColors`: dense lines vs every-tenth emphasis lines). **Grid step**, **Grid extent X / Y** (full span edge-to-edge), and **Grid display Z offset** in the Settings pane use the **same length scale as sketch length dimensions** (display value = model value / internal `dimension_scale`, default **100**). Saved JSON (`occt_view`) stores **half-extent** in model units for OCCT (`grid_graphic_*`); Settings shows **full** extent (twice the stored half-extent). +4. **3D view grid** — **Fine grid lines** and **Major grid lines** (passed to Open CASCADE `Aspect_Grid::SetColors`: dense lines vs every-tenth emphasis lines). **Grid step**, **Grid extent X / Y** (full span edge-to-edge), and **Grid display Z offset** in the Settings pane use the **same length scale as sketch length dimensions** (display value = model value / internal `dimension_scale`, default **100**). Saved JSON (`occt_view`) stores **half-extent** in model units for OCCT (`grid_graphic_*`); Settings shows **full** extent (twice the stored half-extent). -5. **Sketch** (always) — **Dimension line width** — slider **0.5** to **8.0** (has `(?)`). **Underlay highlight color** — RGB (has `(?)`). +5. **Sketch** — **Dimension line width** — slider **0.5** to **8.0** (has `(?)`). **Underlay highlight color** — RGB (has `(?)`). -6. **Startup project** (verbosity **5**+; **Desktop only:** **Load last opened on startup** (checkbox, with `(?)`), then **Last opened path:** … or **(No path saved yet.)** Then **Save current as startup project**, **Clear saved startup** (with `(?)`). **WebAssembly:** no load-last row; only the two buttons and `(?)`. See [Startup project](#startup-project). +6. **Startup project** — **Desktop only:** **Load last opened on startup** (checkbox, with `(?)`), then **Last opened path:** … or **(No path saved yet.)** Then **Save current as startup project**, **Clear saved startup** (with `(?)`). **WebAssembly:** no load-last row; only the two buttons and `(?)`. See [Startup project](#startup-project). **Not in this pane** - **View** menu items such as **Options**, **Sketch List**, **Lua Console** — they only show or hide panes; they are not rows inside **Settings**. Their visibility is still saved under `gui.*` in the settings file (see [Settings file reference](#settings-file-reference)). -- **Length value placement** for edge dimensions — **Options** panel when the edge-dimension tool is active; see [Options panel (sketch)](#options-panel-sketch). +- **Length value placement** for edge dimensions — **Options** panel when the edge-dimension tool is active; see [Options panel](#options-panel). **Saving** — On desktop, settings are written when you change options that save, and on exit. On **Emscripten**, use **File -> Save settings** so the browser persists (see [Where settings are stored](#where-settings-are-stored)). -## Options panel (sketch) +## Options panel -Sketch-related preferences are edited in the **Options** panel while you use a tool, not in the **Settings** pane. They appear under section headings in the panel: +Open **View -> Options**. Content depends on the active tool mode. Related controls are grouped under headings (for example **Sketch options**, **Extrude**, **Selection**, **Material**). + +If you resize the pane narrower than its controls, a **horizontal scrollbar** appears so long labels (for example **Orthographic projection**) stay readable. + +### Normal mode (Inspection) + +Under **Selection**: + +- **Selection Mode** — combo for the 3D pick filter (vertices, edges, faces, solids, and combinations). The **`(?)`** marker links to [shape selection filter hotkeys](usage.md#shape-selection-filter-normal-mode-only) in the usage guide. +- **Orthographic projection** — checkbox toggling an orthographic camera in inspection mode (sketch modes still force orthographic as before). Persisted as **`gui.inspection_orthographic`**. + +Under **Material**: + +- Document preset for new solids that do not inherit from a clicked shape (toolbar **Box**, **polar duplicate** output, and similar). To change material on an existing solid, use the [Shape List](usage.md#shape-list). + +For other non-sketch Options content (for example **Polar duplicate**), see [usage.md -> User Interface](usage.md#user-interface) (Options Panel). + +### Sketch tools + +Sketch-related preferences are edited in the **Options** panel while you use a sketch tool, not in the **Settings** pane: - **Sketch options** (all sketch tools): **Snap dist** and **Snap guide mode** (*Traditional*, *Fullscreen*, *Both*). - **Toggle edge dimension** (length dimensions): **Length value placement** - combo: *Near first point*, *Near second point*, *Center on dimension line*, *Automatic*. Maps to the `edge_dim_label_h` key (integers **0** through **3**). Changing it persists like other GUI flags. @@ -72,8 +90,6 @@ Sketch-related preferences are edited in the **Options** panel while you use a t **Dimension line width** for length dimensions is in **Settings -> Sketch** (see above). -For **Normal** mode (selection and document **Material** preset), **polar duplicate**, and other non-sketch Options content, see [usage.md](usage.md#user-interface) under **User Interface** (Options Panel). - ## Where settings are stored EzyCad reads and writes a single JSON file named **`ezycad_settings.json`**. @@ -135,9 +151,9 @@ String: ImGui `.ini` text for window positions and docking saved with **SaveIniS | `show_settings_dialog` | boolean | Whether the Settings pane was open when last saved (usually false). | | `show_lua_console` | boolean | Lua console pane visible. | | `show_python_console` | boolean | Python console pane visible (native builds with Python). | -| `ui_verbosity` | integer | UI depth: **0** = minimal; odd values add features (panes, menus); even values add help (tooltips, hints). Default **6**. Negative values are clamped to **0** on load. | | `show_dbg` | boolean | Debug pane visible (debug builds only). | -| `edge_dim_label_h` | integer | Length dimension label placement: **0** to **3** (see [Options panel (sketch)](#options-panel-sketch)). Values outside this range are ignored. | +| `inspection_orthographic` | boolean | **Normal** mode Options: orthographic camera when true (default false). | +| `edge_dim_label_h` | integer | Length dimension label placement: **0** to **3** (see [Options panel](#options-panel)). Values outside this range are ignored. | | `edge_dim_line_width` | number | Sketch length dimension line width (allowed range **0.5** to **8.0** in code). | | `imgui_rounding_general` | number | Window/child/frame/popup rounding (**0** to **32** clamped in code; sliders stop at 16 in the UI). | | `imgui_rounding_scroll` | number | Scrollbar and grab rounding (same clamp). | @@ -148,7 +164,7 @@ String: ImGui `.ini` text for window positions and docking saved with **SaveIniS | `load_last_opened_on_startup` | boolean | Desktop: open the last `.ezy` on launch. **Legacy:** `load_last_saved_on_startup` is read as a fallback if the newer key is absent. | | `last_opened_project_path` | string | Path of the last opened project for the option above. **Legacy:** `last_saved_project_path` is accepted if the newer key is missing. | -Scripting API **`ezy.occt_view_settings_json()`** returns a JSON string with **`occt_view`** plus selected **`gui`** keys (including **`gui.ui_verbosity`**, **`gui.edge_dim_label_h`**, **`gui.edge_dim_line_width`**, **`gui.view_roll_step_deg`**, **`gui.view_zoom_scroll_scale`** when saved). See [scripting.md](scripting.md). +Scripting API **`ezy.occt_view_settings_json()`** returns a JSON string with **`occt_view`** plus selected **`gui`** keys (including **`gui.inspection_orthographic`**, **`gui.edge_dim_label_h`**, **`gui.edge_dim_line_width`**, **`gui.view_roll_step_deg`**, **`gui.view_zoom_scroll_scale`** when saved). See [scripting.md](scripting.md). --- diff --git a/usage.md b/usage.md index e1f02fb..c25e2e6 100644 --- a/usage.md +++ b/usage.md @@ -5,7 +5,7 @@ ## Table of Contents 1. [Introduction](#introduction) 2. [Getting Started](#getting-started) -3. [User Interface](#user-interface) ([UI verbosity](#ui-verbosity)) +3. [User Interface](#user-interface) 4. [File Operations](#file-operations) 5. [Edit Operations](#edit-operations) 6. [Modeling Tools](#modeling-tools) @@ -40,7 +40,7 @@ EzyCad (Easy CAD) is a CAD application for hobbyist machinists to design and edi 1. **Menu Bar** - **File** - [New](#new-project), [Open](#open-project), [Save](#save-project), Save as, [Import](#importing-3d-geometries), [Export](#exporting-3d-geometries), Examples, Exit - **Edit** - [Undo](#edit-operations), [Redo](#edit-operations) - - **View** - [Settings, panes, Lua/Python consoles](usage-settings.md#view-menu); pane depth also depends on [UI verbosity](#ui-verbosity) + - **View** - [Settings, panes, Lua/Python consoles](usage-settings.md#view-menu) - **Help** - [About](#help-menu), [Usage Guide](#help-menu), and the separate **[Settings guide](usage-settings.md)** 2. **Toolbar** @@ -58,11 +58,12 @@ EzyCad (Easy CAD) is a CAD application for hobbyist machinists to design and edi 5. **Options Panel** - Adjust tool parameters; related controls are grouped by headings (for example **Sketch options**, **Extrude**, **Selection**, **Material**, **Polar duplicate**), depending on the active tool. - - **Normal** mode (Inspection): **Selection** is the 3D pick filter and **Orthographic projection** toggles the camera (saved in settings). **Material** is the document preset for new solids that do not inherit from a clicked shape (for example toolbar **Box**, **polar duplicate** output). **Face extrude** reads the same preset in its Options **Material** row. + - If you resize the pane narrower than its controls, a **horizontal scrollbar** appears so long labels (for example **Orthographic projection**) stay readable. + - **Normal** mode (Inspection): **Selection** is the 3D pick filter and **Orthographic projection** toggles the camera (persisted as `gui.inspection_orthographic`). **Material** is the document preset for new solids that do not inherit from a clicked shape (for example toolbar **Box**, **polar duplicate** output). **Face extrude** reads the same preset in its Options **Material** row. - To change material on a solid already in the scene, use the [Shape List](#shape-list). - **Chamfer** and **Fillet**: distance and mode only; the result solid keeps the **source shape's material**. - **Move**, **Rotate**, and **Scale**: transform options only (no material row there). - - Sketch-related options (snap, length dimension placement, face extrude, shortcuts) are summarized in **[usage-settings.md](usage-settings.md#options-panel-sketch)**. + - Sketch-related options (snap, length dimension placement, face extrude, shortcuts) are summarized in **[usage-settings.md](usage-settings.md#options-panel)**. 6. **Log Window** - View operation history @@ -74,61 +75,23 @@ EzyCad (Easy CAD) is a CAD application for hobbyist machinists to design and edi - **About** - Opens the [project README](README.md) in the browser. - **Usage Guide** - Opens the [online usage guide](https://ezycad.readthedocs.io/en/latest/usage.html) (Read the Docs; source is [usage.md](usage.md) in this repository). -For **View** (Settings, pane toggles, consoles), saving preferences, and the **Settings** pane sections, see **[usage-settings.md](usage-settings.md)**. - -### UI verbosity - -**UI verbosity** is an integer in **View -> Settings** (stored as **`gui.ui_verbosity`**; default **6**). It controls how much chrome and guidance EzyCad shows. Use the **left** / **right** arrows next to the value to step it, or type a number directly. Negative values are treated as **0** on load; values above **6** are saved but do not unlock more until future releases add higher tiers. - -#### How stepping works - -Verbosity is **cumulative**: everything unlocked at a lower value stays available at higher values. - -- **Even** steps (**2**, **4**, **6**, ...) add **help**: tooltips, `(?)` hints, and short wrapped notes. -- **Odd** steps (**1**, **3**, **5**, ...) add **features**: extra panes, menus, and controls. - -There is one deliberate **split between 2 and 3** in the [Sketch List](#sketch-list): at **2** the **[P]** column appears but the button is disabled (layout preview); at **3** **[P]** works and row **expand** (`>`) is enabled. That way help (step 2) can appear before the properties workflow (step 3). - -**Pane visibility** (Options, Sketch List, and so on) is still saved in your settings file. Lowering verbosity hides panes without clearing those flags; raising verbosity shows them again if they were on before. - -#### Why it exists - -A lower verbosity keeps the screen focused on the 3D view and core modeling actions, which helps on small displays or while learning the toolbar. Higher values expose lists, scripting consoles, import paths, and inline documentation for day-to-day work. You can raise verbosity temporarily when you need a control, then lower it again. - -#### What each value enables - -The table lists what **first becomes available** at each step (not everything repeated at every row). - -| Value | Step type | Newly available | -| --- | --- | --- | -| **0** | Minimal | **Toolbar** and **3D view**. **File**: New, Open, Save, Save as, Export, Exit. **Edit**: Undo, Redo, New sketch, quick **Add** primitives (box, pyramid, sphere, cylinder, cone, torus at default size, no `*_prms` dialogs). **View**: **Settings** only. **Help**: About, Usage Guide. **Settings**: UI verbosity, Dark mode, **3D view navigation**, **3D view background**, **Sketch** (dimension width, underlay tint, snap guides). No Options, Sketch List, Shape List, or Log panes. No toolbar tooltips. | -| **1** | Features | **Options**, **Sketch List**, **Shape List**, and **Log** panes (when enabled under **View**). Matching **View** menu entries to toggle them. | -| **2** | Help | **Toolbar** button tooltips. Sketch List: disabled **[P]** placeholder (column reserved, not clickable). | -| **3** | Features | **File**: Import, Sketch underlay image, **Examples**. **Lua** / **Python** consoles (**View** menu). Sketch List: active **[P]** (sketch properties), **`>`** expand and per-sketch inspector. | -| **4** | Help | Hover tooltips on Options, sketch/shape lists, sketch properties, and most Settings controls; `(?)` markers on Settings rows (for example grid extent, dimension width). | -| **5** | Features | **Edit**: **Add box_prms**, **Add pyramid_prms**, and other `*_prms` entries (parameter dialogs). **Settings**: **UI corner rounding**, **3D view grid**, **Startup project**. | -| **6** | Help | Longer wrapped hints (for example Options **Shortcuts**, Settings view-navigation paragraph). Settings **`?`** links to the online usage guide. Extra sketch-properties help (for example underlay shear note). | -| **7+** | Reserved | Same as **6** until a future version defines more tiers. | - -**Always on** (at any verbosity): project save/open, toolbar modes, **Export**, and the essential **Settings** sections listed for **0**. **Import** and scripting require at least **3**. - -For the control itself and the JSON key, see **[usage-settings.md](usage-settings.md#settings-pane)**. +For **View** (Settings, pane toggles, consoles), saving preferences, and the **Settings** pane sections, see **[usage-settings.md](usage-settings.md)**. For **Options** panel details by mode, see **[Options panel](usage-settings.md#options-panel)**. ### Sketch List -The **Sketch List** pane lists all 2D sketches in the current document. Open it from **View -> Sketch List** (requires [UI verbosity](#ui-verbosity) **1** or higher). +The **Sketch List** pane lists all 2D sketches in the current document. Open it from **View -> Sketch List**. Each row is laid out left to right: -- **Expand** - At verbosity **3+**, click **`>`** / **`v`** to show or hide details for that sketch (tooltip *Expand details* / *Collapse details* when help tier 2+ is on). Not shown below **3**. +- **Expand** - Click **`>`** / **`v`** to show or hide details for that sketch (tooltip *Expand details* / *Collapse details*). - **Set current** - Radio button (circle). The current sketch is used for editing and for operations such as [extrude](#extrude-sketch-face-tool-e). - **Rename** - Click the name field and type a new name. - **Visibility** - Checkbox to show or hide the sketch in the 3D view. - **Underlay** - Checkbox to show or hide an [image underlay](usage-sketch.md#image-underlay) when one is imported (disabled until an underlay exists; tooltip *Display underlay*). -- **Sketch properties** - **`[P]`** column at verbosity **2+**; the button is active at **3+** and opens **Sketch properties** (import/remove underlay, calibration, transform). At **2** the control is visible but disabled as a preview. See [Image underlay](usage-sketch.md#image-underlay). +- **Sketch properties** - **`[P]`** opens **Sketch properties** (import/remove underlay, calibration, transform). See [Image underlay](usage-sketch.md#image-underlay). - **Delete** - Right-click the name and choose **Delete**. -When expanded (verbosity **3+**), the row shows: +When expanded, the row shows: - **Dimensions** - Table of length dimensions: visibility, editable name, and **offset** (label distance from the edge; **0** = automatic). - **Nodes**, **Edges**, **Faces** - Collapsible lists of element labels for inspection (read-only names). @@ -146,10 +109,10 @@ At the top: For each shape, one row includes: - **Name** - Editable text field; change the label stored with the shape. -- **Right-click the name** - Opens a context menu with **Material** and the same material list as the **M** button. +- **Right-click the name** - **Delete** removes the shape from the document. - **Visibility** - Checkbox (tooltip *visibility*) to show or hide that shape in the 3D view. - **Solid / wire** - Checkbox (tooltip *solid/wire*) to switch **shaded** display or **wireframe** for that shape. -- **M** - Opens a **Material** popup to pick an Open CASCADE material preset (also shown in the tooltip). You can also use the context menu on the name. +- **M** - Click to open a **Material** popup; right-click **M** for **Delete**. The tooltip on **M** also notes that right-clicking the name deletes the shape. Rows that match the **current 3D selection** are drawn with a slightly brighter style so the list stays in sync with what is selected in the viewer (tooltip *Selected in 3D viewer* when you hover the highlighted row).