time line

This commit is contained in:
sleptworld 2024-01-23 01:41:22 +08:00
parent d63048d1b2
commit 24d91b628e
4 changed files with 184 additions and 15 deletions

View File

@ -27,4 +27,8 @@ paned>separator {
.content {
font-size: 14px;
}
}
.lv {
background: transparent;
}

View File

@ -1,6 +1,7 @@
use crate::timeline::TimeLine;
use adw::prelude::*;
use gtk::prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt, ToggleButtonExt};
use relm4::typed_list_view::{RelmListItem, TypedListView};
use relm4::*;
use relm4_components::open_button::{OpenButton, OpenButtonSettings};
use relm4_components::open_dialog::OpenDialogSettings;
@ -8,6 +9,55 @@ use std::path::PathBuf;
pub struct ControlPanelModel {
open_button: Controller<OpenButton>,
list_img_wrapper: TypedListView<ImgItem, gtk::SingleSelection>,
}
#[derive(Debug, PartialEq, PartialOrd, Ord, Eq)]
struct ImgItem {
time: String,
img: Option<gtk::gdk::Texture>,
visiable: bool,
}
impl ImgItem {
fn new(time: String, img: Option<gtk::gdk::Texture>, visiable: bool) -> Self {
Self {
time,
img,
visiable,
}
}
}
struct Widgets {
img: gtk::Image,
}
impl RelmListItem for ImgItem {
type Root = gtk::Frame;
type Widgets = Widgets;
fn setup(_item: &gtk::ListItem) -> (gtk::Frame, Widgets) {
relm4::view! {
my_box = gtk::Frame {
set_height_request: 70,
set_width_request: 100,
gtk::Box{
set_margin_all:2,
#[name = "img"]
gtk::Image{}
}
}
}
let widgets = Widgets { img };
(my_box, widgets)
}
fn bind(&mut self, widgets: &mut Self::Widgets, _root: &mut Self::Root) {
let Widgets { img } = widgets;
}
}
#[derive(Debug)]
@ -79,10 +129,24 @@ impl SimpleComponent for ControlPanelModel {
}
},
gtk::Frame{
set_width_request: 100,
TimeLine{
set_hexpand: true,
set_vexpand: true,
set_width_request: 500,
gtk::Box{
set_orientation:gtk::Orientation::Vertical,
set_spacing: 10,
gtk::Box{
TimeLine{
set_width_request: 500,
}
},
gtk::ScrolledWindow{
set_height_request: 70,
#[local_ref]
my_view -> gtk::ListView{
add_css_class: "lv",
set_orientation: gtk::Orientation::Horizontal,
}
},
}
},
}
@ -106,7 +170,21 @@ impl SimpleComponent for ControlPanelModel {
gtk::StringList::new(&["Option 1", "Option 2", "Option 3", "Editable..."]);
let step_selector = gtk::DropDown::from_strings(&["Option 1", "Option 2", "Option 3"]);
let model = ControlPanelModel { open_button };
let mut list_img_wrapper: TypedListView<ImgItem, gtk::SingleSelection> =
TypedListView::with_sorting();
list_img_wrapper.append(ImgItem::new(
"00:00:00".to_string(),
None,
true,
));
let model = ControlPanelModel {
open_button,
list_img_wrapper,
};
let my_view = &model.list_img_wrapper.view;
let widgets = view_output!();
ComponentParts { model, widgets }

View File

@ -44,7 +44,7 @@ fn main() {
.or_else(|_| libloading::os::windows::Library::open_already_loaded("epoxy-0.dll"))
.unwrap();
gio::resources_register_include!("p.gresource").expect("Failed to register resources.");
// gio::resources_register_include!("p.gresource").expect("Failed to register resources.");
epoxy::load_with(|name| {
unsafe { library.get(name.as_bytes()) }

View File

@ -1,10 +1,11 @@
use gtk::cairo;
use gtk::glib::clone;
use gtk::prelude::DrawingAreaExtManual;
use gtk::prelude::{DrawingAreaExtManual, StyleContextExt};
use gtk::subclass::prelude::*;
use gtk::traits::{GLAreaExt, WidgetExt};
use gtk::{cairo, EventControllerMotion};
use std::cell::RefCell;
use std::num::NonZeroU32;
use svg::parser::Event;
use crate::render::Render;
@ -34,19 +35,96 @@ impl ObjectSubclass for TimeLine {
impl ObjectImpl for TimeLine {
fn constructed(&self) {
let drawing_area = gtk::DrawingArea::new();
let settings = gtk::Settings::default().unwrap();
let prefers_dark_theme = settings.is_gtk_application_prefer_dark_theme();
let obj = self.obj().clone();
let (r, g, b) = if prefers_dark_theme {
(1.0, 1.0, 1.0)
} else {
(0.0, 0.0, 0.0)
};
let container = gtk::Box::builder()
.orientation(gtk::Orientation::Horizontal)
.height_request(70)
.hexpand(true)
.margin_start(10)
.margin_end(10)
.build();
let cursor_pos = std::rc::Rc::new(std::cell::RefCell::new(50.0));
let cursor_pos_clone = cursor_pos.clone();
let motion_controller = EventControllerMotion::new();
let cursor_pos_clone = cursor_pos.clone();
motion_controller.connect_motion(clone!(@weak drawing_area =>
move |_, x, _| {
*cursor_pos.borrow_mut() = x;
drawing_area.queue_draw(); // 重绘时间线和游标
}));
drawing_area.set_draw_func(
(move |_, cr, w, h| {
cr.set_source_rgb(1.0, 0.0, 0.0);
Self::draw_rounded_rectangle(cr, 0f64, 50f64, w as f64, 10f64, 5f64);
cr.fill();
cr.set_source_rgba(0.89, 0.89, 0.89, 1.0);
Self::draw_rounded_rectangle(cr, 0.0, h as f64 / 2.0 - 20.0, w as f64, 45.0, 5.0);
let w = w - 20;
cr.fill().unwrap();
cr.set_source_rgb(r, g, b);
cr.set_line_width(1.5);
let major_tick_interval = 30; // 每小时的像素宽度
let minor_tick_interval = major_tick_interval / 10;
let y_pos = h as f64 / 2.0; // 时间轴位于中央
cr.move_to(10.0, y_pos);
cr.line_to(w as f64, y_pos);
cr.stroke().unwrap();
// 绘制大刻度(一小时)
for i in 0..(w / major_tick_interval + 1) {
let x_pos = i * major_tick_interval;
cr.set_line_width(1.0);
cr.move_to(x_pos as f64 + 10.0, h as f64 / 2.0);
cr.line_to(x_pos as f64 + 10.0, h as f64 / 2.0 - 8.0);
cr.stroke().unwrap();
let time_text = format!("{}", i); // 假设时间轴从0点开始
cr.move_to(x_pos as f64 + 10.0, y_pos + 15.0); // 文本位置
cr.show_text(&time_text).unwrap();
}
// 绘制小刻度(一分钟)
for i in 0..(w / minor_tick_interval + 1) {
let x_pos = i * minor_tick_interval;
cr.set_line_width(0.5);
cr.move_to(x_pos as f64 + 10.0, h as f64 / 2.0);
cr.line_to(x_pos as f64 + 10.0, h as f64 / 2.0 - 5.0);
cr.stroke().unwrap();
}
cr.set_source_rgb(0.98, 0.26, 0.24); // 红色
Self::draw_cursor(
cr,
*cursor_pos_clone.borrow(),
h as f64 / 2.0 - 15.0,
2f64,
35f64,
);
}),
);
let obj = self.obj().clone();
drawing_area.set_parent(&obj);
drawing_area.set_hexpand(true);
drawing_area.add_controller(motion_controller);
drawing_area.set_parent(&container);
drawing_area.set_vexpand(true);
drawing_area.set_hexpand(true);
self.drawing_area.borrow_mut().replace(drawing_area);
container.set_parent(&obj);
self.parent_constructed();
}
}
@ -93,4 +171,13 @@ impl TimeLine {
);
cr.close_path();
}
fn draw_cursor(cr: &gtk::cairo::Context, x: f64, y: f64, width: f64, height: f64) {
// 绘制矩形部分
cr.rectangle(x - width / 2.0, y, width, height);
cr.fill().expect("Failed to fill the rectangle");
// 绘制三角形部分
cr.fill().expect("Failed to fill the triangle");
}
}