"""
Shows how to implement a simple drag operation with transitory visual
side-effects that get cleaned up when the drag completes.  There is a
filled container that contains two filled circles, each of which has a
different kind of "shadow" object that it dynamically adds to the
container when the user clicks and drags the circle around.  Because
the shadow objects are "first-class" components in the filled container,
and because containers default to auto-sizing around their components,
the container stretches to the minimum bounding box of its components
as the user drags the circles around.
"""

from __future__ import with_statement

from numpy import array

from enable.example_support import DemoFrame, demo_main

from enable.api import Container, Component, Container, Pointer, str_to_font, Window

from traits.api import Any, Array, Enum, Float, Instance, Trait, Tuple


class MyFilledContainer(Container):

    fit_window = False
    border_width = 2
    resizable = ""
    _font = Any

    def _draw_container_mainlayer(self, gc, view_bounds, mode="default"):
        'Draws a filled container with the word "Container" in the center'
        if not self._font:
            self._font = str_to_font(None, None, "modern 10")

        with gc:
            gc.set_fill_color(self.bgcolor_)
            gc.rect(self.x, self.y, self.width, self.height)
            gc.draw_path()
            self._draw_border(gc)
            gc.set_font(self._font)
            gc.set_fill_color((1.0, 1.0, 1.0, 1.0))
            tx, ty, tw, th = gc.get_text_extent("Container")
            tx = self.x + self.width/2.0 - tw/2.0
            ty = self.y + self.height/2.0 - th/2.0
            gc.show_text_at_point("Container", tx, ty)

        return


class Circle(Component):
    """
    The circle moves with the mouse cursor but leaves a translucent version of
    itself in its original position until the mouse button is released.
    """

    color = (0.0, 0.0, 1.0, 1.0)
    bgcolor = "none"

    normal_pointer = Pointer("arrow")
    moving_pointer = Pointer("hand")

    prev_x = Float
    prev_y = Float

    shadow_type = Enum("light", "dashed")
    shadow = Instance(Component)

    resizable = ""

    def __init__(self, **traits):
        Component.__init__(self, **traits)
        self.pointer = self.normal_pointer
        return

    def _draw_mainlayer(self, gc, view_bounds=None, mode="default"):
        with gc:
            gc.set_fill_color(self.color)
            dx, dy = self.bounds
            x, y = self.position
            radius = min(dx/2.0, dy/2.0)
            gc.arc(x+dx/2.0, y+dy/2.0, radius, 0.0, 2*3.14159)
            gc.fill_path()
        return

    def normal_left_down(self, event):
        self.event_state = "moving"
        self.pointer = self.moving_pointer
        event.window.set_mouse_owner(self, event.net_transform())

        # Create our shadow
        if self.shadow_type == "light":
            klass = LightCircle
        else:
            klass = DashedCircle
        self.shadow = klass(bounds=self.bounds, position=self.position,
                            color=(1.0, 1.0, 1.0, 1.0))
        self.container.insert(0, self.shadow)
        x, y = self.position
        self.prev_x = event.x
        self.prev_y = event.y
        return

    def moving_mouse_move(self, event):
        self.position = [self.x + (event.x - self.prev_x),
                         self.y + (event.y - self.prev_y)]
        self.prev_x = event.x
        self.prev_y = event.y
        self.request_redraw()
        return

    def moving_left_up(self, event):
        self.event_state = "normal"
        self.pointer = self.normal_pointer
        event.window.set_mouse_owner(None)
        event.window.redraw()
        # Remove our shadow
        self.container.remove(self.shadow)
        return

    def moving_mouse_leave(self, event):
        self.moving_left_up(event)
        return


class LightCircle(Component):

    color = Tuple
    bgcolor = "none"
    radius = Float(1.0)
    resizable = ""

    def _draw_mainlayer(self, gc, view_bounds=None, mode="default"):
        with gc:
            gc.set_fill_color(self.color[0:3] + (self.color[3]*0.3,))
            dx, dy = self.bounds
            x, y = self.position
            radius = min(dx/2.0, dy/2.0)
            gc.arc(x+dx/2.0, y+dy/2.0, radius, 0.0, 2*3.14159)
            gc.fill_path()
        return

class DashedCircle(Component):

    color = Tuple
    bgcolor = "none"
    radius = Float(1.0)
    line_dash = array([2.0, 2.0])
    resizable = ""

    def _draw_mainlayer(self, gc, view_bounds=None, mode="default"):
        with gc:
            gc.set_fill_color(self.color)
            dx, dy = self.bounds
            x, y = self.position
            radius = min(dx/2.0, dy/2.0)
            gc.arc(x+dx/2.0, y+dy/2.0, radius, 0.0, 2*3.14159)
            gc.set_stroke_color(self.color[0:3] + (self.color[3]*0.8,))
            gc.set_line_dash(self.line_dash)
            gc.stroke_path()
        return


class MyFrame(DemoFrame):
    def _create_window(self):
        circle1 = Circle(bounds=[75,75], position=[50, 50], shadow_type="dashed")
        circle2 = Circle(bounds=[75,75], position=[200, 50], shadow_type="light")
        container = MyFilledContainer(bounds=[500,500], bgcolor=(0.2, 0.4, 0.3, 1.0))
        container.auto_size = True
        container.add(circle1)
        container.add(circle2)
        return Window(self, -1, component=container)

if __name__ == "__main__":
    demo_main(MyFrame, title="Click and drag to move the circles")

# EOF
