Merge main

# Conflicts:
#	crates/ui-egui/src/tools/type_tool/fonts.rs
#	crates/ui-egui/src/tools/type_tool/ime_tests.rs
This commit is contained in:
David Mann
2026-10-27 16:26:20 +01:00
14 changed files with 207 additions and 39 deletions
Generated
+167 -7
View File
@@ -1163,6 +1163,15 @@ dependencies = [
"x509-cert",
]
[[package]]
name = "cobs"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
dependencies = [
"thiserror 2.0.21",
]
[[package]]
name = "codespan-reporting"
version = "0.13.1"
@@ -1341,12 +1350,40 @@ dependencies = [
[[package]]
name = "craft-docpath"
version = "0.1.0"
source = "git+https://github.com/storytold/craft-libs?rev=495e5971bc024aa96e6ed318cb6e7cd3a0103184#495e5971bc024aa96e6ed318cb6e7cd3a0103184"
source = "git+https://github.com/storytold/craft-libs?rev=92d392cff132eaf53e13afff77f38b5c11b73aa0#92d392cff132eaf53e13afff77f38b5c11b73aa0"
[[package]]
name = "craft-fonts-build"
version = "0.1.0"
source = "git+https://github.com/storytold/craft-libs?rev=92d392cff132eaf53e13afff77f38b5c11b73aa0#92d392cff132eaf53e13afff77f38b5c11b73aa0"
[[package]]
name = "craft-i18n"
version = "0.1.0"
source = "git+https://github.com/storytold/craft-libs?rev=92d392cff132eaf53e13afff77f38b5c11b73aa0#92d392cff132eaf53e13afff77f38b5c11b73aa0"
dependencies = [
"fixed_decimal",
"icu_decimal",
"icu_locale_core",
"icu_locale_fallback",
"icu_normalizer",
"icu_plurals",
"icu_properties",
"icu_provider",
"icu_provider_adapters",
"icu_provider_blob",
"log",
"objc2-foundation 0.3.2",
"sys-locale",
"unicode-bidi",
"windows-registry",
"writeable",
]
[[package]]
name = "craft-jpeg"
version = "0.1.0"
source = "git+https://github.com/storytold/craft-libs?rev=495e5971bc024aa96e6ed318cb6e7cd3a0103184#495e5971bc024aa96e6ed318cb6e7cd3a0103184"
source = "git+https://github.com/storytold/craft-libs?rev=92d392cff132eaf53e13afff77f38b5c11b73aa0#92d392cff132eaf53e13afff77f38b5c11b73aa0"
dependencies = [
"thiserror 2.0.21",
]
@@ -1354,11 +1391,11 @@ dependencies = [
[[package]]
name = "craft-print"
version = "0.1.0"
source = "git+https://github.com/storytold/craft-libs?rev=495e5971bc024aa96e6ed318cb6e7cd3a0103184#495e5971bc024aa96e6ed318cb6e7cd3a0103184"
source = "git+https://github.com/storytold/craft-libs?rev=92d392cff132eaf53e13afff77f38b5c11b73aa0#92d392cff132eaf53e13afff77f38b5c11b73aa0"
dependencies = [
"craft-winprint-gdi",
"miniz_oxide 0.8.9",
"roxmltree 0.20.0",
"miniz_oxide 0.9.1",
"roxmltree 0.21.1",
"tempfile",
"winprint",
"winsafe",
@@ -1367,20 +1404,28 @@ dependencies = [
[[package]]
name = "craft-ui"
version = "0.1.0"
source = "git+https://github.com/storytold/craft-libs?rev=495e5971bc024aa96e6ed318cb6e7cd3a0103184#495e5971bc024aa96e6ed318cb6e7cd3a0103184"
source = "git+https://github.com/storytold/craft-libs?rev=92d392cff132eaf53e13afff77f38b5c11b73aa0#92d392cff132eaf53e13afff77f38b5c11b73aa0"
dependencies = [
"craft-fonts-build",
"craft-i18n",
"egui",
"epaint",
"js-sys",
"log",
"objc2 0.6.5",
"objc2-app-kit 0.3.2",
"objc2-foundation 0.3.2",
"serde",
"skrifa",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "craft-update"
version = "0.1.0"
source = "git+https://github.com/storytold/craft-libs?rev=495e5971bc024aa96e6ed318cb6e7cd3a0103184#495e5971bc024aa96e6ed318cb6e7cd3a0103184"
source = "git+https://github.com/storytold/craft-libs?rev=92d392cff132eaf53e13afff77f38b5c11b73aa0#92d392cff132eaf53e13afff77f38b5c11b73aa0"
dependencies = [
"chrono",
"dunce",
@@ -2175,6 +2220,17 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484"
[[package]]
name = "fixed_decimal"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2214fb00f669ee96bee5bb29dfb1ddabe058b2bc426817efc79afa03c9bc55ae"
dependencies = [
"displaydoc",
"smallvec",
"writeable",
]
[[package]]
name = "fixedbitset"
version = "0.5.7"
@@ -2956,6 +3012,23 @@ dependencies = [
"zerovec",
]
[[package]]
name = "icu_decimal"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9eb8f655bba2d0c0459e43a5b0e6cd3cd388109898fb3d85d048165e8b0abd08"
dependencies = [
"displaydoc",
"fixed_decimal",
"icu_locale_core",
"icu_pattern",
"icu_plurals",
"icu_provider",
"serde",
"writeable",
"zerovec",
]
[[package]]
name = "icu_locale_core"
version = "2.3.0"
@@ -3001,6 +3074,9 @@ dependencies = [
"icu_properties",
"icu_provider",
"smallvec",
"utf16_iter",
"utf8_iter",
"write16",
"zerovec",
]
@@ -3010,6 +3086,32 @@ version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0"
[[package]]
name = "icu_pattern"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b3db611446bd92c246b03e4aa0bafa71ddb194af431ddbb42b9d70e4bfce1a0"
dependencies = [
"displaydoc",
"either",
"serde",
"writeable",
"zerovec",
]
[[package]]
name = "icu_plurals"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e475e6766ef87b1d3c1f97be6363995b0bfaeddbc789671615df598a97ff0593"
dependencies = [
"displaydoc",
"fixed_decimal",
"icu_provider",
"serde",
"zerovec",
]
[[package]]
name = "icu_properties"
version = "2.3.0"
@@ -3039,6 +3141,7 @@ checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73"
dependencies = [
"displaydoc",
"icu_locale_core",
"postcard",
"serde",
"stable_deref_trait",
"writeable",
@@ -3048,6 +3151,30 @@ dependencies = [
"zerovec",
]
[[package]]
name = "icu_provider_adapters"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df887bc4f55dbc773c7c45a0c7dfa75be886f7b7812830a71ab7271cc1801820"
dependencies = [
"icu_locale_fallback",
"icu_provider",
]
[[package]]
name = "icu_provider_blob"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5916b44fac319d3f58e4d8d805a627df19e27937b582cd99fcde3bb6b7ce1b0e"
dependencies = [
"icu_provider",
"postcard",
"serde",
"writeable",
"zerotrie",
"zerovec",
]
[[package]]
name = "icu_segmenter"
version = "2.3.0"
@@ -3720,6 +3847,9 @@ name = "litemap"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae"
dependencies = [
"serde_core",
]
[[package]]
name = "litrs"
@@ -5515,6 +5645,16 @@ dependencies = [
"portable-atomic",
]
[[package]]
name = "postcard"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
dependencies = [
"cobs",
"serde",
]
[[package]]
name = "potential_utf"
version = "0.1.6"
@@ -7177,7 +7317,10 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
dependencies = [
"js-sys",
"libc",
"wasm-bindgen",
"web-sys",
]
[[package]]
@@ -7826,6 +7969,12 @@ dependencies = [
"xmlwriter",
]
[[package]]
name = "utf16_iter"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
[[package]]
name = "utf8-zero"
version = "0.8.1"
@@ -8865,11 +9014,20 @@ dependencies = [
"wayland-protocols-wlr",
]
[[package]]
name = "write16"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
[[package]]
name = "writeable"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc"
dependencies = [
"either",
]
[[package]]
name = "x11-dl"
@@ -9247,6 +9405,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f"
dependencies = [
"displaydoc",
"litemap",
"serde_core",
"yoke",
"zerofrom",
"zerovec",
+5 -5
View File
@@ -10,7 +10,7 @@ license = "MIT OR Apache-2.0"
rust-version = "1.95"
[workspace.dependencies]
craft-ui = { git = "https://github.com/storytold/craft-libs", rev = "495e5971bc024aa96e6ed318cb6e7cd3a0103184", features = ["serde"] }
craft-ui = { git = "https://github.com/storytold/craft-libs", rev = "92d392cff132eaf53e13afff77f38b5c11b73aa0", features = ["serde"] }
# internal
photocraft-geom = { path = "crates/geom" }
photocraft-color = { path = "crates/color" }
@@ -39,10 +39,10 @@ photocraft-tablet = { path = "crates/tablet" }
photocraft-ipp = { path = "crates/ipp" }
# external
craft-print = { git = "https://github.com/storytold/craft-libs", rev = "495e5971bc024aa96e6ed318cb6e7cd3a0103184" }
craft-docpath = { version = "0.1.0", git = "https://github.com/storytold/craft-libs", rev = "495e5971bc024aa96e6ed318cb6e7cd3a0103184" }
craft-jpeg = { git = "https://github.com/storytold/craft-libs", rev = "495e5971bc024aa96e6ed318cb6e7cd3a0103184" }
craft-update = { git = "https://github.com/storytold/craft-libs", version = "=0.1.0", rev = "495e5971bc024aa96e6ed318cb6e7cd3a0103184", features = ["egui"] }
craft-print = { git = "https://github.com/storytold/craft-libs", rev = "92d392cff132eaf53e13afff77f38b5c11b73aa0" }
craft-docpath = { version = "0.1.0", git = "https://github.com/storytold/craft-libs", rev = "92d392cff132eaf53e13afff77f38b5c11b73aa0" }
craft-jpeg = { git = "https://github.com/storytold/craft-libs", rev = "92d392cff132eaf53e13afff77f38b5c11b73aa0" }
craft-update = { git = "https://github.com/storytold/craft-libs", version = "=0.1.0", rev = "92d392cff132eaf53e13afff77f38b5c11b73aa0", features = ["egui"] }
thiserror = "2"
serde = { version = "1", features = ["derive", "rc"] }
serde_json = "1"
+3
View File
@@ -2,3 +2,6 @@ allow-unwrap-in-tests = true
allow-expect-in-tests = true
allow-panic-in-tests = true
allow-indexing-slicing-in-tests = true
disallowed-types = [
{ path = "egui::ComboBox", reason = "use craft_ui::ComboBox: egui's combo box menu can't grow back while open (egui#5225)" },
]
@@ -158,7 +158,7 @@ pub(super) fn gradient_map(ui: &mut egui::Ui, v: &mut Value, cx: &EditorCx) -> E
label(ui, tl!("Preset:"));
let mut picked = None;
let (press, close) = crate::press_menu::PressCombo::before(ui, cx.mem.with("gm-preset"));
let combo = egui::ComboBox::from_id_salt(cx.mem.with("gm-preset"))
let combo = craft_ui::ComboBox::from_id_salt(cx.mem.with("gm-preset"))
.selected_text(tl!("Custom"))
.width(ui.available_width().min(190.0))
.height(420.0)
+1 -1
View File
@@ -266,7 +266,7 @@ fn contributors_in(app: &mut PhotocraftApp, ui: &mut egui::Ui, contributors: &[C
ui.separator();
ui.label(tl!("Sort"));
let (press, close) = crate::press_menu::PressCombo::before(ui, "credits_sort");
let sort = egui::ComboBox::from_id_salt("credits_sort").selected_text(v.key.label().0).close_behavior(close).show_ui(ui, |ui| {
let sort = craft_ui::ComboBox::from_id_salt("credits_sort").selected_text(v.key.label().0).close_behavior(close).show_ui(ui, |ui| {
for k in SortKey::ALL {
let item = ui.selectable_label(v.key == k, k.label().0);
if press.chosen(ui, &item) {
@@ -207,7 +207,7 @@ pub fn show(app: &mut PhotocraftApp, ctx: &egui::Context) {
let quality_caption = ui.label(tl!("Quality"));
ui.add(egui::DragValue::new(&mut quality).range(0..=MAX_QUALITY).speed(0.1)).labelled_by(quality_caption.id);
// Photoshop's presets: picking one sets the quality it starts at.
let preset = egui::ComboBox::from_id_salt("jpeg-quality-preset").selected_text(quality_label(quality)).show_ui(ui, |ui| {
let preset = craft_ui::ComboBox::from_id_salt("jpeg-quality-preset").selected_text(quality_label(quality)).show_ui(ui, |ui| {
for q in [3, 5, 8, 10] {
if ui.selectable_label(quality_label(quality) == quality_label(q), quality_label(q)).clicked() {
quality = q;
+1 -1
View File
@@ -144,7 +144,7 @@ pub fn dropdown(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
let mut chosen: Option<Choice> = None;
let parent_layer = ui.layer_id();
let combo =
egui::ComboBox::from_id_salt("crop-ratio").selected_text(label).width(140.0).height(420.0).icon(crate::widgets::chevron_icon).show_ui(ui, |ui| {
craft_ui::ComboBox::from_id_salt("crop-ratio").selected_text(label).width(140.0).height(420.0).icon(crate::widgets::chevron_icon).show_ui(ui, |ui| {
crate::press_menu::above_parent_ui(parent_layer, ui);
let (before, after): (Vec<_>, Vec<_>) = builtin.iter().partition(|(k, _)| k != crop_size::FRONT);
for (k, l) in &before {
@@ -262,7 +262,7 @@ pub fn button(
fn choice<T: Copy + PartialEq>(ui: &mut egui::Ui, label: &str, value: &mut T, choices: &[(T, &str)], children: &mut Children) {
let parent_layer = ui.layer_id();
let (press, close) = crate::press_menu::PressCombo::before(ui, label);
let response = egui::ComboBox::from_id_salt(label)
let response = craft_ui::ComboBox::from_id_salt(label)
.width(152.0)
.selected_text(choices.iter().find(|(v, _)| v == value).map_or("", |(_, n)| tl!(*n)))
.close_behavior(close)
@@ -1,4 +1,4 @@
//! The Type tool's searchable font menu (#1369): it keeps its height and focuses its search field.
//! The Type tool's searchable font menu (#1369): it grows back after a search and focuses its search field.
use std::collections::HashMap;
@@ -175,23 +175,28 @@ fn the_search_field_stays_put_while_the_arrows_scroll_the_list() {
assert_eq!(search, h.get_by_role(Role::TextInput).rect(), "the search field scrolled away with the list");
}
/// A query matching no family shrinks the menu; clearing it grows the menu back to its full
/// height (egui#5225), and the search field stays where it was throughout.
#[test]
fn clearing_the_query_restores_the_menu_height() {
fn clearing_a_query_that_matches_nothing_grows_the_menu_back() {
let mut h = harness();
open(&mut h);
let full = popup_rect(&h).expect("menu open").height();
h.get_by_role(Role::TextInput).type_text("zeta");
let search = h.get_by_role(Role::TextInput).rect();
h.get_by_role(Role::TextInput).type_text("xxxx");
h.run();
assert!(h.query_by_label("Family 01").is_none(), "the query filters the list");
let searching = popup_rect(&h).expect("still open").height();
for _ in 0.."zeta".len() {
assert!(h.query_by_label("Family 00").is_none(), "the query matches no family");
let none = popup_rect(&h).expect("still open").height();
assert!(none < full / 2.0, "no matches shrink the menu: {none} vs {full}");
assert_eq!(search, h.get_by_role(Role::TextInput).rect(), "the search field moved when the list emptied");
for _ in 0.."xxxx".len() {
h.key_press(Key::Backspace);
}
h.run();
assert!(h.query_by_label("Family 01").is_some(), "the cleared query lists every family");
let cleared = popup_rect(&h).expect("still open").height();
assert!((cleared - full).abs() < 0.5, "height after clearing {cleared} != original {full}");
assert!((searching - full).abs() < 0.5, "the menu keeps its height while searching: {searching} vs {full}");
assert_eq!(search, h.get_by_role(Role::TextInput).rect(), "the search field moved when the list grew back");
}
#[test]
+5 -5
View File
@@ -386,7 +386,7 @@ pub(crate) fn family_picker_in(
let labels: Option<Arc<HashMap<String, String>>> = ui.ctx().data(|d| d.get_temp(font_labels_id()));
let labels = labels.as_deref();
let shown = labels.and_then(|l| l.get(current.as_str())).unwrap_or(current).clone();
let combo = egui::ComboBox::from_id_salt(salt)
let combo = craft_ui::ComboBox::from_id_salt(salt)
.selected_text(shown)
.width(width)
.height(FONT_MENU_HEIGHT)
@@ -716,7 +716,7 @@ pub(crate) fn family_picker_in(
});
response.response = response.response.accessible_name(tl!("Font"));
press.after(&response.response);
if !egui::ComboBox::is_open(ui.ctx(), response.response.id) {
if !craft_ui::ComboBox::is_open(ui.ctx(), response.response.id) {
ui.data_mut(|d| {
d.remove::<bool>(focus_id);
d.remove::<Vec<String>>(recents_id);
@@ -734,7 +734,7 @@ pub(crate) fn family_picker_in(
if picked {
ui.memory_mut(|m| m.request_focus(field));
}
let open = egui::ComboBox::is_open(ui.ctx(), field);
let open = craft_ui::ComboBox::is_open(ui.ctx(), field);
if !open && ui.is_enabled() && ui.memory(|m| m.has_focus(field)) {
ui.memory_mut(|m| m.set_focus_lock_filter(field, egui::EventFilter { vertical_arrows: true, ..Default::default() }));
let down = ui.input_mut(|i| i.consume_key(egui::Modifiers::NONE, egui::Key::ArrowDown));
@@ -762,7 +762,7 @@ pub(crate) fn family_picker_in(
// The wheel over the closed button steps through the families, a notch each, like Photoshop's
// options-bar font menu: no need to open the list (#3350).
if !egui::ComboBox::is_open(ui.ctx(), response.response.id) && ui.is_enabled() {
if !craft_ui::ComboBox::is_open(ui.ctx(), response.response.id) && ui.is_enabled() {
let hovered = response.response.hovered();
if hovered {
ui.input_mut(|i| i.smooth_scroll_delta = egui::Vec2::ZERO);
@@ -787,7 +787,7 @@ pub(crate) fn family_picker_in(
let hover_id = egui::Id::unique("type-font-hover");
if let Some(f) = hovered_font {
ui.ctx().data_mut(|d| d.insert_temp(hover_id, f));
} else if egui::ComboBox::is_open(ui.ctx(), response.response.id) {
} else if craft_ui::ComboBox::is_open(ui.ctx(), response.response.id) {
// Only the open menu clears it: the options bar and the Character section both draw
// this picker, and the closed one must not wipe the other's hover (#5152).
ui.ctx().data_mut(|d| d.remove::<String>(hover_id));
@@ -253,7 +253,7 @@ pub(super) fn kerning_field(ui: &mut egui::Ui, shown: &str, width: f32) -> Optio
}
let presets = ["Metrics", "Optical", "0", "-100", "-75", "-50", "-25", "-10", "-5", "5", "10", "25", "50", "75", "100", "200"];
let (press, close) = crate::press_menu::PressCombo::before(ui, "props-kern-presets");
let combo = egui::ComboBox::from_id_salt("props-kern-presets")
let combo = craft_ui::ComboBox::from_id_salt("props-kern-presets")
.selected_text("")
.width(16.0)
.height(420.0)
+1 -1
View File
@@ -167,7 +167,7 @@ fn metric_field(
let near = |p: f32| (p * u - value).abs() <= 1e-4 * value.abs().max(1.0);
let (press, close) = crate::press_menu::PressCombo::before(ui, menu);
let combo =
egui::ComboBox::from_id_salt(menu).selected_text("").width(combo_w).height(420.0).icon(crate::widgets::chevron_icon).close_behavior(close).show_ui(
craft_ui::ComboBox::from_id_salt(menu).selected_text("").width(combo_w).height(420.0).icon(crate::widgets::chevron_icon).close_behavior(close).show_ui(
ui,
|ui| {
if let Some(on) = auto {
+5 -5
View File
@@ -64,7 +64,7 @@ fn dropdown_with<T: PartialEq + Clone>(
let (press, close) = crate::press_menu::PressCombo::before(ui, id);
let texts: Vec<String> = options.iter().map(|(_, l)| shown(l)).collect();
let response =
egui::ComboBox::from_id_salt(id).selected_text(label).width(width).height(420.0).icon(chevron_icon).close_behavior(close).show_ui(ui, |ui| {
craft_ui::ComboBox::from_id_salt(id).selected_text(label).width(width).height(420.0).icon(chevron_icon).close_behavior(close).show_ui(ui, |ui| {
fit_widest_option(ui, texts.iter().map(|l| l.as_str()));
// A typed letter jumps to the next option starting with it, ↩ closes the list (#1481).
let labels: Vec<&str> = texts.iter().map(|l| l.as_str()).collect();
@@ -123,7 +123,7 @@ fn dropdown_with<T: PartialEq + Clone>(
if wheel && !over_list {
let stepped = wheel_steps(ui, wheel_id, response.hovered(), current, options);
wheeled = !stepped.is_empty();
if wheeled && egui::ComboBox::is_open(ui.ctx(), response.id) {
if wheeled && craft_ui::ComboBox::is_open(ui.ctx(), response.id) {
ui.data_mut(|d| d.insert_temp(reveal_id, true));
}
chosen.extend(stepped);
@@ -184,7 +184,7 @@ fn wheel_steps<T: PartialEq + Clone>(ui: &mut Ui, id: egui::Id, hovered: bool, c
}
/// Give a dropdown keyboard focus when it opens, then use the arrow keys to move through its
/// choices. `egui::ComboBox` opens a popup but leaves focus on the canvas by default, which makes
/// choices. `craft_ui::ComboBox` opens a popup but leaves focus on the canvas by default, which makes
/// controls such as the Layers panel's Blend Mode dropdown unreachable from the keyboard.
fn combo_box_arrow_keys<T: PartialEq + Clone>(ui: &mut Ui, response: &Response, current: &mut T, options: &[(T, &str)]) -> bool {
if response.clicked() {
@@ -192,7 +192,7 @@ fn combo_box_arrow_keys<T: PartialEq + Clone>(ui: &mut Ui, response: &Response,
}
// The popup, rather than its button, becomes the focused egui layer after it opens. While it
// is open it owns its navigation keys, even though `response.has_focus()` is then false.
if !egui::ComboBox::is_open(ui.ctx(), response.id) || options.is_empty() {
if !craft_ui::ComboBox::is_open(ui.ctx(), response.id) || options.is_empty() {
return false;
}
let step = if ui.input_mut(|i| i.consume_key(egui::Modifiers::NONE, egui::Key::ArrowDown)) {
@@ -268,7 +268,7 @@ pub fn dropdown_with_tooltips<T: PartialEq + Clone>(ui: &mut Ui, id: &str, name:
let mut changed = false;
let (press, close) = crate::press_menu::PressCombo::before(ui, id);
let response =
egui::ComboBox::from_id_salt(id).selected_text(label).width(width).height(420.0).icon(chevron_icon).close_behavior(close).show_ui(ui, |ui| {
craft_ui::ComboBox::from_id_salt(id).selected_text(label).width(width).height(420.0).icon(chevron_icon).close_behavior(close).show_ui(ui, |ui| {
fit_widest_option(ui, options.iter().map(|(_, l, _)| tl!(l)));
let labels: Vec<&str> = options.iter().map(|(_, l, _)| tl!(l)).collect();
let shown = options.iter().position(|(v, _, _)| v == current);
+3 -3
View File
@@ -115,7 +115,7 @@ pub fn show<R>(button: &Response, content: impl FnOnce(&mut Ui, &PressMenu) -> R
shown
}
/// The same press-drag-release for an `egui::ComboBox` (#2735): the list opens on the press, so one
/// The same press-drag-release for a `craft_ui::ComboBox` (#2735): the list opens on the press, so one
/// gesture can press the box, drag onto an option and release to choose it, and a plain click
/// still opens the list for a second click. egui's combo box shows its own list and toggles it on
/// a whole click, so this works around it: [`PressCombo::before`] runs before the box (and gives
@@ -348,7 +348,7 @@ mod tests {
assert!(!rig.frame(Vec::new()).open, "and closed the menu");
}
/// A bare context with one `egui::ComboBox` of three options, driven with [`PressCombo`].
/// A bare context with one `craft_ui::ComboBox` of three options, driven with [`PressCombo`].
struct ComboRig {
ctx: egui::Context,
value: usize,
@@ -374,7 +374,7 @@ mod tests {
let mut output = self.ctx.run_ui(egui::RawInput { screen_rect: Some(rect), events, ..Default::default() }, |ui| {
ui.add_space(20.0);
let (combo, close) = PressCombo::before(ui, "channel");
let shown = egui::ComboBox::from_id_salt("channel").selected_text(OPTIONS[value]).close_behavior(close).show_ui(ui, |ui| {
let shown = craft_ui::ComboBox::from_id_salt("channel").selected_text(OPTIONS[value]).close_behavior(close).show_ui(ui, |ui| {
out.open = true;
for (i, label) in OPTIONS.into_iter().enumerate() {
let item = ui.selectable_label(value == i, label);