diff --git a/abletk-common/src/lib.rs b/abletk-common/src/lib.rs index eae8dc0..a144b8c 100755 --- a/abletk-common/src/lib.rs +++ b/abletk-common/src/lib.rs @@ -69,6 +69,14 @@ impl Renderer { self.renderer.fill_rect(rect) } + pub fn get_text_size(&self, text: &str) -> (u32, u32) { + self.renderer.get_text_size(text) + } + + pub fn position(&self) -> (u32, u32) { + (self.x, self.y) + } + pub fn position_at(&mut self, x: u32, y: u32) { self.x = x; self.y = y diff --git a/abletk-direct2d/src/lib.rs b/abletk-direct2d/src/lib.rs index f2eeaf6..8006340 100755 --- a/abletk-direct2d/src/lib.rs +++ b/abletk-direct2d/src/lib.rs @@ -91,6 +91,21 @@ impl Renderer { } } + pub fn get_text_size(&self, text: &str) -> (u32, u32) { + let metrics = unsafe { + let layout = self.dw_factory.CreateTextLayout( + // fixme: make this not hacky + &text.as_bytes().iter().map(|b| *b as u16).collect::>(), + &self.text_format, + f32::INFINITY, + f32::INFINITY, + ).unwrap(); + layout.GetMetrics().unwrap() + }; + + (metrics.widthIncludingTrailingWhitespace as u32, metrics.height as u32) + } + pub fn resized(&mut self, width: u32, height: u32) { unsafe { if let Some(target) = self.target.as_ref() { diff --git a/src/lib.rs b/src/lib.rs index 0841a2e..19baba7 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,7 @@ pub mod prelude { pub use crate::event::window::Event as WindowEvent; pub use crate::platform::Platform; pub use crate::widget::Label; + pub use crate::widget::Row; pub use crate::widget::Widget; pub use crate::window::*; pub use crate::rgb; diff --git a/src/main.rs b/src/main.rs index 1a2d5ac..9c6d0d7 100755 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,9 @@ fn launch() -> _ { Application::new() .apply_plugin(QuitPlugin) .add_window(Window::builder( - Label::new("Hello, AbleTK!") - .color(rgb!(0xFF00FFFF)))) + Row::new() + .add(Label::new("Hello, AbleTK! ") + .color(rgb!(0xFF00FFFF))) + .add(Label::new("Hello, World!") + .color(rgb!(0x64CAFEFF))))) } diff --git a/src/widget/label.rs b/src/widget/label.rs index 1b023e5..39abbc6 100755 --- a/src/widget/label.rs +++ b/src/widget/label.rs @@ -6,7 +6,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use abletk_common::{Renderer, brush::Brush, color::Color}; +use abletk_common::{Renderer, brush::Brush, color::Color, rgb}; use crate::{widget::Widget, layout::position::Position}; pub struct Label { @@ -20,8 +20,9 @@ impl Widget for Label { renderer.draw_text(&self.text); } - fn position(&self) -> Position { - Position::new(100, 0, 0, 0) + fn position(&self, renderer: &mut Renderer) -> Position { + let (width, height) = renderer.get_text_size(&self.text); + Position::new(0, 0, width, height) } } @@ -29,7 +30,7 @@ impl Label { pub fn new>(text: S) -> Self { Self { text: text.into(), - color: Color(1.0, 1.0, 1.0, 1.0), + color: rgb!(0xFFFFFFFF), } } diff --git a/src/widget/mod.rs b/src/widget/mod.rs index ada1dcd..eff683e 100755 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -7,13 +7,16 @@ */ mod label; +mod row; use abletk_common::Renderer; pub use label::*; +pub use row::*; use crate::layout::position::Position; pub trait Widget { fn draw(&self, renderer: &mut Renderer); - fn position(&self) -> Position; + // fixme: don't pass renderer + fn position(&self, renderer: &mut Renderer) -> Position; } diff --git a/src/widget/row.rs b/src/widget/row.rs new file mode 100755 index 0000000..95473e5 --- /dev/null +++ b/src/widget/row.rs @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 Umut İnan Erdoğan + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +use crate::{layout::position::Position, widget::Widget}; +use abletk_common::Renderer; + +pub struct Row { + widgets: Vec>, +} + +impl Widget for Row { + fn draw(&self, renderer: &mut Renderer) { + self.widgets.iter().for_each(|widget| { + let pos = widget.position(renderer); + renderer.position_at( + renderer.position().0 + pos.x(), + renderer.position().1 + pos.y() + ); + widget.draw(renderer); + renderer.position_at( + renderer.position().0 + pos.width(), + renderer.position().1 + ); + }); + } + + fn position(&self, renderer: &mut Renderer) -> Position { + let (width, height) = self.widgets.iter() + .map(|widget| widget.position(renderer)) + .map(|pos| (pos.width(), pos.height())) + .fold((0, 0), |accum, item| ( + accum.0 + item.0, + if item.1 > accum.1 { item.1 } else { accum.1 } + )); + + Position::new(0, 0, width, height) + } +} + +impl Row { + pub fn new() -> Self { + Self { + widgets: Vec::new(), + } + } + + pub fn add(mut self, widget: T) -> Self { + self.widgets.push(Box::new(widget)); + self + } +} diff --git a/src/window.rs b/src/window.rs index d885dc1..6ebba45 100755 --- a/src/window.rs +++ b/src/window.rs @@ -72,7 +72,7 @@ impl Window { } pub fn render(&mut self) { - let position = self.root.position(); + let position = self.root.position(&mut self.renderer); eprintln!("Rendering window with id {:?}", self.id()); eprintln!("Root widget position: {position:?}");