""" File: JetCtrls.py Contents and purpose: Auditions a jet file to simulate interactive music functions Copyright (c) 2008 Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ import wx import sys from wx.lib.mixins.listctrl import CheckListCtrlMixin, ListCtrlAutoWidthMixin, ColumnSorterMixin from JetUtils import * from JetDefs import * class JetSpin(wx.SpinCtrl): """ Spin control """ def __init__(self, parent, id=-1,value=wx.EmptyString,pos=wx.DefaultPosition,size=wx.DefaultSize,style=wx.SP_ARROW_KEYS,min=0,max=100,initial=0): wx.SpinCtrl.__init__(self, parent, id=id,value=value,pos=(pos[0]-MacOffset(),pos[1]),size=size,style=style,min=min,max=max,initial=initial) def SetValue(self, val): try: if type(val).__name__=='str': wx.SpinCtrl.SetValue(self, int(val)) else: wx.SpinCtrl.SetValue(self, val) except: wx.SpinCtrl.SetValue(self, 0) class JetSpinOneBased(JetSpin): """ Spin control that's one based """ def __init__(self, parent, id=-1,value=wx.EmptyString,pos=wx.DefaultPosition,size=wx.DefaultSize,style=wx.SP_ARROW_KEYS,min=0,max=100,initial=0): wx.SpinCtrl.__init__(self, parent, id=id,value=value,pos=(pos[0]-MacOffset(),pos[1]),size=size,style=style,min=min,max=max,initial=initial) def SetValue(self, val): try: if type(val).__name__=='str': wx.SpinCtrl.SetValue(self, int(val) + 1) else: wx.SpinCtrl.SetValue(self, val + 1) except: wx.SpinCtrl.SetValue(self, 1) def GetValue(self): val = wx.SpinCtrl.GetValue(self) val = val - 1 return val class JetCheckBox(wx.CheckBox): """ Checkbox control """ def __init__(self, parent, id=-1,label=wx.EmptyString,pos=wx.DefaultPosition,size=wx.DefaultSize): wx.CheckBox.__init__(self, parent, id=id, label=label, pos=pos, size=size) def SetValue(self, val): try: if type(val).__name__=='str': if val == 'True': val = True else: val = False wx.CheckBox.SetValue(self, val) else: wx.CheckBox.SetValue(self, val) except: wx.CheckBox.SetValue(self, False) class JetRadioButton(wx.RadioButton): """ Radio button control """ def __init__(self, parent, id=-1,label=wx.EmptyString,pos=wx.DefaultPosition,size=wx.DefaultSize): wx.RadioButton.__init__(self, parent, id=id, label=label, pos=pos, size=size) def SetValue(self, val): try: if type(val).__name__=='str': if val == 'True': val = True else: val = False wx.RadioButton.SetValue(self, val) else: wx.RadioButton.SetValue(self, val) except: wx.RadioButton.SetValue(self, False) class JetListCtrl(wx.ListCtrl, ListCtrlAutoWidthMixin, ColumnSorterMixin): """ List control """ def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize): wx.ListCtrl.__init__(self, parent, id, pos=pos, size=size, style=wx.LC_REPORT | wx.SUNKEN_BORDER) ListCtrlAutoWidthMixin.__init__(self) self.iCol = 0 self.iWidth = 0 self.OnSortOrderChangedAlert = None self.iInitialized = False def AddCol(self, title, width): self.InsertColumn(self.iCol, title) if width > 0: self.SetColumnWidth(self.iCol, width) else: width = self.GetColumnWidth(self.iCol) self.iCol += 1 self.iWidth = self.iWidth + width self.SetSize((self.iWidth + 10, -1)) def AddRows(self, values): for value in values: iCol = 0 for row in value: if iCol == 0: index = self.InsertStringItem(sys.maxint, row) else: self.SetStringItem(index, iCol, row) iCol = iCol + 1 # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py def GetListCtrl(self): return self def InitSorting(self, cols): if not self.iInitialized: ColumnSorterMixin.__init__(self, cols) self.iInitialized = True def OnSortOrderChanged(self): if self.OnSortOrderChangedAlert is not None: self.OnSortOrderChangedAlert() def __OnColClick(self, evt): oldCol = self._col self._col = col = evt.GetColumn() self._colSortFlag[col] = int(not self._colSortFlag[col]) self.OnSortOrderChanged() class JetCheckListCtrl(wx.ListCtrl, CheckListCtrlMixin, ListCtrlAutoWidthMixin, ColumnSorterMixin): """ List control with checkboxes on each line """ def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.LC_REPORT | wx.SUNKEN_BORDER): wx.ListCtrl.__init__(self, parent, id, pos=pos, size=size, style=style) CheckListCtrlMixin.__init__(self) ListCtrlAutoWidthMixin.__init__(self) self.iCol = 0 self.iWidth = 0 self.OnSortOrderChangedAlert = None self.iInitialized = False def AddCol(self, title, width): self.InsertColumn(self.iCol, title) if width > 0: self.SetColumnWidth(self.iCol, width) else: width = self.GetColumnWidth(self.iCol) self.iCol += 1 self.iWidth = self.iWidth + width self.SetSize((self.iWidth + 10, -1)) def OnCheckItem(self, index, flag): if hasattr(self, 'BindCheckBoxFct'): self.BindCheckBoxFct(index, flag) def BindCheckBox(self, fct): self.BindCheckBoxFct = fct def AddRows(self, values): for value in values: iCol = 0 for row in value: if iCol == 0: index = self.InsertStringItem(sys.maxint, row) else: self.SetStringItem(index, iCol, row) iCol = iCol + 1 # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py def GetListCtrl(self): return self def InitSorting(self, cols): if not self.iInitialized: ColumnSorterMixin.__init__(self, cols) self.iInitialized = True def OnSortOrderChanged(self): if self.OnSortOrderChangedAlert is not None: self.OnSortOrderChangedAlert() def __OnColClick(self, evt): oldCol = self._col self._col = col = evt.GetColumn() self._colSortFlag[col] = int(not self._colSortFlag[col]) self.OnSortOrderChanged() class JetTrackCtrl(JetCheckListCtrl): """ List control specifically designed to show tracks in midi file """ def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.LC_REPORT | wx.SUNKEN_BORDER): wx.ListCtrl.__init__(self, parent, id, pos=pos, size=size, style=style) CheckListCtrlMixin.__init__(self) ListCtrlAutoWidthMixin.__init__(self) self.iCol = 0 self.iWidth = 0 self.muteFlags = 0 def SetValue(self, muteFlags): self.muteFlags = muteFlags def GetValue(self): return self.muteFlags def CheckTracks(self, muteFlags): num = self.GetItemCount() for iRow in range(num): track_num = self.GetTrackNumber(iRow) self.CheckItem(iRow, GetMute(track_num, muteFlags)) def AddTrackRow(self, track, loadEmpty=False): if loadEmpty or not track.empty: index = self.InsertStringItem(sys.maxint, str(track.track)) self.SetStringItem(index, 1, str(track.channel)) self.SetStringItem(index, 2, str(track.name)) def GetTrackNumber(self, index): return getColumnValue(self, index, 0) class JetFileCombo(): """ Combo box with file open button """ def __init__(self, parent, pos=(0,0), size=(200,-1), title='Open File', spec='*.*', id=-1): self.spec = spec self.title = title self.EventFire = False BUTWIDTH = 20 BORDER = 5 w = size[0] - (BUTWIDTH + BORDER) col = pos[0] + w + BORDER self.cmb = wx.ComboBox(parent, id, "", pos=(pos[0]-MacOffset(),pos[1]), size=(w, -1), style=wx.CB_DROPDOWN) self.btn = wx.Button(parent, -1, "...", pos=(col, pos[1]+MacOffset()), size=(BUTWIDTH,self.cmb.GetSize()[1])) self.btn.Bind(wx.EVT_BUTTON, self.OnBrowse, self.btn) def OnBrowse(self, event): os = __import__('os') defDir = IniGetValue(JetDefs.JETCREATOR_INI, JetDefs.INI_DEFAULTDIRS, self.spec, 'str', str(os.getcwd())) if OsWindows(): defDir = defDir.replace('/','\\') else: defDir = defDir.replace('\\', '/') dlg = wx.FileDialog(None, self.title, defDir, '', self.spec, wx.FD_OPEN) ret = dlg.ShowModal() if ret == wx.ID_OK: IniSetValue(JetDefs.JETCREATOR_INI, JetDefs.INI_DEFAULTDIRS, self.spec, str(FileJustPath(dlg.GetPath()))) val = dlg.GetPath() self.Append(val) self.cmb.SetValue(val) if self.EventFire: SendEvent(self.cmb, wx.EVT_COMBOBOX.evtType[0]) dlg.Destroy() def SetEventFire(self, fire): self.EventFire = fire def GetValue(self): return StrNoneChk(self.cmb.GetValue()) def SetValue(self, val): try: self.cmb.SetValue(val) except: pass def Append(self, val): try: self.cmb.Append(val) except: pass def SetFocus(self): self.cmb.SetFocus() def SetListValues(self, list): self.cmb.AppendItems(list) def Enable(self, enable): self.cmb.Enable(enable) self.btn.Enable(enable) def SetHelpText(self, Lbl): self.cmb.SetHelpText(Lbl) self.btn.SetHelpText(Lbl) class JetFileText(): """ Capture a filename with a button to browse for a file """ def __init__(self, parent, pos=(0,0), size=(200,-1), title='Open File', spec='*.*', id=-1): self.spec = spec self.title = title BUTWIDTH = 20 BORDER = 5 w = size[0] - (BUTWIDTH + BORDER) col = pos[0] + w + BORDER self.txt = wx.TextCtrl(parent, id, "", pos=(pos[0]-MacOffset(),pos[1]), size=(w, -1)) self.btn = wx.Button(parent, -1, "...", pos=(col, pos[1]), size=(BUTWIDTH,self.txt.GetSize()[1])) self.btn.Bind(wx.EVT_BUTTON, self.OnBrowse, self.btn) def OnBrowse(self, event): os = __import__('os') defDir = IniGetValue(JetDefs.JETCREATOR_INI, JetDefs.INI_DEFAULTDIRS, self.spec, 'str', str(os.getcwd())) if OsWindows(): defDir = defDir.replace('/','\\') else: defDir = defDir.replace('\\', '/') dlg = wx.FileDialog(None, self.title, defDir, '', self.spec, wx.FD_OPEN) ret = dlg.ShowModal() if ret == wx.ID_OK: IniSetValue(JetDefs.JETCREATOR_INI, JetDefs.INI_DEFAULTDIRS, self.spec, str(FileJustPath(dlg.GetPath()))) val = dlg.GetPath() self.txt.SetValue(val) dlg.Destroy() def GetValue(self): return StrNoneChk(self.txt.GetValue()) def SetValue(self, val): try: self.txt.SetValue(val) except: pass def Append(self, val): try: self.txt.Append(val) except: pass def SetFocus(self): self.txt.SetFocus() def Enable(self, enable): self.txt.Enable(enable) self.btn.Enable(enable) def SetHelpText(self, Lbl): self.txt.SetHelpText(Lbl) self.btn.SetHelpText(Lbl) def YesNo(title, question, default): """ Simple Yes/No question box """ dlg = wx.MessageDialog(None, question, title, wx.YES_NO | wx.ICON_QUESTION) if dlg.ShowModal() == wx.ID_YES: result = True else: result = False dlg.Destroy() return result def YesNoCancel(title, question, default): """ Simple Yes/No question box """ dlg = wx.MessageDialog(None, question, title, wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION) result = dlg.ShowModal() dlg.Destroy() return result def ErrorMsg(title, message): """ Dipslay an error message """ dlg = wx.MessageDialog(None, message, title, wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() def InfoMsg(title, message): """ Displays an informational message """ dlg = wx.MessageDialog(None, message, title, wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() class TimeCtrl(wx.Frame): """ Combination of controls to capture measure, beat, tick times """ def __init__(self, parent, pos=(0,0), minimums=(1,1,0), maximums=(999,4,480), value=JetDefs.MBT_DEFAULT, ctlName=''): wx.Frame.__init__(self, parent, -1) self.ChangeCallbackFct = None self.ctlName = ctlName self.mx = maximums self.mn = minimums self.maxTicks = 0 self.iCtrl = 0 p1 = pos[0] top = pos[1] + MacOffset() w1 = 30 self.time = (wx.TextCtrl(parent, -1, str(value[0]), pos=(p1, top), size=(w1, -1), style=wx.TE_NOHIDESEL), wx.TextCtrl(parent, -1, str(value[1]), pos=(p1 + (w1 + 3), top), size=(w1, -1), style=wx.TE_NOHIDESEL), wx.TextCtrl(parent, -1, str(value[2]), pos=(p1 + (w1 + 3) *2, top), size=(w1, -1), style=wx.TE_NOHIDESEL), ) h = self.time[2].GetSize().height w = self.time[2].GetSize().width + self.time[2].GetPosition().x + 8 self.spin = wx.SpinButton(parent, -1, (w, top), (h*2/3, h), wx.SP_VERTICAL) self.spin.SetValue(1) self.spin.SetRange(-999,999) self.spin.Bind(wx.EVT_SPIN_UP, self.OnSpinUp, self.spin) self.spin.Bind(wx.EVT_SPIN_DOWN, self.OnSpinDown, self.spin) self.time[0].Bind(wx.EVT_SET_FOCUS, self.OnFocusMeasure, self.time[0] ) self.time[1].Bind(wx.EVT_SET_FOCUS, self.OnFocusBeat, self.time[1] ) self.time[2].Bind(wx.EVT_SET_FOCUS, self.OnFocusTick, self.time[2] ) self.time[0].Bind(wx.EVT_KILL_FOCUS, self.OnChangeVal, self.time[0] ) self.time[1].Bind(wx.EVT_KILL_FOCUS, self.OnChangeVal, self.time[1] ) self.time[2].Bind(wx.EVT_KILL_FOCUS, self.OnChangeVal, self.time[2] ) self.SetValue(value) def UnBindKillFocus(self): self.time[0].Unbind(wx.EVT_KILL_FOCUS, self.time[0]) self.time[1].Unbind(wx.EVT_KILL_FOCUS, self.time[1]) self.time[2].Unbind(wx.EVT_KILL_FOCUS, self.time[2]) def SetChangeCallbackFct(self, ChangeCallbackFct): self.ChangeCallbackFct = ChangeCallbackFct def OnChangeVal(self, event=None): if not OsWindows(): self.time[self.iCtrl].SetSelection(-1,-1) if int(self.time[self.iCtrl].GetValue()) > self.mx[self.iCtrl]: self.time[self.iCtrl].SetValue(str(self.mx[self.iCtrl])) if int(self.time[self.iCtrl].GetValue()) < self.mn[self.iCtrl]: self.time[self.iCtrl].SetValue(str(self.mn[self.iCtrl])) if self.ChangeCallbackFct is not None: self.ChangeCallbackFct() if event is not None: event.Skip() def OnSpinUp(self, event): if int(self.time[self.iCtrl].GetValue()) < self.mx[self.iCtrl]: self.time[self.iCtrl].SetValue(str(int(self.time[self.iCtrl].GetValue()) + 1)) self.OnChangeVal() def OnSpinDown(self, event): if int(self.time[self.iCtrl].GetValue()) > self.mn[self.iCtrl]: self.time[self.iCtrl].SetValue(str(int(self.time[self.iCtrl].GetValue()) - 1)) self.OnChangeVal() def OnFocusMeasure(self, event): self.iCtrl = 0 def OnFocusBeat(self, event): self.iCtrl = 1 def OnFocusTick(self, event): self.iCtrl = 2 def SetValue(self, mbt): try: if type(mbt).__name__=='str' or type(mbt).__name__=='unicode': mbt = ConvertStrTimeToTuple(mbt) mbt = mbtFct(mbt, 1) self.time[0].SetValue(str(mbt[0])) self.time[1].SetValue(str(mbt[1])) self.time[2].SetValue(str(mbt[2])) except: self.time[0].SetValue(str(self.mn[0])) self.time[1].SetValue(str(self.mn[1])) self.time[2].SetValue(str(self.mn[2])) if not OsWindows(): self.time[0].SetSelection(-1,-1) self.time[1].SetSelection(-1,-1) self.time[2].SetSelection(-1,-1) def GetValue(self, typ='str'): try: if typ == 'str': ret = "%d:%d:%d" % (int(self.time[0].GetValue()), int(self.time[1].GetValue()), int(self.time[2].GetValue())) else: ret = (int(self.time[0].GetValue()), int(self.time[1].GetValue()), int(self.time[2].GetValue())) except: ret = self.minimums return mbtFct(ret, -1) def Enable(self, enable): self.time[0].Enable(enable) self.time[1].Enable(enable) self.time[2].Enable(enable) self.spin.Enable(enable) def SetFocus(self): self.time[0].SetFocus() def SetMaxMbt(self, m, b, t): self.mx = (m,b,t) def GetMaxMbt(self): return "%d:%d:%d" % self.mx def SetMinMbt(self, m, b, t): self.mn = (m,b,t) def SetMaxTicks(self, maxTicks): self.maxTicks = maxTicks def GetMaxTicks(self): return self.maxTicks def SetHelpText(self, Lbl): self.spin.SetHelpText(Lbl) self.time[0].SetHelpText(Lbl) self.time[1].SetHelpText(Lbl) self.time[2].SetHelpText(Lbl) def GetMeasure(self): return int(self.time[0].GetValue()) def GetBeat(self): return int(self.time[1].GetValue()) def GetTick(self): return int(self.time[2].GetValue()) if __name__ == '__main__': """ Test code for controls """ class TestFrame(wx.Frame): def __init__(self, parent, id, title): wx.Frame.__init__(self, parent, id, title, size=(350, 220)) panel = wx.Panel(self, -1) self.tc = TimeCtrl(panel, pos=(30, 20), maximums=(25, 4, 120), value=(2, 3, 4)) #tc.Enable(True) #tc.SetValue((2,3,4)) #tc.SetValue("1:2:3") #print(tc.GetValue()) js = JetSpin(panel, -1, pos=(30, 100)) js.SetValue("1") #js.SetValue(1) #fl = JetFileCombo(panel) wx.EVT_CLOSE(self, self.OnClose) self.Centre() self.Show(True) def OnClose(self, event): self.tc.UnBindKillFocus() self.Destroy() app = wx.App(None) TestFrame(None, -1, 'TestFrame') app.MainLoop()