Ejemplo n.º 1
0
class Task(Properties):
    """A Task represents an action to be performed after a specified
	time interval, either once or repeatedly.
	
	Constructor:
		Task(proc, interval, repeat = False, start = True)
			Creates a task to call the given proc, which should be
			a callable object of no arguments, after the specified
			interval in seconds from the time the task is scheduled.
			If repeat is true, the task will be automatically re-scheduled
			each time the proc is called. If start is true, the task will be 
			automatically scheduled upon creation; otherwise the start()
			method must be called to schedule the task.
	"""

    interval = overridable_property('interval',
                                    "Time in seconds between firings")
    repeat = overridable_property('repeat',
                                  "Whether to fire repeatedly or once only")

    def __del__(self):
        self.stop()

    scheduled = overridable_property(
        'scheduled', "True if the task is currently scheduled. Read-only.")

    def start(self):
        """Schedule the task if it is not already scheduled."""
        raise NotImplementedError("GUI.Task.start")

    def stop(self):
        """Unschedules the task if it is currently scheduled."""
        raise NotImplementedError("GUI.Task.stop")
Ejemplo n.º 2
0
class TabView(Container):
    """ A tabview."""

    selected_index = overridable_property('selected_index',
        "selected tab item")
    items = overridable_property('items', "tab view items")

    def __init__(self, **kwargs):
        Container.__init__(self, **kwargs)

    def add_item(self, v, title = None):
        self.add(v)

    def remove_item(self, v):
        self.remove(v)

    def insert_item_at(self, v, i, title = None):
        self._contents.insert(i, v)

    def remove_item_at(self, i):
        self._contents.remove(self._contents[i])

    def tab_changed(self, tab_index):
        pass

    def get_items(self):
        return self._contents

    def get_selected_index(self):
        raise NotImplementedError

    def set_selected_index(self, index):
        raise NotImplementedError
Ejemplo n.º 3
0
class TextEditor(Component, EditCmdHandler, Printable):
    """A component for editing substantial amounts of text. The text is
    kept internally to the component and cannot be shared between views."""

    text = overridable_property('text', "The contents as a string.")
    text_length = overridable_property('text_length',
                                       "Number of characters in the text.")
    selection = overridable_property('selection', "Range of text selected.")
    font = overridable_property('font')
    tab_spacing = overridable_property('tab_spacing',
                                       "Distance between tab stops")

    def setup_menus(self, m):
        Component.setup_menus(self, m)
        EditCmdHandler.setup_menus(self, m)
        Printable.setup_menus(self, m)

    def key_down(self, e):
        if e.key == 'enter':
            self.pass_to_next_handler('key_down', e)
        else:
            Component.key_down(self, e)

    def print_view(self, page_setup):
        from .TextEditorPrinting import TextEditorPrintView
        view = TextEditorPrintView(self, page_setup)
        view.print_view(page_setup)
Ejemplo n.º 4
0
class ListButton(Control, Action):
	"""A button that displays a value and provides a pop-up or
	pull-down list of choices."""

	titles = overridable_property('titles',
		"List of item title strings")
	
	values = overridable_property('values',
		"List of values corresponding to tiles, or None to use item index as value")
	
	def _extract_initial_items(self, kwds):
		titles = kwds.pop('titles', None) or []
		values = kwds.pop('values', None)
		return titles, values

	def get_titles(self):
		return self._titles
	
	def set_titles(self, x):
		self._titles = x
		self._update_items()
	
	def get_values(self):
		return self._values
	
	def set_values(self, x):
		self._values = x
	
	def get_value(self):
		i = self._get_selected_index()
		if i >= 0:
			values = self.values
			if values:
				return values[i]
			else:
				return i

	def set_value(self, value):
		values = self.values
		if values:
			try:
				i = values.index(value)
			except ValueError:
				i = -1
		else:
			if value is None:
				i = -1
			else:
				i = value
		self._set_selected_index(i)

	def do_action(self):
		try:
			Action.do_action(self)
		except:
			application().report_error()
Ejemplo n.º 5
0
class Control(Component):
    """Abstract base class for components such as buttons, check
	boxes and text entry boxes."""

    title = overridable_property('title', "Title of the control.")
    value = overridable_property('value', "Value of the control.")
    enabled = overridable_property('enabled',
                                   "True if user can manipulate the control.")
    font = overridable_property('font')
    color = overridable_property('color')
    just = overridable_property(
        'just', "Justification ('left', 'center' or 'right').")
    lines = overridable_property(
        'lines',
        "Height of the control measured in lines of the current font.")
    tab_stop = overridable_property(
        'tab_stop', "Whether tab key can navigate into this control.")
    editable = overridable_property(
        'editable',
        "Whether the value of the control can be changed by the user.")

    _vertical_padding = 0  # Extra height to add when setting 'lines' property
    _default_tab_stop = True
    _user_tab_stop_override = True
    _editable = True

    def __init__(self, font=None, lines=None, **kwds):
        Component.__init__(self, **kwds)
        #  If font and lines are both specified, must set font first.
        if font:
            self.font = font
        if lines is not None:
            self.lines = lines

    def get_lines(self):
        return int(
            round((self.height - self._vertical_padding) /
                  self.font.line_height))

    def set_lines(self, num_lines):
        self.height = self._calc_height(self.font, num_lines)

    def _calc_height(self, font, num_lines=1):
        return num_lines * font.line_height + self._vertical_padding

    def _is_targetable(self):
        return self.enabled

    def get_editable(self):
        return self._editable

    def set_editable(self, x):
        self._editable = x
Ejemplo n.º 6
0
class Picture(View):

    image = overridable_property('image', "The image to display")

    _image = None

    def __init__(self, image=None, file=None, **kwds):
        if file:
            from Images import Image
            image = Image(file)
        View.__init__(self, **kwds)
        if image:
            self.size = image.size
            self._image = image

    def get_image(self):
        return self._image

    def set_image(self, x):
        self._image = x
        self.invalidate()

    def draw(self, canvas, rect):
        image = self._image
        if image:
            w, h = self.size
            image.draw(canvas, image.bounds, (0, 0, w, h))
Ejemplo n.º 7
0
class GLContext(object):
    """Abstract base class for objects having an OpenGL context."""
    #
    #  _share_group  ShareGroup
    #

    share_group = overridable_property(
        'share_group',
        "ShareGroup to which this context should belong, or None.")

    def __init__(self, share_group):
        if not share_group:
            share_group = ShareGroup()
        self._share_group = share_group
        if share_group:
            share_group._add(self)

    def destroy(self):
        pass

    def init_context(self):
        """This method is called once after the associated OpenGL context
        is created. When called, this object's OpenGL context is the current
        context and the viewport is set to (0, 0, width, height). This method
        may be used to establish any desired initial OpenGL state."""
        pass

    def get_share_group(self):
        return self._share_group

    def _get_shared_context(self):
        """Return another arbitrarily-chosen member of the share group of this
        context, or None if this context has no share group or there are no
        other members."""
        return self._share_group._some_member(exclude=self)

    def with_context(self, proc, flush=False):
        """The proc should be a callable object of no arguments. Calls
        the proc with the associated OpenGL context as the current context.
        If flush is true, after calling proc, a glFlush followed by a
        buffer flush or swap is performed as appropriate."""
        self._with_context(proc, flush)

    def _with_context(self, proc, flush):
        #  Subclasses override this to implement with_context.
        #  Should call _with_share_group(proc).
        #  Signature can be changed if with_context is overridden to match.
        raise NotImplementedError

    def _with_share_group(self, proc):
        global _current_share_group
        if hasattr(_current_share_group, 'group'):
            old_share_group = _current_share_group.group
        else:
            old_share_group = None
        _current_share_group.group = self._share_group
        try:
            proc()
        finally:
            _current_share_group.group = old_share_group
Ejemplo n.º 8
0
class RadioButton(Control):
    """RadioButtons are used in groups to represent a 1-of-N
	choice. A group of RadioButtons is coordinated by a
	RadioGroup object. The 'group' property indicates the
	RadioGroup to which it belongs, and the 'value' property
	is the value to which the RadioGroup's value is set
	when this RadioButton is selected."""

    group = overridable_property(
        'group', """The RadioGroup to
				which this radio button belongs.""")

    value = overridable_property(
        'value', """The value to which
				the associated radio group's 'value' property should be
				set when this radio button is selected.""")

    _group = None
    _value = None

    #
    #		Properties
    #

    def get_group(self):
        return self._group

    def set_group(self, new_group):
        old_group = self._group
        if new_group is not old_group:
            if old_group:
                old_group._remove_item(self)
            self._group = new_group
            if new_group:
                new_group._add_item(self)

    def get_value(self):
        return self._value

    def set_value(self, new_value):
        old_value = self._value
        if new_value != old_value:
            self._value = new_value
            self._value_changed()

    def _value_changed(self):
        raise NotImplementedError
Ejemplo n.º 9
0
class TableColumn(Properties):
    """Column descriptor for a TableView."""

    column_id = overridable_property('column_id',
                                     "Unique identifier for the column")
    title = overridable_property('title', "Title string for the column")
    width = overridable_property('width', "Width of the column")
    header_font = overridable_property('header_font',
                                       "Font for displaying the header")
    just = overridable_property('just',
                                "Justification of the column ('l', 'c', 'r')")
    editable = overridable_property('editable', "True if column can be edited")
    editor = overridable_property('editor', "Editing control")

    _editable = False

    def __init__(self, title="", width=50, just='left', **kwds):
        if kwds.get('editor'):
            self.editable = True
        Properties.__init__(self, title=title, width=width, just=just, **kwds)

    def get_editable(self):
        return self._editable

    def set_editable(self, x):
        self._editable = x

    def get_editor(self):
        return self._editor

    def set_editor(self, x):
        self._editor = x
Ejemplo n.º 10
0
class Printable(object):
    """Mixin class for components implementing the "Print" command."""

    printable = overridable_property(
        'printable',
        "Whether this component should handle the 'Print' command.")
    page_setup = overridable_property(
        'page_setup', "The PageSetup object to use for printing.")
    print_title = overridable_property('print_title', "Title for print job.")

    _printable = True

    def get_printable(self):
        return self._printable

    def set_printable(self, x):
        self._printable = x

    def get_print_title(self):
        window = self.window
        if window:
            return window.title
        else:
            return ""

    def get_page_setup(self):
        result = None
        model = getattr(self, 'model', None)
        if model:
            result = getattr(model, 'page_setup', None)
        if not result:
            result = application().page_setup
        return result

    def setup_menus(self, m):
        if self.printable:
            m.print_cmd.enabled = True

    def print_cmd(self):
        if self.printable:
            page_setup = self.page_setup
            if page_setup:
                self.print_view(page_setup)
        else:
            self.pass_to_next_handler('print_cmd')
Ejemplo n.º 11
0
class Slider(Control, Action):
    """A control for entering a value by moving a knob along a scale.
	
	Constructor:
		Slider(orient)
			where orient = 'h' for horizontal or 'v' for vertical.
	"""

    _default_length = 100

    value = overridable_property('value', "The current value of the control")
    min_value = overridable_property('min_value',
                                     "Minimum value of the control")
    max_value = overridable_property('max_value',
                                     "Maximum value of the control")
    range = overridable_property('range', "Tuple (min_value, max_value)")
    ticks = overridable_property('ticks', "Number of tick marks")
    discrete = overridable_property('discrete',
                                    "Whether to constrain value to ticks")
    live = overridable_property(
        'live', "Whether to invoke action continuously while dragging")

    def get_range(self):
        return (self.min_value, self.max_value)

    def set_range(self, x):
        self.min_value = x[0]
        self.max_value = x[1]
Ejemplo n.º 12
0
class TextColumn(TableColumn):

    font = overridable_property('font', "Font for displaying the data")
    format = overridable_property('format', "Formatting string")
    parser = overridable_property('parser',
                                  "Function for converting string to value")

    _format = None
    _parser = None
    _editor = None

    def get_format(self):
        return self._format

    def set_format(self, x):
        self._format = x

    def get_parser(self):
        return self._parser

    def set_parser(self, x):
        self._parser = x

    def format_value(self, value):
        """Convert value to string for display, and also for editing with the
        default editor. Default is to perform %-formatting with the format property
        if specified, otherwise apply str to the value."""
        format = self.format
        if format:
            return format % value
        else:
            return str(value)

    def parse_value(self, text):
        """Convert string to value when using the default editor. Default is to
        return the text unchanged."""
        parser = self.parser
        if parser:
            return parser(text)
        else:
            return text
Ejemplo n.º 13
0
class ImageBase(Properties):
    """Abstract base class for Image, Pixmap and GLPixmap."""

    width = overridable_property('width',
                                 "Width of the image in pixels (read only).")
    height = overridable_property(
        'height', "Height of the image in pixels (read only).")
    size = overridable_property('size',
                                "Size of the image in pixels (read only).")
    bounds = overridable_property(
        'bounds', "Bounding rectangle of the image in pixels (read only).")

    def get_size(self):
        return (self.width, self.height)

    def get_bounds(self):
        return rect_sized((0, 0), self.size)

    def draw(self, canvas, src_rect, dst_rect):
        """Draw the part of the image specified by src_rect on the given canvas,
		scaled to fit within dst_rect."""
        raise NotImplementedError
Ejemplo n.º 14
0
class ScrollableBase(object):
    """Mixin for components that can be configured to have scroll bars."""

    scrolling = overridable_property('scrolling',
        "String containing 'h' for horizontal and 'v' for vertical scrolling.")
    
    hscrolling = overridable_property('hscrolling',
        "True if horizontal scrolling is enabled.")
    
    vscrolling = overridable_property('vscrolling',
        "True if vertical scrolling is enabled.")
    
    def get_scrolling(self):
        chars = []
        if self.hscrolling:
            chars.append('h')
        if self.vscrolling:
            chars.append('v')
        return ''.join(chars)
    
    def set_scrolling(self, value):
        self.hscrolling = 'h' in value
        self.vscrolling = 'v' in value
Ejemplo n.º 15
0
class Button(Control, Action):
    """ A pushbutton control."""

    style = overridable_property('style',
                                 "One of 'normal', 'default', 'cancel'")

    def activate(self):
        """Highlight the button momentarily and then perform its action."""
        self.flash()
        self.do_action()

    def flash(self):
        """Highlight the button momentarily as though it had been clicked,
        without performing the action."""
        raise NotImplementedError
Ejemplo n.º 16
0
class CheckBox(Control, Action):
    """A CheckBox is a control used to represent a binary choice."""
    def __init__(self, **kwds):
        Control.__init__(self, **kwds)

    on = overridable_property('on', "Boolean value of the check box.")

    auto_toggle = overridable_property(
        'auto_toggle', """If true,
		the check box's 'on' property will automatically be toggled
		before performing the action, if any.""")

    mixed = overridable_property(
        'mixed', """If true, the check box
		is capable of displaying a mixed state.""")

    _auto_toggle = True
    _mixed = False

    def get_auto_toggle(self):
        return self._auto_toggle

    def set_auto_toggle(self, v):
        self._auto_toggle = v

    def get_mixed(self):
        return self._mixed

    def set_mixed(self, v):
        self._mixed = v

    def get_value(self):
        return self.on

    def set_value(self, x):
        self.on = x
Ejemplo n.º 17
0
class DirRef(Properties):
    """A DirRef is an object representing a directory in the
    file system. Its representation is completely platform
    dependent.

    Constructor:
        DirRef(path = string)
    """

    _path = None

    path = overridable_property('path', "Full pathname of the directory.")

    def __init__(self, path):
        self._path = path

    def get_path(self):
        return self._path

    def __str__(self):
        return "DirRef(%r)" % self.path
Ejemplo n.º 18
0
class Color(object):
    """A drawing color.
    
    Constructors:
        rgb(red, green, blue, alpha = 1.0)
            where red, green, blue, alpha are in the range 0.0 to 1.0
    
    Properties:
        red   -->  float
        green -->  float
        blue  -->  float
        rgb   -->  (red, green, blue)
        rgba  -->  (red, green, blue, alpha)
    """

    red = overridable_property('red', "Red component (0.0 to 1.0)")
    green = overridable_property('green', "Blue component (0.0 to 1.0)")
    blue = overridable_property('blue', "Blue component (0.0 to 1.0)")
    alpha = overridable_property('alpha', "Alpha (opacity) component")
    rgb = overridable_property('rgb',
                               "Tuple of (red, green, blue) (0.0 to 1.0)")
    rgba = overridable_property(
        'rgba', "Tuple of (red, green, blue, alpha) (0.0 to 1.0)")

    def get_alpha(self):
        return 1.0

    def get_rgb(self):
        return (self.red, self.green, self.blue)

    def set_rgb(self, x):
        self.red, self.green, self.blue = x

    def get_rgba(self):
        return (self.red, self.green, self.blue, self.alpha)

    def set_rgba(self, x):
        self.red, self.green, self.blue, self.alpha = x

    def __str__(self):
        return "Color(%g,%g,%g,%g)" % self.rgba
Ejemplo n.º 19
0
class Document(Model, MessageHandler):
    """A Document represents an
	application data structure that can be stored in a file. It
	implements the standard parts of asking the user for file names and
	reading and writing files.

	Each Document can have one or more windows associated with it. When
	the last window belonging to a document is closed, the document itself
	is closed.

	A Document provides support for keeping track of whether it has been
	edited, and asking the user whether to save changes when it is
	closed."""

    #  The following attribute prevents a Document that is the parent
    #  of a Model from being pickled along with that Model.
    pickle_as_parent_model = False

    needs_saving = overridable_property(
        'needs_saving',
        "True if the document has been edited and needs to be saved.")

    file = overridable_property(
        'file',
        """FileRef of the file that the document was read from or last written
		to, or None. Changing this causes update_title to be called.""")

    file_type = overridable_property(
        'file_type',
        """FileType specifying the type of file handled by this document.""")

    title = overridable_property(
        'title',
        """The title of the document. Changing this causes update_title of each
		associated window to be called.""")

    windows = overridable_property(
        'windows',
        "List of windows associated with the document. Do not modify directly."
    )

    page_setup = overridable_property(
        'page_setup', "The PageSetup to be used for printing this document.")

    binary = True  # True if files are to be opened in binary mode

    _file_type = None  # Type of file to create when saving
    _needs_saving = 0  # True if has been edited
    _file = None  # FileRef of associated file, if any
    _title = None  # Title for use in window banners, etc.
    _windows = None  # List of associated windows
    _page_setup = None  # Document-specific PageSetup instance

    #
    #		Initialisation and destruction
    #

    def __init__(self, **kwds):
        self._windows = []
        Model.__init__(self, **kwds)
        application()._add_document(self)

    def destroy(self):
        """Destroy any associated windows, then destroy document contents."""
        #print "Document.destroy:", self ###
        for win in self._windows[:]:
            win.destroy()
        application()._remove_document(self)
        self.destroy_contents()
        Model.destroy(self)

    #
    #		Properties
    #

    def get_needs_saving(self):
        return self._needs_saving

    def set_needs_saving(self, x):
        if self._needs_saving <> x:
            self._needs_saving = x
            for window in self._windows:
                window._document_needs_saving(x)

    def get_file(self):
        return self._file

    def set_file(self, x):
        self._file = x
        if x is not None:
            application()._last_directory = x.dir
        self.update_title()

    def get_file_type(self):
        return self._file_type

    def set_file_type(self, x):
        self._file_type = x

    def get_title(self):
        t = self._title
        if t == None:
            t = self.make_title()
            self._title = t
        return t

    def set_title(self, x):
        self._title = x
        for win in self._windows:
            win.update_title()

    def get_windows(self):
        return self._windows

    def get_page_setup(self):
        ps = self._page_setup
        if not ps:
            ps = PageSetup()
            self._page_setup = ps
        return ps

    def set_page_setup(self, ps):
        self._page_setup = ps

    #
    #		Methods
    #

    def changed(self):
        "Set the needs_saving property to true."
        self.needs_saving = 1

    def new_contents(self):
        """Should initialise the document to the appropriate state following a New
		command."""
        pass

    def read_contents(self, file):
        """Should initialise the document's contents by reading it from the given
		file object."""
        raise UnimplementedMethod(self, 'read_contents')

    def write_contents(self, file):
        """Should write the document's contents to the given file object."""
        raise UnimplementedMethod(self, 'write_contents')

    def destroy_contents(self):
        """Called when the contents of the document are about to be discarded. 
		If the contents contains any Model objects, they should be destroyed."""

    def save_changes(self):
        """If the document has been edited, ask the user whether to save changes,
		and do so if requested."""
        if self._needs_saving:
            result = confirm_or_cancel('Save changes to "%s"?' % self.title,
                                       "Save", "Don't Save", "Cancel")
            if result < 0:
                raise Cancel
            if result:
                self._save()

    def save_cmd(self):
        """Implements the standard Save command. Writes the document to its
		associated file, asking the user for one first if necessary."""
        self._save()

    def _save(self):
        for window in self.windows:
            window.broadcast('flush')
        if self._file == None:
            self.get_new_file_name()
        try:
            self.write()
        except EnvironmentError, e:
            raise ApplicationError("Unable to save '%s'." % self._file.name, e)
Ejemplo n.º 20
0
class DisplayList(Properties):
    """This class encapsulates an OpenGL display list and maintains a
    representation of it for each OpenGL context with which it is used.
    Allocation and maintentance of display list numbers is handled
    automatically."""
    #
    #   _gl_id   ShareGroup -> int   Mapping from OpenGL share group to
    #                                display list number

    setup = overridable_property(
        'setup', """Function to set up the display list by making the necessary
        OpenGL calls, excluding glNewList and glEndList.""")

    def __init__(self, setup=None):
        self._gl_id = DisplayListIdMap()
        self._setup = setup

    def deallocate(self):
        """Deallocate any OpenGL resources that have been allocated for this
        display list in any context."""
        self._gl_id.__del__()

    def get_setup(self):
        return self._setup

    def set_setup(self, x):
        self._setup = x

    def call(self):
        """Calls the display list using glCallList(). If this display list
        has not previously been used with the current context, allocates
        a display list number and arranges for do_setup() to be called
        to compile a representation of the display list."""
        share_group = current_share_group()
        gl_id = self._gl_id.get(share_group)
        if gl_id is None:
            gl_id = glGenLists(1)
            #print "GLDisplayList: assigned id %d for %s in share group %s" % (
            #	gl_id, self, share_group) ###
            self._gl_id[share_group] = gl_id
            call_when_not_compiling_display_list(lambda: self._compile(gl_id))
        glCallList(gl_id)

    def _compile(self, gl_id):
        global compiling_display_list
        compiling_display_list = True
        glNewList(gl_id, GL_COMPILE)
        try:
            self.do_setup()
        finally:
            glEndList()
            compiling_display_list = False

    def do_setup(self):
        """Make all the necessary OpenGL calls to compile the display list,
        except for glNewList() and glEndList() which will be called automatically
        before and after. The default implementation calls the 'setup' property."""
        setup = self._setup
        if setup:
            setup()
        else:
            raise NotImplementedError(
                "No setup function or do_setup method for GL.DisplayList")
Ejemplo n.º 21
0
class Component(Properties, MessageHandler):
    """Component is an abstract class representing a user
    interface component."""

    left = overridable_property(
        'left', "Position of left edge relative to container.")
    top = overridable_property('top',
                               "Position of top edge relative to container.")
    right = overridable_property(
        'right', "Position of right edge relative to container.")
    bottom = overridable_property(
        'bottom', "Position of bottom edge relative to container.")

    x = overridable_property('x', "Horizontal position relative to container.")
    y = overridable_property('y', "Vertical position relative to container.")
    width = overridable_property('width')
    height = overridable_property('height')

    position = overridable_property('position',
                                    "Position relative to container.")
    size = overridable_property('size')

    bounds = overridable_property(
        'bounds', "Bounding rectangle in container's coordinates.")

    container = overridable_property(
        'container',
        "Container which contains this Component. Setting this property has the "
        "effect of removing the component from its previous container, if any, "
        "and adding it to the new one, if any.")

    #	visible = overridable_property('visible',
    #		"Whether the component is currently shown.")

    tab_stop = overridable_property(
        'tab_stop', "Whether tab key can navigate into this control.")

    anchor = overridable_property(
        'anchor',
        "A string of 'ltrb' controlling behaviour when container is resized.")

    border = overridable_property(
        'border', "True if the component should have a border.")

    _is_scrollable = False  #  Overridden by scrollable subclasses
    _generic_tabbing = True  # Whether to use generic tab navigation code
    _default_tab_stop = False
    _user_tab_stop_override = False  # Whether user preference overrides _default_tab_stop
    _tab_stop = None

    #
    #   Class variables defined by implementations:
    #
    #  _has_local_coords   bool   True if component has a local coordinate system
    #

    _container = None
    _border = False
    hmove = 0
    vmove = 0
    hstretch = 0
    vstretch = 0

    def __init__(self, tab_stop=None, **kwds):
        Properties.__init__(self, **kwds)
        if tab_stop is None:
            tab_stop = self._get_default_tab_stop()
        self.tab_stop = tab_stop

    def destroy(self):
        self.container = None

    #
    #		Geometry properties
    #
    #   Default implementations of position and size properties
    #   in terms of the bounds property. A minimal implementation
    #   need only implement get_bounds and set_bounds.
    #
    #   It is the implementation's responsibility to call _resized()
    #   whenever the size of the component changes, either by
    #   explicit assignment to geometry properties or by the user
    #   resizing the containing window. It should not be called if
    #   setting a geometry property does not cause the size to change.
    #

    def get_left(self):
        return self.position[0]

    def set_left(self, v):
        l, t, r, b = self.bounds
        self.bounds = (v, t, r, b)

    def get_top(self):
        return self.bounds[1]

    def set_top(self, v):
        l, t, r, b = self.bounds
        self.bounds = (l, v, r, b)

    def get_right(self):
        return self.bounds[2]

    def set_right(self, v):
        l, t, r, b = self.bounds
        self.bounds = (l, t, v, b)

    def get_bottom(self):
        return self.bounds[3]

    def set_bottom(self, v):
        l, t, r, b = self.bounds
        self.bounds = (l, t, r, v)

    def get_x(self):
        return self.bounds[0]

    def set_x(self, v):
        l, t, r, b = self.bounds
        self.bounds = (v, t, v + r - l, b)

    def get_y(self):
        return self.bounds[1]

    def set_y(self, v):
        l, t, r, b = self.bounds
        self.bounds = (l, v, r, v + b - t)

    def get_position(self):
        l, t, r, b = self.bounds
        return (l, t)

    def set_position(self, xxx_todo_changeme):
        (x, y) = xxx_todo_changeme
        l, t, r, b = self.bounds
        self.bounds = (x, y, x + r - l, y + b - t)

    def get_width(self):
        l, t, r, b = self.bounds
        return r - l

    def set_width(self, v):
        l, t, r, b = self.bounds
        self.bounds = (l, t, l + v, b)

    def get_height(self):
        l, t, r, b = self.bounds
        return b - t

    def set_height(self, v):
        l, t, r, b = self.bounds
        self.bounds = (l, t, r, t + v)

    def get_size(self):
        l, t, r, b = self.bounds
        return (r - l, b - t)

    def set_size(self, xxx_todo_changeme1):
        (w, h) = xxx_todo_changeme1
        l, t, r, b = self.bounds
        self.bounds = (l, t, l + w, t + h)

    #
    #  Container management
    #

    def get_container(self):
        return self._container

    def set_container(self, new_container):
        if self._container != new_container:
            self._change_container(new_container)

    def _change_container(self, new_container):
        old_container = self._container
        if old_container:
            self._container = None
            old_container._remove(self)
        if new_container:
            self._container = new_container
            new_container._add(self)

    #
    #   Message dispatching
    #

    def become_target(self):
        """Arrange for this object to be the first to handle messages
        dispatched to the containing Window. If the component is not
        contained in a Window, the effect is undefined."""
        raise NotImplementedError

    def is_target(self):
        """Return true if this is the current target within the containing
        Window. If the component is not contained in a Window, the result
        is undefined."""
        return self.window and self.window.target is self

    #
    #		Message handling
    #

    def next_handler(self):
        return self._container

    #
    #		Visibility control
    #

#	def show(self):
#		"""Make the Component visible (provided its container is visible)."""
#		self.visible = 1
#
#	def hide(self):
#		"""Make the Component invisible."""
#		self.visible = 0

#
#   Border
#

    def get_border(self):
        return self._border

    def set_border(self, x):
        self._border = x

    #
    #		Resizing
    #

    def get_anchor(self):
        if self.hmove:
            s1 = 'r'
        elif self.hstretch:
            s1 = 'lr'
        else:
            s1 = 'l'
        if self.vmove:
            s2 = 'b'
        elif self.vstretch:
            s2 = 'tb'
        else:
            s2 = 't'
        return s1 + s2

    def set_anchor(self, s):
        if 'r' in s:
            if 'l' in s:
                self.hstretch = True
                self.hmove = False
            else:
                self.hstretch = False
                self.hmove = True
        else:
            self.hstretch = False
            self.hmove = False
        if 'b' in s:
            if 't' in s:
                self.vstretch = True
                self.vmove = False
            else:
                self.vstretch = False
                self.vmove = True
        else:
            self.vstretch = False
            self.vmove = False

    def get_auto_layout(self):
        return self._auto_layout

    def set_auto_layout(self, x):
        self._auto_layout = x

    def _resized(self, delta):
        #  Called whenever the size of the component changes for
        #  any reason.
        pass

    def container_resized(self, delta):
        """Called whenever the component's container changes size and the
        container's auto_layout property is true. The default implementation
        repositions and resizes this component according to its resizing
        options."""
        dw, dh = delta
        left, top, right, bottom = self.bounds
        if self.hmove:
            left += dw
            right += dw
        elif self.hstretch:
            right += dw
        if self.vmove:
            top += dh
            bottom += dh
        elif self.vstretch:
            bottom += dh
        self.bounds = (left, top, right, bottom)

    #
    #		Update region maintenance
    #

    def invalidate(self):
        """Mark the whole Component as needing to be redrawn."""
        self.invalidate_rect(self.viewed_rect())


#	def invalidate_rect(self, r):
#		print "GComponent.invalidate_rect:", self, r ###
#		container = self._container
#		if container:
#			container.invalidate_rect(r)

#	def _invalidate_in_container(self):
#		container = self._container
#		if container:
#			container._invalidate_subcomponent(self)

#
#		Coordinate transformation
#

    def local_to_global(self, p):
        p = self.local_to_container(p)
        parent = self._container
        if parent:
            return parent.local_to_global(p)
        else:
            return p

    def global_to_local(self, p):
        parent = self._container
        if parent:
            p = parent.global_to_local(p)
        return self.container_to_local(p)

    def local_to_container(self, p):
        if self._has_local_coords:
            return add_pt(p, self.local_to_container_offset())
        else:
            return p

    def container_to_local(self, p):
        if self._has_local_coords:
            return sub_pt(p, self.local_to_container_offset())
        else:
            return p

    def local_to_container_offset(self):
        if self._has_local_coords:
            return self.position
        else:
            return (0, 0)

    def transform_from(self, other, p):
        return transform_coords(other, self, p)

    def transform_to(self, other, p):
        return transform_coords(self, other, p)

    #
    #   Placement specification support
    #

    def __add__(self, offset):
        return (self, offset)

    def __sub__(self, offset):
        return (self, -offset)

    #
    #   Tabbing
    #

    def get_tab_stop(self):
        return self._tab_stop

    def set_tab_stop(self, x):
        if self._tab_stop != x:
            self._tab_stop = x
            self._invalidate_tab_chain()

    def _get_default_tab_stop(self):
        if self._user_tab_stop_override:
            result = _user_tab_stop
        else:
            result = None
        if result is None:
            result = self._default_tab_stop
        return result

    def _tab_out(self):
        pass

    def _tab_in(self):
        self.become_target()

    def _build_tab_chain(self, chain):
        if self._tab_stop:
            chain.append(self)

    def _invalidate_tab_chain(self):
        window = self.window
        if window:
            window._invalidate_tab_chain()

    def _is_targetable(self):
        return True

    #
    #		Other
    #

    def targeted(self):
        """Called when the component becomes the target within its Window."""
        pass

    def untargeted(self):
        """Called when the component ceases to be the target within its Window."""
        pass

    window = overridable_property(
        'window', """The Window ultimately containing
        this Component, or None.""")

    def get_window(self):
        container = self._container
        if container:
            return container.window
        else:
            return None

    def reset_blink(self):
        application().reset_blink()

    def viewed_rect(self):
        """Returns the rectangle in local coordinates that is
        currently visible within the component."""
        if self._has_local_coords:
            width, height = self.size
            return (0, 0, width, height)
        else:
            return self.bounds

    def broadcast(self, message, *args):
        """Traverse the component hierarchy, calling each component's handler for
        the given message, if any."""
        method = getattr(self, message, None)
        if method:
            method(*args)

    def _dispatch_mouse_event(self, event):
        self._handle_mouse_event(event)

    def _handle_mouse_event(self, event):
        self.handle(event.kind, event)
Ejemplo n.º 22
0
class GLConfig(Properties):
    """Class holding the attributes of an OpenGL context configuration."""

    #  NOTE: When adding a property here, also add it to
    #        _pixel_format_attribute_names below.

    double_buffer = overridable_property(
        "double_buffer", "True if context is to be double-buffered.")
    alpha = overridable_property("alpha",
                                 "True if there is to be an alpha channel.")
    color_size = overridable_property(
        "color_size", "Number of bits per colour buffer component.")
    alpha_size = overridable_property(
        "alpha_size", "Number of bits per alpha channel component.")
    stereo = overridable_property("stereo",
                                  "True if stereoscopic context is required.")
    aux_buffers = overridable_property(
        "aux_buffers", "Number of auxiliary colour buffers to allocate.")
    depth_buffer = overridable_property("depth_buffer",
                                        "True if a depth buffer is required.")
    depth_size = overridable_property(
        "depth_size", "Number of bits per depth buffer element.")
    stencil_buffer = overridable_property(
        "stencil_buffer", "True if a stencil buffer is required.")
    stencil_size = overridable_property(
        "stencil_size", "Number of bits per stencil buffer element.")
    accum_buffer = overridable_property(
        "accum_buffer", "True if an accumulation buffer is required.")
    accum_size = overridable_property(
        "accum_size", "Number of bits per accumulation buffer component.")
    multisample = overridable_property(
        "multisample", "True if a multisampled context is required.")
    samples_per_pixel = overridable_property(
        "samples_per_pixel", "Number of samples per multisampled pixel.")

    _double_buffer = True
    _alpha = True
    _color_size = 8
    _alpha_size = 8
    _stereo = False
    _aux_buffers = 0
    _depth_buffer = True
    _depth_size = 32
    _stencil_buffer = False
    _stencil_size = 8
    _accum_buffer = False
    _accum_size = 8
    _multisample = False
    _samples_per_pixel = 4

    _pixel_format_attribute_names = (
        'double_buffer',
        'alpha',
        'color_size',
        'alpha_size',
        'stereo',
        'aux_buffers',
        'depth_buffer',
        'depth_size',
        'stencil_buffer',
        'stencil_size',
        'accum_buffer',
        'accum_size',
        'multisample',
        'samples_per_pixel',
    )

    def _from_args(cls, config, kwds):
        #  Extract pixel format arguments from arguments of GLView.__init__
        #  or GLPixmap.__init__ and return a GLConfig. Used keyword
        #  arguments are removed from kwds.
        pf_kwds = {}
        for name in cls._pixel_format_attribute_names:
            if name in kwds:
                pf_kwds[name] = kwds.pop(name)
        if config and pf_kwds:
            raise TypeError(
                "Explicit config cannot be used with other configuration keyword arguments"
            )
        if not config:
            config = cls(**pf_kwds)
        return config

    _from_args = classmethod(_from_args)

    def get_double_buffer(self):
        return self._double_buffer

    def set_double_buffer(self, x):
        self._double_buffer = x

    def get_alpha(self):
        return self._alpha

    def set_alpha(self, x):
        self._alpha = x

    def get_color_size(self):
        return self._color_size

    def set_color_size(self, x):
        self._color_size = x

    def get_alpha_size(self):
        return self._alpha_size

    def set_alpha_size(self, x):
        self._alpha_size = x

    def get_stereo(self):
        return self._stereo

    def set_stereo(self, x):
        self._stereo = x

    def get_aux_buffers(self):
        return self._aux_buffers

    def set_aux_buffers(self, x):
        self._aux_buffers = x

    def get_depth_buffer(self):
        return self._depth_buffer

    def set_depth_buffer(self, x):
        self._depth_buffer = x

    def get_depth_size(self):
        return self._depth_size

    def set_depth_size(self, x):
        self._depth_size = x

    def get_stencil_buffer(self):
        return self._stencil_buffer

    def set_stencil_buffer(self, x):
        self._stencil_buffer = x

    def get_stencil_size(self):
        return self._stencil_size

    def set_stencil_size(self, x):
        self._stencil_size = x

    def get_accum_buffer(self):
        return self._accum_buffer

    def set_accum_buffer(self, x):
        self._accum_buffer = x

    def get_accum_size(self):
        return self._accum_size

    def set_accum_size(self, x):
        self._accum_size = x

    def get_multisample(self):
        return self._multisample

    def set_multisample(self, x):
        self._multisample = x

    def get_samples_per_pixel(self):
        return self._samples_per_pixel

    def set_samples_per_pixel(self, x):
        self._samples_per_pixel = x

    def supported(self):
        """Determine whether the combination of attributes requested by this configuration
		can be satisfied. If successful, a new GLConfig object is returned whose
		attributes reflect those actually allocated. Otherwise, a GLConfigError is
		raised."""
        raise NotImplementedError
Ejemplo n.º 23
0
class ScrollableView(DrawableContainer, ScrollableBase):
	"""A ScrollableView is a 2D drawing area having its own coordinate
	system and clipping area, with support for scrolling."""

#	scrolling = overridable_property('scrolling',
#		"String containing 'h' for horizontal and 'v' for vertical scrolling.")
#	
#	hscrolling = overridable_property('hscrolling',
#		"True if horizontal scrolling is enabled.")
#	
#	vscrolling = overridable_property('vscrolling',
#		"True if vertical scrolling is enabled.")
	
	extent = overridable_property('extent',
		"Size of scrollable area in local coordinates.")

	scroll_offset = overridable_property('scroll_offset',
		"Current scrolling position.")

	line_scroll_amount = overridable_property('line_scroll_amount',
		"Tuple specifying horizontal and vertical line scrolling increments.")
	
	background_color = overridable_property('background_color',
		"Color with which to fill areas outside the extent, or None")

	#scroll_bars = overridable_property('scroll_bars',
	#	"Attached ScrollBar instances.")
	#
	##  _scroll_bars          [ScrollBar]
	
	def set(self, **kwds):
		if 'scrolling' in kwds:
			self.scrolling = kwds.pop('scrolling')
		DrawableContainer.set(self, **kwds)

#	def get_scrolling(self):
#		chars = []
#		if self.hscrolling:
#			chars.append('h')
#		if self.vscrolling:
#			chars.append('v')
#		return ''.join(chars)
#	
#	def set_scrolling(self, value):
#		self.hscrolling = 'h' in value
#		self.vscrolling = 'v' in value

	def viewed_rect(self):
		"""Return the rectangle in local coordinates bounding the currently
		visible part of the extent."""
		return rect_sized(self.scroll_offset, self.size)

	def get_print_extent(self):
		return self.extent
	
	def get_background_color(self):
		return self._background_color
	
	def set_background_color(self, x):
		self._background_color = x
		self.invalidate()

	#
	#		Coordinate transformation
	#

	def local_to_container_offset(self):
		return sub_pt(self.position, self.scroll_offset)

	#
	#		Scrolling
	#

	def h_line_scroll_amount(self):
		"""Return the horizontal line scroll increment."""
		return self.line_scroll_amount[0]

	def v_line_scroll_amount(self):
		"""Return the vertical line scroll increment."""
		return self.line_scroll_amount[1]

	def h_page_scroll_amount(self):
		"""Return the horizontal page scroll increment."""
		return self.width - self.h_line_scroll_amount()

	def v_page_scroll_amount(self):
		"""Return the vertical page scroll increment."""
		return self.height - self.v_line_scroll_amount()

	def scroll_by(self, dx, dy):
		"""Scroll by the given amount horizontally and vertically."""
		self.scroll_offset = add_pt(self.scroll_offset, (dx, dy))

	def scroll_line_left(self):
		"""Called by horizontal scroll bar to scroll left by one line."""
		self.scroll_by(-self.h_line_scroll_amount(), 0)

	def scroll_line_right(self):
		"""Called by horizontal scroll bar to scroll right by one line."""
		self.scroll_by(self.h_line_scroll_amount(), 0)

	def scroll_line_up(self):
		"""Called by vertical scroll bar to scroll up by one line."""
		self.scroll_by(0, -self.v_line_scroll_amount())

	def scroll_line_down(self):
		"""Called by vertical scroll bar to scroll down by one line."""
		self.scroll_by(0, self.v_line_scroll_amount())

	def scroll_page_left(self):
		"""Called by horizontal scroll bar to scroll left by one page."""
		self.scroll_by(-self.h_page_scroll_amount(), 0)

	def scroll_page_right(self):
		"""Called by horizontal scroll bar to scroll right by one page."""
		self.scroll_by(self.h_page_scroll_amount(), 0)

	def scroll_page_up(self):
		"""Called by vertical scroll bar to scroll up by one page."""
		self.scroll_by(0, -self.v_page_scroll_amount())

	def scroll_page_down(self):
		"""Called by vertical scroll bar to scroll down by one page."""
		self.scroll_by(0, self.v_page_scroll_amount())

	#
	#   Background drawing
	#
	
	def _draw_background(self, canvas, clip_rect):
		#  If the view has a background color, uses it to fill the parts of the
		#  clip_rect that are outside the view's extent and returns the remaining
		#  rectangle. Otherwise, returns the clip_rect unchanged.
		color = self._background_color
		if color:
			vl, vt, vr, vb = clip_rect
			ew, eh = self.extent
			if vr > ew or vb > eh:
				#if getattr(self, "_debug_bg", False): ###
				#	print "ScrollableView: old backcolor =", canvas.backcolor ###
				canvas.gsave()
				canvas.backcolor = color
				if ew < vr:
					#if getattr(self, "_debug_bg", False): ###
					#	print "ScrollableView: erasing", (ew, vt, vr, vb) ###
					canvas.erase_rect((ew, vt, vr, vb))
				if eh < vb:
					if getattr(self, "_debug_bg", False): ###
						print "ScrollableView: erasing", (vl, eh, ew, vb) ###
					canvas.erase_rect((vl, eh, ew, vb))
				canvas.grestore()
				#if getattr(self, "_debug_bg", False): ###
				#	print "ScrollableView: restored backcolor =", canvas.backcolor ###
				return sect_rect(clip_rect, (0, 0, ew, eh))
		return clip_rect
Ejemplo n.º 24
0
class TextField(Control, ActionBase, EditCmdHandler):
    """A control for entering and editing small amounts of text."""

    text = overridable_property('text')
    selection = overridable_property('selection', "Range of text selected.")
    multiline = overridable_property('multiline',
                                     "Multiple text lines allowed.")
    password = overridable_property('password',
                                    "Display characters obfuscated.")
    enter_action = action_property(
        'enter_action', "Action to be performed "
        "when the Return or Enter key is pressed.")
    escape_action = action_property(
        'escape_action', "Action to be performed "
        "when the Escape key is pressed.")

    _may_be_password = True

    #_tabbable = True
    _default_tab_stop = True
    _user_tab_stop_override = False
    _enter_action = 'do_default_action'
    _escape_action = 'do_cancel_action'

    _intercept_tab_key = True

    def __init__(self, **kwds):
        self._multiline = kwds.pop('multiline')
        Control.__init__(self, **kwds)

    def get_multiline(self):
        return self._multiline

    def key_down(self, event):
        #print "GTextField.key_down for", self ###
        c = event.char
        if c == '\r':
            if event.key == 'enter' or not self._multiline:
                self.do_enter_action()
                return
        if c == '\x1b':
            self.do_escape_action()
            return
        if c == '\t':
            if self._intercept_tab_key:
                self.pass_event_to_next_handler(event)
                return
        Control.key_down(self, event)

    def setup_menus(self, m):
        Control.setup_menus(self, m)
        EditCmdHandler.setup_menus(self, m)

    def do_enter_action(self):
        self.do_named_action('enter_action')

    def do_escape_action(self):
        self.do_named_action('escape_action')

    def get_text_length(self):
        #  Implementations can override this if they have a more
        #  efficient way of getting the text length.
        return len(self.text)

    def get_value(self):
        return self.text

    def set_value(self, x):
        self.text = x
Ejemplo n.º 25
0
class Model(Properties):
    """A Model represents an application object which can appear in a View. 
    Each Model can have any number of Views attached to it. When a Model is 
    changed, it should notify all of its Views so that they can update
    themselves.
    
    The 'parent' attribute of a Model is treated specially when pickling.
    If it refers to an object having a 'pickle_as_parent_model' attribute
    whose value is false, the 'parent' attribute is not pickled. This allows
    a Model to have a Document as a parent without the Document being pickled
    along with the Model.
    """

    views = overridable_property(
        'views',
        "List of objects observing this model. Do not modify directly.")

    parent = None  # Model

    def __init__(self, parent=None, **kwds):
        Properties.__init__(self, **kwds)
        if parent:
            self.parent = parent

    def destroy(self):
        """All views currently observing this model are removed, and their
        'model_destroyed' methods, if any, are called with the model as
        an argument."""
        for view in self.views[:]:
            self.remove_view(view)
            self._call_if_present(view, 'model_destroyed', self)

    #
    #		Properties
    #

    def get_views(self):
        views = _model_views.get(self)
        if views is None:
            views = []
            _model_views[self] = views
        return views

    #
    #   Pickling behaviour
    #

    def __getstate__(self):
        state = self.__dict__
        parent = self.parent
        if not getattr(parent, 'pickle_as_parent_model', True):
            state = state.copy()
            del state['parent']
        return state

    def __setstate__(self, state):
        self.__dict__.update(state)

    #
    #		Adding and removing views
    #

    def add_view(self, view):
        """Add the given object as an observer of this model. The view will
        typically be a View subclass, but need not be. If the view is not 
        already an observer of this model and defines an 'add_model' method,
        this method is called with the model as an argument."""
        views = self.views
        if view not in views:
            views.append(view)
            self._call_if_present(view, 'add_model', self)

    def remove_view(self, view):
        """If the given object is currently an observer of this model, it
        is removed, and if it defines a 'remove_model' method, this method
        is called with the model as an argument."""
        views = self.views
        if view in views:
            views.remove(view)
            self._call_if_present(view, 'remove_model', self)

    #
    #		View notification
    #

    def notify_views(self, message='model_changed', *args, **kwds):
        """For each observer, if the observer defines a method with the name of the
        message, call it with the given arguments. Otherwise, if it defines a
        method called 'model_changed', call it with no arguments. Otherwise,
        do nothing for that observer."""
        for view in self.views:
            if not self._call_if_present(view, message, self, *args, **kwds):
                self._call_if_present(view, 'model_changed', self)

    def _call_if_present(self, obj, method_name, *args, **kwds):
        method = getattr(obj, method_name, None)
        if method:
            method(*args, **kwds)
            return 1
        else:
            return 0

    #
    #   Marking as changed
    #

    def changed(self):
        "Mark the containing Document as changed."
        parent = self.parent
        if parent:
            parent.changed()
Ejemplo n.º 26
0
class FileType(Properties):
    """A FileType is a multi-platform representation of a file type."""

    _name = None
    _suffix = None
    _mac_creator = None
    _mac_type = None
    _mac_force_suffix = True

    name = overridable_property('name',
                                "Human-readable description of the file type")
    suffix = overridable_property('suffix', "Filename suffix (without dot)")
    mac_creator = overridable_property('mac_creator',
                                       "Macintosh 4-character creator code")
    mac_type = overridable_property('mac_type',
                                    "Macintosh 4-character type code")
    mac_force_suffix = overridable_property(
        'mac_force_suffix', "Enforce filename suffix on MacOSX")

    def get_name(self):
        return self._name

    def set_name(self, x):
        self._name = x

    def get_suffix(self):
        return self._suffix

    def set_suffix(self, x):
        self._suffix = x

    def get_mac_creator(self):
        return self._mac_creator

    def set_mac_creator(self, x):
        self._mac_creator = x

    def get_mac_type(self):
        return self._mac_type

    def set_mac_type(self, x):
        self._mac_type = x

    def get_mac_force_suffix(self):
        return self._mac_force_suffix

    def set_mac_force_suffix(self, x):
        self._mac_force_suffix = x

    def _matches(self, name, mac_type):
        #  Return true if the given name or type code matches that of
        #  this file type.
        this_mac_type = self._mac_type
        this_suffix = self._suffix
        if this_mac_type and mac_type == this_mac_type:
            return True
        #  Allow generic text files to match typeless files for MacOSX
        if not this_suffix and this_mac_type == "TEXT" and mac_type == "\0\0\0\0":
            return True
        if this_suffix and _matches_suffix(name, this_suffix):
            return True
        return False

    def _add_suffix(self, name):
        #  Force the given name to have the appropriate suffix for this file
        #  type. Platforms which have other means of representing file types
        #  (e.g. Macintosh) may override this.
        suffix = self._suffix
        if suffix and not _matches_suffix(name, suffix):
            name = "%s.%s" % (name, suffix)
        return name
Ejemplo n.º 27
0
class ViewBase(object):
    """ViewBase is an abstract base class for user-defined views.
    It provides facilities for handling mouse and keyboard events
    and associating the view with one or more models, and default
    behaviour for responding to changes in the models."""

    models = overridable_property(
        'models', "List of Models being observed. Do not modify directly.")

    model = overridable_property(
        'model',
        "Convenience property for views which observe only one Model.")

    cursor = overridable_property('cursor',
                                  "The cursor to display over the view.")

    #  _models               [Model]

    _cursor = None

    def __init__(self):
        self._models = []

    def destroy(self):
        #print "GViewBase.destroy:", self ###
        for m in self._models[:]:
            #print "GViewBase.destroy: removing model", m ###
            self.remove_model(m)

    def setup_menus(self, m):
        pass

    #
    #		Getting properties
    #

    def get_model(self):
        models = self._models
        if models:
            return self._models[0]
        else:
            return None

    def get_models(self):
        return self._models

    #
    #		Setting properties
    #

    def set_model(self, new_model):
        models = self._models
        if not (len(models) == 1 and models[0] == new_model):
            for old_model in models[:]:
                self.remove_model(old_model)
            if new_model:
                self.add_model(new_model)

    #
    #   Model association
    #

    def add_model(self, model):
        """Add the given Model to the set of models being observed."""
        if model not in self._models:
            self._models.append(model)
            add_view = getattr(model, 'add_view', None)
            if add_view:
                add_view(self)
            self.model_added(model)

    def remove_model(self, model):
        """Remove the given Model from the set of models being observed."""
        if model in self._models:
            self._models.remove(model)
            remove_view = getattr(model, 'remove_view', None)
            if remove_view:
                remove_view(self)
            self.model_removed(model)

    def model_added(self, model):
        """Called after a model has been added to the view."""
        pass

    def model_removed(self, model):
        """Called after a model has been removed from the view."""
        pass

    #
    #   Input event handling
    #

    def track_mouse(self):
        """Following a mouse_down event, returns an iterator which can be used
        to track the movements of the mouse until the mouse is released.
        Each call to the iterator's next() method returns a mouse_drag
        event, except for the last one, which returns a mouse_up event."""
        raise NotImplementedError

# 	def targeted(self):
# 		"""Called when the component becomes the target within its Window."""
# 		pass
#
# 	def untargeted(self):
# 		"""Called when the component ceases to be the target within its Window."""
# 		pass

#
#   Cursors
#

    def get_cursor(self, x):
        return self._cursor

    def set_cursor(self, x):
        self._cursor = x
        self._cursor_changed()

    #
    #		Callbacks
    #

    def model_changed(self, model, *args, **kwds):
        """Default method called by the attached Model's notify_views
        method. Default is to invalidate the whole view."""
        self.invalidate()

    def model_destroyed(self, model):
        """Called when an attached model is destroyed. Default is to
        destroy the window containing this view."""
        win = self.window
        if win:
            win.destroy()
Ejemplo n.º 28
0
class Label(Control):
    """A piece of static text for labelling items in a window."""

    _default_tab_stop = False

    text = overridable_property('text')
Ejemplo n.º 29
0
class FileRef(Properties):
    """A FileRef represents a file system object in a platform-independent way.
    It consists of two parts, a directory specification and the name of an
    object within that directory. The directory specification always refers
    to an existing directory, but the named object may or may not exist.

    Constructors:
        FileRef(dir = DirRef or path, name = string)
        FileRef(path = string)
    """

    dir = overridable_property('dir',
                               "DirRef representing the parent directory.")
    name = overridable_property(
        'name', "Name of the object within the parent directory.")
    path = overridable_property('path', "Full pathname of the object.")

    _dir = None  # DirRef representing the parent directory
    _name = None  # Name, including type suffix if any

    #
    #   Constructor
    #

    def __init__(self, dir=None, name=None, path=None):
        if dir and name and not path:
            if not isinstance(dir, DirRef):
                dir = DirRef(dir)
        elif path and not (dir or name):
            dirpath, name = os.path.split(path)
            dir = DirRef(path=dirpath)
        else:
            raise TypeError(
                "Invalid argument combination to FileRef constructor")
        self._dir = dir
        self._name = name

    #
    #		Properties
    #

    def get_dir(self):
        return self._dir

    def get_name(self):
        "Return the name of the file."
        return self._name

    def get_path(self):
        return os.path.join(self._dir.path, self._name)

    #
    #		Methods
    #

    def open(self, mode, file_type=None):
        """Open as a file with the given mode and return a file object. On
        platforms which have file-type metadata (e.g. Macintosh), if the
        mode contains 'w' and a file_type is specified, the newly-created
        file will be given the specified type."""
        f = open(self.path, mode)
        if "w" in mode and file_type:
            self._set_type(file_type)
        return f

    def mkdir(self):
        """Create a directory with the name and parent directory specified
        by this FileRef. Returns a DirRef for the created directory."""
        return DirRef(os.mkdir(self.path))

    def _set_type(self, file_type):
        #  Platforms which have file-type metadata (e.g. Macintosh) use this
        #  to set the type of a file.
        pass

    def __str__(self):
        return "FileRef(%r,%r)" % (self.dir.path, self.name)
Ejemplo n.º 30
0
class Window(Container):
    """Top-level Container."""

    menus = overridable_property(
        'menus', "Menus to be available when this window is active.")
    document = overridable_property(
        'document', "Document with which this window is associated.")
    title = overridable_property('title', "Title of the window.")
    auto_position = overridable_property(
        'auto_position', "Whether to position automatically when first shown.")
    target = overridable_property(
        'target', "Current target for key events and menu messages.")
    tab_chain = overridable_property(
        'tab_chain', "List of subcomponents in tabbing order.")
    visible = overridable_property('visible',
                                   "Whether the window is currently shown.")

    keeps_document_open = True

    _default_width = 200
    _default_height = 200
    _modal_styles = ('modal_dialog', 'alert')
    _dialog_styles = ('nonmodal_dialog', 'modal_dialog', 'alert')

    _menus = []
    _document = None
    _closable = 0
    _auto_position = True
    _tab_chain = None

    def __init__(self, style='standard', closable=None, **kwds):
        if closable is None:
            raise Exceptions.InternalError(
                "'closable' parameter unspecified in call to generic Window.__init__"
            )
        Container.__init__(self, **kwds)
        self._style = style
        self._dialog_style = style.find('dialog') >= 0
        self._closable = closable
        application()._add_window(self)

    def destroy(self):
        """Detaches the window from document and application and removes it
        from the screen."""
        self.set_document(None)
        application()._remove_window(self)
        Container.destroy(self)

    #
    #		Message handling
    #

    def next_handler(self):
        if self._document:
            return self._document
        else:
            return application()

    def dispatch(self, message, *args):
        self.target.handle(message, *args)

    #
    #		Menus
    #

    def get_menus(self):
        return self._menus

    def set_menus(self, x):
        self._menus = x

    #
    #		Document association
    #

    def get_document(self):
        return self._document

    def set_document(self, x):
        if self._document != x:
            if self._document:
                self._document._windows.remove(self)
            self._document = x
            if self._document:
                self._document._windows.append(self)
                self.update_title()

    #
    #		Title
    #

    def update_title(self):
        """Update the window's title after a change in its document's title."""
        doc = self._document
        if doc:
            self.set_title(doc.title)

    #
    #   Showing and Positioning
    #

    def get_auto_position(self):
        return self._auto_position

    def set_auto_position(self, v):
        self._auto_position = v

    def center(self):
        """Position the window in the centre of the screen."""
        sl, st, sr, sb = self._screen_rect()
        w, h = self.size
        l = (sr - sl - w) // 2
        t = (sb - st - h) // 2
        self.position = (l, t)

    def centre(self):
        self.center()

    def show(self):
        if self._auto_position:
            if self._style == 'standard':
                self._stagger()
            else:
                self.center()
            self._auto_position = False
        self._show()

    def _stagger(self):
        pass

    def _show(self):
        self.visible = True

    def hide(self):
        self.visible = False

    #
    #		Menu commands
    #

    def setup_menus(self, m):
        Container.setup_menus(self, m)
        app = application()
        if self._closable:
            m.close_cmd.enabled = 1

    def close_cmd(self):
        """If this window is the only window belonging to a document
        whose keeps_document_open attribute is true, then close the
        document, else destroy the window."""
        #		app = application()
        #		if not app._may_close_a_window():
        #			#print "GWindow.close_cmd: Quitting the application" ###
        #			app.quit_cmd()
        #		else:
        doc = self._document
        n = 0
        if doc:
            for win in doc._windows:
                if win is not self and win.keeps_document_open:
                    n += 1
        if doc and n == 0:
            doc.close_cmd()
        else:
            self.destroy()

    #
    #   Tabbing
    #

    def get_tab_chain(self):
        chain = self._tab_chain
        if chain is None:
            chain = []
            self._build_tab_chain(chain)
            self._tab_chain = chain
        #print "Window.get_tab_chain:", chain ###
        return chain

    def _invalidate_tab_chain(self):
        self._tab_chain = None

    def _tab_to_next(self):
        self._tab_to(1)

    def _tab_to_prev(self):
        self._tab_to(-1)

    def _tab_to(self, direction):
        print("GWindow._tab_to:", direction)  ###
        chain = self.tab_chain
        if chain:
            old_target = application().target
            new_target = None
            n = len(chain)
            try:
                i = chain.index(old_target)
            except ValueError:
                if direction > 0:
                    i = -1
                else:
                    i = n
            k = n
            while k:
                k -= 1
                i = (i + direction) % n
                comp = chain[i]
                if comp._is_targetable():
                    new_target = comp
                    break
            if new_target:
                if old_target:
                    old_target._tab_out()
                new_target._tab_in()

    def key_down(self, event):
        #print "GWindow.key_down:", event
        if self._generic_tabbing and event.char == '\t':
            #print "GWindow.key_down: doing generic tabbing"
            if event.shift:
                self._tab_to_prev()
            else:
                self._tab_to_next()
        else:
            Container.key_down(self, event)

    #
    #   Other
    #

    def get_window(self):
        return self

    def first_dispatcher(self):
        return self

    def _document_needs_saving(self, state):
        pass

    def modal_event_loop(self):
        """Loop reading and handling events for the given window until
        exit_event_loop() is called. Interaction with other windows is prevented
        (although enabled application-wide menu commands can be used)."""
        #  Implementations can override this together with exit_modal_event_loop()
        #  to implement modal event loops in a different way.
        application()._event_loop(self)

    def exit_modal_event_loop(self):
        #  Cause the current call to modal_event_loop() to exit.
        application()._exit_event_loop()
Ejemplo n.º 31
0
        if self._tab_stop:
            chain.append(self)
    
    def _invalidate_tab_chain(self):
        window = self.window
        if window:
            window._invalidate_tab_chain()
    
    def _is_targetable(self):
        return True

    #
    #		Other
    #
    
    window = overridable_property('window', """The Window ultimately containing
        this Component, or None.""")
    
    def get_window(self):
        container = self._container
        if container:
            return container.window
        else:
            return None

    def reset_blink(self):
        application().reset_blink()
    
    def viewed_rect(self):
        """Returns the rectangle in local coordinates that is
        currently visible within the component."""
        if self._has_local_coords: