Esempio n. 1
0
    layer_a.add_constraint(Clutter.AlignConstraint(source=stage, align_axis=Clutter.AlignAxis.BOTH, factor=0.5))

    # Second actor, with no explicit size
    layer_b = Clutter.Actor()
    layer_b.props.background_color = Clutter.Color.get_static(Clutter.StaticColor.BUTTER_DARK)
    stage.add_child(layer_b)

    # The second actor tracks the X coordinate and the width of the first actor
    layer_b.add_constraint(Clutter.BindConstraint(source=layer_a, coordinate=Clutter.BindCoordinate.X))
    layer_b.add_constraint(Clutter.BindConstraint(source=layer_a, coordinate=Clutter.BindCoordinate.WIDTH))

    # The second actor is snapped between the bottom edge of the first actor
    # and the bottom edge of the stage; vertical spacing of 10px is added for
    # padding
    layer_b.add_constraint(Clutter.SnapConstraint(source=layer_a,
                                                  from_edge=Clutter.SnapEdge.TOP,
                                                  to_edge=Clutter.SnapEdge.BOTTOM,
                                                  offset=10))
    layer_b.add_constraint(Clutter.SnapConstraint(source=stage,
                                                  from_edge=Clutter.SnapEdge.BOTTOM,
                                                  to_edge=Clutter.SnapEdge.BOTTOM,
                                                  offset=-10))

    # The third actor, again with no explicit size
    layer_c = Clutter.Actor()
    layer_c.props.background_color = Clutter.Color.get_static(Clutter.StaticColor.CHAMELEON_LIGHT)
    stage.add_child(layer_c)

    # Like the second actor, the third one also track the X coordinate and
    # width of the first actor
    layer_c.add_constraint(Clutter.BindConstraint(source=layer_a, coordinate=Clutter.BindCoordinate.X))
    layer_c.add_constraint(Clutter.BindConstraint(source=layer_a, coordinate=Clutter.BindCoordinate.WIDTH))
Esempio n. 2
0
    def init_draggable_handles(self):
        # Setup the four handles on the cropbox's corners. These are inset into the corners
        # of the cropbox, and don't actually spill over onto the image stage; the illusion
        # of their outward-facing corners overlapping the stage is made by offsetting the
        # opaque squares slightly onto the cropbox
        handles = []
        coordinates = [TOP | LEFT, TOP | RIGHT, BOT | LEFT, BOT | RIGHT]

        for coordinate in coordinates:
            handle = DraggableHandle(self, coordinate)

            # Each handle has four constraints:
            #   horiz_constraint: binds the handle to the cropbox's top/bottom sides
            #   vert_constraint: binds the handle to the cropbox's left/right sides
            #   width_constraint: binds the handle such that its width stays constant
            #   height_constraint: binds the handle such that its height stays constant
            #
            # The height/width constraints are set by binding the opposite side of the handle
            # that horiz/vert constraints bind (respectively) to the same edge of the cropbox,
            # and setting an offset equal to the desired height/width. The handle's hitbox is
            # constrainted by position to the handle image

            horiz_constraint = Clutter.SnapConstraint()
            horiz_constraint.set_source(self)
            vert_constraint = Clutter.SnapConstraint()
            vert_constraint.set_source(self)

            height_constraint = Clutter.SnapConstraint()
            height_constraint.set_source(self)
            width_constraint = Clutter.SnapConstraint()
            width_constraint.set_source(self)

            hitbox_pos_constraint = Clutter.BindConstraint()
            hitbox_pos_constraint.set_source(handle.current_knob)
            hitbox_pos_constraint.set_offset(4)
            hitbox_pos_constraint.set_coordinate(
                Clutter.BindCoordinate.POSITION)

            offset = handle.get_offset()
            if coordinate & TOP:
                horiz_constraint.set_edges(CLUTTER_EDGES[TOP],
                                           CLUTTER_EDGES[TOP])
                height_constraint.set_edges(CLUTTER_EDGES[BOT],
                                            CLUTTER_EDGES[TOP])
                horiz_constraint.set_offset(BORDER_THICKNESS / 2 - offset)
                height_constraint.set_offset(BORDER_THICKNESS / 2 - offset)
            else:
                horiz_constraint.set_edges(CLUTTER_EDGES[BOT],
                                           CLUTTER_EDGES[BOT])
                height_constraint.set_edges(CLUTTER_EDGES[TOP],
                                            CLUTTER_EDGES[BOT])
                horiz_constraint.set_offset(-(BORDER_THICKNESS / 2 + offset))
                height_constraint.set_offset(-(BORDER_THICKNESS / 2 + offset))

            if coordinate & LEFT:
                vert_constraint.set_edges(CLUTTER_EDGES[LEFT],
                                          CLUTTER_EDGES[LEFT])
                width_constraint.set_edges(CLUTTER_EDGES[RIGHT],
                                           CLUTTER_EDGES[LEFT])
                vert_constraint.set_offset(BORDER_THICKNESS / 2 - offset)
                width_constraint.set_offset(BORDER_THICKNESS / 2 - offset)
            else:
                vert_constraint.set_edges(CLUTTER_EDGES[RIGHT],
                                          CLUTTER_EDGES[RIGHT])
                width_constraint.set_edges(CLUTTER_EDGES[LEFT],
                                           CLUTTER_EDGES[RIGHT])
                vert_constraint.set_offset(-(BORDER_THICKNESS / 2 + offset))
                width_constraint.set_offset(-(BORDER_THICKNESS / 2 + offset))

            handle.add_constraint(height_constraint)
            handle.add_constraint(width_constraint)
            handle.add_constraint(horiz_constraint)
            handle.add_constraint(vert_constraint)
            handle.hitbox.add_constraint(hitbox_pos_constraint)

            handles.append(handle)

        return handles
Esempio n. 3
0
    def init_surrounding_squares(self):
        # Setup the four opaque squares which cover the part
        # of the photo which isn't in the crop box
        squares = []
        coordinates = [TOP, BOT, LEFT, RIGHT]

        # Roughly, the stage looks like this:
        # +---------------------+
        # |         TOP         |
        # |---------------------|
        # | LEFT | CROP | RIGHT |
        # |---------------------|
        # |         BOT         |
        # +---------------------+
        # Each box (except for CROP) is bound by their respective
        # edge of the CROP box (i.e. RIGHT's left side is bound to
        # CROP's right side), as well as adjacent sides of the clutter
        # stage

        for coordinate in coordinates:
            square = Clutter.Actor()
            square.set_reactive(True)
            square.set_background_color(BACKGROUND_COLOR)
            square.set_opacity(BACKGROUND_OPACITY)

            if coordinate & TOP or coordinate & BOT:
                # Both the TOP and BOT squares are bound on their right
                # side to the right side of the stage; likewise for left
                right_constraint = Clutter.SnapConstraint()
                right_constraint.set_source(self.stage)
                right_constraint.set_edges(CLUTTER_EDGES[RIGHT],
                                           CLUTTER_EDGES[RIGHT])

                left_constraint = Clutter.SnapConstraint()
                left_constraint.set_source(self.stage)
                left_constraint.set_edges(CLUTTER_EDGES[LEFT],
                                          CLUTTER_EDGES[LEFT])

                square.add_constraint(left_constraint)
                square.add_constraint(right_constraint)

            if coordinate & LEFT or coordinate & RIGHT:
                # The LEFT and RIGHT squares have their top and bottom edges
                # bound to the top and bottom edges of the CROP box
                top_constraint = Clutter.SnapConstraint()
                top_constraint.set_source(self)
                top_constraint.set_edges(CLUTTER_EDGES[TOP],
                                         CLUTTER_EDGES[TOP])

                bot_constraint = Clutter.SnapConstraint()
                bot_constraint.set_source(self)
                bot_constraint.set_edges(CLUTTER_EDGES[BOT],
                                         CLUTTER_EDGES[BOT])

                square.add_constraint(top_constraint)
                square.add_constraint(bot_constraint)

            # All the boxes have their namesake's edge bound to the same
            # named edge of the stage, and have the opposite side bound to their
            # namesake's edge of CROP.
            #
            # For example, LEFT's left side is bound to the left edge of
            # the stage, and LEFT's right side is bound to the left side of CROP

            cropbox_constraint = Clutter.SnapConstraint()
            cropbox_constraint.set_source(self)
            cropbox_constraint.set_edges(
                CLUTTER_EDGES[self.opposing_side(coordinate)],
                CLUTTER_EDGES[coordinate])

            stage_constraint = Clutter.SnapConstraint()
            stage_constraint.set_source(self.stage)
            stage_constraint.set_edges(CLUTTER_EDGES[coordinate],
                                       CLUTTER_EDGES[coordinate])

            square.add_constraint(cropbox_constraint)
            square.add_constraint(stage_constraint)

            squares.append(square)

        return squares
Esempio n. 4
0
    def init_draggable_borders(self):
        # Setup the borders which lay between the draggable handles
        borders = []
        coordinates = [TOP, BOT, LEFT, RIGHT]

        for coordinate in coordinates:
            border_wrapper = DraggableBorder(self, coordinate)
            border = border_wrapper.line
            border_hitbox = border_wrapper.hitbox

            # Each border has four constraints:
            #   cropbox_edge_constraint: binds the border's x/y position to the respective edge
            #       of the cropbox
            #   thickness_constraint: binds the height/width of the border to the same edge, in
            #       order to maintain a constant thickness
            #   length_constraint (1 & 2): these two bind the two loose ends of the border to the
            #       cropbox's corners
            # Its hitbox is constrained in the same fashion as its length_constraints, but also has
            # a positional constraint to the border
            cropbox_edge_constraint = Clutter.SnapConstraint()
            cropbox_edge_constraint.set_source(self)
            thickness_constraint = Clutter.SnapConstraint()
            thickness_constraint.set_source(self)

            wrapper_constraint_1 = Clutter.SnapConstraint()
            wrapper_constraint_1.set_source(self)
            wrapper_constraint_2 = Clutter.SnapConstraint()
            wrapper_constraint_2.set_source(self)
            wrapper_pos_constraint = Clutter.BindConstraint()
            wrapper_pos_constraint.set_source(border)
            length_constraint_1 = Clutter.SnapConstraint()
            length_constraint_1.set_source(self)
            length_constraint_2 = Clutter.SnapConstraint()
            length_constraint_2.set_source(self)

            if coordinate & TOP or coordinate & LEFT:
                thickness_offset = border_wrapper.get_offset()
            else:
                thickness_offset = -border_wrapper.get_offset()

            cropbox_edge_constraint.set_edges(CLUTTER_EDGES[coordinate],
                                              CLUTTER_EDGES[coordinate])

            thickness_constraint.set_edges(
                CLUTTER_EDGES[self.opposing_side(coordinate)],
                CLUTTER_EDGES[coordinate])
            thickness_constraint.set_offset(thickness_offset)

            wrapper_pos_constraint.set_coordinate(
                Clutter.BindCoordinate.POSITION)
            wrapper_pos_constraint.set_offset(-MARGIN / 2)

            if coordinate & TOP or coordinate & BOT:
                length_constraint_1.set_edges(CLUTTER_EDGES[LEFT],
                                              CLUTTER_EDGES[LEFT])
                length_constraint_2.set_edges(CLUTTER_EDGES[RIGHT],
                                              CLUTTER_EDGES[RIGHT])
                wrapper_constraint_1.set_edges(CLUTTER_EDGES[LEFT],
                                               CLUTTER_EDGES[LEFT])
                wrapper_constraint_2.set_edges(CLUTTER_EDGES[RIGHT],
                                               CLUTTER_EDGES[RIGHT])
                border_hitbox.set_height(MARGIN)
            else:
                length_constraint_1.set_edges(CLUTTER_EDGES[TOP],
                                              CLUTTER_EDGES[TOP])
                length_constraint_2.set_edges(CLUTTER_EDGES[BOT],
                                              CLUTTER_EDGES[BOT])
                wrapper_constraint_1.set_edges(CLUTTER_EDGES[TOP],
                                               CLUTTER_EDGES[TOP])
                wrapper_constraint_2.set_edges(CLUTTER_EDGES[BOT],
                                               CLUTTER_EDGES[BOT])
                border_hitbox.set_width(MARGIN)

            border.add_constraint(cropbox_edge_constraint)
            border.add_constraint(thickness_constraint)
            border.add_constraint(length_constraint_1)
            border.add_constraint(length_constraint_2)
            border_hitbox.add_constraint(wrapper_constraint_1)
            border_hitbox.add_constraint(wrapper_constraint_2)
            border_hitbox.add_constraint(wrapper_pos_constraint)

            borders.append(border_wrapper)

        return borders