C++ docs: rework the entry points

Move the sixtyfps::namespace entry into a dedicated C++ integration overview
page. Also duplicate and specialize the instantiation and model bits, which
differ between the compiled code and the interpreter.

Finally, fix the generated C++ docs to not mention that there's a constructor,
instead we generate a constructor function.
This commit is contained in:
Simon Hausmann 2021-08-27 16:56:30 +02:00
parent 07e2532c0b
commit 8de3075270
4 changed files with 63 additions and 28 deletions

View file

@ -1,14 +1,11 @@
# Generated code
As of now, only the last component of a .60 source is generated. It is planned to generate all
exported components.
The SixtyFPS compiler called by the build system will generate a header file for the root .60
The SixtyFPS compiler called by the build system will generate a header file for the root `.60`
file. This header file will contain a `class` with the same name as the component.
This class will have the following public member functions:
* A default constructor and a destructor.
* A `create` constructor function and a destructor.
* A `show` function, which will show the component on the screen. Note that in order to render
and react to user input, it's still necessary to spin the event loop, by calling {cpp:func}`sixtyfps::run_event_loop()`
or using the convenience `fun` function in this class.
@ -25,6 +22,15 @@ This class will have the following public member functions:
for this callback. the functor must accept the type parameter of the callback
* A `global` function, to provide access to any exported global singletons.
The class is instantiated with the `create` function, which returns the type wrapped in {cpp:class}`sixtyfps::ComponentHandle`.
This is a smart pointer that owns the actual instance and keeps it alive as long as at least one {cpp:class}`sixtyfps::ComponentHandle`
is in scope, similar to `std::shared_ptr<T>`.
For more complex UIs it is common to supply data in the form of an abstract data model, that is used with
[`for` - `in`](markdown/langref.md#repetition) repetitions or [`ListView`](markdown/widgets.md#listview) elements in the `.60` language.
All models in C++ are sub-classes of the {cpp:class}`sixtyfps::Model` and you can sub-class it yourself. For convenience,
the {cpp:class}`sixtyfps::VectorModel` provides an implementation that is backed by a `std::vector<T>`.
## Example
Let's assume we have this code in our `.60` file
@ -48,7 +54,7 @@ This will generate a header with the following contents (edited for documentatio
class SampleComponent {
public:
/// Constructor
/// Constructor function
inline auto create () -> sixtyfps::ComponentHandle<MainWindow>;
/// Destructor
inline ~SampleComponent ();

View file

@ -26,6 +26,8 @@ Welcome to SixtyFPS C++'s documentation!
:hidden:
:caption: C++ / .60 Integration
Overview <overview.md>
Type Mapping to C++ <types.md>
Example Generated Code <generated_code.md>

View file

@ -0,0 +1,47 @@
# Overview
The following two sections explain how you can integrate your `.60` designs into your
C++ application. The entry point is a `.60` file that contains your primary component
that you instantiate from C++.
There are two ways in that you can instantiate your `.60` designs in your C++ application,
either by compiling them ahead of time or by dynamically loading them at run-time.
Once instantiated you feed data into it, for example by setting properties, populating
data models or setting up callbacks that are invoked when the user activates certain elements.
## Compiled `.60` designs
You can choose to compile a `.60` file to C++, which provides the best performance
and lowest memory consumption.
The `sixtyfps_target_60_sources` cmake command makes the translation automatic
and [generated code](generated_code.md) has an API that allows setting and getting
property values, etc. That API will use types from the {ref}`sixtyfps <namespace_sixtyfps>`
namespace, for example {cpp:class}`sixtyfps::SharedString` or {cpp:class}`sixtyfps::Color`.
## Run-time interpreted `.60` designs
Instead of compiling `.60` designs to C++, you can also choose to dynamically load `.60`
files at run-time. This is slower than compiling them ahead of time and requires more memory,
however it provides more flexibility in your application design.
The entry point to loading a `.60` file is the {cpp:class}`sixtyfps::interpreter::ComponentCompiler`
class in the {ref}`sixtyfps::interpreter <namespace_sixtyfps__interpreter>` namespace.
With the help of {cpp:class}`sixtyfps::interpreter::ComponentCompiler` you create a {cpp:class}`sixtyfps::interpreter::ComponentDefinition`,
which provides you with information about properties and callbacks that are common to all instances. The
{cpp:func}`sixtyfps::interpreter::ComponentDefinition::create()` function creates new instances, which
are wrapped in {cpp:class}`sixtyfps::ComponentHandle`. This is a smart pointer that owns the actual instance
and keeps it alive as long as at least one {cpp:class}`sixtyfps::ComponentHandle` is in scope, similar to `std::shared_ptr<T>`.
All property values in `.60` are mapped to {cpp:class}`sixtyfps::interpreter::Value` in C++. This is a
polymorphic data type that can hold different kinds of values, such as numbers, strings or even data models.
For more complex UIs it is common to supply data in the form of an abstract data model, that is used with
[`for` - `in`](markdown/langref.md#repetition) repetitions or [`ListView`](markdown/widgets.md#listview) elements in the `.60` language.
All models in C++ with the interpreter API are sub-classes of the {cpp:class}`sixtyfps::Model` where the template
parameter is {cpp:class}`sixtyfps::interpreter::Value`. Therefore to provide your own data model, you can subclass
`sixtyfps::Model<sixtyfps::interpreter::Value>`.

View file

@ -35,28 +35,8 @@ struct ItemVTable;
/// The :code:`sixtyfps` namespace is the primary entry point into the SixtyFPS C++ API.
/// All available types are in this namespace.
///
/// There are two ways of loading :code:`.60` markup files in your application:
///
/// #. You could translate them to C++ with the help of the :code:`sixtyfps_target_60_sources`
/// cmake command and use the :doc:`generated C++ API<../generated_code>` to instantiate the UI,
/// set or get property values or callback handlers. That API will use types from the
/// :code:`sixtyfps` namespace, for example :cpp:class:`sixtyfps::SharedString` or
/// :cpp:class:`sixtyfps::Color`.
/// #. Alternatively, you can choose to load the :code:`.60` files dynamically at run-time, using
/// the SixtyFPS Interpreter from the :code:`sixtyfps::interpreter` namespace, starting at
/// :cpp:class:`sixtyfps::interpreter::ComponentCompiler`.
///
/// Once you have loaded or instantiated a `.60` file, you will receive a reference to the instance
/// in a :cpp:class:`sixtyfps::ComponentHandle`. This is a smart pointer that owns
/// the actual instance and keeps it alive as long as at least one
/// :cpp:class:`sixtyfps::ComponentHandle` is in scope, similar to :code:`std::shared_ptr<T>`.
///
/// For more complex UIs it is common to supply data in the form of an abstract data model, that is
/// used with |Repetition|_ repetitions or |ListView|_ elements in the :code:`.60`
/// language. All models in C++ are sub-classes of the :cpp:class:`sixtyfps::Model` and you can
/// sub-class it yourself. For convenience, the :cpp:class:`sixtyfps::VectorModel` provides an
/// implementation that is backed by a :code:`std::vector<T>`.
///
/// See the :doc:`Overview <../overview>` documentation for the C++ integration how
/// to load :code:`.60` designs.
/// \endrst
namespace sixtyfps {