mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 02:19:56 -06:00
UI: centre the Home New / Open buttons and links too (#4684)
The first commit centred the headings but left the New / Open buttons and the community links on the left, as `horizontal` fills the width. The buttons' row is now padded by its measured width, and the Home screen's links are centred (label only, no icon; About keeps its left-aligned icon rows). The test now measures where the centred text lies and checks the buttons, the Discord button and the links. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0113uEh3VQ6et4zDMZ9cqzkf
This commit is contained in:
committed by
bflatastic
co-authored by
Claude Sonnet 5.5
parent
3d31b623a4
commit
9b8b1229b6
@@ -31,7 +31,11 @@ fn home_content(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
ui.add_space(4.0);
|
||||
ui.label(egui::RichText::new(tl!("Vector illustration — fast, open, scriptable.")).size(14.0).color(t.text_dim));
|
||||
ui.add_space(22.0);
|
||||
// `horizontal` fills the width, so the row's own width sets its left edge.
|
||||
let gap = ui.spacing().item_spacing.x + 8.0;
|
||||
let row = widgets::button_width(ui, tl!("New file")) + gap + widgets::button_width(ui, tl!("Open"));
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(((ui.available_width() - row) / 2.0).max(0.0));
|
||||
if widgets::primary_button(ui, tl!("New file")).clicked() {
|
||||
app.run("file.newDialog", json!({})).ok();
|
||||
}
|
||||
@@ -60,7 +64,7 @@ fn home_content(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
ui.vertical_centered(|ui| {
|
||||
ui.label(egui::RichText::new(tl!("Community")).font(theme::semibold(14.0)).color(t.text));
|
||||
ui.add_space(10.0);
|
||||
crate::community::links(app, ui);
|
||||
crate::community::links_centered(app, ui);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -53,27 +53,44 @@ pub fn discord_button(app: &mut VectorcraftApp, ui: &mut Ui, large: bool) -> egu
|
||||
resp
|
||||
}
|
||||
|
||||
/// One link row: icon, label, opens the command's URL.
|
||||
fn link(app: &mut VectorcraftApp, ui: &mut Ui, icon: &str, label: &str, cmd: &str, url: &str) {
|
||||
/// One link row: icon, label, opens the command's URL. `centered` drops the icon so the label
|
||||
/// alone sits in the middle of the column.
|
||||
fn link(app: &mut VectorcraftApp, ui: &mut Ui, icon: &str, label: &str, cmd: &str, url: &str, centered: bool) {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
ui.horizontal(|ui| {
|
||||
icons::icon(ui, icon, 16.0, t.icon);
|
||||
let r = ui.add(egui::Button::new(egui::RichText::new(label).color(t.accent).size(13.0)).frame(false)).on_hover_text(url);
|
||||
if r.clicked() {
|
||||
app.open_link(cmd);
|
||||
}
|
||||
});
|
||||
let button = |ui: &mut Ui| ui.add(egui::Button::new(egui::RichText::new(label).color(t.accent).size(13.0)).frame(false)).on_hover_text(url);
|
||||
let r = if centered {
|
||||
button(ui)
|
||||
} else {
|
||||
ui.horizontal(|ui| {
|
||||
icons::icon(ui, icon, 16.0, t.icon);
|
||||
button(ui)
|
||||
})
|
||||
.inner
|
||||
};
|
||||
if r.clicked() {
|
||||
app.open_link(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
/// The Discord button and the website / app page / GitHub links.
|
||||
pub fn links(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
links_in(app, ui, false);
|
||||
}
|
||||
|
||||
/// [`links`] for a centred column (the Home screen's, as PhotoCraft's, #4684): the Discord button
|
||||
/// and the links, each in the middle.
|
||||
pub fn links_centered(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
links_in(app, ui, true);
|
||||
}
|
||||
|
||||
fn links_in(app: &mut VectorcraftApp, ui: &mut Ui, centered: bool) {
|
||||
discord_button(app, ui, true);
|
||||
ui.add_space(8.0);
|
||||
let l = app.session.execute("help.links", &serde_json::json!({})).unwrap_or_default();
|
||||
let s = |k: &str| l[k].as_str().unwrap_or("").to_string();
|
||||
link(app, ui, "globe", tl!("ArtCraft website"), "help.website", &s("website"));
|
||||
link(app, ui, "external-link", tl!("VectorCraft on getartcraft.com"), "help.appPage", &s("appPage"));
|
||||
link(app, ui, "git-branch", tl!("Source code on GitHub"), "help.github", &s("github"));
|
||||
link(app, ui, "globe", tl!("ArtCraft website"), "help.website", &s("website"), centered);
|
||||
link(app, ui, "external-link", tl!("VectorCraft on getartcraft.com"), "help.appPage", &s("appPage"), centered);
|
||||
link(app, ui, "git-branch", tl!("Source code on GitHub"), "help.github", &s("github"), centered);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -440,11 +440,11 @@ fn a_queued_reopen_keeps_the_roots_it_was_asked_in() {
|
||||
}
|
||||
|
||||
/// The x-centre of the first text shape whose text is `text` on a drawn Home screen, and the
|
||||
/// window's centre (#4684).
|
||||
/// window's centre (#4684). A centred galley's `pos` is its anchor, so its rect says where it lies.
|
||||
fn text_centre_x(app: &mut VectorcraftApp, text: &str) -> Option<(f32, f32)> {
|
||||
fn find(s: &egui::Shape, text: &str) -> Option<f32> {
|
||||
match s {
|
||||
egui::Shape::Text(t) if t.galley.text() == text => Some(t.pos.x + t.galley.size().x / 2.0),
|
||||
egui::Shape::Text(t) if t.galley.text() == text => Some(t.pos.x + t.galley.rect.center().x),
|
||||
egui::Shape::Vec(v) => v.iter().find_map(|s| find(s, text)),
|
||||
_ => None,
|
||||
}
|
||||
@@ -460,12 +460,32 @@ fn text_centre_x(app: &mut VectorcraftApp, text: &str) -> Option<(f32, f32)> {
|
||||
Some((x, screen.center().x))
|
||||
}
|
||||
|
||||
/// The Home screen centres its welcome and its community block, as PhotoCraft's does (#4684).
|
||||
/// The Home screen centres its welcome, its New / Open buttons and its community block, as
|
||||
/// PhotoCraft's does (#4684).
|
||||
#[test]
|
||||
fn home_welcome_and_community_are_centred() {
|
||||
let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), crate::Services::default());
|
||||
for text in ["Welcome to VectorCraft", "Community"] {
|
||||
for text in ["Welcome to VectorCraft", "Community", "ArtCraft website", "VectorCraft on getartcraft.com", "Source code on GitHub"] {
|
||||
let (x, centre) = text_centre_x(&mut app, text).unwrap_or_else(|| panic!("{text} is drawn"));
|
||||
assert!((x - centre).abs() < 2.0, "{text} is centred: {x} vs {centre}");
|
||||
assert!((x - centre).abs() < 6.0, "{text} is centred: {x} vs {centre}");
|
||||
}
|
||||
// The Discord button is centred; its label lies right of its icon, 0.375 of the button's 36 pt
|
||||
// height right of the middle.
|
||||
let (x, centre) = text_centre_x(&mut app, "Join our Discord").unwrap();
|
||||
assert!((x - centre - 0.375 * 36.0).abs() < 2.0, "the Discord button is centred: label at {x} about {centre}");
|
||||
// The two buttons (a label's width plus 32, at least 72, each) lie symmetrically about the
|
||||
// centre: the first one's left edge and the second one's right edge are equally far from it.
|
||||
let width = |label: &str| {
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
let mut w = 0.0;
|
||||
let mut out = ctx.run_ui(egui::RawInput::default(), |ui| w = crate::widgets::button_width(ui, label));
|
||||
out.textures_delta.clear();
|
||||
w
|
||||
};
|
||||
let (new_x, centre) = text_centre_x(&mut app, "New file").unwrap();
|
||||
let (open_x, _) = text_centre_x(&mut app, "Open").unwrap();
|
||||
let left = new_x - width("New file") / 2.0;
|
||||
let right = open_x + width("Open") / 2.0;
|
||||
assert!((centre - left - (right - centre)).abs() < 6.0, "New / Open row is centred: {left}..{right} about {centre}");
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ pub use buttons::{
|
||||
SPLIT_ARROW, flat_button, flat_button_fit, icon_button, icon_button_enabled, menu_item, menu_item_name, paint_icon_button, primary_button,
|
||||
primary_button_enabled, secondary_button, split_button, split_button_named, toggle_icon,
|
||||
};
|
||||
pub(crate) use buttons::{icon_button_info, primary_button_width, secondary_button_width};
|
||||
pub(crate) use buttons::{button_width, icon_button_info, primary_button_width, secondary_button_width};
|
||||
#[cfg(test)]
|
||||
use chips::gradient_chip_colors;
|
||||
pub use chips::{ProxyClicks, chip_button, chip_button_named, fill_stroke_proxy, gradient_chip, paint_chip, proxy_chip, swatch_tile};
|
||||
|
||||
@@ -101,6 +101,13 @@ fn flat_fill(ui: &Ui, rect: Rect, resp: &Response) {
|
||||
}
|
||||
}
|
||||
|
||||
/// The width [`primary_button`] and [`secondary_button`] give `text` (their label plus padding, at
|
||||
/// least 72), for centring a row of them.
|
||||
pub(crate) fn button_width(ui: &Ui, text: &str) -> f32 {
|
||||
let galley = ui.painter().layout_no_wrap(tl!(text).to_string(), theme::semibold(12.5), Color32::PLACEHOLDER);
|
||||
(galley.size().x + 32.0).max(72.0)
|
||||
}
|
||||
|
||||
/// The accent call-to-action button (dialog OK/Create).
|
||||
pub fn primary_button(ui: &mut Ui, text: &str) -> Response {
|
||||
primary_button_enabled(ui, text, true)
|
||||
|
||||
Reference in New Issue
Block a user