property.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  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, Optional, TYPE_CHECKING
  17. from flexlay.color import Colorf
  18. from flexlay.util.sexpr_reader import get_value_from_tree
  19. from flexlay.util.sexpr_writer import SExprWriter
  20. if TYPE_CHECKING:
  21. from flexlay.gui.properties_widget import PropertiesWidget
  22. class Property:
  23. """
  24. A property is just that: a property
  25. What these classes do is allow properties to easily be written to files,
  26. and displayed in dialogs.
  27. @see: flexlay/gui/generic_dialog.py, supertux/properties_widget.py
  28. """
  29. # Editable means appears in GenericDialog
  30. editable = False
  31. def __init__(self, label: str, identifier: str, default: Any, optional: bool = False) -> None:
  32. self.label: str = label
  33. self.identifier: str = identifier
  34. self.value: Any = default
  35. self.default: Any = default
  36. self.optional: bool = optional
  37. def read(self, sexpr: Any, obj: Any) -> None:
  38. self.value = get_value_from_tree([self.identifier, "_"], sexpr, self.default)
  39. def write(self, writer: SExprWriter, obj: Any) -> None:
  40. if not self.optional or self.value != self.default:
  41. writer.write(self.identifier, self.value)
  42. def property_dialog(self, dialog: 'PropertiesWidget') -> None:
  43. pass
  44. def on_value_change(self, value: Any) -> None:
  45. self.value = value
  46. class BoolProperty(Property):
  47. editable = True
  48. def property_dialog(self, dialog: 'PropertiesWidget') -> None:
  49. dialog.add_bool(self.label, self.value, self.on_value_change)
  50. class IntProperty(Property):
  51. editable = True
  52. def __init__(self, label: str, identifier: str, default: int = 0, optional: bool = False) -> None:
  53. super().__init__(label, identifier, default, optional)
  54. def property_dialog(self, dialog: 'PropertiesWidget') -> None:
  55. dialog.add_int(self.label, self.value, callback=self.on_value_change)
  56. class FloatProperty(Property):
  57. editable = True
  58. def __init__(self, label: str, identifier: str, default: float = 0.0, optional: bool = False) -> None:
  59. super().__init__(label, identifier, default, optional)
  60. def property_dialog(self, dialog: 'PropertiesWidget') -> None:
  61. dialog.add_float(self.label, self.value, callback=self.on_value_change)
  62. class StringProperty(Property):
  63. editable = True
  64. placeholder: Optional[str] = None
  65. def __init__(self, label: str, identifier: str,
  66. default: str = "",
  67. optional: bool = False,
  68. translatable: bool = False,
  69. placeholder: Optional[str] = None) -> None:
  70. super().__init__(label, identifier, default, optional)
  71. self.translatable = translatable
  72. if placeholder is not None:
  73. self.placeholder = placeholder
  74. def read(self, sexpr: Any, obj: Any) -> None:
  75. self.value = get_value_from_tree([self.identifier, "_"], sexpr, self.default)
  76. def write(self, writer: SExprWriter, obj: Any) -> None:
  77. if not self.optional or self.value != self.default:
  78. writer.write_string(self.identifier, self.value, translatable=self.translatable)
  79. def property_dialog(self, dialog: 'PropertiesWidget') -> None:
  80. dialog.add_string(self.label, self.value, self.on_value_change, self.placeholder)
  81. # dialog.add_string(self.label, self.value, self.on_value_change)
  82. class FileProperty(StringProperty):
  83. editable = True
  84. def __init__(self, label: str, identifier: str, default: str = "",
  85. relative_to: str = "", open_in: str = "") -> None:
  86. """
  87. :param relative_to: The prefix text not displayed in the input box
  88. :param open_in: Where the browse dialog opens
  89. """
  90. super().__init__(label, identifier, default=default)
  91. # Where the file dialog opens by default
  92. self.open_in = open_in
  93. # Where the path shown is relative to (if possible)
  94. self.relative_to = relative_to
  95. # The actual path stored, so that the relative path can be displayed.
  96. self.actual_path = ""
  97. def property_dialog(self, dialog: 'PropertiesWidget') -> None:
  98. dialog.add_file(self.label, self.default, self.relative_to, self.open_in, callback=self.on_value_change)
  99. class EnumProperty(StringProperty):
  100. editable = True
  101. def __init__(self,
  102. label: str,
  103. identifier: str,
  104. default: int,
  105. optional: bool = False,
  106. values: Optional[list[str]] = None) -> None:
  107. """
  108. :param default: Is an index from values!!!
  109. """
  110. super().__init__(label, identifier, values[default] if values else "", optional=optional)
  111. self.default_index: int = default
  112. self.values: list[str] = [] if values is None else values
  113. def property_dialog(self, dialog: 'PropertiesWidget') -> None:
  114. dialog.add_enum(self.label, self.values, self.values.index(self.value), self.on_value_change)
  115. class ColorProperty(Property):
  116. editable = True
  117. def __init__(self,
  118. label: str,
  119. identifier: str,
  120. default: Colorf = Colorf(1.0, 1.0, 1.0),
  121. optional: bool = False) -> None:
  122. super().__init__(label, identifier, default=default, optional=optional)
  123. def read(self, sexpr: Any, obj: Any) -> None:
  124. self.value = Colorf(*get_value_from_tree([self.identifier], sexpr, [1.0, 1.0, 1.0]))
  125. def write(self, writer: SExprWriter, obj: Any) -> None:
  126. if not self.optional or self.value != self.default:
  127. if self.value.a == 1.0:
  128. writer.write_color(self.identifier, self.value.to_list()[0:3])
  129. else:
  130. writer.write_color(self.identifier, self.value.to_list())
  131. def property_dialog(self, dialog: 'PropertiesWidget') -> None:
  132. dialog.add_color(self.label, self.value)
  133. # EOF #