use crate::core::color::Color;
use crate::core::drawing::RaylibDraw;
use crate::core::math::{Rectangle, Vector2};
use crate::core::text::WeakFont;
use crate::core::RaylibHandle;
use crate::ffi;
use std::ffi::{c_char, CStr, CString};
impl RaylibHandle {
#[inline]
pub fn gui_enable(&mut self) {
unsafe { ffi::GuiEnable() }
}
#[inline]
pub fn gui_disable(&mut self) {
unsafe { ffi::GuiDisable() }
}
#[inline]
pub fn gui_lock(&mut self) {
unsafe { ffi::GuiLock() }
}
#[inline]
pub fn gui_unlock(&mut self) {
unsafe { ffi::GuiUnlock() }
}
#[inline]
pub fn gui_fade(&mut self, color: Color, alpha: f32) -> Color {
unsafe { ffi::Fade(color.into(), alpha).into() }
}
#[inline]
pub fn gui_set_state(&mut self, state: crate::consts::GuiState) {
unsafe { ffi::GuiSetState(state as i32) }
}
#[inline]
pub fn gui_get_state(&mut self) -> crate::consts::GuiState {
unsafe { std::mem::transmute(ffi::GuiGetState()) }
}
#[inline]
pub fn gui_set_font(&mut self, font: impl AsRef<ffi::Font>) {
unsafe { ffi::GuiSetFont(*font.as_ref()) }
}
#[inline]
pub fn gui_get_font(&mut self) -> WeakFont {
unsafe { WeakFont(ffi::GuiGetFont()) }
}
#[inline]
pub fn gui_set_style(
&mut self,
control: crate::consts::GuiControl,
property: impl GuiProperty,
value: i32,
) {
unsafe { ffi::GuiSetStyle(control as i32, property.as_i32(), value) }
}
#[inline]
pub fn gui_get_style(
&mut self,
control: crate::consts::GuiControl,
property: impl GuiProperty,
) -> i32 {
unsafe { ffi::GuiGetStyle(control as i32, property.as_i32()) }
}
#[inline]
pub fn gui_load_style(&mut self, filename: &str) {
let c_filename = CString::new(filename).unwrap();
unsafe { ffi::GuiLoadStyle(c_filename.as_ptr()) }
}
#[inline]
pub fn gui_load_style_default(&mut self) {
unsafe { ffi::GuiLoadStyleDefault() }
}
#[inline]
pub fn gui_enable_tooltip(&mut self) {
unsafe { ffi::GuiEnableTooltip() };
}
#[inline]
pub fn gui_disable_tooltip(&mut self) {
unsafe { ffi::GuiDisableTooltip() };
}
#[inline]
pub fn gui_set_tooltip(&mut self, tooltip: &str) {
let c_text = CString::new(tooltip).unwrap();
unsafe {
ffi::GuiSetTooltip(c_text.as_ptr());
}
}
}
impl<D: RaylibDraw> RaylibDrawGui for D {}
pub trait RaylibDrawGui {
#[inline]
fn gui_enable(&mut self) {
unsafe { ffi::GuiEnable() }
}
#[inline]
fn gui_disable(&mut self) {
unsafe { ffi::GuiDisable() }
}
#[inline]
fn gui_lock(&mut self) {
unsafe { ffi::GuiLock() }
}
#[inline]
fn gui_unlock(&mut self) {
unsafe { ffi::GuiUnlock() }
}
#[inline]
fn gui_is_locked(&mut self) -> bool {
unsafe { ffi::GuiIsLocked() }
}
#[inline]
fn gui_fade(&mut self, color: Color, alpha: f32) -> Color {
unsafe { ffi::Fade(color.into(), alpha).into() }
}
#[inline]
fn gui_set_state(&mut self, state: crate::consts::GuiState) {
unsafe { ffi::GuiSetState(state as i32) }
}
#[inline]
fn gui_get_state(&mut self) -> crate::consts::GuiState {
unsafe { std::mem::transmute(ffi::GuiGetState()) }
}
#[inline]
fn gui_set_font(&mut self, font: impl AsRef<ffi::Font>) {
unsafe { ffi::GuiSetFont(*font.as_ref()) }
}
#[inline]
fn gui_get_font(&mut self) -> WeakFont {
unsafe { WeakFont(ffi::GuiGetFont()) }
}
#[inline]
fn gui_set_style(
&mut self,
control: crate::consts::GuiControl,
property: impl GuiProperty,
value: i32,
) {
unsafe { ffi::GuiSetStyle(control as i32, property.as_i32(), value) }
}
fn gui_set_alpha(&mut self, alpha: f32) {
unsafe {
ffi::GuiSetAlpha(alpha);
}
}
#[inline]
fn gui_get_style(&self, control: crate::consts::GuiControl, property: impl GuiProperty) -> i32 {
unsafe { ffi::GuiGetStyle(control as i32, property.as_i32()) }
}
#[inline]
fn gui_load_style(&mut self, filename: &str) {
let c_filename = CString::new(filename).unwrap();
unsafe { ffi::GuiLoadStyle(c_filename.as_ptr()) }
}
#[inline]
fn gui_load_style_default(&mut self) {
unsafe { ffi::GuiLoadStyleDefault() }
}
#[inline]
fn gui_window_box(&mut self, bounds: impl Into<ffi::Rectangle>, title: &str) -> bool {
let c_filename = CString::new(title).unwrap();
unsafe { ffi::GuiWindowBox(bounds.into(), c_filename.as_ptr()) > 0 }
}
#[inline]
fn gui_group_box(&mut self, bounds: impl Into<ffi::Rectangle>, text: &str) -> bool {
let c_filename = CString::new(text).unwrap();
unsafe { ffi::GuiGroupBox(bounds.into(), c_filename.as_ptr()) > 0 }
}
#[inline]
fn gui_line(&mut self, bounds: impl Into<ffi::Rectangle>, text: &str) -> bool {
let c_filename = CString::new(text).unwrap();
unsafe { ffi::GuiLine(bounds.into(), c_filename.as_ptr()) > 0 }
}
#[inline]
fn gui_panel(&mut self, bounds: impl Into<ffi::Rectangle>, text: &str) -> bool {
let cstr: CString;
let c_text = if text.is_empty() {
std::ptr::null()
} else {
cstr = CString::new(text).unwrap();
cstr.as_ptr()
};
unsafe { ffi::GuiPanel(bounds.into(), c_text) > 0 }
}
#[inline]
fn gui_scroll_panel(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text: &str,
content: impl Into<ffi::Rectangle>,
scroll: impl Into<ffi::Vector2>,
view: impl Into<ffi::Rectangle>,
) -> (bool, Rectangle, Vector2) {
let mut scroll = scroll.into();
let mut view = view.into();
let c_filename = CString::new(text).unwrap();
let result = unsafe {
ffi::GuiScrollPanel(
bounds.into(),
c_filename.as_ptr(),
content.into(),
&mut scroll,
&mut view,
)
};
(result > 0, view.into(), scroll.into())
}
#[inline]
fn gui_label(&mut self, bounds: impl Into<ffi::Rectangle>, text: &str) -> bool {
let c_text = CString::new(text).unwrap();
unsafe { ffi::GuiLabel(bounds.into(), c_text.as_ptr()) > 0 }
}
#[inline]
fn gui_button(&mut self, bounds: impl Into<ffi::Rectangle>, text: &str) -> bool {
let c_text = CString::new(text).unwrap();
unsafe { ffi::GuiButton(bounds.into(), c_text.as_ptr()) > 0 }
}
#[inline]
fn gui_label_button(&mut self, bounds: impl Into<ffi::Rectangle>, text: &str) -> bool {
let c_text = CString::new(text).unwrap();
unsafe { ffi::GuiLabelButton(bounds.into(), c_text.as_ptr()) > 0 }
}
#[inline]
fn gui_toggle(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text: &str,
active: &mut bool,
) -> bool {
let c_text = CString::new(text).unwrap();
unsafe { ffi::GuiToggle(bounds.into(), c_text.as_ptr(), active) > 0 }
}
#[inline]
fn gui_toggle_group(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text: &str,
active: &mut i32,
) -> i32 {
let c_text = CString::new(text).unwrap();
unsafe { ffi::GuiToggleGroup(bounds.into(), c_text.as_ptr(), active) }
}
#[inline]
fn gui_check_box(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text: &str,
checked: &mut bool,
) -> bool {
let c_text = CString::new(text).unwrap();
unsafe { ffi::GuiCheckBox(bounds.into(), c_text.as_ptr(), checked) > 0 }
}
#[inline]
fn gui_combo_box(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text: &str,
active: &mut i32,
) -> i32 {
let c_text = CString::new(text).unwrap();
unsafe { ffi::GuiComboBox(bounds.into(), c_text.as_ptr(), active) }
}
#[inline]
fn gui_dropdown_box(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text: &str,
active: &mut i32,
edit_mode: bool,
) -> bool {
let c_text = CString::new(text).unwrap();
unsafe { ffi::GuiDropdownBox(bounds.into(), c_text.as_ptr(), active, edit_mode) > 0 }
}
#[inline]
fn gui_spinner(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text: &str,
value: &mut i32,
min_value: i32,
max_value: i32,
edit_mode: bool,
) -> bool {
let c_text = CString::new(text).unwrap();
unsafe {
ffi::GuiSpinner(
bounds.into(),
c_text.as_ptr(),
value,
min_value,
max_value,
edit_mode,
) > 0
}
}
#[inline]
fn gui_value_box(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text: &str,
value: &mut i32,
min_value: i32,
max_value: i32,
edit_mode: bool,
) -> bool {
let c_text = CString::new(text).unwrap();
unsafe {
ffi::GuiValueBox(
bounds.into(),
c_text.as_ptr(),
value,
min_value,
max_value,
edit_mode,
) > 0
}
}
#[inline]
fn gui_text_box(
&mut self,
bounds: impl Into<ffi::Rectangle>,
buffer: &mut String,
edit_mode: bool,
) -> bool {
buffer.push('\0');
let (ptr, capacity) = (buffer.as_mut_ptr(), buffer.capacity());
let res = unsafe {
ffi::GuiTextBox(
bounds.into(),
ptr as *mut c_char,
capacity as i32,
edit_mode,
) > 0
};
let cap = buffer.capacity();
let buf = unsafe { std::slice::from_raw_parts(buffer.as_ptr(), cap) };
if let Some(len) = buf.iter().position(|x| *x == b'\0') {
unsafe {
buffer.as_mut_vec().set_len(len);
}
} else {
}
res
}
#[inline]
fn gui_slider(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text_left: &str,
text_right: &str,
value: &mut f32,
min_value: f32,
max_value: f32,
) -> bool {
let c_text_left = CString::new(text_left).unwrap();
let c_text_right = CString::new(text_right).unwrap();
unsafe {
ffi::GuiSlider(
bounds.into(),
c_text_left.as_ptr(),
c_text_right.as_ptr(),
value,
min_value,
max_value,
) > 0
}
}
#[inline]
fn gui_slider_bar(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text_left: &str,
text_right: &str,
value: &mut f32,
min_value: f32,
max_value: f32,
) -> bool {
let c_text_left = CString::new(text_left).unwrap();
let c_text_right = CString::new(text_right).unwrap();
unsafe {
ffi::GuiSliderBar(
bounds.into(),
c_text_left.as_ptr(),
c_text_right.as_ptr(),
value,
min_value,
max_value,
) > 0
}
}
#[inline]
fn gui_progress_bar(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text_left: &str,
text_right: &str,
value: &mut f32,
min_value: f32,
max_value: f32,
) -> bool {
let c_text_left = CString::new(text_left).unwrap();
let c_text_right = CString::new(text_right).unwrap();
unsafe {
ffi::GuiProgressBar(
bounds.into(),
c_text_left.as_ptr(),
c_text_right.as_ptr(),
value,
min_value,
max_value,
) > 0
}
}
#[inline]
fn gui_status_bar(&mut self, bounds: impl Into<ffi::Rectangle>, text: &str) -> bool {
let c_text = CString::new(text).unwrap();
unsafe { ffi::GuiStatusBar(bounds.into(), c_text.as_ptr()) > 0 }
}
#[inline]
fn gui_grid(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text: &str,
spacing: f32,
subdivs: i32,
) -> (bool, Vector2) {
let c_text = CString::new(text).unwrap();
let mut mouse_cell = ffi::Vector2 { x: 0.0, y: 0.0 };
(
unsafe {
ffi::GuiGrid(
bounds.into(),
c_text.as_ptr(),
spacing,
subdivs,
&mut mouse_cell,
) > 0
},
mouse_cell.into(),
)
}
#[inline]
fn gui_list_view(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text: &str,
scroll_index: &mut i32,
active: &mut i32,
) -> i32 {
let c_text = CString::new(text).unwrap();
unsafe { ffi::GuiListView(bounds.into(), c_text.as_ptr(), scroll_index, active) }
}
#[inline]
fn gui_list_view_ex(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text: impl Iterator<Item = impl AsRef<str>>,
scroll_index: &mut i32,
active: &mut i32,
focus: &mut i32,
) -> i32 {
let buffer: Box<[Box<CStr>]> = text
.map(|s| CString::new(s.as_ref()).unwrap().into_boxed_c_str())
.collect();
let mut text_params: Box<[*mut c_char]> = buffer
.iter()
.map(|cstr| cstr.as_ptr() as *mut c_char)
.collect();
unsafe {
ffi::GuiListViewEx(
bounds.into(),
text_params.as_mut_ptr(),
text_params.len() as i32,
scroll_index,
active,
focus,
)
}
}
#[inline]
fn gui_message_box(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text: &str,
message: &str,
buttons: &str,
) -> i32 {
let c_text = CString::new(text).unwrap();
let c_message = CString::new(message).unwrap();
let c_buttons = CString::new(buttons).unwrap();
unsafe {
ffi::GuiMessageBox(
bounds.into(),
c_text.as_ptr(),
c_message.as_ptr(),
c_buttons.as_ptr(),
)
}
}
#[allow(clippy::too_many_arguments)]
#[inline]
fn gui_text_input_box(
&mut self,
bounds: impl Into<ffi::Rectangle>,
title: &str,
message: &str,
buttons: &str,
text: &mut String,
text_max_size: i32,
secret_view_active: &mut bool,
) -> i32 {
text.reserve(text_max_size as usize);
text.push('\0');
let (ptr, capacity) = (text.as_mut_ptr(), text.capacity());
let c_title = CString::new(title).unwrap();
let c_message = CString::new(message).unwrap();
let c_buttons = CString::new(buttons).unwrap();
let btn_index = unsafe {
ffi::GuiTextInputBox(
bounds.into(),
c_title.as_ptr(),
c_message.as_ptr(),
c_buttons.as_ptr(),
ptr as *mut c_char,
capacity as i32,
secret_view_active,
)
};
let cap = text.capacity();
let buf = unsafe { std::slice::from_raw_parts(text.as_ptr(), cap) };
if let Some(len) = buf.iter().position(|x| *x == b'\0') {
unsafe {
text.as_mut_vec().set_len(len);
}
} else {
}
btn_index
}
#[inline]
fn gui_color_picker(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text: &str,
color: impl Into<ffi::Color>,
) -> Color {
let mut out = color.into();
let c_text = CString::new(text).unwrap();
let _result = unsafe { ffi::GuiColorPicker(bounds.into(), c_text.as_ptr(), &mut out) };
out.into()
}
#[inline]
fn gui_icon_text(&mut self, icon_id: crate::consts::GuiIconName, text: &str) -> String {
let c_text = CString::new(text).unwrap();
let buffer = unsafe { ffi::GuiIconText(icon_id as i32, c_text.as_ptr()) };
if buffer.is_null() {
let ptr = c_text.as_ptr();
if ptr.is_null() {
return String::default();
}
return unsafe { CStr::from_ptr(ptr).to_string_lossy().to_string() };
}
let c_str = unsafe { CStr::from_ptr(buffer) };
let str_slice = c_str.to_str().unwrap_or("");
let str_buf = str_slice.to_owned();
str_buf
}
#[inline]
fn gui_color_bar_alpha(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text: &str,
alpha: &mut f32,
) -> bool {
let c_text = CString::new(text).unwrap();
unsafe { ffi::GuiColorBarAlpha(bounds.into(), c_text.as_ptr(), alpha) > 0 }
}
#[inline]
fn gui_toggle_slider(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text: &str,
active: &mut i32,
) -> bool {
let c_text = CString::new(text).unwrap();
unsafe { ffi::GuiToggleSlider(bounds.into(), c_text.as_ptr(), active) > 0 }
}
#[inline]
fn gui_dummy_rec(&mut self, bounds: impl Into<ffi::Rectangle>, text: &str) -> bool {
let c_text = CString::new(text).unwrap();
unsafe { ffi::GuiDummyRec(bounds.into(), c_text.as_ptr()) > 0 }
}
#[inline]
fn gui_color_bar_hue(
&mut self,
bounds: impl Into<ffi::Rectangle>,
text: &str,
value: &mut f32,
) -> bool {
let c_text = CString::new(text).unwrap();
unsafe { ffi::GuiColorBarHue(bounds.into(), c_text.as_ptr(), value) > 0 }
}
}
#[diagnostic::on_unimplemented(
message = "{Self} is not a gui property, or does not implement the GuiProperty trait.",
note = "As of Raylib 5.5, raygui functions that once took \"property enum as i32\" now just take the enum."
)]
pub trait GuiProperty {
#[allow(clippy::wrong_self_convention)]
fn as_i32(self) -> i32;
}
impl GuiProperty for crate::consts::GuiControlProperty {
fn as_i32(self) -> i32 {
self as i32
}
}
impl GuiProperty for crate::consts::GuiDefaultProperty {
fn as_i32(self) -> i32 {
self as i32
}
}
impl GuiProperty for crate::consts::GuiCheckBoxProperty {
fn as_i32(self) -> i32 {
self as i32
}
}
impl GuiProperty for crate::consts::GuiColorPickerProperty {
fn as_i32(self) -> i32 {
self as i32
}
}
impl GuiProperty for crate::consts::GuiComboBoxProperty {
fn as_i32(self) -> i32 {
self as i32
}
}
impl GuiProperty for crate::consts::GuiDropdownBoxProperty {
fn as_i32(self) -> i32 {
self as i32
}
}
impl GuiProperty for crate::consts::GuiListViewProperty {
fn as_i32(self) -> i32 {
self as i32
}
}
impl GuiProperty for crate::consts::GuiProgressBarProperty {
fn as_i32(self) -> i32 {
self as i32
}
}
impl GuiProperty for crate::consts::GuiScrollBarProperty {
fn as_i32(self) -> i32 {
self as i32
}
}
impl GuiProperty for crate::consts::GuiSliderProperty {
fn as_i32(self) -> i32 {
self as i32
}
}
impl GuiProperty for crate::consts::GuiValueBoxProperty {
fn as_i32(self) -> i32 {
self as i32
}
}
impl GuiProperty for crate::consts::GuiToggleProperty {
fn as_i32(self) -> i32 {
self as i32
}
}