def place(self, rect, containing_view): """Place this widget on a view. """ if self.viewport is None: if self.CREATES_VIEW: self.viewport = Viewport(self.view, rect) containing_view.addSubview_(self.view) wrappermap.add(self.view, self) else: self.viewport = BorrowedViewport(containing_view, rect) self.viewport_created() else: if not self.viewport.at_position(rect): self.viewport.reposition(rect) self.viewport_repositioned() self.emit('size-allocated', rect.size.width, rect.size.height)
class Widget(signals.SignalEmitter): """Base class for Cocoa widgets. attributes: CREATES_VIEW -- Does the widget create a view for itself? If this is True the widget must have an attribute named view, which is the view that the widget uses. placement -- What portion of view the widget occupies. """ CREATES_VIEW = True def __init__(self): threadcheck.confirm_ui_thread() signals.SignalEmitter.__init__(self) self.create_signal('key-press') self.create_signal('focus-out') self.create_signal('place-in-scroller') self.create_signal('size-request-changed', okay_to_nest=True) self.create_signal('size-allocated', okay_to_nest=True) self.viewport = None self.parent_is_scroller = False self.manual_size_request = None self.cached_size_request = None self._disabled = False def set_can_focus(self, allow): assert isinstance(self.view, NSControl) self.view.setRefusesFirstResponder_(not allow) def set_size_request(self, width, height): self.manual_size_request = (width, height) self.invalidate_size_request() def get_size_request(self): if self.manual_size_request: width, height = self.manual_size_request if width == -1: width = self.get_natural_size_request()[0] if height == -1: height = self.get_natural_size_request()[1] return width, height return self.get_natural_size_request() def get_natural_size_request(self): if self.cached_size_request: return self.cached_size_request else: self.cached_size_request = self.calc_size_request() return self.cached_size_request def invalidate_size_request(self): """Recalculate the size request for this widget.""" old_size_request = self.get_size_request() self.cached_size_request = None self.emit('size-request-changed', old_size_request) def calc_size_request(self): """Return the minimum size needed to display this widget. Must be Implemented by subclasses. """ raise NotImplementedError() def _debug_size_request(self, nesting_level=0): """Debug size request calculations. This method recursively prints out the size request for each widget. """ request = self.calc_size_request() width = int(request[0]) height = int(request[1]) indent = ' ' * nesting_level me = str(self.__class__).split('.')[-1] print '%s%s: %sx%s' % (indent, me, width, height) def place(self, rect, containing_view): """Place this widget on a view. """ if self.viewport is None: if self.CREATES_VIEW: self.viewport = Viewport(self.view, rect) containing_view.addSubview_(self.view) wrappermap.add(self.view, self) else: self.viewport = BorrowedViewport(containing_view, rect) self.viewport_created() else: if not self.viewport.at_position(rect): self.viewport.reposition(rect) self.viewport_repositioned() self.emit('size-allocated', rect.size.width, rect.size.height) def remove_viewport(self): if self.viewport is not None: self.viewport.remove() self.viewport = None if self.CREATES_VIEW: wrappermap.remove(self.view) def viewport_created(self): """Called after we first create a viewport. Subclasses can override this method if they want to handle this event. """ def viewport_repositioned(self): """Called when we reposition our viewport. Subclasses can override this method if they want to handle this event. """ def viewport_scrolled(self): """Called by the Scroller widget on it's child widget when it is scrolled. """ def get_width(self): return int(self.viewport.get_width()) width = property(get_width) def get_height(self): return int(self.viewport.get_height()) height = property(get_height) def get_window(self): if not self.viewport.view: return None return wrappermap.wrapper(self.viewport.view.window()) def queue_redraw(self): if self.viewport: self.viewport.queue_redraw() def redraw_now(self): if self.viewport: self.viewport.redraw_now() def relative_position(self, other_widget): """Get the position of another widget, relative to this widget.""" basePoint = self.viewport.view.convertPoint_fromView_( other_widget.viewport.area().origin, other_widget.viewport.view) return (basePoint.x - self.viewport.area().origin.x, basePoint.y - self.viewport.area().origin.y) def make_color(self, (red, green, blue)): return NSColor.colorWithDeviceRed_green_blue_alpha_(red, green, blue, 1.0)
class Widget(signals.SignalEmitter): """Base class for Cocoa widgets. attributes: CREATES_VIEW -- Does the widget create a view for itself? If this is True the widget must have an attribute named view, which is the view that the widget uses. placement -- What portion of view the widget occupies. """ CREATES_VIEW = True def __init__(self): signals.SignalEmitter.__init__(self, 'size-request-changed', 'size-allocated', 'key-press') self.viewport = None self.parent_is_scroller = False self.manual_size_request = None self.cached_size_request = None self._disabled = False def set_size_request(self, width, height): self.manual_size_request = (width, height) self.invalidate_size_request() def get_size_request(self): if self.manual_size_request: width, height = self.manual_size_request if width == -1: width = self.get_natural_size_request()[0] if height == -1: height = self.get_natural_size_request()[1] return width, height return self.get_natural_size_request() def get_natural_size_request(self): if self.cached_size_request: return self.cached_size_request else: self.cached_size_request = self.calc_size_request() return self.cached_size_request def invalidate_size_request(self): if hasattr(self, 'view') and self.view is not None: scroll_view = self.view.enclosingScrollView() if scroll_view is not None: scrolled_view = scroll_view.contentView() current_scroll_position = scrolled_view.bounds().origin self.do_invalidate_size_request() scrolled_view.scrollPoint_(current_scroll_position) else: self.do_invalidate_size_request() else: self.do_invalidate_size_request() def do_invalidate_size_request(self): """Recalculate the size request for this widget.""" old_size_request = self.cached_size_request self.cached_size_request = None self.emit('size-request-changed', old_size_request) def calc_size_request(self): """Return the minimum size needed to display this widget. Must be Implemented by subclasses. """ raise NotImplementedError() def place(self, rect, containing_view): """Place this widget on a view. """ if self.viewport is None: if self.CREATES_VIEW: self.viewport = Viewport(self.view, rect) containing_view.addSubview_(self.view) wrappermap.add(self.view, self) else: self.viewport = BorrowedViewport(containing_view, rect) self.viewport_created() else: if not self.viewport.at_position(rect): self.viewport.reposition(rect) self.viewport_repositioned() self.emit('size-allocated', rect.size.width, rect.size.height) def remove_viewport(self): if self.viewport is not None: self.viewport.remove() self.viewport = None if self.CREATES_VIEW: wrappermap.remove(self.view) def create_view(self, rect): """Implemented by subclasses with CREATES_VIEW set. It must return a NSView with a frame size equal to rect. """ raise NotImplementedError("%s has CREATES_VIEW set, but doesn't implement create_view" % self.__class__) def viewport_created(self): """Called after we first create a viewport. Subclasses can override this method if they want to handle this event. """ def viewport_repositioned(self): """Called when we reposition our viewport. Subclasses can override this method if they want to handle this event. """ def viewport_scrolled(self): """Called by the Scroller widget on it's child widget when it is scrolled. """ def get_width(self): return int(self.viewport.get_width()) width = property(get_width) def get_height(self): return int(self.viewport.get_height()) height = property(get_height) def get_window(self): if not self.viewport.view: return None return wrappermap.wrapper(self.viewport.view.window()) def queue_redraw(self): if self.viewport: self.viewport.queue_redraw() def redraw_now(self): if self.viewport: self.viewport.redraw_now() def relative_position(self, other_widget): """Get the position of another widget, relative to this widget.""" basePoint = self.viewport.view.convertPoint_fromView_( other_widget.viewport.area().origin, other_widget.viewport.view) return (basePoint.x - self.viewport.area().origin.x, basePoint.y - self.viewport.area().origin.y) def make_color(self, (red, green, blue)): return NSColor.colorWithDeviceRed_green_blue_alpha_(red, green, blue, 1.0)