diff --git a/examples/ggez/main.rs b/examples/ggez/main.rs index 87949dee..7deef072 100644 --- a/examples/ggez/main.rs +++ b/examples/ggez/main.rs @@ -2,26 +2,33 @@ mod renderer; mod widget; use renderer::Renderer; -use widget::Text; +use widget::{button, Button, Column, Text}; use ggez; use ggez::event; use ggez::graphics; +use ggez::input::mouse; use iced::Interface; pub fn main() -> ggez::GameResult { let cb = ggez::ContextBuilder::new("iced", "ggez"); let (ctx, event_loop) = &mut cb.build()?; - let state = &mut Game::new()?; + let state = &mut Game::new(ctx)?; event::run(ctx, event_loop, state) } -struct Game {} +struct Game { + spritesheet: graphics::Image, + button: button::State, +} impl Game { - fn new() -> ggez::GameResult { - Ok(Game {}) + fn new(context: &mut ggez::Context) -> ggez::GameResult { + Ok(Game { + spritesheet: graphics::Image::new(context, "/ui.png").unwrap(), + button: button::State::new(), + }) } } @@ -33,17 +40,50 @@ impl event::EventHandler for Game { fn draw(&mut self, context: &mut ggez::Context) -> ggez::GameResult { graphics::clear(context, [0.1, 0.2, 0.3, 1.0].into()); - { - let renderer = &mut Renderer { context }; - let ui: Interface<(), Renderer> = - Interface::compute(Text::new("Hello, iced!").into(), renderer); + let screen = graphics::screen_coordinates(context); - let mouse_cursor = ui.draw(renderer, iced::Point::new(0.0, 0.0)); + let cursor = { + let hello = Text::new("Hello, iced!") + .horizontal_alignment(iced::text::HorizontalAlignment::Center); + + let button = Button::new(&mut self.button, "Press me!").width(200); + + let content = Column::new() + .width(screen.w as u32) + .height(screen.h as u32) + .align_items(iced::Align::Center) + .justify_content(iced::Justify::Center) + .spacing(20) + .push(hello) + .push(button); + + let renderer = + &mut Renderer::new(context, self.spritesheet.clone()); + + let ui: Interface<(), Renderer> = + Interface::compute(content.into(), renderer); + + let cursor = ui.draw(renderer, iced::Point::new(0.0, 0.0)); renderer.flush(); - } + + cursor + }; + + mouse::set_cursor_type(context, into_cursor_type(cursor)); graphics::present(context)?; Ok(()) } } + +fn into_cursor_type(cursor: iced::MouseCursor) -> mouse::MouseCursor { + match cursor { + iced::MouseCursor::OutOfBounds => mouse::MouseCursor::Default, + iced::MouseCursor::Idle => mouse::MouseCursor::Default, + iced::MouseCursor::Pointer => mouse::MouseCursor::Hand, + iced::MouseCursor::Working => mouse::MouseCursor::Progress, + iced::MouseCursor::Grab => mouse::MouseCursor::Grab, + iced::MouseCursor::Grabbing => mouse::MouseCursor::Grabbing, + } +} diff --git a/examples/ggez/renderer.rs b/examples/ggez/renderer.rs index ae6e3250..d21c5ec3 100644 --- a/examples/ggez/renderer.rs +++ b/examples/ggez/renderer.rs @@ -1,14 +1,31 @@ +mod button; mod text; -use ggez::graphics::{self, Color}; +use ggez::graphics::{self, spritebatch::SpriteBatch, Color, Image}; use ggez::Context; pub struct Renderer<'a> { pub context: &'a mut Context, + pub sprites: SpriteBatch, + pub spritesheet: Image, } impl Renderer<'_> { + pub fn new(context: &mut Context, spritesheet: Image) -> Renderer { + Renderer { + context, + sprites: SpriteBatch::new(spritesheet.clone()), + spritesheet, + } + } pub fn flush(&mut self) { + graphics::draw( + self.context, + &self.sprites, + graphics::DrawParam::default(), + ) + .expect("Draw sprites"); + graphics::draw_queued_text( self.context, graphics::DrawParam::default(), diff --git a/examples/ggez/renderer/button.rs b/examples/ggez/renderer/button.rs new file mode 100644 index 00000000..2423efe1 --- /dev/null +++ b/examples/ggez/renderer/button.rs @@ -0,0 +1,144 @@ +use super::Renderer; +use ggez::graphics::{ + self, Align, Color, DrawParam, Rect, Scale, Text, TextFragment, WHITE, +}; +use iced::{button, MouseCursor}; + +const LEFT: Rect = Rect { + x: 0.0, + y: 34.0, + w: 6.0, + h: 49.0, +}; + +const BACKGROUND: Rect = Rect { + x: LEFT.w, + y: LEFT.y, + w: 1.0, + h: LEFT.h, +}; + +const RIGHT: Rect = Rect { + x: LEFT.h - LEFT.w, + y: LEFT.y, + w: LEFT.w, + h: LEFT.h, +}; + +impl button::Renderer for Renderer<'_> { + fn draw( + &mut self, + cursor_position: iced::Point, + mut bounds: iced::Rectangle, + state: &button::State, + label: &str, + class: button::Class, + ) -> MouseCursor { + let mouse_over = bounds.contains(cursor_position); + + let mut state_offset = 0.0; + + if mouse_over { + if state.is_pressed() { + bounds.y += 4.0; + state_offset = RIGHT.x + RIGHT.w; + } else { + bounds.y -= 1.0; + } + } + + let class_index = match class { + button::Class::Primary => 0, + button::Class::Secondary => 1, + button::Class::Positive => 2, + }; + + let width = self.spritesheet.width() as f32; + let height = self.spritesheet.height() as f32; + + self.sprites.add(DrawParam { + src: Rect { + x: (LEFT.x + state_offset) / width, + y: (LEFT.y + class_index as f32 * LEFT.h) / height, + w: LEFT.w / width, + h: LEFT.h / height, + }, + dest: ggez::mint::Point2 { + x: bounds.x, + y: bounds.y, + }, + ..DrawParam::default() + }); + + self.sprites.add(DrawParam { + src: Rect { + x: (BACKGROUND.x + state_offset) / width, + y: (BACKGROUND.y + class_index as f32 * BACKGROUND.h) / height, + w: BACKGROUND.w / width, + h: BACKGROUND.h / height, + }, + dest: ggez::mint::Point2 { + x: bounds.x + LEFT.w, + y: bounds.y, + }, + scale: ggez::mint::Vector2 { + x: bounds.width - LEFT.w - RIGHT.w, + y: 1.0, + }, + ..DrawParam::default() + }); + + self.sprites.add(DrawParam { + src: Rect { + x: (RIGHT.x + state_offset) / width, + y: (RIGHT.y + class_index as f32 * RIGHT.h) / height, + w: RIGHT.w / width, + h: RIGHT.h / height, + }, + dest: ggez::mint::Point2 { + x: bounds.x + bounds.width - RIGHT.w, + y: bounds.y, + }, + ..DrawParam::default() + }); + + let mut text = Text::new(TextFragment { + text: String::from(label), + scale: Some(Scale { x: 20.0, y: 20.0 }), + ..Default::default() + }); + + text.set_bounds( + ggez::mint::Point2 { + x: bounds.width, + y: bounds.height, + }, + Align::Center, + ); + + graphics::queue_text( + self.context, + &text, + ggez::mint::Point2 { + x: bounds.x, + y: bounds.y + BACKGROUND.h / 4.0, + }, + Some(if mouse_over { + WHITE + } else { + Color { + r: 0.9, + g: 0.9, + b: 0.9, + a: 1.0, + } + }), + ); + + if mouse_over { + MouseCursor::Pointer + } else { + MouseCursor::OutOfBounds + } + } +} diff --git a/examples/ggez/widget.rs b/examples/ggez/widget.rs index a9e0a7ba..657a3190 100644 --- a/examples/ggez/widget.rs +++ b/examples/ggez/widget.rs @@ -1,3 +1,5 @@ use ggez::graphics::Color; +pub use iced::{button, Button, Column, Row}; + pub type Text = iced::Text; diff --git a/resources/ui.png b/resources/ui.png new file mode 100644 index 00000000..4fd3beb3 Binary files /dev/null and b/resources/ui.png differ