1/*
2 * Copyright (C) 2013 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26WebInspector.Slider = function()
27{
28    this._element = document.createElement("div");
29    this._element.className = "slider";
30
31    this._knob = this._element.appendChild(document.createElement("img"));
32
33    this._value = 0;
34    this._knobX = 0;
35    this.__maxX = 0;
36
37    this._element.addEventListener("mousedown", this);
38};
39
40WebInspector.Slider.KnobWidth = 13;
41
42WebInspector.Slider.prototype = {
43    contructor: WebInspector.Slider,
44    __proto__: WebInspector.Object.prototype,
45
46    // Public
47
48    get element()
49    {
50        return this._element;
51    },
52
53    get value()
54    {
55        return this._value;
56    },
57
58    set value(value)
59    {
60        value = Math.max(Math.min(value, 1), 0);
61
62        if (value === this._value)
63            return;
64
65        this._value = value;
66
67        this._knobX = Math.round(value * this._maxX);
68        this._knob.style.webkitTransform = "translate3d(" + this._knobX + "px, 0, 0)";
69
70        if (this.delegate && typeof this.delegate.sliderValueDidChange === "function")
71            this.delegate.sliderValueDidChange(this, value);
72    },
73
74    // Protected
75
76    handleEvent: function(event)
77    {
78        switch (event.type) {
79        case "mousedown":
80            this._handleMousedown(event);
81            break;
82        case "mousemove":
83            this._handleMousemove(event);
84            break;
85        case "mouseup":
86            this._handleMouseup(event);
87            break;
88        }
89    },
90
91    // Private
92
93    _handleMousedown: function(event)
94    {
95        if (event.target !== this._knob)
96            this.value = (this._localPointForEvent(event).x - 3) / this._maxX;
97
98        this._startKnobX = this._knobX;
99        this._startMouseX = this._localPointForEvent(event).x;
100
101        this._element.classList.add("dragging");
102
103        window.addEventListener("mousemove", this, true);
104        window.addEventListener("mouseup", this, true);
105    },
106
107    _handleMousemove: function(event)
108    {
109        var dx = this._localPointForEvent(event).x - this._startMouseX;
110        var x = Math.max(Math.min(this._startKnobX + dx, this._maxX), 0);
111
112        this.value = x / this._maxX;
113    },
114
115    _handleMouseup: function(event)
116    {
117        this._element.classList.remove("dragging");
118
119        window.removeEventListener("mousemove", this, true);
120        window.removeEventListener("mouseup", this, true);
121    },
122
123    _localPointForEvent: function(event)
124    {
125        // We convert all event coordinates from page coordinates to local coordinates such that the slider
126        // may be transformed using CSS Transforms and interaction works as expected.
127        return window.webkitConvertPointFromPageToNode(this._element, new WebKitPoint(event.pageX, event.pageY));
128    },
129
130    get _maxX()
131    {
132        if (this.__maxX == 0 && document.body.contains(this._element))
133            this.__maxX = this._element.offsetWidth - Math.ceil(WebInspector.Slider.KnobWidth / 2);
134
135        return this.__maxX;
136    }
137};
138