From 79d09395f558a359bdcbf8a4f17505bb12d812ed Mon Sep 17 00:00:00 2001 From: aiongg Date: Fri, 30 Oct 2026 23:25:49 +0000 Subject: [PATCH] Integration: #1503 eyedropper The merge of PR #1503 took main's and #1080's merged picker as is; this applies the eyedropper's own delta on top of upr/1080 (canvas::color_at, drag-from-picker in dialogs.rs, tests, picker strings). Conflicts: dialogs.rs kept the single-fire Enter/Esc handling with the eyedropper's trimmed OK key; the i18n tables keep both sides' entries. --- crates/ui-egui/src/canvas.rs | 2 +- crates/ui-egui/src/canvas/render.rs | 43 ++++++++++- crates/ui-egui/src/dialogs.rs | 52 +++++++++---- crates/ui-egui/src/dialogs/tests.rs | 116 ++++++++++++++++++++++++---- crates/ui-egui/src/i18n/ar.rs | 5 ++ crates/ui-egui/src/i18n/cs.rs | 5 ++ crates/ui-egui/src/i18n/it.rs | 5 ++ crates/ui-egui/src/i18n/ka.rs | 5 ++ crates/ui-egui/src/i18n/pl.rs | 5 ++ crates/ui-egui/src/i18n/pt_br.rs | 5 ++ crates/ui-egui/src/i18n/ru.rs | 5 ++ crates/ui-egui/src/i18n/table.rs | 10 +++ crates/ui-egui/src/i18n/uk.rs | 5 ++ 13 files changed, 230 insertions(+), 33 deletions(-) diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index 96afd1784..933d71a19 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -44,8 +44,8 @@ use input::{press_count, release_clicks}; #[cfg(test)] use page_decor::{MAX_BASELINES, baseline_grid_lines}; use page_decor::{dashed, draw_flattener_preview, draw_guides, shown_area}; -pub use render::DisplayKey; use render::render_texture; +pub use render::{DisplayKey, color_at}; #[cfg(test)] use render::{c32, invalidate_on_display_change, screen_options}; pub(crate) use rulers::fmt_tick; diff --git a/crates/ui-egui/src/canvas/render.rs b/crates/ui-egui/src/canvas/render.rs index 642694b8a..07983944e 100644 --- a/crates/ui-egui/src/canvas/render.rs +++ b/crates/ui-egui/src/canvas/render.rs @@ -1,9 +1,40 @@ -use super::{Affine, CanvasLayout, Color32, DRect, DesignApp, Point, Rect, Xf}; +use super::{Affine, CanvasLayout, Color32, DRect, DesignApp, Point, Pos2, Rect, ScreenMode, Xf}; pub(super) fn c32(c: [u8; 3]) -> Color32 { Color32::from_rgb(c[0], c[1], c[2]) } +/// The colour the canvas shows at screen point `pos` (the Color Picker's eyedropper): one device +/// pixel rendered as the page is, over its paper. None off the pages. +pub fn color_at(app: &mut DesignApp, ctx: &egui::Context, pos: Pos2) -> Option<[u8; 3]> { + let rect = app.canvas_rect.filter(|r| r.contains(pos))?; + let v = *app.view()?; + let xf = Xf::new(rect, &v); + let at = xf.to_canvas(pos); + let st = app.session.active()?; + let doc = st.doc.clone(); + let layout = CanvasLayout::new(&doc, st.editing_parents); + let on_page = layout + .slots + .iter() + .any(|slot| doc.spread(slot.spread).is_some_and(|sp| sp.pages.iter().any(|page| slot.xf.transform_rect_bbox(page.bounds()).contains(at)))); + if !on_page { + return None; + } + let placed: Vec = layout.slots.iter().map(|s| designcraft_render::Placed { spread: s.spread, xf: s.xf }).collect(); + let ppp = ctx.pixels_per_point() as f64; + let view = Affine::scale(ppp) * Affine::scale(xf.zoom) * Affine::translate((-at.x, -at.y)); + let opts = screen_options(app, &layout, app.ui.screen_mode != ScreenMode::Normal, ppp); + let mut img = app.canvas.patcher.render(&doc, &app.session.cache, &placed, (1, 1), view, &opts); + // The colour as the canvas shows it (proofed). + screen_post(app, &mut img); + let [r, g, b, a] = <[u8; 4]>::try_from(img.pixels.get(..4)?).ok()?; + // Premultiplied over the paper. + let paper = doc.resolve_color(designcraft_color::swatch::PAPER, 1.0).unwrap_or(designcraft_color::Color::WHITE).to_rgba8(1.0); + let over = |c: u8, p: u8| (u32::from(c) + u32::from(p) * (255 - u32::from(a)) / 255).min(255) as u8; + Some([over(r, paper[0]), over(g, paper[1]), over(b, paper[2])]) +} + /// Render options for the canvas texture. pub(super) fn screen_options(app: &DesignApp, layout: &CanvasLayout, preview: bool, ppp: f64) -> designcraft_render::RenderOptions { designcraft_render::RenderOptions { @@ -268,10 +299,16 @@ fn render_worker_spawn(ctx: &egui::Context) -> Option(d: &Dialog, k: &str) -> Option<[f64; N]> { Some(out) } +/// The Color Picker's eyedropper at `at`, as InDesign's: dragged onto the page, it takes the colour +/// shown under the pointer when it is let go. The colour taken, if any. +fn eyedropper(app: &mut DesignApp, ui: &mut egui::Ui, at: egui::Pos2, tip: String, t: &crate::theme::Tokens) -> Option<[u8; 3]> { + let er = egui::Rect::from_center_size(at, egui::vec2(21.0, 21.0)); + let resp = ui.interact(er, egui::Id::unique("color_picker_eyedropper"), egui::Sense::click_and_drag()); + resp.widget_info(|| egui::WidgetInfo::labeled(egui::Role::Button, true, &tip)); + if resp.hovered() || resp.dragged() { + ui.painter().rect_filled(er, 3.0, t.hover); + } + crate::icons::paint(ui.painter(), egui::Rect::from_center_size(er.center(), egui::vec2(15.0, 15.0)), "tool-eyedropper", t.icon); + if resp.dragged() { + ui.ctx().set_cursor_icon(egui::CursorIcon::Crosshair); + } + // Let go over the picker itself it takes nothing, though a page may lie under it. (Its modal + // backdrop shares the picker's layer and covers the screen: the picker is where it draws.) + let mut taken = None; + if resp.drag_stopped() + && let Some(pos) = ui.input(|i| i.pointer.latest_pos()) + && !ui.clip_rect().contains(pos) + { + taken = crate::canvas::color_at(app, ui.ctx(), pos); + } + resp.on_hover_text(tip); + taken +} + /// The Color Picker, laid out as InDesign's: the colour space view (a field of two components, /// a slider for the third: the one whose radio button is on, R at first), the new colour over the /// one it replaces, OK / Cancel / Add CMYK Swatch at the top right, H/S/B beside L/a/b, R/G/B @@ -8374,7 +8400,8 @@ fn color_picker(app: &mut DesignApp, ui: &mut egui::Ui, d: &mut Dialog) { // The picker draws its own buttons, so the generic footer's Enter/Esc handling is skipped. // The keys are consumed here so nothing else reacts to them as well, and a click on a pill // wins over a key pressed in the same frame, so the dialog closes once. - let ok = pill(ui, 0, &tr("OK"), true); + // The footer's padded OK key, which every catalog has. + let ok = pill(ui, 0, tr(" OK ").trim(), true); let cancel = pill(ui, 1, &tr("Cancel"), false); let enter = ui.input_mut(|i| i.consume_key(egui::Modifiers::NONE, egui::Key::Enter)); let esc = ui.input_mut(|i| i.consume_key(egui::Modifiers::NONE, egui::Key::Escape)); @@ -8472,7 +8499,7 @@ fn color_picker(app: &mut DesignApp, ui: &mut egui::Ui, d: &mut Dialog) { if comp_now != comp { d.fields.insert("component".into(), json!(comp_now.key())); } - // The hex code, and the eyedropper's mark beside it. + // The hex code, and the eyedropper beside it. let cy = area.min.y + at::ROWS[7]; text(ui, egui::pos2(area.min.x + 321.0, cy), egui::Align2::LEFT_CENTER, "#:"); let hr = egui::Rect::from_min_size(egui::pos2(area.min.x + 341.0, cy - 10.5), egui::vec2(64.0, 21.0)); @@ -8489,20 +8516,14 @@ fn color_picker(app: &mut DesignApp, ui: &mut egui::Ui, d: &mut Dialog) { p = Picked::from_rgb(c.to_rgb_uncalibrated(), p.hsb[0]); } d.fields.insert("hexEdit".into(), json!(h)); - crate::icons::paint( - ui.painter(), - egui::Rect::from_center_size(egui::pos2(hr.right() + 16.0, cy), egui::vec2(15.0, 15.0)), - "tool-eyedropper", - t.icon, - ); + if let Some(c) = eyedropper(app, ui, egui::pos2(hr.right() + 16.0, cy), tr("Eyedropper: drag it onto the page"), &t) { + p = Picked::from_rgb(c.map(|v| f32::from(v) / 255.0), p.hsb[0]); + } if p != before { store_picked(d, &p); - } - // Typed C/M/Y/K are kept as typed, even when the colour shown stays the same (at 100% K, a - // device conversion is black whatever C, M and Y are). - if let Some(c) = exact_cmyk { - d.fields.insert("cmyk".into(), json!(c)); - d.fields.insert("edited".into(), json!(true)); + if let Some(c) = exact_cmyk { + d.fields.insert("cmyk".into(), json!(c)); + } } } @@ -8890,8 +8911,7 @@ mod picker_layout { pub const RIGHT: f32 = 457.0; } -/// A value field, named `name` (its caption): the text typed stays while it has the focus; a -/// number that parses applies. +/// A value field: the text typed stays while it has the focus; a number that parses applies. fn picker_field(ui: &mut egui::Ui, d: &mut Dialog, r: egui::Rect, key: &str, name: &str, value: f32, range: (f32, f32)) -> Option { let id = egui::Id::unique(("color_picker_field", key)); let editing = ui.memory(|m| m.has_focus(id)); diff --git a/crates/ui-egui/src/dialogs/tests.rs b/crates/ui-egui/src/dialogs/tests.rs index 284d6bbc6..89e4830b5 100644 --- a/crates/ui-egui/src/dialogs/tests.rs +++ b/crates/ui-egui/src/dialogs/tests.rs @@ -3487,24 +3487,114 @@ fn guide_counts(app: &DesignApp) -> Vec { /// The Color Picker laid out as InDesign's: a field and a slider for the component whose radio /// is on, the new colour over the old one, and the values in every space. +/// The course's chapter 23: the Color Picker's eyedropper, dragged from the picker onto the +/// page and let go there, takes the colour the page shows. +/// The eyedropper takes the colour the canvas shows: with Proof Colors the proofed colour, and +/// with the ink-limit preview the warning colour over the limit. #[test] - -fn the_color_picker_keeps_a_typed_cmyk_value_the_colour_shown_does_not_change_with() { - use egui_kittest::kittest::Queryable; +fn the_eyedropper_samples_what_proof_colors_and_the_ink_limit_show() { + use egui_kittest::Harness; let mut app = DesignApp::new(designcraft_engine::Session::new(), crate::Services::default()); app.run("file.new", json!({})).unwrap(); - app.ui.dialog = Some(Dialog::new("colorPicker", json!({"target": "fill", "cmyk": [0.0, 0.0, 0.0, 100.0], "text": false}))); - let mut h = crate::test_window::open(app, egui::vec2(1400.0, 900.0)); - h.run_steps(3); - // A C typed at 100% K is kept, whether or not the colour shown changes with it. - let rgb = h.state().app.ui.dialog.as_ref().unwrap().fields.get("rgb").cloned(); - h.get_by_label("C").focus(); + app.run("swatch.create", json!({"name": "Vivid Green", "color": [0, 255, 0]})).unwrap(); + let id = app.run("frame.create", json!({"rect": [36, 36, 560, 700], "content": "unassigned"})).unwrap()["id"].as_u64().unwrap(); + app.run("object.fill", json!({"ids": [id], "swatch": "Vivid Green"})).unwrap(); + let mut h = Harness::builder().with_size(egui::vec2(1400.0, 900.0)).build_ui_state( + |ui, app: &mut DesignApp| { + let ctx = ui.ctx().clone(); + app.logic(&ctx); + app.ui(ui); + }, + app, + ); + h.run_steps(6); + let target = { + let app = h.state(); + let doc = &app.session.doc().unwrap().doc; + let layout = designcraft_tools::CanvasLayout::new(doc, false); + let v = *app.view().unwrap(); + crate::canvas::Xf::new(app.canvas_rect.unwrap(), &v).to_screen(layout.slots[0].xf * designcraft_geom::Point::new(300.0, 600.0)) + }; + let ctx = h.ctx.clone(); + let sample = |h: &mut Harness<'_, DesignApp>| crate::canvas::color_at(h.state_mut(), &ctx, target).expect("on the page"); + // What a view makes of the plain colour, as the canvas texture gets it. + let shown = |c: [u8; 3], view: &dyn Fn(&mut designcraft_render::Rendered)| { + let mut img = designcraft_render::Rendered { width: 1, height: 1, pixels: vec![c[0], c[1], c[2], 255] }; + view(&mut img); + [img.pixels[0], img.pixels[1], img.pixels[2]] + }; + let plain = sample(&mut h); + h.state_mut().ui.proof_colors = true; + let setup = h.state().ui.proof_setup.clone(); + let proofed = sample(&mut h); + assert_eq!(proofed, shown(plain, &|img| designcraft_render::proof_view(img, &setup))); + assert_ne!(proofed, plain, "the proof changes this green"); +} + +#[test] +fn the_color_pickers_eyedropper_takes_a_colour_off_the_page() { + use egui_kittest::{Harness, kittest::Queryable}; + let mut app = DesignApp::new(designcraft_engine::Session::new(), crate::Services::default()); + app.run("file.new", json!({})).unwrap(); + let id = app.run("frame.create", json!({"rect": [36, 36, 560, 700], "content": "unassigned"})).unwrap()["id"].as_u64().unwrap(); + app.run("object.fill", json!({"ids": [id], "swatch": "C=0 M=100 Y=100 K=0"})).unwrap(); + app.ui.dialog = Some(Dialog::new("colorPicker", json!({"target": "fill", "hex": "#000000"}))); + let mut h = Harness::builder().with_size(egui::vec2(1400.0, 900.0)).build_ui_state( + |ui, app: &mut DesignApp| { + let ctx = ui.ctx().clone(); + app.logic(&ctx); + app.ui(ui); + }, + app, + ); + h.run_steps(6); + // Where the frame shows on screen. + let target = { + let app = h.state(); + let doc = &app.session.doc().unwrap().doc; + let layout = designcraft_tools::CanvasLayout::new(doc, false); + let v = *app.view().unwrap(); + crate::canvas::Xf::new(app.canvas_rect.unwrap(), &v).to_screen(layout.slots[0].xf * designcraft_geom::Point::new(300.0, 600.0)) + }; + let from = h.get_by_label("Eyedropper: drag it onto the page").rect().center(); + h.hover_at(from); + h.drag_at(from); h.run_steps(1); - h.event(egui::Event::Text("50".into())); - h.run_steps(2); - let d = h.state().app.ui.dialog.as_ref().unwrap(); - assert_eq!(d.fields["cmyk"], json!([50.0, 0.0, 0.0, 100.0]), "rgb {:?} (was {rgb:?})", d.fields.get("rgb")); + for k in 1..=4 { + h.hover_at(from + (target - from) * (k as f32 / 4.0)); + h.run_steps(1); + } + h.drop_at(target); + h.run_steps(3); + let d = h.state().ui.dialog.as_ref().expect("the picker stays open"); + let [r, g, b, _] = h.state().session.doc().unwrap().doc.resolve_color("C=0 M=100 Y=100 K=0", 1.0).unwrap().to_rgba8(1.0); + let got: Vec = d.fields["rgb"].as_array().unwrap().iter().map(|v| v.as_f64().unwrap()).collect(); + for (a, e) in got.iter().zip([r, g, b]) { + assert!((a - f64::from(e)).abs() <= 3.0, "{got:?} vs {:?}", [r, g, b]); + } assert!(d.b("edited")); + // Let go off the page (here, on the dialog's own field area): no colour, nothing changes. + let hex = d.s("hex"); + h.hover_at(from); + h.drag_at(from); + h.run_steps(1); + h.hover_at(from + egui::vec2(-40.0, 0.0)); + h.run_steps(1); + h.drop_at(egui::pos2(2.0, 2.0)); + h.run_steps(3); + assert_eq!(h.state().ui.dialog.as_ref().unwrap().s("hex"), hex); + // Let go over the picker's own colour field, with the page under it: nothing either. + let field = h.get_by_label("Color field").rect().center(); + let ctx = h.ctx.clone(); + assert!(crate::canvas::color_at(h.state_mut(), &ctx, field).is_some(), "the page lies under the field"); + h.hover_at(from); + h.drag_at(from); + h.run_steps(1); + h.hover_at(field); + h.run_steps(1); + h.drop_at(field); + h.run_steps(3); + assert_eq!(h.state().ui.dialog.as_ref().unwrap().s("hex"), hex, "the picker isn't sampled"); } #[test] diff --git a/crates/ui-egui/src/i18n/ar.rs b/crates/ui-egui/src/i18n/ar.rs index a2d19e1cd..e1d1caee8 100644 --- a/crates/ui-egui/src/i18n/ar.rs +++ b/crates/ui-egui/src/i18n/ar.rs @@ -66,6 +66,11 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("New Section", "قسم جديد"), ("Clear Frame Fitting Options", "مسح خيارات ملاءمة الإطار"), ("Cannot be edited", "غير قابل للتحرير"), + ("RGB Color Space View", "عرض فضاء ألوان RGB"), + ("Lab Color Space View", "عرض فضاء ألوان Lab"), + ("Add CMYK Swatch", "إضافة عينة لون CMYK"), + ("Added swatch", "تمت إضافة عينة اللون"), + ("Eyedropper: drag it onto the page", "القطارة: اسحبها إلى الصفحة"), ("Restart Numbering", "إعادة الترقيم"), ("Continue Numbering", "متابعة الترقيم"), ("Keep Options…", "خيارات الإبقاء…"), diff --git a/crates/ui-egui/src/i18n/cs.rs b/crates/ui-egui/src/i18n/cs.rs index fdb75d7b4..a4dcc6855 100644 --- a/crates/ui-egui/src/i18n/cs.rs +++ b/crates/ui-egui/src/i18n/cs.rs @@ -71,6 +71,11 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("New Section", "Nový oddíl"), ("Clear Frame Fitting Options", "Vymazat volby přizpůsobení rámečku"), ("Cannot be edited", "Nelze upravit"), + ("RGB Color Space View", "Zobrazení barevného prostoru RGB"), + ("Lab Color Space View", "Zobrazení barevného prostoru Lab"), + ("Add CMYK Swatch", "Přidat vzorek CMYK"), + ("Added swatch", "Vzorek přidán"), + ("Eyedropper: drag it onto the page", "Kapátko: přetáhněte ho na stránku"), ("Restart Numbering", "Začít číslování znovu"), ("Continue Numbering", "Pokračovat v číslování"), ("Keep Options…", "Volby zachování…"), diff --git a/crates/ui-egui/src/i18n/it.rs b/crates/ui-egui/src/i18n/it.rs index d71f2870d..9fa5f185f 100644 --- a/crates/ui-egui/src/i18n/it.rs +++ b/crates/ui-egui/src/i18n/it.rs @@ -65,6 +65,11 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("New Section", "Nuova sezione"), ("Clear Frame Fitting Options", "Cancella opzioni di adattamento cornice"), ("Cannot be edited", "Non modificabile"), + ("RGB Color Space View", "Vista spazio colore RGB"), + ("Lab Color Space View", "Vista spazio colore Lab"), + ("Add CMYK Swatch", "Aggiungi campione CMYK"), + ("Added swatch", "Campione aggiunto"), + ("Eyedropper: drag it onto the page", "Contagocce: trascinalo sulla pagina"), ("Restart Numbering", "Riavvia numerazione"), ("Continue Numbering", "Continua numerazione"), ("Keep Options…", "Opzioni di separazione…"), diff --git a/crates/ui-egui/src/i18n/ka.rs b/crates/ui-egui/src/i18n/ka.rs index 5a68e37b0..1407e4b05 100644 --- a/crates/ui-egui/src/i18n/ka.rs +++ b/crates/ui-egui/src/i18n/ka.rs @@ -65,6 +65,11 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("New Section", "ახალი სექცია"), ("Clear Frame Fitting Options", "ჩარჩოს მორგების პარამეტრების გასუფთავება"), ("Cannot be edited", "რედაქტირება შეუძლებელია"), + ("RGB Color Space View", "RGB ფერთა სივრცის ხედი"), + ("Lab Color Space View", "Lab ფერთა სივრცის ხედი"), + ("Add CMYK Swatch", "CMYK ფერის ნიმუშის დამატება"), + ("Added swatch", "ფერის ნიმუში დამატებულია"), + ("Eyedropper: drag it onto the page", "პიპეტი: გადაიტანეთ გვერდზე"), ("Restart Numbering", "ნუმერაციის თავიდან დაწყება"), ("Continue Numbering", "ნუმერაციის გაგრძელება"), ("Keep Options…", "შენარჩუნების პარამეტრები…"), diff --git a/crates/ui-egui/src/i18n/pl.rs b/crates/ui-egui/src/i18n/pl.rs index b536be8c7..2cfa47402 100644 --- a/crates/ui-egui/src/i18n/pl.rs +++ b/crates/ui-egui/src/i18n/pl.rs @@ -69,6 +69,11 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("New Section", "Nowa sekcja"), ("Clear Frame Fitting Options", "Wyczyść opcje dopasowania ramki"), ("Cannot be edited", "Nie można edytować"), + ("RGB Color Space View", "Widok przestrzeni barw RGB"), + ("Lab Color Space View", "Widok przestrzeni barw Lab"), + ("Add CMYK Swatch", "Dodaj próbkę CMYK"), + ("Added swatch", "Dodano próbkę"), + ("Eyedropper: drag it onto the page", "Kroplomierz: przeciągnij go na stronę"), ("Restart Numbering", "Zacznij numerowanie od nowa"), ("Continue Numbering", "Kontynuuj numerowanie"), ("Keep Options…", "Opcje utrzymywania…"), diff --git a/crates/ui-egui/src/i18n/pt_br.rs b/crates/ui-egui/src/i18n/pt_br.rs index 505b840ea..0614aa9b8 100644 --- a/crates/ui-egui/src/i18n/pt_br.rs +++ b/crates/ui-egui/src/i18n/pt_br.rs @@ -68,6 +68,11 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("New Section", "Nova seção"), ("Clear Frame Fitting Options", "Limpar opções de ajuste do quadro"), ("Cannot be edited", "Não editável"), + ("RGB Color Space View", "Exibição do espaço de cores RGB"), + ("Lab Color Space View", "Exibição do espaço de cores Lab"), + ("Add CMYK Swatch", "Adicionar amostra CMYK"), + ("Added swatch", "Amostra adicionada"), + ("Eyedropper: drag it onto the page", "Conta-gotas: arraste-o para a página"), ("Restart Numbering", "Reiniciar numeração"), ("Continue Numbering", "Continuar numeração"), ("Keep Options…", "Opções de manutenção…"), diff --git a/crates/ui-egui/src/i18n/ru.rs b/crates/ui-egui/src/i18n/ru.rs index 6e8e49df2..5a096b76b 100644 --- a/crates/ui-egui/src/i18n/ru.rs +++ b/crates/ui-egui/src/i18n/ru.rs @@ -73,6 +73,11 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("New Section", "Новый раздел"), ("Clear Frame Fitting Options", "Очистить параметры подгонки фрейма"), ("Cannot be edited", "Нельзя изменить"), + ("RGB Color Space View", "Просмотр цветового пространства RGB"), + ("Lab Color Space View", "Просмотр цветового пространства Lab"), + ("Add CMYK Swatch", "Добавить образец CMYK"), + ("Added swatch", "Образец добавлен"), + ("Eyedropper: drag it onto the page", "Пипетка: перетащите её на страницу"), ("Restart Numbering", "Начать нумерацию заново"), ("Continue Numbering", "Продолжить нумерацию"), ("Keep Options…", "Параметры удержания…"), diff --git a/crates/ui-egui/src/i18n/table.rs b/crates/ui-egui/src/i18n/table.rs index 384d7eb92..8170e6cb6 100644 --- a/crates/ui-egui/src/i18n/table.rs +++ b/crates/ui-egui/src/i18n/table.rs @@ -1053,6 +1053,16 @@ pub(super) const TABLE: &[(&str, [&str; 5])] = &[ ("Class:", ["Class:", "Classe :", "Class:", "Class:", "类别:"]), ("Color Picker", ["Color Picker", "Sélecteur de couleurs", "Color Picker", "Color Picker", "拾色器"]), ("Color spectrum", ["Farbspektrum", "Spectre de couleurs", "Espectro de color", "カラースペクトル", "色谱"]), + ( + "Eyedropper: drag it onto the page", + [ + "Pipette: auf die Seite ziehen", + "Pipette : faites-la glisser sur la page", + "Cuentagotas: arrástrelo a la página", + "スポイト : ページにドラッグ", + "吸管:将其拖到页面上", + ], + ), ("Color Settings", ["Color Settings", "Réglages des couleurs", "Color Settings", "Color Settings", "颜色设置"]), ("Color:", ["Color:", "Couleur :", "Color:", "Color:", "颜色:"]), ("Columns", ["Columns", "Colonnes", "Columns", "Columns", "栏"]), diff --git a/crates/ui-egui/src/i18n/uk.rs b/crates/ui-egui/src/i18n/uk.rs index 858e0912e..b81bce8b4 100644 --- a/crates/ui-egui/src/i18n/uk.rs +++ b/crates/ui-egui/src/i18n/uk.rs @@ -66,6 +66,11 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("New Section", "Новий розділ"), ("Clear Frame Fitting Options", "Очистити параметри припасування фрейму"), ("Cannot be edited", "Не можна змінити"), + ("RGB Color Space View", "Перегляд колірного простору RGB"), + ("Lab Color Space View", "Перегляд колірного простору Lab"), + ("Add CMYK Swatch", "Додати зразок CMYK"), + ("Added swatch", "Зразок додано"), + ("Eyedropper: drag it onto the page", "Піпетка: перетягніть її на сторінку"), ("Restart Numbering", "Почати нумерацію знову"), ("Continue Numbering", "Продовжити нумерацію"), ("Keep Options…", "Параметри утримання…"),