Source code for elide.graph.spot

# This file is part of Elide, frontend to Lisien, a framework for life simulation games.
# Copyright (c) Zachary Spector, public@zacharyspector.com
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
"""Widget to represent :class:`Place`s. :class:`Pawn` moves around on
top of these.

"""

from kivy.clock import Clock, triggered
from kivy_garden.collider import Collide2DPoly

from elide.pawnspot import GraphPawnSpot

from .arrow import get_points, get_quad_vertices


def trigger(func):
	return triggered()(func)


[docs] class GraphSpot(GraphPawnSpot): """The icon that represents a :class:`Place`. Each :class:`Spot` is located on the Board that represents the :class:`Character` that the underlying :class:`Place` is in. Its coordinates are relative to its :class:`Board`, not necessarily the window the :class:`Board` is in. """ default_image_paths = ["atlas://rltiles/floor.atlas/floor-stone"] default_pos = (0.5, 0.5) def __init__(self, **kwargs): """Deal with triggers and bindings, and arrange to take care of changes in game-time. """ self._pospawn_partials = {} self._pospawn_triggers = {} kwargs["size_hint"] = (None, None) if "place" in kwargs: kwargs["proxy"] = kwargs["place"] del kwargs["place"] super().__init__(**kwargs) def on_board(self, *args): super().on_board(*args) self.board.bind(size=self._upd_pos)
[docs] def on_pos(self, *args): def upd(orig, dest): bgr = r * bg_scale_selected # change for selectedness pls if (orig, dest) not in port_index: return idx = port_index[orig, dest] inst = instructions[orig, dest] (ox, oy, dx, dy), (x1, y1, endx, endy, x2, y2) = get_points( spot[orig], spot[dest], arrowhead_size ) if ox < dx: bot_left_xs[idx] = ox - bgr top_right_xs[idx] = dx + bgr else: bot_left_xs[idx] = dx - bgr top_right_xs[idx] = ox + bgr if oy < dy: bot_left_ys[idx] = oy - bgr top_right_ys[idx] = dy + bgr else: bot_left_ys[idx] = dy - bgr top_right_ys[idx] = oy + bgr quadverts = get_quad_vertices( ox, oy, dx, dy, x1, y1, endx, endy, x2, y2, bgr, r ) inst["shaft_bg"].points = quadverts["shaft_bg"] colliders[orig, dest] = Collide2DPoly(points=quadverts["shaft_bg"]) inst["left_head_bg"].points = quadverts["left_head_bg"] inst["right_head_bg"].points = quadverts["right_head_bg"] inst["shaft_fg"].points = quadverts["shaft_fg"] inst["left_head_fg"].points = quadverts["left_head_fg"] inst["right_head_fg"].points = quadverts["right_head_fg"] if not self.board: return arrow_plane = self.board.arrow_plane fbo = arrow_plane._fbo arrowhead_size = arrow_plane.arrowhead_size r = arrow_plane.arrow_width // 2 bg_scale_selected = arrow_plane.bg_scale_selected spot = self.board.spot succ = self.board.arrow pred = self.board.pred_arrow name = self.name instructions = arrow_plane._instructions_map colliders = arrow_plane._colliders_map instructions = arrow_plane._instructions_map port_index = arrow_plane._port_index bot_left_xs = arrow_plane._bot_left_corner_xs bot_left_ys = arrow_plane._bot_left_corner_ys top_right_xs = arrow_plane._top_right_corner_xs top_right_ys = arrow_plane._top_right_corner_ys fbo.bind() fbo.clear_buffer() if name in succ: for dest in succ[name]: upd(name, dest) if name in pred: for orig in pred[name]: upd(orig, name) fbo.release() return super().on_pos(*args)
def _upd_pos(self, *args): if self.board is None: Clock.schedule_once(self._upd_pos, 0) return self.pos = ( int(self.proxy.get("_x", self.default_pos[0]) * self.board.width), int(self.proxy.get("_y", self.default_pos[1]) * self.board.height), )
[docs] def finalize(self, initial=True): if initial: self._upd_pos() super().finalize(initial)
[docs] def push_pos(self, *args): """Set my current position, expressed as proportions of the graph's width and height, into the ``_x`` and ``_y`` keys of the entity in my ``proxy`` property, such that it will be recorded in the database. """ self.proxy["_x"] = self.x / self.board.width self.proxy["_y"] = self.y / self.board.height
_trigger_push_pos = trigger(push_pos)
[docs] def on_touch_up(self, touch): if touch.grab_current is not self: return False self.center = touch.pos self._trigger_push_pos() touch.ungrab(self) self._trigger_push_pos() return True
def __repr__(self): """Give my name and position.""" return "<{}@({},{}) at {}>".format(self.name, self.x, self.y, id(self))