mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-29 17:34:58 +03:00
trait-ify Button
This commit is contained in:
parent
10d3c0aa60
commit
1682b6c28f
@ -22,7 +22,6 @@ pub struct Widget {
|
||||
}
|
||||
|
||||
enum WidgetType {
|
||||
Btn(Button),
|
||||
Row(Vec<Widget>),
|
||||
Column(Vec<Widget>),
|
||||
Nothing,
|
||||
@ -247,7 +246,7 @@ impl Widget {
|
||||
|
||||
pub(crate) fn btn(btn: Button) -> Widget {
|
||||
let action = btn.action.clone();
|
||||
Widget::new(WidgetType::Btn(btn)).named(action)
|
||||
Widget::new(WidgetType::Generic(Box::new(btn))).named(action)
|
||||
}
|
||||
|
||||
pub fn slider(slider: Slider) -> Widget {
|
||||
@ -352,12 +351,6 @@ impl Widget {
|
||||
impl Widget {
|
||||
fn event(&mut self, ctx: &mut EventCtx, redo_layout: &mut bool) -> Option<Outcome> {
|
||||
match self.widget {
|
||||
WidgetType::Btn(ref mut btn) => {
|
||||
btn.event(ctx);
|
||||
if btn.clicked() {
|
||||
return Some(Outcome::Clicked(btn.action.clone()));
|
||||
}
|
||||
}
|
||||
WidgetType::Row(ref mut widgets) | WidgetType::Column(ref mut widgets) => {
|
||||
for w in widgets {
|
||||
if let Some(o) = w.event(ctx, redo_layout) {
|
||||
@ -388,7 +381,6 @@ impl Widget {
|
||||
}
|
||||
|
||||
match self.widget {
|
||||
WidgetType::Btn(ref btn) => btn.draw(g),
|
||||
WidgetType::Row(ref widgets) | WidgetType::Column(ref widgets) => {
|
||||
for w in widgets {
|
||||
w.draw(g);
|
||||
@ -402,7 +394,6 @@ impl Widget {
|
||||
// Populate a flattened list of Nodes, matching the traversal order
|
||||
fn get_flexbox(&self, parent: Node, stretch: &mut Stretch, nodes: &mut Vec<Node>) {
|
||||
let dims = match self.widget {
|
||||
WidgetType::Btn(ref widget) => widget.get_dims(),
|
||||
WidgetType::Row(ref widgets) => {
|
||||
let mut style = Style {
|
||||
flex_direction: FlexDirection::Row,
|
||||
@ -491,9 +482,6 @@ impl Widget {
|
||||
}
|
||||
|
||||
match self.widget {
|
||||
WidgetType::Btn(ref mut widget) => {
|
||||
widget.set_pos(top_left);
|
||||
}
|
||||
WidgetType::Row(ref mut widgets) => {
|
||||
// layout() doesn't return absolute position; it's relative to the container.
|
||||
for widget in widgets {
|
||||
@ -530,31 +518,23 @@ impl Widget {
|
||||
|
||||
fn get_all_click_actions(&self, actions: &mut HashSet<String>) {
|
||||
match self.widget {
|
||||
WidgetType::Btn(ref btn) => {
|
||||
if actions.contains(&btn.action) {
|
||||
panic!(
|
||||
"Two buttons in one Composite both use action {}",
|
||||
btn.action
|
||||
);
|
||||
}
|
||||
actions.insert(btn.action.clone());
|
||||
}
|
||||
WidgetType::Row(ref widgets) | WidgetType::Column(ref widgets) => {
|
||||
for w in widgets {
|
||||
w.get_all_click_actions(actions);
|
||||
}
|
||||
}
|
||||
WidgetType::Nothing => unreachable!(),
|
||||
// TODO Will need something
|
||||
WidgetType::Generic(_) => {}
|
||||
WidgetType::Generic(ref w) => w.get_all_click_actions(actions),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_btn(&self, name: &str) -> bool {
|
||||
if let WidgetType::Btn(ref btn) = self.widget {
|
||||
btn.action == name
|
||||
} else {
|
||||
false
|
||||
match self.widget {
|
||||
WidgetType::Generic(ref w) => w
|
||||
.downcast_ref::<Button>()
|
||||
.map(|btn| btn.action == name)
|
||||
.unwrap_or(false),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -597,7 +577,7 @@ impl Widget {
|
||||
|
||||
pub(crate) fn take_btn(self) -> Button {
|
||||
match self.widget {
|
||||
WidgetType::Btn(btn) => btn,
|
||||
WidgetType::Generic(w) => *w.downcast::<Button>().ok().unwrap(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
use crate::{
|
||||
text, Color, Drawable, EventCtx, GeomBatch, GfxCtx, JustDraw, Line, MultiKey, RewriteColor,
|
||||
ScreenDims, ScreenPt, Text, Widget, WidgetImpl,
|
||||
text, Color, Drawable, EventCtx, GeomBatch, GfxCtx, JustDraw, Line, MultiKey, Outcome,
|
||||
RewriteColor, ScreenDims, ScreenPt, ScreenRectangle, Text, Widget, WidgetImpl,
|
||||
};
|
||||
use geom::Polygon;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub struct Button {
|
||||
pub action: String,
|
||||
@ -18,7 +19,6 @@ pub struct Button {
|
||||
hitbox: Polygon,
|
||||
|
||||
hovering: bool,
|
||||
clicked: bool,
|
||||
|
||||
pub(crate) top_left: ScreenPt,
|
||||
dims: ScreenDims,
|
||||
@ -53,58 +53,11 @@ impl Button {
|
||||
hitbox,
|
||||
|
||||
hovering: false,
|
||||
clicked: false,
|
||||
|
||||
top_left: ScreenPt::new(0.0, 0.0),
|
||||
dims,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn event(&mut self, ctx: &mut EventCtx) {
|
||||
if self.clicked {
|
||||
panic!("Caller didn't consume button click");
|
||||
}
|
||||
|
||||
if ctx.redo_mouseover() {
|
||||
if let Some(pt) = ctx.canvas.get_cursor_in_screen_space() {
|
||||
self.hovering = self
|
||||
.hitbox
|
||||
.translate(self.top_left.x, self.top_left.y)
|
||||
.contains_pt(pt.to_pt());
|
||||
} else {
|
||||
self.hovering = false;
|
||||
}
|
||||
}
|
||||
if self.hovering && ctx.normal_left_click() {
|
||||
self.clicked = true;
|
||||
self.hovering = false;
|
||||
}
|
||||
|
||||
if let Some(ref hotkey) = self.hotkey {
|
||||
if ctx.input.new_was_pressed(hotkey) {
|
||||
self.clicked = true;
|
||||
self.hovering = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn clicked(&mut self) -> bool {
|
||||
if self.clicked {
|
||||
self.clicked = false;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn draw(&self, g: &mut GfxCtx) {
|
||||
if self.hovering {
|
||||
g.redraw_at(self.top_left, &self.draw_hovered);
|
||||
g.draw_mouse_tooltip(self.tooltip.clone());
|
||||
} else {
|
||||
g.redraw_at(self.top_left, &self.draw_normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for Button {
|
||||
@ -115,6 +68,56 @@ impl WidgetImpl for Button {
|
||||
fn set_pos(&mut self, top_left: ScreenPt) {
|
||||
self.top_left = top_left;
|
||||
}
|
||||
|
||||
fn event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
_rect: &ScreenRectangle,
|
||||
_redo_layout: &mut bool,
|
||||
) -> Option<Outcome> {
|
||||
if ctx.redo_mouseover() {
|
||||
if let Some(pt) = ctx.canvas.get_cursor_in_screen_space() {
|
||||
self.hovering = self
|
||||
.hitbox
|
||||
.translate(self.top_left.x, self.top_left.y)
|
||||
.contains_pt(pt.to_pt());
|
||||
} else {
|
||||
self.hovering = false;
|
||||
}
|
||||
}
|
||||
if self.hovering && ctx.normal_left_click() {
|
||||
self.hovering = false;
|
||||
return Some(Outcome::Clicked(self.action.clone()));
|
||||
}
|
||||
|
||||
if let Some(ref hotkey) = self.hotkey {
|
||||
if ctx.input.new_was_pressed(hotkey) {
|
||||
self.hovering = false;
|
||||
return Some(Outcome::Clicked(self.action.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx) {
|
||||
if self.hovering {
|
||||
g.redraw_at(self.top_left, &self.draw_hovered);
|
||||
g.draw_mouse_tooltip(self.tooltip.clone());
|
||||
} else {
|
||||
g.redraw_at(self.top_left, &self.draw_normal);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_all_click_actions(&self, actions: &mut HashSet<String>) {
|
||||
if actions.contains(&self.action) {
|
||||
panic!(
|
||||
"Two buttons in one Composite both use action {}",
|
||||
self.action
|
||||
);
|
||||
}
|
||||
actions.insert(self.action.clone());
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Btn {}
|
||||
|
@ -36,11 +36,11 @@ impl WidgetImpl for Checkbox {
|
||||
fn event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
_rect: &ScreenRectangle,
|
||||
rect: &ScreenRectangle,
|
||||
redo_layout: &mut bool,
|
||||
) -> Option<Outcome> {
|
||||
self.btn.event(ctx);
|
||||
if self.btn.clicked() {
|
||||
// TODO Lying about the rectangle
|
||||
if self.btn.event(ctx, rect, redo_layout).is_some() {
|
||||
std::mem::swap(&mut self.btn, &mut self.other_btn);
|
||||
self.btn.set_pos(self.other_btn.top_left);
|
||||
self.enabled = !self.enabled;
|
||||
|
@ -75,8 +75,8 @@ impl<T: 'static + Clone> WidgetImpl for Dropdown<T> {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.btn.event(ctx);
|
||||
if self.btn.clicked() {
|
||||
// TODO Again lying about the rectangle
|
||||
if self.btn.event(ctx, rect, redo_layout).is_some() {
|
||||
// TODO set current idx in menu
|
||||
// TODO Choice::map_value?
|
||||
let mut menu = PopupMenu::new(
|
||||
|
@ -14,6 +14,7 @@ pub mod wizard;
|
||||
|
||||
use crate::{EventCtx, GfxCtx, Outcome, ScreenDims, ScreenPt, ScreenRectangle};
|
||||
use ordered_float::NotNan;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub trait WidgetImpl: downcast_rs::Downcast {
|
||||
fn get_dims(&self) -> ScreenDims;
|
||||
@ -29,6 +30,8 @@ pub trait WidgetImpl: downcast_rs::Downcast {
|
||||
None
|
||||
}
|
||||
fn draw(&self, _g: &mut GfxCtx) {}
|
||||
|
||||
fn get_all_click_actions(&self, _actions: &mut HashSet<String>) {}
|
||||
}
|
||||
|
||||
downcast_rs::impl_downcast!(WidgetImpl);
|
||||
|
Loading…
Reference in New Issue
Block a user