use crate::classic_frame;
use conrod_core::{color, widget, widget_ids, Positionable, UiCell, Widget, WidgetCommon};
use widget::button::TimesClicked;
#[derive(Clone, Copy, Debug, WidgetCommon)]
pub struct ClassicButton {
#[conrod(common_builder)]
pub common: widget::CommonBuilder,
pub button_type: ButtonType,
pub hidpi_factor: f64,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum ButtonType {
Collapse,
Uncollapse,
Close,
}
widget_ids! {
pub struct Ids {
frame,
icon,
}
}
impl ClassicButton {
pub fn new(button_type: ButtonType, hidpi_factor: f64) -> Self {
ClassicButton {
common: widget::CommonBuilder::default(),
button_type,
hidpi_factor,
}
}
}
impl Widget for ClassicButton {
type State = Ids;
type Style = ();
type Event = TimesClicked;
fn init_state(&self, id_gen: conrod_core::widget::id::Generator) -> Self::State {
Ids::new(id_gen)
}
fn style(&self) -> Self::Style {}
fn update(self, args: conrod_core::widget::UpdateArgs<Self>) -> Self::Event {
let widget::UpdateArgs {
id,
state,
rect,
ui,
..
} = args;
let state: &mut widget::State<Ids> = state;
let Self {
button_type,
hidpi_factor,
..
} = self;
let (interaction, times_triggered) = interaction_and_times_triggered(id, ui);
let base_color = color::rgba(0.75, 0.75, 0.75, 1.0);
let dpi_int = if hidpi_factor.fract() < 0.51 {
hidpi_factor.trunc()
} else {
hidpi_factor.trunc() + 1.0
};
let border_thickness = 2.0 * dpi_int / hidpi_factor;
let triangles = classic_frame::make_button_frame(
rect.bottom_left(),
rect.top_right(),
border_thickness,
base_color,
interaction == Interaction::Press,
);
widget::Triangles::multi_color(triangles)
.with_bounding_rect(rect)
.middle_of(id)
.graphics_for(id)
.place_on_kid_area(false)
.set(state.frame, ui);
let click_shift = 1.0 * dpi_int / hidpi_factor;
let icon_rect = {
let icon_rect = rect.pad(border_thickness);
if interaction == Interaction::Press {
icon_rect.pad_left(click_shift).pad_top(click_shift)
} else {
icon_rect.pad_right(click_shift).pad_bottom(click_shift)
}
};
match button_type {
ButtonType::Collapse => {
let icon_triangles = classic_frame::make_collapse_button_icon(
icon_rect.bottom_left(),
icon_rect.top_right(),
hidpi_factor,
);
widget::Triangles::single_color(color::BLACK, icon_triangles)
.with_bounding_rect(icon_rect)
.top_left_with_margin_on(id, border_thickness)
.graphics_for(id)
.place_on_kid_area(false)
.set(state.icon, ui);
}
ButtonType::Uncollapse => {
let icon_triangles = classic_frame::make_uncollapse_button_icon(
icon_rect.bottom_left(),
icon_rect.top_right(),
hidpi_factor,
);
widget::Triangles::single_color(color::BLACK, icon_triangles)
.with_bounding_rect(icon_rect)
.top_left_with_margin_on(id, border_thickness)
.graphics_for(id)
.place_on_kid_area(false)
.set(state.icon, ui);
}
ButtonType::Close => {
let icon_triangles = classic_frame::make_close_button_icon(
icon_rect.bottom_left(),
icon_rect.top_right(),
hidpi_factor,
);
widget::Triangles::single_color(color::BLACK, icon_triangles)
.with_bounding_rect(icon_rect)
.top_left_with_margin_on(id, border_thickness)
.graphics_for(id)
.place_on_kid_area(false)
.set(state.icon, ui);
}
}
TimesClicked(times_triggered)
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
enum Interaction {
Idle,
Hover,
Press,
}
fn interaction_and_times_triggered(button_id: widget::Id, ui: &UiCell) -> (Interaction, u16) {
let input = ui.widget_input(button_id);
let mouse_interaction = input.mouse().map_or(Interaction::Idle, |mouse| {
if mouse.buttons.left().is_down() {
if ui.global_input().current.widget_under_mouse == Some(button_id) {
Interaction::Press
} else {
Interaction::Idle
}
} else {
Interaction::Hover
}
});
let interaction = match mouse_interaction {
Interaction::Idle | Interaction::Hover => {
let is_touch_press = ui
.global_input()
.current
.touch
.values()
.any(|t| t.start.widget == Some(button_id) && t.widget == Some(button_id));
if is_touch_press {
Interaction::Press
} else {
mouse_interaction
}
}
Interaction::Press => Interaction::Press,
};
let times_triggered = (input.clicks().left().count() + input.taps().count()) as u16;
(interaction, times_triggered)
}