123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- from gi.repository import GLib, Gtk
- class Tool:
- def __init__(self):
- self.id = ""
- self.name = ""
- self.properties = []
- self.icon_path = ""
- self.on_change_callback = None
- # Let the tool set values
- self.on_init()
- self.props = {}
- for property in self.properties:
- self.props[property.id] = property
- # Create widget for tool
- self.widget = Gtk.Grid()
- self.widget.set_column_spacing(8)
- self.widget.set_row_spacing(6)
- self.widget.set_halign(Gtk.Align.FILL)
- self.widget.set_hexpand(True)
- vpos = 0
- for property in self.properties:
- # Create Header
- if(property.type == "Header"):
- header = Gtk.HBox()
- header.set_margin_top(6)
- if(vpos != 0):
- # Add a Separator
- separator = Gtk.Separator()
- separator.set_margin_top(6)
- self.widget.attach(separator, 0, vpos, 3, 1)
- vpos += 1
- title = Gtk.Label()
- title.set_halign(Gtk.Align.START)
- if(property.is_subheading):
- title.set_markup("<i>%s</i>" % property.name)
- else:
- title.set_markup("<b>%s</b>" % property.name)
- header.add(title)
- if(property.has_toggle):
- toggle = Gtk.Switch()
- toggle.set_halign(Gtk.Align.END)
- header.add(toggle)
- property.on_toggle_callback = self.on_toggled
- property.set_widget(toggle)
- elif(property.has_button):
- button = Gtk.Button()
- button.set_halign(Gtk.Align.END)
- button.set_label(property.button_label)
- header.add(button)
- property.set_widget(button)
- self.widget.attach(header, 0, vpos, 3, 1)
- # Create Combo
- elif(property.type == "Combo"):
- label = Gtk.Label()
- label.set_halign(Gtk.Align.END)
- label.set_justify(Gtk.Justification.RIGHT)
- label.set_text(property.name)
- self.widget.attach(label, 0, vpos, 1, 1)
- combo = Gtk.ComboBoxText()
- combo.set_hexpand(True)
- self.widget.attach(combo, 1, vpos, 1, 1)
- for option in property.options:
- combo.append_text(option)
- property.set_widget(combo)
- # Create Spin
- elif (property.type == "Spin"):
- label = Gtk.Label()
- label.set_halign(Gtk.Align.END)
- label.set_justify(Gtk.Justification.RIGHT)
- label.set_text(property.name)
- self.widget.attach(label, 0, vpos, 1, 1)
- adjustment = Gtk.Adjustment()
- adjustment.set_lower(property.min)
- adjustment.set_upper(property.max)
- adjustment.set_step_increment((property.max - property.min) / 100)
- property.set_widget(adjustment)
- spin = Gtk.SpinButton()
- spin.set_adjustment(adjustment)
- spin.set_hexpand(True)
- spin.set_digits(3)
- property.ui_widget = spin
- self.widget.attach(spin, 1, vpos, 1, 1)
- # Create Toggle
- elif(property.type == "Toggle"):
- label = Gtk.Label()
- label.set_halign(Gtk.Align.END)
- label.set_justify(Gtk.Justification.RIGHT)
- label.set_text(property.name)
- self.widget.attach(label, 0, vpos, 1, 1)
- toggle = Gtk.ToggleButton()
- toggle.set_label("Enable")
- toggle.set_hexpand(True)
- self.widget.attach(toggle, 1, vpos, 1, 1)
- property.set_widget(toggle)
- # Create Slider
- elif (property.type == "Slider"):
- label = Gtk.Label()
- label.set_halign(Gtk.Align.END)
- label.set_justify(Gtk.Justification.RIGHT)
- label.set_text(property.name)
- self.widget.attach(label, 0, vpos, 1, 1)
- adjustment = Gtk.Adjustment()
- adjustment.set_lower(property.min)
- adjustment.set_upper(property.max)
- adjustment.set_step_increment((property.max - property.min)/100)
- property.set_widget(adjustment)
- slider = Gtk.Scale()
- slider.set_adjustment(adjustment)
- slider.set_hexpand(True)
- slider.set_value_pos(Gtk.PositionType.RIGHT)
- property.ui_widget = slider
- self.widget.attach(slider, 1, vpos, 1, 1)
- if(property.type != "Header"):
- # Create reset button
- icon = Gtk.Image()
- icon.set_from_icon_name("edit-clear-symbolic", Gtk.IconSize.BUTTON)
- reset_button = Gtk.Button()
- reset_button.set_image(icon)
- reset_button.connect("clicked", property.reset_value)
- property.reset_button = reset_button
- self.widget.attach(reset_button, 2, vpos, 1, 1)
- # Connect on change
- property.connect_on_change(self.on_change)
- vpos += 1
- for property in self.properties:
- if(property.type == "Header") and (property.has_toggle):
- self.on_toggled(property, property.widget.get_active())
- separator = Gtk.Separator()
- separator.set_margin_top(6)
- self.widget.attach(separator, 0, vpos, 3, 1)
- self.tool_button = Gtk.ToggleButton()
- self.tool_button.set_tooltip_text(self.name)
- icon = Gtk.Image()
- icon.set_from_file(self.icon_path)
- self.tool_button.set_image(icon)
- def on_toggled(self, sender, value):
- si = self.properties.index(sender)
- for property in self.properties[si+1:]:
- if(property.type == "Header") and (property.has_toggle):
- break
- else:
- property.set_enabled(value)
- def is_default(self):
- res = True
- for prop in self.properties:
- if(prop.get_value() != prop.default):
- res = False
- break
- return res
- def connect_on_change(self, callback):
- self.on_change_callback = callback
- def on_change(self, sender):
- if(self.on_change_callback != None):
- self.on_change_callback(self, sender)
- def on_init(self):
- raise NotImplementedError()
- def on_button_pressed(self):
- raise NotImplementedError()
- def on_update(self, image):
- raise NotImplementedError()
- def load_properties(self, dict):
- for key in dict:
- if(key in self.props):
- self.props[key].set_value(dict[key])
- def get_properties_as_dict(self):
- dict = {}
- for prop in self.properties:
- dict[prop.id] = prop.get_value()
- return dict
- def reset(self):
- for prop in self.properties:
- prop.reset_value()
- class Property:
- def __init__(self, id, name, type, default, **kwargs):
- self.id = id
- self.name = name
- self.type = type
- self.on_change_callback = None
- # Types Include:
- # Slider,
- # Toggle,
- # Spin,
- # Combo,
- # Header
- if(self.type == "Slider") or (self.type == "Spin"):
- # Slider and Spinner
- self.max = kwargs["max"]
- self.min = kwargs["min"]
- self.ui_widget = None
- if(self.type == "Combo"):
- self.options = kwargs["options"]
- if(self.type == "Header"):
- self.has_toggle = kwargs["has_toggle"]
- self.has_button = kwargs["has_button"]
- if(self.has_button):
- self.button_callback = kwargs["button_callback"]
- self.button_label = kwargs["button_label"]
- if("is_subheading" in kwargs):
- self.is_subheading = kwargs["is_subheading"]
- else:
- self.is_subheading = False
- self.value = default
- self.default = default
- self.widget = None
- self.reset_button = None
- self.on_toggle_callback = None
- def get_value(self):
- return self.value
- def set_value(self, value):
- self.value = value
- if(self.type == "Header") and (self.has_toggle):
- self.widget.set_active(value)
- if(self.type == "Slider") or (self.type == "Spin"):
- self.widget.set_value(value)
- if(self.type == "Toggle") or (self.type == "Combo"):
- self.widget.set_active(value)
- self.on_change()
- def reset_value(self, sender=None):
- self.set_value(self.default)
- return self.default
- def update_value(self, sender, arg=None):
- if(self.type == "Header") and (self.has_toggle):
- self.set_value(arg)
- if(self.on_toggle_callback != None):
- self.on_toggle_callback(self, arg)
- if(self.type == "Header") and (self.has_button):
- self.button_callback()
- if(self.type == "Slider") or (self.type == "Spin"):
- self.set_value(sender.get_value())
- if(self.type == "Toggle") or (self.type == "Combo"):
- self.set_value(sender.get_active())
- def set_widget(self, object):
- self.widget = object
- self.reset_value()
- if(self.type == "Header") and (self.has_toggle):
- object.connect("state-set", self.update_value)
- if(self.type == "Header") and (self.has_button):
- object.connect("clicked", self.update_value)
- if(self.type == "Slider") or (self.type == "Spin"):
- object.connect("value-changed", self.update_value)
- if(self.type == "Toggle"):
- object.connect("toggled", self.update_value)
- if(self.type == "Combo"):
- object.connect("changed", self.update_value)
- def set_enabled(self, enabled):
- if(self.type == "Slider") or (self.type == "Spin"):
- self.ui_widget.set_sensitive(enabled)
- elif(self.widget != None):
- self.widget.set_sensitive(enabled)
- if(self.reset_button != None):
- self.reset_button.set_sensitive(enabled)
- def connect_on_change(self, callback):
- self.on_change_callback = callback
- def on_change(self):
- if(self.on_change_callback != None):
- self.on_change_callback(self)
|