Hyperlinks: Ctrl+click on a link follows it instead of extending the selection (#1198)

A Ctrl+click went to the add-to-selection branch, so the link under the pointer was never followed. It now goes through follow_link like a plain click (asks before opening web addresses, jumps to references).
This commit is contained in:
xc4pr
2026-10-23 00:44:34 +02:00
parent ac8da7d49c
commit d046ba6aa7
2 changed files with 79 additions and 1 deletions
+9 -1
View File
@@ -2364,7 +2364,15 @@ fn interact(app: &mut SheetApp, ui: &mut egui::Ui, resp: &egui::Response, geo: &
d.selection.anchor = sel.anchor;
}
} else if mods.command {
select_ranges(app, RangeRef::cell(c), true, c);
// Ctrl+click on a hyperlink's text follows it instead of adding the cell to the selection.
if let Some(h) = sh.hyperlinks.get(&c).cloned()
&& primary_clicked
&& p.x < geo.cell_rect(sh, c).left() + geo.cell_rect(sh, c).width() * 0.8
{
follow_link(app, &h.target);
} else {
select_ranges(app, RangeRef::cell(c), true, c);
}
} else {
let _ = app.session.run("selection.set", json!({"cell": c.a1()}));
if primary_clicked && wb.styles.get(sh.style_id(c)).num_fmt.as_str() == "checkbox" {
@@ -0,0 +1,70 @@
//! Ctrl+click on a hyperlink cell follows the link (#1198), like a plain click does.
use egui::{Event, Modifiers, PointerButton, Pos2};
use gridcraft_engine::Session;
use gridcraft_engine::core::CellRef;
use gridcraft_ui_egui::{SheetApp, grid::Geo};
use serde_json::json;
type Harness = egui_kittest::Harness<'static, SheetApp>;
fn harness() -> Harness {
let mut session = Session::new();
session.new_workbook();
session.execute("cell.set", json!({"cell": "B2", "input": "web"})).unwrap();
session.execute("insert.link", json!({"cell": "B2", "target": "https://example.org/a"})).unwrap();
session.execute("cell.set", json!({"cell": "B4", "input": "jump"})).unwrap();
session.execute("insert.link", json!({"cell": "B4", "target": "Sheet1!F9"})).unwrap();
let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state(
|ui, app: &mut SheetApp| {
app.logic(ui.ctx());
app.ui(ui);
},
SheetApp::new(session, Default::default()),
);
h.run_steps(4);
h
}
fn left_of_cell(h: &Harness, cell: &str) -> Pos2 {
let app = h.state();
let sheet = app.session.active().unwrap().wb.active().unwrap();
let geo = Geo::new(sheet, app.grid.rect.unwrap(), app.view().scroll);
let r = geo.cell_rect(sheet, CellRef::parse(cell).unwrap());
egui::pos2(r.left() + r.width() * 0.3, r.center().y)
}
fn click(h: &mut Harness, cell: &str, modifiers: Modifiers) {
let pos = left_of_cell(h, cell);
h.input_mut().events.push(Event::ModifiersChanged(modifiers));
h.input_mut().events.extend([
Event::PointerMoved(pos),
Event::PointerButton { pos, button: PointerButton::Primary, pressed: true, modifiers },
Event::PointerButton { pos, button: PointerButton::Primary, pressed: false, modifiers },
]);
h.run_steps(3);
h.input_mut().events.push(Event::ModifiersChanged(Modifiers::NONE));
h.run_steps(1);
}
#[test]
fn ctrl_click_on_a_web_link_asks_to_open_it() {
let mut h = harness();
click(&mut h, "B2", Modifiers::COMMAND);
let d = h.state().dialog.as_ref().expect("Ctrl+click on a web link opens the confirmation");
assert_eq!(d.name, "openLink");
}
#[test]
fn ctrl_click_on_an_internal_link_goes_there() {
let mut h = harness();
click(&mut h, "B4", Modifiers::COMMAND);
assert_eq!(h.state().session.active().unwrap().selection.active.a1(), "F9");
}
#[test]
fn plain_click_still_follows() {
let mut h = harness();
click(&mut h, "B4", Modifiers::NONE);
assert_eq!(h.state().session.active().unwrap().selection.active.a1(), "F9");
}