refactor: separate renderer code
This commit is contained in:
parent
fe61e12903
commit
2670e7d1da
7 changed files with 273 additions and 234 deletions
11
TODO.md
11
TODO.md
|
@ -16,13 +16,16 @@
|
|||
- [x] 2024-06-28: oauth2 with oauth2c
|
||||
- [x] 2024-06-29: generate changeset
|
||||
- [x] 2024-07-01: upload changeset
|
||||
- [ ] 2024-07-01: add success or error messages buffer
|
||||
- [ ] 2024-07-01: refacto with clippy
|
||||
- [ ] 2024-07-01: configure proxy via env variable
|
||||
- [x] 2024-07-01: add success or error messages buffer
|
||||
- [x] 2024-07-01: refacto with clippy
|
||||
- [ ] refacto renderer
|
||||
- [ ] vim-like commands sequence
|
||||
- [ ] show every singular nodes
|
||||
- [ ] create node
|
||||
- [ ] configure proxy via env variable
|
||||
- [ ] add basic CLI interface
|
||||
- oauth2 status command
|
||||
- [ ] show icons on POI
|
||||
- [ ] vim-like commands sequence
|
||||
- [ ] vim-like text manual command bottom.
|
||||
- `:Goto <coords>`
|
||||
- `:Info`
|
||||
|
|
196
src/main.rs
196
src/main.rs
|
@ -13,25 +13,24 @@ use std::{collections::{HashMap, HashSet}, fs, process, sync::{Arc, Mutex}, thre
|
|||
|
||||
use anyhow::{Context, Result, anyhow};
|
||||
|
||||
use data::{bbox_center, session::{read_session, write_session, Session}, IndexedData};
|
||||
use data::{session::{read_session, write_session, Session}, IndexedData};
|
||||
use fully_pub::fully_pub;
|
||||
use layers::{load_osm_data, load_osm_zone, load_static_cities_layer, Layer, LayerKind};
|
||||
use osm_api::OSMApiClient;
|
||||
use raylib::prelude::*;
|
||||
use ui::{edit_tags, inputs::{collect_actions_from_inputs, UiAction}, messages::{render_messages, UiMessage, UiMessageLevel}, selection::get_objects_in_area};
|
||||
use utils::{deg2num, get_envelope_from_bounds};
|
||||
use ui::{edit_tags, inputs::{collect_actions_from_inputs, UiAction}, messages::{UiMessage, UiMessageLevel}, renderer::render_app, selection::get_objects_in_area};
|
||||
use utils::deg2num;
|
||||
use xdg::BaseDirectories;
|
||||
use std::io::Read;
|
||||
use serde::{Deserialize};
|
||||
use serde::Deserialize;
|
||||
use ureq::Agent;
|
||||
use rand::Rng;
|
||||
use crate::utils::CanvasPos;
|
||||
use crate::utils::Invertion;
|
||||
use crate::utils::ToSlice;
|
||||
|
||||
pub const USER_AGENT: &str = "BobOSM dev";
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
struct Camera {
|
||||
bounds: (Vector2, Vector2),
|
||||
center: Vector2,
|
||||
|
@ -41,6 +40,14 @@ struct Camera {
|
|||
canvas_to_real_factor: f32
|
||||
}
|
||||
|
||||
#[fully_pub]
|
||||
struct AppContext {
|
||||
/// snapshot of camera state
|
||||
camera: Camera,
|
||||
state: Arc<Mutex<AppState>>,
|
||||
layers: Arc<Mutex<Vec<Layer>>>
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
#[fully_pub]
|
||||
enum UiMode {
|
||||
|
@ -270,7 +277,6 @@ fn main() -> Result<()> {
|
|||
UiAction::NavigatePan(move_v) => {
|
||||
camera.bounds.0 += move_v;
|
||||
camera.bounds.1 += move_v;
|
||||
|
||||
},
|
||||
UiAction::NavigateZoom { focus, factor } => {
|
||||
camera.bounds.0 = focus + (camera.bounds.0 - focus).scale_by(factor);
|
||||
|
@ -347,177 +353,11 @@ fn main() -> Result<()> {
|
|||
camera.zoom = 1.0/(camera.bounds.0.x - camera.bounds.1.x).abs();
|
||||
camera.map_zoom = 4.680_851*camera.zoom;
|
||||
|
||||
let mut d = rl.begin_drawing(&thread);
|
||||
// d.draw_texture(&static_t, 0, 0, Color::WHITE);
|
||||
|
||||
d.clear_background(Color::BLACK);
|
||||
// if let Some(texture) = tmp_texture {
|
||||
// println!("{:?}", &texture);
|
||||
// println!("center_canvas_pos {:?}", center_canvas_pos);
|
||||
// d.draw_texture(texture, center_canvas_pos.x.ceil() as i32, center_canvas_pos.y.ceil() as i32, Color::WHITE);
|
||||
// }
|
||||
|
||||
// Repère A: Canvas
|
||||
// Repère B: Virtual canvas
|
||||
// draw raster tiles
|
||||
|
||||
// render layers
|
||||
let current_bounds_aabb = get_envelope_from_bounds(camera.bounds, 0.30);
|
||||
{ // layers
|
||||
let app_state_ref = app_state.lock().unwrap();
|
||||
for (layer_i, layer) in layers.lock().unwrap().iter().enumerate() {
|
||||
// Draw ways
|
||||
if let Some(tree) = &layer.ways_tree {
|
||||
for way in tree.locate_in_envelope_intersecting(¤t_bounds_aabb) {
|
||||
let mut last_p: Option<Vector2> = None;
|
||||
for p in &way.positions {
|
||||
if let Some(last_p_v) = last_p {
|
||||
d.draw_line_ex(
|
||||
last_p_v.to_canvas_pos(&camera),
|
||||
p.to_canvas_pos(&camera),
|
||||
1.0,
|
||||
Color::BLUE
|
||||
)
|
||||
}
|
||||
last_p = Some(*p);
|
||||
}
|
||||
let bbox_center_canvas = bbox_center(way.bbox).to_canvas_pos(&camera);
|
||||
// draw name in center of polygon
|
||||
if !way.name.is_empty() && (
|
||||
(camera.zoom <= 0.9 && way.importance >= 10) ||
|
||||
(camera.zoom >= 1.0 && way.importance >= 9) ||
|
||||
camera.zoom >= 1.2
|
||||
)
|
||||
{
|
||||
d.draw_text(
|
||||
&way.name.to_string(),
|
||||
bbox_center_canvas.x.ceil() as i32 - ((way.name.len()/2)*6) as i32,
|
||||
bbox_center_canvas.y.ceil() as i32 - 5,
|
||||
12,
|
||||
Color::WHITE
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw POI points of interest
|
||||
if let Some(tree) = &layer.pois_tree {
|
||||
for point in tree.locate_in_envelope(¤t_bounds_aabb) {
|
||||
let canvas_pos = point.pos.to_canvas_pos(&camera);
|
||||
let size = 2.0*(((1.)/(1.+ (-(0.4 * camera.zoom - 4.)).exp() )) + 0.2);
|
||||
|
||||
// check if object is selected.
|
||||
let is_selected: bool =
|
||||
if let Some(selected_elements) = app_state_ref.selected_elements_per_layer.get(layer_i) {
|
||||
selected_elements.iter().any(|e_id| *e_id == point.id)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let line_thickness: f32 =
|
||||
(match point.importance {
|
||||
10 => 5.,
|
||||
9 => 3.,
|
||||
_ => 3.0
|
||||
}) +
|
||||
(if is_selected { 4.0 } else { 0. });
|
||||
|
||||
let color = if is_selected {
|
||||
Color::YELLOW
|
||||
} else {
|
||||
match point.importance {
|
||||
10 => Color::GREEN,
|
||||
9 => Color::RED,
|
||||
3 => Color::PURPLE,
|
||||
_ => Color::new(255, 255, 255, 100)
|
||||
}
|
||||
};
|
||||
|
||||
d.draw_poly_lines_ex(
|
||||
canvas_pos,
|
||||
5,
|
||||
match point.importance {
|
||||
10 => size*19.,
|
||||
9 => size*8.,
|
||||
_ => size*3.0
|
||||
},
|
||||
0.,
|
||||
line_thickness,
|
||||
color
|
||||
);
|
||||
|
||||
if
|
||||
(camera.zoom <= 0.9 && point.importance >= 10) ||
|
||||
(camera.zoom >= 1.0 && point.importance >= 9) ||
|
||||
camera.zoom >= 1.2
|
||||
{
|
||||
d.draw_text(
|
||||
&point.name.to_string(),
|
||||
canvas_pos.x.ceil() as i32 + 8,
|
||||
canvas_pos.y.ceil() as i32,
|
||||
match point.importance {
|
||||
10 => 17,
|
||||
9 => 14,
|
||||
_ => 12
|
||||
},
|
||||
Color::WHITE
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
d.draw_circle_sector_lines(mouse_pos, 10.0, 0.0, 360.0, 1, Color::MAGENTA);
|
||||
|
||||
{
|
||||
// draw meta/debug info
|
||||
let app_state_ref = app_state.lock().unwrap();
|
||||
d.draw_text(&format!("Zoom: {:?}, Bounds: {:?}", camera.zoom, camera.bounds), 13, 12, 15, Color::WHITE);
|
||||
d.draw_text(&format!("Mouse: {:?}", real_mouse_pos), 13, 30, 15, Color::WHITE);
|
||||
d.draw_text(&format!("Center: {:?}", camera.center), 13, 45, 15, Color::WHITE);
|
||||
|
||||
// draw app mode
|
||||
d.draw_text(
|
||||
&format!("M: {}",
|
||||
match app_state_ref.ui_mode {
|
||||
UiMode::View => "View",
|
||||
UiMode::Edit => "Edit"
|
||||
})
|
||||
,
|
||||
12, screen_def.1 - 50,
|
||||
15,
|
||||
Color::WHITE
|
||||
);
|
||||
// draw loading indicator
|
||||
if app_state_ref.loading {
|
||||
// TODO: add a sprite
|
||||
d.draw_circle_v(
|
||||
Vector2::new(20., (screen_def.1-20) as f32),
|
||||
10.0,
|
||||
Color::WHITE
|
||||
)
|
||||
}
|
||||
|
||||
// draw UI messages and alerts
|
||||
render_messages(
|
||||
&app_state_ref.messages,
|
||||
&mut d,
|
||||
&screen_def
|
||||
)
|
||||
}
|
||||
|
||||
// draw target cross (center fixed cursor)
|
||||
let cross_width = 6;
|
||||
d.draw_line_v(
|
||||
Vector2::new(((screen_def.0/2) - cross_width) as f32, (screen_def.1/2) as f32),
|
||||
Vector2::new(((screen_def.0/2) + cross_width) as f32, (screen_def.1/2) as f32),
|
||||
Color::WHITE
|
||||
);
|
||||
d.draw_line_v(
|
||||
Vector2::new((screen_def.0/2) as f32, ((screen_def.1/2) - cross_width) as f32),
|
||||
Vector2::new((screen_def.0/2) as f32, ((screen_def.1/2) + cross_width) as f32),
|
||||
Color::WHITE
|
||||
);
|
||||
render_app(&mut rl, &thread, AppContext {
|
||||
state: app_state.clone(),
|
||||
layers: layers.clone(),
|
||||
camera: camera.clone()
|
||||
})
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -32,6 +32,19 @@ enum UiAction {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_real_mouse_pos(
|
||||
rl: &RaylibHandle,
|
||||
camera: &Camera
|
||||
) -> Vector2
|
||||
{
|
||||
let mouse_pos = rl.get_mouse_position();
|
||||
let top_left_bound = Vector2::new(camera.bounds.0.x, camera.bounds.1.y);
|
||||
top_left_bound +
|
||||
mouse_pos
|
||||
.invert_for_canvas()
|
||||
.scale_by(camera.canvas_to_real_factor)
|
||||
}
|
||||
|
||||
/// entry point to handle UI inputs
|
||||
pub fn collect_actions_from_inputs(
|
||||
rl: &mut RaylibHandle,
|
||||
|
@ -101,12 +114,7 @@ pub fn collect_actions_from_inputs(
|
|||
actions.push(UiAction::NavigatePan(move_v));
|
||||
}
|
||||
|
||||
let mouse_pos = rl.get_mouse_position();
|
||||
let top_left_bound = Vector2::new(camera.bounds.0.x, camera.bounds.1.y);
|
||||
let real_mouse_pos = top_left_bound +
|
||||
mouse_pos
|
||||
.invert_for_canvas()
|
||||
.scale_by(camera.canvas_to_real_factor);
|
||||
let real_mouse_pos = get_real_mouse_pos(rl, &camera);
|
||||
let wheel_move = rl.get_mouse_wheel_move();
|
||||
if wheel_move.abs() > 0.0 {
|
||||
actions.push(UiAction::NavigateZoom {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use fully_pub::fully_pub;
|
||||
use raylib::{color::Color, drawing::{RaylibDraw, RaylibDrawHandle}, math::Vector2};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[fully_pub]
|
||||
|
@ -48,7 +47,7 @@ impl UiMessage {
|
|||
UiMessage::new(UiMessageLevel::Error, text)
|
||||
}
|
||||
|
||||
fn is_dead(&self) -> bool {
|
||||
pub fn is_dead(&self) -> bool {
|
||||
let current_epoch = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Time went backwards")
|
||||
|
@ -57,43 +56,3 @@ impl UiMessage {
|
|||
(current_epoch - self.created_at) > self.ttl
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_messages(
|
||||
messages: &Vec<UiMessage>,
|
||||
draw_handle: &mut RaylibDrawHandle,
|
||||
screen_def: &(i32, i32)
|
||||
) -> () {
|
||||
let mut vertical_offset: i32 = 0;
|
||||
for message in messages.iter().rev() {
|
||||
if message.is_dead() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let text: &str = &message.text.to_string();
|
||||
|
||||
let padding = Vector2::new(10., 5.);
|
||||
let pos: Vector2 = Vector2::new(
|
||||
((screen_def.0/2) - 200) as f32,
|
||||
(screen_def.1) as f32,
|
||||
) + padding - Vector2::new(0., 40.0 + vertical_offset as f32);
|
||||
|
||||
draw_handle.draw_rectangle_v(
|
||||
pos-padding,
|
||||
Vector2::new(600.0 + 2.0*padding.x, 14.0 + 2.0*padding.y),
|
||||
Color::WHITE
|
||||
);
|
||||
draw_handle.draw_text(
|
||||
text,
|
||||
pos.x as i32,
|
||||
pos.y as i32,
|
||||
16,
|
||||
match message.level {
|
||||
UiMessageLevel::Success => Color::GREEN,
|
||||
UiMessageLevel::Warning => Color::ORANGE,
|
||||
UiMessageLevel::Error => Color::RED,
|
||||
_ => Color::GRAY
|
||||
}
|
||||
);
|
||||
vertical_offset += 30;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
/// takes the pre-processed data to be rendered and turn it into vectors instructions sent to raylib
|
||||
fn map_render() {
|
||||
|
||||
}
|
43
src/ui/renderer/messages.rs
Normal file
43
src/ui/renderer/messages.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
use raylib::{color::Color, drawing::{RaylibDraw, RaylibDrawHandle}, math::Vector2};
|
||||
|
||||
use crate::ui::messages::{UiMessage, UiMessageLevel};
|
||||
|
||||
pub fn render_messages(
|
||||
messages: &Vec<UiMessage>,
|
||||
draw_handle: &mut RaylibDrawHandle,
|
||||
screen_def: &(i32, i32)
|
||||
) -> () {
|
||||
let mut vertical_offset: i32 = 0;
|
||||
for message in messages.iter().rev() {
|
||||
if message.is_dead() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let text: &str = &message.text.to_string();
|
||||
|
||||
let padding = Vector2::new(10., 5.);
|
||||
let pos: Vector2 = Vector2::new(
|
||||
((screen_def.0/2) - 200) as f32,
|
||||
(screen_def.1) as f32,
|
||||
) + padding - Vector2::new(0., 40.0 + vertical_offset as f32);
|
||||
|
||||
draw_handle.draw_rectangle_v(
|
||||
pos-padding,
|
||||
Vector2::new(600.0 + 2.0*padding.x, 14.0 + 2.0*padding.y),
|
||||
Color::WHITE
|
||||
);
|
||||
draw_handle.draw_text(
|
||||
text,
|
||||
pos.x as i32,
|
||||
pos.y as i32,
|
||||
16,
|
||||
match message.level {
|
||||
UiMessageLevel::Success => Color::GREEN,
|
||||
UiMessageLevel::Warning => Color::ORANGE,
|
||||
UiMessageLevel::Error => Color::RED,
|
||||
_ => Color::GRAY
|
||||
}
|
||||
);
|
||||
vertical_offset += 30;
|
||||
}
|
||||
}
|
190
src/ui/renderer/mod.rs
Normal file
190
src/ui/renderer/mod.rs
Normal file
|
@ -0,0 +1,190 @@
|
|||
mod messages;
|
||||
|
||||
use messages::render_messages;
|
||||
use raylib::{color::Color, drawing::RaylibDraw, math::Vector2, RaylibHandle, RaylibThread};
|
||||
|
||||
use crate::{data::bbox_center, utils::{get_envelope_from_bounds, CanvasPos}, AppContext, UiMode};
|
||||
|
||||
use super::inputs::get_real_mouse_pos;
|
||||
|
||||
/// render entry point
|
||||
/// takes the pre-processed data to be rendered and turn it into vectors instructions sent to raylib
|
||||
pub fn render_app(
|
||||
rl: &mut RaylibHandle,
|
||||
thread: &RaylibThread,
|
||||
context: AppContext
|
||||
) {
|
||||
let camera = context.camera;
|
||||
let screen_def = (rl.get_screen_width(), rl.get_screen_height());
|
||||
let mouse_pos = rl.get_mouse_position();
|
||||
let real_mouse_pos = get_real_mouse_pos(&rl, &camera);
|
||||
|
||||
let mut d = rl.begin_drawing(&thread);
|
||||
// d.draw_texture(&static_t, 0, 0, Color::WHITE);
|
||||
|
||||
d.clear_background(Color::BLACK);
|
||||
// if let Some(texture) = tmp_texture {
|
||||
// println!("{:?}", &texture);
|
||||
// println!("center_canvas_pos {:?}", center_canvas_pos);
|
||||
// d.draw_texture(texture, center_canvas_pos.x.ceil() as i32, center_canvas_pos.y.ceil() as i32, Color::WHITE);
|
||||
// }
|
||||
|
||||
// render layers
|
||||
let current_bounds_aabb = get_envelope_from_bounds(camera.bounds, 0.30);
|
||||
{ // layers
|
||||
let app_state_ref = context.state.lock().unwrap();
|
||||
for (layer_i, layer) in context.layers.lock().unwrap().iter().enumerate() {
|
||||
// Draw ways
|
||||
if let Some(tree) = &layer.ways_tree {
|
||||
for way in tree.locate_in_envelope_intersecting(¤t_bounds_aabb) {
|
||||
let mut last_p: Option<Vector2> = None;
|
||||
for p in &way.positions {
|
||||
if let Some(last_p_v) = last_p {
|
||||
d.draw_line_ex(
|
||||
last_p_v.to_canvas_pos(&camera),
|
||||
p.to_canvas_pos(&camera),
|
||||
1.0,
|
||||
Color::BLUE
|
||||
)
|
||||
}
|
||||
last_p = Some(*p);
|
||||
}
|
||||
let bbox_center_canvas = bbox_center(way.bbox).to_canvas_pos(&camera);
|
||||
// draw name in center of polygon
|
||||
if !way.name.is_empty() && (
|
||||
(camera.zoom <= 0.9 && way.importance >= 10) ||
|
||||
(camera.zoom >= 1.0 && way.importance >= 9) ||
|
||||
camera.zoom >= 1.2
|
||||
)
|
||||
{
|
||||
d.draw_text(
|
||||
&way.name.to_string(),
|
||||
bbox_center_canvas.x.ceil() as i32 - ((way.name.len()/2)*6) as i32,
|
||||
bbox_center_canvas.y.ceil() as i32 - 5,
|
||||
12,
|
||||
Color::WHITE
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw POI points of interest
|
||||
if let Some(tree) = &layer.pois_tree {
|
||||
for point in tree.locate_in_envelope(¤t_bounds_aabb) {
|
||||
let canvas_pos = point.pos.to_canvas_pos(&camera);
|
||||
let size = 2.0*(((1.)/(1.+ (-(0.4 * camera.zoom - 4.)).exp() )) + 0.2);
|
||||
|
||||
// check if object is selected.
|
||||
let is_selected: bool =
|
||||
if let Some(selected_elements) = app_state_ref.selected_elements_per_layer.get(layer_i) {
|
||||
selected_elements.iter().any(|e_id| *e_id == point.id)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let line_thickness: f32 =
|
||||
(match point.importance {
|
||||
10 => 5.,
|
||||
9 => 3.,
|
||||
_ => 3.0
|
||||
}) +
|
||||
(if is_selected { 4.0 } else { 0. });
|
||||
|
||||
let color = if is_selected {
|
||||
Color::YELLOW
|
||||
} else {
|
||||
match point.importance {
|
||||
10 => Color::GREEN,
|
||||
9 => Color::RED,
|
||||
3 => Color::PURPLE,
|
||||
_ => Color::new(255, 255, 255, 100)
|
||||
}
|
||||
};
|
||||
|
||||
d.draw_poly_lines_ex(
|
||||
canvas_pos,
|
||||
5,
|
||||
match point.importance {
|
||||
10 => size*19.,
|
||||
9 => size*8.,
|
||||
_ => size*3.0
|
||||
},
|
||||
0.,
|
||||
line_thickness,
|
||||
color
|
||||
);
|
||||
|
||||
if
|
||||
(camera.zoom <= 0.9 && point.importance >= 10) ||
|
||||
(camera.zoom >= 1.0 && point.importance >= 9) ||
|
||||
camera.zoom >= 1.2
|
||||
{
|
||||
d.draw_text(
|
||||
&point.name.to_string(),
|
||||
canvas_pos.x.ceil() as i32 + 8,
|
||||
canvas_pos.y.ceil() as i32,
|
||||
match point.importance {
|
||||
10 => 17,
|
||||
9 => 14,
|
||||
_ => 12
|
||||
},
|
||||
Color::WHITE
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// draw mouse cursor
|
||||
d.draw_circle_sector_lines(mouse_pos, 10.0, 0.0, 360.0, 1, Color::MAGENTA);
|
||||
{
|
||||
// draw meta/debug info
|
||||
let app_state_ref = context.state.lock().unwrap();
|
||||
d.draw_text(&format!("Zoom: {:?}, Bounds: {:?}", camera.zoom, camera.bounds), 13, 12, 15, Color::WHITE);
|
||||
d.draw_text(&format!("Mouse: {:?}", real_mouse_pos), 13, 30, 15, Color::WHITE);
|
||||
d.draw_text(&format!("Center: {:?}", camera.center), 13, 45, 15, Color::WHITE);
|
||||
|
||||
// draw app mode
|
||||
d.draw_text(
|
||||
&format!("M: {}",
|
||||
match app_state_ref.ui_mode {
|
||||
UiMode::View => "View",
|
||||
UiMode::Edit => "Edit"
|
||||
})
|
||||
,
|
||||
12, screen_def.1 - 50,
|
||||
15,
|
||||
Color::WHITE
|
||||
);
|
||||
// draw loading indicator
|
||||
if app_state_ref.loading {
|
||||
// TODO: add a sprite
|
||||
d.draw_circle_v(
|
||||
Vector2::new(20., (screen_def.1-20) as f32),
|
||||
10.0,
|
||||
Color::WHITE
|
||||
)
|
||||
}
|
||||
|
||||
// draw UI messages and alerts
|
||||
render_messages(
|
||||
&app_state_ref.messages,
|
||||
&mut d,
|
||||
&screen_def
|
||||
)
|
||||
}
|
||||
|
||||
// draw target cross (center fixed cursor)
|
||||
let cross_width = 6;
|
||||
d.draw_line_v(
|
||||
Vector2::new(((screen_def.0/2) - cross_width) as f32, (screen_def.1/2) as f32),
|
||||
Vector2::new(((screen_def.0/2) + cross_width) as f32, (screen_def.1/2) as f32),
|
||||
Color::WHITE
|
||||
);
|
||||
d.draw_line_v(
|
||||
Vector2::new((screen_def.0/2) as f32, ((screen_def.1/2) - cross_width) as f32),
|
||||
Vector2::new((screen_def.0/2) as f32, ((screen_def.1/2) + cross_width) as f32),
|
||||
Color::WHITE
|
||||
);
|
||||
}
|
Loading…
Reference in a new issue