TestControl: concept draft how to simplify building notebook widgets

Gtk::Notebook is a quite powerful container foundation to build complex dialog widgets with multible pages on tabs.
Hower, the construction, wiring an setup is notoriously tedious, due to the repetitiveness
and the sheer amount of child widgets spread over various pages.

This design draft is an attempt to mitigate the required boilerplate, without
overly much obscuring the structure. The basic idea is to package each page into
a locally defined child struct, which is actually heap allocated and managed automatically.
This way, each child page gets its own namespace, and wiring to other components
is made explicit by passing named ctor arguments -- while the overall structure
of building and wiring of widgets stays close to the habits of Gtkmm programming.
This commit is contained in:
Fischlurch 2018-09-26 15:47:39 +02:00
parent 0c082361f3
commit 74f3ab3932
3 changed files with 165 additions and 35 deletions

View file

@ -40,61 +40,123 @@
#include "gui/gtk-base.hpp"
#include "gui/dialog/dialog.hpp"
#include "gui/ctrl/bus-term.hpp"
#include "lib/scoped-ptrvect.hpp"
//#include "lib/meta/function.hpp"
#include "lib/nocopy.hpp"
#include <utility>
namespace gui {
namespace dialog {
using std::forward;
struct FrameVBox
{
Gtk::Frame frame;
Gtk::Box box;
FrameVBox (cuString label)
: frame{label}
, box{Gtk::ORIENTATION_VERTICAL}
{
frame.add (box);
}
operator Gtk::Widget&() { return frame; }
void
pack_start(Gtk::Widget& child, Gtk::PackOptions options = Gtk::PACK_EXPAND_WIDGET, guint padding = 0)
{
box.pack_start (child, options, padding);
}
};
class Page
: public Gtk::Box
, util::NonCopyable
{
public:
Page()
: Gtk::Box{Gtk::ORIENTATION_VERTICAL}
{ }
virtual ~Page() { }
};
class Notebook
: public Gtk::Notebook
, lib::ScopedPtrVect<Gtk::Widget>
{
public:
template<class PAG, typename...ARGS>
Notebook&
buildPage (cuString pageLabel, ARGS&& ...ctorArgs)
{
Gtk::Notebook::append_page (this->manage (new PAG(forward<ARGS> (ctorArgs)...))
,pageLabel);
return *this;
}
};
class TestControl
: public Gtk::Dialog
, ctrl::BusTerm
{
Gtk::Notebook notebook_;
using Bus = ctrl::BusTerm&;
Bus busTerm() { return *this; }
Gtk::Box page_1_;
Gtk::Button trigger_1_;
struct Page1 : Page
{
FrameVBox seg_1_{_("log notification")},
seg_2_{_("mark via UI-Bus")};
Gtk::Button trigger_1_;
Page1(Bus bus)
{
trigger_1_.set_label ("_doIt");
trigger_1_.set_use_underline();
trigger_1_.set_tooltip_markup (_("<b>Ticket #1099</b>:\ntrigger Proc-GUI roundtrip"));
trigger_1_.signal_clicked().connect(
mem_fun(*this, &Page1::demoGuiRoundtrip));
seg_1_.pack_start (trigger_1_, Gtk::PACK_SHRINK);
pack_start (seg_1_);
pack_start (seg_2_);
}
/**
* Ticket #1099 : perform a dummy round-trip to verify Proc-GUI integration.
* This routine invokes the command 'xxx' down in Proc-Layer, passing the settings
* from the radio buttons to select the flavour of feedback, and the text for feedback content.
* The expected behaviour is for the invoked command to send a feedback via UI-Bus towards
* the ErrorLogDisplay within the InfoboxPanel.
*/
void
demoGuiRoundtrip()
{
UNIMPLEMENTED ("collect command arguments and then send the command message for #1099");
}
};
Notebook notebook_;
public:
TestControl (ctrl::BusTerm& upLink, Gtk::Window& parent)
: Dialog(_("Test and Diagnostics"), parent, Gtk::DIALOG_DESTROY_WITH_PARENT)
, ctrl::BusTerm{lib::idi::EntryID<TestControl>{}, upLink}
, page_1_{Gtk::ORIENTATION_VERTICAL}
{
using namespace Gtk;
// Setup the overall dialog layout
set_border_width (BorderPadding);
get_content_area()->pack_start (notebook_);
//-----Page-1------------------------------
trigger_1_.set_label ("_doIt");
trigger_1_.set_use_underline();
trigger_1_.set_tooltip_markup (_("<b>Ticket #1099</b>:\ntrigger Proc-GUI roundtrip"));
trigger_1_.signal_clicked().connect(
mem_fun(*this, &TestControl::demoGuiRoundtrip));
page_1_.pack_start (trigger_1_, PACK_SHRINK);
notebook_.append_page (page_1_, _("#1099"));
// construct and wire the pages...
notebook_.buildPage<Page1> (_("#1099"), busTerm());
show_all();
}
private: /* ==== individual Test/Diagnostics routines ==== */
/**
* Ticket #1099 : perform a dummy round-trip to verify Proc-GUI integration.
* This routine invokes the command 'xxx' down in Proc-Layer, passing the settings
* from the radio buttons to select the flavour of feedback, and the text for feedback content.
* The expected behaviour is for the invoked command to send a feedback via UI-Bus towards
* the ErrorLogDisplay within the InfoboxPanel.
*/
void
demoGuiRoundtrip()
{
UNIMPLEMENTED ("collect command arguments and then send the command message for #1099");
}
};

View file

@ -118,8 +118,8 @@ namespace interact {
/**
* Launch a non modal child window to trigger self-test actions.
* This is a tool for developers and diagnostics. The operations exposed here
* allow to trigger some hard wired actions and test routines, performing within
* This is a tool for diagnostics and development. The operations exposed here
* allow to launch some hard wired actions and test routines, performing within
* the regular UI environment and on equal footing with user operated controls.
*/
void

View file

@ -2771,6 +2771,13 @@
<icon BUILTIN="info"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1537961550200" ID="ID_226231657" MODIFIED="1537962140152" TEXT="setup f&#xfc;r Notebook-Widget">
<icon BUILTIN="pencil"/>
<node COLOR="#435e98" CREATED="1537961568746" ID="ID_1553519505" MODIFIED="1537962304729" TEXT="Prototyp f&#xfc;r generischen Helper">
<arrowlink COLOR="#6ea8be" DESTINATION="ID_591860371" ENDARROW="Default" ENDINCLINATION="1162;51;" ID="Arrow_ID_1534615646" STARTARROW="None" STARTINCLINATION="-185;836;"/>
<icon BUILTIN="yes"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1537836522950" ID="ID_87203159" MODIFIED="1537836526719" TEXT="Radiobuttons">
<icon BUILTIN="flag-yellow"/>
</node>
@ -2824,7 +2831,9 @@
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1534721737507" ID="ID_1467431829" MODIFIED="1534721762112" TEXT="verifizieren">
<icon BUILTIN="full-6"/>
<node CREATED="1534721764680" ID="ID_237796687" MODIFIED="1534721771410" TEXT="Belegen der View"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1534721764680" ID="ID_237796687" MODIFIED="1537961523677" TEXT="Belegen der View">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1534721772238" ID="ID_130695962" MODIFIED="1534721838886" TEXT="Verbinden mit bestehendem InfoboxPanel">
<icon BUILTIN="flag-yellow"/>
</node>
@ -4219,6 +4228,65 @@
<node CREATED="1537659880597" ID="ID_1214109906" MODIFIED="1537659889631" TEXT="Timecode"/>
<node CREATED="1537659890292" ID="ID_1230379898" MODIFIED="1537659892520" TEXT="Placement"/>
</node>
<node CREATED="1537961656982" ID="ID_1251358269" MODIFIED="1537961731447" TEXT="frameworks">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
vorbereitete Grundstrukturen f&#252;r immer wiederkehrende Setups
</p>
</body>
</html>
</richcontent>
<node CREATED="1537961734956" ID="ID_345535043" MODIFIED="1537961770028" TEXT="Notebook-Widget">
<node CREATED="1537961776184" ID="ID_167848646" MODIFIED="1537961791126" TEXT="Problematik">
<icon BUILTIN="forward"/>
<node CREATED="1537961797061" ID="ID_104206298" MODIFIED="1537961806159" TEXT="extrem viele Komponenten-Widgets"/>
<node CREATED="1537961807436" ID="ID_1420879044" MODIFIED="1537961819742" TEXT="Namenskollisionen zwischen Pages"/>
<node CREATED="1537961832009" ID="ID_380956030" MODIFIED="1537961842907" TEXT="Boilerplate-Code goes Spaghetti"/>
</node>
<node CREATED="1537961848735" ID="ID_1187685583" MODIFIED="1537961889952" TEXT="L&#xf6;sungs-Ideen">
<icon BUILTIN="idea"/>
<node CREATED="1537961860374" ID="ID_933681325" MODIFIED="1537961871080" TEXT="managing container"/>
<node CREATED="1537961872836" ID="ID_1674501396" MODIFIED="1537961884942" TEXT="builder lambda"/>
</node>
<node CREATED="1537961894394" ID="ID_1253130867" MODIFIED="1537961909817" TEXT="Prototyp">
<node CREATED="1537961917592" ID="ID_591860371" MODIFIED="1537962293792" TEXT="im TestControl">
<linktarget COLOR="#6ea8be" DESTINATION="ID_591860371" ENDARROW="Default" ENDINCLINATION="1162;51;" ID="Arrow_ID_1534615646" SOURCE="ID_1553519505" STARTARROW="None" STARTINCLINATION="-185;836;"/>
</node>
<node CREATED="1537961950003" ID="ID_1083792924" MODIFIED="1537962085365" TEXT="Schema &quot;managing container&quot;">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...denn das erscheint mir bodenst&#228;ndiger.
</p>
<p>
GUI-Programmierung mu&#223; bodenst&#228;ding bleiben,
</p>
<p>
man gewinnt hier nichts durch blendende Abstraktionen.
</p>
<p>
</p>
<p>
Ich hoffe, da&#223; der Hilfscontainer <i>nahezu transparent </i>gemacht werden kann.
</p>
<p>
Und der Rest sollte so <i>vertraut</i>&#160;aussehen, da&#223; es selbsterkl&#228;rend wird.
</p>
</body>
</html>
</richcontent>
</node>
</node>
</node>
</node>
</node>
<node CREATED="1534336325916" ID="ID_762624766" MODIFIED="1534336335351" TEXT="Bindeglieder"/>
<node CREATED="1534336335963" ID="ID_1176525116" MODIFIED="1534336338575" TEXT="Werkzeug">