portable widget frontend modules

Miro’s widget frontend is split between portable code and platform-specific code.

The portable code is located in portable/frontends/widgets/ and is in the miro.frontends.widgets package space.

See the chapter on platform-specific widget frontend modules for platform-specific details.

FIXME - need explanation here and probably a drawing of the architecture

application - main application code

``miro.frontends.widgets.application – The application module holds Application and the portable code to handle the high level running of the Miro application.

It also holds:

class miro.frontends.widgets.application.Application

This class holds the portable application code. Each platform extends this class with a platform-specific version.

ask_for_url(title, description, error_title, error_description)

Ask the user to enter a url in a TextEntry box.

If the URL the user enters is invalid, she will be asked to re-enter it again. This process repeats until the user enters a valid URL, or clicks Cancel.

The initial text for the TextEntry will be the clipboard contents (if it is a valid URL).

get_main_window_dimensions()

Override this to provide platform-specific Main Window dimensions.

Must return a Rect.

get_right_width()
Returns the width of the right side of the splitter.
on_close()
This is called when the close button is pressed.
quit_ui()
Quit out of the UI event loop.
startup()
Connects to signals, installs handlers, and calls startup() from the miro.startup module.
startup_ui()
Starts up the widget ui by sending a bunch of messages requesting data from the backend. Also sets up managers, initializes the ui, and displays the MiroWindow.
class miro.frontends.widgets.application.FrontendStatesStore(message)
Stores which views were left in list mode by the user.
class miro.frontends.widgets.application.InfoUpdater

Track channel/item updates from the backend.

To track item updates, use add_item_callback(). To track tab updates, connect to one of the signals below.

Signals:

  • feeds-added (self, info_list) – New video feeds were added
  • feeds-changed (self, info_list) – Video feeds were changed
  • feeds-removed (self, info_list) – Video feeds were removed
  • audio-feeds-added (self, info_list) – New audio feeds were added
  • audio-feeds-changed (self, info_list) – Audio feeds were changed
  • audio-feeds-removed (self, info_list) – Audio feeds were removed
  • sites-added (self, info_list) – New sites were added
  • sites-changed (self, info_list) – Sites were changed
  • sites-removed (self, info_list) – Sites were removed
  • playlists-added (self, info_list) – New playlists were added
  • playlists-changed (self, info_list) – Playlists were changed
  • playlists-removed (self, info_list) – Playlists were removed
class miro.frontends.widgets.application.InfoUpdaterCallbackList

Tracks the list of callbacks for InfoUpdater.

add(type_, id_, callback)

Adds the callback to the list for type_ id_.

Parameters:
  • type – the type of the thing (feed, audio-feed, site, ...)
  • id – the id for the thing
  • callback – the callback function to add
get(type_, id_)

Get the list of callbacks for type_, id_.

Parameters:
  • type – the type of the thing (feed, audio-feed, site, ...)
  • id – the id for the thing
remove(type_, id_, callback)

Removes the callback from the list for type_ id_.

Parameters:
  • type – the type of the thing (feed, audio-feed, site, ...)
  • id – the id for the thing
  • callback – the callback function to remove
class miro.frontends.widgets.application.WidgetsMessageHandler

Handles frontend messages.

There’s a method to handle each frontend message type. See miro.messages (portable/messages.py) and miro.messagehandler (portable/messagehandler.py) for more details.

cellpack - code to lay out CustomTableCells

miro.frontends.widgets.cellpack – Code to layout CustomTableCells.

We use the hbox/vbox model to lay things out with a couple changes. The main difference here is that layouts are one-shot. We don’t keep state around inside the cell renderers, so we just set up the objects at the start, then use them to calculate info.

class miro.frontends.widgets.cellpack.Alignment(child, xscale=1.0, yscale=1.0, xalign=0.0, yalign=0.0, min_width=0, min_height=0)
Positions a child inside a larger space.
class miro.frontends.widgets.cellpack.Background(child, min_width=0, min_height=0, margin=None)
Draws a background behind a child element.
class miro.frontends.widgets.cellpack.Box(spacing=0)

Box is the base class for VBox and HBox. Box objects lay out children linearly either left to right or top to bottom.

pack(child, expand=False)

Add a new child to the box. The child will be placed after all the children packed before with pack_start.

Parameters:
  • child – child to pack. It can be anything with a get_size() method, including TextBoxes, ImageSurfarces, Buttons, Boxes and Backgrounds.
  • expand – If True, then the child will enlarge if space available is more than the space required.
pack_end(child, expand=False)

Add a new child to the end box. The child will be placed before all the children packed before with pack_end.

Parameters:
  • child – child to pack. It can be anything with a get_size() method, including TextBoxes, ImageSurfarces, Buttons, Boxes and Backgrounds.
  • expand – If True, then the child will enlarge if space available is more than the space required.
pack_space(size, expand=False)
Pack whitespace into the box.
pack_space_end(size, expand=False)
Pack whitespace into the end of box.
class miro.frontends.widgets.cellpack.ClippedTextBox(textbox, min_width=0, min_height=0)
A TextBox that gets clipped if it’s larger than it’s allocated width.
class miro.frontends.widgets.cellpack.ClippedTextLine(textbox, min_width=0)
A single line of text that gets clipped if it’s larger than the space allocated to it. By default the clipping will happen at character boundaries.
class miro.frontends.widgets.cellpack.DrawingArea(width, height, callback, *args)
Area that uses custom drawing code.
class miro.frontends.widgets.cellpack.Hotspot(name, child)
A Hotspot handles mouse click tracking. It’s only purpose is to store a name to return from find_hotspot(). In terms of layout, it simply renders it’s child in it’s allocated space.
class miro.frontends.widgets.cellpack.Margin(margin)

Helper object used to calculate margins.

inner_rect(x, y, width, height)
Returns the x, y, width, height of the inner box.
outer_size(inner_size)
Returns the width, height of the outer box.
point_in_margin(x, y, width, height)
Returns whether a given point is inside of the margins.
class miro.frontends.widgets.cellpack.Packer

Base class packing objects. Packer objects work similarly to widgets, but they only used in custom cell renderers so there’s a couple differences. The main difference is that cell renderers don’t keep state around. Therefore Packers just get set up, used, then discarded. Also Packers can’t receive events directly, so they have a different system to figure out where mouse clicks happened (the Hotspot class).

draw(context, x, y, width, height)
Included so that Packer objects have a draw() method that matches ImageSurfaces, TextBoxes, etc.
find_hotspot(x, y, width, height)

Find the hotspot at (x, y). width and height are the size of the cell this Packer is rendering.

If a hotspot is found, return the tuple (name, x, y, width, height) where name is the name of the hotspot, x, y is the position relative to the top-left of the hotspot area and width, height are the dimensions of the hotspot.

If no Hotspot is found return None.

get_current_size()

Get the minimum size required to hold the Packer at this point

Call this method if you are going to change the packer after the call, for example if you have more children to pack into a box. get_size() saves caches it’s result which is can mess things up.

get_size()
Get the minimum size required to hold the Packer.
render_layout(context)
position the child elements then call draw() on them.
class miro.frontends.widgets.cellpack.Packing(child, expand)
Helper object used to layout Boxes.
class miro.frontends.widgets.cellpack.Padding(child, top=0, right=0, bottom=0, left=0)
Adds padding to the edges of a packer.
class miro.frontends.widgets.cellpack.Stack
Packer that stacks other packers on top of each other.
class miro.frontends.widgets.cellpack.TextBoxPacker
Base class for ClippedTextLine and ClippedTextBox.
class miro.frontends.widgets.cellpack.WhitespacePacking(size, expand)
Helper object used to layout Boxes.
miro.frontends.widgets.cellpack.align_bottom(packer)
Align a packer to the bottom side of it’s allocated space.
miro.frontends.widgets.cellpack.align_center(packer)
Align a packer to the center of it’s allocated space.
miro.frontends.widgets.cellpack.align_left(packer)
Align a packer to the left side of it’s allocated space.
miro.frontends.widgets.cellpack.align_middle(packer)
Align a packer to the middle of it’s allocated space.
miro.frontends.widgets.cellpack.align_right(packer)
Align a packer to the right side of it’s allocated space.
miro.frontends.widgets.cellpack.align_top(packer)
Align a packer to the top side of it’s allocated space.
miro.frontends.widgets.cellpack.pad(packer, top=0, left=0, bottom=0, right=0)
Add padding to a packer.

dialogs - dialogs

miro.frontends.widgets.dialogs – Dialog boxes for the Widget frontend.

The difference between this module and rundialog.py is that rundialog handles dialog boxes that are coming from the backend code. This model handles dialogs that we create from the frontend

One big difference is that we don’t have to be as general about dialogs, so they can present a somewhat nicer API. One important difference is that all of the dialogs run modally.

class miro.frontends.widgets.dialogs.MainDialog(title, description=None)
Dialog that is transient for the main window.
miro.frontends.widgets.dialogs.ask_for_directory(title, initial_directory=None, transient_for=None)
Returns the directory pathname or None.
miro.frontends.widgets.dialogs.ask_for_open_pathname(title, initial_filename=None, filters=[], transient_for=None, select_multiple=False)
Returns the file pathname or None.
miro.frontends.widgets.dialogs.ask_for_save_pathname(title, initial_filename=None, transient_for=None)
Returns the file pathname or None.
miro.frontends.widgets.dialogs.ask_for_string(title, description, initial_text=None, transient_for=None)

Ask the user to enter a string in a TextEntry box.

description - textual description with newlines initial_text - None, string or callable to pre-populate the entry box

Returns the value entered, or None if the user clicked cancel

miro.frontends.widgets.dialogs.set_transient_for_main(dialog)

Sets a Dialog object to be transient for the main window if possible.

If the main window has not been created yet, this is a no-op.

miro.frontends.widgets.dialogs.show_choice_dialog(title, description, choices, transient_for=None)
Display a message to the user and wait for them to choose an option. Returns the button object chosen.
miro.frontends.widgets.dialogs.show_message(title, description, alert_type=1, transient_for=None)
Display a message to the user and wait for them to click OK

imagepool - Image objects for image filenames

miro.frontends.widgets.imagepool – Get Image objects for image filenames.

imagepool handles creating Image and ImageSurface objects for image filenames. It remembers images that have been created, and doesn’t create duplicate Image/ImageSurface objects for a single path.

class miro.frontends.widgets.imagepool.LazySurface(path, size=None)

Lazily loaded ImageSurface.

LazySurface objects only create ImageSurfaces as needed. If multiple LazySurface objects are created for the same path, then they will share the underlying ImageSurface object.

miro.frontends.widgets.imagepool.get(path, size=None)

Returns an Image for path.

Parameters:
  • path – the filename for the image
  • size – if the image needs to fit into a specified sized space, then specify this and get will return a scaled image; if size is not specified, then this returns the default sized image
miro.frontends.widgets.imagepool.get_surface(path, size=None)

Returns an ImageSurface for path.

Parameters:
  • path – the filename for the image
  • size – if the image needs to fit into a specified sized space, then specify this and get will return a scaled image; if size is not specified, then this returns the default sized image
miro.frontends.widgets.imagepool.scaled_size(image, size)

Takes an image which has a width and a height and a size tuple that specifies the space available and returns the new width and height that allows the image to fit into the sized space at the correct height/width ratio.

Parameters:
  • image – the Image (must have width and height properties)
  • size – (width, height) tuple of space you want the image to fit in

util - utility functions

miro.frontends.widgets.util – Utility functions.

miro.frontends.widgets.util.rounded_rectangle(context, x, y, width, height, xradius, yradius=None)

Create a path using a rounded rectangle. xradius and yradius specifies how far away from the normal rectangle corner the rounded edge will start.

yradius defaults to xradius.

widgetconst - constants

miro.frontends.widgets.widgetconst – Constants for the widgets frontend.

widgetutil - utility functions

miro.frontends.widgets.widgetutil – Utility functions.

class miro.frontends.widgets.widgetutil.HideableWidget(child)

Creates a widget that can be hidden and shown.

Example:

>>> lab = Label(_("Error!"))
>>> hidden_lab = HideableWidget(lab)

Then when we want to hide it, we do:

>>> hidden_lab.hide()

and when we want to show it again, we do:

>>> hidden_lab.show()
child()
Returns the child widget.
hide()
Hides the child widget.
show()
Shows the child widget.
class miro.frontends.widgets.widgetutil.Shadow(color, opacity, offset, blur_radius)
Encapsulates all parameters required to draw shadows.
class miro.frontends.widgets.widgetutil.ThreeImageSurface(basename=None)

Takes a left, center and right image and draws them to an arbitrary width. If the width is greater than the combined width of the 3 images, then the center image will be tiled to compensate.

Example:

>>> timelinebar = ThreeImageSurface("timelinebar")

This creates a ThreeImageSurface using the images images/timelinebar_left.png, images/timelinebar_center.png, and images/timelinebar_right.png.

Example:

>>> timelinebar = ThreeImageSurface()
>>> img_left = make_surface("timelinebar_left")
>>> img_center = make_surface("timelinebar_center")
>>> img_right = make_surface("timelinebar_right")
>>> timelinebar.set_images(img_left, img_center, img_right)

This does the same thing, but allows you to explicitly set which images get used.

set_images(left, center, right)
Sets the left, center and right images to use.
miro.frontends.widgets.widgetutil.align(widget, xalign=0, yalign=0, xscale=0, yscale=0, top_pad=0, bottom_pad=0, left_pad=0, right_pad=0)
Create an alignment, then add widget to it and return the alignment.
miro.frontends.widgets.widgetutil.align_bottom(widget, top_pad=0, bottom_pad=0, left_pad=0, right_pad=0)
Wrap a widget in an Alignment that will align to the bottom.
miro.frontends.widgets.widgetutil.align_center(widget, top_pad=0, bottom_pad=0, left_pad=0, right_pad=0)
Wrap a widget in an Alignment that will center it horizontally.
miro.frontends.widgets.widgetutil.align_left(widget, top_pad=0, bottom_pad=0, left_pad=0, right_pad=0)
Wrap a widget in an Alignment that will align it right.
miro.frontends.widgets.widgetutil.align_middle(widget, top_pad=0, bottom_pad=0, left_pad=0, right_pad=0)
Wrap a widget in an Alignment that will center it vertically.
miro.frontends.widgets.widgetutil.align_right(widget, top_pad=0, bottom_pad=0, left_pad=0, right_pad=0)
Wrap a widget in an Alignment that will align it left.
miro.frontends.widgets.widgetutil.align_top(widget, top_pad=0, bottom_pad=0, left_pad=0, right_pad=0)
Wrap a widget in an Alignment that will align to the top.
miro.frontends.widgets.widgetutil.build_hbox(items, padding=5)
Builds an HBox and packs with the list of widgets. Padding defaults to 5 pixels.
miro.frontends.widgets.widgetutil.circular_rect(context, x, y, width, height)
Make a path for a rectangle with the left/right side being circles.
miro.frontends.widgets.widgetutil.circular_rect_negative(context, x, y, width, height)
The same path as circular_rect(), but going counter clockwise.
miro.frontends.widgets.widgetutil.draw_rounded_icon(context, icon, x, y, width, height, inset=0)

Draw an icon with the corners rounded.

x, y, width, height define where the box is.

inset creates a margin between where the images is drawn and (x, y, width, height)

miro.frontends.widgets.widgetutil.feed_exists(feed_id)
Returns true or false as to whether a Feed with id feed_id exists.
miro.frontends.widgets.widgetutil.get_feed_info(feed_id)
Returns the FeedInfo object for a given feed_id regardless of whether it’s an audio or video feed.
miro.frontends.widgets.widgetutil.pad(widget, top=0, bottom=0, left=0, right=0)
Wrap a widget in an Alignment that will pad it.
miro.frontends.widgets.widgetutil.round_rect(context, x, y, width, height, edge_radius)
Specifies path of a rectangle with rounded corners.
miro.frontends.widgets.widgetutil.round_rect_reverse(context, x, y, width, height, edge_radius)

Specifies path of a rectangle with rounded corners.

This specifies the rectangle in a counter-clockwise fashion.

window - main window code

miro.frontends.widgets.window – Main Miro widget.

class miro.frontends.widgets.window.MiroWindow(title, rect)

The main Miro Window.

set_main_area(widget)
Sets the main area to specified widget.
class miro.frontends.widgets.window.WidgetHolder

Widget used to hold a single child widget.

set(widget)
Sets the child to the specified widget.
unset()
Removes the child widget from the widgetholder.