__init__.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. from gi.repository import GLib, Gtk
  2. class Tool:
  3. def __init__(self):
  4. self.id = ""
  5. self.name = ""
  6. self.properties = []
  7. self.icon_path = ""
  8. self.on_change_callback = None
  9. # Let the tool set values
  10. self.on_init()
  11. self.props = {}
  12. for property in self.properties:
  13. self.props[property.id] = property
  14. # Create widget for tool
  15. self.widget = Gtk.Grid()
  16. self.widget.set_column_spacing(8)
  17. self.widget.set_row_spacing(6)
  18. self.widget.set_halign(Gtk.Align.FILL)
  19. self.widget.set_hexpand(True)
  20. vpos = 0
  21. for property in self.properties:
  22. # Create Header
  23. if(property.type == "Header"):
  24. header = Gtk.HBox()
  25. header.set_margin_top(6)
  26. if(vpos != 0):
  27. # Add a Separator
  28. separator = Gtk.Separator()
  29. separator.set_margin_top(6)
  30. separator.show()
  31. self.widget.attach(separator, 0, vpos, 3, 1)
  32. vpos += 1
  33. title = Gtk.Label()
  34. title.set_halign(Gtk.Align.START)
  35. if(property.is_subheading):
  36. title.set_markup("<i>%s</i>" % property.name)
  37. else:
  38. title.set_markup("<b>%s</b>" % property.name)
  39. header.add(title)
  40. if(property.has_toggle):
  41. toggle = Gtk.Switch()
  42. toggle.set_halign(Gtk.Align.END)
  43. header.add(toggle)
  44. property.on_toggle_callback = self.on_toggled
  45. property.set_widget(toggle)
  46. elif(property.has_button):
  47. button = Gtk.Button()
  48. button.set_halign(Gtk.Align.END)
  49. button.set_label(property.button_label)
  50. header.add(button)
  51. property.set_widget(button)
  52. self.widget.attach(header, 0, vpos, 3, 1)
  53. # Create Combo
  54. elif(property.type == "Combo"):
  55. label = Gtk.Label()
  56. label.set_halign(Gtk.Align.END)
  57. label.set_justify(Gtk.Justification.RIGHT)
  58. label.set_text(property.name)
  59. self.widget.attach(label, 0, vpos, 1, 1)
  60. combo = Gtk.ComboBoxText()
  61. combo.set_hexpand(True)
  62. self.widget.attach(combo, 1, vpos, 1, 1)
  63. for option in property.options:
  64. combo.append_text(option)
  65. property.set_widget(combo)
  66. # Create Spin
  67. elif (property.type == "Spin"):
  68. label = Gtk.Label()
  69. label.set_halign(Gtk.Align.END)
  70. label.set_justify(Gtk.Justification.RIGHT)
  71. label.set_text(property.name)
  72. self.widget.attach(label, 0, vpos, 1, 1)
  73. adjustment = Gtk.Adjustment()
  74. adjustment.set_lower(property.min)
  75. adjustment.set_upper(property.max)
  76. adjustment.set_step_increment((property.max - property.min) / 100)
  77. property.set_widget(adjustment)
  78. spin = Gtk.SpinButton()
  79. spin.set_adjustment(adjustment)
  80. spin.set_hexpand(True)
  81. spin.set_digits(3)
  82. property.ui_widget = spin
  83. self.widget.attach(spin, 1, vpos, 1, 1)
  84. # Create Toggle
  85. elif(property.type == "Toggle"):
  86. label = Gtk.Label()
  87. label.set_halign(Gtk.Align.END)
  88. label.set_justify(Gtk.Justification.RIGHT)
  89. label.set_text(property.name)
  90. self.widget.attach(label, 0, vpos, 1, 1)
  91. toggle = Gtk.ToggleButton()
  92. toggle.set_label("Enable")
  93. toggle.set_hexpand(True)
  94. self.widget.attach(toggle, 1, vpos, 1, 1)
  95. property.set_widget(toggle)
  96. # Create Slider
  97. elif (property.type == "Slider"):
  98. label = Gtk.Label()
  99. label.set_halign(Gtk.Align.END)
  100. label.set_justify(Gtk.Justification.RIGHT)
  101. label.set_text(property.name)
  102. self.widget.attach(label, 0, vpos, 1, 1)
  103. adjustment = Gtk.Adjustment()
  104. adjustment.set_lower(property.min)
  105. adjustment.set_upper(property.max)
  106. adjustment.set_step_increment((property.max - property.min)/100)
  107. property.set_widget(adjustment)
  108. slider = Gtk.Scale()
  109. slider.set_adjustment(adjustment)
  110. slider.set_hexpand(True)
  111. slider.set_value_pos(Gtk.PositionType.RIGHT)
  112. property.ui_widget = slider
  113. self.widget.attach(slider, 1, vpos, 1, 1)
  114. if(property.type != "Header"):
  115. # Create reset button
  116. icon = Gtk.Image()
  117. icon.set_from_icon_name("edit-clear-symbolic", Gtk.IconSize.BUTTON)
  118. reset_button = Gtk.Button()
  119. reset_button.set_image(icon)
  120. reset_button.connect("clicked", property.reset_value)
  121. property.reset_button = reset_button
  122. self.widget.attach(reset_button, 2, vpos, 1, 1)
  123. # Connect on change
  124. property.connect_on_change(self.on_change)
  125. vpos += 1
  126. for property in self.properties:
  127. if(property.type == "Header") and (property.has_toggle):
  128. self.on_toggled(property, property.widget.get_active())
  129. separator = Gtk.Separator()
  130. separator.set_margin_top(6)
  131. separator.show()
  132. self.widget.attach(separator, 0, vpos, 3, 1)
  133. self.widget.show_all()
  134. self.tool_button = Gtk.ToggleButton()
  135. self.tool_button.set_tooltip_text(self.name)
  136. icon = Gtk.Image()
  137. icon.set_from_file(self.icon_path)
  138. self.tool_button.set_image(icon)
  139. def on_toggled(self, sender, value):
  140. si = self.properties.index(sender)
  141. for property in self.properties[si+1:]:
  142. if(property.type == "Header") and (property.has_toggle):
  143. break
  144. else:
  145. property.set_enabled(value)
  146. def is_default(self):
  147. res = True
  148. for prop in self.properties:
  149. if(prop.get_value() != prop.default):
  150. res = False
  151. break
  152. return res
  153. def connect_on_change(self, callback):
  154. self.on_change_callback = callback
  155. def on_change(self, sender):
  156. if(self.on_change_callback != None):
  157. self.on_change_callback(self, sender)
  158. def on_init(self):
  159. raise NotImplementedError()
  160. def on_button_pressed(self):
  161. raise NotImplementedError()
  162. def on_update(self, image):
  163. raise NotImplementedError()
  164. def load_properties(self, dict):
  165. for key in dict:
  166. if(key in self.props):
  167. self.props[key].set_value(dict[key])
  168. def get_properties_as_dict(self):
  169. dict = {}
  170. for prop in self.properties:
  171. dict[prop.id] = prop.get_value()
  172. return dict
  173. def reset(self):
  174. for prop in self.properties:
  175. prop.reset_value()
  176. class Property:
  177. def __init__(self, id, name, type, default, **kwargs):
  178. self.id = id
  179. self.name = name
  180. self.type = type
  181. self.on_change_callback = None
  182. # Types Include:
  183. # Slider,
  184. # Toggle,
  185. # Spin,
  186. # Combo,
  187. # Header
  188. if(self.type == "Slider") or (self.type == "Spin"):
  189. # Slider and Spinner
  190. self.max = kwargs["max"]
  191. self.min = kwargs["min"]
  192. self.ui_widget = None
  193. if(self.type == "Combo"):
  194. self.options = kwargs["options"]
  195. if(self.type == "Header"):
  196. self.has_toggle = kwargs["has_toggle"]
  197. self.has_button = kwargs["has_button"]
  198. if(self.has_button):
  199. self.button_callback = kwargs["button_callback"]
  200. self.button_label = kwargs["button_label"]
  201. if("is_subheading" in kwargs):
  202. self.is_subheading = kwargs["is_subheading"]
  203. else:
  204. self.is_subheading = False
  205. self.value = default
  206. self.default = default
  207. self.widget = None
  208. self.reset_button = None
  209. self.on_toggle_callback = None
  210. def get_value(self):
  211. return self.value
  212. def set_value(self, value):
  213. self.value = value
  214. if(self.type == "Header") and (self.has_toggle):
  215. self.widget.set_active(value)
  216. if(self.type == "Slider") or (self.type == "Spin"):
  217. self.widget.set_value(value)
  218. if(self.type == "Toggle") or (self.type == "Combo"):
  219. self.widget.set_active(value)
  220. self.on_change()
  221. def reset_value(self, sender=None):
  222. self.set_value(self.default)
  223. return self.default
  224. def update_value(self, sender, arg=None):
  225. if(self.type == "Header") and (self.has_toggle):
  226. self.set_value(arg)
  227. if(self.on_toggle_callback != None):
  228. self.on_toggle_callback(self, arg)
  229. if(self.type == "Header") and (self.has_button):
  230. self.button_callback()
  231. if(self.type == "Slider") or (self.type == "Spin"):
  232. self.set_value(sender.get_value())
  233. if(self.type == "Toggle") or (self.type == "Combo"):
  234. self.set_value(sender.get_active())
  235. def set_widget(self, object):
  236. self.widget = object
  237. self.reset_value()
  238. if(self.type == "Header") and (self.has_toggle):
  239. object.connect("state-set", self.update_value)
  240. if(self.type == "Header") and (self.has_button):
  241. object.connect("clicked", self.update_value)
  242. if(self.type == "Slider") or (self.type == "Spin"):
  243. object.connect("value-changed", self.update_value)
  244. if(self.type == "Toggle"):
  245. object.connect("toggled", self.update_value)
  246. if(self.type == "Combo"):
  247. object.connect("changed", self.update_value)
  248. def set_enabled(self, enabled):
  249. if(self.type == "Slider") or (self.type == "Spin"):
  250. self.ui_widget.set_sensitive(enabled)
  251. elif(self.widget != None):
  252. self.widget.set_sensitive(enabled)
  253. if(self.reset_button != None):
  254. self.reset_button.set_sensitive(enabled)
  255. def connect_on_change(self, callback):
  256. self.on_change_callback = callback
  257. def on_change(self):
  258. if(self.on_change_callback != None):
  259. self.on_change_callback(self)