piki-gui 0.2.0

FLTK-based GUI for Piki personal wiki application
Documentation
use crate::draw_context::{DrawContext, FontStyle, FontType};
use fltk::{draw as fltk_draw, enums::*, prelude::*};

/// FLTK implementation of DrawContext
pub struct FltkDrawContext {
    has_focus: bool,
    is_active: bool,
}

impl FltkDrawContext {
    pub fn new(has_focus: bool, is_active: bool) -> Self {
        FltkDrawContext {
            has_focus,
            is_active,
        }
    }

    pub fn from_widget_ptr<T: WidgetExt>(widget: &T) -> Self {
        let has_focus = fltk::app::focus().map(|f| f.as_base_widget()).as_ref()
            == Some(&widget.as_base_widget());

        Self::new(has_focus, widget.active())
    }
}

impl FltkDrawContext {
    fn inner_set_font(&self, font: FontType, style: FontStyle, size: u8) {
        fltk_draw::set_font(
            match font {
                FontType::Content => match style {
                    FontStyle::Regular => Font::Helvetica,
                    FontStyle::Bold => Font::HelveticaBold,
                    FontStyle::Italic => Font::HelveticaItalic,
                    FontStyle::BoldItalic => Font::HelveticaBoldItalic,
                },
                FontType::Code => match style {
                    FontStyle::Regular => Font::Courier,
                    FontStyle::Bold => Font::CourierBold,
                    FontStyle::Italic => Font::CourierItalic,
                    FontStyle::BoldItalic => Font::CourierBoldItalic,
                },
                FontType::Heading => match style {
                    FontStyle::Regular => Font::Helvetica,
                    FontStyle::Bold => Font::HelveticaBold,
                    FontStyle::Italic => Font::HelveticaItalic,
                    FontStyle::BoldItalic => Font::HelveticaBoldItalic,
                },
            },
            size as i32,
        );
    }
}

impl DrawContext for FltkDrawContext {
    fn set_color(&mut self, color: u32) {
        let r = ((color >> 24) & 0xFF) as u8;
        let g = ((color >> 16) & 0xFF) as u8;
        let b = ((color >> 8) & 0xFF) as u8;
        fltk_draw::set_draw_color(Color::from_rgb(r, g, b));
    }

    fn set_font(&mut self, font: FontType, style: FontStyle, size: u8) {
        self.inner_set_font(font, style, size);
    }

    fn draw_text(&mut self, text: &str, x: i32, y: i32) {
        fltk_draw::draw_text(text, x, y);
    }

    fn draw_rect_filled(&mut self, x: i32, y: i32, w: i32, h: i32) {
        fltk_draw::draw_rectf(x, y, w, h);
    }

    fn draw_line(&mut self, x1: i32, y1: i32, x2: i32, y2: i32) {
        fltk_draw::draw_line(x1, y1, x2, y2);
    }

    fn text_width(&mut self, text: &str, font: FontType, style: FontStyle, size: u8) -> f64 {
        self.set_font(font, style, size);
        fltk_draw::width(text)
    }

    fn text_height(&self, font: FontType, style: FontStyle, size: u8) -> i32 {
        self.inner_set_font(font, style, size);
        fltk_draw::height()
    }

    fn text_descent(&self, font: FontType, style: FontStyle, size: u8) -> i32 {
        self.inner_set_font(font, style, size);
        fltk_draw::descent()
    }

    fn push_clip(&mut self, x: i32, y: i32, w: i32, h: i32) {
        fltk_draw::push_clip(x, y, w, h);
    }

    fn pop_clip(&mut self) {
        fltk_draw::pop_clip();
    }

    fn color_average(&self, c1: u32, c2: u32, weight: f32) -> u32 {
        let r1 = ((c1 >> 24) & 0xFF) as f32;
        let g1 = ((c1 >> 16) & 0xFF) as f32;
        let b1 = ((c1 >> 8) & 0xFF) as f32;

        let r2 = ((c2 >> 24) & 0xFF) as f32;
        let g2 = ((c2 >> 16) & 0xFF) as f32;
        let b2 = ((c2 >> 8) & 0xFF) as f32;

        let r = (r1 * (1.0 - weight) + r2 * weight) as u32;
        let g = (g1 * (1.0 - weight) + g2 * weight) as u32;
        let b = (b1 * (1.0 - weight) + b2 * weight) as u32;

        (r << 24) | (g << 16) | (b << 8) | 0xFF
    }

    fn color_contrast(&self, _fg: u32, bg: u32) -> u32 {
        let r = ((bg >> 24) & 0xFF) as f32;
        let g = ((bg >> 16) & 0xFF) as f32;
        let b = ((bg >> 8) & 0xFF) as f32;

        let brightness = (r * 0.299 + g * 0.587 + b * 0.114) / 255.0;

        if brightness > 0.5 {
            0x000000FF // Black
        } else {
            0xFFFFFFFF // White
        }
    }

    fn color_inactive(&self, c: u32) -> u32 {
        let r = ((c >> 24) & 0xFF) as f32;
        let g = ((c >> 16) & 0xFF) as f32;
        let b = ((c >> 8) & 0xFF) as f32;

        let gray = (r + g + b) / 3.0;
        let r = (r * 0.5 + gray * 0.5) as u32;
        let g = (g * 0.5 + gray * 0.5) as u32;
        let b = (b * 0.5 + gray * 0.5) as u32;

        (r << 24) | (g << 16) | (b << 8) | 0xFF
    }

    fn has_focus(&self) -> bool {
        self.has_focus
    }

    fn is_active(&self) -> bool {
        self.is_active
    }
}