Add documentation and docstrings
This commit is contained in:
parent
ca0f843d7f
commit
6831281c98
@ -6,6 +6,7 @@ API reference
|
||||
:caption: View
|
||||
:maxdepth: 1
|
||||
|
||||
api/protocols
|
||||
api/view
|
||||
api/painters
|
||||
api/tools
|
||||
@ -17,8 +18,7 @@ The central part for Gaphas is the View. That's the class that ensures stuff is
|
||||
:maxdepth: 1
|
||||
|
||||
api/connections
|
||||
api/solver
|
||||
api/position
|
||||
api/variable
|
||||
|
||||
One of Gaphas' USP is it's the way it handles connections and the constraint solver.
|
||||
|
||||
@ -28,6 +28,7 @@ One of Gaphas' USP is it's the way it handles connections and the constraint sol
|
||||
|
||||
api/matrix
|
||||
api/quadtree
|
||||
api/solver
|
||||
api/tree
|
||||
api/table
|
||||
api/geometry
|
||||
|
7
docs/api/connections.rst
Normal file
7
docs/api/connections.rst
Normal file
@ -0,0 +1,7 @@
|
||||
Connections
|
||||
===========
|
||||
|
||||
The ``Connections`` class can be used to manage any type of constraint.
|
||||
|
||||
.. autoclass:: gaphas.connections.Connections
|
||||
:members:
|
7
docs/api/matrix.rst
Normal file
7
docs/api/matrix.rst
Normal file
@ -0,0 +1,7 @@
|
||||
Matrix
|
||||
======
|
||||
|
||||
The ``Matrix`` class used to records item placement (translation), scale and skew.
|
||||
|
||||
.. autoclass:: gaphas.matrix.Matrix
|
||||
:members:
|
39
docs/api/painters.rst
Normal file
39
docs/api/painters.rst
Normal file
@ -0,0 +1,39 @@
|
||||
Painters
|
||||
========
|
||||
|
||||
Painters are used to draw the view.
|
||||
|
||||
Each painter adheres to the ``Painter`` protocol.
|
||||
|
||||
.. autoclass:: gaphas.painter.Painter
|
||||
:members:
|
||||
|
||||
Some painters, such as ``FreeHandPainter`` and ``BoundingBoxPainter``, require a special painter protocol:
|
||||
|
||||
.. autoclass:: gaphas.painter.painter.ItemPainterType
|
||||
:members:
|
||||
|
||||
|
||||
Default implementations
|
||||
-----------------------
|
||||
|
||||
.. autoclass:: gaphas.painter.PainterChain
|
||||
:members: append, prepend
|
||||
|
||||
|
||||
.. autoclass:: gaphas.painter.ItemPainter
|
||||
|
||||
.. autoclass:: gaphas.painter.HandlePainter
|
||||
|
||||
.. autoclass:: gaphas.painter.BoundingBoxPainter
|
||||
|
||||
.. autoclass:: gaphas.painter.FreeHandPainter
|
||||
|
||||
|
||||
Rubberband tool
|
||||
---------------
|
||||
|
||||
A special painter is used to display rubberband selection. This painter shares some state with
|
||||
the rubberband tool.
|
||||
|
||||
.. autoclass:: gaphas.tool.rubberband.RubberbandPainter
|
18
docs/api/protocols.rst
Normal file
18
docs/api/protocols.rst
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
Protocols
|
||||
=========
|
||||
|
||||
Although ``gaphas.Canvas`` can be used as a default model, any class that adhere's to the Model protocol can be used as a model.
|
||||
|
||||
.. autoclass:: gaphas.view.model.Model
|
||||
:members:
|
||||
|
||||
An item should implement these methods, so it can be rendered by the View. Not that painters or tools can require additional methods.
|
||||
|
||||
.. autoclass:: gaphas.item.Item
|
||||
:members:
|
||||
|
||||
The view should support just thise one protocol, which will allow update requests to
|
||||
propagate to the view:
|
||||
|
||||
.. automethod:: gaphas.view.model.View.request_update
|
14
docs/api/tools.rst
Normal file
14
docs/api/tools.rst
Normal file
@ -0,0 +1,14 @@
|
||||
Tools
|
||||
=====
|
||||
|
||||
Tools are used to interact with the view.
|
||||
|
||||
Each tool is basically a function that produces a ``Gtk.EventController``.
|
||||
The event controllers are already configured.
|
||||
|
||||
.. autofunction:: gaphas.tool.hover_tool
|
||||
.. autofunction:: gaphas.tool.item_tool
|
||||
.. autofunction:: gaphas.tool.placement_tool
|
||||
.. autofunction:: gaphas.tool.rubberband_tool
|
||||
.. autofunction:: gaphas.tool.scroll_tool
|
||||
.. autofunction:: gaphas.tool.zoom_tool
|
11
docs/api/variable.rst
Normal file
11
docs/api/variable.rst
Normal file
@ -0,0 +1,11 @@
|
||||
Variables and Position
|
||||
======================
|
||||
|
||||
|
||||
.. autoclass:: gaphas.solver.Variable
|
||||
:members:
|
||||
|
||||
.. autofunction:: gaphas.solver.variable
|
||||
|
||||
|
||||
.. autoclass:: gaphas.position.Position
|
@ -1,21 +1,7 @@
|
||||
View
|
||||
====
|
||||
|
||||
Protocols
|
||||
---------
|
||||
View is the central class in Gaphas. It shows your diagram and allows you to interact with it.
|
||||
|
||||
Although gaphas.Canvas can be used as a default model, any class that adhere's to the Model protocol can be used as a model.
|
||||
|
||||
.. autoclass:: gaphas.view.model.Model
|
||||
:members:
|
||||
|
||||
The view should support just thise one protocol, which will allow update requests to
|
||||
propagate to the view:
|
||||
|
||||
.. automethod:: gaphas.view.model.View.request_update
|
||||
|
||||
|
||||
GtkView
|
||||
-------
|
||||
.. autoclass:: gaphas.view.GtkView
|
||||
:members:
|
@ -87,7 +87,7 @@ exclude_patterns = [
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = None
|
||||
|
||||
|
||||
autodoc_member_order = "bysource"
|
||||
autodoc_mock_imports = ["gi"]
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
@ -19,8 +19,8 @@ Above rules are constraints, which need to be applied to a rectangular
|
||||
item. The rules can be satisfied (constraints can be solved) using
|
||||
`constraint solver <http://en.wikipedia.org/wiki/Constraint_satisfaction_problem>`_.
|
||||
|
||||
Gaphas implements its own constraint solver (`gaphas.solver` module).
|
||||
Items can be constrained using APIs defined in `Canvas` and `Item` classes.
|
||||
Gaphas implements its own constraint solver (`gaphas.solver.Solver`).
|
||||
Items can be constrained using APIs defined in `Connection` class.
|
||||
|
||||
Constraints API
|
||||
---------------
|
||||
@ -38,13 +38,6 @@ positions, i.e.
|
||||
If this API does not provide some constraint declaration, then one can
|
||||
fallback to `Canvas` class constraint API.
|
||||
|
||||
Examples
|
||||
--------
|
||||
Item API
|
||||
^^^^^^^^
|
||||
Canvas API
|
||||
^^^^^^^^^^
|
||||
|
||||
Further Reading
|
||||
---------------
|
||||
Theory and examples related to constraint solving
|
||||
@ -59,4 +52,3 @@ There are other projects providing constraint solvers
|
||||
- http://minion.sourceforge.net/
|
||||
- http://labix.org/python-constraint
|
||||
- http://www.cs.washington.edu/research/constraints/cassowary/
|
||||
|
||||
|
@ -6,26 +6,7 @@ This class diagram describes the basic layout of Gaphas.
|
||||
.. image:: gaphas-canvas.png
|
||||
:width: 700
|
||||
|
||||
One-oh-one:
|
||||
|
||||
:doc:`api/canvas`
|
||||
The main canvas class (container for Items)
|
||||
:doc:`api/items`
|
||||
Objects placed on a Canvas. Items can draw themselves, but not act on user events
|
||||
:doc:`api/solver`
|
||||
A constraint solver. Nice to have when you want to connect items together in a generic way.
|
||||
:doc:`api/gtkview`
|
||||
A view to be used in GTK+ applications. This view class is interactive. Interaction with users is handled by Tools.
|
||||
:doc:`api/painters`
|
||||
Painters are the workers when it comes to painting items.
|
||||
:doc:`api/tools`
|
||||
Tools are used to handle user events (such as mouse movement and button presses).
|
||||
:doc:`api/aspects`
|
||||
Tools do not modify the items directly. They use aspects (not the AOP kind) as intermediate step. Since aspects are defined as generic functions, the behaviour for each diagram item type can be slightly different.
|
||||
|
||||
Tools
|
||||
-----
|
||||
|
||||
Several tools_ are used to make the overall user experience complete.
|
||||
|
||||
.. _tools: tools.html
|
||||
The central class is ``GtkView``. It takes a model.
|
||||
A default implementation is provided by `gaphas.Canvas`.
|
||||
A view is rendered by ``Painter``s. Interaction is handled
|
||||
by ``Tool``s.
|
||||
|
@ -389,9 +389,8 @@ solver.py: Variable
|
||||
Variable's strength and value properties are observed:
|
||||
|
||||
>>> from gaphas.solver import Variable
|
||||
>>> v = Variable()
|
||||
>>> v = Variable(strength=100)
|
||||
>>> v.value = 10
|
||||
>>> v.strength = 100
|
||||
>>> v
|
||||
Variable(10, 100)
|
||||
>>> undo()
|
||||
|
@ -26,21 +26,28 @@ class ConnectionError(Exception):
|
||||
|
||||
|
||||
class Connections:
|
||||
"""Manage connections and constraints."""
|
||||
|
||||
def __init__(self, solver: Optional[Solver] = None):
|
||||
self._solver = solver or Solver()
|
||||
self._connections = table.Table(Connection, list(range(4)))
|
||||
|
||||
solver = property(lambda s: s._solver)
|
||||
solver = property(
|
||||
lambda s: s._solver, doc="The solver used by this connections instance"
|
||||
)
|
||||
|
||||
def solve(self):
|
||||
"""Solve all constraints."""
|
||||
self._solver.solve()
|
||||
|
||||
def add_constraint(self, item, constraint):
|
||||
"""Add a "simple" constraint for an item."""
|
||||
self._solver.add_constraint(constraint)
|
||||
self._connections.insert(item, None, None, None, constraint, None)
|
||||
return constraint
|
||||
|
||||
def remove_constraint(self, item, constraint):
|
||||
"""Remove an item specific constraint."""
|
||||
self._solver.remove_constraint(constraint)
|
||||
self._connections.delete(item, None, None, None, constraint, None)
|
||||
|
||||
@ -51,25 +58,19 @@ class Connections:
|
||||
"""Create a connection between two items. The connection is registered
|
||||
and the constraint is added to the constraint solver.
|
||||
|
||||
The pair (item, handle) should be unique and not yet connected.
|
||||
The pair ``(item, handle)`` should be unique and not yet connected.
|
||||
|
||||
The callback is invoked when the connection is broken.
|
||||
|
||||
:Parameters:
|
||||
item
|
||||
Connecting item (i.e. a line).
|
||||
handle
|
||||
Handle of connecting item.
|
||||
connected
|
||||
Connected item (i.e. a box).
|
||||
port
|
||||
Port of connected item.
|
||||
constraint
|
||||
Constraint to keep the connection in place.
|
||||
callback
|
||||
Function to be called on disconnection.
|
||||
Args:
|
||||
item (Item): Connecting item (i.e. a line).
|
||||
handle (Handle): Handle of connecting item.
|
||||
connected (Item): Connected item (i.e. a box).
|
||||
port (Port): Port of connected item.
|
||||
constraint (Constraint): Constraint to keep the connection in place.
|
||||
callback (() -> None): Function to be called on disconnection.
|
||||
|
||||
ConnectionError is raised in case handle is already registered
|
||||
``ConnectionError`` is raised in case handle is already registered
|
||||
on a connection.
|
||||
"""
|
||||
if self.get_connection(handle):
|
||||
|
@ -18,32 +18,39 @@ from gaphas.state import (
|
||||
|
||||
@runtime_checkable
|
||||
class Item(Protocol):
|
||||
"""This protocol should be implemented by model items.
|
||||
|
||||
All items that are rendered on a view.
|
||||
"""
|
||||
|
||||
@property
|
||||
def matrix(self) -> Matrix:
|
||||
...
|
||||
"""The "local", item-to-parent matrix."""
|
||||
|
||||
@property
|
||||
def matrix_i2c(self) -> Matrix:
|
||||
...
|
||||
"""Matrix from item to toplevel."""
|
||||
|
||||
def handles(self) -> Sequence[Handle]:
|
||||
"""Return a list of handles owned by the item."""
|
||||
|
||||
def ports(self) -> Sequence[Port]:
|
||||
"""Return list of ports."""
|
||||
"""Return list of ports owned by the item."""
|
||||
|
||||
def point(self, x: float, y: float) -> float:
|
||||
"""Get the distance from a point (``x``, ``y``) to the item.
|
||||
|
||||
``x`` and ``y`` are in item coordinates.
|
||||
|
||||
A distance of 0 means the point is on the item.
|
||||
"""
|
||||
|
||||
def draw(self, context: Context):
|
||||
"""Render the item to a canvas view. Context contains the following
|
||||
attributes:
|
||||
|
||||
- cairo: the Cairo Context use this one to draw
|
||||
- selected, focused, hovered, dropzone: view state of items
|
||||
* `cairo`: the Cairo Context use this one to draw
|
||||
* `selected`, `focused`, `hovered`, `dropzone`: view state of items
|
||||
(True/False)
|
||||
"""
|
||||
|
||||
|
@ -7,10 +7,7 @@ from gaphas.painter.painter import Painter
|
||||
|
||||
|
||||
class PainterChain:
|
||||
"""Chain up a set of painters.
|
||||
|
||||
like ToolChain.
|
||||
"""
|
||||
"""Chain up a set of painters."""
|
||||
|
||||
def __init__(self):
|
||||
self._painters: List[Painter] = []
|
||||
|
@ -22,15 +22,6 @@ class FreeHandCairoContext:
|
||||
KAPPA = 0.5522847498
|
||||
|
||||
def __init__(self, cr, sloppiness=0.5):
|
||||
"""Create context with given sloppiness. Range [0..2.0] gives
|
||||
acceptable results.
|
||||
|
||||
* Draftsman: 0.0
|
||||
* Artist: 0.25
|
||||
* Cartoonist: 0.5
|
||||
* Child: 1.0
|
||||
* Drunk: 2.0
|
||||
"""
|
||||
self.cr = cr
|
||||
self.sloppiness = sloppiness # In range 0.0 .. 2.0
|
||||
|
||||
@ -134,7 +125,19 @@ class FreeHandCairoContext:
|
||||
|
||||
|
||||
class FreeHandPainter:
|
||||
def __init__(self, subpainter: ItemPainterType, sloppiness=1.0):
|
||||
"""This painter is a wrapper for an Item painter. The Cairo context is
|
||||
modified to allow for a sloppy, hand written drawing style.
|
||||
|
||||
Range [0..2.0] gives acceptable results.
|
||||
|
||||
* Draftsman: 0.0
|
||||
* Artist: 0.25
|
||||
* Cartoonist: 0.5
|
||||
* Child: 1.0
|
||||
* Drunk: 2.0
|
||||
"""
|
||||
|
||||
def __init__(self, subpainter: ItemPainterType, sloppiness=0.5):
|
||||
self.subpainter = subpainter
|
||||
self.sloppiness = sloppiness
|
||||
|
||||
|
@ -21,20 +21,20 @@ class Position:
|
||||
def _set_x(self, v):
|
||||
self._x.value = v
|
||||
|
||||
x = property(lambda s: s._x, _set_x)
|
||||
x = property(lambda s: s._x, _set_x, doc="Position.x")
|
||||
|
||||
def _set_y(self, v):
|
||||
self._y.value = v
|
||||
|
||||
y = property(lambda s: s._y, _set_y)
|
||||
y = property(lambda s: s._y, _set_y, doc="Position.y")
|
||||
|
||||
strength = property(lambda s: s._x.strength)
|
||||
strength = property(lambda s: s._x.strength, doc="Strength.")
|
||||
|
||||
def _set_pos(self, pos):
|
||||
"""Set handle position (Item coordinates)."""
|
||||
self._x.value, self._y.value = pos
|
||||
|
||||
pos = property(lambda s: (s._x, s._y), _set_pos)
|
||||
pos = property(lambda s: (s._x, s._y), _set_pos, doc="The position.")
|
||||
|
||||
def __str__(self):
|
||||
return f"<{self.__class__.__name__} object on ({self._x}, {self._y})>"
|
||||
@ -73,11 +73,13 @@ class MatrixProjection(Constraint):
|
||||
self.solve_for(self._proj_pos.x)
|
||||
|
||||
def add_handler(self, handler):
|
||||
"""Add a callback handler."""
|
||||
if not self._handlers:
|
||||
self.matrix.add_handler(self._on_matrix_changed)
|
||||
super().add_handler(handler)
|
||||
|
||||
def remove_handler(self, handler):
|
||||
"""Remove a previously assigned handler."""
|
||||
super().remove_handler(handler)
|
||||
if not self._handlers:
|
||||
self.matrix.remove_handler(self._on_matrix_changed)
|
||||
@ -88,9 +90,13 @@ class MatrixProjection(Constraint):
|
||||
def _set_y(self, y):
|
||||
self._proj_pos.y = y
|
||||
|
||||
pos = property(lambda s: s._proj_pos)
|
||||
x = property(lambda s: s._proj_pos.x, _set_x)
|
||||
y = property(lambda s: s._proj_pos.y, _set_y)
|
||||
pos = property(lambda s: s._proj_pos, doc="The projected position")
|
||||
x = property(
|
||||
lambda s: s._proj_pos.x, _set_x, doc="The projected position's ``x`` part."
|
||||
)
|
||||
y = property(
|
||||
lambda s: s._proj_pos.y, _set_y, doc="The projected position's ``y`` part."
|
||||
)
|
||||
|
||||
def mark_dirty(self, var):
|
||||
if var is self._orig_pos.x or var is self._orig_pos.y:
|
||||
|
@ -62,11 +62,13 @@ class variable:
|
||||
class Variable:
|
||||
"""Representation of a variable in the constraint solver.
|
||||
|
||||
Each Variable has a @value and a @strength. In a constraint the weakest
|
||||
Each Variable has a ``value`` and a ``strength``. In a constraint the weakest
|
||||
variables are changed.
|
||||
|
||||
You can even do some calculating with it. The Variable always represents a
|
||||
float variable.
|
||||
|
||||
The ``variable`` decorator can be used to easily define variables in classes.
|
||||
"""
|
||||
|
||||
def __init__(self, value: SupportsFloat = 0.0, strength: int = NORMAL):
|
||||
@ -75,12 +77,15 @@ class Variable:
|
||||
self._handlers: Set[Callable[[Variable], None]] = set()
|
||||
|
||||
def add_handler(self, handler: Callable[[Variable], None]):
|
||||
"""Add a handler, to be invoked when the value changes."""
|
||||
self._handlers.add(handler)
|
||||
|
||||
def remove_handler(self, handler: Callable[[Variable], None]):
|
||||
"""Remove a handler."""
|
||||
self._handlers.discard(handler)
|
||||
|
||||
def notify(self):
|
||||
"""Notify all handlers."""
|
||||
for handler in self._handlers:
|
||||
handler(self)
|
||||
|
||||
@ -88,11 +93,12 @@ class Variable:
|
||||
def _set_strength(self, strength):
|
||||
self._strength = strength
|
||||
|
||||
strength = reversible_property(lambda s: s._strength, _set_strength)
|
||||
strength = reversible_property(
|
||||
lambda s: s._strength, _set_strength, doc="Strength."
|
||||
)
|
||||
|
||||
def dirty(self):
|
||||
"""Mark the variable dirty in both the constraint solver and attached
|
||||
constraints.
|
||||
"""Mark the variable dirty in all attached constraints.
|
||||
|
||||
Variables are marked dirty also during constraints solving to
|
||||
solve all dependent constraints, i.e. two equals constraints
|
||||
|
@ -6,6 +6,7 @@ from gaphas.view import GtkView
|
||||
|
||||
|
||||
def hover_tool(view: GtkView):
|
||||
"""Highlight the currenly hovered item."""
|
||||
ctrl = Gtk.EventControllerMotion.new(view)
|
||||
ctrl.connect("motion", on_motion)
|
||||
return ctrl
|
||||
|
@ -29,7 +29,8 @@ class MoveType(Protocol):
|
||||
...
|
||||
|
||||
|
||||
def item_tool(view):
|
||||
def item_tool(view: GtkView):
|
||||
"""Handle item movement and movement of handles."""
|
||||
gesture = Gtk.GestureDrag.new(view)
|
||||
drag_state = DragState()
|
||||
gesture.connect("drag-begin", on_drag_begin, drag_state)
|
||||
|
@ -11,6 +11,7 @@ FactoryType = Callable[[], Item]
|
||||
|
||||
|
||||
def placement_tool(view: GtkView, factory: FactoryType, handle_index: int):
|
||||
"""Place a new item on the model."""
|
||||
gesture = Gtk.GestureDrag.new(view)
|
||||
placement_state = PlacementState(factory, handle_index)
|
||||
gesture.connect("drag-begin", on_drag_begin, placement_state)
|
||||
|
@ -10,6 +10,12 @@ class RubberbandState:
|
||||
|
||||
|
||||
class RubberbandPainter:
|
||||
"""The rubberband painter should be used in conjunction with the rubberband
|
||||
tool.
|
||||
|
||||
``RubberbandState`` should be shared between the two.
|
||||
"""
|
||||
|
||||
def __init__(self, rubberband_state):
|
||||
self.rubberband_state = rubberband_state
|
||||
|
||||
@ -27,6 +33,10 @@ class RubberbandPainter:
|
||||
|
||||
|
||||
def rubberband_tool(view, rubberband_state):
|
||||
"""Rubberband selection tool.
|
||||
|
||||
Should be used in conjunction with ``RubberbandPainter``.
|
||||
"""
|
||||
gesture = Gtk.GestureDrag.new(view)
|
||||
gesture.connect("drag-begin", on_drag_begin, rubberband_state)
|
||||
gesture.connect("drag-update", on_drag_update, rubberband_state)
|
||||
|
@ -4,6 +4,7 @@ from gaphas.view import GtkView
|
||||
|
||||
|
||||
def scroll_tool(view: GtkView, speed=5):
|
||||
"""Scroll tool recognized 2 finger scroll gestures."""
|
||||
ctrl = Gtk.EventControllerScroll.new(
|
||||
view, Gtk.EventControllerScrollFlags.BOTH_AXES,
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user