__init__.py 11 KB

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