property.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. # Flexlay - A Generic 2D Game Editor
  2. # Copyright (C) 2014 Ingo Ruhnke <grumbel@gmail.com>
  3. #
  4. # This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. from typing import Any
  17. from flexlay.util.sexpr_writer import SExprWriter
  18. from flexlay.workspace import Workspace
  19. from flexlay.math import Point
  20. from flexlay.util.sexpr_reader import get_value_from_tree
  21. from flexlay.gui.properties_widget import PropertiesWidget
  22. from flexlay.property import (
  23. Property,
  24. EnumProperty,
  25. StringProperty,
  26. IntProperty,
  27. )
  28. class DirectionProperty(EnumProperty):
  29. editable = True
  30. def __init__(self, label: str, identifier: str, default: Any) -> None:
  31. super().__init__(label, identifier, default, optional=True, values=["auto", "left", "right"])
  32. class InlinePosProperty(Property):
  33. editable = False
  34. def __init__(self) -> None:
  35. self.identifier = "" # To stop errors
  36. def read(self, sexpr: Any, obj: Any) -> None:
  37. obj.pos.x = get_value_from_tree(["x", "_"], sexpr, 0.0)
  38. obj.pos.y = get_value_from_tree(["y", "_"], sexpr, 0.0)
  39. def write(self, writer: SExprWriter, obj: Any) -> None:
  40. if obj.pos.x != 0:
  41. writer.write_float("x", obj.pos.x)
  42. if obj.pos.y != 0:
  43. writer.write_float("y", obj.pos.y)
  44. class InlineTilePosProperty(InlinePosProperty):
  45. """Written to file as coords on tilemap, but displays correctly."""
  46. editable = False
  47. def read(self, sexpr: Any, obj: Any) -> None:
  48. obj.pos.x = get_value_from_tree(["x", "_"], sexpr, 0.0) * 32
  49. obj.pos.y = get_value_from_tree(["y", "_"], sexpr, 0.0) * 32
  50. def write(self, writer: SExprWriter, obj: Any) -> None:
  51. tilemap_position = Point(obj.pos.x // 32, obj.pos.y // 32)
  52. writer.write_inline_point(tilemap_position)
  53. class InlineRectProperty(Property):
  54. editable = False
  55. def __init__(self) -> None:
  56. pass
  57. def read(self, sexpr: Any, obj: Any) -> None:
  58. obj.pos.x = get_value_from_tree(["x", "_"], sexpr, 0.0)
  59. obj.pos.y = get_value_from_tree(["y", "_"], sexpr, 0.0)
  60. obj.size.width = get_value_from_tree(["width", "_"], sexpr, 0.0)
  61. obj.size.height = get_value_from_tree(["height", "_"], sexpr, 0.0)
  62. def write(self, writer: SExprWriter, obj: Any) -> None:
  63. writer.write_inline_sizef(obj.size)
  64. writer.write_inline_pointf(obj.pos)
  65. class SpriteProperty(StringProperty):
  66. editable = False
  67. placeholder = "default"
  68. def write(self, writer: SExprWriter, obj: Any) -> None:
  69. if self.value:
  70. super().write(writer, obj)
  71. class BadGuyProperty(EnumProperty):
  72. editable = True
  73. def __init__(self, label: str, identifier: str) -> None:
  74. from supertux.gameobj_factor import supertux_gameobj_factory
  75. super().__init__(label, identifier, 0, values=[badguy[0] for badguy in supertux_gameobj_factory.badguys])
  76. class ImageProperty(StringProperty):
  77. editable = False
  78. def __init__(self, *args: Any, **kwargs: Any) -> None:
  79. super().__init__(*args, **kwargs)
  80. class SoundProperty(StringProperty):
  81. editable = False
  82. def __init__(self, label: str, identifier: str, default: str = "") -> None:
  83. super().__init__(label, identifier, default=default)
  84. class PathProperty(Property):
  85. class Node:
  86. mode_values = ['oneshot', 'pingpong', 'circular']
  87. def __init__(self, x: float, y: float, time: float) -> None:
  88. self.x = x
  89. self.y = y
  90. self.time = time
  91. editable = False
  92. def __init__(self, label: str, identifier: str) -> None:
  93. self.label: str = label
  94. self.identifier: str = identifier
  95. self.mode: int = 2
  96. self.nodes: list[PathProperty.Node] = []
  97. def read(self, sexpr: Any, obj: Any) -> None:
  98. self.nodes = []
  99. sexpr = get_value_from_tree([self.identifier], sexpr, [])
  100. for node in sexpr:
  101. if node[0] == 'node':
  102. x = get_value_from_tree(["x", "_"], node[1:], 0)
  103. y = get_value_from_tree(["y", "_"], node[1:], 0)
  104. time = get_value_from_tree(["time", "_"], node[1:], 1)
  105. self.nodes.append(PathProperty.Node(x, y, time))
  106. elif node[0] == 'mode':
  107. if node[1] in PathProperty.Node.mode_values:
  108. self.mode = PathProperty.Node.mode_values.index(node[1])
  109. else:
  110. raise RuntimeError("unknown enum value %r" % node[1])
  111. else:
  112. raise RuntimeError("unknown tag %r" % node[0])
  113. def write(self, writer: SExprWriter, obj: Any) -> None:
  114. if self.nodes:
  115. writer.begin_list("path")
  116. if self.mode != 2:
  117. writer.write_string("mode", PathProperty.Node.mode_values[self.mode])
  118. for node in self.nodes:
  119. writer.begin_list("node")
  120. writer.write_float("x", node.x)
  121. writer.write_float("y", node.y)
  122. if node.time != 1:
  123. writer.write_float("time", node.time)
  124. writer.end_list()
  125. writer.end_list()
  126. class SampleProperty(StringProperty):
  127. editable = False
  128. def __init__(self, label: str, identifier: str, default: str) -> None:
  129. super().__init__(label, identifier, default, optional=True)
  130. class TilemapProperty(EnumProperty):
  131. editable = False
  132. def __init__(self, label: str, identifier: str, optional: bool, placeholder: Any = None) -> None:
  133. super().__init__(label, identifier, 0, optional=optional, values=None)
  134. # super().__init__(label, identifier, "", optional=True, placeholder=placeholder)
  135. def property_dialog(self, dialog: PropertiesWidget) -> None:
  136. self.values = self._get_tilemaps()
  137. super().property_dialog(dialog)
  138. def _get_tilemaps(self) -> list[str]:
  139. assert Workspace.current is not None
  140. sector = Workspace.current.current_sector
  141. if sector is None:
  142. return [""]
  143. return [""] + [tilemap.name for tilemap in sector.tilemaps]
  144. class SectorProperty(StringProperty):
  145. editable = False
  146. def __init__(self, label: str, identifier: str, default: Any, optional: bool) -> None:
  147. super().__init__(label, identifier, default, optional=optional)
  148. class ZPosProperty(IntProperty):
  149. editable = True
  150. def __init__(self, default: int = 0) -> None:
  151. super().__init__("Z-Pos", "z-pos", default=default, optional=True)
  152. # EOF #