JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
cleanup hover/filter stuff
[crayon_mockup.git] / auto.coffee
index 63870d5..2bd4bfa 100644 (file)
@@ -12,6 +12,17 @@ STYLE_HOVER = 2
 STYLE_EDITING = 3
 STYLE_DRAGGING = 4
 
+STYLE_TO_CLASS = [
+       "normal"
+       "selected"
+       "hover"
+       "editing"
+       "dragging"
+]
+
+set_style_class = (args) ->
+       args.el.setAttribute 'class', "#{args.class} #{STYLE_TO_CLASS[args.style]}"
+
 # json (compiled to javascript and minified) is ~8% smaller than the resulting xml
 json_to_svg = (json) ->
        for tag, attrs of json
@@ -20,49 +31,40 @@ json_to_svg = (json) ->
                        if k is 'children'
                                for child in v
                                        el.appendChild json_to_svg child
+                       else if k is 'contents'
+                               el.appendChild document.createTextNode v
                        else
                                el.setAttribute k, v
        return el
 
 next_widget_id = 0
 # public vars: x, y, width, height, el
-class Widget
+class Visible
        # required args: svg
        constructor: (args) ->
                @id = next_widget_id
                next_widget_id += 1
                @svg = args.svg
-               @style = args.style ? STYLE_NORMAL
                @x = args.x ? 1
                @y = args.y ? 1
                @width = args.width ? 50
                @height = args.height ? 34
+               @style = args.style ? STYLE_NORMAL
        destruct: ->
-       clone: ->
-               return new Widget @
        move: (args) ->
                @x = args.x
                @y = args.y
        proximity: (xy) -> # return the square of the distance to your visible bits
                return PROX_MAX + 1
        set_style: (style) ->
-               return if @style is style
-               if style is STYLE_NORMAL
-                       @el.setAttribute 'style', 'filter: url(#crayon)'
-               else
-                       if @style is STYLE_NORMAL
-                               @el.setAttribute 'style', ''
-               switch style
-                       when STYLE_NORMAL
-                               @el.setAttribute 'class', "#{@css_class}"
-                       when STYLE_SELECTED
-                               @el.setAttribute 'class', "#{@css_class} selected"
-                       when STYLE_HOVER
-                               @el.setAttribute 'class', "#{@css_class} hover"
-                       when STYLE_DRAGGING
-                               @el.setAttribute 'class', "#{@css_class} dragging"
-                       # FIXME when STYLE_EDITING
                @style = style
+
+class Control extends Visible
+
+class Widget extends Visible
+       #sub-classes are expected to implement all of these:
+       clone: ->
+               return new Widget @
        controls: -> # create controls, return them
                return []
        hide_controls: ->
@@ -76,14 +78,17 @@ class RectWidget extends Widget
                        y: @y + 1
                        width: @width - 2
                        height: @height - 2
-                       class: 'box'
-                       style: if @style is STYLE_NORMAL then 'filter: url(#crayon)' else ''
+                       class: 'box normal'
                @svg.appendChild @el
        destruct: ->
+               super()
                if @el?
                        @svg.removeChild @el
        clone: ->
                return new RectWidget @
+       set_style: (style) ->
+               super style
+               set_style_class el: @el, class: 'box', style: style
        move: (args) ->
                super args
                @el.setAttribute 'x', @x + 1
@@ -133,6 +138,9 @@ init = ->
                        { feTurbulence: baseFrequency: '.3', numOctaves: '2', type: 'fractalNoise' }
                        { feDisplacementMap: scale: '6', xChannelSelector: 'R', in: 'SourceGraphic' }
                ]
+       svg.appendChild json_to_svg style:
+               type: 'text/css'
+               contents: '.box.normal,.box.hover,.box.selected{filter: url(#crayon)}'
 
        # create canvas border
        svg.appendChild json_to_svg rect:
@@ -141,41 +149,39 @@ init = ->
                width: width - 2
                height: height - 2 - supply_height
                class: 'canvas_border'
-       
-       supply = [
-               new RectWidget svg: svg
-               new RectWidget svg: svg, width: 12, height: 50
-               new RectWidget svg: svg, width: 70, height: 12
+
+       supply = {}
+       for args, i in [
+               { width: 40, height: 40 }
+               { width: 12, height: 50 }
+               { width: 70, height: 12 }
        ]
-       for widget, i in supply
-               widget.move {
-                       x: 30 + i * 90 + (70 - widget.width) / 2
-                       y: (supply_height - widget.height) / 2
+               widget = new RectWidget {
+                       width: args.width
+                       height: args.height
+                       x: 30 + i * 90 + (70 - args.width) / 2
+                       y: (supply_height - args.height) / 2
+                       svg: svg
                }
-       
+               supply[widget.id] = widget
+
        # editor state
-       on_canvas = []
-       selected = []
-       editing = [] # has controls
+       on_canvas = {}
+       selected = {}
+       editing = {} # has controls
        dragging = false
-       dragging_offset = x: 0, y: 0 # from mouse x,y -> widget x,y
+       drag_from = x: 0, y: 0 # mouse was here at last frame of drag
+       shift_key_down = false
 
        deselect_all = (args) ->
                except = args?.except ? null
-               found = false
-               for w in selected
-                       if w is except
-                               found = true
-                       else
-                               w.set_style STYLE_NORMAL
-               if found
-                       selected = [except]
-               else
-                       selected = []
+               for id, w of selected
+                       w.set_style STYLE_NORMAL
+                       delete selected[id]
        closest_widget = (widgets, xy) ->
                prox = PROX_MAX + 1
                closest = null
-               for w in widgets
+               for id, w of widgets
                        new_prox = w.proximity xy
                        if new_prox < prox
                                prox = new_prox
@@ -199,25 +205,26 @@ init = ->
                        closest = closest_widget supply, xy
                        if closest?
                                closest = closest.clone()
-                               on_canvas.push closest
+                               on_canvas[closest.id] = closest
                else
                        closest = closest_widget on_canvas, xy
                if closest?
-                       deselect_all except: closest
-                       selected = [closest]
+                       unless (shift_key_down or selected[closest.id]?)
+                               deselect_all except: closest
+                       selected[closest.id] = closest
                        closest.set_style STYLE_DRAGGING
                        dragging = true
-                       dragging_offset.x = closest.x - xy.x
-                       dragging_offset.y = closest.y - xy.y
+                       drag_from = xy
                else
                        deselect_all()
                return false
        mouseup = (e) ->
                mousemove e
                if dragging
-                       for w in selected
+                       for id, w of selected
                                if w.y < supply_height
                                        w.destruct()
+                                       delete selected[id]
                                else
                                        w.set_style STYLE_SELECTED
                dragging = false
@@ -226,30 +233,33 @@ init = ->
        mousemove = (e) ->
                xy = svg_event_to_xy e
                if dragging
-                       xy.x += dragging_offset.x
-                       xy.y += dragging_offset.y
-                       selected[0].move xy
+                       return if drag_from.x is xy.x and drag_from.y is xy.y
+                       rel_x = xy.x - drag_from.x
+                       rel_y = xy.y - drag_from.y
+                       drag_from = xy
+                       for id, w of selected
+                               w.move x: w.x + rel_x, y: w.y + rel_y
                else
                        hover = closest_widget on_canvas, xy
                        unless hover?
                                hover = closest_widget supply, xy
                        if hover != prev_hover
-                               prev_hover = hover
-                               for w in selected
-                                       if w.style is STYLE_HOVER and w isnt hover
-                                               w.set_style STYLE_SELECTED
-                               for w in supply
-                                       if w.style is STYLE_HOVER and w isnt hover
-                                               w.set_style STYLE_NORMAL
-                               for w in on_canvas
-                                       if w.style is STYLE_HOVER and w isnt hover
-                                               w.set_style STYLE_NORMAL
-                               if hover
+                               if prev_hover?
+                                       # FIXME
+                                       if selected[prev_hover.id]?
+                                               prev_hover.set_style STYLE_SELECTED
+                                       else
+                                               prev_hover.set_style STYLE_NORMAL
+                               if hover?
                                        hover.set_style STYLE_HOVER
+                               prev_hover = hover
                return false
        $svg.mousedown mousedown
        $svg.mouseup mouseup
        $svg.mousemove mousemove
+       $(document).on 'keyup keydown', (e) ->
+               shift_key_down = e.shiftKey
+               return true
        #($ document).keydown (e) ->
 
 $ init