feat(field): Formula, Hyperlink and plot fields; local-time field dates, file times and display name; header dates on save

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
ramox81andClaude Opus 5.5 committed 2026-10-02 12:38:49 +03:00
1 parent f6f2b81441
commit a735b10b34
30 files changed
+475 -10

No files matched your search

Generated
+1 -1
View File
@@ -4206,7 +4206,7 @@ dependencies = [
[[package]]
name = "opencadcodec"
version = "0.5.5"
source = "git+https://github.com/ramox81/cadcodec.git?rev=595800e#595800ed4b778827c3c9e48245cade9cd8ccc05a"
source = "git+https://github.com/ramox81/cadcodec.git?rev=6d3713d#6d3713df1fe0a4aeeb9ef308a376e3db49c727c3"
dependencies = [
"ahash 0.8.12",
"anyhow",
+2 -2
View File
@@ -74,7 +74,7 @@ naga = { version = "27", features = ["wgsl-in"] }
[target.'cfg(target_os = "windows")'.dependencies]
libloading = "0.8"
windows-sys = { version = "0.61", features = ["Win32_UI_Shell", "Win32_UI_WindowsAndMessaging", "Win32_UI_Input", "Win32_System_LibraryLoader", "Win32_System_Threading", "Win32_Security", "Win32_System_Com", "Win32_System_Registry", "Win32_Storage_FileSystem", "Win32_Foundation", "Win32_Graphics_Printing", "Win32_Graphics_Gdi", "Win32_Storage_Xps", "Win32_Globalization"] }
windows-sys = { version = "0.61", features = ["Win32_UI_Shell", "Win32_UI_WindowsAndMessaging", "Win32_UI_Input", "Win32_System_LibraryLoader", "Win32_System_Threading", "Win32_Security", "Win32_System_Com", "Win32_System_Registry", "Win32_Storage_FileSystem", "Win32_Foundation", "Win32_Graphics_Printing", "Win32_Graphics_Gdi", "Win32_Storage_Xps", "Win32_Globalization", "Win32_Security_Authentication_Identity"] }
[target.'cfg(target_os = "linux")'.dependencies]
ashpd = { version = "0.13.13", default-features = false, features = ["async-io", "wayland"] }
@@ -92,7 +92,7 @@ objc2-foundation = { version = "0.2", features = ["NSArray", "NSURL", "NSString"
# Field authoring API and field format codes (opencadcodec PR pending).
[patch."https://github.com/HakanSeven12/opencadcodec.git"]
opencadcodec = { git = "https://github.com/ramox81/cadcodec.git", rev = "595800e" }
opencadcodec = { git = "https://github.com/ramox81/cadcodec.git", rev = "6d3713d" }
[patch.crates-io]
iced_core = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39" }
+8
View File
@@ -4105,6 +4105,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4092,6 +4092,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4090,6 +4090,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4091,6 +4091,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4093,6 +4093,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4094,6 +4094,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4093,6 +4093,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4092,6 +4092,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4093,6 +4093,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4081,6 +4081,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4092,6 +4092,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4092,6 +4092,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4081,6 +4081,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4092,6 +4092,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4091,6 +4091,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4092,6 +4092,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4093,6 +4093,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4094,6 +4094,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4053,6 +4053,14 @@ insert =
.field-select-object = Nesne seç
.field-expression = Alan ifadesi
.field-help = Bir alan ekler: çizimden, tarihten veya başka bir kaynaktan güncellenen metin.
.field-cat-linked = Bağlantılı
.field-current-precision = Geçerli hassasiyet
.field-evaluate = Hesapla
.field-text-to-display = Görüntülenecek metin
.field-address = Adres
.field-select-link-file = Bağlanacak dosyayı seçin
.field-current-units = Geçerli birimler
.field-use-scale-name = Ölçek adını kullan
.field-cat-date = Tarih ve Saat
.field-cat-document = Belge
.field-cat-other = Diğer
+8
View File
@@ -4076,6 +4076,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+8
View File
@@ -4088,6 +4088,14 @@ insert =
.field-select-object = Select object
.field-expression = Field expression
.field-help = Inserts a field: text that updates from the drawing, the date or another source.
.field-cat-linked = Linked
.field-current-precision = Current precision
.field-evaluate = Evaluate
.field-text-to-display = Text to display
.field-address = Address
.field-select-link-file = Select a file to link
.field-current-units = Current units
.field-use-scale-name = Use scale name
.field-cat-date = Date & Time
.field-cat-document = Document
.field-cat-other = Other
+22
View File
@@ -133,6 +133,28 @@ impl OpenCADStudio {
}
FieldDialogMsg::Named(k) => state.named = Some(k),
FieldDialogMsg::ObjectProp(p) => state.object_prop = Some(p),
FieldDialogMsg::Formula(v) => state.formula = v,
FieldDialogMsg::FormulaFormat(k) => state.formula_format = k,
FieldDialogMsg::FormulaPrecision(k) => state.formula_precision = k,
FieldDialogMsg::Evaluate => {}
FieldDialogMsg::HyperlinkText(v) => state.hyperlink_text = v,
FieldDialogMsg::HyperlinkUrl(v) => state.hyperlink_url = v,
FieldDialogMsg::BrowseHyperlink => {
return Task::perform(
async {
rfd::AsyncFileDialog::new()
.set_title(crate::t!("Select a file to link").as_ref())
.pick_file()
.await
.map(|h| crate::sys::handle_path(&h))
},
|path| match path {
Some(path) => Message::FieldDialog(FieldDialogMsg::HyperlinkUrl(path.to_string_lossy().into_owned())),
None => Message::Noop,
},
);
}
FieldDialogMsg::PlotScale(k) => state.plot_scale = k,
FieldDialogMsg::SelectObject => {
// The dialog waits while one object is picked.
self.active_modal = None;
+8 -1
View File
@@ -981,7 +981,8 @@ impl OpenCADStudio {
// One field of the open Field dialog: `category=<index>`, `name=Date`,
// `date=yyyy-MM-dd`, `case=0..4`, `file=1|2|3`, `ext=0|1`, `size=0..2`,
// `sysvar=dimscale`, `diesel=…`, `named_type=<index>`, `named=<index>`,
// `prop=Area`, `select_object`.
// `prop=Area`, `select_object`, `formula=(1+2)*3`, `formula_format=<index>`,
// `precision=<index>`, `link_text=…`, `link_url=…`, `plot_scale=<index>`.
"field_dialog" => {
use crate::ui::window::field_dialog::{self as fd, FieldDialogMsg as F};
let value = string(req, "value")?;
@@ -1004,6 +1005,12 @@ impl OpenCADStudio {
"named" => F::Named(index()?),
"prop" => F::ObjectProp(known(&["Area", "Center", "Circumference", "Diameter", "EndPoint", "Length", "Radius", "StartPoint"])?),
"select_object" => F::SelectObject,
"formula" => F::Formula(v.into()),
"formula_format" => F::FormulaFormat(index()?),
"precision" => F::FormulaPrecision(index()?),
"link_text" => F::HyperlinkText(v.into()),
"link_url" => F::HyperlinkUrl(v.into()),
"plot_scale" => F::PlotScale(index()?),
_ => return Err(failure("invalid_value", "Unknown field dialog key")),
})
}
+87 -2
View File
@@ -17,11 +17,29 @@ struct OcsFieldContext<'a>(Option<&'a CadDocument>);
impl FieldContext for OcsFieldContext<'_> {
fn now_julian(&self) -> f64 {
// Unix epoch is Julian Day 2440587.5.
epoch_secs() as f64 / 86_400.0 + 2_440_587.5
// Fields show local time. Unix epoch is Julian Day 2440587.5.
now_utc_julian() + utc_offset_days()
}
fn file_times(&self) -> Option<(f64, f64)> {
#[cfg(not(target_arch = "wasm32"))]
{
let meta = std::fs::metadata(self.0?.source_path.as_deref()?).ok()?;
let julian = |t: std::time::SystemTime| -> Option<f64> {
let secs = t.duration_since(std::time::UNIX_EPOCH).ok()?.as_secs_f64();
Some(secs / 86_400.0 + 2_440_587.5 + utc_offset_days())
};
return Some((julian(meta.created().ok()?)?, julian(meta.modified().ok()?)?));
}
#[cfg(target_arch = "wasm32")]
None
}
fn login(&self) -> Option<String> {
// The account's display name, as the reference shows it.
if let Some(name) = display_name() {
return Some(name);
}
#[cfg(not(target_arch = "wasm32"))]
{
for var in ["USER", "LOGNAME", "USERNAME"] {
@@ -275,3 +293,70 @@ pub fn hosts_field(document: &CadDocument, entity: &codec::entities::EntityType)
Some(codec::objects::ObjectType::Dictionary(d)) if d.get("ACAD_FIELD").is_some()
)
}
fn now_utc_julian() -> f64 {
epoch_secs() as f64 / 86_400.0 + 2_440_587.5
}
/// Local time minus UTC, in days (the zone's current offset).
pub fn utc_offset_days() -> f64 {
#[cfg(target_os = "windows")]
{
use windows_sys::Win32::Foundation::FILETIME;
use windows_sys::Win32::Storage::FileSystem::FileTimeToLocalFileTime;
// 100 ns ticks since 1601-01-01.
let ticks = (epoch_secs() as u64 + 11_644_473_600) * 10_000_000;
let utc = FILETIME { dwLowDateTime: ticks as u32, dwHighDateTime: (ticks >> 32) as u32 };
let mut local = FILETIME { dwLowDateTime: 0, dwHighDateTime: 0 };
if unsafe { FileTimeToLocalFileTime(&utc, &mut local) } != 0 {
let local = ((local.dwHighDateTime as u64) << 32) | local.dwLowDateTime as u64;
return (local as i64 - ticks as i64) as f64 / 864_000_000_000.0;
}
0.0
}
#[cfg(not(target_os = "windows"))]
0.0
}
/// A DWG stores its header dates in universal time only; the local TDCREATE
/// and TDUPDATE come from the zone, as the reference derives them on load.
pub fn local_header_dates(document: &mut CadDocument) {
let h = &mut document.header;
let offset = utc_offset_days();
if h.universal_create_date_julian != 0.0 && h.create_date_julian == h.universal_create_date_julian {
h.create_date_julian = h.universal_create_date_julian + offset;
}
if h.universal_update_date_julian != 0.0 && h.update_date_julian == h.universal_update_date_julian {
h.update_date_julian = h.universal_update_date_julian + offset;
}
}
/// Stamp the header's update date (and the creation date of a new drawing)
/// in local and universal time before a save.
pub fn stamp_save_dates(document: &mut CadDocument) {
let utc = now_utc_julian();
let local = utc + utc_offset_days();
let h = &mut document.header;
if h.create_date_julian == 0.0 && h.universal_create_date_julian == 0.0 {
h.create_date_julian = local;
h.universal_create_date_julian = utc;
}
h.update_date_julian = local;
h.universal_update_date_julian = utc;
}
/// The signed-in account's display name, when it has one.
fn display_name() -> Option<String> {
#[cfg(target_os = "windows")]
{
use windows_sys::Win32::Security::Authentication::Identity::{GetUserNameExW, NameDisplay};
let mut buffer = [0u16; 256];
let mut len = buffer.len() as u32;
if unsafe { GetUserNameExW(NameDisplay, buffer.as_mut_ptr(), &mut len) } && len > 0 {
return Some(String::from_utf16_lossy(&buffer[..len as usize])).filter(|n| !n.trim().is_empty());
}
None
}
#[cfg(not(target_os = "windows"))]
None
}
+4
View File
@@ -723,6 +723,7 @@ async fn load_web_bytes(
}
fix_viewport_status_flags(&mut doc);
fix_current_style_names(&mut doc);
crate::entities::field::local_header_dates(&mut doc);
progress.set(crate::app::OPEN_PHASE_CACHING, 7000, 0, 1);
let dropped = purge_corrupt_entities(&mut doc);
if !recovery_mode && dropped > 0 {
@@ -764,6 +765,7 @@ pub fn load_bytes(name: &str, bytes: Vec<u8>) -> Result<CadDocument, String> {
.map_err(|e| e.to_string())?;
fix_viewport_status_flags(&mut doc);
fix_current_style_names(&mut doc);
crate::entities::field::local_header_dates(&mut doc);
Ok(doc)
}
"dxf" => {
@@ -775,6 +777,7 @@ pub fn load_bytes(name: &str, bytes: Vec<u8>) -> Result<CadDocument, String> {
fix_dxf_layout_plot_settings(&mut doc);
fix_viewport_status_flags(&mut doc);
fix_current_style_names(&mut doc);
crate::entities::field::local_header_dates(&mut doc);
Ok(doc)
}
_ => Err(format!("Unsupported file format: .{ext}")),
@@ -1040,6 +1043,7 @@ fn finalize_loaded_outcome(
}
fix_viewport_status_flags(doc);
fix_current_style_names(doc);
crate::entities::field::local_header_dates(doc);
resolve_raster_image_paths(doc, path.parent());
doc.source_path = Some(path.to_string_lossy().into_owned());
Ok(outcome)
+8
View File
@@ -235,6 +235,14 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
"Select object" => Some(("insert", "field-select-object")),
"Field expression" => Some(("insert", "field-expression")),
"Inserts a field: text that updates from the drawing, the date or another source." => Some(("insert", "field-help")),
"Linked" => Some(("insert", "field-cat-linked")),
"Current precision" => Some(("insert", "field-current-precision")),
"Evaluate" => Some(("insert", "field-evaluate")),
"Text to display" => Some(("insert", "field-text-to-display")),
"Address" => Some(("insert", "field-address")),
"Select a file to link" => Some(("insert", "field-select-link-file")),
"Current units" => Some(("insert", "field-current-units")),
"Use scale name" => Some(("insert", "field-use-scale-name")),
"Date & Time" => Some(("insert", "field-cat-date")),
"Document" => Some(("insert", "field-cat-document")),
"Other" => Some(("insert", "field-cat-other")),
+1
View File
@@ -2533,6 +2533,7 @@ impl super::Scene {
}
}
crate::io::xref::strip_resolved_xref_content(&mut document);
crate::entities::field::stamp_save_dates(&mut document);
document
}
+174 -4
View File
@@ -31,9 +31,13 @@ pub const CATEGORIES: &[(&str, &[&str])] = &[
"Document",
&["Author", "Comments", "Filename", "Filesize", "HyperlinkBase", "Keywords", "LastSavedBy", "Subject", "Title"],
),
("Objects", &["NamedObject", "Object"]),
("Linked", &["Hyperlink"]),
("Objects", &["Formula", "NamedObject", "Object"]),
("Other", &["DieselExpression", "SystemVariable"]),
("Plot", &["Login", "PlotDate"]),
(
"Plot",
&["DeviceName", "Login", "PageSetupName", "PaperSize", "PlotDate", "PlotOrientation", "PlotScale", "PlotStyleTable"],
),
];
/// The fields of a category; "All" lists every field once, sorted.
@@ -70,8 +74,15 @@ pub enum FieldKind {
Diesel,
NamedObject,
Object,
Formula,
Hyperlink,
PlotScale,
}
/// Formula precisions: the current one, then 0 to 8 decimals.
pub const FORMULA_PRECISIONS: &[&str] =
&["Current precision", "0", "0.0", "0.00", "0.000", "0.0000", "0.00000", "0.000000", "0.0000000", "0.00000000"];
pub fn kind_of(name: &str) -> FieldKind {
match name {
"CreateDate" | "Date" | "PlotDate" | "SaveDate" => FieldKind::Date,
@@ -81,6 +92,9 @@ pub fn kind_of(name: &str) -> FieldKind {
"DieselExpression" => FieldKind::Diesel,
"NamedObject" => FieldKind::NamedObject,
"Object" => FieldKind::Object,
"Formula" => FieldKind::Formula,
"Hyperlink" => FieldKind::Hyperlink,
"PlotScale" => FieldKind::PlotScale,
_ => FieldKind::Text,
}
}
@@ -106,6 +120,14 @@ pub struct FieldDialogState {
pub object: Option<(codec::Handle, String)>,
pub object_props: Vec<&'static str>,
pub object_prop: Option<&'static str>,
pub formula: String,
/// Indexes into codec FORMULA_FORMATS and FORMULA_PRECISIONS.
pub formula_format: usize,
pub formula_precision: usize,
pub hyperlink_text: String,
pub hyperlink_url: String,
/// Index into codec PLOT_SCALE_FORMATS.
pub plot_scale: usize,
pub preview: String,
/// Today in each of DATE_FORMATS, for the Examples list.
pub examples: Vec<String>,
@@ -130,6 +152,12 @@ impl FieldDialogState {
object: None,
object_props: Vec::new(),
object_prop: None,
formula: String::new(),
formula_format: 0,
formula_precision: 0,
hyperlink_text: String::new(),
hyperlink_url: String::new(),
plot_scale: 0,
preview: String::new(),
examples: Vec::new(),
}
@@ -153,7 +181,36 @@ impl FieldDialogState {
};
(format!("\\AcVar Filename \\f \"{case}%fn{bits}\""), vec![])
}
FieldKind::Filesize => (format!("\\AcVar Filesize \\f \"%ld%by{}\"", self.size_unit + 1), vec![]),
// Bytes are whole; kilo- and megabytes keep two decimals.
FieldKind::Filesize => (
match self.size_unit {
0 => "\\AcVar Filesize \\f \"%ld%by1\"".to_string(),
n => format!("\\AcVar Filesize \\f \"%.2f%by{}\"", n + 1),
},
vec![],
),
FieldKind::Formula => {
let format = codec::fields::FORMULA_FORMATS.get(self.formula_format).map_or("", |f| f.1);
let precision = match self.formula_precision {
0 => String::new(),
n => format!("%pr{}", n - 1),
};
let body = format!("\\AcExpr ({})", self.formula.trim());
match format!("{format}{precision}") {
f if f.is_empty() => (body, vec![]),
f => (format!("{body} \\f \"{f}\""), vec![]),
}
}
FieldKind::Hyperlink => (
format!("\\AcVar \\href \"{}##{}#0\"", self.hyperlink_url.trim(), self.hyperlink_text),
vec![],
),
FieldKind::PlotScale => (
codec::fields::PLOT_SCALE_FORMATS
.get(self.plot_scale)
.map_or_else(|| "\\AcVar PlotScale".to_string(), |f| f.1.to_string()),
vec![],
),
FieldKind::SystemVariable => (format!("\\AcVar {}", self.sysvar), vec![]),
FieldKind::Diesel => (format!("\\AcDiesel {}", self.diesel), vec![]),
FieldKind::NamedObject => match self.named.and_then(|i| self.named_names.get(i)) {
@@ -176,6 +233,8 @@ impl FieldDialogState {
FieldKind::NamedObject => self.named.is_some(),
FieldKind::Object => self.object.is_some() && self.object_prop.is_some(),
FieldKind::Diesel => !self.diesel.trim().is_empty(),
FieldKind::Formula => !self.formula.trim().is_empty(),
FieldKind::Hyperlink => !self.hyperlink_url.trim().is_empty(),
_ => true,
}
}
@@ -211,6 +270,14 @@ pub enum FieldDialogMsg {
Named(usize),
SelectObject,
ObjectProp(&'static str),
Formula(String),
FormulaFormat(usize),
FormulaPrecision(usize),
Evaluate,
HyperlinkText(String),
HyperlinkUrl(String),
BrowseHyperlink,
PlotScale(usize),
Help,
Ok,
}
@@ -396,6 +463,85 @@ fn format_panel<'a>(state: &'a FieldDialogState) -> Element<'a, Message> {
]
.spacing(8)
.into(),
FieldKind::Formula => {
let formats: Vec<Pick> = codec::fields::FORMULA_FORMATS
.iter()
.enumerate()
.map(|(i, (n, _))| Pick(i, t!(*n).into_owned()))
.collect();
let precisions: Vec<Pick> =
FORMULA_PRECISIONS.iter().enumerate().map(|(i, n)| Pick(i, t!(*n).into_owned())).collect();
column![
row![
text(t!("Format")).size(12).width(Length::Fixed(80.0)),
pick_list(Some(formats[state.formula_format].clone()), formats.clone(), |p: &Pick| p.1.clone())
.on_select(|p| msg(FieldDialogMsg::FormulaFormat(p.0)))
.text_size(12)
.padding([5, 8])
.width(Fill),
]
.spacing(8)
.align_y(iced::Center),
row![
text(t!("Precision")).size(12).width(Length::Fixed(80.0)),
pick_list(
Some(precisions[state.formula_precision].clone()),
precisions.clone(),
|p: &Pick| p.1.clone(),
)
.on_select(|p| msg(FieldDialogMsg::FormulaPrecision(p.0)))
.text_size(12)
.padding([5, 8])
.width(Fill),
]
.spacing(8)
.align_y(iced::Center),
]
.spacing(8)
.into()
}
FieldKind::Hyperlink => column![
row![
text(t!("Text to display")).size(12).width(Length::Fixed(120.0)),
text_input("", &state.hyperlink_text)
.size(12)
.padding([5, 8])
.style(field_style)
.on_input(|v| msg(FieldDialogMsg::HyperlinkText(v))),
]
.spacing(8)
.align_y(iced::Center),
row![
text(t!("Address")).size(12).width(Length::Fixed(120.0)),
text_input("https://", &state.hyperlink_url)
.size(12)
.padding([5, 8])
.font(iced::Font::MONOSPACE)
.style(field_style)
.on_input(|v| msg(FieldDialogMsg::HyperlinkUrl(v))),
button(text("…").size(12))
.on_press(msg(FieldDialogMsg::BrowseHyperlink))
.style(button_style(false))
.padding([5, 10]),
]
.spacing(8)
.align_y(iced::Center),
]
.spacing(8)
.into(),
FieldKind::PlotScale => column![
text(t!("Format")).size(12),
list(
codec::fields::PLOT_SCALE_FORMATS
.iter()
.enumerate()
.map(|(i, (n, _))| (t!(*n).into_owned(), state.plot_scale == i, FieldDialogMsg::PlotScale(i)))
.collect(),
170.0,
),
]
.spacing(8)
.into(),
FieldKind::Object => column![
row![
text(t!("Object type")).size(12).width(Length::Fixed(96.0)),
@@ -460,7 +606,31 @@ pub fn view<'a>(
.padding([6, 8])
.width(Fill),
);
let right = column![card(t!("Format").into_owned(), format_panel(state)), preview].spacing(10);
let right = match kind_of(state.name) {
FieldKind::Formula => column![
card(
t!("Formula").into_owned(),
column![
text_input("(12+3)*2", &state.formula)
.size(12)
.padding([8, 8])
.font(iced::Font::MONOSPACE)
.style(field_style)
.on_input(|v| msg(FieldDialogMsg::Formula(v))),
button(text(t!("Evaluate")).size(12))
.on_press(msg(FieldDialogMsg::Evaluate))
.style(button_style(false))
.padding([5, 14]),
]
.spacing(8),
),
card(t!("Format").into_owned(), format_panel(state)),
preview,
]
.spacing(10),
FieldKind::Hyperlink => column![card(t!("Hyperlink").into_owned(), format_panel(state)), preview].spacing(10),
_ => column![card(t!("Format").into_owned(), format_panel(state)), preview].spacing(10),
};
let (code, _) = state.code();
let expression = column![
text(t!("Field expression")).size(12),