rust_widgets 0.9.6

Pure Rust cross-platform native GUI library with hardware-adaptive rendering, 60+ widgets, touch/gesture support, i18n, and SVG-pipeline-accurate output
use super::types::{LinuxHandleKind, LinuxPlatform};
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
use crate::core::MutexExt;
use crate::platform::{WidgetTriggerEvent, WidgetTriggerKind};
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
use gtk::prelude::*;
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
use std::sync::Arc;

impl LinuxPlatform {
    pub(crate) fn create_menu_bar_impl(
        &self,
        parent: u64,
        x: i32,
        y: i32,
        width: u32,
        height: u32,
    ) -> u64 {
        if !matches!(self.kind_of(parent), Some(LinuxHandleKind::Window)) {
            return 0;
        }
        let id = self.insert_widget(LinuxHandleKind::MenuBar, "MenuBar", x, y, width, height);
        #[cfg(all(target_os = "linux", feature = "gtk-native"))]
        {
            let menu_bar = gtk::MenuBar::new();
            let widget = menu_bar.clone().upcast::<gtk::Widget>();
            let mut native = self.native.lock_guard();
            native.menu_bars.insert(id, menu_bar);
            native.widgets.insert(id, widget);
            let _ = parent;
            let _ = (x, y, width, height);
        }
        id
    }
    pub(crate) fn create_menu_impl(
        &self,
        parent: u64,
        text: &str,
        x: i32,
        y: i32,
        width: u32,
        height: u32,
    ) -> u64 {
        if !matches!(self.kind_of(parent), Some(LinuxHandleKind::MenuBar | LinuxHandleKind::Menu)) {
            return 0;
        }
        let id = self.insert_widget(LinuxHandleKind::Menu, text, x, y, width, height);
        self.menus
            .lock()
            .expect("linux menu lock poisoned")
            .menu_children
            .entry(parent)
            .or_default()
            .push(id);
        #[cfg(all(target_os = "linux", feature = "gtk-native"))]
        {
            let menu = gtk::Menu::new();
            let menu_item = gtk::MenuItem::with_label(text);
            menu_item.set_submenu(Some(&menu));
            let mut native = self.native.lock_guard();
            if let Some(menu_bar) = native.menu_bars.get(&parent) {
                menu_bar.append(&menu_item);
            } else if let Some(parent_menu) = native.menus.get(&parent) {
                parent_menu.append(&menu_item);
            }
            native.widgets.insert(id, menu_item.clone().upcast::<gtk::Widget>());
            native.menus.insert(id, menu);
            let _ = (x, y, width, height);
        }
        id
    }
    pub(crate) fn create_tool_bar_impl(
        &self,
        parent: u64,
        x: i32,
        y: i32,
        width: u32,
        height: u32,
    ) -> u64 {
        if !matches!(self.kind_of(parent), Some(LinuxHandleKind::Window)) {
            return 0;
        }
        let id = self.insert_widget(LinuxHandleKind::ToolBar, "ToolBar", x, y, width, height);
        self.menus.lock().expect("linux menu lock poisoned").widget_parent.insert(id, parent);
        #[cfg(all(target_os = "linux", feature = "gtk-native"))]
        {
            let toolbar = gtk::Box::new(gtk::Orientation::Horizontal, 4);
            toolbar.set_size_request(width as i32, height as i32);
            let widget = toolbar.clone().upcast::<gtk::Widget>();
            let mut native = self.native.lock_guard();
            if let Some(container) = native.content_fixed.get(&parent) {
                container.put(&toolbar, x, y);
            }
            native.widgets.insert(id, widget);
        }
        id
    }
    pub(crate) fn create_status_bar_impl(
        &self,
        parent: u64,
        text: &str,
        x: i32,
        y: i32,
        width: u32,
        height: u32,
    ) -> u64 {
        if !matches!(self.kind_of(parent), Some(LinuxHandleKind::Window)) {
            return 0;
        }
        let id = self.insert_widget(LinuxHandleKind::StatusBar, text, x, y, width, height);
        self.menus.lock().expect("linux menu lock poisoned").widget_parent.insert(id, parent);
        #[cfg(all(target_os = "linux", feature = "gtk-native"))]
        {
            let label = gtk::Label::new(Some(text));
            label.set_size_request(width as i32, height as i32);
            let widget = label.clone().upcast::<gtk::Widget>();
            let mut native = self.native.lock_guard();
            if let Some(container) = native.content_fixed.get(&parent) {
                container.put(&label, x, y);
            }
            native.widgets.insert(id, widget);
        }
        id
    }
    pub(crate) fn attach_menu_bar_to_window_impl(&self, window: u64, menu_bar: u64) -> bool {
        if matches!(self.kind_of(window), Some(LinuxHandleKind::Window))
            && matches!(self.kind_of(menu_bar), Some(LinuxHandleKind::MenuBar))
        {
            self.menus
                .lock()
                .expect("linux menu lock poisoned")
                .attached_menu_bar
                .insert(window, menu_bar);
            #[cfg(all(target_os = "linux", feature = "gtk-native"))]
            {
                let native = self.native.lock_guard();
                if let (Some(root), Some(bar)) =
                    (native.root_boxes.get(&window), native.menu_bars.get(&menu_bar))
                {
                    root.pack_start(bar, false, false, 0);
                    root.reorder_child(bar, 0);
                    bar.show_all();
                }
            }
            return true;
        }
        false
    }
    pub(crate) fn menu_add_item_impl(
        &self,
        parent_menu: u64,
        text: &str,
        shortcut: Option<&str>,
    ) -> u64 {
        if !matches!(self.kind_of(parent_menu), Some(LinuxHandleKind::Menu)) {
            return 0;
        }
        let item_id = self.insert_widget(LinuxHandleKind::MenuItem, text, 0, 0, 0, 0);
        let _ = shortcut;
        {
            let mut menus = self.menus.lock().expect("linux menu lock poisoned");
            menus.menu_children.entry(parent_menu).or_default().push(item_id);
        }
        #[cfg(all(target_os = "linux", feature = "gtk-native"))]
        {
            let menu_item = gtk::MenuItem::with_label(text);
            let menus_arc = Arc::clone(&self.menus);
            menu_item.connect_activate(move |_| {
                menus_arc
                    .lock()
                    .expect("linux menu lock poisoned")
                    .pending_menu_events
                    .push_back(item_id);
            });
            let mut native = self.native.lock_guard();
            if let Some(parent) = native.menus.get(&parent_menu) {
                parent.append(&menu_item);
            }
            native.widgets.insert(item_id, menu_item.clone().upcast::<gtk::Widget>());
        }
        item_id
    }
    pub(crate) fn poll_menu_triggered_impl(&self) -> Option<u64> {
        self.menus.lock().expect("linux menu lock poisoned").pending_menu_events.pop_front()
    }
    pub(crate) fn inject_menu_trigger_impl(&self, menu_item_id: u64) -> bool {
        if !matches!(self.kind_of(menu_item_id), Some(LinuxHandleKind::MenuItem)) {
            return false;
        }
        self.menus
            .lock()
            .expect("linux menu lock poisoned")
            .pending_menu_events
            .push_back(menu_item_id);
        true
    }
    pub(crate) fn poll_widget_triggered_impl(&self) -> Option<u64> {
        self.poll_widget_trigger_event_impl().map(|event| event.widget_id)
    }
    pub(crate) fn poll_widget_trigger_event_impl(&self) -> Option<WidgetTriggerEvent> {
        self.menus.lock().expect("linux menu lock poisoned").pending_widget_events.pop_front()
    }
    pub(crate) fn inject_widget_trigger_event_impl(
        &self,
        widget_id: u64,
        kind: WidgetTriggerKind,
    ) -> bool {
        if self.kind_of(widget_id).is_none() {
            return false;
        }
        self.menus
            .lock()
            .expect("linux menu lock poisoned")
            .pending_widget_events
            .push_back(WidgetTriggerEvent { widget_id, kind });
        true
    }
}