mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-28 12:07:48 -06:00
Timeline: comp tabs draw through craft-ui's extra-tabs hook
Pin craft-libs crates to 3723e32a, which adds the group extra-tabs hook. The comp tabs follow the panel tabs directly, with no drag bar between them, and the group header holds only the lock and the panel menu.
This commit is contained in:
Generated
+6
-6
@@ -1038,12 +1038,12 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "craft-docpath"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=1e6f127844ec61b3b8afdcc2bb76e7cfe470153f#1e6f127844ec61b3b8afdcc2bb76e7cfe470153f"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=3723e32ab104bfb3b73fb207dd06a212f8a30e4b#3723e32ab104bfb3b73fb207dd06a212f8a30e4b"
|
||||
|
||||
[[package]]
|
||||
name = "craft-pdf"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=1e6f127844ec61b3b8afdcc2bb76e7cfe470153f#1e6f127844ec61b3b8afdcc2bb76e7cfe470153f"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=3723e32ab104bfb3b73fb207dd06a212f8a30e4b#3723e32ab104bfb3b73fb207dd06a212f8a30e4b"
|
||||
dependencies = [
|
||||
"hayro-syntax",
|
||||
"thiserror 2.0.21",
|
||||
@@ -1052,7 +1052,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "craft-ui"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=1e6f127844ec61b3b8afdcc2bb76e7cfe470153f#1e6f127844ec61b3b8afdcc2bb76e7cfe470153f"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=3723e32ab104bfb3b73fb207dd06a212f8a30e4b#3723e32ab104bfb3b73fb207dd06a212f8a30e4b"
|
||||
dependencies = [
|
||||
"egui",
|
||||
"log",
|
||||
@@ -1065,7 +1065,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "craft-update"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=1e6f127844ec61b3b8afdcc2bb76e7cfe470153f#1e6f127844ec61b3b8afdcc2bb76e7cfe470153f"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=3723e32ab104bfb3b73fb207dd06a212f8a30e4b#3723e32ab104bfb3b73fb207dd06a212f8a30e4b"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"dunce",
|
||||
@@ -2870,7 +2870,7 @@ checksum = "9f4d0e94ddd48749f06bbe4e5389fb9799a0c45bcaf00495042076ef05e3241a"
|
||||
[[package]]
|
||||
name = "hayro-jbig2"
|
||||
version = "0.3.0"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=1e6f127844ec61b3b8afdcc2bb76e7cfe470153f#1e6f127844ec61b3b8afdcc2bb76e7cfe470153f"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=3723e32ab104bfb3b73fb207dd06a212f8a30e4b#3723e32ab104bfb3b73fb207dd06a212f8a30e4b"
|
||||
dependencies = [
|
||||
"hayro-ccitt",
|
||||
]
|
||||
@@ -2884,7 +2884,7 @@ checksum = "c75ab947623ef4ccaa7acf0579edf7cbb5a73838e3839a7be73335e522f433a1"
|
||||
[[package]]
|
||||
name = "hayro-syntax"
|
||||
version = "0.7.2"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=1e6f127844ec61b3b8afdcc2bb76e7cfe470153f#1e6f127844ec61b3b8afdcc2bb76e7cfe470153f"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=3723e32ab104bfb3b73fb207dd06a212f8a30e4b#3723e32ab104bfb3b73fb207dd06a212f8a30e4b"
|
||||
dependencies = [
|
||||
"hayro-jbig2",
|
||||
"hayro-jpeg2000",
|
||||
|
||||
+6
-6
@@ -11,9 +11,9 @@ rust-version = "1.95"
|
||||
repository = "https://github.com/storytold/effectcraft"
|
||||
|
||||
[workspace.dependencies]
|
||||
craft-pdf = { git = "https://github.com/storytold/craft-libs", rev = "1e6f127844ec61b3b8afdcc2bb76e7cfe470153f", version = "=0.1.0", default-features = false, features = ["read"] }
|
||||
craft-docpath = { version = "0.1.0", git = "https://github.com/storytold/craft-libs", rev = "1e6f127844ec61b3b8afdcc2bb76e7cfe470153f" }
|
||||
craft-update = { git = "https://github.com/storytold/craft-libs", version = "=0.1.0", rev = "1e6f127844ec61b3b8afdcc2bb76e7cfe470153f", features = ["egui"] }
|
||||
craft-pdf = { git = "https://github.com/storytold/craft-libs", rev = "3723e32ab104bfb3b73fb207dd06a212f8a30e4b", version = "=0.1.0", default-features = false, features = ["read"] }
|
||||
craft-docpath = { version = "0.1.0", git = "https://github.com/storytold/craft-libs", rev = "3723e32ab104bfb3b73fb207dd06a212f8a30e4b" }
|
||||
craft-update = { git = "https://github.com/storytold/craft-libs", version = "=0.1.0", rev = "3723e32ab104bfb3b73fb207dd06a212f8a30e4b", features = ["egui"] }
|
||||
# internal
|
||||
effectcraft-time = { path = "crates/time" }
|
||||
effectcraft-geom = { path = "crates/geom" }
|
||||
@@ -108,7 +108,7 @@ pollster = "1"
|
||||
# ui
|
||||
# Shared frontend components; keep this dependency above the engine boundary.
|
||||
# Shared UI and the complete egui family select reviewed immutable commits below.
|
||||
craft-ui = { version = "0.1.0", git = "https://github.com/storytold/craft-libs", rev = "1e6f127844ec61b3b8afdcc2bb76e7cfe470153f", features = ["serde"] }
|
||||
craft-ui = { version = "0.1.0", git = "https://github.com/storytold/craft-libs", rev = "3723e32ab104bfb3b73fb207dd06a212f8a30e4b", features = ["serde"] }
|
||||
# `default_fonts` and `monochrome_emoji_fonts` are explicit: the app's `FontDefinitions::default()`
|
||||
# and its `✔`/`▣` chrome glyphs need both, and kittest's own dev-dependencies do not propagate.
|
||||
egui = { version = "0.37", default-features = false, features = ["default_fonts", "monochrome_emoji_fonts"] }
|
||||
@@ -220,8 +220,8 @@ lto = "thin"
|
||||
codegen-units = 1
|
||||
|
||||
[patch.crates-io]
|
||||
hayro-syntax = { git = "https://github.com/storytold/craft-libs", rev = "1e6f127844ec61b3b8afdcc2bb76e7cfe470153f", version = "=0.7.2" }
|
||||
hayro-jbig2 = { git = "https://github.com/storytold/craft-libs", rev = "1e6f127844ec61b3b8afdcc2bb76e7cfe470153f", version = "=0.3.0" }
|
||||
hayro-syntax = { git = "https://github.com/storytold/craft-libs", rev = "3723e32ab104bfb3b73fb207dd06a212f8a30e4b", version = "=0.7.2" }
|
||||
hayro-jbig2 = { git = "https://github.com/storytold/craft-libs", rev = "3723e32ab104bfb3b73fb207dd06a212f8a30e4b", version = "=0.3.0" }
|
||||
ecolor = { git = "https://github.com/storytold/egui.git", rev = "6d518fc799681571963842f95b55a6b68431b15a" }
|
||||
emath = { git = "https://github.com/storytold/egui.git", rev = "6d518fc799681571963842f95b55a6b68431b15a" }
|
||||
epaint = { git = "https://github.com/storytold/egui.git", rev = "6d518fc799681571963842f95b55a6b68431b15a" }
|
||||
|
||||
@@ -138,7 +138,7 @@ ffmpeg elsewhere) to check the code tables against an independent implementation
|
||||
## Shared parser setup and bounds
|
||||
|
||||
The workspace pins `craft-pdf` to `craft-libs` Git revision
|
||||
`1e6f127844ec61b3b8afdcc2bb76e7cfe470153f`, with `default-features = false` and only the explicit `read`
|
||||
`3723e32ab104bfb3b73fb207dd06a212f8a30e4b`, with `default-features = false` and only the explicit `read`
|
||||
feature. This excludes the backend's bundled fonts and Adobe CMaps and preserves EffectCraft's
|
||||
font and asset policies. The shared parser does not change the supported drawing operators,
|
||||
image codecs, continuously rasterized SVG tree, editable shapes, or EPS interpreter.
|
||||
|
||||
@@ -528,9 +528,9 @@ pub enum DocAction {
|
||||
}
|
||||
|
||||
/// Room around a tab's label, as craft-ui gives its dock tabs.
|
||||
pub const TAB_PADDING: f32 = 24.0;
|
||||
const TAB_PADDING: f32 = 24.0;
|
||||
/// Width of the » button that lists the comp tabs with no room in the strip.
|
||||
pub const DOC_OVERFLOW: f32 = 22.0;
|
||||
const DOC_OVERFLOW: f32 = 22.0;
|
||||
/// Room for the × after the shown comp's name.
|
||||
const DOC_CLOSE: f32 = 16.0;
|
||||
|
||||
@@ -543,7 +543,7 @@ fn doc_job(doc: &DocTab, font: &egui::FontId, color: egui::Color32) -> egui::tex
|
||||
}
|
||||
|
||||
/// The width of one line of `job` at the fonts' current size.
|
||||
pub fn text_width(ctx: &egui::Context, job: egui::text::LayoutJob) -> f32 {
|
||||
fn text_width(ctx: &egui::Context, job: egui::text::LayoutJob) -> f32 {
|
||||
ctx.fonts_mut(|f| f.layout_job(job)).size().x
|
||||
}
|
||||
|
||||
|
||||
@@ -632,7 +632,7 @@ struct EffectContent<'a> {
|
||||
titles: Vec<(PanelKind, String)>,
|
||||
swatches: Vec<(PanelKind, egui::Color32)>,
|
||||
docs: Vec<DocTab>,
|
||||
/// Measures tab labels for the group header's width.
|
||||
/// Measures the comp tabs for their width in the tab row.
|
||||
ctx: egui::Context,
|
||||
style: DockStyle,
|
||||
doc_actions: Vec<DocAction>,
|
||||
@@ -749,37 +749,14 @@ fn window_bodies(window: &Floating<PanelKind>) -> usize {
|
||||
}
|
||||
|
||||
impl EffectContent<'_> {
|
||||
/// The header holds the shown panel's lock and ≡ at the strip's end and, in the Timeline's
|
||||
/// group, the comp tabs before them. craft-ui puts the header after the group's drag bar, so
|
||||
/// the comp tabs follow the panel tabs only when the header takes all the room the panel tabs
|
||||
/// and the bar leave. The panel tabs keep their full width; comps without room go to ».
|
||||
fn header_width(&self, panels: &[PanelKind], active: PanelKind, strip_width: f32) -> f32 {
|
||||
let tools = if has_lock(active) { LOCK_W } else { 0.0 } + MENU_W;
|
||||
if self.docs.is_empty() || !panels.contains(&PanelKind::Timeline) {
|
||||
return tools.min(strip_width * 2.0 / 3.0).max(MENU_W);
|
||||
}
|
||||
let tabs: f32 = panels.iter().map(|p| self.tab_width(p)).sum();
|
||||
// Half a point keeps rounding from shrinking the panel tabs.
|
||||
let room = strip_width - tabs - self.style.drag_bar_width - 0.5;
|
||||
room.max(tools + dock::DOC_OVERFLOW).min(strip_width).max(0.0)
|
||||
fn header_width(&self, active: PanelKind, strip_width: f32) -> f32 {
|
||||
let lock = if has_lock(active) { LOCK_W } else { 0.0 };
|
||||
(lock + MENU_W).min(strip_width * 2.0 / 3.0).max(MENU_W)
|
||||
}
|
||||
|
||||
/// A panel tab's width as craft-ui lays it out: its label and the tab padding.
|
||||
fn tab_width(&self, panel: &PanelKind) -> f32 {
|
||||
let logical = self.logical_label(panel);
|
||||
let (font, color) = (&self.style.font, self.style.text);
|
||||
dock::text_width(&self.ctx, self.tab_job(panel, &logical, font, color)) + dock::TAB_PADDING
|
||||
}
|
||||
|
||||
/// A panel tab's text: what the panel shows, after the label swatch of its comp or layer.
|
||||
fn tab_job(&self, panel: &PanelKind, logical: &str, font: &egui::FontId, color: egui::Color32) -> egui::text::LayoutJob {
|
||||
let title = self.titles.iter().find(|(p, _)| p == panel).map_or(logical, |(_, s)| s.as_str());
|
||||
let mut job = egui::text::LayoutJob::default();
|
||||
if let Some((_, swatch)) = self.swatches.iter().find(|(p, _)| p == panel) {
|
||||
job.append("■ ", 0.0, egui::TextFormat::simple(font.clone(), *swatch));
|
||||
}
|
||||
job.append(title, 0.0, egui::TextFormat::simple(font.clone(), color));
|
||||
job
|
||||
/// Whether the group of `panels` shows comp tabs: it holds the Timeline and comps are open.
|
||||
fn has_doc_tabs(&self, panels: &[PanelKind]) -> bool {
|
||||
panels.contains(&PanelKind::Timeline) && !self.docs.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -816,36 +793,30 @@ impl DockContent<PanelKind> for EffectContent<'_> {
|
||||
/// comp or layer. With comps open, the Timeline's own tab is just "Timeline"; each comp has a
|
||||
/// tab of its own after the group's panel tabs.
|
||||
fn label(&mut self, _ui: &egui::Ui, panel: &PanelKind, logical: &str, font: &egui::FontId, color: egui::Color32) -> egui::WidgetText {
|
||||
if self.swatches.iter().any(|(p, _)| p == panel) {
|
||||
return self.tab_job(panel, logical, font, color).into();
|
||||
}
|
||||
self.titles.iter().find(|(p, _)| p == panel).map_or(logical, |(_, s)| s.as_str()).into()
|
||||
let title = self.titles.iter().find(|(p, _)| p == panel).map_or(logical, |(_, s)| s.as_str());
|
||||
let Some((_, swatch)) = self.swatches.iter().find(|(p, _)| p == panel) else { return title.into() };
|
||||
let mut job = egui::text::LayoutJob::default();
|
||||
job.append("■ ", 0.0, egui::TextFormat::simple(font.clone(), *swatch));
|
||||
job.append(title, 0.0, egui::TextFormat::simple(font.clone(), color));
|
||||
job.into()
|
||||
}
|
||||
|
||||
fn group_header_width(&self, panels: &[PanelKind], active: &PanelKind, _floating: bool, strip_width: f32) -> f32 {
|
||||
self.header_width(panels, *active, strip_width)
|
||||
fn group_header_width(&self, _panels: &[PanelKind], active: &PanelKind, _floating: bool, strip_width: f32) -> f32 {
|
||||
self.header_width(*active, strip_width)
|
||||
}
|
||||
|
||||
/// The Timeline's comp tabs (in its group, whichever panel is shown), then the viewer lock
|
||||
/// and the ≡ panel menu of the shown panel.
|
||||
fn group_header(&mut self, ui: &mut egui::Ui, panels: &[PanelKind], active: &PanelKind, _floating: bool) {
|
||||
/// The viewer lock and the ≡ panel menu of the shown panel.
|
||||
fn group_header(&mut self, ui: &mut egui::Ui, _panels: &[PanelKind], active: &PanelKind, _floating: bool) {
|
||||
let t = self.tokens;
|
||||
let header = ui.max_rect();
|
||||
let menu = Rect::from_min_max(pos2((header.max.x - MENU_W).max(header.min.x), header.min.y), header.max);
|
||||
let mut end = menu.min.x;
|
||||
if has_lock(*active) {
|
||||
let lock = Rect::from_center_size(pos2(end - LOCK_W / 2.0, header.center().y), vec2(14.0, 14.0));
|
||||
end -= LOCK_W;
|
||||
let lock = Rect::from_center_size(pos2(menu.min.x - LOCK_W / 2.0, header.center().y), vec2(14.0, 14.0));
|
||||
let locked = self.app.ui.locked_tabs.contains(&active.id());
|
||||
if dock::lock_button(ui, lock, *active, locked, &t, &mut self.app.auto) {
|
||||
self.locks.push(*active);
|
||||
}
|
||||
}
|
||||
if panels.contains(&PanelKind::Timeline) && !self.docs.is_empty() {
|
||||
let strip = Rect::from_min_max(header.min, pos2(end.max(header.min.x), header.max.y));
|
||||
let selected = *active == PanelKind::Timeline;
|
||||
self.doc_actions.extend(dock::doc_tabs(ui, strip, &self.docs, selected, &self.style, &mut self.app.auto));
|
||||
}
|
||||
let rect = Rect::from_center_size(menu.center(), vec2(18.0, 18.0));
|
||||
let response = ui.interact(rect, egui::Id::unique(("panel-menu-button", active.id())), Sense::click());
|
||||
response.widget_info(|| egui::WidgetInfo::labeled(egui::Role::Button, response.enabled(), "panel menu"));
|
||||
@@ -858,4 +829,19 @@ impl DockContent<PanelKind> for EffectContent<'_> {
|
||||
self.menu = Some((*active, rect.left_bottom()));
|
||||
}
|
||||
}
|
||||
|
||||
fn group_extra_tabs_width(&self, panels: &[PanelKind], active: &PanelKind, _floating: bool) -> f32 {
|
||||
if !self.has_doc_tabs(panels) {
|
||||
return 0.0;
|
||||
}
|
||||
dock::doc_widths(&self.ctx, &self.docs, *active == PanelKind::Timeline, &self.style.font).iter().sum()
|
||||
}
|
||||
|
||||
/// The Timeline's comp tabs, after its group's panel tabs whichever panel is shown.
|
||||
fn group_extra_tabs(&mut self, ui: &mut egui::Ui, panels: &[PanelKind], active: &PanelKind, _floating: bool) {
|
||||
if self.has_doc_tabs(panels) {
|
||||
let selected = *active == PanelKind::Timeline;
|
||||
self.doc_actions.extend(dock::doc_tabs(ui, ui.max_rect(), &self.docs, selected, &self.style, &mut self.app.auto));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::process::Command;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
const REV: &str = "1e6f127844ec61b3b8afdcc2bb76e7cfe470153f";
|
||||
const REV: &str = "3723e32ab104bfb3b73fb207dd06a212f8a30e4b";
|
||||
const PACKAGES: &[(&str, &str)] = &[("craft-pdf", "0.1.0"), ("hayro-syntax", "0.7.2"), ("hayro-jbig2", "0.3.0")];
|
||||
|
||||
pub fn run(root: &Path) -> Result<(), String> {
|
||||
|
||||
Reference in New Issue
Block a user