Boost logo

Boost :

From: George van den Driessche (grebe_at_[hidden])
Date: 2004-11-13 11:06:39


> Message: 11
> Date: Fri, 12 Nov 2004 22:18:53 +0200
> From: John Torjo <john.lists_at_[hidden]>
> Subject: Re: [boost] Re: GUI Library Proposal for a Proposal
> To: boost_at_[hidden]
> Message-ID: <41951AAD.20208_at_[hidden]>
> Content-Type: text/plain; charset=us-ascii; format=flowed
>
>
>>
>> You have made a good point. I still feel uncomfortable about parsing
>> header
>> files to determine type information. If header files were used, since
>> run-time reflection does not exist, one would have to inject the
>> correct
>> code into source files based on design-time decisions. But it does
>> seem as
>
> I think reflection in general is very different from reflection for a
> GUI.
>
> When you have a GUI control, you want to apply reflection for a few of
> its properties. You won't have #ifdefs (or at least I would consider it
> bad design). Case in point: its interface should be extremely simple
> and
> easy to parse.
>
> You shouldn't need complex information like reflection for virtual
> functions, overloading etc.
>
> Even reflected property types should be of trivial types:
> 1. build in types
> 2. std::string
> 3. types that can simply be read from /written to strings.
>
> For case 3., you might also have a validation function which will be
> used in design-mode to validate user input.
>
> At least that's what I want.

I *think* what you envisage is based around collecting data from the
user via dialogs. So in your view of things, there would be a C++
object that holds the collected data, a set of validation routines, and
a reflection map that binds these to the UI. But you don't do anything
to the program state until the user clicks "OK" in your dialog, at
which point you suck the data out of your simple C++ object and act on
it.

In contrast, other people (myself included) are considering binding
properties and member functions to the UI for similar purposes to why
you would expose them to script: to allow the user to drive them. So,
for a simple example, let's suppose you have some object that
corresponds to a file:

class file_backed_t
{
public:
   std::string get_filename();
   /// This actually renames the file on disk.
   void set_filename( std::string const& );
};

Now, when you bind the filename property to the UI, you'll
automatically do the rename as soon as the user changes the text in the
edit box. (Probably that isn't the desired behaviour in this case, but
it serves as a demonstration.) This usage pattern corresponds better to
modeless dialogs where you don't have an "OK" button.

Of course if you are using a generalised reflection architecture like I
mentioned yesterday, then you can do both approaches:

> One of the things that I noticed about serialisation code is that
> there's
> generally a symmetry between the reading and writing routines. So
> rather
> than write "this is how I load an X, and this is how I save one" I'd
> want to
> write "these are the things in X that need to be saved" and let some
> templates figure out what the corresponding routines are. And then it
> was
> this desire to serialise things automatically by specifying properties
> that
> led me on to think about a common architecture for language binding and
> serialisation. Maybe in the end you'd get declarations like:
>
> /// Properties for serialisation
> boost::properties< my_t, "my_t", boost::serialisation >
> .def( "my_int", &my_t::my_int, &my_t::set_my_int )
> // After serialisation format version 4,a
> // my_float no longer needed to be serialised
> .def( "my_float", &my_t::my_float, &my_t::set_my_float,
> boost::serialisation::in_format_version_range<>( 0, 4 ) )
> ;
>
> /// Properties for scripting
> boost::properties< my_t, "my_t", boost::langbinding >
> // Use serialisation properties to implement pickling.
> .def_pickle( default_pickle_suite< my_t >() )
> .def( "my_int", &my_t::my_int, &my_t::set_my_int,
> boost::langbinding::return_internal_reference<>() )
> // We don't want to bind my_float, for whatever reason.
> ;

boost::properties< file_backed_t, "file_backed_t", boost::gui >
   // This is a heavyweight property for a modeless dialog
   .def( "filename", &file_backed_t::get_filename,
&file_backed_t::set_filename )
;

// dialog_data_t is just a struct to store data for a modal dialog till
// the user clicks "OK", which is when we process it.
struct dialog_data_t
{
   std::string filename;
   // Says whether to back up the specified file before
   // processing it.
   bool make_backup;
};

// Helper function for dialog_data_t reflection.
bool is_good_filename( std::string const& );

boost::properties< dialog_data_t, "dialog_data_t", boost::gui >
   .def( "filename", &dialog_data_t::filename,
     boost::gui::validator( &is_good_filename ) )
   // No validation required for this simple bool.
   .def( "make_backup", &dialog_data_t::make_backup )
;

George


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk