add backend

This commit is contained in:
sleptworld 2023-04-27 18:29:47 +08:00
parent 038a25948f
commit 13dda7c316
11 changed files with 175 additions and 47 deletions

7
Cargo.lock generated
View File

@ -122,6 +122,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"cairo-rs", "cairo-rs",
"glib", "glib",
"glib-build-tools",
"gtk4", "gtk4",
"plotters", "plotters",
"plotters-backend", "plotters-backend",
@ -602,6 +603,12 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "glib-build-tools"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f8480c9ba9cc06aa8d5baf446037f8dc237bee127e9b62080c4db7e293d8ea0"
[[package]] [[package]]
name = "glib-macros" name = "glib-macros"
version = "0.17.9" version = "0.17.9"

View File

@ -13,3 +13,6 @@ gtk = { version = "0.6.6", package = "gtk4", features = ["v4_8"] }
plotters = "0.3.4" plotters = "0.3.4"
plotters-backend = "0.3.4" plotters-backend = "0.3.4"
[build-dependencies]
glib-build-tools = "0.17.0"

7
build.rs Normal file
View File

@ -0,0 +1,7 @@
fn main() {
glib_build_tools::compile_resources(
&["src/resources"],
"src/resources/resources.gresource.xml",
"window.gresource",
);
}

3
src/css/style.css Normal file
View File

@ -0,0 +1,3 @@
button {
color: magenta;
}

View File

@ -1,19 +1,27 @@
use crate::backend::CairoBackend; use backend::CairoBackend;
use gtk::gdk::CairoContext; use gtk::gdk::Display;
use gtk::{glib, Application, ApplicationWindow}; use gtk::{
gio, glib, style_context_add_provider_for_display, Application, ApplicationWindow, CssProvider,
StyleContext,
};
use gtk::{prelude::*, DrawingArea}; use gtk::{prelude::*, DrawingArea};
use plotters::prelude::*; use plotters::prelude::{ChartBuilder, IntoDrawingArea};
use plotters::style::{BLACK, WHITE};
use cairo::Context; // use plotters::prelude::DrawingArea;
use window::Window;
pub mod backend; mod backend;
mod painter;
mod window;
const APP_ID: &str = "org.gtk_rs.HelloWorld2"; const APP_ID: &str = "org.gtk_rs.HelloWorld2";
fn main() -> glib::ExitCode { fn main() -> glib::ExitCode {
gio::resources_register_include!("window.gresource").expect("Failed to register resources");
// Create a new application // Create a new application
let app = Application::builder().application_id(APP_ID).build(); let app = Application::builder().application_id(APP_ID).build();
app.connect_startup(|_| load_css());
// Connect to "activate" signal of `app` // Connect to "activate" signal of `app`
app.connect_activate(build_ui); app.connect_activate(build_ui);
@ -23,50 +31,42 @@ fn main() -> glib::ExitCode {
fn build_ui(app: &Application) { fn build_ui(app: &Application) {
// Create a window and set the title // Create a window and set the title
let window = ApplicationWindow::builder()
.application(app)
.title("My GTK App")
.build();
let draw_area = DrawingArea::new(); let window = Window::new(app);
draw_area.set_draw_func(|a, cr, width, height| { let drawing_area = DrawingArea::new();
draw(cr, 2000, 1000);
drawing_area.set_draw_func(|a, b, c, d| {
let root = CairoBackend::new(b, (500, 500))
.expect("fuck")
.into_drawing_area();
root.fill(&WHITE);
let mut chart = ChartBuilder::on(&root)
.margin(20)
.build_cartesian_2d(-2.1f64..0.6f64, -1.2f64..1.2f64).unwrap();
chart.configure_mesh().draw().unwrap();
}); });
window.set_child(Some(&draw_area)); window.set_child(Some(&drawing_area));
// Present window window.set_default_width(1000);
window.set_default_height(800);
window.present(); window.present();
} }
fn draw(ctx: &Context, width: u32, height: u32) -> Result<(), Box<dyn std::error::Error>> { fn load_css() {
// let mut backend = root.fill(&WHITE)?; // Load the CSS file and add it to the provider
let mut root = CairoBackend::new(ctx, (width, height))?.into_drawing_area(); let provider = CssProvider::new();
provider.load_from_data(include_str!("css/style.css"));
let mut chart = ChartBuilder::on(&root) // Add the provider to the default screen
.caption("y=x^2", ("sans-serif", 50).into_font()) style_context_add_provider_for_display(
.margin(5) &Display::default().expect("Could not connect to a display."),
.x_label_area_size(30) &provider,
.y_label_area_size(30) gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
.build_cartesian_2d(-1f32..1f32, -0.1f32..1f32)?; );
chart.configure_mesh().draw()?;
chart
.draw_series(LineSeries::new(
(-50..=50).map(|x| x as f32 / 50.0).map(|x| (x, x * x)),
&RED,
))?
.label("y = x^2")
.legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &RED));
chart
.configure_series_labels()
.background_style(&WHITE.mix(0.8))
.border_style(&BLACK)
.draw()?;
root.present()?;
Ok(())
} }

1
src/painter/mod.rs Normal file
View File

@ -0,0 +1 @@
mod polar_coord;

View File

@ -0,0 +1,16 @@
use plotters::{coord::ranged1d, prelude::Ranged};
#[derive(Clone)]
pub struct PolarCoord2d<R: Ranged, A: Ranged> {
logic_r: R,
logic_a: A,
}
impl<R: Ranged, A: Ranged> PolarCoord2d<R, A> {
pub fn new<IntoR: Into<R>, IntoA: Into<A>>(logic_r: IntoR, logic_a: IntoA) -> Self {
Self {
logic_r: logic_r.into(),
logic_a: logic_a.into(),
}
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/cinrad_g/">
<file compressed="true" preprocess="xml-stripblanks">window.ui</file>
</gresource>
</gresources>

15
src/resources/window.ui Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="MyGtkAppWindow" parent="GtkApplicationWindow">
<property name="title">My GTK App</property>
<child>
<object class="GtkButton" id="button">
<property name="label">Press me!</property>
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
</object>
</child>
</template>
</interface>

50
src/window/imp.rs Normal file
View File

@ -0,0 +1,50 @@
use glib::subclass::InitializingObject;
use gtk::prelude::*;
use gtk::subclass::prelude::*;
use gtk::{glib, Button, CompositeTemplate};
#[derive(CompositeTemplate, Default)]
#[template(resource = "/org/cinrad_g/window.ui")]
pub struct Window {
#[template_child]
pub button: TemplateChild<Button>,
}
#[glib::object_subclass]
impl ObjectSubclass for Window {
// `NAME` needs to match `class` attribute of template
const NAME: &'static str = "MyGtkAppWindow";
type Type = super::Window;
type ParentType = gtk::ApplicationWindow;
fn class_init(klass: &mut Self::Class) {
klass.bind_template();
}
fn instance_init(obj: &InitializingObject<Self>) {
obj.init_template();
}
}
impl ObjectImpl for Window {
fn constructed(&self) {
// Call "constructed" on parent
self.parent_constructed();
// Connect to "clicked" signal of `button`
self.button.connect_clicked(move |button| {
// Set the label to "Hello World!" after the button has been clicked on
button.set_label("Hello World!");
});
}
}
// ANCHOR_END: object_impl
// Trait shared by all widgets
impl WidgetImpl for Window {}
// Trait shared by all windows
impl WindowImpl for Window {}
// Trait shared by all application windows
impl ApplicationWindowImpl for Window {}

20
src/window/mod.rs Normal file
View File

@ -0,0 +1,20 @@
mod imp;
use glib::Object;
use gtk::{gio, glib, Application};
glib::wrapper! {
pub struct Window(ObjectSubclass<imp::Window>)
@extends gtk::ApplicationWindow, gtk::Window, gtk::Widget,
@implements gio::ActionGroup, gio::ActionMap, gtk::Accessible, gtk::Buildable,
gtk::ConstraintTarget, gtk::Native, gtk::Root, gtk::ShortcutManager;
}
impl Window {
pub fn new(app: &Application) -> Self {
// Create new window
Object::builder()
.property("application", app)
.build()
}
}