dear-imgui-rs 0.12.0

High-level Rust bindings to Dear ImGui v1.92.7 with docking, WGPU/GL backends, and extensions (ImPlot/ImPlot3D, ImNodes, ImGuizmo, file browser, reflection-based UI)
Documentation
//! Tooltips
//!
//! Tooltip helpers with automatic lifetime management via tokens and
//! convenient `with_tooltip` patterns.
//!
#![allow(
    clippy::cast_possible_truncation,
    clippy::cast_sign_loss,
    clippy::as_conversions
)]
use crate::input::MouseButton;
use crate::sys;
use crate::ui::Ui;

/// # Tooltip Widgets
impl Ui {
    /// Construct a tooltip window that can have any kind of content.
    ///
    /// Typically used with `Ui::is_item_hovered()` or some other conditional check.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # use dear_imgui_rs::*;
    /// # let mut ctx = Context::create();
    /// # let ui = ctx.frame();
    /// ui.text("Hover over me");
    /// if ui.is_item_hovered() {
    ///     ui.tooltip(|| {
    ///         ui.text_colored([1.0, 0.0, 0.0, 1.0], "I'm red!");
    ///     });
    /// }
    /// ```
    #[doc(alias = "BeginTooltip", alias = "EndTooltip")]
    pub fn tooltip<F: FnOnce()>(&self, f: F) {
        if let Some(_token) = self.begin_tooltip() {
            f();
        }
    }

    /// Construct a tooltip window that can have any kind of content.
    ///
    /// Returns a `TooltipToken` that must be ended by calling `.end()` or by dropping.
    #[doc(alias = "BeginTooltip")]
    pub fn begin_tooltip(&self) -> Option<TooltipToken<'_>> {
        if unsafe { sys::igBeginTooltip() } {
            Some(TooltipToken::new(self))
        } else {
            None
        }
    }

    /// Shortcut to call [`Self::tooltip`] with simple text content.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # use dear_imgui_rs::*;
    /// # let mut ctx = Context::create();
    /// # let ui = ctx.frame();
    /// ui.text("Hover over me");
    /// if ui.is_item_hovered() {
    ///     ui.tooltip_text("I'm a tooltip!");
    /// }
    /// ```
    #[doc(alias = "BeginTooltip", alias = "EndTooltip", alias = "SetTooltip")]
    pub fn tooltip_text(&self, text: impl AsRef<str>) {
        self.tooltip(|| self.text(text));
    }

    /// Sets a tooltip with simple text content.
    ///
    /// This renders unformatted text (no `%`-style formatting) and avoids calling C variadic APIs.
    #[doc(alias = "SetTooltip")]
    pub fn set_tooltip(&self, text: impl AsRef<str>) {
        let s = text.as_ref();
        unsafe {
            // Avoid calling C variadic APIs: build a tooltip window and render unformatted text.
            if sys::igBeginTooltip() {
                let begin = s.as_ptr() as *const std::os::raw::c_char;
                let end = begin.add(s.len());
                sys::igTextUnformatted(begin, end);
                sys::igEndTooltip();
            }
        }
    }

    /// Sets a tooltip with formatted text content.
    #[doc(alias = "SetTooltip")]
    pub fn set_tooltip_formatted(&self, text: impl AsRef<str>) {
        self.set_tooltip(text);
    }

    /// Sets a tooltip for the last item with simple text content.
    ///
    /// Uses the non-variadic `BeginItemTooltip` path and renders unformatted text.
    #[doc(alias = "SetItemTooltip")]
    pub fn set_item_tooltip(&self, text: impl AsRef<str>) {
        let s = text.as_ref();
        unsafe {
            // Prefer the non-variadic ImGui 1.9x+ API when available.
            if sys::igBeginItemTooltip() {
                let begin = s.as_ptr() as *const std::os::raw::c_char;
                let end = begin.add(s.len());
                sys::igTextUnformatted(begin, end);
                sys::igEndTooltip();
            }
        }
    }
}

/// # Item/Widget Utilities and Query Functions
impl Ui {
    /// Returns true if the last item is being hovered by mouse (and usable).
    /// This is typically used to show tooltips.
    #[doc(alias = "IsItemHovered")]
    pub fn is_item_hovered(&self) -> bool {
        unsafe { sys::igIsItemHovered(crate::HoveredFlags::NONE.bits()) }
    }

    /// Returns true if the last item is being hovered by mouse with specific flags.
    #[doc(alias = "IsItemHovered")]
    pub fn is_item_hovered_with_flags(&self, flags: crate::HoveredFlags) -> bool {
        unsafe { sys::igIsItemHovered(flags.bits()) }
    }

    /// Returns true if the last item is active (e.g. button being held, text field being edited).
    #[doc(alias = "IsItemActive")]
    pub fn is_item_active(&self) -> bool {
        unsafe { sys::igIsItemActive() }
    }

    /// Returns true if the last item is focused (e.g. text input field).
    #[doc(alias = "IsItemFocused")]
    pub fn is_item_focused(&self) -> bool {
        unsafe { sys::igIsItemFocused() }
    }

    /// Returns true if the last item was just clicked.
    #[doc(alias = "IsItemClicked")]
    pub fn is_item_clicked(&self) -> bool {
        unsafe { sys::igIsItemClicked(crate::input::MouseButton::Left as i32) }
    }

    /// Returns true if the last item was clicked with specific mouse button.
    #[doc(alias = "IsItemClicked")]
    pub fn is_item_clicked_with_button(&self, mouse_button: MouseButton) -> bool {
        unsafe { sys::igIsItemClicked(mouse_button as i32) }
    }

    /// Returns true if the last item is visible (not clipped).
    #[doc(alias = "IsItemVisible")]
    pub fn is_item_visible(&self) -> bool {
        unsafe { sys::igIsItemVisible() }
    }

    /// Returns true if the last item was just made active (e.g. button was pressed).
    #[doc(alias = "IsItemActivated")]
    pub fn is_item_activated(&self) -> bool {
        unsafe { sys::igIsItemActivated() }
    }

    /// Returns true if the last item was just made inactive (e.g. button was released).
    #[doc(alias = "IsItemDeactivated")]
    pub fn is_item_deactivated(&self) -> bool {
        unsafe { sys::igIsItemDeactivated() }
    }

    /// Returns true if the last item was just made inactive and was edited.
    #[doc(alias = "IsItemDeactivatedAfterEdit")]
    pub fn is_item_deactivated_after_edit(&self) -> bool {
        unsafe { sys::igIsItemDeactivatedAfterEdit() }
    }

    /// Returns true if the last item was edited.
    ///
    /// This is typically used to detect value changes for widgets.
    #[doc(alias = "IsItemEdited")]
    pub fn is_item_edited(&self) -> bool {
        unsafe { sys::igIsItemEdited() }
    }

    /// Returns true if any item is active.
    #[doc(alias = "IsAnyItemActive")]
    pub fn is_any_item_active(&self) -> bool {
        unsafe { sys::igIsAnyItemActive() }
    }

    /// Returns true if any item is focused.
    #[doc(alias = "IsAnyItemFocused")]
    pub fn is_any_item_focused(&self) -> bool {
        unsafe { sys::igIsAnyItemFocused() }
    }

    /// Returns true if any item is hovered.
    #[doc(alias = "IsAnyItemHovered")]
    pub fn is_any_item_hovered(&self) -> bool {
        unsafe { sys::igIsAnyItemHovered() }
    }

    /// Gets the bounding rectangle of the last item in screen space.
    #[doc(alias = "GetItemRectMin", alias = "GetItemRectMax")]
    pub fn item_rect(&self) -> ([f32; 2], [f32; 2]) {
        let min = unsafe { sys::igGetItemRectMin() };
        let max = unsafe { sys::igGetItemRectMax() };
        ([min.x, min.y], [max.x, max.y])
    }

    /// Gets the size of the last item.
    #[doc(alias = "GetItemRectSize")]
    pub fn item_rect_size(&self) -> [f32; 2] {
        let size = unsafe { sys::igGetItemRectSize() };
        [size.x, size.y]
    }

    /// Returns the ImGui ID of the last item.
    #[doc(alias = "GetItemID")]
    pub fn item_id(&self) -> crate::Id {
        unsafe { crate::Id::from(sys::igGetItemID()) }
    }
}

/// Tracks a tooltip that can be ended by calling `.end()` or by dropping
#[must_use]
pub struct TooltipToken<'ui> {
    _ui: &'ui Ui,
}

impl<'ui> TooltipToken<'ui> {
    /// Creates a new tooltip token
    fn new(ui: &'ui Ui) -> Self {
        TooltipToken { _ui: ui }
    }

    /// Ends the tooltip
    pub fn end(self) {
        // The drop implementation will handle the actual ending
    }
}

impl<'ui> Drop for TooltipToken<'ui> {
    fn drop(&mut self) {
        unsafe {
            sys::igEndTooltip();
        }
    }
}