class ControlPanel(wx.Panel): """""" def __init__(self, parent, *args, **kwargs): """""" self.parent = parent self.stitch_plan = kwargs.pop('stitch_plan') self.target_stitches_per_second = kwargs.pop('stitches_per_second') self.target_duration = kwargs.pop('target_duration') kwargs['style'] = wx.BORDER_SUNKEN wx.Panel.__init__(self, parent, *args, **kwargs) self.statusbar = self.GetTopLevelParent().statusbar self.drawing_panel = None self.num_stitches = 1 self.current_stitch = 1 self.speed = 1 self.direction = 1 # Widgets self.btnMinus = wx.Button(self, -1, label='-') self.btnMinus.Bind(wx.EVT_BUTTON, self.animation_slow_down) self.btnMinus.SetToolTip(_('Slow down (arrow down)')) self.btnPlus = wx.Button(self, -1, label='+') self.btnPlus.Bind(wx.EVT_BUTTON, self.animation_speed_up) self.btnPlus.SetToolTip(_('Speed up (arrow up)')) self.btnBackwardStitch = wx.Button(self, -1, label='<|') self.btnBackwardStitch.Bind(wx.EVT_BUTTON, self.animation_one_stitch_backward) self.btnBackwardStitch.SetToolTip(_('Go on step backward (-)')) self.btnForwardStitch = wx.Button(self, -1, label='|>') self.btnForwardStitch.Bind(wx.EVT_BUTTON, self.animation_one_stitch_forward) self.btnForwardStitch.SetToolTip(_('Go on step forward (+)')) self.directionBtn = wx.Button(self, -1, label='<<') self.directionBtn.Bind(wx.EVT_BUTTON, self.on_direction_button) self.directionBtn.SetToolTip( _('Switch direction (arrow left | arrow right)')) self.pauseBtn = wx.Button(self, -1, label=_('Pause')) self.pauseBtn.Bind(wx.EVT_BUTTON, self.on_pause_start_button) self.pauseBtn.SetToolTip(_('Pause (P)')) self.restartBtn = wx.Button(self, -1, label=_('Restart')) self.restartBtn.Bind(wx.EVT_BUTTON, self.animation_restart) self.restartBtn.SetToolTip(_('Restart (R)')) self.quitBtn = wx.Button(self, -1, label=_('Quit')) self.quitBtn.Bind(wx.EVT_BUTTON, self.animation_quit) self.quitBtn.SetToolTip(_('Quit (Q)')) self.slider = wx.Slider(self, -1, value=1, minValue=1, maxValue=2, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.slider.Bind(wx.EVT_SLIDER, self.on_slider) self.stitchBox = IntCtrl(self, -1, value=1, min=1, max=2, limited=True, allow_none=False) self.stitchBox.Bind(wx.EVT_TEXT, self.on_stitch_box) # Layout self.vbSizer = vbSizer = wx.BoxSizer(wx.VERTICAL) self.hbSizer1 = hbSizer1 = wx.BoxSizer(wx.HORIZONTAL) self.hbSizer2 = hbSizer2 = wx.BoxSizer(wx.HORIZONTAL) hbSizer1.Add(self.slider, 1, wx.EXPAND | wx.ALL, 3) hbSizer1.Add(self.stitchBox, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 2) vbSizer.Add(hbSizer1, 1, wx.EXPAND | wx.ALL, 3) hbSizer2.Add(self.btnMinus, 0, wx.EXPAND | wx.ALL, 2) hbSizer2.Add(self.btnPlus, 0, wx.EXPAND | wx.ALL, 2) hbSizer2.Add(self.btnBackwardStitch, 0, wx.EXPAND | wx.ALL, 2) hbSizer2.Add(self.btnForwardStitch, 0, wx.EXPAND | wx.ALL, 2) hbSizer2.Add(self.directionBtn, 0, wx.EXPAND | wx.ALL, 2) hbSizer2.Add(self.pauseBtn, 0, wx.EXPAND | wx.ALL, 2) hbSizer2.Add(self.restartBtn, 0, wx.EXPAND | wx.ALL, 2) hbSizer2.Add(self.quitBtn, 0, wx.EXPAND | wx.ALL, 2) vbSizer.Add(hbSizer2, 0, wx.EXPAND | wx.ALL, 3) self.SetSizerAndFit(vbSizer) # Keyboard Shortcuts shortcut_keys = [ (wx.ACCEL_NORMAL, wx.WXK_RIGHT, self.animation_forward), (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_RIGHT, self.animation_forward), (wx.ACCEL_NORMAL, wx.WXK_LEFT, self.animation_reverse), (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_LEFT, self.animation_reverse), (wx.ACCEL_NORMAL, wx.WXK_UP, self.animation_speed_up), (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_UP, self.animation_speed_up), (wx.ACCEL_NORMAL, wx.WXK_DOWN, self.animation_slow_down), (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_DOWN, self.animation_slow_down), (wx.ACCEL_NORMAL, ord('+'), self.animation_one_stitch_forward), (wx.ACCEL_NORMAL, ord('='), self.animation_one_stitch_forward), (wx.ACCEL_SHIFT, ord('='), self.animation_one_stitch_forward), (wx.ACCEL_NORMAL, wx.WXK_ADD, self.animation_one_stitch_forward), (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_ADD, self.animation_one_stitch_forward), (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_UP, self.animation_one_stitch_forward), (wx.ACCEL_NORMAL, ord('-'), self.animation_one_stitch_backward), (wx.ACCEL_NORMAL, ord('_'), self.animation_one_stitch_backward), (wx.ACCEL_NORMAL, wx.WXK_SUBTRACT, self.animation_one_stitch_backward), (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_SUBTRACT, self.animation_one_stitch_backward), (wx.ACCEL_NORMAL, ord('r'), self.animation_restart), (wx.ACCEL_NORMAL, ord('p'), self.on_pause_start_button), (wx.ACCEL_NORMAL, wx.WXK_SPACE, self.on_pause_start_button), (wx.ACCEL_NORMAL, ord('q'), self.animation_quit) ] accel_entries = [] for shortcut_key in shortcut_keys: eventId = wx.NewId() accel_entries.append((shortcut_key[0], shortcut_key[1], eventId)) self.Bind(wx.EVT_MENU, shortcut_key[2], id=eventId) accel_table = wx.AcceleratorTable(accel_entries) self.SetAcceleratorTable(accel_table) self.SetFocus() def set_drawing_panel(self, drawing_panel): self.drawing_panel = drawing_panel self.drawing_panel.set_speed(self.speed) def set_num_stitches(self, num_stitches): if num_stitches < 2: # otherwise the slider and intctrl get mad num_stitches = 2 self.num_stitches = num_stitches self.stitchBox.SetMax(num_stitches) self.slider.SetMax(num_stitches) self.choose_speed() def choose_speed(self): if self.target_duration: self.set_speed(int(self.num_stitches / float(self.target_duration))) else: self.set_speed(self.target_stitches_per_second) def animation_forward(self, event=None): self.directionBtn.SetLabel("<<") self.drawing_panel.forward() self.direction = 1 self.update_speed_text() def animation_reverse(self, event=None): self.directionBtn.SetLabel(">>") self.drawing_panel.reverse() self.direction = -1 self.update_speed_text() def on_direction_button(self, event): if self.direction == 1: self.animation_reverse() else: self.animation_forward() def set_speed(self, speed): self.speed = int(max(speed, 1)) self.update_speed_text() if self.drawing_panel: self.drawing_panel.set_speed(self.speed) def update_speed_text(self): self.statusbar.SetStatusText( _('Speed: %d stitches/sec') % (self.speed * self.direction), 0) self.hbSizer2.Layout() def on_slider(self, event): stitch = event.GetEventObject().GetValue() self.stitchBox.SetValue(stitch) if self.drawing_panel: self.drawing_panel.set_current_stitch(stitch) def on_current_stitch(self, stitch, command): if self.current_stitch != stitch: self.current_stitch = stitch self.slider.SetValue(stitch) self.stitchBox.SetValue(stitch) self.statusbar.SetStatusText(COMMAND_NAMES[command], 1) def on_stitch_box(self, event): stitch = self.stitchBox.GetValue() self.slider.SetValue(stitch) if self.drawing_panel: self.drawing_panel.set_current_stitch(stitch) def animation_slow_down(self, event): """""" self.set_speed(self.speed / 2.0) def animation_speed_up(self, event): """""" self.set_speed(self.speed * 2.0) def animation_pause(self, event=None): self.drawing_panel.stop() def animation_start(self, event=None): self.drawing_panel.go() def on_start(self): self.pauseBtn.SetLabel(_('Pause')) def on_stop(self): self.pauseBtn.SetLabel(_('Start')) def on_pause_start_button(self, event): """""" if self.pauseBtn.GetLabel() == _('Pause'): self.animation_pause() else: self.animation_start() def animation_one_stitch_forward(self, event): self.animation_pause() self.drawing_panel.one_stitch_forward() def animation_one_stitch_backward(self, event): self.animation_pause() self.drawing_panel.one_stitch_backward() def animation_quit(self, event): self.parent.quit() def animation_restart(self, event): self.drawing_panel.restart()
class DmgPatternEditorDlg(wx.Dialog): def __init__(self, parent): wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title=u"Damage Pattern Editor", size=wx.Size(400, 240)) self.block = False self.SetSizeHintsSz(wx.DefaultSize, wx.DefaultSize) mainSizer = wx.BoxSizer(wx.VERTICAL) self.headerSizer = headerSizer = wx.BoxSizer(wx.HORIZONTAL) cDP = service.DamagePattern.getInstance() self.choices = cDP.getDamagePatternList() # Remove "Uniform" and "Selected Ammo" Damage Patterns for dp in self.choices: if dp.name in ("Uniform", "Selected Ammo"): self.choices.remove(dp) # Sort the remaining list and continue on self.choices.sort(key=lambda p: p.name) self.ccDmgPattern = wx.Choice(self, choices=map(lambda p: p.name, self.choices)) self.ccDmgPattern.Bind(wx.EVT_CHOICE, self.patternChanged) self.ccDmgPattern.SetSelection(0) self.namePicker = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER) self.namePicker.Bind(wx.EVT_TEXT_ENTER, self.processRename) self.namePicker.Hide() self.btnSave = wx.Button(self, wx.ID_SAVE) self.btnSave.Hide() self.btnSave.Bind(wx.EVT_BUTTON, self.processRename) size = None headerSizer.Add(self.ccDmgPattern, 1, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.LEFT, 3) buttons = (("new", wx.ART_NEW), ("rename", bitmapLoader.getBitmap("rename", "icons")), ("copy", wx.ART_COPY), ("delete", wx.ART_DELETE)) for name, art in buttons: bitmap = wx.ArtProvider.GetBitmap( art, wx.ART_BUTTON) if name != "rename" else art btn = wx.BitmapButton(self, wx.ID_ANY, bitmap) if size is None: size = btn.GetSize() btn.SetMinSize(size) btn.SetMaxSize(size) btn.Layout() setattr(self, name, btn) btn.Enable(True) btn.SetToolTipString("%s pattern" % name.capitalize()) headerSizer.Add(btn, 0, wx.ALIGN_CENTER_VERTICAL) mainSizer.Add(headerSizer, 0, wx.EXPAND | wx.ALL, 2) self.sl = wx.StaticLine(self) mainSizer.Add(self.sl, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) contentSizer = wx.BoxSizer(wx.VERTICAL) self.embitmap = bitmapLoader.getBitmap("em_big", "icons") self.thermbitmap = bitmapLoader.getBitmap("thermal_big", "icons") self.kinbitmap = bitmapLoader.getBitmap("kinetic_big", "icons") self.expbitmap = bitmapLoader.getBitmap("explosive_big", "icons") dmgeditSizer = wx.FlexGridSizer(2, 4, 0, 2) dmgeditSizer.AddGrowableCol(1) dmgeditSizer.AddGrowableCol(2) dmgeditSizer.SetFlexibleDirection(wx.BOTH) dmgeditSizer.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) width = -1 defSize = wx.Size(width, -1) self.editEm = IntCtrl(self, wx.ID_ANY, 0, wx.DefaultPosition, defSize, wx.TE_RIGHT) dmgeditSizer.Add(self.editEm, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) self.bmpEM = wx.StaticBitmap(self, wx.ID_ANY, self.embitmap) dmgeditSizer.Add(self.bmpEM, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL, 5) self.bmpTHERM = wx.StaticBitmap(self, wx.ID_ANY, self.thermbitmap) dmgeditSizer.Add( self.bmpTHERM, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT, 5) self.editThermal = IntCtrl(self, wx.ID_ANY, 0, wx.DefaultPosition, defSize, 0) dmgeditSizer.Add(self.editThermal, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) self.editKinetic = IntCtrl(self, wx.ID_ANY, 0, wx.DefaultPosition, defSize, wx.TE_RIGHT) dmgeditSizer.Add(self.editKinetic, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) self.bmpKIN = wx.StaticBitmap(self, wx.ID_ANY, self.kinbitmap) dmgeditSizer.Add(self.bmpKIN, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL, 5) self.bmpEXP = wx.StaticBitmap(self, wx.ID_ANY, self.expbitmap) dmgeditSizer.Add( self.bmpEXP, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT, 5) self.editExplosive = IntCtrl(self, wx.ID_ANY, 0, wx.DefaultPosition, defSize, 0) dmgeditSizer.Add(self.editExplosive, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) contentSizer.Add(dmgeditSizer, 1, wx.EXPAND | wx.ALL, 5) self.slfooter = wx.StaticLine(self) contentSizer.Add(self.slfooter, 0, wx.EXPAND | wx.TOP, 5) footerSizer = wx.BoxSizer(wx.HORIZONTAL) perSizer = wx.BoxSizer(wx.VERTICAL) self.stPercentages = wx.StaticText(self, wx.ID_ANY, u"") self.stPercentages.Wrap(-1) perSizer.Add(self.stPercentages, 0, wx.BOTTOM | wx.LEFT, 5) footerSizer.Add(perSizer, 0, 0, 5) self.totSizer = wx.BoxSizer(wx.VERTICAL) self.stTotal = wx.StaticText(self, wx.ID_ANY, u"") self.stTotal.Wrap(-1) self.totSizer.Add(self.stTotal, 0, wx.ALIGN_RIGHT | wx.BOTTOM | wx.RIGHT, 5) footerSizer.Add(self.totSizer, 1, 0, 5) contentSizer.Add(footerSizer, 0, wx.EXPAND, 5) mainSizer.Add(contentSizer, 1, wx.EXPAND, 0) self.SetSizer(mainSizer) self.Layout() bsize = self.GetBestSize() self.SetSize((-1, bsize.height)) self.editEm.SetLimited(True) self.editThermal.SetLimited(True) self.editKinetic.SetLimited(True) self.editExplosive.SetLimited(True) self.editEm.SetMin(0) self.editThermal.SetMin(0) self.editKinetic.SetMin(0) self.editExplosive.SetMin(0) self.editEm.SetMax(99999) self.editThermal.SetMax(99999) self.editKinetic.SetMax(99999) self.editExplosive.SetMax(99999) self.new.Bind(wx.EVT_BUTTON, self.newPattern) self.rename.Bind(wx.EVT_BUTTON, self.renamePattern) self.copy.Bind(wx.EVT_BUTTON, self.copyPattern) self.delete.Bind(wx.EVT_BUTTON, self.deletePattern) self.editEm.Bind(wx.EVT_TEXT, self.ValuesUpdated) self.editThermal.Bind(wx.EVT_TEXT, self.ValuesUpdated) self.editKinetic.Bind(wx.EVT_TEXT, self.ValuesUpdated) self.editExplosive.Bind(wx.EVT_TEXT, self.ValuesUpdated) self.patternChanged() def ValuesUpdated(self, event=None): if self.block: return p = self.getActivePattern() p.emAmount = self._EM = self.editEm.GetValue() p.thermalAmount = self._THERM = self.editThermal.GetValue() p.kineticAmount = self._KIN = self.editKinetic.GetValue() p.explosiveAmount = self._EXP = self.editExplosive.GetValue() total = self._EM + self._THERM + self._KIN + self._EXP format = "EM: % 3d%% THERM: % 3d%% KIN: % 3d%% EXP: % 3d%%" if total > 0: ltext = format % (self._EM * 100 / total, self._THERM * 100 / total, self._KIN * 100 / total, self._EXP * 100 / total) else: ltext = format % (0, 0, 0, 0) ttext = "Total: % 6d" % (total) self.stPercentages.SetLabel(ltext) self.stTotal.SetLabel(ttext) self.totSizer.Layout() if event is not None: event.Skip() service.DamagePattern.getInstance().saveChanges(p) def restrict(self): self.editEm.Enable(False) self.editExplosive.Enable(False) self.editKinetic.Enable(False) self.editThermal.Enable(False) self.rename.Enable(False) self.delete.Enable(False) def unrestrict(self): self.editEm.Enable() self.editExplosive.Enable() self.editKinetic.Enable() self.editThermal.Enable() self.rename.Enable() self.delete.Enable() def getActivePattern(self): if len(self.choices) == 0: return None return self.choices[self.ccDmgPattern.GetSelection()] def patternChanged(self, event=None): p = self.getActivePattern() if p is None: return if p.name == "Uniform" or p.name == "Selected Ammo": self.restrict() else: self.unrestrict() self.block = True for field in ("em", "thermal", "kinetic", "explosive"): edit = getattr(self, "edit%s" % field.capitalize()) amount = getattr(p, "%sAmount" % field) edit.SetValue(amount) self.block = False self.ValuesUpdated() def newPattern(self, event): cDP = service.DamagePattern.getInstance() p = cDP.newPattern() self.choices.append(p) id = self.ccDmgPattern.Append(p.name) self.ccDmgPattern.SetSelection(id) self.btnSave.SetLabel("Create") self.renamePattern() def renamePattern(self, event=None): if event is not None: self.btnSave.SetLabel("Rename") self.ccDmgPattern.Hide() self.namePicker.Show() self.headerSizer.Replace(self.ccDmgPattern, self.namePicker) self.namePicker.SetFocus() self.namePicker.SetValue(self.getActivePattern().name) for btn in (self.new, self.rename, self.delete, self.copy): btn.Hide() self.headerSizer.Remove(btn) self.headerSizer.Add(self.btnSave, 0, wx.ALIGN_CENTER) self.btnSave.Show() self.headerSizer.Layout() if event is not None: event.Skip() def processRename(self, event): newName = self.namePicker.GetLineText(0) self.stPercentages.SetLabel("") self.stTotal.SetLabel("") p = self.getActivePattern() for pattern in self.choices: if pattern.name == newName and p != pattern: self.stPercentages.SetLabel( "Name already used, please pick another") return cDP = service.DamagePattern.getInstance() cDP.renamePattern(p, newName) self.headerSizer.Replace(self.namePicker, self.ccDmgPattern) self.ccDmgPattern.Show() self.namePicker.Hide() self.btnSave.Hide() self.headerSizer.Remove(self.btnSave) for btn in (self.new, self.rename, self.delete, self.copy): self.headerSizer.Add(btn, 0, wx.ALIGN_CENTER_VERTICAL) btn.Show() sel = self.ccDmgPattern.GetSelection() self.ccDmgPattern.Delete(sel) self.ccDmgPattern.Insert(newName, sel) self.ccDmgPattern.SetSelection(sel) self.ValuesUpdated() def copyPattern(self, event): cDP = service.DamagePattern.getInstance() p = cDP.copyPattern(self.getActivePattern()) self.choices.append(p) id = self.ccDmgPattern.Append(p.name) self.ccDmgPattern.SetSelection(id) self.btnSave.SetLabel("Copy") self.renamePattern() self.patternChanged() def deletePattern(self, event): cDP = service.DamagePattern.getInstance() sel = self.ccDmgPattern.GetSelection() cDP.deletePattern(self.getActivePattern()) self.ccDmgPattern.Delete(sel) self.ccDmgPattern.SetSelection(max(0, sel - 1)) del self.choices[sel] self.patternChanged() def __del__(self): pass