gui 0.6.2

A generic UI library/framework.
Documentation
// Copyright (C) 2018-2024 Daniel Mueller (deso@posteo.net)
// SPDX-License-Identifier: GPL-3.0-or-later

use std::any::TypeId;
use std::fmt::Debug;

use crate::BBox;
use crate::Cap;
use crate::Renderer;


/// A trait representing a renderable object.
pub trait Renderable: 'static + Debug {
  /// Get the [`TypeId`] of `self`.
  fn type_id(&self) -> TypeId;

  /// Render the renderable object.
  ///
  /// This method should just forward the call to the given
  /// [`Renderer`], supplying a trait object of the actual widget. The
  /// renderer is advised to honor the given [`BBox`] and is free to
  /// inquire additional state using the supplied [`Cap`].
  ///
  /// This method is invoked before all the widget's children are
  /// rendered ("pre-order").
  fn render(&self, cap: &dyn Cap, renderer: &dyn Renderer, bbox: BBox) -> BBox;

  /// A method invoked once rendering of this widget and all its
  /// children concluded ("post-order").
  ///
  /// By default, this method does nothing, but it can be useful for
  /// rendering an overlay or for certain renderer related state
  /// adjustments.
  #[allow(unused_variables)]
  fn render_done(&self, cap: &dyn Cap, renderer: &dyn Renderer, bbox: BBox) {}
}

impl dyn Renderable {
  /// Check if the widget is of type `T`.
  pub fn is<T>(&self) -> bool
  where
    T: Renderable,
  {
    let t = TypeId::of::<T>();
    let own_t = self.type_id();

    t == own_t
  }

  /// Downcast the widget reference to type `T`.
  pub fn downcast_ref<T>(&self) -> Option<&T>
  where
    T: Renderable,
  {
    if self.is::<T>() {
      unsafe { Some(&*(self as *const dyn Renderable as *const T)) }
    } else {
      None
    }
  }

  /// Downcast the widget reference to type `T`.
  pub fn downcast_mut<T>(&mut self) -> Option<&mut T>
  where
    T: Renderable,
  {
    if self.is::<T>() {
      unsafe { Some(&mut *(self as *mut dyn Renderable as *mut T)) }
    } else {
      None
    }
  }
}