from GtkSelectionList import GtkSelectionList from GtkButtonGrid import GtkButtonGrid from gi.repository import Gdk from gi.repository import Gtk from pad import * import os import simplemidi import sys gtk=Gtk from MidiConst import * def when_button_is_clicked(label): ''' Quand le bouton est cliqué ''' label.set_text('Hello world!') def ok(btn): print("OK clicked") _GAMME = { "Personalisée": "", "Majeur" : GAMME_MAJEUR, "Mineur naturelle" : GAMME_MINEUR_NATURELLE, "Mineur harmonique" : GAMME_MINEUR_HARMONIQUE, "Mineur mélodique" : GAMME_MINEUR_MELODIQUE } class Pane: def __init__(self, app): self.app = app self.pad=app.pad self.builder = app.builder def connect(self, name, signal, fct): self.builder.get_object(name).connect(signal, fct) def widget(self, name): return self.builder.get_object(name) class _Dialog: def __init__(self, parent, name): self.builder=parent.builder self.parent=parent self.dialog=self.widget(name) self.dialog.connect("delete-event", self.drop) self.modify=False self.isInit=False def on_ok(self, btn): self.dialog.hide() self.dialog.hide() if self.modify: self.parent.on_modify_return(self.get_data()) else: self.parent.on_add_return(self.get_data()) def on_cancel(self, x=None): self.dialog.hide() self.dialog.hide() def run(self): if not self.isInit: self.dialog.show() self.isInit=True self.dialog.hide() self.update(None) self.dialog.show() def get_data(self): raise NotImplementedError def _init(self, data, ): raise NotImplementedError def drop(self,a,b): self.dialog.hide() return True def connect(self, name, signal, fct): self.builder.get_object(name).connect(signal, fct) def widget(self, name): return self.builder.get_object(name) def init(self, data): self.modify=data!=None self._init(data) self.update(None) class NewDialog(_Dialog): def __init__(self, pane): super().__init__(pane, "new_pad_conf_dialog") self.cb=self.widget("cb_new_pad") l=PadManager.pad_list() for k in l: self.cb.append(k,k) if len(l): self.cb.set_active(0) self.widget("new_pad").connect("clicked", self.on_valid) self.app=pane def on_valid(self, x): self.app.on_new(self.cb.get_active_id()) self.drop(None,None) def update(self, x): pass class InitDialog(_Dialog): def __init__(self, pane): super().__init__(pane, "init_dialog") self.wchannel=[self.widget("init_enable_channel"),self.widget("init_channel_value"),self.widget("init_channel_absolute")] self.wkey=[self.widget("init_enable_key"),self.widget("init_key_value"),self.widget("init_key_absolute")] self.wvelocity=[self.widget("init_enable_velocity"),self.widget("init_velocity_value"),self.widget("init_velocity_absolute")] self.widget("init_ok").connect("clicked", self.on_ok) self.widget("init_cancel").connect("clicked", self.on_cancel) self.wchannel[0].connect("toggled", self.update) self.wkey[0].connect("toggled", self.update) self.wvelocity[0].connect("toggled", self.update) self.message=self.widget("init_message") def get_data(self): return [ self.message.get_active_id(), int(self.wchannel[1].get_value()) if self.wchannel[0].get_active() else -1, int(self.wkey[1].get_value()) if self.wkey[0].get_active() else -1, int(self.wvelocity[1].get_value()) if self.wvelocity[0].get_active() else -1 ] def _init(self, data): self.message.set_active(0) self.wchannel[0].set_active(False) self.wkey[0].set_active(False) self.wvelocity[0].set_active(False) self.wchannel[1].set_sensitive(False) self.wkey[1].set_sensitive(False) self.wvelocity[1].set_sensitive(False) self.wchannel[1].set_value(0) self.wkey[1].set_value(0) self.wvelocity[1].set_value(0) if data: self.message.set_active_id(data[0]) self.wchannel[0].set_active(data[1]>=0) self.wkey[0].set_active(data[2]>=0) self.wvelocity[0].set_active(data[3]>=0) self.wchannel[1].set_sensitive(data[1]>=0) self.wkey[1].set_sensitive(data[2]>=0) self.wvelocity[1].set_sensitive(data[3]>=0) self.wchannel[1].set_value(data[1]) self.wkey[1].set_value(data[2]) self.wvelocity[1].set_value(data[3]) def update(self, x): self.wchannel[1].set_sensitive(self.wchannel[0].get_active()) self.wkey[1].set_sensitive(self.wkey[0].get_active()) self.wvelocity[1].set_sensitive(self.wvelocity[0].get_active()) class OperationDialog(_Dialog): def __init__(self, pane): super().__init__(pane, "operation_dialog") self.cbtype=self.widget("operation_type") self.cbtype.connect("changed", self.update) self.current_type="TRANSLATE" self.widget("operation_ok").connect("clicked", self.on_ok) self.widget("operation_cancel").connect("clicked", self.on_cancel) self.frames={ "TRANSLATE" : self.widget("operation_translate"), "RANGE" : self.widget("operation_range"), "REORDER" : self.widget("operation_reorder"), "DROP" : self.widget("operation_drop") } self.reorder_offest=self.widget("operation_offset") self.gamme_note=self.widget("operation_gamme_note") self.gamme_gamme=self.widget("operation_gamme_gamme") self.gamme_custom=self.widget("operation_gamme_custom") self.gamme_octave=self.widget("operation_gamme_note_octave") self.trans_ch=[self.widget("operation_translate_channel"), self.widget("operation_translate_channel_absolute")] self.trans_key=[self.widget("operation_translate_key"), self.widget("operation_translate_key_absolute")] self.trans_vel=[self.widget("operation_translate_velocity"), self.widget("operation_translate_velocity_absolute")] for k in _GAMME: self.gamme_gamme.append(k, k) for k in ARR_NOTE: self.gamme_note.append(k, k) self.update() def update(self, x=None): self.current_type=self.cbtype.get_active_id() for k in self.frames: if k==self.current_type: self.frames[k].show() else: self.frames[k].hide() def get_data(self): if self.current_type=="TRANSLATE": values=[self.trans_ch[0].get_value(),self.trans_key[0].get_value(),self.trans_vel[0].get_value()] modes=[self.trans_ch[1].get_active(),self.trans_key[1].get_active(),self.trans_vel[1].get_active()] return TranslateOperation.new(values, modes) elif self.current_type=="DROP": return DropOperation.new() elif self.current_type=="RANGE": gamme=self.gamme_gamme.get_active_id() gamme=_GAMME[gamme] if gamme else json.loads("["+self.gamme_custom.get_text()+"]") note=Note.parse(self.gamme_note.get_active_id()+self.gamme_octave.get_active_id()) return RangeOperation.new(gamme, note) elif self.current_type=="REORDER": return ReorderOperation.new(int(self.reorder_offest.get_value())) def _init(self, data): self.gamme_gamme.set_active(0) self.gamme_note.set_active(0) self.gamme_octave.set_active(5) self.gamme_custom.set_text("") self.trans_ch[0].set_value(0) self.trans_key[0].set_value(0) self.trans_vel[0].set_value(0) self.trans_ch[1].set_active(False) self.trans_key[1].set_active(False) self.trans_vel[1].set_active(False) self.reorder_offest.set_value(0) if data: self.cbtype.set_active_id(data.type) if isinstance(data, RangeOperation): self.gamme_note.set_active(Note.get_note(data.key)) self.gamme_octave.set_active(Note.get_octave(data.key)) range_set=False for i in _GAMME: if _GAMME[i]!="" and _GAMME[i]==data.range: range_set=True self.gamme_gamme.set_active_id(i) if not range_set: self.gamme_custom.set_text(str(data.range)[1:-1]) if isinstance(data, ReorderOperation): self.reorder_offest.set_value(int(data.offset)) if isinstance(data, TranslateOperation): self.trans_ch[0].set_value(data.channel) self.trans_key[0].set_value(data.key) self.trans_vel[0].set_value(data.velocity) self.trans_ch[1].set_active(data.channelmode=="FIXED") self.trans_key[1].set_active(data.keymode=="FIXED") self.trans_vel[1].set_active(data.velocitymode=="FIXED") class CRUDPane(Pane): def __init__(self, app, prefix): super().__init__(app) #self.widget(prefix+"_down").connect("clicked", self.on_down) self.widget(prefix+"_up").connect("clicked", self._on_up) self.widget(prefix+"_remove").connect("clicked", self._on_remove) self.widget(prefix+"_add").connect("clicked", self._on_add) self.widget(prefix+"_edit").connect("clicked", self._on_edit) self.list=self.widget(prefix+"_listbox") self.dialog=None self.data=[] def print(self, tmp="After"): pass def get_index(self): return self.find_index(self.list.get_selected_row()) def find_index(self, widget): n=-1 if not widget: return -1 widget=widget.get_child() for i in range(len(self.data)): k=self.data[i] if k[1]==widget: return i return -1 def insert(self, i, data): self.data.append(None) for j in reversed(range(i,len(self.data)-1)): self.data[j+1]=self.data[j] lbl=Gtk.Label.new(str(data)) self.data[j] =(data, lbl) self.list.insert(lbl, i) self.list.show_all() def _on_up(self, btn): if not self.app.sel_pane.get_current_selection(): return n=self.get_index() if n>0: x=self.data[n] self.list.remove(x[1].get_parent()) self.insert(n-1, x[0]) self.data.remove(x) self.list.select_row(self.data[n-1][1].get_parent()) self.on_up(n) self.print("up") def _on_down(self, btn): if not self.app.sel_pane.get_current_selection(): return n=self.get_index() if n>=0 and n<=len(self.data)-1: x=self.data[n] self.list.remove(x[1].get_parent()) self.insert(n+1, x[0]) self.data.remove(x) self.list.select_row(self.data[n+1][1].get_parent()) self.on_down(n) self.print("down") def _on_remove(self, btn): if not self.app.sel_pane.get_current_selection(): return n=self.get_index() if n>=0: x=self.data[n] self.list.remove(x[1].get_parent()) self.data.remove(x) self.on_remove(n) self.print("remove") def _on_add(self, btn): if not self.app.sel_pane.get_current_selection(): return self.dialog.init(None) self.dialog.run() def _on_edit(self, btn): if not self.app.sel_pane.get_current_selection(): return n=self.get_index() if n>=0: self.dialog.init(self.data[n][0]) self.dialog.run() def init(self, data): self.data=[] ch = self.list.get_children() for i in ch: self.list.remove(i) for d in data: self.add_on_ui(d) def data_to_str(self, x): return str(x) def add_on_ui(self, data): lbl=Gtk.Label.new(self.data_to_str(data)) lbl.set_alignment(0,0) self.data.append((data, lbl)) self.list.add(lbl) self.list.show_all() def on_add_return(self, data): self.add_on_ui(data) self.on_add(data) self.print("add") def on_modify_return(self, data): n=self.find_index(self.list.get_selected_row()) lbl=self.data[n][1] lbl.set_label(self.data_to_str(data)) self.data[n]=(data, lbl) self.on_modify(n, data) self.print("modify") def on_add(self, x): raise NotImplementedError def on_modify(self, i, x): raise NotImplementedError def on_remove(self, i): raise NotImplementedError def on_up(self, i): raise NotImplementedError def on_down(self, i): raise NotImplementedError class InitPane(CRUDPane): def __init__(self, app): super().__init__(app, "init") self.dialog=InitDialog(self) def data_to_str(self, x): out="" if x[0]=="noteon": out="NoteOn(" if x[0]=="noteoff": out="NoteOff(" args=[] if x[1]>=0: args.append("channel %d"%x[1]) if x[2]>=0: args.append("key %d"%x[2]) if x[3]>=0: args.append("velocity %d"%x[3]) return out+",".join(args)+")" def on_add(self, x): sel = self.app.sel_pane.get_current_selection() sel.init.actions.append(InputAction(x)) def on_modify(self, i, x): sel = self.app.sel_pane.get_current_selection() sel.init.actions[i]=InputAction(x) def on_remove(self, i): sel = self.app.sel_pane.get_current_selection() sel.init.actions.remove(sel.init.actions[i]) def on_up(self, i): sel = self.app.sel_pane.get_current_selection() tmp=sel.init.actions[i] sel.init.actions[i]=sel.init.actions[i-1] sel.init.actions[i-1]=tmp def on_down(self, i): sel = self.app.sel_pane.get_current_selection() tmp=sel.init.actions[i] sel.init.actions[i]=sel.init.actions[i+1] sel.init.actions[i+1]=tmp class OperationPane(CRUDPane): def __init__(self, app): super().__init__(app, "operation") self.dialog=OperationDialog(self) def on_add(self, x): sel = self.app.sel_pane.get_current_selection() sel.operations.append(x) def on_modify(self, i, x): sel = self.app.sel_pane.get_current_selection() sel.operations[i]=x def on_remove(self, i): sel = self.app.sel_pane.get_current_selection() sel.operations.remove(sel.operations[i]) def on_up(self, i): sel = self.app.sel_pane.get_current_selection() tmp=sel.operations[i] sel.operations[i]=sel.operations[i-1] sel.operations[i-1]=tmp def on_down(self, i): sel = self.app.sel_pane.get_current_selection() tmp=sel.operations[i] sel.operations[i]=sel.operations[i+1] sel.operations[i+1]=tmp class SelectionPane(Pane): def __init__(self, app): super().__init__(app) self.input_new_pad=self.builder.get_object("input_new_pad") self.sel_list=GtkSelectionList() self.pad=app.pad self.builder.get_object("sel_pane_root").pack_start(self.sel_list, True, True, 0) self.builder.get_object("sel_pane_root").reorder_child(self.sel_list,1) self.sel_list.set_on_selected(self.on_selections_changed) self.connect("button_new_sel", "clicked", self.on_new_sel) self.grid=GtkButtonGrid() self.grid.set_on_select(self.on_button_selected) self.grid.set_on_unselect(self.on_button_unselected) self.widget("grid_root").pack_start(self.grid, True, True, 0) self.entry_name=self.widget("entry_sel_name") self.widget("rename_sel").connect("clicked", self.on_name_change) self.sel_edit_box=self.widget("sel_edit_box") self.modifying=False self.init_pane=InitPane(self.app) self.op_pane=OperationPane(self.app) def on_name_change(self, editable): old=self.sel_list.current_selection_name new=self.entry_name.get_text() self.pad.rename_selection(old, new) self.sel_list.rename(old, new) def on_new_sel(self, btn): name = self.input_new_pad.get_text() sel=self.pad.new_sel(name) self.sel_list.append(name, sel) self.input_new_pad.set_text("") def on_selections_changed(self, sel, selection): self.set_selection(sel, selection) self.entry_name.set_text(sel if sel else "") def set_selection(self, name, selection): self.modifying=True self.grid.unselect_all() if name: for i in selection.inputs: self.grid[i].select() self.sel_edit_box.set_visible(True) self.sel_edit_box.show() self.sel_edit_box.queue_draw() self.init_pane.init(selection.init.json()) self.op_pane.init(selection.operations) self.sel_edit_box.show() else: self.init_pane.init([]) self.op_pane.init([]) self.sel_edit_box.hide() self.grid.update() self.modifying=False def init(self, pad): self.modifying=True self.pad=pad self.sel_list.init() print(self.sel_list.get_children()) for k in self.pad.selections: self.sel_list.append(k, self.pad.selections[k]) self.grid.set_grid_size(self.pad.width, self.pad.height) for i in range(self.pad.width*self.pad.height): sel = self.pad.find_selection_of(i) if sel: sel=self.pad.selections[sel] self.grid[i]=(sel, self.pad.matrix[i], i) self.modifying=False def get_current_selection_name(self): return self.sel_list.current_selection_name def get_current_selection(self): n=self.sel_list.current_selection_name if n and n in self.pad.selections: return self.pad.selections[n] return None def on_button_selected(self, i, btn): if not self.modifying and self.get_current_selection_name(): self.pad.add_button_to(self.sel_list.current_selection_name, i) btn.select() def on_button_unselected(self, i, btn): if not self.modifying and self.get_current_selection_name(): self.pad.remove_button_selection(i) btn.unselect() class Application: def __init__(self): self.builder = Gtk.Builder() self.builder.add_from_file('ui.glade') self.window=self.builder.get_object('main_window') self.window.connect('delete-event', Gtk.main_quit) self.pad=None self.sel_pane=SelectionPane(self) self.window.show_all() self.widget("menu_open").connect("activate", self.open_dialog) self.widget("menu_save").connect("activate", self.on_save_as) self.widget("menu_save_as").connect("activate", self.save_dialog) self.widget("menu_new").connect("activate", self.new_dialog) self.widget("toolbox_start").connect("clicked", self.start_simple_midi) self.widget("toolbox_clear").connect("clicked", self.reset_simple_midi) self.file_open=None self.file_dir_open=None self.changed=False self.simplemidi= simplemidi.SimpleMidi() self.simplemidi.run() self.widget("notebook").hide() self.dialog_new=NewDialog(self) def widget(self, name): return self.builder.get_object(name) def connect(self, name, signal, fct): self.builder.get_object(name).connect(signal, fct) def set_pad_configuration(self, conf): self.pad=PadConfiguration.parse(conf) self.init() def set_new_pad(self, pad): self.pad=PadConfiguration.new(pad) self.init() def set_changed(self): self.cahnged=True self.window.set_title("*"+os.path.basename(self.file_open)) def init(self): self.sel_pane.init(self.pad) def open(self, file :str): self.set_pad_configuration(file) self.window.show_all() self.sel_pane.set_selection(None, None) self.file_open=file self.file_dir_open=os.path.dirname(file) self.widget("selection_root_pane").set_position(100) self.window.set_title(os.path.basename(self.file_open)) self.simplemidi.set_pad(self.pad.name) def save(self, file): with open(file, "w") as f: f.write(json.dumps(self.pad.json(), indent=4)) self.changed=False def test(self): with open("test", "w") as f: f.write(json.dumps(self.pad.json(), indent=4)) def open_dialog(self, x): dialog = Gtk.FileChooserDialog("Please choose a file", self.window, Gtk.FileChooserAction.OPEN, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) response = dialog.run() if response == Gtk.ResponseType.OK: file_path = dialog.get_filename() self.open(file_path) elif response == Gtk.ResponseType.CANCEL: pass dialog.destroy() def save_dialog(self, x): dialog = Gtk.FileChooserDialog("Please choose a file", self.window, Gtk.FileChooserAction.SAVE, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE_AS, Gtk.ResponseType.OK)) dialog.set_current_folder(self.file_dir_open if self.file_dir_open else ".") dialog.set_filename(os.path.basename(self.file_open)) response = dialog.run() if response == Gtk.ResponseType.OK: file_path = dialog.get_filename() self.save(file_path) elif response == Gtk.ResponseType.CANCEL: pass dialog.destroy() def on_save_as(self, x): if self.file_dir_open: self.save(self.file_open) else: self.save_dialog(None) def new_dialog(self, x): self.dialog_new.run() def reset_simple_midi(self, x): if self.pad: self.simplemidi.clear() def start_simple_midi(self, x): if self.pad: self.simplemidi.set_configuration_data(self.pad) def on_new(self, pad): self.set_new_pad(pad) self.file_open=pad+" configuration" self.file_dir_open=None self.set_changed() self.window.show_all() def main(self): self.window.show() Gtk.main() app = Application() app.open("conf3.conf") app.main()