diff options
Diffstat (limited to 'mvc/widgets/osx/control.py')
-rw-r--r-- | mvc/widgets/osx/control.py | 530 |
1 files changed, 0 insertions, 530 deletions
diff --git a/mvc/widgets/osx/control.py b/mvc/widgets/osx/control.py deleted file mode 100644 index ed6ea34..0000000 --- a/mvc/widgets/osx/control.py +++ /dev/null @@ -1,530 +0,0 @@ -# @Base: Miro - an RSS based video player application -# Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 -# Participatory Culture Foundation -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# -# In addition, as a special exception, the copyright holders give -# permission to link the code of portions of this program with the OpenSSL -# library. -# -# You must obey the GNU General Public License in all respects for all of -# the code used other than OpenSSL. If you modify file(s) with this -# exception, you may extend this exception to your version of the file(s), -# but you are not obligated to do so. If you do not wish to do so, delete -# this exception statement from your version. If you delete this exception -# statement from all source files in the program, then also delete it here. - -""".control - Controls.""" - -from AppKit import * -from Foundation import * -from objc import YES, NO, nil - -from mvc.widgets import widgetconst -import wrappermap -from .base import Widget -from .helpers import NotificationForwarder - -class SizedControl(Widget): - def set_size(self, size): - if size == widgetconst.SIZE_NORMAL: - self.view.cell().setControlSize_(NSRegularControlSize) - font = NSFont.systemFontOfSize_(NSFont.systemFontSize()) - self.font_size = NSFont.systemFontSize() - elif size == widgetconst.SIZE_SMALL: - font = NSFont.systemFontOfSize_(NSFont.smallSystemFontSize()) - self.view.cell().setControlSize_(NSSmallControlSize) - self.font_size = NSFont.smallSystemFontSize() - else: - self.view.cell().setControlSize_(NSRegularControlSize) - font = NSFont.systemFontOfSize_(NSFont.systemFontSize() * size) - self.font_size = NSFont.systemFontSize() * size - self.view.setFont_(font) - -class BaseTextEntry(SizedControl): - """See https://develop.participatoryculture.org/index.php/WidgetAPI for a description of the API for this class.""" - def __init__(self, initial_text=None): - SizedControl.__init__(self) - self.view = self.make_view() - self.font = NSFont.systemFontOfSize_(NSFont.systemFontSize()) - self.view.setFont_(self.font) - self.view.setEditable_(YES) - self.view.cell().setScrollable_(YES) - self.view.cell().setLineBreakMode_(NSLineBreakByClipping) - self.sizer_cell = self.view.cell().copy() - if initial_text: - self.view.setStringValue_(initial_text) - self.set_width(len(initial_text)) - else: - self.set_width(10) - - self.notifications = NotificationForwarder.create(self.view) - - self.create_signal('activate') - self.create_signal('changed') - self.create_signal('validate') - - def focus(self): - if self.view.window() is not None: - self.view.window().makeFirstResponder_(self.view) - - def start_editing(self, initial_text): - self.set_text(initial_text) - self.focus() - # unselect the text and locate the cursor at the end of the entry - text_field = self.view.window().fieldEditor_forObject_(YES, self.view) - text_field.setSelectedRange_(NSMakeRange(len(self.get_text()), 0)) - - def viewport_created(self): - SizedControl.viewport_created(self) - self.notifications.connect(self.on_changed, 'NSControlTextDidChangeNotification') - self.notifications.connect(self.on_end_editing, - 'NSControlTextDidEndEditingNotification') - - def remove_viewport(self): - SizedControl.remove_viewport(self) - self.notifications.disconnect() - - def baseline(self): - return -self.view.font().descender() + 2 - - def on_changed(self, notification): - self.emit('changed') - - def on_end_editing(self, notification): - self.emit('focus-out') - - def calc_size_request(self): - size = self.sizer_cell.cellSize() - return size.width, size.height - - def set_text(self, text): - self.view.setStringValue_(text) - self.emit('changed') - - def get_text(self): - return self.view.stringValue() - - def set_width(self, chars): - self.sizer_cell.setStringValue_('X' * chars) - self.invalidate_size_request() - - def set_activates_default(self, setting): - pass - - def enable(self): - SizedControl.enable(self) - self.view.setEnabled_(True) - - def disable(self): - SizedControl.disable(self) - self.view.setEnabled_(False) - -class MiroTextField(NSTextField): - def textDidEndEditing_(self, notification): - wrappermap.wrapper(self).emit('activate') - return NSTextField.textDidEndEditing_(self, notification) - -class TextEntry(BaseTextEntry): - def make_view(self): - return MiroTextField.alloc().init() - -class NumberEntry(BaseTextEntry): - def make_view(self): - return MiroTextField.alloc().init() - - def set_max_length(self, length): - # TODO - pass - - def _filter_value(self): - """Discard any non-numeric characters""" - digits = ''.join(x for x in self.view.stringValue() if x.isdigit()) - self.view.setStringValue_(digits) - - def on_changed(self, notification): - # overriding on_changed rather than connecting to it ensures that we - # filter the value before anything else connected to the signal sees it - self._filter_value() - BaseTextEntry.on_changed(self, notification) - - def get_text(self): - # handles get_text between when text is entered and when on_changed - # filters it, in case that's possible - self._filter_value() - return BaseTextEntry.get_text(self) - -class MiroSecureTextField(NSSecureTextField): - def textDidEndEditing_(self, notification): - wrappermap.wrapper(self).emit('activate') - return NSSecureTextField.textDidEndEditing_(self, notification) - -class SecureTextEntry(BaseTextEntry): - def make_view(self): - return MiroSecureTextField.alloc().init() - -class MultilineTextEntry(Widget): - def __init__(self, initial_text=None): - Widget.__init__(self) - if initial_text is None: - initial_text = "" - self.view = NSTextView.alloc().initWithFrame_(NSRect((0,0),(50,50))) - self.view.setMaxSize_((1.0e7, 1.0e7)) - self.view.setHorizontallyResizable_(NO) - self.view.setVerticallyResizable_(YES) - self.notifications = NotificationForwarder.create(self.view) - self.create_signal('changed') - self.create_signal('focus-out') - if initial_text is not None: - self.set_text(initial_text) - self.set_size(widgetconst.SIZE_NORMAL) - - def set_size(self, size): - if size == widgetconst.SIZE_NORMAL: - font = NSFont.systemFontOfSize_(NSFont.systemFontSize()) - elif size == widgetconst.SIZE_SMALL: - self.view.cell().setControlSize_(NSSmallControlSize) - else: - raise ValueError("Unknown size: %s" % size) - self.view.setFont_(font) - - def viewport_created(self): - Widget.viewport_created(self) - self.notifications.connect(self.on_changed, 'NSTextDidChangeNotification') - self.notifications.connect(self.on_end_editing, - 'NSControlTextDidEndEditingNotification') - self.invalidate_size_request() - - def remove_viewport(self): - Widget.remove_viewport(self) - self.notifications.disconnect() - - def focus(self): - if self.view.window() is not None: - self.view.window().makeFirstResponder_(self.view) - - def set_text(self, text): - self.view.setString_(text) - self.invalidate_size_request() - - def get_text(self): - return self.view.string() - - def on_changed(self, notification): - self.invalidate_size_request() - self.emit("changed") - - def on_end_editing(self, notification): - self.emit("focus-out") - - def calc_size_request(self): - layout_manager = self.view.layoutManager() - text_container = self.view.textContainer() - # The next line is there just to force cocoa to layout the text - layout_manager.glyphRangeForTextContainer_(text_container) - rect = layout_manager.usedRectForTextContainer_(text_container) - return rect.size.width, rect.size.height - - def set_editable(self, editable): - if editable: - self.view.setEditable_(YES) - else: - self.view.setEditable_(NO) - - -class MiroButton(NSButton): - - def initWithSignal_(self, signal): - self = super(MiroButton, self).init() - self.signal = signal - return self - - def sendAction_to_(self, action, to): - # We override the Cocoa machinery here and just send it to our wrapper - # widget. - wrappermap.wrapper(self).emit(self.signal) - return YES - -class Checkbox(SizedControl): - """See https://develop.participatoryculture.org/index.php/WidgetAPI for a description of the API for this class.""" - def __init__(self, text="", bold=False, color=None): - SizedControl.__init__(self) - self.create_signal('toggled') - self.view = MiroButton.alloc().initWithSignal_('toggled') - self.view.setButtonType_(NSSwitchButton) - self.bold = bold - self.title = text - self.font_size = NSFont.systemFontSize() - self.color = self.make_color(color) - self._set_title() - - def set_size(self, size): - SizedControl.set_size(self, size) - self._set_title() - - def _set_title(self): - if self.color is None: - self.view.setTitle_(self.title) - else: - attributes = { - NSForegroundColorAttributeName: self.color, - NSFontAttributeName: NSFont.systemFontOfSize_(self.font_size) - } - string = NSAttributedString.alloc().initWithString_attributes_( - self.title, attributes) - self.view.setAttributedTitle_(string) - - def calc_size_request(self): - if self.manual_size_request: - width, height = self.manual_size_request - if width == -1: - width = 10000 - if height == -1: - height = 10000 - size = self.view.cell().cellSizeForBounds_( - NSRect((0, 0), (width, height))) - else: - size = self.view.cell().cellSize() - return (size.width, size.height) - - def baseline(self): - return -self.view.font().descender() + 1 - - def get_checked(self): - return self.view.state() == NSOnState - - def set_checked(self, value): - if value: - self.view.setState_(NSOnState) - else: - self.view.setState_(NSOffState) - - def enable(self): - SizedControl.enable(self) - self.view.setEnabled_(True) - - def disable(self): - SizedControl.disable(self) - self.view.setEnabled_(False) - - def get_text_padding(self): - """ - Returns the amount of space the checkbox takes up before the label. - """ - # XXX FIXME - return 18 - -class Button(SizedControl): - """See https://develop.participatoryculture.org/index.php/WidgetAPI for a description of the API for this class.""" - def __init__(self, label, style='normal', width=0): - SizedControl.__init__(self) - self.color = None - self.title = label - self.create_signal('clicked') - self.view = MiroButton.alloc().initWithSignal_('clicked') - self.view.setButtonType_(NSMomentaryPushInButton) - self._set_title() - self.setup_style(style) - self.min_width = width - - def set_text(self, label): - self.title = label - self._set_title() - - def set_color(self, color): - self.color = self.make_color(color) - self._set_title() - - def _set_title(self): - if self.color is None: - self.view.setTitle_(self.title) - else: - attributes = { - NSForegroundColorAttributeName: self.color, - NSFontAttributeName: self.view.font() - } - string = NSAttributedString.alloc().initWithString_attributes_( - self.title, attributes) - self.view.setAttributedTitle_(string) - - def setup_style(self, style): - if style == 'normal': - self.view.setBezelStyle_(NSRoundedBezelStyle) - self.pad_height = 0 - self.pad_width = 10 - self.min_width = 112 - elif style == 'smooth': - self.view.setBezelStyle_(NSRoundRectBezelStyle) - self.pad_width = 0 - self.pad_height = 4 - self.paragraph_style = NSMutableParagraphStyle.alloc().init() - self.paragraph_style.setAlignment_(NSCenterTextAlignment) - - def make_default(self): - self.view.setKeyEquivalent_("\r") - - def calc_size_request(self): - size = self.view.cell().cellSize() - width = max(self.min_width, size.width + self.pad_width) - height = size.height + self.pad_height - return width, height - - def baseline(self): - return -self.view.font().descender() + 10 + self.pad_height - - def enable(self): - SizedControl.enable(self) - self.view.setEnabled_(True) - - def disable(self): - SizedControl.disable(self) - self.view.setEnabled_(False) - -class MiroPopupButton(NSPopUpButton): - - def init(self): - self = super(MiroPopupButton, self).init() - self.setTarget_(self) - self.setAction_('handleChange:') - return self - - def handleChange_(self, sender): - wrappermap.wrapper(self).emit('changed', self.indexOfSelectedItem()) - -class OptionMenu(SizedControl): - def __init__(self, options): - SizedControl.__init__(self) - self.create_signal('changed') - self.view = MiroPopupButton.alloc().init() - self.options = options - for option, value in options: - self.view.addItemWithTitle_(option) - - def baseline(self): - if self.view.cell().controlSize() == NSRegularControlSize: - return -self.view.font().descender() + 6 - else: - return -self.view.font().descender() + 5 - - def calc_size_request(self): - return self.view.cell().cellSize() - - def set_selected(self, index): - self.view.selectItemAtIndex_(index) - - def get_selected(self): - return self.view.indexOfSelectedItem() - - def enable(self): - SizedControl.enable(self) - self.view.setEnabled_(True) - - def disable(self): - SizedControl.disable(self) - self.view.setEnabled_(False) - - def set_width(self, width): - # TODO - pass - -class RadioButtonGroup: - def __init__(self): - self._buttons = [] - - def handle_click(self, widget): - self.set_selected(widget) - - def add_button(self, button): - self._buttons.append(button) - button.connect('clicked', self.handle_click) - if len(self._buttons) == 1: - button.view.setState_(NSOnState) - else: - button.view.setState_(NSOffState) - - def get_buttons(self): - return self._buttons - - def get_selected(self): - for mem in self._buttons: - if mem.get_selected(): - return mem - - def set_selected(self, button): - for mem in self._buttons: - if button is mem: - mem.view.setState_(NSOnState) - else: - mem.view.setState_(NSOffState) - -class RadioButton(SizedControl): - def __init__(self, label, group=None, bold=False, color=None): - SizedControl.__init__(self) - self.create_signal('clicked') - self.view = MiroButton.alloc().initWithSignal_('clicked') - self.view.setButtonType_(NSRadioButton) - self.color = self.make_color(color) - self.title = label - self.bold = bold - self.font_size = NSFont.systemFontSize() - self._set_title() - - if group is not None: - self.group = group - else: - self.group = RadioButtonGroup() - - self.group.add_button(self) - - def set_size(self, size): - SizedControl.set_size(self, size) - self._set_title() - - def _set_title(self): - if self.color is None: - self.view.setTitle_(self.title) - else: - attributes = { - NSForegroundColorAttributeName: self.color, - NSFontAttributeName: NSFont.systemFontOfSize_(self.font_size) - } - string = NSAttributedString.alloc().initWithString_attributes_( - self.title, attributes) - self.view.setAttributedTitle_(string) - - def calc_size_request(self): - size = self.view.cell().cellSize() - return (size.width, size.height) - - def baseline(self): - -self.view.font().descender() + 2 - - def get_group(self): - return self.group - - def get_selected(self): - return self.view.state() == NSOnState - - def set_selected(self): - self.group.set_selected(self) - - def enable(self): - SizedControl.enable(self) - self.view.setEnabled_(True) - - def disable(self): - SizedControl.disable(self) - self.view.setEnabled_(False) |