commit 2e3361408c34945f3a8b0a3be9854f7716f87d52
parent 19f210b2ade5aa6bb0b39655dd6a7702c80bb57b
Author: Bradley Gannon <bradley@bradleygannon.com>
Date: Wed, 9 Sep 2026 17:27:08 -0400
Highlight moused-over book slot and show popup for that book if present
Diffstat:
3 files changed, 100 insertions(+), 50 deletions(-)
diff --git a/client/src/input.rs b/client/src/input.rs
@@ -70,7 +70,7 @@ pub(crate) fn handle_drop_book_input(
}
}
-fn get_bookshelf_mouse_address(
+pub(crate) fn get_bookshelf_mouse_address(
camera: &Camera,
bookshelves: &HashMap<BookshelfId, Bookshelf>,
) -> Option<SlotAddress> {
diff --git a/client/src/render.rs b/client/src/render.rs
@@ -1,8 +1,8 @@
-use common::game::book::{BOOKS, Bookshelf, Slot};
+use common::game::book::{BOOKS, BookId, Bookshelf, Slot};
use lazy_static::lazy_static;
use macroquad::prelude::*;
-use crate::ClientState;
+use crate::{ClientState, input::get_bookshelf_mouse_address};
lazy_static! {
pub(crate) static ref SPRITESHEET: Spritesheet = Spritesheet::load();
@@ -87,8 +87,9 @@ impl ClientState {
if let Some(local_player_id) = self.local_player_id
&& let Some(local_player) = self.interpolated_game.get_player(&local_player_id)
{
+ let mouse_slot = get_bookshelf_mouse_address(&self.camera, self.game.bookshelves());
// Render bookshelves
- for bookshelf in self.interpolated_game.bookshelves().values() {
+ for (bookshelf_id, bookshelf) in self.interpolated_game.bookshelves() {
const BOOKSHELF_BACKGROUND: Color = BROWN;
const BOOKSHELF_FRAME: Color = DARKBROWN;
let bounds: Rect = bookshelf.rect().offset(-self.camera.position);
@@ -127,26 +128,63 @@ impl ClientState {
* (Bookshelf::BOOK_HEIGHT + Bookshelf::SHELF_THICKNESS)
- Bookshelf::FRAME_THICKNESS;
for (slot_index, slot) in shelf.iter().enumerate() {
- if let Slot::Book { .. } = slot {
- let x = bounds.x
- + Bookshelf::FRAME_THICKNESS
- + slot_index as f32 * Bookshelf::BOOK_WIDTH;
- draw_line(x, y, x, y + Bookshelf::BOOK_HEIGHT, 2., BLACK);
- draw_rectangle(
- x,
- y,
- Bookshelf::BOOK_WIDTH,
- Bookshelf::BOOK_HEIGHT,
- BLUE,
- );
- draw_line(
- x + Bookshelf::BOOK_WIDTH,
- y,
- x + Bookshelf::BOOK_WIDTH,
- y + Bookshelf::BOOK_HEIGHT,
- 1.,
- BLACK,
- );
+ let x = bounds.x
+ + Bookshelf::FRAME_THICKNESS
+ + slot_index as f32 * Bookshelf::BOOK_WIDTH;
+ match slot {
+ Slot::Book { book_id } => {
+ draw_line(x, y, x, y + Bookshelf::BOOK_HEIGHT, 2., BLACK);
+ draw_rectangle(
+ x,
+ y,
+ Bookshelf::BOOK_WIDTH,
+ Bookshelf::BOOK_HEIGHT,
+ BLUE,
+ );
+ draw_line(
+ x + Bookshelf::BOOK_WIDTH,
+ y,
+ x + Bookshelf::BOOK_WIDTH,
+ y + Bookshelf::BOOK_HEIGHT,
+ 1.,
+ BLACK,
+ );
+ if let Some(ms) = mouse_slot
+ && ms.bookshelf_id() == *bookshelf_id
+ && ms.shelf_index() == shelf_index
+ && ms.position() == slot_index
+ {
+ draw_rectangle(
+ x,
+ y,
+ Bookshelf::BOOK_WIDTH,
+ Bookshelf::BOOK_HEIGHT,
+ GOLD.with_alpha(0.5),
+ );
+ self.draw_book_metadata_popup(
+ Vec2::new(
+ x - Bookshelf::BOOK_WIDTH / 2. + self.camera.position.x,
+ y + self.camera.position.y,
+ ),
+ book_id,
+ );
+ }
+ }
+ Slot::Empty => {
+ if let Some(ms) = mouse_slot
+ && ms.bookshelf_id() == *bookshelf_id
+ && ms.shelf_index() == shelf_index
+ && ms.position() == slot_index
+ {
+ draw_rectangle(
+ x,
+ y,
+ Bookshelf::BOOK_WIDTH,
+ Bookshelf::BOOK_HEIGHT,
+ GOLD.with_alpha(0.5),
+ );
+ }
+ }
}
}
}
@@ -193,31 +231,9 @@ impl ClientState {
)
})
{
- let text = if let Some(metadata) = BOOKS.get(&nearby_floor_book.id()) {
- metadata.to_string()
- } else {
- "Unknown book".to_string()
- };
- let font_size = 24.;
- let text_dimensions = measure_text(&text, None, font_size as u16, 1.);
- let padding = 4.;
- let x = nearby_floor_book.position().x - self.camera.position.x;
- let y = nearby_floor_book.position().y - self.camera.position.y - 16.;
- let w = text_dimensions.width;
- let h = text_dimensions.height;
- draw_rectangle(
- x - padding,
- y - text_dimensions.offset_y - padding,
- w + padding,
- h + padding,
- WHITE.with_alpha(0.5),
- );
- draw_text(text, x, y, font_size, BLACK.with_alpha(0.5));
- draw_triangle(
- Vec2::new(x + 4., y + 5.),
- Vec2::new(x + 12., y + 13.),
- Vec2::new(x + 20., y + 5.),
- WHITE.with_alpha(0.5),
+ self.draw_book_metadata_popup(
+ nearby_floor_book.position(),
+ &nearby_floor_book.id(),
);
}
@@ -238,7 +254,7 @@ impl ClientState {
// Render debug view if enabled
if self.debug_view {
draw_rectangle(0., 0., 284., 56., BLACK);
- draw_text("Library Tech Demo 2026-09-07", 4., 16., 16., WHITE);
+ draw_text("Library Tech Demo 2026-09-09", 4., 16., 16., WHITE);
draw_text(format!("fps {}", get_fps()), 4., 32., 16., WHITE);
draw_text(format!("id {}", local_player_id), 4., 48., 16., WHITE);
draw_text(
@@ -265,4 +281,32 @@ impl ClientState {
local_player.position() - screen_center + player_sprite.size / 2.;
}
}
+ fn draw_book_metadata_popup(&self, position: Vec2, book_id: &BookId) {
+ let text = if let Some(metadata) = BOOKS.get(book_id) {
+ metadata.to_string()
+ } else {
+ "Unknown book".to_string()
+ };
+ let font_size = 24.;
+ let text_dimensions = measure_text(&text, None, font_size as u16, 1.);
+ let padding = 4.;
+ let x = position.x - self.camera.position.x;
+ let y = position.y - self.camera.position.y - 16.;
+ let w = text_dimensions.width;
+ let h = text_dimensions.height;
+ draw_rectangle(
+ x - padding,
+ y - text_dimensions.offset_y - padding,
+ w + padding,
+ h + padding,
+ WHITE.with_alpha(0.5),
+ );
+ draw_text(text, x, y, font_size, BLACK.with_alpha(0.5));
+ draw_triangle(
+ Vec2::new(x + 4., y + 5.),
+ Vec2::new(x + 12., y + 13.),
+ Vec2::new(x + 20., y + 5.),
+ WHITE.with_alpha(0.5),
+ );
+ }
}
diff --git a/common/src/game/book.rs b/common/src/game/book.rs
@@ -41,6 +41,12 @@ impl SlotAddress {
pub fn bookshelf_id(&self) -> BookshelfId {
self.bookshelf_id
}
+ pub fn shelf_index(&self) -> usize {
+ self.shelf_index
+ }
+ pub fn position(&self) -> usize {
+ self.position
+ }
}
#[derive(