veloren/voxygen/src/hud/minimap.rs

233 lines
7.2 KiB
Rust
Raw Normal View History

2019-10-02 10:05:17 +00:00
use super::{img_ids::Imgs, Fonts, Show, HP_COLOR, TEXT_COLOR};
use client::{self, Client};
use common::comp;
use conrod_core::{
color,
image::Id,
widget::{self, Button, Image, Rectangle, Text},
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
};
2019-11-30 06:41:20 +00:00
use specs::WorldExt;
use std::time::{Duration, Instant};
2019-10-02 10:05:17 +00:00
use vek::*;
2019-06-19 14:55:26 +00:00
widget_ids! {
struct Ids {
mmap_frame,
mmap_frame_bg,
mmap_location,
mmap_button,
zone_display_bg,
zone_display,
2019-10-02 10:05:17 +00:00
grid,
indicator
}
}
#[derive(WidgetCommon)]
pub struct MiniMap<'a> {
show: &'a Show,
2019-06-19 14:55:26 +00:00
client: &'a Client,
imgs: &'a Imgs,
_world_map: Id,
2019-10-04 18:27:12 +00:00
fonts: &'a Fonts,
#[conrod(common_builder)]
common: widget::CommonBuilder,
}
impl<'a> MiniMap<'a> {
pub fn new(
show: &'a Show,
client: &'a Client,
imgs: &'a Imgs,
world_map: Id,
fonts: &'a Fonts,
) -> Self {
Self {
show,
2019-06-19 14:55:26 +00:00
client,
imgs,
_world_map: world_map,
2019-10-04 18:27:12 +00:00
fonts: fonts,
common: widget::CommonBuilder::default(),
}
}
}
pub struct State {
ids: Ids,
last_region_name: Option<String>,
last_update: Instant,
}
pub enum Event {
Toggle,
}
impl<'a> Widget for MiniMap<'a> {
type State = State;
type Style = ();
type Event = Option<Event>;
fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
State {
ids: Ids::new(id_gen),
last_region_name: None,
last_update: Instant::now(),
}
}
fn style(&self) -> Self::Style {
()
}
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
let widget::UpdateArgs { state, ui, .. } = args;
if self.show.mini_map {
Image::new(self.imgs.mmap_frame)
.w_h(100.0 * 4.0, 100.0 * 4.0)
.top_right_with_margins_on(ui.window, 5.0, 5.0)
.set(state.ids.mmap_frame, ui);
Rectangle::fill_with([92.0 * 4.0, 82.0 * 4.0], color::TRANSPARENT)
.mid_top_with_margin_on(state.ids.mmap_frame, 13.0 * 4.0 + 4.0)
.set(state.ids.mmap_frame_bg, ui);
2019-10-02 10:05:17 +00:00
// Map Image
Image::new(/*self.world_map*/ self.imgs.map_placeholder)
2019-10-02 10:05:17 +00:00
.middle_of(state.ids.mmap_frame_bg)
.w_h(92.0 * 4.0, 82.0 * 4.0)
2019-10-02 10:05:17 +00:00
.parent(state.ids.mmap_frame_bg)
.set(state.ids.grid, ui);
// Coordinates
let player_pos = self
.client
.state()
.ecs()
.read_storage::<comp::Pos>()
.get(self.client.entity())
.map_or(Vec3::zero(), |pos| pos.0);
let worldsize = 32768.0; // TODO This has to get the actual world size and not be hardcoded
let x = player_pos.x as f64 / worldsize * 92.0 * 4.0;
let y = (/*1.0X-*/player_pos.y as f64 / worldsize) * 82.0 * 4.0;
2019-10-02 10:05:17 +00:00
// Indicator
Image::new(self.imgs.indicator_mmap)
.bottom_left_with_margins_on(state.ids.grid, y, x - 5.0)
.w_h(10.0, 10.0)
2019-10-02 10:05:17 +00:00
.floating(true)
.parent(ui.window)
.set(state.ids.indicator, ui);
} else {
Image::new(self.imgs.mmap_frame_closed)
.w_h(100.0 * 2.0, 11.0 * 2.0)
.top_right_with_margins_on(ui.window, 5.0, 5.0)
.set(state.ids.mmap_frame, ui);
}
if Button::image(if self.show.mini_map {
self.imgs.mmap_open
} else {
self.imgs.mmap_closed
})
.wh(if self.show.mini_map {
[100.0 * 0.4; 2]
} else {
[100.0 * 0.2; 2]
})
.hover_image(if self.show.mini_map {
self.imgs.mmap_open_hover
} else {
self.imgs.mmap_closed_hover
})
.press_image(if self.show.mini_map {
self.imgs.mmap_open_press
} else {
self.imgs.mmap_closed_press
})
.top_right_with_margins_on(state.ids.mmap_frame, 0.0, 0.0)
.set(state.ids.mmap_button, ui)
.was_clicked()
{
return Some(Event::Toggle);
}
// Display zone name on entry
const FADE_IN: f32 = 0.5;
const FADE_HOLD: f32 = 1.0;
const FADE_OUT: f32 = 3.0;
2019-11-24 16:45:13 +00:00
match self.client.current_chunk() {
Some(chunk) => {
let current = chunk.meta().name();
// Check if no other popup is displayed and a new one is needed
if state.last_update.elapsed()
> Duration::from_secs_f32(FADE_IN + FADE_HOLD + FADE_OUT)
&& state
.last_region_name
.as_ref()
.map(|l| l != current)
.unwrap_or(true)
{
// Update last_region
state.update(|s| s.last_region_name = Some(current.to_owned()));
state.update(|s| s.last_update = Instant::now());
}
2019-11-24 16:45:13 +00:00
let seconds = state.last_update.elapsed().as_secs_f32();
let fade = if seconds < FADE_IN {
seconds / FADE_IN
} else if seconds < FADE_IN + FADE_HOLD {
1.0
} else {
(1.0 - (seconds - FADE_IN - FADE_HOLD) / FADE_OUT).max(0.0)
};
// Region Name
Text::new(state.last_region_name.as_ref().unwrap_or(&"".to_owned()))
.mid_top_with_margin_on(ui.window, 200.0)
.font_size(70)
.font_id(self.fonts.alkhemi)
.color(Color::Rgba(0.0, 0.0, 0.0, fade))
.set(state.ids.zone_display_bg, ui);
Text::new(state.last_region_name.as_ref().unwrap_or(&"".to_owned()))
.top_left_with_margins_on(state.ids.zone_display_bg, -2.5, -2.5)
.font_size(70)
.font_id(self.fonts.alkhemi)
.color(Color::Rgba(1.0, 1.0, 1.0, fade))
.set(state.ids.zone_display, ui);
}
2019-11-24 16:45:13 +00:00
None => Text::new(" ")
.middle_of(ui.window)
.font_size(14)
.color(HP_COLOR)
.set(state.ids.zone_display, ui),
}
// TODO: Subregion name display
// Title
2019-06-19 14:55:26 +00:00
match self.client.current_chunk() {
Some(chunk) => Text::new(chunk.meta().name())
.mid_top_with_margin_on(
state.ids.mmap_frame,
if self.show.mini_map { 6.0 } else { 0.0 },
)
.font_size(if self.show.mini_map { 30 } else { 18 })
2019-10-05 21:51:08 +00:00
.font_id(self.fonts.cyri)
2019-06-19 14:55:26 +00:00
.color(TEXT_COLOR)
.set(state.ids.mmap_location, ui),
2019-06-22 14:30:53 +00:00
None => Text::new(" ")
2019-10-04 18:27:12 +00:00
.mid_top_with_margin_on(state.ids.mmap_frame, 0.0)
.font_size(18)
2019-06-19 14:55:26 +00:00
.color(TEXT_COLOR)
.set(state.ids.mmap_location, ui),
}
None
}
}