From 14738704ede6dfa6ac79f362a9c1f7f40f470cdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Eduardo?= Date: Mon, 11 Sep 2017 17:47:17 -0500 Subject: rename mvc at lvc --- mvc/widgets/osx/layout.py | 748 ---------------------------------------------- 1 file changed, 748 deletions(-) delete mode 100644 mvc/widgets/osx/layout.py (limited to 'mvc/widgets/osx/layout.py') diff --git a/mvc/widgets/osx/layout.py b/mvc/widgets/osx/layout.py deleted file mode 100644 index 0238975..0000000 --- a/mvc/widgets/osx/layout.py +++ /dev/null @@ -1,748 +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. - -""".layout -- Widgets that handle laying out other -widgets. - -We basically follow GTK's packing model. Widgets are packed into vboxes, -hboxes or other container widgets. The child widgets request a minimum size, -and the container widgets allocate space for their children. Widgets may get -more size then they requested in which case they have to deal with it. In -rare cases, widgets may get less size then they requested in which case they -should just make sure they don't throw an exception or segfault. - -Check out the GTK tutorial for more info. -""" - -import itertools - -from AppKit import * -from Foundation import * -from objc import YES, NO, nil, signature, loadBundle - -import tableview -import wrappermap -from .base import Container, Bin, FlippedView -from mvc.utils import Matrix - -# These don't seem to be in pyobjc's AppKit (yet) -NSScrollerKnobStyleDefault = 0 -NSScrollerKnobStyleDark = 1 -NSScrollerKnobStyleLight = 2 - -NSScrollerStyleLegacy = 0 -NSScrollerStyleOverlay = 1 - -def _extra_space_iter(extra_length, count): - """Utility function to allocate extra space left over in containers.""" - if count == 0: - return - extra_space, leftover = divmod(extra_length, count) - while leftover >= 1: - yield extra_space + 1 - leftover -= 1 - yield extra_space + leftover - while True: - yield extra_space - -class BoxPacking: - """Utility class to store how we are packing a single widget.""" - - def __init__(self, widget, expand, padding): - self.widget = widget - self.expand = expand - self.padding = padding - -class Box(Container): - """Base class for HBox and VBox. """ - CREATES_VIEW = False - - def __init__(self, spacing=0): - self.spacing = spacing - Container.__init__(self) - self.packing_start = [] - self.packing_end = [] - self.expand_count = 0 - - def packing_both(self): - return itertools.chain(self.packing_start, self.packing_end) - - def get_children(self): - for packing in self.packing_both(): - yield packing.widget - children = property(get_children) - - # Internally Boxes use a (length, breadth) coordinate system. length and - # breadth will be either x or y depending on which way the box is - # oriented. The subclasses must provide methods to translate between the - # 2 coordinate systems. - - def translate_size(self, size): - """Translate a (width, height) tulple to (length, breadth).""" - raise NotImplementedError() - - def untranslate_size(self, size): - """Reverse the work of translate_size.""" - raise NotImplementedError() - - def make_child_rect(self, position, length): - """Create a rect to position a child with.""" - raise NotImplementedError() - - def pack_start(self, child, expand=False, padding=0): - self.packing_start.append(BoxPacking(child, expand, padding)) - if expand: - self.expand_count += 1 - self.child_added(child) - - def pack_end(self, child, expand=False, padding=0): - self.packing_end.append(BoxPacking(child, expand, padding)) - if expand: - self.expand_count += 1 - self.child_added(child) - - def _remove_from_packing(self, child): - for i in xrange(len(self.packing_start)): - if self.packing_start[i].widget is child: - return self.packing_start.pop(i) - for i in xrange(len(self.packing_end)): - if self.packing_end[i].widget is child: - return self.packing_end.pop(i) - raise LookupError("%s not found" % child) - - def remove(self, child): - packing = self._remove_from_packing(child) - if packing.expand: - self.expand_count -= 1 - self.child_removed(child) - - def translate_widget_size(self, widget): - return self.translate_size(widget.get_size_request()) - - def calc_size_request(self): - length = breadth = 0 - for packing in self.packing_both(): - child_length, child_breadth = \ - self.translate_widget_size(packing.widget) - length += child_length - if packing.padding: - length += packing.padding * 2 # Need to pad on both sides - breadth = max(breadth, child_breadth) - spaces = max(0, len(self.packing_start) + len(self.packing_end) - 1) - length += spaces * self.spacing - return self.untranslate_size((length, breadth)) - - def place_children(self): - request_length, request_breadth = self.translate_widget_size(self) - ps = self.viewport.placement.size - total_length, dummy = self.translate_size((ps.width, ps.height)) - total_extra_space = total_length - request_length - extra_space_iter = _extra_space_iter(total_extra_space, - self.expand_count) - start_end = self._place_packing_list(self.packing_start, - extra_space_iter, 0) - if self.expand_count == 0 and total_extra_space > 0: - # account for empty space after the end of pack_start list and - # before the pack_end list. - self.draw_empty_space(start_end, total_extra_space) - start_end += total_extra_space - self._place_packing_list(reversed(self.packing_end), extra_space_iter, - start_end) - - def draw_empty_space(self, start, length): - empty_rect = self.make_child_rect(start, length) - my_view = self.viewport.view - opaque_view = my_view.opaqueAncestor() - if opaque_view is not None: - empty_rect2 = opaque_view.convertRect_fromView_(empty_rect, my_view) - opaque_view.setNeedsDisplayInRect_(empty_rect2) - - def _place_packing_list(self, packing_list, extra_space_iter, position): - for packing in packing_list: - child_length, child_breadth = \ - self.translate_widget_size(packing.widget) - if packing.expand: - child_length += extra_space_iter.next() - if packing.padding: # space before - self.draw_empty_space(position, packing.padding) - position += packing.padding - child_rect = self.make_child_rect(position, child_length) - if packing.padding: # space after - self.draw_empty_space(position, packing.padding) - position += packing.padding - packing.widget.place(child_rect, self.viewport.view) - position += child_length - if self.spacing > 0: - self.draw_empty_space(position, self.spacing) - position += self.spacing - return position - - def enable(self): - Container.enable(self) - for mem in self.children: - mem.enable() - - def disable(self): - Container.disable(self) - for mem in self.children: - mem.disable() - -class VBox(Box): - """See https://develop.participatoryculture.org/index.php/WidgetAPI for a description of the API for this class.""" - def translate_size(self, size): - return (size[1], size[0]) - - def untranslate_size(self, size): - return (size[1], size[0]) - - def make_child_rect(self, position, length): - placement = self.viewport.placement - return NSMakeRect(placement.origin.x, placement.origin.y + position, - placement.size.width, length) - -class HBox(Box): - """See https://develop.participatoryculture.org/index.php/WidgetAPI for a description of the API for this class.""" - def translate_size(self, size): - return (size[0], size[1]) - - def untranslate_size(self, size): - return (size[0], size[1]) - - def make_child_rect(self, position, length): - placement = self.viewport.placement - return NSMakeRect(placement.origin.x + position, placement.origin.y, - length, placement.size.height) - -class Alignment(Bin): - """See https://develop.participatoryculture.org/index.php/WidgetAPI for a description of the API for this class.""" - CREATES_VIEW = False - - def __init__(self, xalign=0.0, yalign=0.0, xscale=0.0, yscale=0.0, - top_pad=0, bottom_pad=0, left_pad=0, right_pad=0): - Bin.__init__(self) - self.xalign = xalign - self.yalign = yalign - self.xscale = xscale - self.yscale = yscale - self.top_pad = top_pad - self.bottom_pad = bottom_pad - self.left_pad = left_pad - self.right_pad = right_pad - if self.child is not None: - self.place_children() - - def set(self, xalign=0.0, yalign=0.0, xscale=0.0, yscale=0.0): - self.xalign = xalign - self.yalign = yalign - self.xscale = xscale - self.yscale = yscale - if self.child is not None: - self.place_children() - - def set_padding(self, top_pad=0, bottom_pad=0, left_pad=0, right_pad=0): - self.top_pad = top_pad - self.bottom_pad = bottom_pad - self.left_pad = left_pad - self.right_pad = right_pad - if self.child is not None and self.viewport is not None: - self.place_children() - - def vertical_pad(self): - return self.top_pad + self.bottom_pad - - def horizontal_pad(self): - return self.left_pad + self.right_pad - - def calc_size_request(self): - if self.child: - child_width, child_height = self.child.get_size_request() - return (child_width + self.horizontal_pad(), - child_height + self.vertical_pad()) - else: - return (0, 0) - - def calc_size(self, requested, total, scale): - extra_width = max(0, total - requested) - return requested + int(round(extra_width * scale)) - - def calc_position(self, size, total, align): - return int(round((total - size) * align)) - - def place_children(self): - if self.child is None: - return - - total_width = self.viewport.placement.size.width - total_height = self.viewport.placement.size.height - total_width -= self.horizontal_pad() - total_height -= self.vertical_pad() - request_width, request_height = self.child.get_size_request() - - child_width = self.calc_size(request_width, total_width, self.xscale) - child_height = self.calc_size(request_height, total_height, self.yscale) - child_x = self.calc_position(child_width, total_width, self.xalign) - child_y = self.calc_position(child_height, total_height, self.yalign) - child_x += self.left_pad - child_y += self.top_pad - - my_origin = self.viewport.area().origin - child_rect = NSMakeRect(my_origin.x + child_x, my_origin.y + child_y, child_width, child_height) - self.child.place(child_rect, self.viewport.view) - # Make sure the space not taken up by our child is redrawn. - self.viewport.queue_redraw() - -class DetachedWindowHolder(Alignment): - def __init__(self): - Alignment.__init__(self, bottom_pad=16, xscale=1.0, yscale=1.0) - -class _TablePacking(object): - """Utility class to help with packing Table widgets.""" - def __init__(self, widget, column, row, column_span, row_span): - self.widget = widget - self.column = column - self.row = row - self.column_span = column_span - self.row_span = row_span - - def column_indexes(self): - return range(self.column, self.column + self.column_span) - - def row_indexes(self): - return range(self.row, self.row + self.row_span) - -class Table(Container): - """See https://develop.participatoryculture.org/index.php/WidgetAPI for a description of the API for this class.""" - CREATES_VIEW = False - - def __init__(self, columns, rows): - Container.__init__(self) - self._cells = Matrix(columns, rows) - self._children = [] # List of _TablePacking objects - self._children_sorted = True - self.rows = rows - self.columns = columns - self.row_spacing = self.column_spacing = 0 - - def _ensure_children_sorted(self): - if not self._children_sorted: - def cell_area(table_packing): - return table_packing.column_span * table_packing.row_span - self._children.sort(key=cell_area) - self._children_sorted = True - - def get_children(self): - return [cell.widget for cell in self._children] - children = property(get_children) - - def calc_size_request(self): - self._ensure_children_sorted() - self._calc_dimensions() - return self.total_width, self.total_height - - def _calc_dimensions(self): - self.column_widths = [0] * self.columns - self.row_heights = [0] * self.rows - - for tp in self._children: - child_width, child_height = tp.widget.get_size_request() - # recalc the width of the child's columns - self._recalc_dimension(child_width, self.column_widths, - tp.column_indexes()) - # recalc the height of the child's rows - self._recalc_dimension(child_height, self.row_heights, - tp.row_indexes()) - - self.total_width = (self.column_spacing * (self.columns - 1) + - sum(self.column_widths)) - self.total_height = (self.row_spacing * (self.rows - 1) + - sum(self.row_heights)) - - def _recalc_dimension(self, child_size, size_array, positions): - current_size = sum(size_array[p] for p in positions) - child_size_needed = child_size - current_size - if child_size_needed > 0: - iter = _extra_space_iter(child_size_needed, len(positions)) - for p in positions: - size_array[p] += iter.next() - - def place_children(self): - # This method depepnds on us calling _calc_dimensions() in - # calc_size_request(). Ensure that this happens. - if self.cached_size_request is None: - self.get_size_request() - column_positions = [0] - for width in self.column_widths[:-1]: - column_positions.append(width + column_positions[-1] + self.column_spacing) - row_positions = [0] - for height in self.row_heights[:-1]: - row_positions.append(height + row_positions[-1] + self.row_spacing) - - my_x= self.viewport.placement.origin.x - my_y = self.viewport.placement.origin.y - for tp in self._children: - x = my_x + column_positions[tp.column] - y = my_y + row_positions[tp.row] - width = sum(self.column_widths[i] for i in tp.column_indexes()) - height = sum(self.row_heights[i] for i in tp.row_indexes()) - rect = NSMakeRect(x, y, width, height) - tp.widget.place(rect, self.viewport.view) - - def pack(self, widget, column, row, column_span=1, row_span=1): - tp = _TablePacking(widget, column, row, column_span, row_span) - for c in tp.column_indexes(): - for r in tp.row_indexes(): - if self._cells[c, r]: - raise ValueError("Cell %d x %d is already taken" % (c, r)) - self._cells[column, row] = widget - self._children.append(tp) - self._children_sorted = False - self.child_added(widget) - - def remove(self, child): - for i in xrange(len(self._children)): - if self._children[i].widget is child: - self._children.remove(i) - break - else: - raise ValueError("%s is not a child of this Table" % child) - self._cells.remove(child) - self.child_removed(widget) - - def set_column_spacing(self, spacing): - self.column_spacing = spacing - self.invalidate_size_request() - - def set_row_spacing(self, spacing): - self.row_spacing = spacing - self.invalidate_size_request() - - def enable(self, row=None, column=None): - Container.enable(self) - if row != None and column != None: - if self._cells[column, row]: - self._cells[column, row].enable() - elif row != None: - for mem in self._cells.row(row): - if mem: mem.enable() - elif column != None: - for mem in self._cells.column(column): - if mem: mem.enable() - else: - for mem in self._cells: - if mem: mem.enable() - - def disable(self, row=None, column=None): - Container.disable(self) - if row != None and column != None: - if self._cells[column, row]: - self._cells[column, row].disable() - elif row != None: - for mem in self._cells.row(row): - if mem: mem.disable() - elif column != None: - for mem in self._cells.column(column): - if mem: mem.disable() - else: - for mem in self._cells: - if mem: mem.disable() - -class MiroScrollView(NSScrollView): - def tile(self): - NSScrollView.tile(self) - # tile is called when we need to layout our child view and scrollers. - # This probably means that we've either hidden or shown a scrollbar so - # call invalidate_size_request to ensure that things get re-layed out - # correctly. (#see 13842) - wrapper = wrappermap.wrapper(self) - if wrapper is not None: - wrapper.invalidate_size_request() - -class Scroller(Bin): - """See https://develop.participatoryculture.org/index.php/WidgetAPI for a description of the API for this class.""" - def __init__(self, horizontal, vertical): - Bin.__init__(self) - self.view = MiroScrollView.alloc().init() - self.view.setAutohidesScrollers_(YES) - self.view.setHasHorizontalScroller_(horizontal) - self.view.setHasVerticalScroller_(vertical) - self.document_view = FlippedView.alloc().init() - self.view.setDocumentView_(self.document_view) - - def prepare_for_dark_content(self): - try: - self.view.setScrollerKnobStyle_(NSScrollerKnobStyleLight) - except AttributeError: - # This only works on 10.7 and abvoe - pass - - def set_has_borders(self, has_border): - self.view.setBorderType_(NSBezelBorder) - - def viewport_repositioned(self): - # If the window is resized, this translates to a - # viewport_repositioned() event. Instead of calling - # place_children() one, which is what our suporclass does, we need - # some extra logic here. place the chilren to work out if we need a - # scrollbar, then get the new size, then replace the children (which - # now takes into account of scrollbar size.) - super(Scroller, self).viewport_repositioned() - self.cached_size_request = self.calc_size_request() - self.place_children() - - def set_background_color(self, color): - self.view.setBackgroundColor_(self.make_color(color)) - - def add(self, child): - child.parent_is_scroller = True - Bin.add(self, child) - - def remove(self): - child.parent_is_scroller = False - Bin.remove(self) - - def children_changed(self): - # since our size isn't dependent on our children, don't call - # invalidate_size_request() here. Just call place_children() so that - # they get positioned correctly in the document view. - # - # XXX dodgy - why are we laying out the children twice? When the - # children change, the scroller could appear/disappear. But you have - # no idea if that's going to happen without knowing how big your - # children are. So we lay it out, get the size, then, place the - # children again. This makes sure that the right side of the children - # are redrawn. There's got to be a better way?? - self.place_children() - self.cached_size_request = self.calc_size_request() - self.place_children() - - def calc_size_request(self): - if self.child: - width = height = 0 - try: - legacy = self.view.scrollerStyle() == NSScrollerStyleLegacy - except AttributeError: - legacy = True - if not self.view.hasHorizontalScroller(): - width = self.child.get_size_request()[0] - if not self.view.hasVerticalScroller(): - height = self.child.get_size_request()[1] - # Add a little room for the scrollbars (if necessary) - if legacy and self.view.hasHorizontalScroller(): - height += NSScroller.scrollerWidth() - if legacy and self.view.hasVerticalScroller(): - width += NSScroller.scrollerWidth() - return width, height - else: - return 0, 0 - - def place_children(self): - if self.child is not None: - scroll_view_size = self.view.contentView().frame().size - child_width, child_height = self.child.get_size_request() - child_width = max(child_width, scroll_view_size.width) - child_height = max(child_height, scroll_view_size.height) - frame = NSRect(NSPoint(0,0), NSSize(child_width, child_height)) - if isinstance(self.child, tableview.TableView) and self.child.is_showing_headers(): - # Hack to allow the content of a table view to scroll, but not - # the headers - self.child.place(frame, self.document_view) - if self.view.documentView() is not self.child.tableview: - self.view.setDocumentView_(self.child.tableview) - else: - self.child.place(frame, self.document_view) - self.document_view.setFrame_(frame) - self.document_view.setNeedsDisplay_(YES) - self.view.setNeedsDisplay_(YES) - self.child.emit('place-in-scroller') - -class ExpanderView(FlippedView): - def init(self): - self = super(ExpanderView, self).init() - self.label_rect = None - self.content_view = None - self.button = NSButton.alloc().init() - self.button.setState_(NSOffState) - self.button.setTitle_("") - self.button.setBezelStyle_(NSDisclosureBezelStyle) - self.button.setButtonType_(NSPushOnPushOffButton) - self.button.sizeToFit() - self.addSubview_(self.button) - self.button.setTarget_(self) - self.button.setAction_('buttonChanged:') - self.content_view = FlippedView.alloc().init() - return self - - def buttonChanged_(self, button): - if button.state() == NSOnState: - self.addSubview_(self.content_view) - else: - self.content_view.removeFromSuperview() - if self.window(): - wrappermap.wrapper(self).invalidate_size_request() - - def mouseDown_(self, event): - pass # Just need to respond to the selector so we get mouseUp_ - - def mouseUp_(self, event): - position = event.locationInWindow() - window_label_rect = self.convertRect_toView_(self.label_rect, None) - if NSPointInRect(position, window_label_rect): - self.button.setNextState() - self.buttonChanged_(self.button) - -class Expander(Bin): - BUTTON_PAD_TOP = 2 - BUTTON_PAD_LEFT = 4 - LABEL_SPACING = 4 - - def __init__(self, child): - Bin.__init__(self) - if child: - self.add(child) - self.label = None - self.spacing = 0 - self.view = ExpanderView.alloc().init() - self.button = self.view.button - self.button.setFrameOrigin_(NSPoint(self.BUTTON_PAD_LEFT, - self.BUTTON_PAD_TOP)) - self.content_view = self.view.content_view - - def remove_viewport(self): - Bin.remove_viewport(self) - if self.label is not None: - self.label.remove_viewport() - - def set_spacing(self, spacing): - self.spacing = spacing - - def set_label(self, widget): - if self.label is not None: - self.label.remove_viewport() - self.label = widget - self.children_changed() - - def set_expanded(self, expanded): - if expanded: - self.button.setState_(NSOnState) - else: - self.button.setState_(NSOffState) - self.view.buttonChanged_(self.button) - - def calc_top_size(self): - width = self.button.bounds().size.width - height = self.button.bounds().size.height - if self.label is not None: - label_width, label_height = self.label.get_size_request() - width += self.LABEL_SPACING + label_width - height = max(height, label_height) - width += self.BUTTON_PAD_LEFT - height += self.BUTTON_PAD_TOP - return width, height - - def calc_size_request(self): - width, height = self.calc_top_size() - if self.child is not None and self.button.state() == NSOnState: - child_width, child_height = self.child.get_size_request() - width = max(width, child_width) - height += self.spacing + child_height - return width, height - - def place_children(self): - top_width, top_height = self.calc_top_size() - if self.label: - label_width, label_height = self.label.get_size_request() - button_width = self.button.bounds().size.width - label_x = self.BUTTON_PAD_LEFT + button_width + self.LABEL_SPACING - label_rect = NSMakeRect(label_x, self.BUTTON_PAD_TOP, - label_width, label_height) - self.label.place(label_rect, self.viewport.view) - self.view.label_rect = label_rect - if self.child: - size = self.viewport.area().size - child_rect = NSMakeRect(0, 0, size.width, size.height - - top_height) - self.content_view.setFrame_(NSMakeRect(0, top_height, size.width, - size.height - top_height)) - self.child.place(child_rect, self.content_view) - - -class TabViewDelegate(NSObject): - def tabView_willSelectTabViewItem_(self, tab_view, tab_view_item): - try: - wrapper = wrappermap.wrapper(tab_view) - except KeyError: - pass # The NSTabView hasn't been placed yet, don't worry about it. - else: - wrapper.place_child_with_item(tab_view_item) - -class TabContainer(Container): - def __init__(self): - Container.__init__(self) - self.children = [] - self.item_to_child = {} - self.view = NSTabView.alloc().init() - self.view.setAllowsTruncatedLabels_(NO) - self.delegate = TabViewDelegate.alloc().init() - self.view.setDelegate_(self.delegate) - - def append_tab(self, child_widget, label, image): - item = NSTabViewItem.alloc().init() - item.setLabel_(label) - item.setView_(FlippedView.alloc().init()) - self.view.addTabViewItem_(item) - self.children.append(child_widget) - self.child_added(child_widget) - self.item_to_child[item] = child_widget - - def select_tab(self, index): - self.view.selectTabViewItemAtIndex_(index) - - def place_children(self): - self.place_child_with_item(self.view.selectedTabViewItem()) - - def place_child_with_item(self, tab_view_item): - child = self.item_to_child[tab_view_item] - child_view = tab_view_item.view() - content_rect =self.view.contentRect() - child_view.setFrame_(content_rect) - child.place(child_view.bounds(), child_view) - - def calc_size_request(self): - tab_size = self.view.minimumSize() - # make sure there's enough room for the tabs, plus a little extra - # space to make things look good - max_width = tab_size.width + 60 - max_height = 0 - for child in self.children: - width, height = child.get_size_request() - max_width = max(width, max_width) - max_height = max(height, max_height) - max_height += tab_size.height - - return max_width, max_height -- cgit v1.2.3