Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drawing via DrawHandler prevents gtk::render_* functions from working #229

Open
SolarLiner opened this issue Jul 15, 2020 · 1 comment
Open

Comments

@SolarLiner
Copy link

SolarLiner commented Jul 15, 2020

Using a DrawHandler<_> to perform drawing "the relm way" makes the gtk::render_* functions useless, as they do not draw anything. Furthermore, the StyleContext struct returned by cairo::Context::get_style_context() seems zeroed as it only returns transparent black colors for get_*_color.

For example, gtk::render_background renders the background with respect for the user's GTK theme, which works fine with regular GTK and hooking manually into connnect_draw, does not draw anything when used with relm, which results in the drawing area not being cleared at the beginning of each draw.

gtk-rs example code (works)
use gio::prelude::*;
use gtk::{prelude::*, StateFlags, Window, WindowType};
use std::ops::Deref;
use std::{rc::Rc, time::Instant};

fn main() {
    gtk::init().unwrap();
    let start = Instant::now();
    let window = Window::new(WindowType::Toplevel);
    window.set_title("GTK DrawingArea test");

    let draw_area = gtk::DrawingArea::new();
    let draw_area = Rc::from(draw_area);
    draw_area.connect_draw({
        move |da, cr| {
            let alloc = da.get_allocation();
            let width = alloc.width as f64;
            let height = alloc.height as f64;
            let style = da.get_style_context();
            gtk::render_background(&style, cr, 0.0, 0.0, width, height);

            cr.set_source_rgb(1.0, 0.5, 0.1);
            let t = Instant::now() - start;
            let x = t.as_secs_f64().sin().abs() * width;

            cr.rectangle(x, 0.0, 10., 10.);
            cr.fill();

            let col = style.get_color(StateFlags::NORMAL);
            cr.set_source_rgb(col.red, col.green, col.blue);
            let text = format!("Elapsed: {}.{} s", t.as_secs(), t.subsec_millis());
            cr.move_to(15., 10.);
            cr.show_text(&text);

            gtk::Inhibit(false)
        }
    });

    gtk::timeout_add(16, {
        let draw_area = draw_area.clone();
        move || {
            draw_area.queue_draw();
            Continue(true)
        }
    });

    window.connect_destroy_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });
    window.add(draw_area.deref());
    window.show_all();

    gtk::main();
}
relm code (doesn't work)
fn main() {
    use relm::{interval, DrawHandler, Update, Widget};
    use relm_derive::Msg;
    #[derive(Msg)]
    enum Messages {
        Redraw,
    }

    struct App {
        win: gtk::Window,
        draw_area: gtk::DrawingArea,
        draw_handler: DrawHandler<gtk::DrawingArea>,
        start: Instant,
    }

    impl Update for App {
        type Model = Instant;
        type ModelParam = ();
        type Msg = Messages;

        fn model(relm: &Relm<Self>, param: Self::ModelParam) -> Self::Model {
            Instant::now()
        }

        fn subscriptions(&mut self, _relm: &Relm<Self>) {
            interval(_relm.stream(), 16, || Messages::Redraw);
        }

        fn update(&mut self, event: Self::Msg) {
            match event {
                Messages::Redraw => {
                    let ctx = self.draw_handler.get_context();
                    let style = self.draw_area.get_style_context();
                    let alloc = self.draw_area.get_allocation();
                    let width = alloc.width as f64;
                    let height = alloc.height as f64;

                    gtk::render_background(&style, &ctx, 0.0, 0.0, width, height);

                    ctx.set_source_rgb(1.0, 0.5, 0.1);
                    let t = Instant::now() - self.start;
                    let x = t.as_secs_f64().sin().abs() * width;

                    ctx.rectangle(x, 0.0, 10., 10.);
                    ctx.fill();

                    let col = style.get_color(StateFlags::NORMAL);
                    ctx.set_source_rgb(col.red, col.green, col.blue);
                    let text = format!("Elapsed: {}.{} s", t.as_secs(), t.subsec_millis());
                    ctx.move_to(15., 10.);
                    ctx.show_text(&text);
                }
            }
        }
    }

    impl Widget for App {
        type Root = gtk::Window;

        fn init_view(&mut self) {
            self.win.show_all();
            self.draw_handler.init(&self.draw_area);
        }

        fn root(&self) -> Self::Root {
            self.win.clone()
        }

        fn view(relm: &Relm<Self>, start: Self::Model) -> Self {
            let draw_area = gtk::DrawingArea::new();
            let win = gtk::Window::new(gtk::WindowType::Toplevel);

            win.add(&draw_area);

            Self {
                win,
                draw_area,
                draw_handler: DrawHandler::new().unwrap(),
                start,
            }
        }
    }

    App::run(()).unwrap();
}
Workaround for relm
fn main() {
    use relm::{interval, DrawHandler, Update, Widget};
    use relm_derive::Msg;
    #[derive(Msg)]
    enum Messages {
        Redraw,
    }

    struct App {
        win: gtk::Window,
        draw_area: gtk::DrawingArea,
        //draw_handler: DrawHandler<gtk::DrawingArea>,
        start: Instant,
    }

    impl Update for App {
        type Model = Instant;
        type ModelParam = ();
        type Msg = Messages;

        fn model(relm: &Relm<Self>, param: Self::ModelParam) -> Self::Model {
            Instant::now()
        }

        fn subscriptions(&mut self, _relm: &Relm<Self>) {
            interval(_relm.stream(), 16, || Messages::Redraw);
        }

        fn update(&mut self, event: Self::Msg) {
            match event {
                Messages::Redraw => {
                    self.draw_area.queue_draw();
                    /*let ctx = self.draw_handler.get_context();
                    let style = self.draw_area.get_style_context();
                    let alloc = self.draw_area.get_allocation();
                    let width = alloc.width as f64;
                    let height = alloc.height as f64;

                    gtk::render_background(&style, &ctx, 0.0, 0.0, width, height);

                    ctx.set_source_rgb(1.0, 0.5, 0.1);
                    let t = Instant::now() - self.start;
                    let x = t.as_secs_f64().sin().abs() * width;

                    ctx.rectangle(x, 0.0, 10., 10.);
                    ctx.fill();

                    let col = style.get_color(StateFlags::NORMAL);
                    ctx.set_source_rgb(col.red, col.green, col.blue);
                    let text = format!("Elapsed: {}.{} s", t.as_secs(), t.subsec_millis());
                    ctx.move_to(15., 10.);
                    ctx.show_text(&text);*/
                }
            }
        }
    }

    impl Widget for App {
        type Root = gtk::Window;

        fn init_view(&mut self) {
            self.win.show_all();
            let start = self.start.clone();
            //self.draw_handler.init(&self.draw_area);
            self.draw_area.connect_draw(move |da, cr| {
                let alloc = da.get_allocation();
                let width = alloc.width as f64;
                let height = alloc.height as f64;
                let style = da.get_style_context();
                gtk::render_background(&style, cr, 0.0, 0.0, width, height);

                cr.set_source_rgb(1.0, 0.5, 0.1);
                let t = Instant::now() - start;
                let x = t.as_secs_f64().sin().abs() * width;

                cr.rectangle(x, 0.0, 10., 10.);
                cr.fill();

                let col = style.get_color(StateFlags::NORMAL);
                cr.set_source_rgb(col.red, col.green, col.blue);
                let text = format!("Elapsed: {}.{} s", t.as_secs(), t.subsec_millis());
                cr.move_to(15., 10.);
                cr.show_text(&text);

                gtk::Inhibit(false)
            });
        }

        fn root(&self) -> Self::Root {
            self.win.clone()
        }

        fn view(relm: &Relm<Self>, start: Self::Model) -> Self {
            let draw_area = gtk::DrawingArea::new();
            let win = gtk::Window::new(gtk::WindowType::Toplevel);

            win.add(&draw_area);

            Self {
                win,
                draw_area,
                //draw_handler: DrawHandler::new().unwrap(),
                start,
            }
        }
    }

    App::run(()).unwrap();
}
@antoyo
Copy link
Owner

antoyo commented Jul 15, 2020

This drawing system is not ready yet, but I'll look at this issue when I finish this system.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants