diff options
author | Jesús Eduardo <heckyel@hyperbola.info> | 2017-05-31 18:08:31 -0500 |
---|---|---|
committer | Jesús Eduardo <heckyel@hyperbola.info> | 2017-05-31 18:08:31 -0500 |
commit | e1180428ed3e7634fe1596103511fbb1da05f228 (patch) | |
tree | 13de9592bcde7050b089b9644839668024c518b3 /mvc/widgets/widgetutil.py | |
download | librevideoconverter-e1180428ed3e7634fe1596103511fbb1da05f228.tar.lz librevideoconverter-e1180428ed3e7634fe1596103511fbb1da05f228.tar.xz librevideoconverter-e1180428ed3e7634fe1596103511fbb1da05f228.zip |
first commit
Diffstat (limited to 'mvc/widgets/widgetutil.py')
-rw-r--r-- | mvc/widgets/widgetutil.py | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/mvc/widgets/widgetutil.py b/mvc/widgets/widgetutil.py new file mode 100644 index 0000000..5fb3db2 --- /dev/null +++ b/mvc/widgets/widgetutil.py @@ -0,0 +1,225 @@ +from math import pi as PI +from mvc.widgets import widgetset +from mvc.resources import image_path + +def make_surface(image_name, height=None): + path = image_path(image_name + '.png') + image = widgetset.Image(path) + if height is not None: + image = image.resize(image.width, height) + return widgetset.ImageSurface(image) + +def font_scale_from_osx_points(points): + """Create a font scale so that it's points large on OS X. + + Assumptions (these should be true for OS X) + - the default font size is 13pt + - the DPI is 72ppi + """ + return points / 13.0 + +def css_to_color(css_string): + parts = (css_string[1:3], css_string[3:5], css_string[5:7]) + return tuple((int(value, 16) / 255.0) for value in parts) + +def 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. + """ + alignment = widgetset.Alignment(xalign, yalign, xscale, yscale, + top_pad, bottom_pad, left_pad, right_pad) + alignment.add(widget) + return alignment + +def 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. + """ + return align(widget, 0.5, 0, 0, 1, + top_pad, bottom_pad, left_pad, right_pad) + +def 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. + """ + return align(widget, 1, 0, 0, 1, top_pad, bottom_pad, left_pad, right_pad) + +def 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. + """ + return align(widget, 0, 0, 0, 1, top_pad, bottom_pad, left_pad, right_pad) + +def 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. + """ + return align(widget, 0, 0.5, 1, 0, + top_pad, bottom_pad, left_pad, right_pad) + +def 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. + """ + return align(widget, 0, 0, 1, 0, top_pad, bottom_pad, left_pad, right_pad) + +def 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. + """ + return align(widget, 0, 1, 1, 0, top_pad, bottom_pad, left_pad, right_pad) + +def pad(widget, top=0, bottom=0, left=0, right=0): + """Wrap a widget in an Alignment that will pad it. + """ + alignment = widgetset.Alignment(0, 0, 1, 1, + top, bottom, left, right) + alignment.add(widget) + return alignment + +def round_rect(context, x, y, width, height, edge_radius): + """Specifies path of a rectangle with rounded corners. + """ + edge_radius = min(edge_radius, min(width, height)/2.0) + inner_width = width - edge_radius*2 + inner_height = height - edge_radius*2 + x_inner1 = x + edge_radius + x_inner2 = x + width - edge_radius + y_inner1 = y + edge_radius + y_inner2 = y + height - edge_radius + + context.move_to(x+edge_radius, y) + context.rel_line_to(inner_width, 0) + context.arc(x_inner2, y_inner1, edge_radius, -PI/2, 0) + context.rel_line_to(0, inner_height) + context.arc(x_inner2, y_inner2, edge_radius, 0, PI/2) + context.rel_line_to(-inner_width, 0) + context.arc(x_inner1, y_inner2, edge_radius, PI/2, PI) + context.rel_line_to(0, -inner_height) + context.arc(x_inner1, y_inner1, edge_radius, PI, PI*3/2) + +def 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. + """ + edge_radius = min(edge_radius, min(width, height)/2.0) + inner_width = width - edge_radius*2 + inner_height = height - edge_radius*2 + x_inner1 = x + edge_radius + x_inner2 = x + width - edge_radius + y_inner1 = y + edge_radius + y_inner2 = y + height - edge_radius + + context.move_to(x+edge_radius, y) + context.arc_negative(x_inner1, y_inner1, edge_radius, PI*3/2, PI) + context.rel_line_to(0, inner_height) + context.arc_negative(x_inner1, y_inner2, edge_radius, PI, PI/2) + context.rel_line_to(inner_width, 0) + context.arc_negative(x_inner2, y_inner2, edge_radius, PI/2, 0) + context.rel_line_to(0, -inner_height) + context.arc_negative(x_inner2, y_inner1, edge_radius, 0, -PI/2) + context.rel_line_to(-inner_width, 0) + +def circular_rect(context, x, y, width, height): + """Make a path for a rectangle with the left/right side being circles. + """ + radius = height / 2.0 + inner_width = width - height + inner_y = y + radius + inner_x1 = x + radius + inner_x2 = inner_x1 + inner_width + + context.move_to(inner_x1, y) + context.rel_line_to(inner_width, 0) + context.arc(inner_x2, inner_y, radius, -PI/2, PI/2) + context.rel_line_to(-inner_width, 0) + context.arc(inner_x1, inner_y, radius, PI/2, -PI/2) + +def circular_rect_negative(context, x, y, width, height): + """The same path as ``circular_rect()``, but going counter clockwise. + """ + radius = height / 2.0 + inner_width = width - height + inner_y = y + radius + inner_x1 = x + radius + inner_x2 = inner_x1 + inner_width + + context.move_to(inner_x1, y) + context.arc_negative(inner_x1, inner_y, radius, -PI/2, PI/2) + context.rel_line_to(inner_width, 0) + context.arc_negative(inner_x2, inner_y, radius, PI/2, -PI/2) + context.rel_line_to(-inner_width, 0) + +class Shadow(object): + """Encapsulates all parameters required to draw shadows. + """ + def __init__(self, color, opacity, offset, blur_radius): + self.color = color + self.opacity = opacity + self.offset = offset + self.blur_radius = blur_radius + +class ThreeImageSurface(object): + """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. + """ + def __init__(self, basename=None, height=None): + self.left = self.center = self.right = None + self.height = 0 + self.width = None + if basename is not None: + left = make_surface(basename + '_left', height) + center = make_surface(basename + '_center', height) + right = make_surface(basename + '_right', height) + self.set_images(left, center, right) + + def set_images(self, left, center, right): + """Sets the left, center and right images to use. + """ + self.left = left + self.center = center + self.right = right + if not (self.left.height == self.center.height == self.right.height): + raise ValueError("Images aren't the same height") + self.height = self.left.height + + def set_width(self, width): + """Manually set a width. + + When ThreeImageSurface have a width, then they have pretty much the + same API as ImageSurface does. In particular, they can now be nested + in another ThreeImageSurface. + """ + self.width = width + + def get_size(self): + return self.width, self.height + + def draw(self, context, x, y, width, fraction=1.0): + left_width = min(self.left.width, width) + self.left.draw(context, x, y, left_width, self.height, fraction) + self.draw_right(context, x + left_width, y, width - left_width, fraction) + + def draw_right(self, context, x, y, width, fraction=1.0): + # draws only the right two images + + right_width = min(self.right.width, width) + center_width = int(width - right_width) + + self.center.draw(context, x, y, center_width, self.height, fraction) + self.right.draw(context, x + center_width, y, right_width, self.height, fraction) |