uniui_layout_linear_layout 0.0.10

Label widget for uniui_* crate family.
Documentation
use crate::ItemsAlignment;

use super::implz::Platform;

use uniui_gui::{
	prelude::*,
	AlignmentHorizontal,
	AlignmentVertical,
	Application,
	Color,
	DataProcessor,
	NativeWidget,
	Orientation,
	Widget,
	WidgetGenerator,
	Wrap,
};

// FIXME(#174): how widget can modifies it's space occupation policy?
/// LinearLayout places widgets one after another verically or horizontally.
///
/// The space will be equally distributed beetween widgets. You can modify it
/// by using [uniui_wrapper_stretchfactor].
///
/// Example (without macros, see better example with macros below):
/// ```
/// use uniui_widget_button::Button;
/// use uniui_layout_linear_layout::LinearLayout;
///
/// let button1 = Button::new("Button1".to_owned());
/// let button2 = Button::new("Button2".to_owned());
///
/// let mut linear_layout = LinearLayout::new(Orientation::Horizontal);
/// linear_layout.push_widget(button1);
/// linear_layout.push_widget(button2);
/// ```
/// # Macros
/// You may be interested in [u_linear_layout!](u_linear_layout!) macros
/// to simplify LinearLayout creation. Better example with macros:
/// ```
/// use uniui_layout_linear_layout::prelude::*;
///
/// let linear_layout = u_linear_layout! {
///     orientation: Orientation::Vertical,
///     widgets: {
///         Button::new("Button1".to_owned()),
///         Button::new("Button2".to_owned()),
///     }
/// };
/// ```
pub struct LinearLayout {
	childs: Vec<Box<dyn Widget>>,
	orientation: Orientation,
	wrap: Property<Wrap>,
	alignment_vertical: Property<AlignmentVertical>,
	alignment_horizontal: Property<AlignmentHorizontal>,
	items_alignment: Property<ItemsAlignment>,
	platform: Platform,
}

impl LinearLayout {
	/// Creates new LinearLayout with predefined [Orientation](uniui_gui::Orientation)
	///
	/// ```
	/// use uniui_gui::Orientation;
	/// use uniui_layout_linear_layout::LinearLayout;
	///
	/// let linear_layout = LinearLayout::new(Orientation::Horizontal);
	/// ```
	pub fn new(orientation: Orientation) -> LinearLayout {
		return LinearLayout {
			childs: Vec::new(),
			orientation,
			wrap: Property::new(Wrap::NoWrap),
			alignment_horizontal: Property::new(AlignmentHorizontal::Stretch),
			alignment_vertical: Property::new(AlignmentVertical::Stretch),
			items_alignment: Property::new(ItemsAlignment::Stretch),
			platform: Platform::new(),
		};
	}

	/// Moves widget into layout
	///
	/// Since widget itself will be moved into layout so the widget have to
	/// be configured before `push_widget` will be called.
	///
	/// ```
	/// use uniui_gui::Orientation;
	/// use uniui_layout_linear_layout::LinearLayout;
	/// use uniui_widget_button::Button;
	///
	/// let mut linear_layout = LinearLayout::new(Orientation::Horizontal);
	///
	/// let button = Button::new("Button".to_owned());
	/// linear_layout.push_widget(button);
	/// ```
	pub fn push_widget<W>(
		&mut self,
		widget: W,
	) where
		W: Sized + Widget + 'static,
	{
		self.childs.push(Box::new(widget));
	}

	// FIXME(#174): provide documentation
	pub fn slot_alignment_horizontal(&self) -> &dyn Slot<AlignmentHorizontal> {
		return self.alignment_horizontal.slot();
	}

	// FIXME(#174): provide documentation
	pub fn slot_alignment_vertical(&self) -> &dyn Slot<AlignmentVertical> {
		return self.alignment_vertical.slot();
	}

	// FIXME(#174): provide documentation
	pub fn slot_set_items_alignment(&self) -> &dyn Slot<ItemsAlignment> {
		return self.items_alignment.slot();
	}

	// FIXME(#174): provide documentation
	pub fn slot_set_wrap(&self) -> &dyn Slot<Wrap> {
		return self.wrap.slot();
	}

	#[doc(hidden)]
	/// Deprecated. Will be removed soon.
	///
	/// For the same functionality please take a look at
	/// * [BackgroundColor](uniui_wrapper_backgroundcolor::BackgroundColor),
	/// * [BackgroundGradient](uniui_wrapper_backgroundgradient::BackgroundGradient)
	/// * [BackgroundImage](uniui_wrapper_backgroundimage::BackgroundImage)
	pub fn set_background(
		&mut self,
		color: &Color,
	) {
		self.platform.set_background(color);
	}

	#[doc(hidden)]
	/// Deprecated. Will be removed soon.
	///
	/// For the same functionality please take a look at
	/// (LinearLayout::slot_alignment_horizontal)[crate::LinearLayout.
	/// slot_alignment_horizontal)
	pub fn set_alignment_horizontal(
		&mut self,
		alignment: AlignmentHorizontal,
	) {
		self.slot_alignment_horizontal().exec_for(alignment);
	}

	#[doc(hidden)]
	/// Deprecated. Will be removed soon.
	///
	/// For the same functionality please take a look at
	/// (LinearLayout::slot_alignment_vertical)[crate::LinearLayout.
	/// slot_alignment_vertical)
	pub fn set_alignment_vertical(
		&mut self,
		alignment: AlignmentVertical,
	) {
		self.slot_alignment_vertical().exec_for(alignment);
	}
}

impl Widget for LinearLayout {
	fn to_native(
		&mut self,
		widget_generator: &mut dyn WidgetGenerator,
	) -> Result<NativeWidget, ()> {
		self.items_alignment.try_update();
		self.wrap.try_update();
		self.alignment_horizontal.try_update();
		self.alignment_vertical.try_update();

		return self.platform.to_native(
			widget_generator,
			&mut self.childs,
			&self.orientation,
			self.wrap.as_ref(),
			self.alignment_horizontal.as_ref(),
			self.alignment_vertical.as_ref(),
			self.items_alignment.as_ref(),
		);
	}

	fn draw(&mut self) {
		self.childs.iter_mut().for_each(|child| child.as_mut().draw());
	}
}

impl DataProcessor for LinearLayout {
	fn process_data(
		&mut self,
		msec_since_app_epoch: i64,
		app: &mut dyn Application,
	) {
		self.childs
			.iter_mut()
			.for_each(|child| child.as_mut().process_data(msec_since_app_epoch, app));

		if self.items_alignment.try_update() {
			self.platform.update_alignment(self.items_alignment.as_ref());
		}

		if self.wrap.try_update() {
			self.platform.update_wrap(self.wrap.as_ref());
		}

		if self.alignment_horizontal.try_update() {
			self.platform.update_alignment_horizontal(self.alignment_horizontal.as_ref());
		}

		if self.alignment_vertical.try_update() {
			self.platform.update_alignment_vertical(self.alignment_vertical.as_ref());
		}
	}
}