Lumiera  0.pre.03
»edit your freedom«
track-body.cpp
Go to the documentation of this file.
1 /*
2  TrackBody - track body area within the timeline display canvas
3 
4  Copyright (C)
5  2016, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 * *****************************************************************/
13 
14 
27 #include "stage/gtk-base.hpp"
30 
31 #include "lib/util.hpp"
32 
33 using util::isnil;
34 using util::min;
35 
36 
37 namespace stage {
38 namespace timeline {
39 
40  namespace {
41  const uint DEFAULT_CONTENT_HEIGHT_px = 40;
42  const uint TIMELINE_BOTTOM_PADDING_px = 5;
43  }
44 
45 
46 
47 
48  TrackBody::TrackBody()
49  : contentHeight_{DEFAULT_CONTENT_HEIGHT_px}
50  , contentOffset_{0}
51  , startLine_{0}
52  , subTracks_{}
53  , rulers_{}
54  { }
55 
56 
57  TrackBody::~TrackBody()
58  { // indicate change of the global track structure
59  signalStructureChange_();
60  }
61 
62 
65 
66 
67  void
68  TrackBody::setTrackName (cuString& trackName)
69  {
70  TODO ("is the track name of any relevance for the TrackBody widget?");
71  }
72 
73 
74  /* ==== Interface: ViewHook ===== */
75 
76  void
77  TrackBody::hook (TrackBody& subBody)
78  {
79  subTracks_.push_back (&subBody);
80 
81  // notify presentation code of the changed structure
82  subBody.signalStructureChange_ = signalStructureChange_;
83  signalStructureChange_(); // this _is_ such a change
84  }
85 
86  void
87  TrackBody::remove (TrackBody& subBody)
88  {
89  util::removeall (subTracks_, &subBody);
90  signalStructureChange_();
91  }
92 
93  void
94  TrackBody::rehook (TrackBody& subBody) noexcept
95  {
96  util::removeall (subTracks_, &subBody);
97  subTracks_.push_back (&subBody);
98  signalStructureChange_();
99  }
100 
101 
102  /* ==== Code for vertical track display layout ==== */
103 
108  void
109  TrackBody::accommodateContentHeight(uint contentExtension)
110  {
111  if (contentExtension > contentHeight_)
112  contentHeight_ = contentExtension;
113  }
114 
122  uint
124  {
125  return calcContentHeight()
126  + calcSubtrackHeight();
127  }
128 
133  uint
135  {
136  return calcRulerHeight()
137  + contentHeight_ + decoration.content
138  + (isnil (subTracks_)? 0 // slope down to nested scope
139  : decoration.borders[0]);
140  }
141 
146  uint
148  { // „insider trick“ to include prelude padding on root track...
149  uint overviewHeight{startLine_== 0? // parent adds offset to startLine_ of any sub-track
150  decoration.topMar : 0};
151  for (auto& ruler : rulers_)
152  {
153  overviewHeight += ruler->calcHeight()
154  + ruler->getGapHeight()
155  + decoration.ruler;
156  }
157  return overviewHeight;
158  }
159 
160  uint
161  TrackBody::calcSubtrackHeight() const
162  {
163  uint heightSum{isnil (subTracks_)? 0 // approximate slope up (possibly exaggerated)
164  : decoration.borders[0] };
165  for (TrackBody* subTrack : subTracks_)
166  heightSum += subTrack->calcHeight();
167  return heightSum;
168  }
169 
170 
171  namespace {
179  inline uint
180  combinedSlopeHeight (uint depth)
181  {
182  if (depth==0) return 0;
183  depth = min (depth, TrackBody::decoration.borders.size() - 1);
184  return TrackBody::decoration.borders[depth];
185  }
186  }
187 
188 
203  uint
205  {
206  uint line=0;
207  bool topLevel = isnil (profile);
208  if (topLevel)
209  {
210  // global setup for the profile
211  line += decoration.topMar;
212  profile.append_prelude();
213  }
214  else
215  { // adjust if preceded by a combined up-slope
216  line += combinedSlopeHeight (profile.getPrecedingSlopeUp());
217  }
218 
219  // reserve space for the overview rulers
220  for (auto& ruler : rulers_)
221  {
222  uint rulerHeight = ruler->calcHeight();
223  uint gapHeight = ruler->getGapHeight();
224  line += rulerHeight+gapHeight + decoration.ruler;
225  profile.append_ruler (rulerHeight);
226  if (gapHeight > 0)
227  profile.append_gap (gapHeight);
228  }
229  if (topLevel)
230  {
231  // The first Profile elements are always visible on top;
232  // we render this prefix part on a separate drawing canvas,
233  profile.markPrefixEnd();
234  // ...and now we switch to the second, scrollable canvas,
235  // which uses its own local coordinates, thus restart Y-pos.
236  line = 0;
237  }
238  // mark offset of the actual content area relative to this track's top
239  this->contentOffset_ = line + decoration.trackPad;
240 
241  // allocate space for the track content
242  line += this->contentHeight_ + decoration.content;
243  profile.append_content (this->contentHeight_);
244 
245  // account for the space required by nested sub-tracks
246  if (not isnil (subTracks_))
247  {
248  // account for a single slope one step down
249  line += decoration.borders[0]; // (downward slopes are never combined)
250  profile.addSlopeDown();
251 
252  for (TrackBody* subTrack : subTracks_)
253  {
254  // (re)set the subTrack's start coordinates
255  // to reflect the allocation calculation done thus far
256  subTrack->startLine_ = this->startLine_ + line;
257  line += subTrack->establishTrackSpace (profile);
258  }
259 
260  profile.addSlopeUp(); // note: up-slopes might be combined
261  } // thus we'll add their contribution
262  // at the calling function one level higher
263  if (topLevel)
264  {
265  // adjust when reaching top-level after a combined up-slope
266  line += combinedSlopeHeight (profile.getPrecedingSlopeUp());
267 
268  line += decoration.botMar + TIMELINE_BOTTOM_PADDING_px;
269  profile.append_coda (TIMELINE_BOTTOM_PADDING_px);
270  }
271 
272  return line;
273  }
274 
275 
276 
277 }}// namespace stage::timeline
uint calcRulerHeight() const
sum up the vertical extension required by all overview rulers.
Definition: track-body.cpp:147
uint calcHeight() const
recursively calculate the height in pixels to display this track, including all nested sub-tracks and...
Definition: track-body.cpp:123
static Decoration decoration
storage for common style/padding settings
Definition: track-body.hpp:102
uint calcContentHeight() const
Definition: track-body.cpp:134
Borders borders
width of up to 6 levels of combined upward slope borders (defined in CSS)
Definition: track-body.hpp:70
Description of the structure and arrangement of tracks for display in the UI.
Lumiera GTK UI implementation root.
Definition: guifacade.cpp:37
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
void accommodateContentHeight(uint contentExtension)
ensure content with the given extension can be accommodated within this track&#39;s content area ...
Definition: track-body.cpp:109
uint combinedSlopeHeight(uint depth)
helper to get the width of combined slope borders.
Definition: track-body.cpp:180
uint establishTrackSpace(TrackProfile &)
recursively establish the screen space allocation for this structure of nested tracks.
Definition: track-body.cpp:204
Helper to organise and draw the space allocated for a fork of sub-tracks.
Definition: track-body.hpp:86
This helper class serves to manage the layout and display of the horizontally extended space of a "tr...
Configure additional vertical padding for the decorations added through CSS.
Definition: track-body.hpp:61
Abstraction to build the layout for the track spaces within timeline display.
A set of basic GTK includes for the UI.