forked from 1b-agent/opencadstudio-upstream
Merge branch 'HakanSeven12:main' into main
This commit is contained in:
28 files changed
+1133
-273
No files matched your search
Generated
+1
@@ -45,6 +45,7 @@ dependencies = [
|
||||
"objc2-foundation 0.2.2",
|
||||
"ocs_plugin_api",
|
||||
"open",
|
||||
"pollster",
|
||||
"printpdf",
|
||||
"rayon",
|
||||
"resvg",
|
||||
|
||||
@@ -55,6 +55,7 @@ ttf-parser = "0.25"
|
||||
cosmic-text = "0.15"
|
||||
unicode-bidi = "0.3"
|
||||
lyon_tessellation = "1.0.20"
|
||||
pollster = "0.4"
|
||||
|
||||
[dev-dependencies]
|
||||
fluent-syntax = "0.12"
|
||||
|
||||
@@ -193,7 +193,7 @@ fn call_timeout() -> Duration {
|
||||
|
||||
/// Per-request-kind timeout floors. The user-configured default is raised to
|
||||
/// these minima so that no request kind can be configured into an unsafe value.
|
||||
fn request_timeout(kind: &'static str) -> Duration {
|
||||
pub(crate) fn request_timeout(kind: &'static str) -> Duration {
|
||||
base_max_floor(call_timeout(), kind)
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ fn base_max_floor(base: Duration, kind: &'static str) -> Duration {
|
||||
base.max(floor)
|
||||
}
|
||||
|
||||
fn request_kind(req: &HostRequest) -> &'static str {
|
||||
pub(crate) fn request_kind(req: &HostRequest) -> &'static str {
|
||||
match req {
|
||||
HostRequest::GetManifest => "GetManifest",
|
||||
HostRequest::GetRibbon => "GetRibbon",
|
||||
|
||||
@@ -17,63 +17,7 @@ use crate::ipc::v4::server::{
|
||||
default_notify_rate_limit, run_host_reader_thread, HostIncoming, RateLimiter, V4HostShared,
|
||||
};
|
||||
use crate::process::PluginError;
|
||||
|
||||
/// Default maximum time to wait for a plugin call to respond.
|
||||
const CALL_TIMEOUT_DEFAULT: Duration = Duration::from_secs(30);
|
||||
|
||||
fn call_timeout() -> Duration {
|
||||
std::env::var("OCS_PLUGIN_CALL_TIMEOUT_SECS")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.map(Duration::from_secs)
|
||||
.unwrap_or(CALL_TIMEOUT_DEFAULT)
|
||||
}
|
||||
|
||||
/// Per-request-kind timeout floors.
|
||||
fn request_timeout(kind: &'static str) -> Duration {
|
||||
base_max_floor(call_timeout(), kind)
|
||||
}
|
||||
|
||||
fn execute_code_timeout() -> Duration {
|
||||
const DEFAULT: Duration = Duration::from_secs(60);
|
||||
std::env::var("OCS_PLUGIN_EXECUTE_TIMEOUT_SECS")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.map(Duration::from_secs)
|
||||
.unwrap_or(DEFAULT)
|
||||
.max(DEFAULT)
|
||||
}
|
||||
|
||||
fn base_max_floor(base: Duration, kind: &'static str) -> Duration {
|
||||
#[cfg(test)]
|
||||
if let Some(secs) = std::env::var("OCS_PLUGIN_TEST_FLOOR_SECS")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
{
|
||||
return base.max(Duration::from_secs(secs));
|
||||
}
|
||||
let floor = match kind {
|
||||
"GetManifest" | "GetRibbon" => Duration::from_secs(5),
|
||||
"Dispatch" => Duration::from_secs(10),
|
||||
"InteractiveEvent" | "GetPrompt" | "NeedsEntityPick" => Duration::from_secs(2),
|
||||
"ExecuteCode" => execute_code_timeout(),
|
||||
_ => Duration::from_secs(1),
|
||||
};
|
||||
base.max(floor)
|
||||
}
|
||||
|
||||
fn request_kind(req: &HostRequest) -> &'static str {
|
||||
match req {
|
||||
HostRequest::GetManifest => "GetManifest",
|
||||
HostRequest::GetRibbon => "GetRibbon",
|
||||
HostRequest::Dispatch { .. } => "Dispatch",
|
||||
HostRequest::InteractiveEvent { .. } => "InteractiveEvent",
|
||||
HostRequest::GetPrompt { .. } => "GetPrompt",
|
||||
HostRequest::NeedsEntityPick { .. } => "NeedsEntityPick",
|
||||
HostRequest::ExecuteCode { .. } => "ExecuteCode",
|
||||
HostRequest::Shutdown => "Shutdown",
|
||||
}
|
||||
}
|
||||
use crate::process::{request_kind, request_timeout};
|
||||
|
||||
type DeferredRequest = (u64, Option<u64>, Box<PluginRequest>);
|
||||
|
||||
|
||||
@@ -196,15 +196,6 @@
|
||||
<ComponentRef Id='DesktopShortcutComp' />
|
||||
</Feature>
|
||||
</Feature>
|
||||
<CustomAction
|
||||
Id='RefreshShellIcons'
|
||||
Directory='APPLICATIONROOTDIRECTORY'
|
||||
ExeCommand='"[SystemFolder]ie4uinit.exe" -show'
|
||||
Execute='immediate'
|
||||
Return='ignore' />
|
||||
<InstallExecuteSequence>
|
||||
<Custom Action='RefreshShellIcons' After='InstallFinalize'>NOT REMOVE</Custom>
|
||||
</InstallExecuteSequence>
|
||||
<UIRef Id='OpenCADStudioUI' />
|
||||
|
||||
</Product>
|
||||
|
||||
@@ -4393,6 +4393,17 @@ impl OpenCADStudio {
|
||||
// `--read-only` disables saving. `--script` queues command lines.
|
||||
let cfg = crate::cli::gui_config();
|
||||
s.read_only = cfg.read_only;
|
||||
// GPU backend / renderer fallback: the resolver ran before iced
|
||||
// booted, so surface its verdict here where the user can see it.
|
||||
if let Some(notice) = cfg.gpu_fallback_notice {
|
||||
s.command_line.push_warning(¬ice);
|
||||
crate::scene::pipeline::report_gpu_line(&format!("[gpu] {notice}"));
|
||||
}
|
||||
if cfg.gpu_compat_auto {
|
||||
let notice = crate::gpu_backend::compat_notice();
|
||||
s.command_line.push_warning(¬ice);
|
||||
crate::scene::pipeline::report_gpu_line(&format!("[gpu] {notice}"));
|
||||
}
|
||||
let cli_open: Task<Message> = if !cfg.files.is_empty() {
|
||||
Task::batch(
|
||||
cfg.files
|
||||
|
||||
+13
@@ -100,6 +100,13 @@ pub struct Cli {
|
||||
#[arg(help = crate::t!("Log level (error|warn|info|debug|trace). Also reads RUST_LOG.").into_owned(), long_help = None)]
|
||||
pub log: Option<String>,
|
||||
|
||||
/// Internal: probe one GPU backend offscreen (`dx12|vulkan|gl|sw`), print
|
||||
/// one JSON line on success, then exit 0/1. Spawned by the GPU backend
|
||||
/// resolver so a legacy-driver abort kills only the probe child, never
|
||||
/// the editor itself.
|
||||
#[arg(long, value_name = "BACKEND", hide = true)]
|
||||
pub gpu_probe: Option<String>,
|
||||
|
||||
/// Internal: run as the plugin runner child process.
|
||||
#[arg(long, value_names = ["SOCKET", "CDYLIB"], num_args = 2, hide = true)]
|
||||
pub ocs_plugin_runner: Option<Vec<String>>,
|
||||
@@ -124,6 +131,12 @@ pub struct GuiConfig {
|
||||
pub compat_renderer: bool,
|
||||
/// Command lines to run once the editor is up.
|
||||
pub script_lines: Vec<String>,
|
||||
/// Why this launch switched graphics backend, if it did. Shown once
|
||||
/// as a command-line warning so the switch is never silent.
|
||||
pub gpu_fallback_notice: Option<String>,
|
||||
/// The GPU probe found no shader storage buffers: the packed
|
||||
/// compatibility renderer was enabled automatically for this session.
|
||||
pub gpu_compat_auto: bool,
|
||||
}
|
||||
|
||||
/// Set once by `main` before the GUI boots; read by `app::boot`.
|
||||
|
||||
+1030
File diff suppressed because it is too large.
Load diff
@@ -8,6 +8,8 @@ pub mod command;
|
||||
pub mod config;
|
||||
pub mod discussions;
|
||||
pub mod entities;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod gpu_backend;
|
||||
pub mod i18n;
|
||||
pub(crate) mod input;
|
||||
pub mod io;
|
||||
|
||||
+47
-15
@@ -29,6 +29,14 @@ fn main() -> iced::Result {
|
||||
use clap::Parser;
|
||||
let args = cli::Cli::parse();
|
||||
|
||||
// GPU probe child: exercise one backend offscreen, print one JSON
|
||||
// line on success and exit 0/1. This must run before any logging/GUI
|
||||
// setup; the parent interprets any non-zero exit (including a driver
|
||||
// abort) as "this backend is unusable".
|
||||
if let Some(which) = &args.gpu_probe {
|
||||
OpenCADStudio::gpu_backend::run_probe_child(which);
|
||||
}
|
||||
|
||||
// Plugin runner mode: the host spawns itself with this hidden flag to
|
||||
// load a plugin cdylib in an isolated process. Hand off immediately so
|
||||
// the child never touches GUI state.
|
||||
@@ -77,19 +85,20 @@ fn main() -> iced::Result {
|
||||
}
|
||||
|
||||
// GPU backend selection. Explicit `--backend` wins; `--safe-mode`
|
||||
// forces GL for flaky drivers. On Windows, fall back to DX12/Vulkan so
|
||||
// the AMD OpenGL ICD (atio6axx.dll) is never touched at startup — it
|
||||
// access-violates on some hybrid-GPU laptops before any window appears
|
||||
// (#55). An already-set WGPU_BACKEND always wins.
|
||||
if let Some(backend) = &args.backend {
|
||||
std::env::set_var("WGPU_BACKEND", backend);
|
||||
} else if args.safe_mode {
|
||||
std::env::set_var("WGPU_BACKEND", "gl");
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
if std::env::var_os("WGPU_BACKEND").is_none() {
|
||||
std::env::set_var("WGPU_BACKEND", "dx12,vulkan");
|
||||
}
|
||||
// forces GL for flaky drivers. On Windows the preference order starts
|
||||
// with DX12/Vulkan so the AMD OpenGL ICD (atio6axx.dll) is never
|
||||
// touched at startup — it access-violates on some hybrid-GPU laptops
|
||||
// before any window appears (#55). An already-set WGPU_BACKEND always
|
||||
// wins.
|
||||
//
|
||||
// Older GPUs without usable DirectX 12 Feature Level 12_0 or working
|
||||
// Vulkan (e.g. legacy Intel iGPUs), and old GLES drivers whose shader
|
||||
// compiler rejects iced's own shaders, crash at startup or on the
|
||||
// first drawing viewport instead. `resolve_gpu` probes each candidate
|
||||
// backend in an isolated child process and selects the first one that
|
||||
// survives a real offscreen render; a crash sentinel skips backends
|
||||
// that died with the previous run.
|
||||
let gpu = OpenCADStudio::gpu_backend::resolve_gpu(args.backend.as_deref(), args.safe_mode);
|
||||
|
||||
// Headless modes exit without ever creating a window.
|
||||
if args.serve {
|
||||
@@ -145,12 +154,22 @@ fn main() -> iced::Result {
|
||||
}
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let gpu_fallback_notice = gpu
|
||||
.reason
|
||||
.map(|reason| OpenCADStudio::gpu_backend::fallback_notice(&reason));
|
||||
// The probe enables the packed renderer automatically on GPUs without
|
||||
// shader storage buffers; an explicit `--compat-renderer` does the
|
||||
// same without the notice.
|
||||
let compat_renderer = args.compat_renderer || gpu.compat_renderer;
|
||||
let gpu_compat_auto = !args.compat_renderer && gpu.compat_renderer;
|
||||
let _ = cli::GUI_CONFIG.set(cli::GuiConfig {
|
||||
files: if args.new { Vec::new() } else { args.files },
|
||||
new: args.new,
|
||||
read_only: args.read_only,
|
||||
compat_renderer: args.compat_renderer,
|
||||
compat_renderer,
|
||||
script_lines,
|
||||
gpu_fallback_notice,
|
||||
gpu_compat_auto,
|
||||
});
|
||||
|
||||
// Register (or refresh) the freedesktop DWG thumbnailer so file managers
|
||||
@@ -159,6 +178,19 @@ fn main() -> iced::Result {
|
||||
// mode. Silently ignored on failure or non-Linux.
|
||||
io::file_association::install_thumbnailer();
|
||||
|
||||
app::run()
|
||||
// Crash sentinel: armed while the GPU is live, naming the attempted
|
||||
// backend. A stale file at the next launch means this run aborted, so
|
||||
// the resolver skips those backends instead of crashing again.
|
||||
// Inactive on macOS/wasm, where the resolver leaves the env alone.
|
||||
if OpenCADStudio::gpu_backend::gpu_guard_active() {
|
||||
OpenCADStudio::gpu_backend::arm_sentinel(
|
||||
gpu.backend_value.as_deref().unwrap_or("auto"),
|
||||
);
|
||||
let result = app::run();
|
||||
OpenCADStudio::gpu_backend::disarm_sentinel();
|
||||
result
|
||||
} else {
|
||||
app::run()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ use iced::widget::{
|
||||
};
|
||||
use iced::{mouse, Background, Border, Element, Length, Point, Rectangle, Theme};
|
||||
use crate::ui::style::common::muted_style;
|
||||
use crate::ui::style::form::hdivider;
|
||||
use crate::t;
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
@@ -263,19 +264,6 @@ impl canvas::Program<Message> for DimensionPreview {
|
||||
}
|
||||
}
|
||||
|
||||
fn hdivider<'a>(width: iced::Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(width).height(1))
|
||||
.width(width)
|
||||
.height(1)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.palette().background.neutral.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn view_window<'a>(
|
||||
styles: Vec<String>,
|
||||
selected: &'a str,
|
||||
|
||||
@@ -83,6 +83,12 @@ pub fn vseparator<'a>(height: Length) -> Element<'a, Message> {
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Alias kept for call sites that historically used `vsep`.
|
||||
/// Same implementation as [`vseparator`].
|
||||
pub fn vsep<'a>(height: Length) -> Element<'a, Message> {
|
||||
vseparator(height)
|
||||
}
|
||||
|
||||
/// Muted section heading.
|
||||
pub fn section_label<'a>(label: Cow<'static, str>) -> Element<'a, Message> {
|
||||
text(label).size(11).style(muted_style).into()
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::app::Message;
|
||||
use iced::widget::{button, column, container, row, scrollable, text, text_input, Space};
|
||||
use iced::{Background, Border, Element, Theme};
|
||||
use crate::ui::style::common::muted_style;
|
||||
use crate::ui::style::form::{hdivider, vsep};
|
||||
use crate::t;
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
@@ -83,32 +84,6 @@ fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
||||
}
|
||||
}
|
||||
|
||||
fn hdivider<'a>(width: iced::Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(width).height(1))
|
||||
.width(width)
|
||||
.height(1)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.palette().background.neutral.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
fn vsep<'a>(height: iced::Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(1).height(height))
|
||||
.width(1)
|
||||
.height(height)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.palette().background.neutral.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn view_window<'a>(
|
||||
document: &'a acadrust::CadDocument,
|
||||
table: Option<&'a crate::io::plot_style::PlotStyleTable>,
|
||||
|
||||
@@ -327,28 +327,4 @@ pub(crate) fn muted_text_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
crate::ui::style::common::muted_style(theme)
|
||||
}
|
||||
|
||||
pub(crate) fn hdivider<'a>(width: iced::Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(width).height(1))
|
||||
.width(width)
|
||||
.height(1)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.palette().background.neutral.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
pub(crate) fn vsep<'a>(height: iced::Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(1).height(height))
|
||||
.width(1)
|
||||
.height(height)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.palette().background.neutral.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.into()
|
||||
}
|
||||
pub(crate) use crate::ui::style::form::{hdivider, vsep};
|
||||
@@ -1,14 +1,9 @@
|
||||
use crate::app::Message;
|
||||
use crate::t;
|
||||
use crate::ui::style::common::muted_style;
|
||||
use iced::widget::{button, column, container, row, svg, text, Space};
|
||||
use iced::{Background, Border, Element, Fill, Length, Shrink, Theme};
|
||||
|
||||
fn muted_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().background.base.text.scale_alpha(0.68)),
|
||||
}
|
||||
}
|
||||
|
||||
fn primary_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().primary.base.color),
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//! unsaved-changes guard on close.
|
||||
|
||||
use crate::app::Message;
|
||||
use crate::ui::style::common::muted_style;
|
||||
use iced::widget::{button, column, container, row, scrollable, text, text_input, Space};
|
||||
use iced::{Background, Element, Length, Theme};
|
||||
use crate::t;
|
||||
@@ -21,12 +22,6 @@ pub enum AliasField {
|
||||
/// Right-hand lane reserved for the scrollbar so it never overlaps the ✕ column.
|
||||
const GUTTER: f32 = 16.0;
|
||||
|
||||
fn muted_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().background.base.text.scale_alpha(0.68)),
|
||||
}
|
||||
}
|
||||
|
||||
fn danger_text_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().danger.base.color),
|
||||
|
||||
@@ -25,6 +25,8 @@ use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
|
||||
use crate::ui::properties::{lw_options, LwItem};
|
||||
use crate::ui::style::common::muted_style;
|
||||
use crate::ui::style::form::hdivider;
|
||||
|
||||
const LABEL_W: f32 = 120.0;
|
||||
|
||||
@@ -139,12 +141,6 @@ pub fn color_from_label(label: &str) -> Option<AcadColor> {
|
||||
})
|
||||
}
|
||||
|
||||
fn muted_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().background.base.text.scale_alpha(0.68)),
|
||||
}
|
||||
}
|
||||
|
||||
fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
||||
let palette = theme.palette();
|
||||
let border = match status {
|
||||
@@ -161,20 +157,6 @@ fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
||||
}
|
||||
}
|
||||
|
||||
/// Horizontal 1px divider in the shared border colour (matches style windows).
|
||||
fn hdivider<'a>(width: Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(width).height(1))
|
||||
.width(width)
|
||||
.height(1)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.palette().background.neutral.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
/// One `label : widget` row with a fixed-width label column.
|
||||
fn field_row<'a>(
|
||||
label: Cow<'static, str>,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use crate::app::Message;
|
||||
use crate::ui::properties::{lw_options, LinetypeItem, LwItem};
|
||||
use crate::ui::style::common::muted_style;
|
||||
use crate::ui::ROW_H;
|
||||
use acadrust::tables::layer::Layer as DocLayer;
|
||||
use acadrust::tables::Table;
|
||||
@@ -51,12 +52,6 @@ const LINETYPE_MENU_W: f32 = 220.0;
|
||||
/// scrolled into view after it is added (#271).
|
||||
pub const LAYER_TABLE_SCROLL_ID: &str = "layer-manager-table-scroll";
|
||||
|
||||
fn muted_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().background.base.text.scale_alpha(0.68)),
|
||||
}
|
||||
}
|
||||
|
||||
fn table_input_style(
|
||||
theme: &Theme,
|
||||
status: iced::widget::text_input::Status,
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
//! Layout Manager window — fills the entire OS window.
|
||||
|
||||
use crate::app::Message;
|
||||
use crate::ui::style::common::muted_style;
|
||||
use crate::ui::style::form::{hdivider, vsep};
|
||||
use iced::widget::{button, column, container, row, scrollable, text, text_input, Space};
|
||||
use iced::{Background, Element, Theme};
|
||||
use crate::t;
|
||||
|
||||
fn muted_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().background.base.text.scale_alpha(0.68)),
|
||||
}
|
||||
}
|
||||
|
||||
fn primary_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().primary.base.color),
|
||||
@@ -37,32 +33,6 @@ fn list_item(active: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
|
||||
}
|
||||
}
|
||||
|
||||
fn hdivider<'a>(width: iced::Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(width).height(1))
|
||||
.width(width)
|
||||
.height(1)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.palette().background.neutral.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
fn vsep<'a>(height: iced::Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(1).height(height))
|
||||
.width(1)
|
||||
.height(height)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.palette().background.neutral.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn view_window<'a>(
|
||||
layouts: Vec<String>,
|
||||
selected: &'a str,
|
||||
|
||||
@@ -17,6 +17,7 @@ use crate::app::Message;
|
||||
use crate::scene::named_parameters::ParameterTable;
|
||||
use crate::scene::Scene;
|
||||
use crate::t;
|
||||
use crate::ui::style::common::muted_style;
|
||||
use acadrust::types::Handle;
|
||||
use acadrust::EntityType;
|
||||
use iced::widget::tooltip::Position as TipPos;
|
||||
@@ -113,12 +114,6 @@ pub struct ParamEditorRow {
|
||||
/// column — same convention and value as `alias_editor::GUTTER`.
|
||||
const GUTTER: f32 = 16.0;
|
||||
|
||||
fn muted_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().background.base.text.scale_alpha(0.68)),
|
||||
}
|
||||
}
|
||||
|
||||
fn danger_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().danger.base.color),
|
||||
|
||||
@@ -9,6 +9,7 @@ use crate::io::paper_catalog::{self, CustomPaper, Margins, PaperSize, PaperUnits
|
||||
use crate::io::plot_device::PrinterCapabilities;
|
||||
use crate::ui::style::common::muted_style;
|
||||
use crate::ui::style::form;
|
||||
use crate::ui::style::form::{hdivider, vseparator as vsep};
|
||||
use iced::widget::{
|
||||
button, checkbox, column, container, mouse_area, row, scrollable, text, text_input,
|
||||
Space,
|
||||
@@ -543,18 +544,10 @@ fn btn(accent: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
|
||||
form::button_style(accent)
|
||||
}
|
||||
|
||||
fn hdivider<'a>(width: Length) -> Element<'a, Message> {
|
||||
form::hdivider(width)
|
||||
}
|
||||
|
||||
fn section_label<'a>(s: Cow<'static, str>) -> Element<'a, Message> {
|
||||
form::section_label(s)
|
||||
}
|
||||
|
||||
fn vsep<'a>(height: Length) -> Element<'a, Message> {
|
||||
form::vseparator(height)
|
||||
}
|
||||
|
||||
fn setup_row<'a>(
|
||||
name: &'a str,
|
||||
selected: &str,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
use crate::app::Message;
|
||||
use crate::plugin::external::{ExternalPlugin, RegistryEntry, ReleaseInfo};
|
||||
use crate::ui::style::common::muted_style;
|
||||
use iced::widget::{
|
||||
button, column, container, markdown, row, rule, scrollable, text, text_input, Space,
|
||||
};
|
||||
@@ -48,12 +49,6 @@ inventory::submit!(crate::command::CommandRegistration {
|
||||
names: &["PLUGINS", "PLUGINMANAGER"]
|
||||
});
|
||||
|
||||
fn muted_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().background.base.text.scale_alpha(0.68)),
|
||||
}
|
||||
}
|
||||
|
||||
fn primary_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().primary.base.color),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::app::Message;
|
||||
use crate::t;
|
||||
use crate::ui::style::common::muted_style as muted;
|
||||
use iced::widget::{button, checkbox, column, container, row, scrollable, text, Space};
|
||||
use iced::{Background, Border, Element, Length, Theme};
|
||||
|
||||
@@ -13,12 +14,6 @@ fn button_style(primary: bool) -> impl Fn(&Theme, button::Status) -> button::Sty
|
||||
}
|
||||
}
|
||||
|
||||
fn muted(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().background.base.text.scale_alpha(0.68)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view_window<'a>(
|
||||
layouts: &'a [(String, bool)],
|
||||
printer: Option<&'a str>,
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
use crate::app::Message;
|
||||
use crate::io::recovery::{RecoveryReport, RecoveryStatus};
|
||||
use crate::ui::style::common::muted_style;
|
||||
use iced::widget::{button, column, container, row, scrollable, text, Space};
|
||||
use iced::{Background, Border, Element, Fill, Length, Shrink, Theme};
|
||||
|
||||
fn muted_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().background.base.text.scale_alpha(0.68)),
|
||||
}
|
||||
}
|
||||
|
||||
fn status_style(
|
||||
status: RecoveryStatus,
|
||||
) -> impl Fn(&Theme) -> iced::widget::text::Style + Copy {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use crate::app::Message;
|
||||
use crate::t;
|
||||
use crate::ui::style::common::muted_style;
|
||||
use iced::widget::{button, column, container, row, scrollable, text, text_input, Space};
|
||||
use iced::{Background, Element, Length, Theme};
|
||||
|
||||
@@ -13,12 +14,6 @@ pub enum ShortcutField {
|
||||
|
||||
const GUTTER: f32 = 16.0;
|
||||
|
||||
fn muted_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().background.base.text.scale_alpha(0.68)),
|
||||
}
|
||||
}
|
||||
|
||||
fn danger_text_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().danger.base.color),
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
use crate::app::Message;
|
||||
use crate::ui::style::common::muted_style;
|
||||
use iced::widget::{button, column, container, row, scrollable, text, Space};
|
||||
use iced::{Background, Border, Element, Theme};
|
||||
use crate::t;
|
||||
use std::borrow::Cow;
|
||||
|
||||
fn muted_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().background.base.text.scale_alpha(0.68)),
|
||||
}
|
||||
}
|
||||
|
||||
fn primary_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().primary.base.color),
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
//! unreadable sliver.
|
||||
|
||||
use crate::app::Message;
|
||||
use crate::ui::style::common::muted_style;
|
||||
use iced::widget::{button, column, container, row, text, Space};
|
||||
use iced::{Background, Element, Fill, Length, Theme};
|
||||
|
||||
@@ -12,12 +13,6 @@ use iced::{Background, Element, Fill, Length, Theme};
|
||||
/// missing or broken behavior where it will be seen.
|
||||
pub const XREF_ISSUES_URL: &str = "https://github.com/HakanSeven12/OpenCADStudio/issues";
|
||||
|
||||
fn muted_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().background.base.text.scale_alpha(0.68)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view_window(sizing: crate::ui::modal::ModalSizing) -> Element<'static, Message> {
|
||||
// Fixed window width: paragraphs wrap against this instead of the
|
||||
// toolbar, which is what made the dropdown unreadable.
|
||||
|
||||
@@ -9,6 +9,7 @@ use crate::app::Message;
|
||||
use crate::io::xref::collect_entries_with_prev;
|
||||
use crate::io::xref_model::{normalize_lexical, Pathtype, RefKind, RefStatus, RefType, ReferenceEntry};
|
||||
use crate::ui::ROW_H;
|
||||
use crate::ui::style::common::muted_style;
|
||||
use acadrust::CadDocument;
|
||||
use iced::widget::{button, column, container, mouse_area, row, scrollable, text, tooltip};
|
||||
use iced::Padding;
|
||||
@@ -1286,12 +1287,6 @@ fn format_date(modified: Option<SystemTime>) -> String {
|
||||
|
||||
// ── Widget helpers (layers.rs conventions) ────────────────────────────────
|
||||
|
||||
fn muted_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.palette().background.base.text.scale_alpha(0.68)),
|
||||
}
|
||||
}
|
||||
|
||||
fn row_button_style(selected: bool, index: usize) -> impl Fn(&Theme, button::Status) -> button::Style {
|
||||
move |theme: &Theme, status: button::Status| {
|
||||
let palette = theme.palette();
|
||||
|
||||
Reference in new issue
Block a user