time line
This commit is contained in:
parent
d63048d1b2
commit
24d91b628e
@ -28,3 +28,7 @@ paned>separator {
|
|||||||
.content {
|
.content {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lv {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use crate::timeline::TimeLine;
|
use crate::timeline::TimeLine;
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use gtk::prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt, ToggleButtonExt};
|
use gtk::prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt, ToggleButtonExt};
|
||||||
|
use relm4::typed_list_view::{RelmListItem, TypedListView};
|
||||||
use relm4::*;
|
use relm4::*;
|
||||||
use relm4_components::open_button::{OpenButton, OpenButtonSettings};
|
use relm4_components::open_button::{OpenButton, OpenButtonSettings};
|
||||||
use relm4_components::open_dialog::OpenDialogSettings;
|
use relm4_components::open_dialog::OpenDialogSettings;
|
||||||
@ -8,6 +9,55 @@ use std::path::PathBuf;
|
|||||||
|
|
||||||
pub struct ControlPanelModel {
|
pub struct ControlPanelModel {
|
||||||
open_button: Controller<OpenButton>,
|
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: >k::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)]
|
#[derive(Debug)]
|
||||||
@ -79,10 +129,24 @@ impl SimpleComponent for ControlPanelModel {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
gtk::Frame{
|
gtk::Frame{
|
||||||
set_width_request: 100,
|
set_width_request: 500,
|
||||||
TimeLine{
|
gtk::Box{
|
||||||
set_hexpand: true,
|
set_orientation:gtk::Orientation::Vertical,
|
||||||
set_vexpand: true,
|
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..."]);
|
gtk::StringList::new(&["Option 1", "Option 2", "Option 3", "Editable..."]);
|
||||||
let step_selector = gtk::DropDown::from_strings(&["Option 1", "Option 2", "Option 3"]);
|
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!();
|
let widgets = view_output!();
|
||||||
|
|
||||||
ComponentParts { model, widgets }
|
ComponentParts { model, widgets }
|
||||||
|
|||||||
@ -44,7 +44,7 @@ fn main() {
|
|||||||
.or_else(|_| libloading::os::windows::Library::open_already_loaded("epoxy-0.dll"))
|
.or_else(|_| libloading::os::windows::Library::open_already_loaded("epoxy-0.dll"))
|
||||||
.unwrap();
|
.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| {
|
epoxy::load_with(|name| {
|
||||||
unsafe { library.get(name.as_bytes()) }
|
unsafe { library.get(name.as_bytes()) }
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
use gtk::cairo;
|
|
||||||
use gtk::glib::clone;
|
use gtk::glib::clone;
|
||||||
use gtk::prelude::DrawingAreaExtManual;
|
use gtk::prelude::{DrawingAreaExtManual, StyleContextExt};
|
||||||
use gtk::subclass::prelude::*;
|
use gtk::subclass::prelude::*;
|
||||||
use gtk::traits::{GLAreaExt, WidgetExt};
|
use gtk::traits::{GLAreaExt, WidgetExt};
|
||||||
|
use gtk::{cairo, EventControllerMotion};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
|
use svg::parser::Event;
|
||||||
|
|
||||||
use crate::render::Render;
|
use crate::render::Render;
|
||||||
|
|
||||||
@ -34,19 +35,96 @@ impl ObjectSubclass for TimeLine {
|
|||||||
impl ObjectImpl for TimeLine {
|
impl ObjectImpl for TimeLine {
|
||||||
fn constructed(&self) {
|
fn constructed(&self) {
|
||||||
let drawing_area = gtk::DrawingArea::new();
|
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(
|
drawing_area.set_draw_func(
|
||||||
(move |_, cr, w, h| {
|
(move |_, cr, w, h| {
|
||||||
cr.set_source_rgb(1.0, 0.0, 0.0);
|
cr.set_source_rgba(0.89, 0.89, 0.89, 1.0);
|
||||||
Self::draw_rounded_rectangle(cr, 0f64, 50f64, w as f64, 10f64, 5f64);
|
|
||||||
cr.fill();
|
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.add_controller(motion_controller);
|
||||||
drawing_area.set_parent(&obj);
|
|
||||||
drawing_area.set_hexpand(true);
|
drawing_area.set_parent(&container);
|
||||||
drawing_area.set_vexpand(true);
|
drawing_area.set_vexpand(true);
|
||||||
|
drawing_area.set_hexpand(true);
|
||||||
self.drawing_area.borrow_mut().replace(drawing_area);
|
self.drawing_area.borrow_mut().replace(drawing_area);
|
||||||
|
|
||||||
|
container.set_parent(&obj);
|
||||||
self.parent_constructed();
|
self.parent_constructed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,4 +171,13 @@ impl TimeLine {
|
|||||||
);
|
);
|
||||||
cr.close_path();
|
cr.close_path();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn draw_cursor(cr: >k::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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user