///|
pub using @sys {
TRAYENTRY_BUTTON,
TRAYENTRY_CHECKBOX,
TRAYENTRY_SUBMENU,
TRAYENTRY_DISABLED,
TRAYENTRY_CHECKED,
}
///|
let call_tray_callback : FuncRef[(() -> Unit) -> Unit] = fn(callback) {
callback()
}
///|
priv trait MenuElement {
fn insert(Self, TrayMenu, Int) -> Unit raise SdlError
}
///|
pub struct Menu {
priv elements : Array[&MenuElement]
}
///|
pub fn Menu::Menu() -> Self {
{ elements: [] }
}
///|
pub fn Menu::button(
self : Self,
label~ : String,
on_click? : () -> Unit,
enabled? : Bool = true,
) -> Self {
let mut flags = TRAYENTRY_BUTTON
if !enabled {
flags = flags + TRAYENTRY_DISABLED
}
self.elements.push(Button::{ label, flags, on_click })
self
}
///|
pub fn Menu::checkbox(
self : Self,
label~ : String,
on_click? : () -> Unit,
checked? : Bool = false,
enabled? : Bool = true,
) -> Self {
let mut flags = TRAYENTRY_CHECKBOX
if checked {
flags = flags + TRAYENTRY_CHECKED
}
if !enabled {
flags = flags + TRAYENTRY_DISABLED
}
self.elements.push(Checkbox::{ label, flags, on_click })
self
}
///|
pub fn Menu::separator(self : Self) -> Self {
self.elements.push(Separator::{ })
self
}
///|
pub fn Menu::submenu(self : Self, label~ : String, menu~ : Menu) -> Self {
self.elements.push(Submenu::{ label, menu })
self
}
///|
pub fn Menu::append(self : Self, menu : Menu) -> Self {
self.elements.append(menu.elements)
self
}
///|
priv struct Button {
label : String
flags : UInt
on_click : (() -> Unit)?
}
///|
impl MenuElement for Button with fn insert(self, menu, pos) {
let element = menu.insert_entry(@utf8.encode(self.label), self.flags, pos~)
element.set_on_click(self.on_click)
}
///|
priv struct Checkbox {
label : String
flags : UInt
on_click : (() -> Unit)?
}
///|
impl MenuElement for Checkbox with fn insert(self, menu, pos) {
let element = menu.insert_entry(@utf8.encode(self.label), self.flags, pos~)
element.set_on_click(self.on_click)
}
///|
priv struct Separator {}
///|
impl MenuElement for Separator with fn insert(_self, menu, pos) {
menu.insert_entry([], 0, pos~) |> ignore
}
///|
priv struct Submenu {
label : String
menu : Menu
}
///|
impl MenuElement for Submenu with fn insert(self, menu, pos) {
let entry = menu.insert_entry(
@utf8.encode(self.label),
TRAYENTRY_SUBMENU,
pos~,
)
entry.submenu().insert_menu(self.menu)
}
///|
priv struct TrayContext {
callback_handles : Array[@sys.TrayEntryCallback]
}
///|
struct Tray {
raw : @sys.Tray
context : TrayContext
}
///|
pub fn Tray::Tray(tooltip~ : String, menu? : Menu) -> Tray raise SdlError {
let raw = @sys.create_tray(@utf8.encode(tooltip))
if raw.is_null() {
raise_last_error("SDL_CreateTray")
}
let tray : Tray = { raw, context: { callback_handles: [] } }
if menu is Some(menu) {
tray.append(menu)
}
tray
}
///|
pub fn Tray::destroy(self : Self) -> Unit {
@sys.destroy_tray(self.raw)
}
///|
pub fn Tray::set_tooltip(self : Self, tooltip : String) -> Unit {
@sys.set_tray_tooltip(self.raw, @utf8.encode(tooltip))
}
///|
pub fn Tray::append(self : Self, menu : Menu) -> Unit raise SdlError {
self.menu().insert_menu(menu)
}
///|
fn Tray::menu(self : Self) -> TrayMenu raise SdlError {
let existing = @sys.get_tray_menu(self.raw)
if !existing.is_null() {
return { raw: existing, context: self.context }
}
let raw = @sys.create_tray_menu(self.raw)
if raw.is_null() {
raise_last_error("SDL_CreateTrayMenu")
}
{ raw, context: self.context }
}
///|
pub fn Tray::raw(self : Self) -> @sys.Tray {
self.raw
}
///|
priv struct TrayMenu {
raw : @sys.TrayMenu
context : TrayContext
}
///|
fn TrayMenu::insert_menu(
self : Self,
menu : Menu,
pos? : Int = -1,
) -> Unit raise SdlError {
for i, element in menu.elements {
let element_pos = if pos < 0 { -1 } else { pos + i }
element.insert(self, element_pos)
}
}
///|
fn TrayMenu::insert_entry(
self : Self,
label : Bytes,
flags : UInt,
pos? : Int = -1,
) -> TrayEntry raise SdlError {
let raw = @sys.insert_tray_entry_at(self.raw, pos, label, flags)
if raw.is_null() {
raise_last_error("SDL_InsertTrayEntryAt")
}
{ raw, context: self.context }
}
///|
priv struct TrayEntry {
raw : @sys.TrayEntry
context : TrayContext
}
///|
fn TrayEntry::set_on_click(self : Self, callback : (() -> Unit)?) -> Unit {
if callback is Some(callback) {
let handle = @sys.make_tray_entry_callback(call_tray_callback, callback)
self.context.callback_handles.push(handle)
@sys.set_tray_entry_callback(self.raw, handle)
}
}
///|
fn TrayEntry::submenu(self : Self) -> TrayMenu raise SdlError {
let existing = @sys.get_tray_submenu(self.raw)
if !existing.is_null() {
return { raw: existing, context: self.context }
}
let raw = @sys.create_tray_submenu(self.raw)
if raw.is_null() {
raise_last_error("SDL_CreateTraySubmenu")
}
{ raw, context: self.context }
}
///|
pub fn Tray::update() -> Unit {
@sys.update_trays()
}