Scroll long menus and lists with the mouse wheel or a swipe
Touch clicks in menus happen on release without a swipe. The first-start language picker is a flag grid that scrolls. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d8e9184a9c
commit
6629472811
4 files changed
+157
-25
No files matched your search
+49
-9
@@ -15,7 +15,7 @@ use crate::ui::{grid_center, grid_center_y, mouse, sh, sw, tool_info, wrap, side
|
||||
use macroquad::prelude::*;
|
||||
|
||||
mod bestiary;
|
||||
mod flags;
|
||||
pub mod flags;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum Page {
|
||||
@@ -645,6 +645,7 @@ impl Menu {
|
||||
MenuAction::Consumed
|
||||
}
|
||||
Some(Btn::Tab(t)) => {
|
||||
self.scroll = 0;
|
||||
self.page = Some(Page::Settings { tab: t, from_title });
|
||||
MenuAction::Consumed
|
||||
}
|
||||
@@ -1171,9 +1172,17 @@ impl Menu {
|
||||
let half = (acts.len() + 1) / 2;
|
||||
let colw = (cols as f32 - 6.0) * CW() * 0.5;
|
||||
let rowh = CH();
|
||||
// on small screens the two columns scroll (mouse wheel, swipe)
|
||||
let vis = (((y + (rows - 6) as f32 * CH() - top) / rowh).floor() as usize).max(1).min(half);
|
||||
self.rows_visible = vis;
|
||||
self.scroll = self.scroll.min(half - vis);
|
||||
for (k, a) in acts.iter().enumerate() {
|
||||
let c = k / half;
|
||||
let r = k % half;
|
||||
if r < self.scroll || r >= self.scroll + vis {
|
||||
continue;
|
||||
}
|
||||
let r = r - self.scroll;
|
||||
let bx = x + CW() * 2.0 + c as f32 * (colw + CW() * 2.0);
|
||||
let by = top + r as f32 * rowh;
|
||||
let rect = Rect::new(bx, by - 2.0, colw, rowh - 2.0);
|
||||
@@ -1188,8 +1197,12 @@ impl Menu {
|
||||
gfx.text(&key, bx + colw - gfx.measure(&key, S()) - CW() * 0.5, by, S(), GOLD);
|
||||
self.buttons.push((rect, Btn::Key(k)));
|
||||
}
|
||||
if vis < half {
|
||||
let pos = format!("{}-{}/{}", self.scroll + 1, self.scroll + vis, half);
|
||||
gfx.text(&pos, x + cols as f32 * CW() - gfx.measure(&pos, SMALL()) - CW() * 2.0, top - CH() * 1.2, SMALL(), DIM);
|
||||
}
|
||||
let hint = tr("set.keys_hint");
|
||||
gfx.text(&hint, x + CW() * 2.0, top + half as f32 * rowh + CH() * 0.5, SMALL(), DIM);
|
||||
gfx.text(&hint, x + CW() * 2.0, top + vis as f32 * rowh + CH() * 0.5, SMALL(), DIM);
|
||||
let rw = gfx.measure(&tr("set.reset_keys"), S()) + CW() * 4.0;
|
||||
let rr = Rect::new(x + cols as f32 * CW() - rw - CW() * 2.0, y + (rows - 4) as f32 * CH(), rw, CH() * 2.0);
|
||||
button(gfx, rr, &tr("set.reset_keys"), rr.contains(vec2(mx, my)), FRAME);
|
||||
@@ -1612,7 +1625,22 @@ impl Menu {
|
||||
|
||||
// scrolling on pages with lists (mouse wheel)
|
||||
pub fn scrollable(&self) -> bool {
|
||||
matches!(self.page, Some(Page::Saves { .. }) | Some(Page::Campaign) | Some(Page::CampaignEditor) | Some(Page::Briefing { .. }))
|
||||
matches!(
|
||||
self.page,
|
||||
Some(Page::Saves { .. }) | Some(Page::Campaign) | Some(Page::CampaignEditor) | Some(Page::Briefing { .. }) | Some(Page::Settings { tab: 5, .. }) | Some(Page::Match { .. }) | Some(Page::Account)
|
||||
)
|
||||
}
|
||||
|
||||
// mouse wheel or a swipe: scrolls what is under it (an open dropdown first); d lines down
|
||||
pub fn wheel(&mut self, d: i32) {
|
||||
if self.lang_wheel(d) {
|
||||
return;
|
||||
}
|
||||
if matches!(self.page, Some(Page::Bestiary { .. })) {
|
||||
self.bestiary_wheel(d);
|
||||
} else if self.scrollable() {
|
||||
self.scroll_lines(d);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scroll_lines(&mut self, d: i32) {
|
||||
@@ -1729,11 +1757,16 @@ impl Menu {
|
||||
let sure = tr("saves.sure");
|
||||
let dw = gfx.measure(&del, S()).max(gfx.measure(&sure, S())) + CW() * 3.0;
|
||||
let bottom = y + (rows - 5) as f32 * CH();
|
||||
for (k, u) in cloud.users.iter().enumerate() {
|
||||
let ry = yy + k as f32 * CH() * 2.5;
|
||||
if ry + CH() * 2.0 > bottom {
|
||||
break;
|
||||
}
|
||||
// more users than fit: the list scrolls (mouse wheel, swipe)
|
||||
let vis = (((bottom - yy) / (CH() * 2.5)).floor() as usize).max(1);
|
||||
self.rows_visible = vis;
|
||||
self.scroll = self.scroll.min(cloud.users.len().saturating_sub(vis));
|
||||
if cloud.users.len() > vis {
|
||||
let pos = format!("{}-{}/{}", self.scroll + 1, (self.scroll + vis).min(cloud.users.len()), cloud.users.len());
|
||||
gfx.text(&pos, ix + w - gfx.measure(&pos, SMALL()), yy - CH() * 1.2, SMALL(), DIM);
|
||||
}
|
||||
for (k, u) in cloud.users.iter().enumerate().skip(self.scroll).take(vis) {
|
||||
let ry = yy + (k - self.scroll) as f32 * CH() * 2.5;
|
||||
let label = if u.admin { format!("{} (admin)", u.name) } else { u.name.clone() };
|
||||
gfx.text(&label, ix, ry + CH() * 0.5, S(), TXT);
|
||||
if !u.admin {
|
||||
@@ -1847,7 +1880,14 @@ impl Menu {
|
||||
if !ui.rooms.is_empty() && !ui.started {
|
||||
gfx.text(&tr("net.rooms"), ix, yy, S(), GOLD);
|
||||
yy += CH() * 1.4;
|
||||
for (k, room) in ui.rooms.iter().take(4).enumerate() {
|
||||
// more than four open matches: the list scrolls (mouse wheel, swipe)
|
||||
self.rows_visible = 4;
|
||||
self.scroll = self.scroll.min(ui.rooms.len().saturating_sub(4));
|
||||
if ui.rooms.len() > 4 {
|
||||
let pos = format!("{}-{}/{}", self.scroll + 1, self.scroll + 4, ui.rooms.len());
|
||||
gfx.text(&pos, ix + 25.0 * CW(), yy - CH() * 1.4, SMALL(), DIM);
|
||||
}
|
||||
for (k, room) in ui.rooms.iter().enumerate().skip(self.scroll).take(4) {
|
||||
let label = format!("{} {}{}{}", room.code, room.players, if room.started { " *" } else { "" }, if room.paused { " p" } else { "" });
|
||||
let r = Rect::new(ix, yy, 24.0 * CW(), CH() * 2.0);
|
||||
button(gfx, r, &label, r.contains(vec2(mx, my)), FRAME);
|
||||
|
||||
Reference in new issue
Block a user