73 using CairoC = PCairoContext
const&;
74 using StyleC = PStyleContext
const&;
78 const int INITIAL_TIMERULER_HEIGHT_px = 30;
79 const int INITIAL_CONTENT_HEIGHT_px = 100;
80 const int MINIMAL_CONTENT_WIDTH_px = 100;
87 slopeClassName(
int depth)
91 case 1:
return CLASS_slope_deep1;
92 case 2:
return CLASS_slope_deep2;
93 case 3:
return CLASS_slope_deep3;
94 case 4:
return CLASS_slope_deep4;
95 default:
return CLASS_slope_verydeep;
98 const uint SLOPE_CAP_DEPTH = 5;
109 static bool styleSetupDone{
false};
110 if (styleSetupDone)
return;
112 StyleC styleRuler{trackRulerStyle.getAdvice()};
116 + styleRuler->get_margin().get_bottom()
117 + styleRuler->get_border().get_top()
118 + styleRuler->get_border().get_bottom()
119 + styleRuler->get_padding().get_top()
120 + styleRuler->get_padding().get_bottom()
123 + styleBody->get_margin().get_bottom()
124 + styleBody->get_padding().get_top()
125 + styleBody->get_padding().get_bottom()
128 + styleBody->get_padding().get_top()
133 for (uint depth=SLOPE_CAP_DEPTH; depth>0; --depth)
136 styleBody->add_class (slopeClassName(depth));
141 styleBody->remove_class (slopeClassName(depth));
144 styleSetupDone =
true;
176 fillBackground (StyleC style,
int height)
178 style->render_background (cox_
188 : cox_{currentDrawContext}
190 , styleR_{trackRulerStyle.getAdvice()}
212 int topMargin = style_->get_margin().get_top();
221 int bottomPad = pad + style_->get_margin().get_bottom();
230 int marTop = styleR_->get_margin().get_top();
231 int marBot = styleR_->get_margin().get_bottom();
232 int padTop = styleR_->get_padding().get_top();
233 int padBot = styleR_->get_padding().get_bottom();
234 int frameT = styleR_->get_border().get_top();
235 int frameB = styleR_->get_border().get_bottom();
237 int heightWithFrame = contentHeight + padTop+padBot + frameT+frameB;
240 fillBackground(styleR_, heightWithFrame);
241 styleR_->render_frame (cox_
247 line_ += heightWithFrame;
263 int marTop = style_->get_margin().get_top();
264 int marBot = style_->get_margin().get_bottom();
265 int padTop = style_->get_padding().get_top();
266 int padBot = style_->get_padding().get_bottom();
267 int heightWithPadding = contentHeight + padTop+padBot;
270 fillBackground (style_, heightWithPadding);
271 line_ += heightWithPadding;
281 style_->add_class (slopeClassName (1));
282 int slopeWidth = style_->get_border().get_top();
283 style_->render_frame_gap(cox_
284 ,visible_.b - slopeWidth
286 ,visible_.delta() + 2*slopeWidth
289 ,Gtk::PositionType::POS_BOTTOM
291 ,visible_.e + 2*slopeWidth
294 style_->remove_class (slopeClassName(1));
308 style_->add_class (slopeClassName(n));
309 int slopeWidth = style_->get_border().get_bottom();
311 style_->render_frame_gap(cox_
312 ,visible_.b - slopeWidth
314 ,visible_.delta() + 2*slopeWidth
317 ,Gtk::PositionType::POS_TOP
319 ,visible_.e + 2*slopeWidth
322 style_->remove_class (slopeClassName(n));
323 line_ += 2*slopeWidth;
327 using AbstractTrackRenderer::AbstractTrackRenderer;
341 line_ += style_->get_margin().get_top();
350 line_ += pad + style_->get_margin().get_bottom();
358 int marTop = styleR_->get_margin().get_top();
359 int marBot = styleR_->get_margin().get_bottom();
360 int padTop = styleR_->get_padding().get_top();
361 int padBot = styleR_->get_padding().get_bottom();
362 int frameT = styleR_->get_border().get_top();
363 int frameB = styleR_->get_border().get_bottom();
365 int heightWithFrame = contentHeight + padTop+padBot + frameT+frameB;
387 int marTop = style_->get_margin().get_top();
388 int marBot = style_->get_margin().get_bottom();
389 int padTop = style_->get_padding().get_top();
390 int padBot = style_->get_padding().get_bottom();
391 int heightWithPadding = contentHeight + padTop+padBot;
404 style_->add_class (slopeClassName (1));
405 int slopeWidth = style_->get_border().get_top();
407 style_->remove_class (slopeClassName(1));
416 style_->add_class (slopeClassName(n));
417 int slopeWidth = style_->get_border().get_bottom();
419 style_->remove_class (slopeClassName(n));
424 using AbstractTrackRenderer::AbstractTrackRenderer;
428 template<
class PINT,
bool isRuler>
432 return [&](CairoC cox)
434 PINT concreteRenderScheme{cox, layout};
435 getProfile().performWith (concreteRenderScheme, isRuler);
442 const bool RULER =
true;
443 const bool BODY =
false;
450 BodyCanvasWidget::~BodyCanvasWidget() { }
453 BodyCanvasWidget::BodyCanvasWidget (
DisplayManager& displayManager)
454 : Glib::ObjectBase(
"body")
455 , Gtk::Box{Gtk::ORIENTATION_VERTICAL}
456 , layout_{displayManager}
460 , rulerArea_{contentArea_.get_hadjustment(), Gtk::Adjustment::create (0,0,0,0,0,0)}
461 , rulerCanvas_{makeRenderer<Grounding,RULER>(layout_,getProfile), makeRenderer<Overlay,RULER>(layout_,getProfile)}
462 , mainCanvas_ {makeRenderer<Grounding,BODY> (layout_,getProfile), makeRenderer<Overlay,BODY> (layout_,getProfile)}
464 get_style_context()->add_class(CLASS_timeline);
465 get_style_context()->add_class(CLASS_timeline_body);
473 maybeRebuildLayout();
478 adjustCanvasSize(MINIMAL_CONTENT_WIDTH_px, INITIAL_CONTENT_HEIGHT_px, INITIAL_TIMERULER_HEIGHT_px);
480 this->set_border_width (0);
481 this->property_expand() =
true;
482 this->pack_start (rulerArea_, Gtk::PACK_SHRINK);
483 this->pack_start (contentArea_, Gtk::PACK_EXPAND_WIDGET);
485 rulerArea_.set_shadow_type (Gtk::SHADOW_NONE);
486 rulerArea_.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER);
487 rulerArea_.property_expand() =
false;
488 rulerArea_.add (rulerCanvas_);
489 contentArea_.set_shadow_type (Gtk::SHADOW_NONE);
490 contentArea_.set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_ALWAYS);
491 contentArea_.property_expand() =
true;
492 contentArea_.add (mainCanvas_);
511 rootBody_ = &rootTrackBody;
515 BodyCanvasWidget::disable()
538 while (rootBody_ and isnil (profile_))
541 layout_.triggerDisplayEvaluation();
543 ENSURE (not isnil (profile_),
"DisplayEvaluation logic broken");
558 auto adjust = [](Gtk::Layout& canvas, guint newWidth, guint newHeight) ->
void 560 guint currWidth{0}, currHeight{0};
561 canvas.get_size(currWidth, currHeight);
562 if (currWidth != newWidth or currHeight != newHeight)
564 canvas.set_size(newWidth, newHeight);
568 canvas.set_size_request(MINIMAL_CONTENT_WIDTH_px, newHeight);
572 adjust (rulerCanvas_, canvasWidth, rulerHeight);
573 adjust (mainCanvas_, canvasWidth, contentHeight);
578 BodyCanvasWidget::forceRedraw()
580 rulerCanvas_.queue_draw();
581 mainCanvas_.queue_draw();
585 BodyCanvasWidget::getCanvas (
int yPos)
594 BodyCanvasWidget::hook (Gtk::Widget& widget,
int xPos,
int yPos)
597 getCanvas(yPos).put (widget, xPos, yPos);
601 BodyCanvasWidget::remove (Gtk::Widget& widget)
604 getCanvas(0).remove (widget);
608 BodyCanvasWidget::move (Gtk::Widget& widget,
int xPos,
int yPos)
611 getCanvas(yPos).move (widget, xPos, yPos);
629 uint contentHeight = rootBody_->establishTrackSpace (profile_);
630 uint rulerHeight = rootBody_->calcRulerHeight();
631 adjustCanvasSize(layout_.getPixSpan().delta(), contentHeight, rulerHeight);
645 TimelineCanvas::TimelineCanvas (_Renderer groundingFun, _Renderer overlayFun)
647 , renderGrounding_{groundingFun}
648 , renderOverlay_{overlayFun}
670 bool event_is_handled = Gtk::Layout::on_draw(cox);
677 return event_is_handled;
691 auto adjH = get_hadjustment();
692 auto adjV = get_vadjustment();
693 double offH = adjH->get_value();
694 double offV = adjV->get_value();
697 cox->translate(-offH, -offV);
719 renderGrounding_(cox);
void close(uint n) override
paint closing slope to finish nested sub tracks
void maybeRebuildLayout()
Possibly (re)build the allocation and distribution of layout space.
PixSpan getPixSpan()
the overall horizontal pixel span to cover by this timeline
SignalStructureChange signalStructureChange_
signal to be invoked whenever the virtual structure of the corresponding timeline changes...
void closeCanvas(CairoC)
Finish and close the virtual drawing canvas established by openCanvas().
Access point for the advised entity (client).
std::function< TrackProfile &()> ProfileGetter
a way to get and possibly (re)compute the current TrackProfile
Mix-in interface to allow for concrete CanvasHooked widgets to adapt themselves to the metric current...
Widget to render the body of timeline display, by custom drawing into a canvas control.
void coda(uint pad) override
finish painting the track body area
void content(uint contentHeight) override
fill background of track content area with the given vertical extension
static Decoration decoration
storage for common style/padding settings
void ruler(uint contentHeight) override
draw grounding of an overview/ruler track with the given height
void open() override
render overlays covering the opening slope towards nested tracks
void coda(uint pad) override
finish painting overlays a the bottom of the track body area
void openCanvas(CairoC)
Prepare the drawing canvas to work within our virtual canvas coordinate system.
Lumiera's internal time value datatype.
void prelude() override
overlays to show at top of the track body area
void drawOverlays(CairoC)
model::DisplayMetric & getMetric() const override
access the component to handle layout metric
void gap(uint h) override
render overlays on top of padding/gap
void ruler(uint contentHeight) override
draw overlays on top of overview/ruler track
Visitor and state holder for a collaborative layout adjustment pass.
Expecting Advice and giving Advice: a cross-cutting collaboration of loosely coupled participants...
Borders borders
width of up to 6 levels of combined upward slope borders (defined in CSS)
Abstraction: service for the widgets to translate themselves into screen layout.
void content(uint contentHeight) override
place overlays on top of of track content area,
void prelude() override
create spacing at the top of the track body area
Description of the structure and arrangement of tracks for display in the UI.
void adjustCanvasSize(int canvasWidth, int totalHeight, int rulerHeight)
After the (recent) display evaluation pass has negotiated the required space for the currently presen...
Lumiera GTK UI implementation root.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
void drawGrounding(CairoC)
Establish and render the structure of (possibly nested) tracks and overview rulers.
void gap(uint h) override
insert additional padding/gap (typically below a ruler)
void installForkRoot(TrackBody &rootTrackBody)
The Lumiera Timeline model does not rely on a list of tracks, as most conventional video editing soft...
Helper to organise and draw the space allocated for a fork of sub-tracks.
This helper class serves to manage the layout and display of the horizontally extended space of a "tr...
virtual bool on_draw(CairoC) override
Custom drawing of the timeline content area.
void close(uint n) override
render overlays covering the closing slope towards nested tracks
Abstraction to build the layout for the track spaces within timeline display.
void establishLayout(DisplayEvaluation &) override
respond to the DisplayEvaluation pass.
Definition of access keys for uniform UI styling.
void slotStructureChange() noexcept
force rebuilding of theTrackProfile whenever the global timeline structure changes ...
A set of basic GTK includes for the UI.
void setupAdditionalTrackPadding_fromCSS()
Adjust the vertical space to accommodate for additional decorations as required by the CSS style rule...
Interface for coordination of the overall timeline display.
void open() override
paint opening slope to enter nested sub tracks
lumiera::advice::Request< PStyleContext > trackBodyStyle
request a pre-defined CSS style context for the track body