Add handlers for solved constraints

This should be used to trigger items that should redraw due to
constraint solving.
This commit is contained in:
Arjan Molenaar 2020-12-14 09:20:01 +01:00
parent e8566883fb
commit de2d2a8dab
No known key found for this signature in database
GPG Key ID: BF977B918996CB13
3 changed files with 74 additions and 4 deletions

View File

@ -1,6 +1,8 @@
"""This module contains a connections manager."""
from typing import Callable, Iterator, NamedTuple, Optional
from __future__ import annotations
from typing import Callable, Iterator, NamedTuple, Optional, Set
from gaphas import table
from gaphas.connector import Handle, Port
@ -40,8 +42,27 @@ class Connections:
def __init__(self, solver: Optional[Solver] = None) -> None:
self._solver = solver or Solver()
self._connections: table.Table[Connection] = table.Table(
Connection, tuple(range(4))
Connection, tuple(range(5))
)
self._handlers: Set[Callable[[Connection], None]] = set()
self._solver.add_handler(self._on_constraint_solved)
def add_handler(self, handler):
"""Add a callback handler.
Handlers are triggered when a constraint has been solved.
"""
self._handlers.add(handler)
def remove_handler(self, handler):
"""Remove a previously assigned handler."""
self._handlers.discard(handler)
def _on_constraint_solved(self, constraint):
for cinfo in self._connections.query(constraint=constraint):
for handler in self._handlers:
handler(cinfo)
@property
def solver(self) -> Solver:
@ -107,7 +128,6 @@ class Connections:
If handle is not None, only the connection for that handle is
disconnected.
"""
# disconnect on canvas level
for cinfo in list(self._connections.query(item=item, handle=handle)):
self._disconnect_item(*cinfo)

View File

@ -32,7 +32,7 @@ every constraint is being asked to solve itself
(`constraint.Constraint.solve_for()` method) changing appropriate
variables to make the constraint valid again.
"""
from typing import Collection, List, Set
from typing import Callable, Collection, List, Set
from gaphas.solver.constraint import Constraint
from gaphas.state import observed, reversible_pair
@ -49,6 +49,19 @@ class Solver:
self._constraints: Set[Constraint] = set()
self._marked_cons: List[Constraint] = []
self._solving = False
self._handlers: Set[Callable[[Constraint], None]] = set()
def add_handler(self, handler):
"""Add a callback handler, triggered when a constraint is resolved."""
self._handlers.add(handler)
def remove_handler(self, handler):
"""Remove a previously assigned handler."""
self._handlers.discard(handler)
def _notify(self, constraint):
for handler in self._handlers:
handler(constraint)
@property
def constraints(self) -> Collection[Constraint]:
@ -154,6 +167,7 @@ class Solver:
10.0
"""
marked_cons = self._marked_cons
notify = self._notify
try:
self._solving = True
@ -164,6 +178,7 @@ class Solver:
while n < len(marked_cons):
c = marked_cons[n]
c.solve()
notify(c)
n += 1
self._marked_cons = []

View File

@ -66,3 +66,38 @@ def test_remove_item_constraint_when_item_is_disconnected(connections):
connections.disconnect_item(i)
assert list(connections.get_connections(item=i)) == []
def test_notify_on_constraint_solved(connections):
events = []
def on_notify(cinfo):
events.append(cinfo)
i = item.Line(connections)
c = EqualsConstraint(i.handles()[0].pos.x, i.handles()[0].pos.x)
connections.add_constraint(i, c)
connections.add_handler(on_notify)
connections.solve()
assert events
assert events[0].constraint is c
def test_connection_remove_handler(connections):
events = []
def on_notify(cinfo):
events.append(cinfo)
i = item.Line(connections)
c = EqualsConstraint(i.handles()[0].pos.x, i.handles()[0].pos.x)
connections.add_constraint(i, c)
connections.add_handler(on_notify)
connections.remove_handler(on_notify)
connections.remove_handler(on_notify)
connections.solve()
assert not events