Created Tutorial page; TODOs pending.

This commit is contained in:
Megadash452 2022-10-02 15:23:48 +00:00
parent 6ad1433587
commit 52e651a168

452
docs/tutorial.rst Normal file
View file

@ -0,0 +1,452 @@
========
Tutorial
========
.. margin at column 75
Read this if you want to learn how to use Blueprint and never used
the XML syntax that can be read by GtkBuilder.
For compatibility with Blueprint IDE extensions, blueprint files
should end with `.blp`.
Namespaces
----------
Blueprint needs the widget library to be imported. These include Gtk,
Libadwaita, Shumate, etc. To import a namespace, write `using` followed
by the library and version number.
.. code-block::
using Gtk 4.0;
using Adw 1;
The Gtk import is required in all blueprints and the minor version
number must be 0.
Comments
--------
Blueprint has inline or multi-line comments
.. code-block::
// This is an inline comment
/* This is
a multiline
comment */
Multi-line comments can't have inner multi-line comments. The compiler
will interpret the inner comment's closing token as the outer comment's
closing token. For example, the following will not compile:
.. code-block::
// Bad comment below:
/* Outer comment
/* Inner comment */
*/
Widgets
-------
Create widgets in the following format:
.. code-block::
Namespace.WidgetClass {
}
The Gtk namespace is implied for widgets, so you can just write the
widget class
.. code-block::
Box {
}
Other namespaces must be written explicitly.
.. code-block::
Adw.Leaflet {
}
Consult the widget library's documentation for a list of widgets. Here is
for `Link Gtk <https://docs.gtk.org/gtk4/index.html>`.
Naming Widgets
~~~~~~~~~~~~~~
Widgets can be given **name**s so that they can be referenced by other
widgets in the blueprint.
.. code-block::
Namespace.WidgetClass widget-name {
}
Any time you want to use this widget as a property (more about that in the
next section) or something else, write the widget's **name** (e.g.
`main-window`).
Properties
----------
Every widget has properties defined by their GObject class. For example,
Libadwaita Toast properties can be found
`Link here <https://gnome.pages.gitlab.gnome.org/libadwaita/doc/1.2/class.Toast.html#properties>`_.
Write properties inside the curly brackets of a widget:
.. code-block::
Namespace.WidgetClass {
property-name: value;
}
Properties are *all lowercase* (except strings) and must end with a
semicolon (;).
Property Types
~~~~~~~~~~~~~~
These are the **types** of values that can be used in properties:
- Booleans: `true`, `false`
- Numbers: e.g. `1`, `1.5`, `-2`, `-2.5`
- Strings (single- or double-quoted): e.g. `"a string"`, `'another string'`
- Enums
- Widgets
Properties are **strongly typed**, so you can't use, for example, a string
for the orientation property, which requires an `Orientation` enum
vartiant as its value.
Enum Properties
~~~~~~~~~~~~~~~
In the Gtk documentation, enum variants have long names and are
capitalized. For example, these are the
`Link Orientation <https://docs.gtk.org/gtk4/enum.Orientation.html>`_
enum variants:
- GTK_ORIENTATION_HORIZONTAL
- GTK_ORIENTATION_VERTICAL
In the blueprint, you would only write the *variant* part of the enum in
*lowercase*, just like you would in the XML.
.. code-block::
Box {
orientation: horizontal;
}
Widget Properties
~~~~~~~~~~~~~~~~~
Some widgets take other widgets as properties. For example, the
`Gtk.StackSidebar` has a stack property which takes a `Gtk.Stack` widget.
You can create a new widget for the value, or you can reference another
widget by its **name**.
.. code-block::
StackSidebar {
stack: Stack { };
}
OR
.. code-block::
StackSidebar {
stack: my-stack;
}
Stack my-stack {
}
Note the use of a semicolon at the end of the property in both cases.
Widget properties are not exempt of this rule.
Property Bindings
-----------------
If you want a widget's property to have the same value as another widget's
property (without hard-coding the value), you could `bind` two widgets'
properties of the same type. Bindings must reference a *source* widget by
**name**. As long as the two properties have the same type, you can bind
properties of different names and of widgets with different widget classes.
.. code-block::
Box my-box {
halign: fill; // Source
}
Button {
valign: bind my-box.halign; // Target
}
Binding Flags
~~~~~~~~~~~~~
Modify the behavior of bindings with flags. Flags are written after the
binding.
.. code-block::
Box my-box {
hexpand: true; // Source
}
Button {
vexpand: bind my-box.hexpand inverted bidirectional; // Target
}
no-sync-create
.. TODO: I'm not exactly sure what this does
Only update the target value when the *Source* value changes, not when
the binding is first created.
bidirectional
When either the *Source* or *Target* value is modified, the other's
value will be updated. For example, if the logic of the program
changes the Button's vexpand value to `false`, then the Box's halign
value will also be updated to `false`.
inverted
If the property is a boolean, the value of the bind can be negated
with this flag. For example, if the Box's hexpand property is `true`,
the Button's vexpand property will be `false` in the code below.
Signals
-------
Gtk allows you to register signals in your program. This can be done by
getting the object from the GtkBuilder and connecting a handler to the
signal. Or register the handler with the application and reference it in
the blueprint.
Signals have an *event name*, a *handler* (aka callback), and optionally
some *flags*. Each widget will have a set of defined signals. Consult the
widget's documentation for a list of its signals.
To register a handler with the application, consult the documentation for
your language's bindings of Gtk.
.. code-block::
WidgetClass {
event-name => handler_name() flags;
}
.. TODO: add a list of flags and their descriptions
By default, signals in the blueprint will pass the widget that the signal
is for as an argument to the *handler*. However, you can specify the
widget that is passed to the handler by referencing its name inside the
parenthesis.
.. code-block::
Label my-label {
label: "Hide me";
}
Button {
clicked => hide_widget(my-label);
}
Custom Widget Classes
---------------------
Some programs have custom widgets defined in their logic, and so blueprint
won't know that they exist. Writing widgets not defined in the GIR will
result in an error. Prepend a custom widget with a `.` to prevent the
compiler from trying to validate the widget. This is essentially leaving
out the *namespace*.
To register a custom widget with the application consult the documentation
for your language's bindings of Gtk.
.. code-block::
.MyCustomWidget {
}
Templates
---------
.. TODO
CSS Style Classes
-----------------
.. Unsure if to group styles with widget-specific items
Widgets can be given style classes that can be used with your CSS or
`Link predefined styles <https://gnome.pages.gitlab.gnome.org/libadwaita/doc/1.2/style-classes.html>`_
in libraries like Libadwaita.
.. code-block::
Button {
label: "Click me";
styles ["my-style", "pill"]
}
Note the lack of a *colon* after "styles" and a *semicolon* at the end of
the line. This syntax looks like the properties syntax, but it compiles to
XML completely different from properties.
The syntax may change to `styles! [...]` in the future so that it is not
confused with the properties syntax.
Consult your language's bindings of Gtk to use a CSS file.
Non-property Elements
~~~~~~~~~~~~~~~~~~~~~
.. TODO: ^^^ should it be called that?
Some widgets will have elements which are not properties, but they sort
of act like properties. Most of the time they will be specific only to a
certain widget. *Styles* is one of these elements, except that styles can
be used for any widget. Similarly to how every widget has styles,
`Gtk.ComboBoxText` has *items*:
.. code-block::
Gtk.ComboBoxText {
items [
item1: "Item 1",
item2: _("Items can be translated"),
"The item ID is not required",
]
}
See the `Link examples page <examples.html>`_ for a list of more of these
widget-specific items.
Menus
-----
Menus are usually the widgets that are placed along the top-bar of a
window, or pop up when you right-click some other widget. In Blueprint a
`menu` is a `Gio.MenuModel` that can be shown by MenuButtons or other
widgets.
Similarly to how it is explained in
`Link Gtk.PopoverMenu <https://docs.gtk.org/gtk4/class.PopoverMenu.html#menu-models>`_,
in Blueprint `menu`s have *items*, *sections*, and *submenus*. `Menu`s can
also be given a **name** like a widget. Please read the **Menu Model**
section of `Gtk.PopoverMenu` for more details on the menu model.
Here is an example of a menu:
.. code-block::
menu my-menu {
section {
label: "File";
item {
label: "Open";
action: "win.open";
icon-name: "document-open-symbolic";
}
item {
label: "Save";
action: "win.save";
icon-name: "document-save-symbolic";
}
submenu {
label: "Save As";
icon-name: "document-save-as-symbolic";
item {
label: "PDF";
action: "win.save_as_pdf";
}
}
}
}
There is a shorthand for *items*. Items require at least a label. The
action and icon-name are optional.
.. code-block::
menu {
item ( "Item 2" )
item ( "Item 2", "app.action", "icon-name" )
}
A widget that uses a `menu` is `Gtk.MenuButton`. It has the *menu-model*
property, which takes a menu. You can write the menu inline with the
property, or write the menu separately and reference it by **name**.
.. code-block::
MenuButton {
menu-model: my-menu;
}
Child Types
-----------
Child types describe how a child widget is placed on a parent widget. For
example, HeaderBars widgets can have children placed either at the *start*
or the *end* of the Headerbar. Child widgets of HeaderBars can have the
*start* or *end* types. Values for child types a widget can have are
defined in the widget's documentation.
Child types in blueprint are written between square brackets [] and before
the child the type is for.
The following blueprint code...
.. code-block::
HeaderBar {
[start]
Button {
label: "Button";
}
}
\... would look like this:
---------------------------
| Button |
---------------------------
And the following blueprint code...
.. code-block::
HeaderBar {
[end]
Button {
label: "Button";
}
}
\... would look like this:
---------------------------
| Button |
---------------------------
Translatable Strings
--------------------
Mark any string as translatable using this syntax: `_("...")`.
Two strings that are the same in English could be translated in different
ways in other languages because of different *contexts*. Translatable
strings with context look like this: `C_("...", "context")`. An example
where a context is needed is the word "have", which in Spanish could
translate to "tener" or "haber".
.. code-block::
Label {
label: C_("have", "1st have");
}
Label {
label: C_("have", "2nd have");
}
See `Link translations page <translations.html>`_ for more details.