mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Add ability to position tuples of widgets ingame
Former-commit-id: e2958a37e7062132d6a7b6d5ad61bd4002768532
This commit is contained in:
parent
b828bffba9
commit
93ec66a8b1
@ -25,7 +25,7 @@ use small_window::{SmallWindow, SmallWindowType};
|
||||
use crate::{
|
||||
render::{Consts, Globals, Renderer},
|
||||
settings::{ControlSettings, Settings},
|
||||
ui::{Ingame, ScaleMode, Ui},
|
||||
ui::{Ingame, Ingameable, ScaleMode, Ui},
|
||||
window::{Event as WinEvent, Key, Window},
|
||||
GlobalState,
|
||||
};
|
||||
@ -287,27 +287,24 @@ impl Hud {
|
||||
})
|
||||
.enumerate()
|
||||
{
|
||||
Ingame::from_primitive(
|
||||
pos + Vec3::new(0.0, 0.0, 3.0),
|
||||
Text::new(&name)
|
||||
.font_size(15)
|
||||
.color(Color::Rgba(1.0, 1.0, 1.0, 1.0)),
|
||||
)
|
||||
.resolution(50.0)
|
||||
.set(self.ids.name_tags[i], ui_widgets);
|
||||
Text::new(&name)
|
||||
.font_size(20)
|
||||
.color(Color::Rgba(1.0, 1.0, 1.0, 1.0))
|
||||
.x_y(0.0, 0.0)
|
||||
.position_ingame(pos + Vec3::new(0.0, 0.0, 3.0))
|
||||
.resolution(100.0)
|
||||
.set(self.ids.name_tags[i], ui_widgets);
|
||||
}
|
||||
}
|
||||
// test
|
||||
Ingame::from_primitive(
|
||||
[0.0, 25.0, 25.0].into(),
|
||||
//Rectangle::fill_with([1.0, 1.0], Color::Rgba(0.2, 0.0, 0.4, 1.0)),
|
||||
Text::new("Squarefection")
|
||||
.font_size(20)
|
||||
.color(TEXT_COLOR)
|
||||
.font_id(self.fonts.opensans),
|
||||
)
|
||||
.resolution(40.0)
|
||||
.set(self.ids.temp, ui_widgets);
|
||||
Text::new("Squarefection")
|
||||
.font_size(20)
|
||||
.color(TEXT_COLOR)
|
||||
.font_id(self.fonts.opensans)
|
||||
.x_y(0.0, 0.0)
|
||||
.position_ingame([0.0, 25.0, 25.0].into())
|
||||
.resolution(40.0)
|
||||
.set(self.ids.temp, ui_widgets);
|
||||
|
||||
// Display debug window.
|
||||
if self.show.debug {
|
||||
|
@ -6,7 +6,6 @@ pub struct Event(pub Input);
|
||||
impl Event {
|
||||
pub fn try_from(event: glutin::Event, window: &glutin::GlWindow) -> Option<Self> {
|
||||
use conrod_winit::*;
|
||||
use winit;
|
||||
// A wrapper around the winit window that allows us to implement the trait necessary for
|
||||
// enabling the winit <-> conrod conversion functions.
|
||||
struct WindowRef<'a>(&'a winit::Window);
|
||||
|
@ -12,7 +12,11 @@ mod font_ids;
|
||||
pub use event::Event;
|
||||
pub use graphic::Graphic;
|
||||
pub use scale::ScaleMode;
|
||||
pub use widgets::{image_slider::ImageSlider, ingame::Ingame, toggle_button::ToggleButton};
|
||||
pub use widgets::{
|
||||
image_slider::ImageSlider,
|
||||
ingame::{Ingame, Ingameable},
|
||||
toggle_button::ToggleButton,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
render::{
|
||||
@ -294,8 +298,12 @@ impl Ui {
|
||||
// Push new position command
|
||||
self.draw_commands.push(DrawCommand::WorldPos(None));
|
||||
}
|
||||
Some((n, res)) => in_world = Some((n - 1, res)),
|
||||
None => (),
|
||||
Some((n, res)) => match kind {
|
||||
// Other types don't need to be drawn in the game
|
||||
PrimitiveKind::Other(_) => (),
|
||||
_ => in_world = Some((n - 1, res)),
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
|
||||
// Functions for converting for conrod scalar coords to GL vertex coords (-1.0 to 1.0).
|
||||
@ -500,11 +508,11 @@ impl Ui {
|
||||
PrimitiveKind::Other(container) => {
|
||||
if container.type_id == std::any::TypeId::of::<widgets::ingame::State>() {
|
||||
// Retrieve world position
|
||||
let (pos, res) = container
|
||||
let parameters = container
|
||||
.state_and_style::<widgets::ingame::State, widgets::ingame::Style>()
|
||||
.unwrap()
|
||||
.state
|
||||
.pos_res();
|
||||
.parameters;
|
||||
// Finish current state
|
||||
self.draw_commands.push(match current_state {
|
||||
State::Plain => DrawCommand::plain(start..mesh.vertices().len()),
|
||||
@ -513,10 +521,10 @@ impl Ui {
|
||||
start = mesh.vertices().len();
|
||||
// Push new position command
|
||||
self.draw_commands.push(DrawCommand::WorldPos(Some(
|
||||
renderer.create_consts(&[pos.into()]).unwrap(),
|
||||
renderer.create_consts(&[parameters.pos.into()]).unwrap(),
|
||||
)));
|
||||
|
||||
in_world = Some((1, res));
|
||||
in_world = Some((parameters.num, parameters.res));
|
||||
p_scale_factor = 1.0;
|
||||
}
|
||||
}
|
||||
|
@ -1,82 +1,232 @@
|
||||
use conrod_core::{
|
||||
builder_methods, image,
|
||||
position::Dimension,
|
||||
widget::{self, button},
|
||||
widget_ids, Color, Position, Positionable, Rect, Sizeable, Ui, Widget, WidgetCommon,
|
||||
widget::{self, button, Id},
|
||||
widget_ids, Color, Position, Positionable, Rect, Sizeable, Ui, UiCell, Widget, WidgetCommon,
|
||||
};
|
||||
use std::slice;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Clone, WidgetCommon)]
|
||||
pub struct Ingame<W>
|
||||
where
|
||||
W: Widget,
|
||||
{
|
||||
pub struct Ingame<W> {
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
widget: W,
|
||||
pos: Vec3<f32>,
|
||||
parameters: IngameParameters,
|
||||
}
|
||||
|
||||
pub trait Ingameable: Sized {
|
||||
type Event;
|
||||
fn prim_count(&self) -> usize;
|
||||
fn set_ingame(self, ids: Ids, parent_id: Id, ui: &mut UiCell) -> Self::Event;
|
||||
fn init_ids(mut id_gen: widget::id::Generator) -> Ids;
|
||||
fn position_ingame(self, pos: Vec3<f32>) -> Ingame<Self> {
|
||||
Ingame::new(pos, self)
|
||||
}
|
||||
}
|
||||
|
||||
// Note this is not responsible for the positioning
|
||||
// Only call this directly if using IngameAnchor
|
||||
pub fn set_ingame<W: Widget>(widget: W, parent_id: Id, id: Id, ui: &mut UiCell) -> W::Event {
|
||||
widget
|
||||
// should pass focus to the window if these are clicked
|
||||
// (they are not displayed where conrod thinks they are)
|
||||
.graphics_for(ui.window)
|
||||
//.parent(id) // is this needed
|
||||
.set(id, ui)
|
||||
}
|
||||
|
||||
pub trait PrimitiveMarker {}
|
||||
impl PrimitiveMarker for widget::Line {}
|
||||
impl PrimitiveMarker for widget::Image {}
|
||||
impl<I> PrimitiveMarker for widget::PointPath<I> {}
|
||||
impl PrimitiveMarker for widget::Circle {}
|
||||
impl<S> PrimitiveMarker for widget::Oval<S> {}
|
||||
impl<I> PrimitiveMarker for widget::Polygon<I> {}
|
||||
impl PrimitiveMarker for widget::Rectangle {}
|
||||
impl<S, I> PrimitiveMarker for widget::Triangles<S, I> {}
|
||||
impl<'a> PrimitiveMarker for widget::Text<'a> {}
|
||||
|
||||
impl<P> Ingameable for P
|
||||
where
|
||||
P: Widget + PrimitiveMarker,
|
||||
{
|
||||
type Event = P::Event;
|
||||
fn prim_count(&self) -> usize {
|
||||
1
|
||||
}
|
||||
fn set_ingame(self, ids: Ids, parent_id: Id, ui: &mut UiCell) -> Self::Event {
|
||||
let id = ids.one().unwrap();
|
||||
|
||||
set_ingame(self, parent_id, id, ui)
|
||||
}
|
||||
fn init_ids(mut id_gen: widget::id::Generator) -> Ids {
|
||||
Ids::One(id_gen.next())
|
||||
}
|
||||
}
|
||||
|
||||
trait IngameWidget: Ingameable + Widget {}
|
||||
impl<T> IngameWidget for T where T: Ingameable + Widget {}
|
||||
|
||||
impl<W, E> Ingameable for (W, E)
|
||||
where
|
||||
W: IngameWidget,
|
||||
E: IngameWidget,
|
||||
{
|
||||
type Event = (<W as Widget>::Event, <E as Widget>::Event);
|
||||
fn prim_count(&self) -> usize {
|
||||
self.0.prim_count() + self.1.prim_count()
|
||||
}
|
||||
fn set_ingame(self, ids: Ids, parent_id: Id, ui: &mut UiCell) -> Self::Event {
|
||||
let (w1, w2) = self;
|
||||
let [id1, id2] = ids.two().unwrap();
|
||||
(
|
||||
set_ingame(w1, parent_id, id1, ui),
|
||||
set_ingame(w2, parent_id, id2, ui),
|
||||
)
|
||||
}
|
||||
fn init_ids(mut id_gen: widget::id::Generator) -> Ids {
|
||||
Ids::Two([id_gen.next(), id_gen.next()])
|
||||
}
|
||||
}
|
||||
impl<W, E, R> Ingameable for (W, E, R)
|
||||
where
|
||||
W: IngameWidget,
|
||||
E: IngameWidget,
|
||||
R: IngameWidget,
|
||||
{
|
||||
type Event = (
|
||||
<W as Widget>::Event,
|
||||
<E as Widget>::Event,
|
||||
<R as Widget>::Event,
|
||||
);
|
||||
fn prim_count(&self) -> usize {
|
||||
self.0.prim_count() + self.1.prim_count() + self.2.prim_count()
|
||||
}
|
||||
fn set_ingame(self, ids: Ids, parent_id: Id, ui: &mut UiCell) -> Self::Event {
|
||||
let (w1, w2, w3) = self;
|
||||
let ids = ids.three().unwrap();
|
||||
(
|
||||
set_ingame(w1, parent_id, ids[0], ui),
|
||||
set_ingame(w2, parent_id, ids[1], ui),
|
||||
set_ingame(w3, parent_id, ids[2], ui),
|
||||
)
|
||||
}
|
||||
fn init_ids(mut id_gen: widget::id::Generator) -> Ids {
|
||||
Ids::Three([id_gen.next(), id_gen.next(), id_gen.next()])
|
||||
}
|
||||
}
|
||||
impl<W, E, R, T> Ingameable for (W, E, R, T)
|
||||
where
|
||||
W: IngameWidget,
|
||||
E: IngameWidget,
|
||||
R: IngameWidget,
|
||||
T: IngameWidget,
|
||||
{
|
||||
type Event = (
|
||||
<W as Widget>::Event,
|
||||
<E as Widget>::Event,
|
||||
<R as Widget>::Event,
|
||||
<T as Widget>::Event,
|
||||
);
|
||||
fn prim_count(&self) -> usize {
|
||||
self.0.prim_count() + self.1.prim_count() + self.2.prim_count() + self.3.prim_count()
|
||||
}
|
||||
fn set_ingame(self, ids: Ids, parent_id: Id, ui: &mut UiCell) -> Self::Event {
|
||||
let (w1, w2, w3, w4) = self;
|
||||
let ids = ids.four().unwrap();
|
||||
(
|
||||
set_ingame(w1, parent_id, ids[0], ui),
|
||||
set_ingame(w2, parent_id, ids[1], ui),
|
||||
set_ingame(w3, parent_id, ids[2], ui),
|
||||
set_ingame(w4, parent_id, ids[3], ui),
|
||||
)
|
||||
}
|
||||
fn init_ids(mut id_gen: widget::id::Generator) -> Ids {
|
||||
Ids::Four([id_gen.next(), id_gen.next(), id_gen.next(), id_gen.next()])
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum Ids {
|
||||
None,
|
||||
One(Id),
|
||||
Two([Id; 2]),
|
||||
Three([Id; 3]),
|
||||
Four([Id; 4]),
|
||||
}
|
||||
impl Ids {
|
||||
fn one(self) -> Option<Id> {
|
||||
match self {
|
||||
Ids::One(id) => Some(id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn two(self) -> Option<[Id; 2]> {
|
||||
match self {
|
||||
Ids::Two(ids) => Some(ids),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn three(self) -> Option<[Id; 3]> {
|
||||
match self {
|
||||
Ids::Three(ids) => Some(ids),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn four(self) -> Option<[Id; 4]> {
|
||||
match self {
|
||||
Ids::Four(ids) => Some(ids),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub struct IngameParameters {
|
||||
// Number of primitive widgets to position in the game at the specified position
|
||||
// Note this could be more than the number of widgets in the widgets field since widgets can contain widgets
|
||||
pub num: usize,
|
||||
pub pos: Vec3<f32>,
|
||||
// Number of pixels per 1 unit in world coordinates (ie a voxel)
|
||||
// Used for widgets that are rasterized before being sent to the gpu (text & images)
|
||||
// Potentially make this autmatic based on distance to camera?
|
||||
res: f32,
|
||||
}
|
||||
|
||||
// TODO: add convenience function to this trait
|
||||
pub trait Primitive {}
|
||||
impl Primitive for widget::Line {}
|
||||
impl Primitive for widget::Image {}
|
||||
impl<I> Primitive for widget::PointPath<I> {}
|
||||
impl Primitive for widget::Circle {}
|
||||
impl<S> Primitive for widget::Oval<S> {}
|
||||
impl<I> Primitive for widget::Polygon<I> {}
|
||||
impl Primitive for widget::Rectangle {}
|
||||
impl<S, I> Primitive for widget::Triangles<S, I> {}
|
||||
impl<'a> Primitive for widget::Text<'a> {}
|
||||
|
||||
widget_ids! {
|
||||
struct Ids {
|
||||
prim,
|
||||
}
|
||||
pub res: f32,
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
ids: Ids,
|
||||
pos: Vec3<f32>,
|
||||
res: f32,
|
||||
}
|
||||
impl State {
|
||||
// retrieve the postion and resolution as a tuple
|
||||
pub fn pos_res(&self) -> (Vec3<f32>, f32) {
|
||||
(self.pos, self.res)
|
||||
}
|
||||
pub parameters: IngameParameters,
|
||||
}
|
||||
|
||||
pub type Style = ();
|
||||
|
||||
impl<W: Widget + Primitive> Ingame<W> {
|
||||
pub fn from_primitive(pos: Vec3<f32>, widget: W) -> Self {
|
||||
impl<W: Ingameable> Ingame<W> {
|
||||
pub fn new(pos: Vec3<f32>, widget: W) -> Self {
|
||||
Self {
|
||||
common: widget::CommonBuilder::default(),
|
||||
pos,
|
||||
parameters: IngameParameters {
|
||||
num: widget.prim_count(),
|
||||
pos,
|
||||
res: 1.0,
|
||||
},
|
||||
widget,
|
||||
res: 1.0,
|
||||
}
|
||||
}
|
||||
builder_methods! {
|
||||
pub resolution { res = f32 }
|
||||
pub resolution { parameters.res = f32 }
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Widget> Widget for Ingame<W> {
|
||||
impl<W: Ingameable> Widget for Ingame<W> {
|
||||
type State = State;
|
||||
type Style = Style;
|
||||
type Event = ();
|
||||
type Event = W::Event;
|
||||
|
||||
fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
|
||||
fn init_state(&self, mut id_gen: widget::id::Generator) -> Self::State {
|
||||
State {
|
||||
ids: Ids::new(id_gen),
|
||||
pos: Vec3::default(),
|
||||
res: 1.0,
|
||||
ids: W::init_ids(id_gen),
|
||||
parameters: self.parameters,
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,22 +237,17 @@ impl<W: Widget> Widget for Ingame<W> {
|
||||
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
|
||||
let widget::UpdateArgs { id, state, ui, .. } = args;
|
||||
let Ingame {
|
||||
widget, pos, res, ..
|
||||
widget, parameters, ..
|
||||
} = self;
|
||||
|
||||
// Update pos if it has changed
|
||||
if state.pos != pos || state.res != res {
|
||||
if state.parameters != parameters {
|
||||
state.update(|s| {
|
||||
s.pos = pos;
|
||||
s.res = res;
|
||||
s.parameters = parameters;
|
||||
});
|
||||
}
|
||||
|
||||
widget
|
||||
.graphics_for(ui.window)
|
||||
.x_y(0.0, 0.0)
|
||||
.parent(id) // is this needed
|
||||
.set(state.ids.prim, ui);
|
||||
widget.set_ingame(state.ids, id, ui)
|
||||
}
|
||||
|
||||
fn default_x_position(&self, ui: &Ui) -> Position {
|
||||
@ -118,3 +263,67 @@ impl<W: Widget> Widget for Ingame<W> {
|
||||
Dimension::Absolute(1.0)
|
||||
}
|
||||
}
|
||||
|
||||
// Use this if you have multiple widgets that you want to place at the same spot in-game
|
||||
// but don't want to create a new custom widget to contain them both
|
||||
// Note: widgets must be set immediately after settings this
|
||||
// Note: remove this if it ends up unused
|
||||
#[derive(Clone, WidgetCommon)]
|
||||
pub struct IngameAnchor {
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
parameters: IngameParameters,
|
||||
}
|
||||
impl IngameAnchor {
|
||||
pub fn new(pos: Vec3<f32>) -> Self {
|
||||
IngameAnchor {
|
||||
common: widget::CommonBuilder::default(),
|
||||
parameters: IngameParameters {
|
||||
num: 0,
|
||||
pos,
|
||||
res: 1.0,
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn for_widget(mut self, widget: impl Ingameable) -> Self {
|
||||
self.parameters.num += widget.prim_count();
|
||||
self
|
||||
}
|
||||
pub fn for_widgets(mut self, widget: impl Ingameable, n: usize) -> Self {
|
||||
self.parameters.num += n * widget.prim_count();
|
||||
self
|
||||
}
|
||||
pub fn for_prims(mut self, num: usize) -> Self {
|
||||
self.parameters.num += num;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for IngameAnchor {
|
||||
type State = State;
|
||||
type Style = Style;
|
||||
type Event = ();
|
||||
|
||||
fn init_state(&self, _: widget::id::Generator) -> Self::State {
|
||||
State {
|
||||
ids: Ids::None,
|
||||
parameters: self.parameters,
|
||||
}
|
||||
}
|
||||
|
||||
fn style(&self) -> Self::Style {
|
||||
()
|
||||
}
|
||||
|
||||
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
|
||||
let widget::UpdateArgs { id, state, ui, .. } = args;
|
||||
let IngameAnchor { parameters, .. } = self;
|
||||
|
||||
// Update pos if it has changed
|
||||
if state.parameters != parameters {
|
||||
state.update(|s| {
|
||||
s.parameters = parameters;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user