use crate::app::{font_index, FONTS};
use crate::prelude::{FltkError, FltkErrorKind};
use crate::utils::{self, FlString};
use fltk_sys::fl;
use std::{
ffi::{CStr, CString},
mem, path,
};
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum LabelType {
Normal = 0,
None,
Shadow,
Engraved,
Embossed,
}
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ColorDepth {
L8 = 1,
La8 = 2,
Rgb8 = 3,
Rgba8 = 4,
}
impl ColorDepth {
pub fn from_u8(val: u8) -> Result<ColorDepth, FltkError> {
if !(1..=4).contains(&val) {
Err(FltkError::Internal(FltkErrorKind::FailedOperation))
} else {
Ok(unsafe { mem::transmute(val) })
}
}
}
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum FrameType {
NoBox = 0,
FlatBox,
UpBox,
DownBox,
UpFrame,
DownFrame,
ThinUpBox,
ThinDownBox,
ThinUpFrame,
ThinDownFrame,
EngravedBox,
EmbossedBox,
EngravedFrame,
EmbossedFrame,
BorderBox,
ShadowBox,
BorderFrame,
ShadowFrame,
RoundedBox,
RShadowBox,
RoundedFrame,
RFlatBox,
RoundUpBox,
RoundDownBox,
DiamondUpBox,
DiamondDownBox,
OvalBox,
OShadowBox,
OvalFrame,
OFlatFrame,
PlasticUpBox,
PlasticDownBox,
PlasticUpFrame,
PlasticDownFrame,
PlasticThinUpBox,
PlasticThinDownBox,
PlasticRoundUpBox,
PlasticRoundDownBox,
GtkUpBox,
GtkDownBox,
GtkUpFrame,
GtkDownFrame,
GtkThinUpBox,
GtkThinDownBox,
GtkThinUpFrame,
GtkThinDownFrame,
GtkRoundUpFrame,
GtkRoundDownFrame,
GleamUpBox,
GleamDownBox,
GleamUpFrame,
GleamDownFrame,
GleamThinUpBox,
GleamThinDownBox,
GleamRoundUpBox,
GleamRoundDownBox,
FreeBoxType,
}
impl FrameType {
pub const OFlatBox: FrameType = FrameType::OFlatFrame;
pub const GtkRoundDownBox: FrameType = FrameType::GtkRoundDownFrame;
pub fn by_index(idx: usize) -> FrameType {
let idx = if idx > 56 { 56 } else { idx };
unsafe { mem::transmute(idx as i32) }
}
pub fn dx(self) -> i32 {
unsafe { fl::Fl_box_dx(self as i32) }
}
pub fn dy(self) -> i32 {
unsafe { fl::Fl_box_dy(self as i32) }
}
pub fn dw(self) -> i32 {
unsafe { fl::Fl_box_dw(self as i32) }
}
pub fn dh(self) -> i32 {
unsafe { fl::Fl_box_dh(self as i32) }
}
pub fn swap_frames(old_frame: FrameType, new_frame: FrameType) {
unsafe {
let new_frame = new_frame as i32;
let old_frame = old_frame as i32;
fl::Fl_set_box_type(old_frame, new_frame);
}
}
}
bitflags::bitflags! {
pub struct Align: i32 {
const Center = 0x0000;
const Top = 0x0001;
const Bottom = 0x0002;
const Left = 0x0004;
const Right = 0x0008;
const Inside = 0x0010;
const TextOverImage = 0x0020;
const Clip = 0x0040;
const Wrap = 0x0080;
const ImageNextToText = 0x0100;
const TextNextToImage = 0x0120;
const ImageBackdrop = 0x0200;
const TopLeft = 0x0001 | 0x0004;
const TopRight = 0x0001 | 0x0008;
const BottomLeft = 0x0002 | 0x0004;
const BottomRight = 0x0002 | 0x0008;
const LeftTop = 0x0007;
const RightTop = 0x000B;
const LeftBottom = 0x000D;
const RightBottom = 0x000E;
const PositionMask = 0x000F;
const ImageMask = 0x0320;
}
}
bitflags::bitflags! {
pub struct Font: i32 {
const Helvetica = 0;
const HelveticaBold = 1;
const HelveticaItalic = 2;
const HelveticaBoldItalic = 3;
const Courier = 4;
const CourierBold = 5;
const CourierItalic = 6;
const CourierBoldItalic = 7;
const Times = 8;
const TimesBold = 9;
const TimesItalic = 10;
const TimesBoldItalic = 11;
const Symbol = 12;
const Screen = 13;
const ScreenBold = 14;
const Zapfdingbats = 15;
}
}
impl Font {
pub fn by_index(idx: usize) -> Font {
if idx < (FONTS.lock().unwrap()).len() {
unsafe { mem::transmute(idx as i32) }
} else {
Font::Helvetica
}
}
pub fn by_name(name: &str) -> Font {
match font_index(name) {
Some(val) => Font::by_index(val),
None => Font::Helvetica,
}
}
pub fn set_font(old: Font, new: &str) {
let new = CString::safe_new(new);
unsafe {
fl::Fl_set_font2(old.bits, new.into_raw() as _);
}
}
pub fn load_font<P: AsRef<path::Path>>(path: P) -> Result<String, FltkError> {
Font::load_font_(path.as_ref())
}
fn load_font_(path: &path::Path) -> Result<String, FltkError> {
unsafe {
if !path.exists() {
return Err::<String, FltkError>(FltkError::Internal(
FltkErrorKind::ResourceNotFound,
));
}
if let Some(p) = path.to_str() {
let font_data = std::fs::read(path)?;
let face = match ttf_parser::Face::parse(&font_data, 0) {
Ok(f) => f,
Err(_) => {
return Err(FltkError::Internal(FltkErrorKind::FailedOperation));
}
};
let family_name = face
.names()
.into_iter()
.find(|name| {
name.name_id == ttf_parser::name_id::FULL_NAME && name.is_unicode()
})
.and_then(|name| name.to_string());
let path = CString::safe_new(p);
let ret = fl::Fl_load_font(path.as_ptr());
if let Some(family_name) = family_name {
if ret > 0 {
Ok(family_name)
} else {
Err(FltkError::Internal(FltkErrorKind::FailedOperation))
}
} else {
Err(FltkError::Internal(FltkErrorKind::FailedOperation))
}
} else {
Err(FltkError::Internal(FltkErrorKind::FailedOperation))
}
}
}
pub fn get_name(&self) -> String {
unsafe {
CStr::from_ptr(fl::Fl_get_font_name(self.bits as i32))
.to_string_lossy()
.to_string()
}
}
}
bitflags::bitflags! {
pub struct Color: u32 {
const ForeGround = 0;
const Foreground = 0;
const BackGround2 = 7;
const Background2 = 7;
const Inactive = 8;
const Selection = 15;
const Free = 16;
const Gray0 = 32;
const GrayRamp = 32;
const Dark3 = 39;
const Dark2 = 45;
const Dark1 = 47;
const FrameDefault = 49;
const BackGround = 49;
const Background = 49;
const Light1 = 50;
const Light2 = 52;
const Light3 = 54;
const Black = 56;
const Red = 88;
const Green = 63;
const Yellow = 95;
const Blue = 216;
const Magenta = 248;
const Cyan = 223;
const DarkRed = 72;
const DarkGreen = 60;
const DarkYellow = 76;
const DarkBlue = 136;
const DarkMagenta = 152;
const DarkCyan = 140;
const White = 255;
}
}
impl Color {
pub const fn from_rgb(r: u8, g: u8, b: u8) -> Color {
let r = r as u32;
let g = g as u32;
let b = b as u32;
let val: u32 = ((r & 0xff) << 24) + ((g & 0xff) << 16) + ((b & 0xff) << 8);
Color::from_rgbi(val)
}
#[cfg(feature = "enable-glwindow")]
pub const fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Color {
let r = r as u32;
let g = g as u32;
let b = b as u32;
let a = a as u32;
let val: u32 = ((r & 0xff) << 24) + ((g & 0xff) << 16) + ((b & 0xff) << 8) + (a & 0xff);
Color::from_rgbi(val)
}
pub const fn from_rgbi(val: u32) -> Color {
let mut c = Color::Black;
c.bits = val;
c
}
pub fn from_rgba_tuple(tup: (u8, u8, u8, u8)) -> Color {
if tup.3 != 255 {
let bg_col = if let Some(grp) = crate::group::Group::try_current() {
use crate::prelude::WidgetExt;
grp.color()
} else {
Color::BackGround
};
let bg_col = bg_col.to_rgb();
let alpha = tup.3 as f32 / 255.0;
let r = alpha * tup.0 as f32 + (1.0 - alpha) * bg_col.0 as f32;
let r = r as u8;
let g = alpha * tup.1 as f32 + (1.0 - alpha) * bg_col.1 as f32;
let g = g as u8;
let b = alpha * tup.2 as f32 + (1.0 - alpha) * bg_col.2 as f32;
let b = b as u8;
Color::from_rgb(r, g, b)
} else {
Color::from_rgb(tup.0, tup.1, tup.2)
}
}
pub const fn from_u32(val: u32) -> Color {
#[cfg(feature = "enable-glwindow")]
{
let (r, g, b, a) = utils::hex2rgba(val);
Color::from_rgba(r, g, b, a)
}
#[cfg(not(feature = "enable-glwindow"))]
{
let (r, g, b) = utils::hex2rgb(val);
Color::from_rgb(r, g, b)
}
}
pub const fn from_hex(val: u32) -> Color {
Color::from_u32(val)
}
pub fn from_hex_str(col: &str) -> Result<Color, FltkError> {
if !col.starts_with('#') || col.len() < 7 {
return Err(FltkError::Internal(FltkErrorKind::InvalidColor));
}
let color: Color;
#[cfg(not(feature = "enable-glwindow"))]
{
color = Color::from_hex(u32::from_str_radix(&col[1..7], 16)?);
}
#[cfg(feature = "enable-glwindow")]
{
color = Color::from_hex(u32::from_str_radix(&col[1..9], 16)?);
}
Ok(color)
}
pub fn to_hex_str(&self) -> String {
#[cfg(not(feature = "enable-glwindow"))]
{
let (r, g, b) = self.to_rgb();
format!("#{:02x}{:02x}{:02x}", r, g, b)
}
#[cfg(feature = "enable-glwindow")]
{
let (r, g, b, a) = self.to_rgba();
format!("#{:02x}{:02x}{:02x}{:02x}", r, g, b, a)
}
}
pub fn by_index(idx: u8) -> Color {
unsafe { mem::transmute(idx as u32) }
}
pub fn inactive(&self) -> Color {
unsafe { mem::transmute(fl::Fl_inactive(self.bits)) }
}
pub fn darker(&self) -> Color {
unsafe { mem::transmute(fl::Fl_darker(self.bits)) }
}
pub fn lighter(&self) -> Color {
unsafe { mem::transmute(fl::Fl_lighter(self.bits)) }
}
pub fn gray_ramp(val: i32) -> Color {
unsafe { mem::transmute(fl::Fl_gray_ramp(val)) }
}
pub fn color_average(c1: Color, c2: Color, weight: f32) -> Color {
unsafe { mem::transmute(fl::Fl_color_average(c1.bits, c2.bits, weight)) }
}
pub fn contrast(fg: Color, bg: Color) -> Color {
unsafe { mem::transmute(fl::Fl_contrast(fg.bits, bg.bits)) }
}
pub fn gray_scale(g: u8) -> Color {
unsafe { mem::transmute(fl::Fl_rgb_color2(g)) }
}
pub fn rgb_color(r: u8, g: u8, b: u8) -> Color {
unsafe { mem::transmute(fl::Fl_rgb_color(r, g, b)) }
}
pub fn to_rgb(&self) -> (u8, u8, u8) {
unsafe {
let val = self.bits;
let r = ((val >> 24) & 0xff) as u8;
let g = ((val >> 16) & 0xff) as u8;
let b = ((val >> 8) & 0xff) as u8;
let i = (val & 0xff) as u8;
if i == 0 {
(r, g, b)
} else {
let val = fl::Fl_cmap(val);
let r = ((val >> 24) & 0xff) as u8;
let g = ((val >> 16) & 0xff) as u8;
let b = ((val >> 8) & 0xff) as u8;
(r, g, b)
}
}
}
#[cfg(feature = "enable-glwindow")]
pub fn to_rgba(&self) -> (u8, u8, u8, u8) {
let val = self.bits;
let r = ((val >> 24) & 0xff) as u8;
let g = ((val >> 16) & 0xff) as u8;
let b = ((val >> 8) & 0xff) as u8;
let a = (val & 0xff) as u8;
(r, g, b, a)
}
}
#[allow(unreachable_patterns)]
impl std::fmt::Display for Color {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
Color::ForeGround => write!(f, "Color::ForeGround"),
Color::BackGround => write!(f, "Color::BackGround"),
Color::BackGround2 => write!(f, "Color::BackGround2"),
Color::Foreground => write!(f, "Color::Foreground"),
Color::Background => write!(f, "Color::Background"),
Color::Background2 => write!(f, "Color::Background2"),
Color::Inactive => write!(f, "Color::Inactive"),
Color::Selection => write!(f, "Color::Selection"),
Color::Gray0 => write!(f, "Color::Gray0"),
Color::Dark3 => write!(f, "Color::Dark3"),
Color::Dark2 => write!(f, "Color::Dark2"),
Color::Dark1 => write!(f, "Color::Dark1"),
Color::FrameDefault => write!(f, "Color::FrameDefault"),
Color::Light1 => write!(f, "Color::Light1"),
Color::Light2 => write!(f, "Color::Light2"),
Color::Light3 => write!(f, "Color::Light3"),
Color::Black => write!(f, "Color::Black"),
Color::Red => write!(f, "Color::Red"),
Color::Green => write!(f, "Color::Green"),
Color::Yellow => write!(f, "Color::Yellow"),
Color::Blue => write!(f, "Color::Blue"),
Color::Magenta => write!(f, "Color::Magenta"),
Color::Cyan => write!(f, "Color::Cyan"),
Color::DarkRed => write!(f, "Color::DarkRed"),
Color::DarkGreen => write!(f, "Color::DarkGreen"),
Color::DarkYellow => write!(f, "Color::DarkYellow"),
Color::DarkBlue => write!(f, "Color::DarkBlue"),
Color::DarkMagenta => write!(f, "Color::DarkMagenta"),
Color::DarkCyan => write!(f, "Color::DarkCyan"),
Color::White => write!(f, "Color::White"),
_ => {
let temp = format!("{:08x}", self.bits);
write!(f, "Color::from_hex(0x{})", &temp[0..6])
}
}
}
}
bitflags::bitflags! {
pub struct Event: i32 {
const NoEvent = 0;
const Push = 1;
const Released = 2;
const Enter = 3;
const Leave = 4;
const Drag = 5;
const Focus = 6;
const Unfocus = 7;
const KeyDown = 8;
const KeyUp = 9;
const Close = 10;
const Move = 11;
const Shortcut = 12;
const Deactivate = 13;
const Activate = 14;
const Hide = 15;
const Show = 16;
const Paste = 17;
const SelectionClear = 18;
const MouseWheel = 19;
const DndEnter = 20;
const DndDrag = 21;
const DndLeave = 22;
const DndRelease = 23;
const ScreenConfigChanged = 24;
const Fullscreen = 25;
const ZoomGesture = 26;
const ZoomEvent = 27;
const Resize = 28;
}
}
impl Event {
pub const fn from_i32(val: i32) -> Event {
let mut ev = Event::NoEvent;
ev.bits = val;
ev
}
}
impl From<i32> for Event {
fn from(val: i32) -> Event {
Event::from_i32(val)
}
}
#[allow(unreachable_patterns)]
impl std::fmt::Display for Event {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
Event::NoEvent => write!(f, "Event::NoEvent"),
Event::Push => write!(f, "Event::Push"),
Event::Released => write!(f, "Event::Released"),
Event::Enter => write!(f, "Event::Enter"),
Event::Leave => write!(f, "Event::Leave"),
Event::Drag => write!(f, "Event::Drag"),
Event::Focus => write!(f, "Event::Focus"),
Event::Unfocus => write!(f, "Event::Unfocus"),
Event::KeyDown => write!(f, "Event::KeyDown"),
Event::KeyUp => write!(f, "Event::KeyUp"),
Event::Close => write!(f, "Event::Close"),
Event::Move => write!(f, "Event::Move"),
Event::Shortcut => write!(f, "Event::Shortcut"),
Event::Deactivate => write!(f, "Event::Deactivate"),
Event::Activate => write!(f, "Event::Activate"),
Event::Hide => write!(f, "Event::Hide"),
Event::Show => write!(f, "Event::Show"),
Event::Paste => write!(f, "Event::Paste"),
Event::SelectionClear => write!(f, "Event::SelectionClear"),
Event::MouseWheel => write!(f, "Event::MouseWheel"),
Event::DndEnter => write!(f, "Event::DndEnter"),
Event::DndDrag => write!(f, "Event::DndDrag"),
Event::DndLeave => write!(f, "Event::DndLeave"),
Event::DndRelease => write!(f, "Event::DndRelease"),
Event::ScreenConfigChanged => write!(f, "Event::ScreenConfigChanged"),
Event::Fullscreen => write!(f, "Event::Fullscreen"),
Event::ZoomGesture => write!(f, "Event::ZoomGesture"),
Event::ZoomEvent => write!(f, "Event::ZoomEvent"),
Event::Resize => write!(f, "Event::Resize"),
_ => {
write!(f, "Event::from_i32({})", self.bits)
}
}
}
}
bitflags::bitflags! {
pub struct Key: i32 {
const None = 0;
const Button = 0xfee8;
const BackSpace = 0xff08;
const Tab = 0xff09;
const IsoKey = 0xff0c;
const Enter = 0xff0d;
const Pause = 0xff13;
const ScrollLock = 0xff14;
const Escape = 0xff1b;
const Kana = 0xff2e;
const Eisu = 0xff2f;
const Yen = 0xff30;
const JISUnderscore = 0xff31;
const Home = 0xff50;
const Left = 0xff51;
const Up = 0xff52;
const Right = 0xff53;
const Down = 0xff54;
const PageUp = 0xff55;
const PageDown = 0xff56;
const End = 0xff57;
const Print = 0xff61;
const Insert = 0xff63;
const Menu = 0xff67;
const Help = 0xff68;
const NumLock = 0xff7f;
const KP = 0xff80;
const KPEnter = 0xff8d;
const KPLast = 0xffbd;
const F1 = 0xffbd + 1;
const F2 = 0xffbd + 2;
const F3 = 0xffbd + 3;
const F4 = 0xffbd + 4;
const F5 = 0xffbd + 5;
const F6 = 0xffbd + 6;
const F7 = 0xffbd + 7;
const F8 = 0xffbd + 8;
const F9 = 0xffbd + 9;
const F10 = 0xffbd + 10;
const F11 = 0xffbd + 11;
const F12 = 0xffbd + 12;
const FLast = 0xffe0;
const ShiftL = 0xffe1;
const ShiftR = 0xffe2;
const ControlL = 0xffe3;
const ControlR = 0xffe4;
const CapsLock = 0xffe5;
const MetaL = 0xffe7;
const MetaR = 0xffe8;
const AltL = 0xffe9;
const AltR = 0xffea;
const Delete = 0xffff;
}
}
impl Key {
pub const fn from_i32(val: i32) -> Key {
let mut k = Key::None;
k.bits = val;
k
}
pub const fn from_char(val: char) -> Key {
let mut k = Key::None;
k.bits = val as i32;
k
}
pub const fn to_char(&self) -> Option<char> {
let bits = self.bits;
if bits >= 0xD800 && bits <= 0xDFFF {
None
} else {
Some(bits as u8 as char)
}
}
pub const fn is_fn_key(key: Key) -> bool {
key.bits() >= Key::F1.bits() && key.bits() < Key::FLast.bits()
}
pub const fn fn_key(val: i32) -> Key {
Key::from_i32(Key::F1.bits() - 1 + val)
}
}
bitflags::bitflags! {
pub struct Shortcut: i32 {
const None = 0;
const Shift = 0x0001_0000;
const CapsLock = 0x0002_0000;
const Ctrl = 0x0004_0000;
const Alt = 0x0008_0000;
const Meta = 0x0040_0000;
const Command = if cfg!(target_os = "macos") {
Shortcut::Meta.bits
} else {
Shortcut::Ctrl.bits
};
const Control = if cfg!(target_os = "macos") {
Shortcut::Ctrl.bits
} else {
Shortcut::Meta.bits
};
const Button1 = 0x0100_0000;
const Button2 = 0x0200_0000;
const Button3 = 0x0400_0000;
const Buttons = 0x7f00_0000;
}
}
pub type EventState = Shortcut;
impl Shortcut {
pub const fn from_char(c: char) -> Shortcut {
let mut s = Shortcut::None;
s.bits = c as _;
s
}
pub const fn from_key(k: Key) -> Shortcut {
let mut s = Shortcut::None;
s.bits = k.bits();
s
}
pub const fn from_i32(v: i32) -> Shortcut {
let mut s = Shortcut::None;
s.bits = v;
s
}
pub const fn key(&self) -> Key {
let mut temp = self.bits;
temp &= 0x0000_ffff;
Key::from_i32(temp)
}
pub const fn button(button_num: i32) -> Shortcut {
let mut s = Shortcut::None;
s.bits = 0x0080_0000 << button_num;
s
}
}
bitflags::bitflags! {
pub struct CallbackTrigger: i32 {
const Never = 0;
const Changed = 1;
const NotChanged = 2;
const Release = 4;
const ReleaseAlways = 6;
const EnterKey = 8;
const EnterKeyAlways = 10;
const EnterKeyChanged = 11;
const Closed = 16;
}
}
#[repr(i32)]
#[non_exhaustive]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum CallbackReason {
Unknown,
Selected,
Deselected,
Reselected,
Opened,
Closed,
Dragged,
Cancelled,
Changed,
GotFocus,
LostFocus,
Released,
}
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Cursor {
Default = 0,
Arrow = 35,
Cross = 66,
Wait = 76,
Insert = 77,
Hand = 31,
Help = 47,
Move = 27,
NS = 78,
WE = 79,
NWSE = 80,
NESW = 81,
N = 70,
NE = 69,
E = 49,
SE = 8,
S = 9,
SW = 7,
W = 36,
NW = 68,
None = 255,
}
bitflags::bitflags! {
pub struct Mode: i32 {
const Rgb = 0;
const Single = 0;
const Index = 1;
const Double = 2;
const Accum = 4;
const Alpha = 8;
const Depth = 16;
const Stencil = 32;
const Rgb8 = 64;
const MultiSample = 128;
const Stereo = 256;
const FakeSingle = 512; const Opengl3 = 1024;
}
}
bitflags::bitflags! {
pub struct Damage: u8 {
const None = 0x00;
const Child = 0x01;
const Expose = 0x02;
const Scroll = 0x04;
const Overlay = 0x08;
const User1 = 0x10;
const User2 = 0x20;
const All = 0x80;
}
}
impl std::ops::BitOr<char> for Shortcut {
type Output = Shortcut;
fn bitor(self, other: char) -> Self::Output {
unsafe { mem::transmute(self.bits as i32 | other as i32) }
}
}
impl std::ops::BitOr<Key> for Shortcut {
type Output = Shortcut;
fn bitor(self, other: Key) -> Self::Output {
unsafe { mem::transmute(self.bits as i32 | other.bits() as i32) }
}
}
impl std::ops::BitOr<i32> for Align {
type Output = Align;
fn bitor(self, rhs: i32) -> Self::Output {
unsafe { mem::transmute(self.bits | rhs as i32) }
}
}