1""" 2 File: 3 JetCtrls.py 4 5 Contents and purpose: 6 Auditions a jet file to simulate interactive music functions 7 8 Copyright (c) 2008 Android Open Source Project 9 10 Licensed under the Apache License, Version 2.0 (the "License"); 11 you may not use this file except in compliance with the License. 12 You may obtain a copy of the License at 13 14 http://www.apache.org/licenses/LICENSE-2.0 15 16 Unless required by applicable law or agreed to in writing, software 17 distributed under the License is distributed on an "AS IS" BASIS, 18 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 See the License for the specific language governing permissions and 20 limitations under the License. 21""" 22 23import wx 24import sys 25 26from wx.lib.mixins.listctrl import CheckListCtrlMixin, ListCtrlAutoWidthMixin, ColumnSorterMixin 27from JetUtils import * 28from JetDefs import * 29 30class JetSpin(wx.SpinCtrl): 31 """ Spin control """ 32 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): 33 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) 34 35 def SetValue(self, val): 36 try: 37 if type(val).__name__=='str': 38 wx.SpinCtrl.SetValue(self, int(val)) 39 else: 40 wx.SpinCtrl.SetValue(self, val) 41 except: 42 wx.SpinCtrl.SetValue(self, 0) 43 44class JetSpinOneBased(JetSpin): 45 """ Spin control that's one based """ 46 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): 47 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) 48 49 def SetValue(self, val): 50 try: 51 if type(val).__name__=='str': 52 wx.SpinCtrl.SetValue(self, int(val) + 1) 53 else: 54 wx.SpinCtrl.SetValue(self, val + 1) 55 except: 56 wx.SpinCtrl.SetValue(self, 1) 57 58 def GetValue(self): 59 val = wx.SpinCtrl.GetValue(self) 60 val = val - 1 61 return val 62 63class JetCheckBox(wx.CheckBox): 64 """ Checkbox control """ 65 def __init__(self, parent, id=-1,label=wx.EmptyString,pos=wx.DefaultPosition,size=wx.DefaultSize): 66 wx.CheckBox.__init__(self, parent, id=id, label=label, pos=pos, size=size) 67 68 def SetValue(self, val): 69 try: 70 if type(val).__name__=='str': 71 if val == 'True': 72 val = True 73 else: 74 val = False 75 wx.CheckBox.SetValue(self, val) 76 else: 77 wx.CheckBox.SetValue(self, val) 78 except: 79 wx.CheckBox.SetValue(self, False) 80 81class JetRadioButton(wx.RadioButton): 82 """ Radio button control """ 83 def __init__(self, parent, id=-1,label=wx.EmptyString,pos=wx.DefaultPosition,size=wx.DefaultSize): 84 wx.RadioButton.__init__(self, parent, id=id, label=label, pos=pos, size=size) 85 86 def SetValue(self, val): 87 try: 88 if type(val).__name__=='str': 89 if val == 'True': 90 val = True 91 else: 92 val = False 93 wx.RadioButton.SetValue(self, val) 94 else: 95 wx.RadioButton.SetValue(self, val) 96 except: 97 wx.RadioButton.SetValue(self, False) 98 99class JetListCtrl(wx.ListCtrl, ListCtrlAutoWidthMixin, ColumnSorterMixin): 100 """ List control """ 101 def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize): 102 wx.ListCtrl.__init__(self, parent, id, pos=pos, size=size, style=wx.LC_REPORT | wx.SUNKEN_BORDER) 103 ListCtrlAutoWidthMixin.__init__(self) 104 self.iCol = 0 105 self.iWidth = 0 106 self.OnSortOrderChangedAlert = None 107 self.iInitialized = False 108 109 def AddCol(self, title, width): 110 self.InsertColumn(self.iCol, title) 111 if width > 0: 112 self.SetColumnWidth(self.iCol, width) 113 else: 114 width = self.GetColumnWidth(self.iCol) 115 self.iCol += 1 116 self.iWidth = self.iWidth + width 117 self.SetSize((self.iWidth + 10, -1)) 118 119 def AddRows(self, values): 120 for value in values: 121 iCol = 0 122 for row in value: 123 if iCol == 0: 124 index = self.InsertStringItem(sys.maxint, row) 125 else: 126 self.SetStringItem(index, iCol, row) 127 iCol = iCol + 1 128 129 # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py 130 def GetListCtrl(self): 131 return self 132 133 def InitSorting(self, cols): 134 if not self.iInitialized: 135 ColumnSorterMixin.__init__(self, cols) 136 self.iInitialized = True 137 138 def OnSortOrderChanged(self): 139 if self.OnSortOrderChangedAlert is not None: 140 self.OnSortOrderChangedAlert() 141 142 def __OnColClick(self, evt): 143 oldCol = self._col 144 self._col = col = evt.GetColumn() 145 self._colSortFlag[col] = int(not self._colSortFlag[col]) 146 self.OnSortOrderChanged() 147 148class JetCheckListCtrl(wx.ListCtrl, CheckListCtrlMixin, ListCtrlAutoWidthMixin, ColumnSorterMixin): 149 """ List control with checkboxes on each line """ 150 def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.LC_REPORT | wx.SUNKEN_BORDER): 151 wx.ListCtrl.__init__(self, parent, id, pos=pos, size=size, style=style) 152 CheckListCtrlMixin.__init__(self) 153 ListCtrlAutoWidthMixin.__init__(self) 154 155 self.iCol = 0 156 self.iWidth = 0 157 self.OnSortOrderChangedAlert = None 158 self.iInitialized = False 159 160 def AddCol(self, title, width): 161 self.InsertColumn(self.iCol, title) 162 if width > 0: 163 self.SetColumnWidth(self.iCol, width) 164 else: 165 width = self.GetColumnWidth(self.iCol) 166 self.iCol += 1 167 self.iWidth = self.iWidth + width 168 self.SetSize((self.iWidth + 10, -1)) 169 170 def OnCheckItem(self, index, flag): 171 if hasattr(self, 'BindCheckBoxFct'): 172 self.BindCheckBoxFct(index, flag) 173 174 def BindCheckBox(self, fct): 175 self.BindCheckBoxFct = fct 176 177 def AddRows(self, values): 178 for value in values: 179 iCol = 0 180 for row in value: 181 if iCol == 0: 182 index = self.InsertStringItem(sys.maxint, row) 183 else: 184 self.SetStringItem(index, iCol, row) 185 iCol = iCol + 1 186 187 # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py 188 def GetListCtrl(self): 189 return self 190 191 def InitSorting(self, cols): 192 if not self.iInitialized: 193 ColumnSorterMixin.__init__(self, cols) 194 self.iInitialized = True 195 196 def OnSortOrderChanged(self): 197 if self.OnSortOrderChangedAlert is not None: 198 self.OnSortOrderChangedAlert() 199 200 def __OnColClick(self, evt): 201 oldCol = self._col 202 self._col = col = evt.GetColumn() 203 self._colSortFlag[col] = int(not self._colSortFlag[col]) 204 self.OnSortOrderChanged() 205 206class JetTrackCtrl(JetCheckListCtrl): 207 """ List control specifically designed to show tracks in midi file """ 208 def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.LC_REPORT | wx.SUNKEN_BORDER): 209 wx.ListCtrl.__init__(self, parent, id, pos=pos, size=size, style=style) 210 CheckListCtrlMixin.__init__(self) 211 ListCtrlAutoWidthMixin.__init__(self) 212 213 self.iCol = 0 214 self.iWidth = 0 215 self.muteFlags = 0 216 217 def SetValue(self, muteFlags): 218 self.muteFlags = muteFlags 219 220 def GetValue(self): 221 return self.muteFlags 222 223 def CheckTracks(self, muteFlags): 224 num = self.GetItemCount() 225 for iRow in range(num): 226 track_num = self.GetTrackNumber(iRow) 227 self.CheckItem(iRow, GetMute(track_num, muteFlags)) 228 229 def AddTrackRow(self, track, loadEmpty=False): 230 if loadEmpty or not track.empty: 231 index = self.InsertStringItem(sys.maxint, str(track.track)) 232 self.SetStringItem(index, 1, str(track.channel)) 233 self.SetStringItem(index, 2, str(track.name)) 234 235 def GetTrackNumber(self, index): 236 return getColumnValue(self, index, 0) 237 238class JetFileCombo(): 239 """ Combo box with file open button """ 240 def __init__(self, parent, pos=(0,0), size=(200,-1), title='Open File', spec='*.*', id=-1): 241 self.spec = spec 242 self.title = title 243 self.EventFire = False 244 BUTWIDTH = 20 245 BORDER = 5 246 w = size[0] - (BUTWIDTH + BORDER) 247 col = pos[0] + w + BORDER 248 249 self.cmb = wx.ComboBox(parent, id, "", pos=(pos[0]-MacOffset(),pos[1]), size=(w, -1), style=wx.CB_DROPDOWN) 250 self.btn = wx.Button(parent, -1, "...", pos=(col, pos[1]+MacOffset()), size=(BUTWIDTH,self.cmb.GetSize()[1])) 251 self.btn.Bind(wx.EVT_BUTTON, self.OnBrowse, self.btn) 252 253 def OnBrowse(self, event): 254 os = __import__('os') 255 defDir = IniGetValue(JetDefs.JETCREATOR_INI, JetDefs.INI_DEFAULTDIRS, self.spec, 'str', str(os.getcwd())) 256 if OsWindows(): 257 defDir = defDir.replace('/','\\') 258 else: 259 defDir = defDir.replace('\\', '/') 260 261 dlg = wx.FileDialog(None, self.title, defDir, '', self.spec, wx.FD_OPEN) 262 ret = dlg.ShowModal() 263 if ret == wx.ID_OK: 264 IniSetValue(JetDefs.JETCREATOR_INI, JetDefs.INI_DEFAULTDIRS, self.spec, str(FileJustPath(dlg.GetPath()))) 265 val = dlg.GetPath() 266 267 self.Append(val) 268 self.cmb.SetValue(val) 269 270 if self.EventFire: 271 SendEvent(self.cmb, wx.EVT_COMBOBOX.evtType[0]) 272 dlg.Destroy() 273 274 def SetEventFire(self, fire): 275 self.EventFire = fire 276 277 def GetValue(self): 278 return StrNoneChk(self.cmb.GetValue()) 279 280 def SetValue(self, val): 281 try: 282 self.cmb.SetValue(val) 283 except: 284 pass 285 286 def Append(self, val): 287 try: 288 self.cmb.Append(val) 289 except: 290 pass 291 292 def SetFocus(self): 293 self.cmb.SetFocus() 294 295 def SetListValues(self, list): 296 self.cmb.AppendItems(list) 297 298 def Enable(self, enable): 299 self.cmb.Enable(enable) 300 self.btn.Enable(enable) 301 302 def SetHelpText(self, Lbl): 303 self.cmb.SetHelpText(Lbl) 304 self.btn.SetHelpText(Lbl) 305 306class JetFileText(): 307 """ Capture a filename with a button to browse for a file """ 308 def __init__(self, parent, pos=(0,0), size=(200,-1), title='Open File', spec='*.*', id=-1): 309 self.spec = spec 310 self.title = title 311 BUTWIDTH = 20 312 BORDER = 5 313 w = size[0] - (BUTWIDTH + BORDER) 314 col = pos[0] + w + BORDER 315 316 self.txt = wx.TextCtrl(parent, id, "", pos=(pos[0]-MacOffset(),pos[1]), size=(w, -1)) 317 self.btn = wx.Button(parent, -1, "...", pos=(col, pos[1]), size=(BUTWIDTH,self.txt.GetSize()[1])) 318 self.btn.Bind(wx.EVT_BUTTON, self.OnBrowse, self.btn) 319 320 def OnBrowse(self, event): 321 os = __import__('os') 322 defDir = IniGetValue(JetDefs.JETCREATOR_INI, JetDefs.INI_DEFAULTDIRS, self.spec, 'str', str(os.getcwd())) 323 if OsWindows(): 324 defDir = defDir.replace('/','\\') 325 else: 326 defDir = defDir.replace('\\', '/') 327 328 dlg = wx.FileDialog(None, self.title, defDir, '', self.spec, wx.FD_OPEN) 329 ret = dlg.ShowModal() 330 if ret == wx.ID_OK: 331 IniSetValue(JetDefs.JETCREATOR_INI, JetDefs.INI_DEFAULTDIRS, self.spec, str(FileJustPath(dlg.GetPath()))) 332 val = dlg.GetPath() 333 self.txt.SetValue(val) 334 dlg.Destroy() 335 336 def GetValue(self): 337 return StrNoneChk(self.txt.GetValue()) 338 339 def SetValue(self, val): 340 try: 341 self.txt.SetValue(val) 342 except: 343 pass 344 345 def Append(self, val): 346 try: 347 self.txt.Append(val) 348 except: 349 pass 350 351 def SetFocus(self): 352 self.txt.SetFocus() 353 354 def Enable(self, enable): 355 self.txt.Enable(enable) 356 self.btn.Enable(enable) 357 358 def SetHelpText(self, Lbl): 359 self.txt.SetHelpText(Lbl) 360 self.btn.SetHelpText(Lbl) 361 362def YesNo(title, question, default): 363 """ Simple Yes/No question box """ 364 dlg = wx.MessageDialog(None, question, title, wx.YES_NO | wx.ICON_QUESTION) 365 if dlg.ShowModal() == wx.ID_YES: 366 result = True 367 else: 368 result = False 369 dlg.Destroy() 370 return result 371 372def YesNoCancel(title, question, default): 373 """ Simple Yes/No question box """ 374 dlg = wx.MessageDialog(None, question, title, wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION) 375 result = dlg.ShowModal() 376 dlg.Destroy() 377 return result 378 379def ErrorMsg(title, message): 380 """ Dipslay an error message """ 381 dlg = wx.MessageDialog(None, message, title, wx.ICON_ERROR) 382 dlg.ShowModal() 383 dlg.Destroy() 384 385def InfoMsg(title, message): 386 """ Displays an informational message """ 387 dlg = wx.MessageDialog(None, message, title, wx.ICON_INFORMATION) 388 dlg.ShowModal() 389 dlg.Destroy() 390 391class TimeCtrl(wx.Frame): 392 """ Combination of controls to capture measure, beat, tick times """ 393 def __init__(self, parent, pos=(0,0), minimums=(1,1,0), maximums=(999,4,480), value=JetDefs.MBT_DEFAULT, ctlName=''): 394 wx.Frame.__init__(self, parent, -1) 395 396 self.ChangeCallbackFct = None 397 self.ctlName = ctlName 398 self.mx = maximums 399 self.mn = minimums 400 self.maxTicks = 0 401 self.iCtrl = 0 402 p1 = pos[0] 403 top = pos[1] + MacOffset() 404 w1 = 30 405 self.time = (wx.TextCtrl(parent, -1, str(value[0]), pos=(p1, top), size=(w1, -1), style=wx.TE_NOHIDESEL), 406 wx.TextCtrl(parent, -1, str(value[1]), pos=(p1 + (w1 + 3), top), size=(w1, -1), style=wx.TE_NOHIDESEL), 407 wx.TextCtrl(parent, -1, str(value[2]), pos=(p1 + (w1 + 3) *2, top), size=(w1, -1), style=wx.TE_NOHIDESEL), 408 ) 409 h = self.time[2].GetSize().height 410 w = self.time[2].GetSize().width + self.time[2].GetPosition().x + 8 411 412 self.spin = wx.SpinButton(parent, -1, (w, top), (h*2/3, h), wx.SP_VERTICAL) 413 self.spin.SetValue(1) 414 self.spin.SetRange(-999,999) 415 416 self.spin.Bind(wx.EVT_SPIN_UP, self.OnSpinUp, self.spin) 417 self.spin.Bind(wx.EVT_SPIN_DOWN, self.OnSpinDown, self.spin) 418 419 self.time[0].Bind(wx.EVT_SET_FOCUS, self.OnFocusMeasure, self.time[0] ) 420 self.time[1].Bind(wx.EVT_SET_FOCUS, self.OnFocusBeat, self.time[1] ) 421 self.time[2].Bind(wx.EVT_SET_FOCUS, self.OnFocusTick, self.time[2] ) 422 423 self.time[0].Bind(wx.EVT_KILL_FOCUS, self.OnChangeVal, self.time[0] ) 424 self.time[1].Bind(wx.EVT_KILL_FOCUS, self.OnChangeVal, self.time[1] ) 425 self.time[2].Bind(wx.EVT_KILL_FOCUS, self.OnChangeVal, self.time[2] ) 426 427 self.SetValue(value) 428 429 def UnBindKillFocus(self): 430 self.time[0].Unbind(wx.EVT_KILL_FOCUS, self.time[0]) 431 self.time[1].Unbind(wx.EVT_KILL_FOCUS, self.time[1]) 432 self.time[2].Unbind(wx.EVT_KILL_FOCUS, self.time[2]) 433 434 def SetChangeCallbackFct(self, ChangeCallbackFct): 435 self.ChangeCallbackFct = ChangeCallbackFct 436 437 def OnChangeVal(self, event=None): 438 if not OsWindows(): 439 self.time[self.iCtrl].SetSelection(-1,-1) 440 if int(self.time[self.iCtrl].GetValue()) > self.mx[self.iCtrl]: 441 self.time[self.iCtrl].SetValue(str(self.mx[self.iCtrl])) 442 if int(self.time[self.iCtrl].GetValue()) < self.mn[self.iCtrl]: 443 self.time[self.iCtrl].SetValue(str(self.mn[self.iCtrl])) 444 if self.ChangeCallbackFct is not None: 445 self.ChangeCallbackFct() 446 if event is not None: 447 event.Skip() 448 449 def OnSpinUp(self, event): 450 if int(self.time[self.iCtrl].GetValue()) < self.mx[self.iCtrl]: 451 self.time[self.iCtrl].SetValue(str(int(self.time[self.iCtrl].GetValue()) + 1)) 452 self.OnChangeVal() 453 454 def OnSpinDown(self, event): 455 if int(self.time[self.iCtrl].GetValue()) > self.mn[self.iCtrl]: 456 self.time[self.iCtrl].SetValue(str(int(self.time[self.iCtrl].GetValue()) - 1)) 457 self.OnChangeVal() 458 459 def OnFocusMeasure(self, event): 460 self.iCtrl = 0 461 462 def OnFocusBeat(self, event): 463 self.iCtrl = 1 464 465 def OnFocusTick(self, event): 466 self.iCtrl = 2 467 468 def SetValue(self, mbt): 469 try: 470 if type(mbt).__name__=='str' or type(mbt).__name__=='unicode': 471 mbt = ConvertStrTimeToTuple(mbt) 472 mbt = mbtFct(mbt, 1) 473 self.time[0].SetValue(str(mbt[0])) 474 self.time[1].SetValue(str(mbt[1])) 475 self.time[2].SetValue(str(mbt[2])) 476 except: 477 self.time[0].SetValue(str(self.mn[0])) 478 self.time[1].SetValue(str(self.mn[1])) 479 self.time[2].SetValue(str(self.mn[2])) 480 if not OsWindows(): 481 self.time[0].SetSelection(-1,-1) 482 self.time[1].SetSelection(-1,-1) 483 self.time[2].SetSelection(-1,-1) 484 485 def GetValue(self, typ='str'): 486 try: 487 if typ == 'str': 488 ret = "%d:%d:%d" % (int(self.time[0].GetValue()), int(self.time[1].GetValue()), int(self.time[2].GetValue())) 489 else: 490 ret = (int(self.time[0].GetValue()), int(self.time[1].GetValue()), int(self.time[2].GetValue())) 491 except: 492 ret = self.minimums 493 return mbtFct(ret, -1) 494 495 def Enable(self, enable): 496 self.time[0].Enable(enable) 497 self.time[1].Enable(enable) 498 self.time[2].Enable(enable) 499 self.spin.Enable(enable) 500 501 def SetFocus(self): 502 self.time[0].SetFocus() 503 504 def SetMaxMbt(self, m, b, t): 505 self.mx = (m,b,t) 506 507 def GetMaxMbt(self): 508 return "%d:%d:%d" % self.mx 509 510 def SetMinMbt(self, m, b, t): 511 self.mn = (m,b,t) 512 513 def SetMaxTicks(self, maxTicks): 514 self.maxTicks = maxTicks 515 516 def GetMaxTicks(self): 517 return self.maxTicks 518 519 def SetHelpText(self, Lbl): 520 self.spin.SetHelpText(Lbl) 521 self.time[0].SetHelpText(Lbl) 522 self.time[1].SetHelpText(Lbl) 523 self.time[2].SetHelpText(Lbl) 524 525 def GetMeasure(self): 526 return int(self.time[0].GetValue()) 527 528 def GetBeat(self): 529 return int(self.time[1].GetValue()) 530 531 def GetTick(self): 532 return int(self.time[2].GetValue()) 533 534if __name__ == '__main__': 535 """ Test code for controls """ 536 class TestFrame(wx.Frame): 537 def __init__(self, parent, id, title): 538 wx.Frame.__init__(self, parent, id, title, size=(350, 220)) 539 540 panel = wx.Panel(self, -1) 541 542 self.tc = TimeCtrl(panel, pos=(30, 20), maximums=(25, 4, 120), value=(2, 3, 4)) 543 #tc.Enable(True) 544 #tc.SetValue((2,3,4)) 545 #tc.SetValue("1:2:3") 546 #print(tc.GetValue()) 547 548 js = JetSpin(panel, -1, pos=(30, 100)) 549 js.SetValue("1") 550 #js.SetValue(1) 551 552 #fl = JetFileCombo(panel) 553 554 wx.EVT_CLOSE(self, self.OnClose) 555 556 self.Centre() 557 self.Show(True) 558 559 def OnClose(self, event): 560 self.tc.UnBindKillFocus() 561 self.Destroy() 562 563 app = wx.App(None) 564 TestFrame(None, -1, 'TestFrame') 565 app.MainLoop() 566 567 568