mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-02 18:16:19 +00:00
* claim: #9274 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Browser: placements start closed (#9274) A large assembly opened with every placement unfolded, so the browser was a long list to scroll through. Placements now start closed; opening one shows its own placements still closed, and closing and reopening it leaves them as they were. Find in Browser, a pick in the view, Expand All and Collapse All open and close them as before. Preferences > Interface > Components start open (browser_components_open) keeps every placement open from the start, as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Browser: scenarios and the icon audit open placements, which now start closed Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Browser: tests that read rows inside placements set the open-placements preference Three tests added on main since this branch started (joint folders, Features folder marks, group rename) look at rows inside placements, which now start closed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: bherbruck <tenbee91@gmail.com> Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"en": {
|
||||
"prefs.browser_components_open": "Components start open",
|
||||
"prefs.browser_components_open_note": "Every component in the browser starts open, as before, instead of closed until you open it."
|
||||
},
|
||||
"ar": {
|
||||
"prefs.browser_components_open": "المكوّنات مفتوحة من البداية",
|
||||
"prefs.browser_components_open_note": "يبدأ كل مكوّن في المستعرض مفتوحًا كما كان من قبل، بدلاً من أن يبقى مغلقًا حتى تفتحه."
|
||||
},
|
||||
"de": {
|
||||
"prefs.browser_components_open": "Komponenten zu Beginn aufgeklappt",
|
||||
"prefs.browser_components_open_note": "Jede Komponente im Browser ist wie bisher von Anfang an aufgeklappt, statt zugeklappt zu bleiben, bis du sie aufklappst."
|
||||
},
|
||||
"es": {
|
||||
"prefs.browser_components_open": "Componentes abiertos al inicio",
|
||||
"prefs.browser_components_open_note": "Cada componente del explorador empieza abierto, como antes, en lugar de cerrado hasta que lo abras."
|
||||
},
|
||||
"fr": {
|
||||
"prefs.browser_components_open": "Composants dépliés au départ",
|
||||
"prefs.browser_components_open_note": "Chaque composant du navigateur commence déplié, comme avant, au lieu de rester replié jusqu'à ce que vous le dépliiez."
|
||||
},
|
||||
"he": {
|
||||
"prefs.browser_components_open": "רכיבים פתוחים מההתחלה",
|
||||
"prefs.browser_components_open_note": "כל רכיב בעץ התכן מתחיל פתוח, כמו קודם, במקום סגור עד שתפתח אותו."
|
||||
},
|
||||
"it": {
|
||||
"prefs.browser_components_open": "Componenti aperti all'inizio",
|
||||
"prefs.browser_components_open_note": "Ogni componente nel browser inizia aperto, come prima, invece che chiuso finché non lo apri."
|
||||
},
|
||||
"ja": {
|
||||
"prefs.browser_components_open": "コンポーネントを最初から展開",
|
||||
"prefs.browser_components_open_note": "ブラウザーのすべてのコンポーネントを以前と同じく最初から展開して表示します。オフの場合は展開するまで折りたたまれています。"
|
||||
},
|
||||
"ko": {
|
||||
"prefs.browser_components_open": "구성요소를 펼친 상태로 시작",
|
||||
"prefs.browser_components_open_note": "브라우저의 모든 구성요소가 이전처럼 펼쳐진 상태로 시작합니다. 끄면 직접 펼칠 때까지 접혀 있습니다."
|
||||
},
|
||||
"pt-BR": {
|
||||
"prefs.browser_components_open": "Componentes começam abertos",
|
||||
"prefs.browser_components_open_note": "Cada componente no navegador começa aberto, como antes, em vez de fechado até que você o abra."
|
||||
},
|
||||
"ru": {
|
||||
"prefs.browser_components_open": "Компоненты развёрнуты с начала",
|
||||
"prefs.browser_components_open_note": "Каждый компонент в браузере сразу развёрнут, как раньше, а не свёрнут, пока вы его не развернёте."
|
||||
},
|
||||
"uk": {
|
||||
"prefs.browser_components_open": "Компоненти розгорнуті з початку",
|
||||
"prefs.browser_components_open_note": "Кожен компонент у браузері одразу розгорнутий, як раніше, а не згорнутий, доки ви його не розгорнете."
|
||||
},
|
||||
"vi": {
|
||||
"prefs.browser_components_open": "Thành phần mở sẵn",
|
||||
"prefs.browser_components_open_note": "Mọi thành phần trong trình duyệt đều mở sẵn như trước, thay vì đóng cho đến khi bạn mở."
|
||||
},
|
||||
"zh": {
|
||||
"prefs.browser_components_open": "组件初始展开",
|
||||
"prefs.browser_components_open_note": "浏览器中的每个组件都像以前一样初始展开,而不是在您展开前保持折叠。"
|
||||
},
|
||||
"zh-TW": {
|
||||
"prefs.browser_components_open": "元件初始展開",
|
||||
"prefs.browser_components_open_note": "瀏覽器中的每個元件都像以前一樣初始展開,而不是在您展開前保持摺疊。"
|
||||
}
|
||||
}
|
||||
@@ -53,10 +53,10 @@ pub(crate) fn reveal_body(app: &mut SolveApp, body: &str) {
|
||||
};
|
||||
app.tree.collapsed.remove("c0");
|
||||
for depth in 1..=path.len() {
|
||||
app.tree.collapsed.remove(&occurrence_key(&path[..depth]));
|
||||
app.tree.open_row(&occurrence_key(&path[..depth]));
|
||||
}
|
||||
let scope = if path.is_empty() { format!("c{component}") } else { occurrence_key(&path) };
|
||||
app.tree.collapsed.remove(&scope);
|
||||
app.tree.open_row(&scope);
|
||||
app.tree.collapsed.remove(&format!("{scope}/bodies"));
|
||||
open_group_chain(app, &scope, component, "bodies", &source);
|
||||
}
|
||||
@@ -200,6 +200,25 @@ impl TreeState {
|
||||
self.picked_folder = None;
|
||||
}
|
||||
|
||||
/// Open a row. A placement's row is noted open in `expanded` as well, because it starts
|
||||
/// closed unless the "Components start open" preference is on (#9274).
|
||||
pub(crate) fn open_row(&mut self, key: &str) {
|
||||
self.collapsed.remove(key);
|
||||
if is_placement_key(key) && !self.expanded.contains(key) {
|
||||
self.expanded.insert(key.to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
/// Close a row, whichever way its placement starts.
|
||||
pub(crate) fn close_row(&mut self, key: &str) {
|
||||
if !self.collapsed.contains(key) {
|
||||
self.collapsed.insert(key.to_owned());
|
||||
}
|
||||
if is_placement_key(key) {
|
||||
self.expanded.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
fn remember(&mut self, key: &str) {
|
||||
if let Some(slot) = self.order.get_mut(self.order_len) {
|
||||
if slot != key {
|
||||
@@ -694,12 +713,32 @@ fn reveal_path(app: &mut SolveApp) -> Option<Vec<u64>> {
|
||||
app.tree.model.as_mut()?.body_path(&app.session, &body)
|
||||
}
|
||||
|
||||
/// A placement's own row (`o:1/2`), not a folder under it (`o:1/2/bodies`).
|
||||
pub(crate) fn is_placement_key(key: &str) -> bool {
|
||||
key.strip_prefix("o:").is_some_and(|p| !p.is_empty() && p.bytes().all(|b| b.is_ascii_digit() || b == b'/'))
|
||||
}
|
||||
|
||||
/// Whether a placement's row is open. Placements start closed, so a large assembly opens as a
|
||||
/// short list (#9274); the "Components start open" preference keeps them open as before.
|
||||
pub(crate) fn placement_open(app: &SolveApp, key: &str) -> bool {
|
||||
!app.tree.collapsed.contains(key) && (app.preferences.browser_components_open || app.tree.expanded.contains(key))
|
||||
}
|
||||
|
||||
pub(crate) fn is_open(app: &SolveApp, key: &str, default: bool) -> bool {
|
||||
if is_placement_key(key) {
|
||||
return placement_open(app, key);
|
||||
}
|
||||
if default { !app.tree.collapsed.contains(key) } else { app.tree.expanded.contains(key) }
|
||||
}
|
||||
|
||||
pub(crate) fn toggle(app: &mut SolveApp, key: &str, default: bool) {
|
||||
if default {
|
||||
if is_placement_key(key) {
|
||||
if placement_open(app, key) {
|
||||
app.tree.close_row(key);
|
||||
} else {
|
||||
app.tree.open_row(key);
|
||||
}
|
||||
} else if default {
|
||||
if !app.tree.collapsed.remove(key) {
|
||||
app.tree.collapsed.insert(key.to_string());
|
||||
}
|
||||
@@ -709,18 +748,19 @@ pub(crate) fn toggle(app: &mut SolveApp, key: &str, default: bool) {
|
||||
}
|
||||
|
||||
/// Apply Expand All / Collapse All: open-by-default keys live in `collapsed` when closed;
|
||||
/// closed-by-default keys live in `expanded` when open.
|
||||
/// closed-by-default keys live in `expanded` when open. Placements, whichever way they start,
|
||||
/// are noted in both.
|
||||
pub fn apply_fold(app: &mut SolveApp, open: bool, open_by_default: &[String], closed_by_default: &[String]) {
|
||||
if open {
|
||||
for key in open_by_default {
|
||||
app.tree.collapsed.remove(key);
|
||||
app.tree.open_row(key);
|
||||
}
|
||||
for key in closed_by_default {
|
||||
app.tree.expanded.insert(key.clone());
|
||||
}
|
||||
} else {
|
||||
for key in open_by_default {
|
||||
app.tree.collapsed.insert(key.clone());
|
||||
app.tree.close_row(key);
|
||||
}
|
||||
for key in closed_by_default {
|
||||
app.tree.expanded.remove(key);
|
||||
@@ -1595,7 +1635,7 @@ fn occurrence_key(path: &[u64]) -> String {
|
||||
/// Show a placement's row closed: a pasted (or moved) component arrives folded, whatever a row
|
||||
/// at that path showed before.
|
||||
pub(crate) fn close_placement(app: &mut SolveApp, path: &[u64]) {
|
||||
app.tree.collapsed.insert(occurrence_key(path));
|
||||
app.tree.close_row(&occurrence_key(path));
|
||||
}
|
||||
|
||||
/// A placement, rather than a component definition: repeated child IDs remain distinct
|
||||
@@ -1618,7 +1658,7 @@ fn occurrence_rows_inner(
|
||||
) {
|
||||
let key = &placement.key;
|
||||
if reveal_path(app).is_some_and(|rp| rp.starts_with(path)) {
|
||||
app.tree.collapsed.remove(key);
|
||||
app.tree.open_row(key);
|
||||
}
|
||||
let open = is_open(app, key, true);
|
||||
let on_screen = ui.is_rect_visible(row_rect(ui));
|
||||
|
||||
@@ -41,10 +41,10 @@ pub(crate) fn reveal(app: &mut SolveApp, id: u64, body: &str) {
|
||||
app.tree.reveal = None;
|
||||
app.tree.collapsed.remove("c0");
|
||||
for depth in 1..=path.len() {
|
||||
app.tree.collapsed.remove(&occurrence_key(&path[..depth]));
|
||||
app.tree.open_row(&occurrence_key(&path[..depth]));
|
||||
}
|
||||
let scope = if path.is_empty() { format!("c{component}") } else { occurrence_key(&path) };
|
||||
app.tree.collapsed.remove(&scope);
|
||||
app.tree.open_row(&scope);
|
||||
app.tree.expanded.insert(format!("{scope}/features"));
|
||||
app.tree.reveal_feature = Some(Reveal { id, path });
|
||||
}
|
||||
@@ -731,6 +731,8 @@ mod tests {
|
||||
#[test]
|
||||
fn only_folded_features_folders_on_screen_work_out_their_mark() {
|
||||
let mut h = Harness::new();
|
||||
// The folders sit inside placements, which start closed (#9274).
|
||||
h.app.preferences.browser_components_open = true;
|
||||
let component = h.app.run("component.create", json!({"name":"Part"})).unwrap();
|
||||
let feature = h.app.run("solid.box", json!({"length":10,"width":10,"height":10,"body_name":"Plate"})).unwrap()["feature"].as_u64().unwrap();
|
||||
h.app.run("component.activate", json!({"component":0})).unwrap();
|
||||
|
||||
@@ -78,6 +78,8 @@ fn f2_on_a_clicked_browser_group_renames_the_group() {
|
||||
h.app.run("solid.box", json!({"length":10,"width":10,"height":10,"body_name":"Body1"})).unwrap();
|
||||
(h, 0)
|
||||
};
|
||||
// The group's row sits inside a placement, which starts closed (#9274).
|
||||
h.app.preferences.browser_components_open = true;
|
||||
let body = h.app.session.model.state().bodies[0].name.clone();
|
||||
let group = h.app.run("browser.group", json!({"component":component,"folder":"bodies","items":[body],"name":"Group"})).unwrap()["group"]
|
||||
.as_u64()
|
||||
@@ -790,6 +792,8 @@ fn browser_occurrence_clicks_fill_align_components_input() {
|
||||
#[test]
|
||||
fn row_eyes_line_up_at_the_right_end_unless_the_preference_keeps_them_left() {
|
||||
let mut h = Harness::new();
|
||||
// These rows are read with every placement open, as placements started before #9274.
|
||||
h.app.preferences.browser_components_open = true;
|
||||
h.app.run("solid.box", json!({"length":10,"width":10,"height":10,"body_name":"Top"})).unwrap();
|
||||
let part = h.app.run("component.create", json!({"name":"Part"})).unwrap()["occurrence"].as_u64().unwrap();
|
||||
h.app.run("solid.box", json!({"length":10,"width":10,"height":10,"corner":[20,0,0],"body_name":"Inner"})).unwrap();
|
||||
|
||||
@@ -500,3 +500,58 @@ fn a_design_saved_before_nested_groups_keeps_its_browser_order() {
|
||||
assert_eq!(drawn(&rows), expected, "groups {groups:?}, saved order {saved:?}");
|
||||
}
|
||||
}
|
||||
|
||||
/// #9274: placements start closed, so a large assembly opens as a short list. Opening one shows
|
||||
/// its own placements still closed, and closing and reopening it leaves them as they were.
|
||||
/// Expand All opens them, and the "Components start open" preference opens every one as before.
|
||||
#[test]
|
||||
fn placements_start_closed_and_the_preference_opens_them_as_before() {
|
||||
fn drawn(h: &mut crate::scenario::Harness) -> Vec<(Vec<u64>, bool)> {
|
||||
h.frames(2);
|
||||
super::drawn_occurrences().into_iter().map(|(path, _, _, open)| (path, open)).collect()
|
||||
}
|
||||
let mut h = crate::scenario::Harness::new();
|
||||
h.app.ui.show_browser = true;
|
||||
let sub = h.app.run("component.create", json!({"name":"Sub"})).unwrap();
|
||||
let outer = vec![sub["occurrence"].as_u64().unwrap()];
|
||||
let leaf = h.app.run("component.create", json!({"name":"Leaf"})).unwrap()["occurrence"].as_u64().unwrap();
|
||||
h.app.run("solid.box", json!({"length":10,"width":10,"height":10})).unwrap();
|
||||
h.app.run("component.activate", json!({"component":0})).unwrap();
|
||||
let inner = vec![outer[0], leaf];
|
||||
let fold = format!("fold:occurrence:{}", outer[0]);
|
||||
|
||||
assert_eq!(drawn(&mut h), [(outer.clone(), false)], "only the top placement is listed, closed");
|
||||
click(&mut h, &fold);
|
||||
assert_eq!(drawn(&mut h), [(outer.clone(), true), (inner.clone(), false)], "the placement inside stays closed");
|
||||
click(&mut h, &fold);
|
||||
assert_eq!(drawn(&mut h), [(outer.clone(), false)]);
|
||||
click(&mut h, &fold);
|
||||
assert_eq!(drawn(&mut h), [(outer.clone(), true), (inner.clone(), false)], "reopening shows it as it was");
|
||||
|
||||
h.app.run("browser.expand_all", json!({})).unwrap();
|
||||
assert_eq!(drawn(&mut h), [(outer.clone(), true), (inner.clone(), true)], "Expand All opens every placement");
|
||||
h.app.run("browser.collapse_all", json!({})).unwrap();
|
||||
assert_eq!(drawn(&mut h), [(outer.clone(), false)], "Collapse All closes them again");
|
||||
|
||||
h.app.tree.collapsed.clear();
|
||||
h.app.tree.expanded.clear();
|
||||
h.call("ui.prefs", json!({"browser_components_open": true}));
|
||||
assert!(h.app.preferences.browser_components_open);
|
||||
assert_eq!(drawn(&mut h), [(outer.clone(), true), (inner, true)], "the preference opens every placement, as before #9274");
|
||||
click(&mut h, &fold);
|
||||
assert_eq!(drawn(&mut h), [(outer, false)], "and its arrow still closes one");
|
||||
}
|
||||
|
||||
/// #9274: Find in Browser opens the placements, closed from the start, down to the body's row.
|
||||
#[test]
|
||||
fn find_in_browser_opens_placements_that_start_closed() {
|
||||
let (mut h, _, occurrence) = fixture();
|
||||
h.app.ui.show_browser = true;
|
||||
let body = super::model_placement(&mut h.app, &[occurrence]).unwrap().bodies[0].world.clone();
|
||||
h.frames(2);
|
||||
assert!(!super::is_open(&h.app, &super::occurrence_key(&[occurrence]), true), "the placement starts closed");
|
||||
super::reveal_body(&mut h.app, &body);
|
||||
h.frames(3);
|
||||
assert!(super::is_open(&h.app, &super::occurrence_key(&[occurrence]), true));
|
||||
assert!(h.app.tree.order.contains(&format!("b:{body}")), "the body's row is drawn");
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ fn harness() -> Harness {
|
||||
let mut h = Harness::new();
|
||||
h.app.home.open = false;
|
||||
h.app.ui.show_browser = true;
|
||||
// The tests read the Joints folders inside placements, which start closed (#9274).
|
||||
h.app.preferences.browser_components_open = true;
|
||||
crate::test_support::grounded_boxes(&[("A", 0), ("B", 30), ("C", 60)], |id, p| h.app.run(id, p).unwrap());
|
||||
h.app
|
||||
.run("joint.create", json!({"type": "revolute", "name": "Hinge", "a": {"occurrence": "A:1", "face": [10, 10, 10]}, "b": {"occurrence": "B:1", "face": [40, 10, 0]}}))
|
||||
|
||||
@@ -6,6 +6,8 @@ use solidcraft_engine::Sel;
|
||||
#[test]
|
||||
fn replaced_body_name_uses_evaluated_owner_in_browser_and_component_actions() {
|
||||
let mut h = Harness::new();
|
||||
// These rows are read with every placement open, as placements started before #9274.
|
||||
h.app.preferences.browser_components_open = true;
|
||||
h.app.run("solid.box", json!({"length":10,"width":10,"height":10,"body_name":"Block"})).unwrap();
|
||||
let transferred = h.app.run("component.from_bodies", json!({"bodies":["Block"]})).unwrap();
|
||||
let owner = transferred["components"][0]["component"].as_u64().unwrap();
|
||||
@@ -30,6 +32,8 @@ fn replaced_body_name_uses_evaluated_owner_in_browser_and_component_actions() {
|
||||
fn fixture() -> (Harness, u64, u64, u64) {
|
||||
let (mut h, component, first) = crate::test_support::component_box();
|
||||
let second = h.app.run("occurrence.copy", json!({"occurrence":first,"translate":[50,0,0]})).unwrap()["occurrence"].as_u64().unwrap();
|
||||
// These rows are read with every placement open, as placements started before #9274.
|
||||
h.app.preferences.browser_components_open = true;
|
||||
h.frames(3);
|
||||
(h, component, first, second)
|
||||
}
|
||||
@@ -305,6 +309,8 @@ fn occurrence_body_appearance_editor_inherits_definition_precision() {
|
||||
#[test]
|
||||
fn occurrence_nested_shared_child_has_distinct_rows_and_scope() {
|
||||
let mut h = Harness::new();
|
||||
// These rows are read with every placement open, as placements started before #9274.
|
||||
h.app.preferences.browser_components_open = true;
|
||||
let parent = h.app.run("component.create", json!({"name":"Assembly"})).unwrap();
|
||||
let parent_component = parent["component"].as_u64().unwrap();
|
||||
let parent_occurrence = parent["occurrence"].as_u64().unwrap();
|
||||
@@ -362,6 +368,8 @@ fn occurrence_distance_editor_reads_inches_and_keeps_four_digits_in_model_space(
|
||||
#[test]
|
||||
fn a_body_dropped_on_a_bodies_folder_moves_into_that_component() {
|
||||
let mut h = Harness::new();
|
||||
// These rows are read with every placement open, as placements started before #9274.
|
||||
h.app.preferences.browser_components_open = true;
|
||||
h.app.home.open = false;
|
||||
h.app.run("solid.box", json!({"length":10,"width":10,"height":10,"body_name":"Plate"})).unwrap();
|
||||
h.app.run("solid.box", json!({"corner":[20,0,0],"length":5,"width":5,"height":5,"body_name":"Lid"})).unwrap();
|
||||
@@ -459,6 +467,8 @@ fn bodies_folders_fold_by_the_preference_but_never_the_designs_or_a_hidden_one()
|
||||
fn a_folded_body_sits_one_level_under_its_nested_placement() {
|
||||
use crate::prefs::BodiesFolders;
|
||||
let mut h = Harness::new();
|
||||
// These rows are read with every placement open, as placements started before #9274.
|
||||
h.app.preferences.browser_components_open = true;
|
||||
let parent = h.app.run("component.create", json!({"name":"Assembly"})).unwrap()["occurrence"].as_u64().unwrap();
|
||||
let child = h.app.run("component.create", json!({"name":"Child"})).unwrap()["occurrence"].as_u64().unwrap();
|
||||
h.app.run("solid.box", json!({"length":10,"width":10,"height":10,"body_name":"Pin"})).unwrap();
|
||||
@@ -536,6 +546,8 @@ fn a_folded_folders_menu_items_move_to_the_placements_menu() {
|
||||
#[test]
|
||||
fn dragging_an_occurrence_row_onto_another_moves_it_into_that_component() {
|
||||
let mut h = Harness::new();
|
||||
// These rows are read with every placement open, as placements started before #9274.
|
||||
h.app.preferences.browser_components_open = true;
|
||||
// Component A with a body, at the design root.
|
||||
let a = h.app.run("component.create", json!({"name":"A"})).unwrap();
|
||||
let (_a_comp, a_occ) = (a["component"].as_u64().unwrap(), a["occurrence"].as_u64().unwrap());
|
||||
|
||||
@@ -1303,6 +1303,9 @@ preference_settings! {
|
||||
/// Each tree row's eye between its fold arrow and its radio, as before #8718, instead of in a
|
||||
/// column at the rows' right end. Off by default.
|
||||
browser_eye_left: bool = false, PAGE_LAYOUT => check_id("prefs.browser_eye_left");
|
||||
/// Every component placement in the browser starts open, as before #9274, instead of closed
|
||||
/// until the user opens it. Off by default.
|
||||
browser_components_open: bool = false, PAGE_LAYOUT => check_id("prefs.browser_components_open");
|
||||
/// The wheel zooms toward the point under the cursor (else toward the view's centre).
|
||||
zoom_to_cursor: bool = true, PAGE_NAVIGATION => check("Zoom to the cursor", "The wheel zooms toward the point under the cursor (off: toward the view's center)");
|
||||
/// Speed multiplier for wheel zoom, independent of the 3D mouse.
|
||||
@@ -5783,6 +5786,7 @@ mod tests {
|
||||
("view_confirm_corner", json!(true), PAGE_LAYOUT),
|
||||
("status_bar", json!(true), PAGE_LAYOUT),
|
||||
("browser_eye_left", json!(true), PAGE_LAYOUT),
|
||||
("browser_components_open", json!(true), PAGE_LAYOUT),
|
||||
("quick_measure", json!(true), PAGE_GRAPHICS),
|
||||
("origin_plane_names", json!("top_front_right"), PAGE_DESIGN),
|
||||
("direct_interaction", json!(true), PAGE_TOOLS),
|
||||
|
||||
@@ -341,6 +341,11 @@ pub(super) fn layout(app: &mut SolveApp, ui: &mut egui::Ui) {
|
||||
app.preferences.browser_bodies_folders = *mode;
|
||||
}
|
||||
});
|
||||
// Placements open in the browser from the start, as before #9274.
|
||||
ui_kit::row(ui, "", |ui| {
|
||||
let check = setting::browser_components_open(app, ui).on_hover_text(app.tr("prefs.browser_components_open_note"));
|
||||
crate::scenario::publish_target("prefs:browser_components_open", check.rect);
|
||||
});
|
||||
// The eye beside the fold arrow, where it was before #8718.
|
||||
ui_kit::row(ui, "", |ui| {
|
||||
let check = setting::browser_eye_left(app, ui).on_hover_text(app.tr("prefs.browser_eye_left_note"));
|
||||
|
||||
@@ -10,6 +10,7 @@ use solidcraft_ui_egui::{icon_svg, scenario::Harness, workspace};
|
||||
fn harness() -> Harness {
|
||||
let mut h = Harness::new();
|
||||
h.app.preferences.auto_operation = false;
|
||||
h.app.preferences.browser_components_open = true;
|
||||
h
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
[
|
||||
{"call": "ui.prefs", "params": {"browser_components_open": true}},
|
||||
{"note": "Bodies folders (#4217, Preferences › Interface): a nested assembly of plain boxes. Frame:1 holds the body Plate and the placement Pin:1, which holds the body Shaft. The design itself has no bodies, so every Bodies row is a component's."},
|
||||
{"note": "Each row's indent handle is where its depth puts it, so their order shows each row's depth."},
|
||||
{"call": "engine.execute", "params": {"command": "component.create", "params": {"name": "Frame"}}},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
[
|
||||
{"call": "ui.prefs", "params": {"browser_components_open": true}},
|
||||
{
|
||||
"note": "A design with every kind of browser folder: bodies in a group, a component, a sketch, a construction plane, a canvas and named views."
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
[
|
||||
{"call": "ui.prefs", "params": {"browser_components_open": true}},
|
||||
{
|
||||
"note": "Browser chevrons expand and collapse every kind of node (folders, components, groups, the origin, named views, document settings). Model: two components with a body each, a joint, a sketch, an offset plane, a named view."
|
||||
},
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
{"expect":{"shown":"(55.00, 5.00, 5.00) mm","query":{"command":"occurrence.properties","params":{"occurrence":4,"path":[4]},"path":["total","center_of_mass",0],"value":55}}},
|
||||
{"shot":"second_occurrence_properties"},
|
||||
{"click":{"handle":"eye:occurrence:4"}},
|
||||
{"note":"Placements start closed (#9274): the fold arrow opens the row, then folds it again."},
|
||||
{"click":{"handle":"fold:occurrence:4"}},
|
||||
{"click":{"handle":"fold:occurrence:4"}},
|
||||
{"shot":"second_occurrence_hidden_folded"},
|
||||
{"click":{"handle":"eye:occurrence:4"}},
|
||||
|
||||
@@ -28,7 +28,10 @@
|
||||
puts it back beside the fold arrow; press an eye and drag up or down over other eyes to show or hide them all at once, as one undo step), a component's radio button makes it the active component,
|
||||
and right-clicking any row gives that item's menu. Right-click the design or a component and choose **Expand All** or
|
||||
**Collapse All** to open or close every folder under that row (the design row stays visible
|
||||
when the whole tree is collapsed). Rows drag into groups and other components. **Preferences ›
|
||||
when the whole tree is collapsed). Components start closed, so a large assembly opens as a
|
||||
short list; open one with its fold arrow, or use **Find in Browser** on a body to open the rows
|
||||
down to it (**Preferences › Interface › Components start open** opens every component from the
|
||||
start, as before). Rows drag into groups and other components. **Preferences ›
|
||||
Interface › Bodies folders** sets when a component's bodies sit in a Bodies folder of their own:
|
||||
**Several bodies only** (the default) lists a component's body straight under it when it has
|
||||
only one and no groups, **Never** lists every component's bodies and groups straight under it
|
||||
|
||||
@@ -468,6 +468,7 @@ One setting per line, sorted by name. A change that adds a setting adds its own
|
||||
- `assembly_move_handles` (default true): explicit Assembly Move uses the permitted joint-motion handles; false keeps the previous Move panel.
|
||||
- `auto_operation` (default true: feature windows choose Join, New Body or Cut from what their material touches until one is picked; false: each keeps the operation it opens with, Extrude its own Join or Cut)
|
||||
- `browser_bodies_folders` (`several` (default): a component with one body and no groups lists it straight under the component in the browser, without a Bodies folder; `always`; `never`: components list their bodies and groups straight under them, and the folder's menu items are on the component's menu; the design's own Bodies folder, and one hidden with its eye, always show; #4217)
|
||||
- `browser_components_open` (default false: each component placement in the browser starts closed until it is opened, by its fold arrow, Expand All or Find in Browser; true: every placement starts open, as before #9274)
|
||||
- `browser_eye_left` (default false: each browser and History tree row's eye, handle `eye:<name>`, sits in a column at the rows' right end, clear of the fold arrow and the radio; true: between them, as before #8718)
|
||||
- `check_updates` (default true; [updates](book/src/guide/updates.md))
|
||||
- `color_vision` (`off` (default), `protan`, `deutan`, `tritan`: colour vision modes, #778)
|
||||
|
||||
Reference in New Issue
Block a user