2011-01-12 Dimitri Glazkov <dglazkov@chromium.org>
[WebKit.git] / Source / WebCore / html / shadow / SliderThumbElement.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3  * Copyright (C) 2010 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32
33 #include "config.h"
34 #include "SliderThumbElement.h"
35
36 #include "Event.h"
37 #include "Frame.h"
38 #include "MouseEvent.h"
39 #include "RenderSlider.h"
40 #include "RenderTheme.h"
41
42 namespace WebCore {
43
44 // FIXME: Find a way to cascade appearance (see the layout method) and get rid of this class.
45 class RenderSliderThumb : public RenderBlock {
46 public:
47     RenderSliderThumb(Node*);
48     virtual void layout();
49 };
50
51
52 RenderSliderThumb::RenderSliderThumb(Node* node)
53     : RenderBlock(node)
54 {
55 }
56
57 void RenderSliderThumb::layout()
58 {
59     // FIXME: Hard-coding this cascade of appearance is bad, because it's something
60     // that CSS usually does. We need to find a way to express this in CSS.
61     RenderStyle* parentStyle = parent()->style();
62     if (parentStyle->appearance() == SliderVerticalPart)
63         style()->setAppearance(SliderThumbVerticalPart);
64     else if (parentStyle->appearance() == SliderHorizontalPart)
65         style()->setAppearance(SliderThumbHorizontalPart);
66     else if (parentStyle->appearance() == MediaSliderPart)
67         style()->setAppearance(MediaSliderThumbPart);
68     else if (parentStyle->appearance() == MediaVolumeSliderPart)
69         style()->setAppearance(MediaVolumeSliderThumbPart);
70
71     if (style()->hasAppearance()) {
72         // FIXME: This should pass the style, not the renderer, to the theme.
73         theme()->adjustSliderThumbSize(this);
74     }
75     RenderBlock::layout();
76 }
77
78 RenderObject* SliderThumbElement::createRenderer(RenderArena* arena, RenderStyle*)
79 {
80     return new (arena) RenderSliderThumb(this);
81 }
82
83 void SliderThumbElement::defaultEventHandler(Event* event)
84 {
85     if (!event->isMouseEvent()) {
86         HTMLDivElement::defaultEventHandler(event);
87         return;
88     }
89
90     MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
91     bool isLeftButton = mouseEvent->button() == LeftButton;
92     const AtomicString& eventType = event->type();
93
94     if (eventType == eventNames().mousedownEvent && isLeftButton) {
95         if (document()->frame() && renderer()) {
96             RenderSlider* slider = toRenderSlider(renderer()->parent());
97             if (slider) {
98                 if (slider->mouseEventIsInThumb(mouseEvent)) {
99                     // We selected the thumb, we want the cursor to always stay at
100                     // the same position relative to the thumb.
101                     m_offsetToThumb = slider->mouseEventOffsetToThumb(mouseEvent);
102                 } else {
103                     // We are outside the thumb, move the thumb to the point were
104                     // we clicked. We'll be exactly at the center of the thumb.
105                     m_offsetToThumb.setX(0);
106                     m_offsetToThumb.setY(0);
107                 }
108
109                 m_inDragMode = true;
110                 document()->frame()->eventHandler()->setCapturingMouseEventsNode(shadowHost());
111                 event->setDefaultHandled();
112                 return;
113             }
114         }
115     } else if (eventType == eventNames().mouseupEvent && isLeftButton) {
116         if (m_inDragMode) {
117             if (Frame* frame = document()->frame())
118                 frame->eventHandler()->setCapturingMouseEventsNode(0);      
119             m_inDragMode = false;
120             event->setDefaultHandled();
121             return;
122         }
123     } else if (eventType == eventNames().mousemoveEvent) {
124         if (m_inDragMode && renderer() && renderer()->parent()) {
125             RenderSlider* slider = toRenderSlider(renderer()->parent());
126             if (slider) {
127                 FloatPoint curPoint = slider->absoluteToLocal(mouseEvent->absoluteLocation(), false, true);
128                 IntPoint eventOffset(curPoint.x() + m_offsetToThumb.x(), curPoint.y() + m_offsetToThumb.y());
129                 slider->setValueForPosition(slider->positionForOffset(eventOffset));
130                 event->setDefaultHandled();
131                 return;
132             }
133         }
134     }
135
136     HTMLDivElement::defaultEventHandler(event);
137 }
138
139 void SliderThumbElement::detach()
140 {
141     if (m_inDragMode) {
142         if (Frame* frame = document()->frame())
143             frame->eventHandler()->setCapturingMouseEventsNode(0);      
144     }
145     HTMLDivElement::detach();
146 }
147
148 }
149