Skip to content

Commit

Permalink
[DOCS] Add docs for variables, canvas, menu, themes, events and callb…
Browse files Browse the repository at this point in the history
…acks
  • Loading branch information
ObaraEmmanuel committed Nov 19, 2024
1 parent fc1f1bb commit cedf8fd
Show file tree
Hide file tree
Showing 37 changed files with 629 additions and 13 deletions.
Binary file added docs/_static/callback_connect.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/canvas_component.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/canvas_component_group.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/canvas_item_attributes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/canvas_item_selection.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/canvas_item_stacking.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/components-native.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/draw_canvas_item.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/event_pane.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/event_pane_entry.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/menu_add_items.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/menu_add_items_cascade.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/menu_attribute.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/menu_cascade_preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/menu_cascade_stylepane.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/menu_component.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/menu_component_group.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/menu_item_reposition.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/menu_preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/menu_stylepane.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/studio_parts.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/theme_select.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/variable_connect.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/variable_multiconnect.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/variables_add.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/variables_detail.png
159 changes: 159 additions & 0 deletions docs/callbacks.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
.. _callbacks:

Callbacks
=========

Formation allows you to connect callbacks that will be invoked when a certain
action occurs. These can be set on the following widget attributes:

* ``command``: Invoked when the widget like a button is clicked.
* ``validatecommand``: Invoked when the widget like an entry is validated.
* ``invalidcommand``: Invoked when the widget like a entry is invalid.
* ``postcommand``: Invoked after a menu is posted.
* ``tearoffcommand``: Invoked when the a menu is torn off.
* ``xscrollcommand``: Invoked when the widget like a scrollbar is horizontally scrolled.
* ``yscrollcommand``: Invoked when the widget like a scrollbar is vertically scrolled.

.. note::

Some of these command attributes may require a callabck that accepts a number of arguments.
Before connecting a callback, make sure you know the arguments that the callback will receive.

.. _callback_format:

Callback Format
----------------
To set a simple callback without any arguments you can just use the callback name
as defined in your code

.. code-block:: python
callback
Or set it as a call with no arguments

.. code-block:: python
callback()
To pass arguments to a callabck you simply have to use the call format

.. code-block:: python
callback(arg1, arg2, arg3)
The arguments (``arg1``, ``arg2``, and ``arg3``) will be passed to the callback
You can also pass ``kwargs`` to the callback using the format

.. code-block:: python
callback(arg1, arg2, arg3, kwarg1=value1, kwarg2=value2)
Any number of arguments and kwargs can be passed to the callback this way.
The arguments can also be expressions that will be evaluated before being passed to the callback.

.. code-block:: python
callback("SomeText".lower())
callback(1 + 2, 3 * 4, 5 ** 6)
The function will get the result of the expression as the argument.

You can also pass the widget that triggered the callback as the first argument by prefixing the callback name with ``::``

.. code-block:: python
::callback
::callback(arg1, arg2, arg3)
::callback(arg1, arg2, arg3, kwarg1=value1, kwarg2=value2)
If you have additional arguments, they will be passed after the widget.

.. code-block:: python
::callback(20)
.. code-block::
def callback(widget, value):
print(widget, value) # <tkinter object> 20
Below is an example where we connect a callabck to each key of a keypad. The callback is a function
named ``key_pressed`` which takes the widget and the value of the key as arguments.

.. figure:: _static/callback_connect.png
:align: center

Connecting a callback to a keypad


The code for the callback is as follows

.. code-block:: python
def key_pressed(widget, value):
print(widget, value)
# do something with the value and widget
.. note::

The ``::`` prefix is not part of the callback name. It is only used to indicate that the widget
should be passed as the first argument to the callback.

.. _callback_connect:

Connecting callbacks to your code
---------------------------------

When loading a design from a file, you can connect the callbacks to your code by using the :meth:`~formation.loader.Builder.connect_callbacks` method
of ``Builder``. You can either pass a dictionary with the callback names as keys and the functions as values or pass
an instance of a class that has the callback names as methods.

.. code-block:: python
...
def on_click(event):
print("button clicked")
def on_keypress(event):
print("key pressed")
# method #1: manual dictionary
build = Builder(parent, path="my_design.xml")
build.connect_callbacks({
"on_click": on_click,
"on_keypress: on_keypress,
})
# method #2: globals() dictionary
build = Builder(path="my_design.xml")
build.connect_callbacks(globals())
...
.. code-block:: python
# method #3: class instance
class App(tkinter.Tk):
def __init__(self):
self.build = Builder(self, path="my_design.xml")
self.build.connect_callbacks(self)
def on_click(self, event):
print("button clicked")
def on_keypress(self, event):
print("key pressed")
app = App()
app.mainloop()
...
108 changes: 107 additions & 1 deletion docs/canvas.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,110 @@
Canvas
*******

Canvas
Setting up
==========

Formation studio allows you to draw on the Tkinter canvas.
To draw on the canvas, you need to first place a canvas on the designer.
The canvas will be in the ``legacy (tk)`` group in the Components pane under ``Container``.

.. figure:: _static/canvas_component.png
:align: center

Canvas component

To place a canvas on the designer, drag and drop the canvas component from the Components pane to the designer.
Once the canvas is placed and selected, The ``Canvas`` section will appear in the Components pane.


.. figure:: _static/canvas_component_group.png
:align: center

Canvas items

Adding items
============

To draw a canvas item, you need to select the item in the ``Canvas`` section and the cursor on the designer will
change to a crosshair. You can then draw the item on the canvas by clicking and dragging the mouse over the canvas.
For multipoint items like lines and polygons, you can double click to finish drawing the item.

.. figure:: _static/draw_canvas_item.png
:align: center

Drawing a canvas item


Selection, Resizing and Moving
==============================

To switch to selection mode, you can click on the selected item in the ``Canvas`` section to deselect it. Alternatively,
you can ``CTRL + click`` on the canvas to switch to selection mode. In selection mode, the cursor changes from a
cross-hair to a pointer allowing you to select items on the canvas by clicking on them. Once an item is selected,
you can move it by dragging it. For multipoint items like lines and polygons, you can move individual points by
dragging them or add new points by right-clicking on an edge/line and selecting ``add_point``. You can also delete a
point by right-clicking on it and selecting ``remove``. Just like widgets, canvas items can be multi-selected
by ``CTRL + click``.

.. figure:: _static/canvas_item_selection.png
:align: center

Selecting and manipulating canvas items

Styling
=======

The canvas items can be styled using the ``Canvas Item`` section in the Styles pane. The available styles depend on the
type of item selected. If you select multiple items, only the styles that are common to all the selected items will be shown.

.. figure:: _static/canvas_item_attributes.png
:align: center

Styling canvas items


Stacking Order
==============

The stacking order of the canvas items can be changed using the context menu.
There are four self-explanatory options available in the context menu:

* bring to front
* send to back
* back one step
* forward one step

The stacking order can also be adjusted manually by dragging the canvas items in the ``Component tree``.
The higher the item in the tree, the lower it will be in the stacking order.

.. figure:: _static/canvas_item_stacking.png
:align: center

Changing stacking order

Accessing the canvas items in code
==================================

Assumming you have a canvas object named ``canvas_1`` and you have drawn a line on it with the item id ``line_1``,
the line object can be manipulated in code as shown below:

.. code-block:: python
from formation import AppBuilder
app = AppBuilder(path="hello.xml")
#access the canvas object
canvas = app.canvas_1
#configure the line item
canvas.itemconfig(app.line_1, fill="red")
#change coordinates of the line
canvas.coords(app.line_1, 0, 0, 100, 100)
app.mainloop()
Generally, the name/id of the item will point to the ``itemid`` that can be used to manipute the item in any of the
canvas item methods.
16 changes: 7 additions & 9 deletions docs/component_pane.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ them based on their functions. These sub-groups are:
* Widget (*widgets that have special functionality*)
* Input (*widgets that allow text and other values to be input*)

More groups may appear depending on what extensions you are using. The canvas tool
More groups may appear depending on what extensions you are using. The `canvas tool <canvas>`_
for example may avail an additional ``canvas`` group with widgets that can
be drawn on a canvas. Find out more on this in the :ref:`canvas` section
be drawn on a canvas and the menu tool will avail the ``menu`` group.

.. note::

Expand All @@ -29,8 +29,8 @@ be drawn on a canvas. Find out more on this in the :ref:`canvas` section
across all sub-groups with ease.
* You can mix widgets in Legacy and Native in the same design.

Legacy
=======
Legacy (tk)
===========

This consists of the classic tkinter widgets. They allow more style attributes
to be set. They look the same on all systems and their default look may seem
Expand All @@ -42,12 +42,11 @@ disposal. Some widgets can only be found in this Legacy group for instance:
* **Text** (*text area allowing multiline text input*)
* **Message** (*label for longer text*)

.. figure:: _static/examples/calculator/components.png
:height: 150px
.. figure:: _static/components_legacy.png
:align: center

Native
=======
Native (ttk)
============

This consists of ttk extension widgets. These types of widgets are designed to
be themed and hence don't allow you to modify several style options that were
Expand All @@ -62,5 +61,4 @@ only be found in this native group for instance:
* **LabeledScale** (*A scale with a built-in label*)

.. figure:: _static/components-native.png
:height: 150px
:align: center
58 changes: 58 additions & 0 deletions docs/events.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
.. _events:

Events
******

The formation studio allows you to bind events to widgets in the Event pane.
You can do this from the event pane accessible as ``Event pane`` from the side bar or the ``View`` menu.

.. figure:: _static/event_pane.png
:align: center

The Event pane

Adding an event
---------------

To add an event, select the widget(s) to be bound then click on the ``+`` button in the Event pane.
This will add an empty entry in the event table.

.. figure:: _static/event_pane_entry.png
:align: center

The Event table

The entry has the following fields:

* **Sequence**: This identifies the type of event to be bound. It has to exactly match any of the event types
supported by Tkinter for instance ``<Button-1>`` for a left mouse click or ``<Motion>`` for mouse motion.

* **Handler**: This is the name of the callback function that will be called when the event is triggered. It uses
the same syntax as the :ref:`command callback <callback_format>`.

* **Add**: This is a checkbox that allows you to indicate whether the binding should override any existing bindings
for the same event type. If checked, the new binding will be added to the existing ones, otherwise it will
replace them.

You can bind as many events as you want to a widget. You can also bind custom events to a widget by using the
format ``<<Custom>>``. You can read more on tkinter events in the `official documentation`

To delete an event, click on the delete icon to the right of the entry.

.. note::

The callaback passed to the handler will **always receive an event object as its first argument**. If the ``::`` prefix
is used, the event object will still be passed as the first argument with the widget argument following it.
Make sure to account for this in your callback function.

.. code-block:: python
def my_handler(event, <other args ...>):
print(event)
Connecting events to callbacks
------------------------------

You can connect the callbacks to your code by using the :meth:`~formation.loader.Builder.connect_callbacks` method
of ``Builder`` as described in the :ref:`callbacks section <callback_connect>`.
4 changes: 4 additions & 0 deletions docs/examples/calculator.rst
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,10 @@ The complete code to run our app which will be located at ``calculate.py`` will
app.mainloop()
:download:`calculator.py <https://raw.githubusercontent.com/ObaraEmmanuel/Formation/refs/heads/master/examples/calculator/calculator.py>`

:download:`calculator.xml <https://raw.githubusercontent.com/ObaraEmmanuel/Formation/refs/heads/master/examples/calculator/calculator.xml>`

You can now run ``calculator.py`` and it should display your beautiful working app. Type
a simple mathematical expression in the entry box and click "calculate" and it should display the
computed result
Expand Down
Loading

0 comments on commit cedf8fd

Please sign in to comment.