--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2026 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#![allow(dead_code)]
+
+use std::ffi::{c_char, c_int, c_void, CString};
+use std::path::Path;
+use crate::ui::{ffi, toolkit, UiContext, UiImage};
+use crate::ui::ffi::{UiImageViewerArgs, UiLabelArgs};
+use crate::ui::label::{Label, LabelCreate};
+use crate::ui::widget::Widget;
+
+#[cfg(unix)]
+fn path_to_cstring(path: &Path) -> Result<CString, std::ffi::NulError> {
+ use std::os::unix::ffi::OsStrExt;
+ CString::new(path.as_os_str().as_bytes())
+}
+
+#[cfg(windows)]
+fn path_to_cstring(path: &Path) -> Result<CString, std::ffi::NulError> {
+ CString::new(path.to_string_lossy().as_bytes())
+}
+
+impl UiImage {
+ pub fn init(&mut self, ctx: &UiContext, name: Option<&str>) {
+ let c_string = name.map(|n| CString::new(n).unwrap());
+ let c_str = c_string.as_ref().map_or(std::ptr::null(), |s| s.as_ptr());
+ unsafe {
+ self.ptr = crate::ui::toolkit::ui_generic_new(ctx.ptr, c_str);
+ }
+ }
+
+ pub fn load_image_file(&mut self, path: &Path) -> Result<(), i32> {
+ if self.ptr.is_null() {
+ return Err(-2);
+ }
+
+ let path_str = match path_to_cstring(path) {
+ Ok(s) => s,
+ Err(_) => return Err(-1),
+ };
+ let ret = unsafe {
+ ui_image_load_file(self.ptr, path_str.as_ptr())
+ };
+
+ if ret == 0 {
+ Ok(())
+ } else {
+ Err(ret)
+ }
+ }
+
+ pub fn image_load_data(&mut self, data: &[u8]) -> Result<(), i32> {
+ let ret = unsafe {
+ ui_image_load_data(self.ptr, data.as_ptr().cast(), data.len())
+ };
+
+ if ret == 0 {
+ Ok(())
+ } else {
+ Err(ret)
+ }
+ }
+}
+
+pub struct ImageViewer {
+ ptr: *mut c_void
+}
+
+impl Widget for ImageViewer {
+ fn get_widget(&self) -> *mut c_void {
+ self.ptr
+ }
+}
+
+pub struct ImageViewerBuilder<'a, T> {
+ args: *mut UiImageViewerArgs,
+ obj: &'a mut toolkit::UiObject<T>,
+}
+
+impl<'a, T> Drop for ImageViewerBuilder<'a, T> {
+ fn drop(&mut self) {
+ unsafe {
+ ui_imageviewer_args_free(self.args);
+ }
+ }
+}
+
+impl<'a, T> ImageViewerBuilder<'a, T> {
+ pub fn create(&mut self) -> ImageViewer {
+ ImageViewer { ptr: unsafe { ui_imageviewer_create(self.obj.ptr, self.args) } }
+ }
+
+ pub fn fill(&mut self, fill: bool) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_fill(self.args, fill as c_int);
+ }
+ self
+ }
+
+ pub fn hexpand(&mut self, value: bool) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_hexpand(self.args, value as c_int);
+ }
+ self
+ }
+
+ pub fn vexpand(&mut self, value: bool) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_vexpand(self.args, value as c_int);
+ }
+ self
+ }
+
+ pub fn hfill(&mut self, value: bool) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_hfill(self.args, value as c_int);
+ }
+ self
+ }
+
+ pub fn vfill(&mut self, value: bool) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_vfill(self.args, value as c_int);
+ }
+ self
+ }
+
+ pub fn override_defaults(&mut self, value: bool) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_override_defaults(self.args, value as c_int);
+ }
+ self
+ }
+
+ pub fn margin(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_margin(self.args, value);
+ }
+ self
+ }
+
+ pub fn margin_left(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_margin_left(self.args, value);
+ }
+ self
+ }
+
+ pub fn margin_right(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_margin_right(self.args, value);
+ }
+ self
+ }
+
+ pub fn margin_top(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_margin_top(self.args, value);
+ }
+ self
+ }
+
+ pub fn margin_bottom(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_margin_bottom(self.args, value);
+ }
+ self
+ }
+
+ pub fn colspan(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_colspan(self.args, value);
+ }
+ self
+ }
+
+ pub fn rowspan(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_rowspan(self.args, value);
+ }
+ self
+ }
+
+ pub fn name(&mut self, value: &str) -> &mut Self {
+ let cstr = CString::new(value).unwrap();
+ unsafe {
+ ui_imageviewer_args_set_name(self.args, cstr.as_ptr());
+ }
+ self
+ }
+
+ pub fn style_class(&mut self, value: &str) -> &mut Self {
+ let cstr = CString::new(value).unwrap();
+ unsafe {
+ ui_imageviewer_args_set_style_class(self.args, cstr.as_ptr());
+ }
+ self
+ }
+
+ pub fn value(&mut self, value: &toolkit::UiImage) -> &mut Self{
+ unsafe {
+ ui_imageviewer_args_set_value(self.args, value.ptr);
+ }
+ self
+ }
+
+ pub fn varname(&mut self, varname: &str) -> &mut Self {
+ let cstr = CString::new(varname).unwrap();
+ unsafe {
+ ui_imageviewer_args_set_varname(self.args, cstr.as_ptr());
+ }
+ self
+ }
+
+ pub fn scrollview(&mut self, enable: bool) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_scrollarea(self.args, enable as c_int);
+ }
+ self
+ }
+
+ pub fn autoscale(&mut self, enable: bool) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_autoscale(self.args, enable as c_int);
+ }
+ self
+ }
+
+ pub fn adjustwidgetsize(&mut self, enable: bool) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_adjustwidgetsize(self.args, enable as c_int);
+ }
+ self
+ }
+
+ pub fn useradjustable(&mut self, enable: bool) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_useradjustable(self.args, enable as c_int);
+ }
+ self
+ }
+
+ pub fn padding(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_image_padding(self.args, value as c_int);
+ }
+ self
+ }
+
+ pub fn padding_left(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_image_padding_left(self.args, value as c_int);
+ }
+ self
+ }
+
+ pub fn padding_right(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_image_padding_right(self.args, value as c_int);
+ }
+ self
+ }
+
+ pub fn padding_top(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_image_padding_top(self.args, value as c_int);
+ }
+ self
+ }
+
+ pub fn padding_bottom(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_image_padding_bottom(self.args, value as c_int);
+ }
+ self
+ }
+
+ pub fn visibility_states(&mut self, states: &[i32]) -> &mut Self {
+ unsafe {
+ ui_imageviewer_args_set_visibility_states(self.args, states.as_ptr(), states.len() as c_int);
+ }
+ self
+ }
+}
+
+/* -------------------------------- C functions -------------------------------- */
+
+unsafe extern "C" {
+ fn ui_image_load_file(obj: *mut ffi::UiGeneric, path: *const c_char) -> c_int;
+ fn ui_image_load_data(obj: *mut ffi::UiGeneric, imgdata: *const c_void, size: libc::size_t) -> c_int;
+
+ fn ui_imageviewer_create(obj: *mut ffi::UiObject, args: *const ffi::UiImageViewerArgs) -> *mut c_void;
+
+ fn ui_imageviewer_args_new() -> *mut UiImageViewerArgs;
+ fn ui_imageviewer_args_set_fill(args: *mut UiImageViewerArgs, fill: c_int);
+ fn ui_imageviewer_args_set_hexpand(args: *mut UiImageViewerArgs, value: c_int);
+ fn ui_imageviewer_args_set_vexpand(args: *mut UiImageViewerArgs, value: c_int);
+ fn ui_imageviewer_args_set_hfill(args: *mut UiImageViewerArgs, value: c_int);
+ fn ui_imageviewer_args_set_vfill(args: *mut UiImageViewerArgs, value: c_int);
+ fn ui_imageviewer_args_set_override_defaults(args: *mut UiImageViewerArgs, value: c_int);
+ fn ui_imageviewer_args_set_margin(args: *mut UiImageViewerArgs, value: c_int);
+ fn ui_imageviewer_args_set_margin_left(args: *mut UiImageViewerArgs, value: c_int);
+ fn ui_imageviewer_args_set_margin_right(args: *mut UiImageViewerArgs, value: c_int);
+ fn ui_imageviewer_args_set_margin_top(args: *mut UiImageViewerArgs, value: c_int);
+ fn ui_imageviewer_args_set_margin_bottom(args: *mut UiImageViewerArgs, value: c_int);
+ fn ui_imageviewer_args_set_colspan(args: *mut UiImageViewerArgs, value: c_int);
+ fn ui_imageviewer_args_set_rowspan(args: *mut UiImageViewerArgs, value: c_int);
+ fn ui_imageviewer_args_set_name(args: *mut UiImageViewerArgs, name: *const c_char);
+ fn ui_imageviewer_args_set_style_class(args: *mut UiImageViewerArgs, classname: *const c_char);
+ fn ui_imageviewer_args_set_style(args: *mut UiImageViewerArgs, style: c_int);
+ fn ui_imageviewer_args_set_value(args: *mut UiImageViewerArgs, value: *mut ffi::UiGeneric);
+ fn ui_imageviewer_args_set_varname(args: *mut UiImageViewerArgs, varname: *const c_char);
+ fn ui_imageviewer_args_set_scrollarea(args: *mut UiImageViewerArgs, fill: c_int);
+ fn ui_imageviewer_args_set_autoscale(args: *mut UiImageViewerArgs, fill: c_int);
+ fn ui_imageviewer_args_set_adjustwidgetsize(args: *mut UiImageViewerArgs, fill: c_int);
+ fn ui_imageviewer_args_set_useradjustable(args: *mut UiImageViewerArgs, fill: c_int);
+ fn ui_imageviewer_args_set_image_padding(args: *mut UiImageViewerArgs, value: c_int);
+ fn ui_imageviewer_args_set_image_padding_left(args: *mut UiImageViewerArgs, value: c_int);
+ fn ui_imageviewer_args_set_image_padding_right(args: *mut UiImageViewerArgs, value: c_int);
+ fn ui_imageviewer_args_set_image_padding_top(args: *mut UiImageViewerArgs, value: c_int);
+ fn ui_imageviewer_args_set_image_padding_bottom(args: *mut UiImageViewerArgs, value: c_int);
+ fn ui_imageviewer_args_set_visibility_states(args: *mut UiImageViewerArgs, states: *const c_int, numstates: c_int);
+ fn ui_imageviewer_args_free(args: *mut UiImageViewerArgs);
+
+ fn ui_imageviewer_reset(widget: *mut c_void);
+ fn ui_imageviewer_set_autoscale(widget: *mut c_void, set: c_int);
+ fn ui_imageviewer_set_adjustwidgetsize(widget: *mut c_void, set: c_int);
+ fn ui_imageviewer_set_useradjustable(widget: *mut c_void, set: c_int);
+}
\ No newline at end of file