4 from gi
.repository
import GObject
, Gdk
, Gtk
, GLib
as glib
7 Gtk
.TreeView
.insert_column_with_attributes
= lambda self
, col
, title
, renderer
, xarg
= None, **kwargs
: self
.insert_column(Gtk
.TreeViewColumn(title
= title
, cell_renderer
= renderer
, **kwargs
), col
)
9 def callback(cmd
, cb
, args
):
10 print ("%s %s %s" % (cmd
, cb
, args
))
12 def bold_label(text
, halign
= 1):
14 l
.set_markup("<b>%s</b>" % text
)
15 l
.set_alignment(halign
, 0.5)
20 l
.set_alignment(0, 0.5)
23 def standard_hslider(adj
):
24 sc
= Gtk
.HScale(adjustment
= adj
)
25 sc
.set_size_request(160, -1)
26 sc
.set_value_pos(Gtk
.PositionType
.RIGHT
)
30 'c' : 0, 'c#' : 1, 'db' : 1,
31 'd' : 2, 'd#' : 3, 'eb' : 3,
32 'e' : 4, 'e#' : 5, 'fb' : 5,
33 'f' : 5, 'f#' : 6, 'gb' : 6,
34 'g' : 7, 'g#' : 8, 'ab' : 8,
35 'a' : 9, 'a#' : 10, 'bb' : 10,
36 'b' : 11, 'b#' : 0, 'cb' : 11,
39 def sfznote2value(note
):
40 if re
.match("[0-9]+$", note
):
41 return int(rdata
['key'])
43 g
= re
.match("([cdefgab](#|b)?)(-?[0-9])", note
)
45 raise ValueError(note
)
46 return 12 + int(g
.group(3)) * 12 + notenames
[g
.group(1).lower()]
49 def __init__(self
, min, max, format
= "%f"):
52 self
.format_string
= format
54 return float(self
.min) * ((float(self
.max) / self
.min) ** (value
/ 100.0))
55 def unmap(self
, value
):
56 return math
.log(value
/ float(self
.min)) * 100 / math
.log(float(self
.max) / self
.min)
57 def format_value(self
, value
):
58 return self
.format_string
% self
.map(value
)
62 ms_format
= "%0.1f ms"
63 lfo_freq_mapper
= LogMapper(0.01, 20, "%0.2f")
64 env_mapper
= LogMapper(0.002, 20, "%f")
65 filter_freq_mapper
= LogMapper(20, 20000, "%0.1f Hz")
67 def standard_mapped_hslider(adj
, mapper
):
68 sc
= Gtk
.HScale(adjustment
= adj
)
69 sc
.set_size_request(160, -1)
70 sc
.set_value_pos(Gtk
.PositionType
.RIGHT
)
71 sc
.connect('format-value', lambda scale
, value
, mapper
: mapper
.format_value(value
), mapper
)
74 def standard_align(w
, xo
, yo
, xs
, ys
):
75 a
= Gtk
.Alignment(xalign
= xo
, yalign
= yo
, xscale
= xs
, yscale
= ys
)
79 def standard_vscroll_window(width
, height
, content
= None):
80 scroller
= Gtk
.ScrolledWindow()
81 scroller
.set_size_request(width
, height
)
82 scroller
.set_shadow_type(Gtk
.ShadowType
.NONE
);
83 scroller
.set_policy(Gtk
.PolicyType
.NEVER
, Gtk
.PolicyType
.AUTOMATIC
);
84 if content
is not None:
85 scroller
.add_with_viewport(content
)
88 def standard_combo(model
, active_item
= None, column
= 0, active_item_lookup
= None, lookup_column
= None, width
= None):
89 cb
= Gtk
.ComboBox(model
= model
)
90 if active_item_lookup
is not None:
91 if lookup_column
is None:
92 lookup_column
= column
93 active_item
= ls_index(model
, active_item_lookup
, lookup_column
)
94 if active_item
is not None:
95 cb
.set_active(active_item
)
96 cell
= Gtk
.CellRendererText()
98 cb
.set_size_request(width
, -1)
99 cb
.pack_start(cell
, True)
100 cb
.add_attribute(cell
, 'text', column
)
103 def ls_index(list_store
, value
, column
):
104 for i
in range(len(list_store
)):
105 if list_store
[i
][column
] == value
:
109 def standard_filter(patterns
, name
):
116 def checkbox_changed_bool(checkbox
, vpath
):
117 vpath
.set(1 if checkbox
.get_active() else 0)
119 def adjustment_changed_int(adjustment
, vpath
):
120 vpath
.set(int(adjustment
.get_value()))
122 def adjustment_changed_float(adjustment
, vpath
):
123 vpath
.set(float(adjustment
.get_value()))
125 def adjustment_changed_float_mapped(adjustment
, vpath
, mapper
):
126 vpath
.set(mapper
.map(adjustment
.get_value()))
128 def combo_value_changed(combo
, vpath
, value_offset
= 0):
129 if combo
.get_active() != -1:
130 vpath
.set(value_offset
+ combo
.get_active())
132 def combo_value_changed_use_column(combo
, vpath
, column
):
133 if combo
.get_active() != -1:
134 vpath
.set(combo
.get_model()[combo
.get_active()][column
])
136 def tree_toggle_changed_bool(renderer
, tree_path
, model
, opath
, column
):
137 model
[int(tree_path
)][column
] = not model
[int(tree_path
)][column
]
138 cbox
.do_cmd(model
.make_row_item(opath
, tree_path
), None, [1 if model
[int(tree_path
)][column
] else 0])
140 def tree_combo_changed(renderer
, tree_path
, new_value
, model
, opath
, column
):
141 new_value
= renderer
.get_property('model')[new_value
][0]
142 model
[int(tree_path
)][column
] = new_value
143 cbox
.do_cmd(model
.make_row_item(opath
, tree_path
), None, [new_value
])
145 def standard_toggle_renderer(list_model
, path
, column
):
146 toggle
= Gtk
.CellRendererToggle()
147 toggle
.connect('toggled', tree_toggle_changed_bool
, list_model
, path
, column
)
150 def standard_combo_renderer(list_model
, model
, path
, column
):
151 combo
= Gtk
.CellRendererCombo()
152 combo
.set_property('model', model
)
153 combo
.set_property('editable', True)
154 combo
.set_property('has-entry', False)
155 combo
.set_property('text-column', 1)
156 combo
.set_property('mode', Gtk
.CellRendererMode
.EDITABLE
)
157 combo
.connect('changed', tree_combo_changed
, list_model
, path
, column
)
160 def add_display_row(t
, row
, label
, path
, values
, item
):
161 t
.attach(bold_label(label
), 0, 1, row
, row
+1, Gtk
.AttachOptions
.SHRINK | Gtk
.AttachOptions
.FILL
, Gtk
.AttachOptions
.SHRINK
)
162 w
= left_label(getattr(values
, item
))
163 t
.attach(w
, 1, 2, row
, row
+1, Gtk
.AttachOptions
.EXPAND | Gtk
.AttachOptions
.FILL
, Gtk
.AttachOptions
.SHRINK
)
166 def set_timer(widget
, time
, func
, *args
):
167 refresh_id
= glib
.timeout_add(time
, func
, *args
)
168 widget
.connect('destroy', lambda obj
, id: glib
.source_remove(id), refresh_id
)
170 def create_menu(title
, items
):
171 menuitem
= Gtk
.MenuItem
.new_with_mnemonic(title
)
172 if items
is not None:
174 menuitem
.set_submenu(menu
)
175 for label
, meth
in items
:
176 mit
= Gtk
.MenuItem
.new_with_mnemonic(label
)
178 mit
.set_sensitive(False)
180 mit
.connect('activate', meth
)
184 def note_to_name(note
):
188 return ("C C#D D#E F F#G G#A A#B "[n
* 2 : n
* 2 + 2]) + str((note
// 12) - 2)
190 #################################################################################################################################
192 class TableRowWidget
:
193 def __init__(self
, label
, name
, **kwargs
):
197 def get_with_default(self
, name
, def_value
):
198 return self
.kwargs
[name
] if name
in self
.kwargs
else def_value
199 def create_label(self
):
200 return bold_label(self
.label
)
201 def has_attr(self
, values
):
202 if type(values
) is dict:
203 return self
.name
in values
204 return hasattr(values
, self
.name
)
205 def get_attr(self
, values
):
206 if type(values
) is dict:
207 return values
[self
.name
]
208 return getattr(values
, self
.name
)
209 def get_value(self
, values
, vpath
):
210 if len(vpath
.args
) == 1:
211 return self
.get_attr(values
)[vpath
.args
[0]]
212 return self
.get_attr(values
)
213 def add_row(self
, table
, row
, vpath
, values
):
214 table
.attach(self
.create_label(), 0, 1, row
, row
+ 1, Gtk
.AttachOptions
.SHRINK | Gtk
.AttachOptions
.FILL
, Gtk
.AttachOptions
.SHRINK
)
215 widget
, refresher
= self
.create_widget(vpath
)
216 table
.attach(widget
, 1, 2, row
, row
+ 1, Gtk
.AttachOptions
.EXPAND | Gtk
.AttachOptions
.FILL
, Gtk
.AttachOptions
.SHRINK
)
217 if values
is not None:
220 def update_sensitive(self
, widget
, values
):
221 sensitive
= (values
is not None) and (self
.get_with_default('setter', 0) is not None) and self
.has_attr(values
)
222 widget
.set_sensitive(sensitive
)
225 class SliderRow(TableRowWidget
):
226 def __init__(self
, label
, name
, minv
, maxv
, **kwargs
):
227 TableRowWidget
.__init
__(self
, label
, name
, **kwargs
)
230 def create_widget(self
, vpath
):
231 setter
= self
.get_with_default('setter', adjustment_changed_float
)
232 step
= self
.kwargs
['step'] if 'step' in self
.kwargs
else 1
233 adj
= Gtk
.Adjustment(self
.minv
, self
.minv
, self
.maxv
, step
, 6, 0)
234 slider
= standard_hslider(adj
)
235 if 'digits' in self
.kwargs
:
236 slider
.set_digits(self
.kwargs
['digits'])
237 if setter
is not None:
238 adj
.connect("value_changed", setter
, vpath
.plus(self
.name
))
240 slider
.set_sensitive(False)
241 def refresher(values
):
242 if self
.update_sensitive(slider
, values
):
243 adj
.set_value(self
.get_value(values
, vpath
))
244 return (slider
, refresher
)
246 class IntSliderRow(SliderRow
):
247 def __init__(self
, label
, name
, minv
, maxv
, **kwargs
):
248 SliderRow
.__init
__(self
, label
, name
, minv
, maxv
, setter
= adjustment_changed_int
, **kwargs
)
249 def create_widget(self
, vpath
):
250 (slider
, refresher
) = SliderRow
.create_widget(self
, vpath
)
251 slider
.connect('change-value', self
.on_change_value
)
253 return slider
, refresher
254 def on_change_value(self
, range, scroll
, value
):
255 range.set_value(int(value
))
259 class MappedSliderRow(TableRowWidget
):
260 def __init__(self
, label
, name
, mapper
, **kwargs
):
261 TableRowWidget
.__init
__(self
, label
, name
, **kwargs
)
263 def create_widget(self
, vpath
):
264 setter
= self
.get_with_default('setter', adjustment_changed_float_mapped
)
265 adj
= Gtk
.Adjustment(0, 0, 100, 1, 6, 0)
266 slider
= standard_mapped_hslider(adj
, self
.mapper
)
267 if setter
is not None:
268 adj
.connect("value_changed", setter
, vpath
.plus(self
.name
), self
.mapper
)
270 slider
.set_sensitive(False)
271 def refresher(values
):
272 if self
.update_sensitive(slider
, values
):
273 adj
.set_value(self
.mapper
.unmap(self
.get_value(values
, vpath
)))
274 return (slider
, refresher
)
276 class CheckBoxRow(TableRowWidget
):
277 def create_widget(self
, vpath
):
278 widget
= Gtk
.CheckButton(self
.label
)
279 widget
.connect("clicked", checkbox_changed_bool
, vpath
.plus(self
.name
))
280 def refresher(values
):
281 if self
.update_sensitive(widget
, values
):
282 widget
.set_active(self
.get_value(values
, vpath
) > 0)
283 return (widget
, refresher
)
285 #################################################################################################################################
287 class SelectObjectDialog(Gtk
.Dialog
):
288 def __init__(self
, parent
):
289 Gtk
.Dialog
.__init
__(self
, self
.title
, parent
, Gtk
.DialogFlags
.MODAL
,
290 (Gtk
.STOCK_CANCEL
, Gtk
.ResponseType
.CANCEL
, Gtk
.STOCK_OK
, Gtk
.ResponseType
.OK
))
291 self
.set_default_response(Gtk
.ResponseType
.OK
)
292 model
= Gtk
.ListStore(GObject
.TYPE_STRING
, GObject
.TYPE_STRING
, GObject
.TYPE_STRING
, GObject
.TYPE_STRING
)
294 self
.update_model(model
)
296 scroll
= Gtk
.ScrolledWindow()
297 scenes
= Gtk
.TreeView(model
)
298 scenes
.insert_column_with_attributes(0, "Name", Gtk
.CellRendererText(), text
=0)
299 scenes
.insert_column_with_attributes(1, "Title", Gtk
.CellRendererText(), text
=3)
300 scenes
.insert_column_with_attributes(2, "Type", Gtk
.CellRendererText(), text
=1)
301 scenes
.get_column(0).set_property('min_width', 150)
302 scenes
.get_column(1).set_property('min_width', 300)
303 scenes
.get_column(2).set_property('min_width', 150)
305 self
.vbox
.pack_start(scroll
, False, False, 0)
307 scroll
.set_size_request(640, 500)
310 self
.scenes
.connect('cursor-changed', lambda w
: self
.update_default_button())
311 self
.scenes
.connect('row-activated', lambda w
, path
, column
: self
.response(Gtk
.ResponseType
.OK
))
312 self
.scenes
.set_cursor((0,), scenes
.get_column(0))
313 self
.scenes
.grab_focus()
314 self
.update_default_button()
316 def get_selected_object(self
):
317 return self
.scenes
.get_model()[self
.scenes
.get_cursor()[0].get_indices()[0]]
318 def update_default_button(self
):
319 self
.set_response_sensitive(Gtk
.ResponseType
.OK
, self
.scenes
.get_cursor()[1] is not None)
321 #################################################################################################################################
323 class SaveConfigObjectDialog(Gtk
.Dialog
):
324 def __init__(self
, parent
, title
):
325 Gtk
.Dialog
.__init
__(self
, title
, parent
, Gtk
.DialogFlags
.MODAL
,
326 (Gtk
.STOCK_CANCEL
, Gtk
.ResponseType
.CANCEL
, Gtk
.STOCK_OK
, Gtk
.ResponseType
.OK
))
327 self
.set_default_response(Gtk
.ResponseType
.OK
)
330 l
.set_text_with_mnemonic("_Name")
333 e
.set_activates_default(True)
334 e
.connect('changed', self
.on_entry_changed
)
336 row
.pack_start(l
, False, False, 5)
337 row
.pack_start(e
, True, True, 5)
339 self
.vbox
.pack_start(row
, True, True, 0)
341 self
.on_entry_changed(e
)
343 return self
.entry
.get_text()
344 def on_entry_changed(self
, w
):
345 self
.set_response_sensitive(Gtk
.ResponseType
.OK
, w
.get_text() != '')