2015-01-06 14:37:26 +01:00
/*
2018-04-07 01:00:25 +02:00
ELEMENT - ACCESS . hpp - access to generic elements in the UI
2015-01-06 14:37:26 +01:00
Copyright ( C ) Lumiera . org
2015 , Hermann Vosseler < Ichthyostega @ web . de >
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation ; either version 2 of
the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2018-04-07 01:00:25 +02:00
/** @file element-access.hpp
2018-04-07 02:28:29 +02:00
* * Interface to discover and access raw UI elements in a cross cutting way .
* * We have several orthogonal identification and access schemes within the UI .
* * A naively written UI application just attaches the core logic below some widgets and
* * controllers - - not only does this lead to a hard to maintain codebase , this approach
* * is even outright impossible for Lumiera , since the core is able to run standalone and
* * the UI is loaded as plug - in , which places us into the situation to connect a self
* * contained core with a self contained UI . This is a binding , which , as a sideline , also
* * generates a control structure of its own . An another kind of generic access happens
* * when we _navigate_ the topological UI structure for focus management .
2015-01-06 14:37:26 +01:00
* *
2018-04-07 02:28:29 +02:00
* * This interface defines an abstract service to translate a generic element designation
* * into a ( language level ) access to internal structures of the UI toolkit ( GTK in our case ) .
* * This access to low - level structure proceeds in two stages :
* * - navigate down the UI topology . Optionally , this may involve a mutation ( create element )
* * - evaluate the result ( found , not found , element created ) and access the target ,
* * possibly with conversion ( which might fail )
* *
* * @ note as of 4 / 2018 this is a first draft and WIP - WIP - WIP
2018-04-07 01:00:25 +02:00
* * @ todo WIP ///////////////////////TICKET #1134
2015-01-06 14:37:26 +01:00
* *
2018-04-07 02:28:29 +02:00
* * @ see ElementAccess_test
* * @ see elem - access - dir . hpp implementation
2015-01-06 14:37:26 +01:00
* *
*/
2018-04-07 01:00:25 +02:00
# ifndef GUI_MODEL_ELEMENT_ACCESS_H
# define GUI_MODEL_ELEMENT_ACCESS_H
2015-01-06 14:37:26 +01:00
# include "lib/error.hpp"
2018-03-24 05:35:13 +01:00
# include "lib/nocopy.hpp"
2018-04-07 02:28:29 +02:00
# include "lib/result.hpp"
2018-04-09 00:51:24 +02:00
# include "include/limits.h"
2018-04-09 02:19:54 +02:00
# include "lib/variant.hpp"
2018-04-09 00:51:24 +02:00
# include "lib/access-casted.hpp"
2018-04-07 02:28:29 +02:00
# include "gui/interact/ui-coord.hpp"
2018-04-09 00:51:24 +02:00
//#include "lib/format-string.hpp"
2015-01-06 14:37:26 +01:00
//#include "lib/symbol.hpp"
2018-04-07 02:28:29 +02:00
//#include "lib/util.hpp"
2015-01-06 14:37:26 +01:00
2018-04-09 00:51:24 +02:00
# include <string>
2015-01-06 14:37:26 +01:00
2018-04-09 01:14:12 +02:00
namespace Gtk {
class Widget ;
}
2015-01-06 14:37:26 +01:00
namespace gui {
namespace model {
2018-04-09 00:51:24 +02:00
namespace error = lumiera : : error ;
2015-01-06 14:37:26 +01:00
2018-04-07 02:28:29 +02:00
using interact : : UICoord ;
2018-04-09 02:19:54 +02:00
using lib : : meta : : Types ;
2018-04-07 02:28:29 +02:00
// using util::isnil;
2018-04-09 00:51:24 +02:00
using std : : string ;
2015-01-06 14:37:26 +01:00
2018-04-09 01:14:12 +02:00
class Tangible ;
2015-01-06 14:37:26 +01:00
/**
2018-04-07 02:28:29 +02:00
* Interface : access UI elements by navigating the UI topology .
2015-01-06 14:37:26 +01:00
*
2018-04-07 02:28:29 +02:00
* @ see gui : : interact : : Navigator
* @ see ElementAccess_test
2015-01-06 14:37:26 +01:00
*/
2018-04-07 01:00:25 +02:00
class ElementAccess
2018-04-07 02:28:29 +02:00
: util : : NonCopyable
2015-01-06 14:37:26 +01:00
{
public :
2018-04-07 02:28:29 +02:00
virtual ~ ElementAccess ( ) { } ///< this is an interface
2015-01-06 14:37:26 +01:00
2018-04-07 02:28:29 +02:00
template < class TAR >
using Result = lib : : Result < TAR > ;
2015-01-06 14:37:26 +01:00
2018-04-07 02:28:29 +02:00
/* == Access by Location == */
2015-01-06 14:37:26 +01:00
2018-04-07 02:28:29 +02:00
template < class TAR >
Result < TAR & > access ( UICoord destination ) ;
2015-01-06 14:37:26 +01:00
2018-04-07 02:28:29 +02:00
template < class TAR >
2018-04-09 00:51:24 +02:00
Result < TAR & > access_or_create ( UICoord destination , size_t limitCreation = LUMIERA_MAX_ORDINAL_NUMBER ) ;
2015-01-06 14:37:26 +01:00
2018-04-07 02:28:29 +02:00
protected :
2018-04-09 02:19:54 +02:00
using RawResult = lib : : Variant < Types < model : : Tangible * , Gtk : : Widget * > > ;
2018-04-09 01:14:12 +02:00
2018-04-09 00:51:24 +02:00
/** @internal drill down according to coordinates, maybe create element */
2018-04-09 01:14:12 +02:00
virtual RawResult performAccessTo ( UICoord , size_t limitCreation ) = 0 ;
2015-01-06 14:37:26 +01:00
} ;
2018-04-09 00:51:24 +02:00
/** Navigate the UI topology to access the designated component.
* @ tparam TAR type of result element expected at the designated location
2018-04-07 02:28:29 +02:00
* @ return suitably converted direct ( language ) reference to the desired element
* wrapped as _result proxy_
2018-04-09 00:51:24 +02:00
* @ throw error : : Invalid when the designated element exists , but is not
* type or conversion compatible to the expected result type
2018-04-07 02:28:29 +02:00
* @ note when access was not possible because the element does not exist ,
* the result proxy is empty and convertible to ` bool ( false ) `
*/
template < class TAR >
inline ElementAccess : : Result < TAR & >
ElementAccess : : access ( UICoord destination )
{
2018-04-09 02:19:54 +02:00
return access_or_create < TAR > ( destination , 0 ) ;
2018-04-07 02:28:29 +02:00
}
/** Navigate to the designated component, possibly create the element and parents
* @ return suitably converted direct ( language ) reference to the desired element
* wrapped as _result proxy_
* @ note when access was not possible because the element could not been created ,
* the result proxy is empty and convertible to ` bool ( false ) `
2015-01-06 14:37:26 +01:00
*/
2018-04-07 02:28:29 +02:00
template < class TAR >
inline ElementAccess : : Result < TAR & >
2018-04-09 00:51:24 +02:00
ElementAccess : : access_or_create ( UICoord destination , size_t limitCreation )
2015-01-06 14:37:26 +01:00
{
2018-04-09 02:19:54 +02:00
struct TypeConverter
: RawResult : : Visitor
{
Result < TAR & > result ;
void accept ( model : : Tangible * t ) { result = util : : AccessCasted < TAR & > : : access ( t ) ; }
void accept ( Gtk : : Widget * w ) { result = util : : AccessCasted < TAR & > : : access ( w ) ; }
} ;
///////////////////////////////////////////////////////////////////////////////////////////////////TODO Verdammter Mist!!!! es werden WIEDER beide Zweige compiliert, aber nur einer geht!!!
RawResult targetElm = performAccessTo ( destination , limitCreation ) ;
if ( targetElm . tangible )
return util : : AccessCasted < TAR & > : : access ( targetElm . tangible ) ;
else
if ( targetElm . gtkWidget )
return util : : AccessCasted < TAR & > : : access ( targetElm . gtkWidget ) ;
else
return " In current UI, there is no element at location " + string ( destination ) ;
2015-01-06 14:37:26 +01:00
}
} } // namespace gui::model
2018-04-07 01:00:25 +02:00
# endif /*GUI_MODEL_ELEMENT_ACCESS_H*/