from Carbon import Ctl, Controls from Carbon import Evt, Qd, Win import Wbase class ControlWidget(Wbase.ClickableWidget): """Baseclass for all native controls.""" def __init__(self, possize, title = "Control", procID = 0, callback = None, value = 0, min = 0, max = 1, viewsize = 0): Wbase.ClickableWidget.__init__(self, possize) self._control = None self._title = title self._callback = callback self._procID = procID self._value = value self._min = min self._max = max self._enabled = 1 self._viewsize = viewsize def open(self): self._calcbounds() # NewControl doesn't accept 32-bit value, min, or max, so for consistency # with the new 32-bit set/get methods, out-of-range values are initially # set as zero, followed by a 32-bit set of the actual value. # Values not representable in 16 bits will fail on MacOS 8.1, however # the vast majority of control usage should still be compatible. _value, _min, _max = self._value, self._min, self._max if -32768 <= _value <= 32767: bigvalue = None else: bigvalue = _value _value = 0 if -32768 <= _min <= 32767: bigmin = None else: bigmin = _min _min = 0 if -32768 <= _max <= 32767: bigmax = None else: bigmax = _max _max = 0 self._control = Ctl.NewControl(self._parentwindow.wid, self._bounds, self._title, 1, _value, _min, _max, self._procID, 0) if bigvalue: self._control.SetControl32BitValue(bigvalue) if bigmin: self._control.SetControl32BitMinimum(bigmin) if bigmax: self._control.SetControl32BitMaximum(bigmax) if self._viewsize: try: self._control.SetControlViewSize(self._viewsize) # Not available in MacOS 8.1, but that's OK since it only affects # proportional scrollbars which weren't available in 8.1 either. except NotImplementedError: pass self.enable(self._enabled) def adjust(self, oldbounds): self.SetPort() self._control.HideControl() self._control.MoveControl(self._bounds[0], self._bounds[1]) self._control.SizeControl(self._bounds[2] - self._bounds[0], self._bounds[3] - self._bounds[1]) if self._visible: Qd.EraseRect(self._bounds) self._control.ShowControl() self.GetWindow().ValidWindowRect(self._bounds) def close(self): self._control.HideControl() self._control = None Wbase.ClickableWidget.close(self) def enable(self, onoff): if self._control and self._enabled <> onoff: self._control.HiliteControl((not onoff) and 255) self._enabled = onoff def show(self, onoff): self._visible = onoff for w in self._widgets: w.show(onoff) if onoff: self._control.ShowControl() else: self._control.HideControl() def activate(self, onoff): self._activated = onoff if self._enabled: if onoff: self._control.ActivateControl() else: self._control.DeactivateControl() def draw(self, visRgn = None): if self._visible: self._control.Draw1Control() def test(self, point): if Qd.PtInRect(point, self._bounds) and self._enabled: return 1 #ctltype, control = Ctl.FindControl(point, self._parentwindow.wid) #if self._enabled and control == self._control: # return 1 def click(self, point, modifiers): if not self._enabled: return part = self._control.TrackControl(point) if part: if self._callback: Wbase.CallbackCall(self._callback, 0) def settitle(self, title): if self._control: self._control.SetControlTitle(title) self._title = title def gettitle(self): return self._title def set(self, value): if self._control: if -32768 <= value <= 32767: # No 32-bit control support in MacOS 8.1, so use # the 16-bit interface when possible. self._control.SetControlValue(value) else: self._control.SetControl32BitValue(value) else: self._value = value def get(self): if self._control: try: return self._control.GetControl32BitValue() # No 32-bit control support in MacOS 8.1, so fall # back to the 16-bit interface when needed. except NotImplementedError: return self._control.GetControlValue() else: return self._value class Button(ControlWidget): """Standard push button.""" procID = Controls.pushButProc | Controls.useWFont def __init__(self, possize, title = "Button", callback = None): ControlWidget.__init__(self, possize, title, self.procID, callback, 0, 0, 1) self._isdefault = 0 def push(self): if not self._enabled: return # emulate the pushing of the button import time self._control.HiliteControl(Controls.kControlButtonPart) Qd.QDFlushPortBuffer(self._parentwindow.wid, None) # needed under OSX time.sleep(0.1) self._control.HiliteControl(0) if self._callback: Wbase.CallbackCall(self._callback, 0) def enable(self, onoff): if self._control and self._enabled <> onoff: self._control.HiliteControl((not onoff) and 255) self._enabled = onoff def show(self, onoff): ControlWidget.show(self, onoff) def draw(self, visRgn = None): if self._visible: self._control.Draw1Control() def open(self): ControlWidget.open(self) if self._isdefault: self._setdefault(self._isdefault) def _setdefault(self, onoff): c = self._control if c is not None: if onoff: data = "\xFF" else: data = "\0" # hide before changing state, otherwise the button isn't always # redrawn correctly, although it's quite different under Aqua # and Classic... c.HideControl() c.SetControlData(Controls.kControlNoPart, Controls.kControlPushButtonDefaultTag, data) c.ShowControl() self._isdefault = onoff def adjust(self, oldbounds): if self._isdefault: old = Qd.InsetRect(oldbounds, -4, -4) new = Qd.InsetRect(self._bounds, -4, -4) Qd.EraseRect(old) self.GetWindow().InvalWindowRect(old) self.GetWindow().InvalWindowRect(new) ControlWidget.adjust(self, oldbounds) class BevelButton(Button): procID = Controls.kControlBevelButtonNormalBevelProc | Controls.useWFont class CheckBox(ControlWidget): """Standard checkbox.""" def __init__(self, possize, title = "Checkbox", callback = None, value = 0): procID = Controls.checkBoxProc | Controls.useWFont ControlWidget.__init__(self, possize, title, procID, callback, value, 0, 1) def click(self, point, modifiers): if not self._enabled: return part = self._control.TrackControl(point) if part: self.toggle() if self._callback: Wbase.CallbackCall(self._callback, 0, self.get()) def push(self): if not self._enabled: return self.toggle() if self._callback: Wbase.CallbackCall(self._callback, 0, self.get()) def toggle(self): self.set(not self.get()) class RadioButton(ControlWidget): """Standard radiobutton.""" # XXX We need a radiogroup widget; this is too kludgy. def __init__(self, possize, title, thebuttons, callback = None, value = 0): procID = Controls.radioButProc | Controls.useWFont ControlWidget.__init__(self, possize, title, procID, callback, value, 0, 1) self.thebuttons = thebuttons thebuttons.append(self) def close(self): self.thebuttons = None ControlWidget.close(self) def click(self, point, modifiers): if not self._enabled: return part = self._control.TrackControl(point) if part: self.set(1) if self._callback: Wbase.CallbackCall(self._callback, 0, 1) def push(self): if not self._enabled: return self.set(1) if self._callback: Wbase.CallbackCall(self._callback, 0, 1) def set(self, value): for button in self.thebuttons: if button._control: button._control.SetControlValue(button == self) else: button._value = (button == self) class Scrollbar(ControlWidget): """Standard scrollbar.""" def __init__(self, possize, callback = None, value = 0, min = 0, max = 0): procID = Controls.scrollBarProc ControlWidget.__init__(self, possize, "", procID, callback, value, min, max) # interface # def set(self, value): # if self._callback: # Wbase.CallbackCall(self._callback, 1, value) def up(self): if self._callback: Wbase.CallbackCall(self._callback, 1, '+') def down(self): if self._callback: Wbase.CallbackCall(self._callback, 1, '-') def pageup(self): if self._callback: Wbase.CallbackCall(self._callback, 1, '++') def pagedown(self): if self._callback: Wbase.CallbackCall(self._callback, 1, '--') def setmin(self, min): if self._control is not None: if -32768 <= min <= 32767: # No 32-bit control support in MacOS 8.1, so use # the 16-bit interface when possible. self._control.SetControlMinimum(min) else: self._control.SetControl32BitMinimum(min) else: self._min = min def setmax(self, max): if self._control is not None: if -32768 <= max <= 32767: # No 32-bit control support in MacOS 8.1, so use # the 16-bit interface when possible. self._control.SetControlMaximum(max) else: self._control.SetControl32BitMaximum(max) else: self._max = max def setviewsize(self, viewsize): if self._control is not None: try: self._control.SetControlViewSize(viewsize) # Not available in MacOS 8.1, but that's OK since it only affects # proportional scrollbars which weren't available in 8.1 either. except NotImplementedError: pass else: self._viewsize = viewsize def getmin(self): try: return self._control.GetControl32BitMinimum() # No 32-bit control support in MacOS 8.1, so fall # back to the 16-bit interface when needed. except NotImplementedError: return self._control.GetControlMinimum() def getmax(self): try: return self._control.GetControl32BitMaximum() # No 32-bit control support in MacOS 8.1, so fall # back to the 16-bit interface when needed. except NotImplementedError: return self._control.GetControlMaximum() # internals def click(self, point, modifiers): if not self._enabled: return # custom TrackControl. A mousedown in a scrollbar arrow or page area should # generate _control hits as long as the mouse is a) down, b) still in the same part part = self._control.TestControl(point) if Controls.inUpButton <= part <= Controls.inPageDown: self._control.HiliteControl(part) self._hit(part) oldpart = part # slight delay before scrolling at top speed... now = Evt.TickCount() while Evt.StillDown(): if (Evt.TickCount() - now) > 18: # 0.3 seconds break while Evt.StillDown(): part = self._control.TestControl(point) if part == oldpart: self._control.HiliteControl(part) self._hit(part) else: self._control.HiliteControl(0) self.SetPort() point = Evt.GetMouse() self._control.HiliteControl(0) elif part == Controls.inThumb: part = self._control.TrackControl(point) if part: self._hit(part) def _hit(self, part): if part == Controls.inThumb: try: value = self._control.GetControl32BitValue() # No 32-bit control support in MacOS 8.1, so fall # back to the 16-bit interface when needed. except NotImplementedError: value = self._control.GetControlValue() elif part == Controls.inUpButton: value = "+" elif part == Controls.inDownButton: value = "-" elif part == Controls.inPageUp: value = "++" elif part == Controls.inPageDown: value = "--" if self._callback: Wbase.CallbackCall(self._callback, 1, value) def draw(self, visRgn = None): if self._visible: self._control.Draw1Control() #Qd.FrameRect(self._bounds) def adjust(self, oldbounds): self.SetPort() self.GetWindow().InvalWindowRect(oldbounds) self._control.HideControl() self._control.MoveControl(self._bounds[0], self._bounds[1]) self._control.SizeControl(self._bounds[2] - self._bounds[0], self._bounds[3] - self._bounds[1]) if self._visible: Qd.EraseRect(self._bounds) if self._activated: self._control.ShowControl() else: Qd.FrameRect(self._bounds) self.GetWindow().ValidWindowRect(self._bounds) def _scalebarvalue(absmin, absmax, curmin, curmax): if curmin <= absmin and curmax >= absmax: return None if curmin <= absmin: return 0 if curmax >= absmax: return 32767 perc = float(curmin-absmin) / float((absmax - absmin) - (curmax - curmin)) return int(perc*32767)