View backgrounds: reference blend, image adjust, layouts, cleanup, style name

- Gradients: the middle colour sits (horizon - 0.5) viewport widths from the
  centre and blends over height viewport heights each side; two colours
  blend over a viewport height each side.
- Image backgrounds: offset in device pixels (right, down), negative scale
  mirrors, fitted with aspect ratio covers the viewport; the dialog keeps an
  image's offset and scale.
- Layouts: a model-space view restored on a sheet asks for the viewport,
  enters it and gives it the view's camera, background and visual style;
  inside a viewport the view goes there; a paper-space view's background is
  kept on the sheet viewport but not drawn; floating viewports draw their
  background.
- Background objects no view or viewport uses any more are erased; a view
  without a background restored where the viewport already is leaves the
  viewport's background.
- The viewport's named visual style (Realistic, ...) shows by name and the
  render-mode picker records its style on the viewport record.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
ramox81andClaude Opus 5.5 committed 2026-10-12 17:31:01 +03:00
1 parent 1cf13971dc
commit 9ef8f4bedf
12 files changed
+349 -70

No files matched your search

+32 -1
View File
@@ -57,6 +57,8 @@ pub struct ViewInfo {
pub category: String,
pub visual_style: Option<String>,
pub live_section: Option<String>,
/// Saved in paper space.
pub paper_space: bool,
}
/// What -VIEW checks typed names against.
@@ -65,6 +67,10 @@ pub struct ViewNames {
pub views: Vec<ViewInfo>,
pub visual_styles: Vec<String>,
pub live_sections: Vec<String>,
/// On a layout's sheet (no viewport entered): the layout's viewports as
/// (handle, [min x, min y, max x, max y]), one of which takes a
/// model-space view being restored.
pub sheet_viewports: Option<Vec<(u64, [f64; 4])>>,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
@@ -106,6 +112,7 @@ enum Step {
List,
Delete,
Restore,
RestoreViewport(String),
Save,
WindowName,
WindowFirst(String),
@@ -350,6 +357,7 @@ impl CadCommand for DashViewCommand {
Step::List | Step::SettingViewList(_) => "Enter view name(s) to list <*>:".into(),
Step::Delete => "Enter view name(s) to delete:".into(),
Step::Restore => "Enter view name to restore:".into(),
Step::RestoreViewport(_) => "Select Viewport for view:".into(),
Step::Save | Step::WindowName => "Enter view name to save:".into(),
Step::WindowFirst(_) => "Specify first corner:".into(),
Step::WindowSecond(..) => "Specify opposite corner:".into(),
@@ -421,9 +429,19 @@ impl CadCommand for DashViewCommand {
}
}
Step::Restore => match self.view(t) {
// On a sheet a model-space view goes into a viewport the
// user selects.
Some(view) if !view.paper_space && self.names.sheet_viewports.is_some() => {
self.step = Step::RestoreViewport(view.name.clone());
CmdResult::ReportMeasurement("Restoring Model space view.".into())
}
Some(view) => CmdResult::Dispatch(format!("-VIEW >RESTORE {}", view.name)),
None => Self::end(&format!("Cannot find view \"{t}\".")),
},
Step::RestoreViewport(name) => {
self.step = Step::RestoreViewport(name);
CmdResult::ReportError("*Invalid selection*".into())
}
Step::Save => CmdResult::Dispatch(format!("-VIEW >SAVE {t}")),
Step::WindowName => {
self.step = Step::WindowFirst(t.to_string());
@@ -494,6 +512,19 @@ impl CadCommand for DashViewCommand {
"-VIEW >WINDOW {}\u{1f}{},{}\u{1f}{},{}",
name, first.x, first.y, pt.x, pt.y
)),
Step::RestoreViewport(name) => {
// The topmost viewport under the pick.
let hit = self.names.sheet_viewports.iter().flatten().rev().find(|(_, [x0, y0, x1, y1])| {
pt.x >= *x0 && pt.x <= *x1 && pt.y >= *y0 && pt.y <= *y1
});
match hit {
Some((handle, _)) => CmdResult::Dispatch(format!("-VIEW >RESTOREVP {name}\u{1f}{handle:X}")),
None => {
self.step = Step::RestoreViewport(name);
CmdResult::NeedPoint
}
}
}
step => {
self.step = step;
CmdResult::NeedPoint
@@ -503,7 +534,7 @@ impl CadCommand for DashViewCommand {
fn on_enter(&mut self) -> CmdResult {
match std::mem::replace(&mut self.step, Step::Main) {
Step::Main | Step::Delete | Step::Restore | Step::Save | Step::WindowName => {
Step::Main | Step::Delete | Step::Restore | Step::RestoreViewport(_) | Step::Save | Step::WindowName => {
CmdResult::Dispatch("-VIEW >END".into())
}
Step::Orthographic => CmdResult::Dispatch("-VIEW >PRESET TOP".into()),
+32
View File
@@ -106,6 +106,38 @@ pub fn label_for(mode: Mode) -> &'static str {
.unwrap_or("Wireframe 2D")
}
/// The render mode a named visual style draws as, and whether the name is a
/// style of its own (Realistic, Conceptual, …) rather than one of the modes.
pub fn mode_for_style_name(name: &str) -> Option<(Mode, bool)> {
Some(match name {
"2dWireframe" => (Mode::Wireframe2D, false),
"Wireframe" => (Mode::Wireframe3D, false),
"Hidden" => (Mode::HiddenLine, false),
"Flat" => (Mode::FlatShaded, false),
"FlatWithEdges" => (Mode::FlatShadedWithEdges, false),
"Gouraud" => (Mode::GouraudShaded, false),
"GouraudWithEdges" => (Mode::GouraudShadedWithEdges, false),
"Shaded with edges" => (Mode::GouraudShadedWithEdges, true),
"Realistic" | "Shaded" | "Conceptual" | "Shades of Gray" | "Sketchy" | "X-Ray" => {
(Mode::GouraudShaded, true)
}
_ => return None,
})
}
/// The name of the visual style a render mode is saved as.
pub fn style_name_for(mode: Mode) -> &'static str {
match mode {
Mode::Wireframe2D => "2dWireframe",
Mode::Wireframe3D => "Wireframe",
Mode::HiddenLine => "Hidden",
Mode::FlatShaded => "Flat",
Mode::FlatShadedWithEdges => "FlatWithEdges",
Mode::GouraudShaded => "Gouraud",
Mode::GouraudShadedWithEdges => "GouraudWithEdges",
}
}
/// The style a style keyword names. Only the seven exist; nothing maps onto a
/// nearest neighbour, because there is no longer anything else to map from.
pub fn mode_for_keyword(keyword: &str) -> Option<Mode> {