diff --git a/docs/tutorial.rst b/docs/tutorial.rst new file mode 100644 index 0000000..09f2d8a --- /dev/null +++ b/docs/tutorial.rst @@ -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 `. + +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 `_. +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 `_ +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 `_ +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 `_ 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 `_, +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 `_ for more details. \ No newline at end of file