Merge branch 'imbris/fix-4' into 'master'

Actually fix ui offset bug and fix issues where going back to the menus from ingame didn't propagate window size and language changes.

See merge request 
This commit is contained in:
Imbris 2020-11-13 06:14:42 +00:00
commit d8721e8dc5
10 changed files with 151 additions and 68 deletions
voxygen/src

@ -57,9 +57,16 @@ impl CharSelectionState {
}
impl PlayState for CharSelectionState {
fn enter(&mut self, _: &mut GlobalState, _: Direction) {
fn enter(&mut self, global_state: &mut GlobalState, _: Direction) {
// Load the player's character list
self.client.borrow_mut().load_character_list();
// Updated localization in case the selected language was changed
let localized_strings = crate::i18n::Localization::load_expect(
&crate::i18n::i18n_asset_key(&global_state.settings.language.selected_language),
);
self.char_selection_ui
.update_language(std::sync::Arc::clone(&localized_strings));
}
fn tick(&mut self, global_state: &mut GlobalState, events: Vec<WinEvent>) -> PlayStateResult {

@ -1406,10 +1406,20 @@ impl CharSelectionUi {
window::Event::MouseButton(_, window::PressState::Pressed) => {
!self.controls.mouse_detector.mouse_over()
},
window::Event::ScaleFactorChanged(s) => {
self.ui.scale_factor_changed(s);
false
},
_ => false,
}
}
pub fn update_language(&mut self, i18n: std::sync::Arc<Localization>) {
self.controls.i18n = i18n;
self.controls.fonts = Fonts::load(&self.controls.i18n.fonts, &mut self.ui)
.expect("Impossible to load fonts!");
}
// TODO: do we need whole client here or just character list?
pub fn maintain(&mut self, global_state: &mut GlobalState, client: &mut Client) -> Vec<Event> {
let mut events = Vec::new();

@ -46,8 +46,18 @@ impl PlayState for MainMenuState {
{
global_state.singleplayer = None;
}
// Updated localization in case the selected language was changed
let localized_strings = crate::i18n::Localization::load_expect(
&crate::i18n::i18n_asset_key(&global_state.settings.language.selected_language),
);
self.main_menu_ui.update_language(
std::sync::Arc::clone(&localized_strings),
&global_state.settings,
);
}
#[allow(clippy::single_match)] // TODO: remove when event match has multiple arms
fn tick(&mut self, global_state: &mut GlobalState, events: Vec<Event>) -> PlayStateResult {
span!(_guard, "tick", "<MainMenuState as PlayState>::tick");
let mut localized_strings = crate::i18n::Localization::load_expect(
@ -84,12 +94,13 @@ impl PlayState for MainMenuState {
// Handle window events.
for event in events {
// Pass all events to the ui first.
if self.main_menu_ui.handle_event(event.clone()) {
continue;
}
match event {
Event::Close => return PlayStateResult::Shutdown,
// Pass events to ui.
Event::IcedUi(event) => {
self.main_menu_ui.handle_event(event);
},
// Ignore all other events.
_ => {},
}
@ -258,8 +269,10 @@ impl PlayState for MainMenuState {
&global_state.settings.language.selected_language,
));
localized_strings.log_missing_entries();
self.main_menu_ui
.update_language(std::sync::Arc::clone(&localized_strings));
self.main_menu_ui.update_language(
std::sync::Arc::clone(&localized_strings),
&global_state.settings,
);
},
#[cfg(feature = "singleplayer")]
MainMenuEvent::StartSingleplayer => {

@ -14,7 +14,7 @@ use crate::{
img_ids::{ImageGraphic, VoxelGraphic},
Graphic,
},
GlobalState,
window, GlobalState,
};
use iced::{text_input, Column, Container, HorizontalAlignment, Length, Row, Space};
//ImageFrame, Tooltip,
@ -363,7 +363,6 @@ impl Controls {
},
Message::Username(new_value) => self.login_info.username = new_value,
Message::LanguageChanged(new_value) => {
self.selected_language_index = Some(new_value);
events.push(Event::ChangeLanguage(language_metadatas.remove(new_value)));
},
Message::OpenLanguageMenu => self.is_selecting_language = !self.is_selecting_language,
@ -522,10 +521,14 @@ impl<'a> MainMenuUi {
Self { ui, controls }
}
pub fn update_language(&mut self, i18n: std::sync::Arc<Localization>) {
pub fn update_language(&mut self, i18n: std::sync::Arc<Localization>, settings: &Settings) {
self.controls.i18n = i18n;
self.controls.fonts = Fonts::load(&self.controls.i18n.fonts, &mut self.ui)
.expect("Impossible to load fonts!");
let language_metadatas = crate::i18n::list_localizations();
self.controls.selected_language_index = language_metadatas
.iter()
.position(|f| f.language_identifier == settings.language.selected_language);
}
pub fn auth_trust_prompt(&mut self, auth_server: String) {
@ -538,7 +541,22 @@ impl<'a> MainMenuUi {
pub fn cancel_connection(&mut self) { self.controls.exit_connect_screen(); }
pub fn handle_event(&mut self, event: ui::ice::Event) {
pub fn handle_event(&mut self, event: window::Event) -> bool {
match event {
// Pass events to ui.
window::Event::IcedUi(event) => {
self.handle_ui_event(event);
true
},
window::Event::ScaleFactorChanged(s) => {
self.ui.scale_factor_changed(s);
false
},
_ => false,
}
}
pub fn handle_ui_event(&mut self, event: ui::ice::Event) {
// Tab for input fields
use iced::keyboard;
if matches!(

@ -601,6 +601,8 @@ impl Renderer {
}
/// Get the resolution of the render target.
/// Note: the change after a resize can be delayed so
/// don't rely on this value being constant between resize events
pub fn get_resolution(&self) -> Vec2<u16> {
Vec2::new(
self.win_color_view.get_dimensions().0,

@ -30,8 +30,7 @@ pub struct IcedUi {
cursor_position: Vec2<f32>,
// Scaling of the ui
scale: Scale,
window_resized: Option<Vec2<u32>>,
scale_mode_changed: bool,
scale_changed: bool,
}
impl IcedUi {
pub fn new(
@ -42,19 +41,24 @@ impl IcedUi {
let scale = Scale::new(window, scale_mode, 1.2);
let renderer = window.renderer_mut();
let scaled_dims = scale.scaled_window_size().map(|e| e as f32);
let scaled_resolution = scale.scaled_resolution().map(|e| e as f32);
let physical_resolution = scale.physical_resolution();
// TODO: examine how much mem fonts take up and reduce clones if significant
Ok(Self {
renderer: IcedRenderer::new(renderer, scaled_dims, default_font)?,
renderer: IcedRenderer::new(
renderer,
scaled_resolution,
physical_resolution,
default_font,
)?,
cache: Some(Cache::new()),
events: Vec::new(),
// TODO: handle None
clipboard: Clipboard::new(window.window()).unwrap(),
cursor_position: Vec2::zero(),
scale,
window_resized: None,
scale_mode_changed: false,
scale_changed: false,
})
}
@ -75,7 +79,13 @@ impl IcedUi {
pub fn set_scaling_mode(&mut self, mode: ScaleMode) {
self.scale.set_scaling_mode(mode);
// Signal that change needs to be handled
self.scale_mode_changed = true;
self.scale_changed = true;
}
/// Dpi factor changed
/// Not to be confused with scaling mode
pub fn scale_factor_changed(&mut self, scale_factor: f64) {
self.scale_changed |= self.scale.scale_factor_changed(scale_factor);
}
pub fn handle_event(&mut self, event: Event) {
@ -86,7 +96,10 @@ impl IcedUi {
// ideally these values should be the logical ones
Event::Window(window::Event::Resized { width, height }) => {
if width != 0 && height != 0 {
self.window_resized = Some(Vec2::new(width, height));
let new_dims = Vec2::new(width, height);
// TODO maybe use u32 in Scale to be consistent with iced
// Avoid resetting cache if window size didn't change
self.scale_changed |= self.scale.window_resized(new_dims.map(|e| e as f64));
}
},
// Scale cursor movement events
@ -133,32 +146,22 @@ impl IcedUi {
renderer: &mut Renderer,
) -> (Vec<M>, mouse::Interaction) {
span!(_guard, "maintain", "IcedUi::maintain");
// Handle window resizing and scale mode changing
let scaled_dims = if let Some(new_dims) = self.window_resized.take() {
// TODO maybe use u32 in Scale to be consistent with iced
self.scale
.window_resized(new_dims.map(|e| e as f64), renderer)
// Avoid resetting cache if window size didn't change
.then(|| self.scale.scaled_window_size())
} else if self.scale_mode_changed {
Some(self.scale.scaled_window_size())
} else {
None
};
if let Some(scaled_dims) = scaled_dims {
self.scale_mode_changed = false;
// Handle window resizing, dpi factor change, and scale mode changing
if self.scale_changed {
self.scale_changed = false;
let scaled_resolution = self.scale.scaled_resolution().map(|e| e as f32);
self.events
.push(Event::Window(iced::window::Event::Resized {
width: scaled_dims.x as u32,
height: scaled_dims.y as u32,
width: scaled_resolution.x as u32,
height: scaled_resolution.y as u32,
}));
// Avoid panic in graphic cache when minimizing.
// Somewhat inefficient for elements that won't change size after a window
// resize
let res = renderer.get_resolution();
if res.x > 0 && res.y > 0 {
let physical_resolution = self.scale.physical_resolution();
if physical_resolution.map(|e| e > 0).reduce_and() {
self.renderer
.resize(scaled_dims.map(|e| e as f32), renderer);
.resize(scaled_resolution, physical_resolution, renderer);
}
}
@ -168,7 +171,7 @@ impl IcedUi {
};
// TODO: convert to f32 at source
let window_size = self.scale.scaled_window_size().map(|e| e as f32);
let window_size = self.scale.scaled_resolution().map(|e| e as f32);
span!(guard, "build user_interface");
let mut user_interface = UserInterface::build(

@ -117,11 +117,12 @@ pub struct IcedRenderer {
impl IcedRenderer {
pub fn new(
renderer: &mut Renderer,
scaled_dims: Vec2<f32>,
scaled_resolution: Vec2<f32>,
physical_resolution: Vec2<u16>,
default_font: Font,
) -> Result<Self, Error> {
let (half_res, align, p_scale) =
Self::calculate_resolution_dependents(renderer.get_resolution(), scaled_dims);
Self::calculate_resolution_dependents(physical_resolution, scaled_resolution);
Ok(Self {
cache: Cache::new(renderer, default_font)?,
@ -137,8 +138,8 @@ impl IcedRenderer {
half_res,
align,
p_scale,
win_dims: scaled_dims,
window_scissor: default_scissor(renderer),
win_dims: scaled_resolution,
window_scissor: default_scissor(physical_resolution),
start: 0,
})
}
@ -162,11 +163,16 @@ impl IcedRenderer {
.unwrap()
}
pub fn resize(&mut self, scaled_dims: Vec2<f32>, renderer: &mut Renderer) {
self.win_dims = scaled_dims;
self.window_scissor = default_scissor(renderer);
pub fn resize(
&mut self,
scaled_resolution: Vec2<f32>,
physical_resolution: Vec2<u16>,
renderer: &mut Renderer,
) {
self.win_dims = scaled_resolution;
self.window_scissor = default_scissor(physical_resolution);
self.update_resolution_dependents(renderer.get_resolution());
self.update_resolution_dependents(physical_resolution);
// Resize graphic cache
self.cache.resize_graphic_cache(renderer);
@ -194,7 +200,7 @@ impl IcedRenderer {
// Draw glyph cache (use for debugging).
/*self.draw_commands
.push(DrawCommand::Scissor(default_scissor(renderer)));
.push(DrawCommand::Scissor(self.window_scissor));
self.start = self.mesh.vertices().len();
self.mesh.push_quad(create_ui_quad(
Aabr {
@ -758,7 +764,7 @@ impl IcedRenderer {
pub fn render(&self, renderer: &mut Renderer, maybe_globals: Option<&Consts<Globals>>) {
span!(_guard, "render", "IcedRenderer::render");
let mut scissor = default_scissor(renderer);
let mut scissor = self.window_scissor;
let globals = maybe_globals.unwrap_or(&self.default_globals);
let mut locals = &self.interface_locals;
for draw_command in self.draw_commands.iter() {
@ -793,8 +799,8 @@ fn align(res: Vec2<u16>) -> Vec2<f32> {
res.map(|e| (e & 1) as f32 * 0.5)
}
fn default_scissor(renderer: &Renderer) -> Aabr<u16> {
let (screen_w, screen_h) = renderer.get_resolution().map(|e| e as u16).into_tuple();
fn default_scissor(physical_resolution: Vec2<u16>) -> Aabr<u16> {
let (screen_w, screen_h) = physical_resolution.into_tuple();
Aabr {
min: Vec2 { x: 0, y: 0 },
max: Vec2 {

@ -126,7 +126,7 @@ pub struct Ui {
impl Ui {
pub fn new(window: &mut Window) -> Result<Self, Error> {
let scale = Scale::new(window, ScaleMode::Absolute(1.0), 1.0);
let win_dims = scale.scaled_window_size().into_array();
let win_dims = scale.scaled_resolution().into_array();
let renderer = window.renderer_mut();
@ -165,7 +165,7 @@ impl Ui {
// To clear the cache (it won't be resized in this case)
self.need_cache_resize = true;
// Give conrod the new size.
let (w, h) = self.scale.scaled_window_size().into_tuple();
let (w, h) = self.scale.scaled_resolution().into_tuple();
self.ui.handle_event(Input::Resize(w, h));
}
@ -286,9 +286,9 @@ impl Ui {
// Handle window resizing.
if let Some(new_dims) = self.window_resized.take() {
let (old_w, old_h) = self.scale.scaled_window_size().into_tuple();
self.scale.window_resized(new_dims, renderer);
let (w, h) = self.scale.scaled_window_size().into_tuple();
let (old_w, old_h) = self.scale.scaled_resolution().into_tuple();
self.scale.window_resized(new_dims);
let (w, h) = self.scale.scaled_resolution().into_tuple();
self.ui.handle_event(Input::Resize(w, h));
// Avoid panic in graphic cache when minimizing.

@ -1,4 +1,4 @@
use crate::{render::Renderer, window::Window};
use crate::window::Window;
use serde::{Deserialize, Serialize};
use vek::*;
@ -31,7 +31,7 @@ pub struct Scale {
impl Scale {
pub fn new(window: &Window, mode: ScaleMode, extra_factor: f64) -> Self {
let window_dims = window.logical_size();
let scale_factor = window.renderer().get_resolution().x as f64 / window_dims.x;
let scale_factor = window.scale_factor();
Scale {
mode,
scale_factor,
@ -74,22 +74,34 @@ impl Scale {
/// Multiply by scaled coordinates to get the physical coordinates
pub fn scale_factor_physical(&self) -> f64 { self.scale_factor_logical() * self.scale_factor }
/// Updates internal window size (and/or scale_factor).
/// Returns true if either value was changed
/// Updates window size
/// Returns true if the value was changed
#[allow(clippy::float_cmp)]
pub fn window_resized(&mut self, new_dims: Vec2<f64>, renderer: &Renderer) -> bool {
let old_scale_factor = self.scale_factor;
pub fn window_resized(&mut self, new_dims: Vec2<f64>) -> bool {
let old_window_dims = self.window_dims;
self.scale_factor = renderer.get_resolution().x as f64 / new_dims.x;
self.window_dims = new_dims;
old_scale_factor != self.scale_factor || old_window_dims != self.window_dims
old_window_dims != self.window_dims
}
/// Updates scale factor
/// Returns true if the value was changed
#[allow(clippy::float_cmp)]
pub fn scale_factor_changed(&mut self, scale_factor: f64) -> bool {
let old_scale_factor = self.scale_factor;
self.scale_factor = scale_factor;
old_scale_factor != self.scale_factor
}
/// Get scaled window size.
pub fn scaled_window_size(&self) -> Vec2<f64> { self.window_dims / self.scale_factor_logical() }
pub fn scaled_resolution(&self) -> Vec2<f64> { self.window_dims / self.scale_factor_logical() }
/// Get logical window size
pub fn window_size(&self) -> Vec2<f64> { self.window_dims }
pub fn logical_resolution(&self) -> Vec2<f64> { self.window_dims }
/// Get physical window size
pub fn physical_resolution(&self) -> Vec2<u16> {
(self.window_dims * self.scale_factor).map(|e| e.round() as u16)
}
// Transform point from logical to scaled coordinates.
pub fn scale_point(&self, point: Vec2<f64>) -> Vec2<f64> { point / self.scale_factor_logical() }

@ -266,6 +266,8 @@ pub enum Event {
Close,
/// The window has been resized.
Resize(Vec2<u32>),
/// The window scale factor has been changed
ScaleFactorChanged(f64),
/// The window has been moved.
Moved(Vec2<u32>),
/// A key has been typed that corresponds to a specific character.
@ -647,8 +649,17 @@ impl Window {
pub fn fetch_events(&mut self) -> Vec<Event> {
// Refresh ui size (used when changing playstates)
if self.needs_refresh_resize {
let logical_size = self.logical_size();
self.events
.push(Event::Ui(ui::Event::new_resize(self.logical_size())));
.push(Event::Ui(ui::Event::new_resize(logical_size)));
self.events.push(Event::IcedUi(iced::Event::Window(
iced::window::Event::Resized {
width: logical_size.x as u32,
height: logical_size.y as u32,
},
)));
self.events
.push(Event::ScaleFactorChanged(self.scale_factor));
self.needs_refresh_resize = false;
}
@ -927,7 +938,8 @@ impl Window {
.push(Event::Resize(Vec2::new(width as u32, height as u32)));
},
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
self.scale_factor = scale_factor
self.scale_factor = scale_factor;
self.events.push(Event::ScaleFactorChanged(scale_factor));
},
WindowEvent::ReceivedCharacter(c) => self.events.push(Event::Char(c)),
WindowEvent::MouseInput { button, state, .. } => {