You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

568 lines
20 KiB

"""
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()