Inv(#1020): adjust curtom drawing for scrolled viewport

this makes the custom drawing stiched to the absolute canvas,
allowing to move around with the help of the scrollbars...
This commit is contained in:
Fischlurch 2016-10-30 17:08:41 +01:00
parent 90cc17b733
commit 6fd0045a65
3 changed files with 110 additions and 14 deletions

View file

@ -162,9 +162,6 @@ namespace panel {
sizeX = max (sizeX, x);
sizeY = max (sizeY, y);
}
// additional leeway for the scrollbars
sizeX += 10;
sizeY += 10;
canvas_.set_size (sizeX, sizeY);
}
@ -261,23 +258,58 @@ namespace panel {
}
namespace {
_Fmt debugAdj(" | Adj-%s(%3d<%5.2f<%3d)");
}
bool
Canvas::on_draw(Cairo::RefPtr<Cairo::Context> const& cox)
{
if (shallDraw_)
{
int w = get_allocation().get_width();
int h = get_allocation().get_height();
int h = get_allocation().get_width();
int v = get_allocation().get_height();
cox->set_line_width (10.0);
uint extH, extV;
get_size (extH, extV);
auto adjH = get_hadjustment();
auto adjV = get_vadjustment();
cout << "draw h:"<<h<<" v:"<<v
<< " ext-h:"<<extH<<" ext-v:"<<extV
<< string(debugAdj % "H" % adjH->get_lower() % adjH->get_value() % adjH->get_upper())
<< string(debugAdj % "V" % adjV->get_lower() % adjV->get_value() % adjV->get_upper())
<< endl;
double offH = adjH->get_value();
double offV = adjV->get_value();
cox->save();
cox->translate(-offH, -offV);
// draw red diagonal line
cox->set_source_rgb(0.8, 0.0, 0.0);
cox->set_line_width (10.0);
cox->move_to(0, 0);
cox->line_to(w, h);
cox->line_to(extH, extV);
cox->stroke();
cox->restore();
Gtk::Layout::on_draw(cox);
cox->save();
cox->translate(-offH, -offV);
cox->set_source_rgb(0.2, 0.4, 0.9);
cox->set_line_width (2.0);
cox->rectangle(0,0, extH, extV);
cox->stroke();
cox->restore();
return false;
}
return Gtk::Layout::on_draw(cox);
else
return Gtk::Layout::on_draw(cox);
}

View file

@ -2398,15 +2398,17 @@ On a second thought, the fact that the [[Bus-MObject|BusMO]] is rather void of a
:sound mixing desks use list style arrangement, and this has proven to be quite viable, when combined with the ability to //send over// output from one mixer stripe to the input of another, allowing to build arbitrary complex filter matrices. On the other hand, organising a mix in //subgroups// can be considered best practice. This leads to arranging the pipes //as wood:// by default and on top level as list, optionally expanding into a subtree with automatic rooting, augmented by the ability to route any output to any input (cycles being detected and flagged as error).
</pre>
</div>
<div title="GtkCustomDrawing" creator="Ichthyostega" modifier="Ichthyostega" created="201610300111" modified="201610300154" tags="spec GuiPattern" changecount="7">
<div title="GtkCustomDrawing" creator="Ichthyostega" modifier="Ichthyostega" created="201610300111" modified="201610301604" tags="spec GuiPattern" changecount="10">
<pre>//some information how to achieve custom drawing with ~GTKmm...//
valuable reference documentation comes bundled with lib ~GTKmm, in the guide [[&quot;Programming with GTKmm|https://developer.gnome.org/gtkmm-tutorial/stable/index.html.en]]
valuable reference documentation comes bundled with lib ~GTKmm, in the guide [[&quot;Programming with GTKmm&quot;|https://developer.gnome.org/gtkmm-tutorial/stable/index.html.en]]
* the chapter detailing [[use of the Gtk::DrawingArea|https://developer.gnome.org/gtkmm-tutorial/stable/chapter-drawingarea.html.en]], including an introduction to [[Cairomm|https://www.cairographics.org/documentation/cairomm/reference/]]
* the chapter about [[constructing a custom widget|https://developer.gnome.org/gtkmm-tutorial/stable/sec-custom-widgets.html.en]]
Basically we have to handle the {{{signal_draw}}} events. Since we need to control the event processing, it is recommended to do this event handling by //overriding the {{{on_draw()}}} function,// not by connecting a slot directly to the signal. Two details are to be considered here: the //return value// controls if the event can be considered as fully handled. If we return {{{false}}}, enclosing (parent) widgets get also to handle this event. And, secondly, if we derive from any widget, it is a good idea to invoke the //parent implementation of {{{on_draw()}}} at the appropriate point.// This is especially relevant when our custom drawing involves the ''canvas widget'' ({{{Gtk::Layout}}}), which has the ability to place several further widgets embedded onto the canvas area. Without invoking this parent event handler, those embedded widgets won't be shown.
Typically, when starting the draw operation, we retrieve our //allocation.// This is precisely the rectangle reserved for the current widget, //insofar it is visible.// Especially this means, when a larger canvas is partially shown with the help of scrollbars, the allocation is the actually visible rectangle, not the virtual extension of the canvas.
Typically, when starting the draw operation, we retrieve our //allocation.// This is precisely the rectangle reserved for the current widget, //insofar it is visible.// Especially this means, when a larger canvas is partially shown with the help of scrollbars, the allocation is the actually visible rectangle, not the virtual extension of the canvas. Each scrollbar is associated with a {{{Gtk::Adjustment}}}, which is basically a bracketed value with preconfigured step increments. The //value// of the adjustment corresponds to the //coordinates of the viewport// within the larger area of the canvas. Since coordinates in Gtk and Cairo are oriented towards the right and downwards, the value properties of both adjustments (horizontal and vertical) together give us the coordinates of the upper left corner of the viewport. The maximum value possible within such an adjustment is such as to fulfil {{{max(value) + viewport-size == canvas-size}}}. By printing values from the {{{on_draw()}}} callback, it can be verified that Gtk indeed handles it precisely that way.
Thus, if we want to use absolute canvas coordinates for our drawing, we need to adjust the cairo context prior to any drawing operations: we translate it in the opposite direction of the values retrieved from the scrollbar {{{Gtk::Adjustment}}}s. This causes the //user coordinates// to coincede with the absolute canvas coordinates.
</pre>
</div>
<div title="GtkLayoutWidget" creator="Ichthyostega" modifier="Ichthyostega" created="201610141819" modified="201610141820" tags="GuiPattern impl" changecount="3">
@ -2646,7 +2648,7 @@ In the most general case, there can be per-track content and nested content at t
&amp;rarr; important question: how to [[organise the widgets|GuiTimelineWidgetStructure]]
</pre>
</div>
<div title="GuiTimelineWidgetStructure" creator="Ichthyostega" modifier="Ichthyostega" created="201410250002" modified="201610300152" tags="GuiPattern discuss decision impl" changecount="51">
<div title="GuiTimelineWidgetStructure" creator="Ichthyostega" modifier="Ichthyostega" created="201410250002" modified="201610301605" tags="GuiPattern discuss decision impl" changecount="52">
<pre>The Timeline is probably the most prominent place in the GUI where we need to come up with a custom UI design.
Instead of combining standard components in one of the well-known ways, here we need to come up with our own handling solution -- which also means to write one or several custom GTK widgets. Thus the question of layout and screen space division and organisation becomes a crucial design decision. The ~GTK-2 Gui, as implemented currently, did already take some steps along this route, yet this kind of decision should be cast and documented explicitly (be it after the fact).
@ -2733,7 +2735,7 @@ In order to build a sensible plan for our timeline structure, we need to investi
:** when invoked //before// our custom drawing, we draw on top of the embedded widgets
:** when invoked //after// our custom drawing, the embedded widgets stay on top
:* the {{{Gtk::Allocation}}} is precisely the visible screen area reserved for the widget.&lt;br/&gt;It is //not// the extension of the virtual canvas.
:* ...consequently, if our drawing shall be stitched to the canvas, we need to care for translation and for clipping ourselves.
:* ...consequently, if our drawing shall be stitched to the canvas, we need to care for translation and for clipping ourselves. &amp;rarr; see [[here|GtkCustomDrawing]]
</pre>
</div>
<div title="HighLevelModel" modifier="Ichthyostega" created="200808152311" modified="201505310109" tags="Model spec design discuss img" changecount="2">

View file

@ -9438,7 +9438,8 @@
</richcontent>
</node>
</node>
<node CREATED="1477791881630" ID="ID_1823256674" MODIFIED="1477791884001" TEXT="coordinates">
<node CREATED="1477791881630" ID="ID_1823256674" MODIFIED="1477843569686" TEXT="coordinates">
<icon BUILTIN="pencil"/>
<node CREATED="1477791885614" ID="ID_380369648" MODIFIED="1477791916343">
<richcontent TYPE="NODE"><html>
<head>
@ -9454,6 +9455,67 @@
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1477791921953" ID="ID_555455740" MODIFIED="1477791952896" TEXT="...not the extension of the canvas!"/>
<node CREATED="1477841655353" ID="ID_1533125137" MODIFIED="1477841674650" TEXT="adjust to compensate">
<icon BUILTIN="idea"/>
<node CREATED="1477841600713" ID="ID_1319450558" LINK="http://stackoverflow.com/questions/40325668/scrollable-drawing-in-gtklayout" MODIFIED="1477841645668" TEXT="Question: can the framework adjust for us">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
asked on stackoverflow...
</p>
</body>
</html></richcontent>
<icon BUILTIN="help"/>
</node>
<node CREATED="1477841687997" ID="ID_1267996486" MODIFIED="1477841698287" TEXT="explicitly by code">
<node CREATED="1477841706107" ID="ID_1685967940" MODIFIED="1477841722860" TEXT="use get_value() from adjustment"/>
<node CREATED="1477841728496" ID="ID_935017463" MODIFIED="1477841747713" TEXT="because this represents coord. of visible viewport"/>
<node CREATED="1477841753180" ID="ID_501431504" MODIFIED="1477841795159" TEXT="max(value) + viewport-size == canvas size">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...as can be observed
</p>
<p>
by printing values from the on_draw() callback
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1477841809741" ID="ID_1400891730" MODIFIED="1477841816024" TEXT="context-&gt;translate">
<node CREATED="1477841816516" ID="ID_642580279" MODIFIED="1477841841348" TEXT="by -value"/>
<node CREATED="1477841842512" ID="ID_1549119493" MODIFIED="1477841854051" TEXT="allows us to use absolute coords."/>
<node CREATED="1477841854807" ID="ID_1202368941" MODIFIED="1477841859362" TEXT="clipping happens automatically"/>
<node CREATED="1477841860278" ID="ID_208350074" MODIFIED="1477841903458" TEXT="need to ctx-&gt;save() and ctx-&gt;restore()">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...otherwise adjustment values will cummulate,
</p>
<p>
causing us to adjust too much
</p>
</body>
</html>
</richcontent>
</node>
</node>
</node>
</node>
<node CREATED="1477843534095" ID="ID_1261380784" MODIFIED="1477843541259" TEXT="Problem: widget extension">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1477843543126" ID="ID_1096450231" MODIFIED="1477843556632" TEXT="seems to be defined only after drawing it"/>
</node>
</node>
<node CREATED="1477784943797" ID="ID_298493039" MODIFIED="1477791972306" TEXT="layering">
<icon BUILTIN="button_ok"/>