Commit f989049f authored by adele's avatar adele
Browse files

Reviewed by Adam.

        Initial implementation of engine-based list box control.

        * WebCore.xcodeproj/project.pbxproj: Added RenderListBox.h and RenderListBox.cpp

        * bridge/mac/FrameMac.h: Added _mouseDownMayStartAutoscroll.
        * bridge/mac/FrameMac.mm: Updated autoscroll code to use renderers instead of layers, so any renderer that implements autoscroll will work.
        (WebCore::FrameMac::FrameMac):
        (WebCore::FrameMac::handleMousePressEvent):
        (WebCore::FrameMac::handleMouseMoveEvent):
        (WebCore::FrameMac::mouseDown):

        * page/Frame.cpp:
        (WebCore::Frame::handleMouseMoveEvent):
        (WebCore::Frame::scrollOverflow): Don't scroll list box here- this would cause arrow keys to scroll instead of select.
        (WebCore::Frame::handleAutoscroll): Updated to use a renderer instead of a layer when setting up autoscroll.
        (WebCore::Frame::autoscrollTimerFired): ditto.
        (WebCore::Frame::stopAutoscrollTimer): ditto.
        (WebCore::Frame::passWidgetMouseDownEventToWidget): Updated to check for list box's scroll bar.
        * page/Frame.h:
        * page/FramePrivate.h: (WebCore::FramePrivate::FramePrivate): Updated to use renderer unstead of layer for autoscroll.

        * page/FrameView.cpp: Keep track of current mouse position so this can be used for list box autoscroll.
        (WebCore::FrameViewPrivate::reset):
        (WebCore::FrameView::currentMousePosition):
        (WebCore::FrameView::handleMousePressEvent):
        (WebCore::FrameView::handleMouseDoubleClickEvent):
        (WebCore::selectCursor):
        (WebCore::FrameView::handleMouseMoveEvent):
        (WebCore::FrameView::handleMouseReleaseEvent):
        * page/FrameView.h:

        * platform/ScrollBar.cpp: (WebCore::ScrollBar::ScrollBar): Added controlSize argument.  The list box will use a smaller scroll bar size.
        * platform/ScrollBar.h:
        (WebCore::):
        (WebCore::ScrollBar::controlSize):
        * platform/mac/PlatformScrollBar.h:
        * platform/mac/PlatformScrollBarMac.mm:
        (NSControlSizeForScrollBarControlSize):
        (-[WebCoreScrollBar initWithPlatformScrollBar:]):
        (WebCore::PlatformScrollBar::PlatformScrollBar):

        * rendering/RenderBlock.h:
        * rendering/RenderLayer.cpp: (WebCore::RenderLayer::createScrollbar): Updated to pass regular control size to scrollbar constructor.
        * rendering/RenderLayer.h:
        * rendering/RenderObject.cpp:
        (WebCore::RenderObject::shouldAutoscroll):
        (WebCore::RenderObject::autoscroll):
        * rendering/RenderObject.h: (WebCore::RenderObject::isListBox):

        * css/html4.css: Added properties for new list boxes.

        * html/HTMLOptionElement.cpp:
        (WebCore::HTMLOptionElement::setSelected): Doesn't allow selection to be changed here if the option is disabled.
        (WebCore::HTMLOptionElement::disabled): Added. Checks the parent's disabled status.
        * html/HTMLOptionElement.h: Added disabled method.

        * html/HTMLSelectElement.cpp: Added appearance switch for new list box implementation.
        (WebCore::HTMLSelectElement::recalcStyle):
        (WebCore::HTMLSelectElement::lastSelectedListIndex):
        (WebCore::HTMLSelectElement::deselectItems):
        (WebCore::HTMLSelectElement::setSelectedIndex):
        (WebCore::HTMLSelectElement::isKeyboardFocusable):
        (WebCore::HTMLSelectElement::isMouseFocusable):
        (WebCore::HTMLSelectElement::createRenderer):
        (WebCore::HTMLSelectElement::recalcListItems):
        (WebCore::HTMLSelectElement::setRecalcListItems):
        (WebCore::HTMLSelectElement::reset):
        (WebCore::HTMLSelectElement::notifyOptionSelected):
        (WebCore::HTMLSelectElement::defaultEventHandler): Added code to select options for list box when clicking and using arrow keys.
        (WebCore::HTMLSelectElement::nextSelectableListIndex):
        (WebCore::HTMLSelectElement::previousSelectableListIndex):
        * html/HTMLSelectElement.h:

        * rendering/RenderTheme.cpp: Added support for ListBoxAppearance
        (WebCore::RenderTheme::paint):
        (WebCore::RenderTheme::paintBorderOnly):
        (WebCore::RenderTheme::paintDecorations):
        (WebCore::RenderTheme::activeListBoxSelectionBackgroundColor):
        (WebCore::RenderTheme::activeListBoxSelectionForegroundColor):
        (WebCore::RenderTheme::inactiveListBoxSelectionBackgroundColor):
        (WebCore::RenderTheme::inactiveListBoxSelectionForegroundColor):
        (WebCore::RenderTheme::isControlStyled):
        (WebCore::RenderTheme::supportsFocusRing):
        * rendering/RenderTheme.h:
        * rendering/RenderThemeMac.mm: (WebCore::RenderThemeMac::isControlStyled):

        * rendering/RenderListBox.cpp: Added.
        (WebCore::RenderListBox::RenderListBox):
        (WebCore::RenderListBox::~RenderListBox):
        (WebCore::RenderListBox::setStyle):
        (WebCore::RenderListBox::updateFromElement):
        (WebCore::RenderListBox::calcMinMaxWidth):
        (WebCore::RenderListBox::size):
        (WebCore::RenderListBox::numItems):
        (WebCore::RenderListBox::calcHeight):
        (WebCore::RenderListBox::baselinePosition):
        (WebCore::RenderListBox::itemBoundingBoxRect):
        (WebCore::RenderListBox::paintObject):
        (WebCore::RenderListBox::paintScrollbar):
        (WebCore::RenderListBox::paintItemForeground):
        (WebCore::RenderListBox::paintItemBackground):
        (WebCore::RenderListBox::scrollBarTarget):
        (WebCore::RenderListBox::isPointInScrollbar):
        (WebCore::RenderListBox::optionAtPoint):
        (WebCore::RenderListBox::autoscroll):
        (WebCore::RenderListBox::scrollToRevealElementAtListIndex):
        (WebCore::RenderListBox::scroll):
        (WebCore::RenderListBox::valueChanged):
        * rendering/RenderListBox.h: Added.
        (WebCore::RenderListBox::isListBox):
        (WebCore::RenderListBox::selectionChanged):
        (WebCore::RenderListBox::setSelectionChanged):
        (WebCore::RenderListBox::canHaveChildren):
        (WebCore::RenderListBox::renderName):
        (WebCore::RenderListBox::setOptionsChanged):
        (WebCore::RenderListBox::shouldAutoscroll):
        (WebCore::RenderListBox::listIndexIsVisible):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@16663 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 9d05e15f
2006-09-29 Adele Peterson <adele@apple.com>
Reviewed by Adam.
Initial implementation of engine-based list box control.
* WebCore.xcodeproj/project.pbxproj: Added RenderListBox.h and RenderListBox.cpp
* bridge/mac/FrameMac.h: Added _mouseDownMayStartAutoscroll.
* bridge/mac/FrameMac.mm: Updated autoscroll code to use renderers instead of layers, so any renderer that implements autoscroll will work.
(WebCore::FrameMac::FrameMac):
(WebCore::FrameMac::handleMousePressEvent):
(WebCore::FrameMac::handleMouseMoveEvent):
(WebCore::FrameMac::mouseDown):
* page/Frame.cpp:
(WebCore::Frame::handleMouseMoveEvent):
(WebCore::Frame::scrollOverflow): Don't scroll list box here- this would cause arrow keys to scroll instead of select.
(WebCore::Frame::handleAutoscroll): Updated to use a renderer instead of a layer when setting up autoscroll.
(WebCore::Frame::autoscrollTimerFired): ditto.
(WebCore::Frame::stopAutoscrollTimer): ditto.
(WebCore::Frame::passWidgetMouseDownEventToWidget): Updated to check for list box's scroll bar.
* page/Frame.h:
* page/FramePrivate.h: (WebCore::FramePrivate::FramePrivate): Updated to use renderer unstead of layer for autoscroll.
* page/FrameView.cpp: Keep track of current mouse position so this can be used for list box autoscroll.
(WebCore::FrameViewPrivate::reset):
(WebCore::FrameView::currentMousePosition):
(WebCore::FrameView::handleMousePressEvent):
(WebCore::FrameView::handleMouseDoubleClickEvent):
(WebCore::selectCursor):
(WebCore::FrameView::handleMouseMoveEvent):
(WebCore::FrameView::handleMouseReleaseEvent):
* page/FrameView.h:
* platform/ScrollBar.cpp: (WebCore::ScrollBar::ScrollBar): Added controlSize argument. The list box will use a smaller scroll bar size.
* platform/ScrollBar.h:
(WebCore::):
(WebCore::ScrollBar::controlSize):
* platform/mac/PlatformScrollBar.h:
* platform/mac/PlatformScrollBarMac.mm:
(NSControlSizeForScrollBarControlSize):
(-[WebCoreScrollBar initWithPlatformScrollBar:]):
(WebCore::PlatformScrollBar::PlatformScrollBar):
* rendering/RenderBlock.h:
* rendering/RenderLayer.cpp: (WebCore::RenderLayer::createScrollbar): Updated to pass regular control size to scrollbar constructor.
* rendering/RenderLayer.h:
* rendering/RenderObject.cpp:
(WebCore::RenderObject::shouldAutoscroll):
(WebCore::RenderObject::autoscroll):
* rendering/RenderObject.h: (WebCore::RenderObject::isListBox):
* css/html4.css: Added properties for new list boxes.
* html/HTMLOptionElement.cpp:
(WebCore::HTMLOptionElement::setSelected): Doesn't allow selection to be changed here if the option is disabled.
(WebCore::HTMLOptionElement::disabled): Added. Checks the parent's disabled status.
* html/HTMLOptionElement.h: Added disabled method.
* html/HTMLSelectElement.cpp: Added appearance switch for new list box implementation.
(WebCore::HTMLSelectElement::recalcStyle):
(WebCore::HTMLSelectElement::lastSelectedListIndex):
(WebCore::HTMLSelectElement::deselectItems):
(WebCore::HTMLSelectElement::setSelectedIndex):
(WebCore::HTMLSelectElement::isKeyboardFocusable):
(WebCore::HTMLSelectElement::isMouseFocusable):
(WebCore::HTMLSelectElement::createRenderer):
(WebCore::HTMLSelectElement::recalcListItems):
(WebCore::HTMLSelectElement::setRecalcListItems):
(WebCore::HTMLSelectElement::reset):
(WebCore::HTMLSelectElement::notifyOptionSelected):
(WebCore::HTMLSelectElement::defaultEventHandler): Added code to select options for list box when clicking and using arrow keys.
(WebCore::HTMLSelectElement::nextSelectableListIndex):
(WebCore::HTMLSelectElement::previousSelectableListIndex):
* html/HTMLSelectElement.h:
* rendering/RenderTheme.cpp: Added support for ListBoxAppearance
(WebCore::RenderTheme::paint):
(WebCore::RenderTheme::paintBorderOnly):
(WebCore::RenderTheme::paintDecorations):
(WebCore::RenderTheme::activeListBoxSelectionBackgroundColor):
(WebCore::RenderTheme::activeListBoxSelectionForegroundColor):
(WebCore::RenderTheme::inactiveListBoxSelectionBackgroundColor):
(WebCore::RenderTheme::inactiveListBoxSelectionForegroundColor):
(WebCore::RenderTheme::isControlStyled):
(WebCore::RenderTheme::supportsFocusRing):
* rendering/RenderTheme.h:
* rendering/RenderThemeMac.mm: (WebCore::RenderThemeMac::isControlStyled):
* rendering/RenderListBox.cpp: Added.
(WebCore::RenderListBox::RenderListBox):
(WebCore::RenderListBox::~RenderListBox):
(WebCore::RenderListBox::setStyle):
(WebCore::RenderListBox::updateFromElement):
(WebCore::RenderListBox::calcMinMaxWidth):
(WebCore::RenderListBox::size):
(WebCore::RenderListBox::numItems):
(WebCore::RenderListBox::calcHeight):
(WebCore::RenderListBox::baselinePosition):
(WebCore::RenderListBox::itemBoundingBoxRect):
(WebCore::RenderListBox::paintObject):
(WebCore::RenderListBox::paintScrollbar):
(WebCore::RenderListBox::paintItemForeground):
(WebCore::RenderListBox::paintItemBackground):
(WebCore::RenderListBox::scrollBarTarget):
(WebCore::RenderListBox::isPointInScrollbar):
(WebCore::RenderListBox::optionAtPoint):
(WebCore::RenderListBox::autoscroll):
(WebCore::RenderListBox::scrollToRevealElementAtListIndex):
(WebCore::RenderListBox::scroll):
(WebCore::RenderListBox::valueChanged):
* rendering/RenderListBox.h: Added.
(WebCore::RenderListBox::isListBox):
(WebCore::RenderListBox::selectionChanged):
(WebCore::RenderListBox::setSelectionChanged):
(WebCore::RenderListBox::canHaveChildren):
(WebCore::RenderListBox::renderName):
(WebCore::RenderListBox::setOptionsChanged):
(WebCore::RenderListBox::shouldAutoscroll):
(WebCore::RenderListBox::listIndexIsVisible):
2006-09-29 Beth Dakin <bdakin@apple.com>
 
Reviewed by Darin.
......@@ -1891,6 +1891,8 @@
AB4261D80A2F6C9700BDD17D /* missingImage.tiff in Resources */ = {isa = PBXBuildFile; fileRef = AB4261D70A2F6C9700BDD17D /* missingImage.tiff */; };
AB67D1A8097F3AE300F9392E /* RenderTextControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB67D1A6097F3AE300F9392E /* RenderTextControl.cpp */; };
AB67D1A9097F3AE300F9392E /* RenderTextControl.h in Headers */ = {isa = PBXBuildFile; fileRef = AB67D1A7097F3AE300F9392E /* RenderTextControl.h */; };
ABB5419E0ACDDFE4002820EB /* RenderListBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABB5419C0ACDDFE4002820EB /* RenderListBox.cpp */; };
ABB5419F0ACDDFE4002820EB /* RenderListBox.h in Headers */ = {isa = PBXBuildFile; fileRef = ABB5419D0ACDDFE4002820EB /* RenderListBox.h */; };
ABDDFE790A5C6E7000A3E11D /* RenderMenuList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABDDFE730A5C6E6F00A3E11D /* RenderMenuList.cpp */; };
ABDDFE7A0A5C6E7000A3E11D /* RenderMenuList.h in Headers */ = {isa = PBXBuildFile; fileRef = ABDDFE740A5C6E7000A3E11D /* RenderMenuList.h */; };
ABDDFE7B0A5C6E7000A3E11D /* RenderPopupMenu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABDDFE750A5C6E7000A3E11D /* RenderPopupMenu.cpp */; };
......@@ -4343,6 +4345,8 @@
AB4261D70A2F6C9700BDD17D /* missingImage.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = missingImage.tiff; sourceTree = "<group>"; };
AB67D1A6097F3AE300F9392E /* RenderTextControl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RenderTextControl.cpp; sourceTree = "<group>"; };
AB67D1A7097F3AE300F9392E /* RenderTextControl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = RenderTextControl.h; sourceTree = "<group>"; };
ABB5419C0ACDDFE4002820EB /* RenderListBox.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RenderListBox.cpp; sourceTree = "<group>"; };
ABB5419D0ACDDFE4002820EB /* RenderListBox.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = RenderListBox.h; sourceTree = "<group>"; };
ABDDFE730A5C6E6F00A3E11D /* RenderMenuList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RenderMenuList.cpp; sourceTree = "<group>"; };
ABDDFE740A5C6E7000A3E11D /* RenderMenuList.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = RenderMenuList.h; sourceTree = "<group>"; };
ABDDFE750A5C6E7000A3E11D /* RenderPopupMenu.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RenderPopupMenu.cpp; sourceTree = "<group>"; };
......@@ -7697,6 +7701,8 @@
F523D2F302DE443B018635CA /* rendering */ = {
isa = PBXGroup;
children = (
ABB5419C0ACDDFE4002820EB /* RenderListBox.cpp */,
ABB5419D0ACDDFE4002820EB /* RenderListBox.h */,
A8CFF04B0A154F09000A4234 /* AutoTableLayout.cpp */,
A8CFF0490A154F09000A4234 /* AutoTableLayout.h */,
BCEA4813097D93020094C9E4 /* bidi.cpp */,
......@@ -9135,6 +9141,7 @@
85989DD00ACC8BBD00A0BC51 /* DOMUIEventInternal.h in Headers */,
85989DD10ACC8BBD00A0BC51 /* DOMWheelEventInternal.h in Headers */,
4BBDBF7E0ACC9290005F6E97 /* CommandByName.h in Headers */,
ABB5419F0ACDDFE4002820EB /* RenderListBox.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -9182,7 +9189,6 @@
mainGroup = 0867D691FE84028FC02AAC07 /* WebKit */;
productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
93F198A508245E59001E9ABC /* WebCore */,
DD041FBE09D9DDBE0010AF2A /* Derived Sources */,
......@@ -10247,6 +10253,7 @@
85D79ADB0ACA17EB00F02FC5 /* DOMSVGStringList.mm in Sources */,
859C9C400ACACCCC00791611 /* DOMSVGRectElement.mm in Sources */,
4BBDBF7D0ACC9290005F6E97 /* CommandByName.cpp in Sources */,
ABB5419E0ACDDFE4002820EB /* RenderListBox.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -351,6 +351,7 @@ private:
bool _sendingEventToSubview;
bool _mouseDownMayStartDrag;
bool _mouseDownMayStartSelect;
bool _mouseDownMayStartAutoscroll;
PlatformMouseEvent m_mouseDown;
// in our view's coords
IntPoint m_mouseDownPos;
......
......@@ -153,6 +153,7 @@ FrameMac::FrameMac(Page* page, Element* ownerElement)
, _sendingEventToSubview(false)
, _mouseDownMayStartDrag(false)
, _mouseDownMayStartSelect(false)
, _mouseDownMayStartAutoscroll(false)
, _activationEventNumber(0)
, _bindingRoot(0)
, _windowScriptObject(0)
......@@ -1380,6 +1381,8 @@ void FrameMac::handleMousePressEvent(const MouseEventWithHitTestResults& event)
_mouseDownMayStartDrag = singleClick;
d->m_mousePressNode = event.targetNode();
_mouseDownMayStartAutoscroll = d->m_mousePressNode && d->m_mousePressNode->renderer() && d->m_mousePressNode->renderer()->shouldAutoscroll();
if (!passWidgetMouseDownEventToWidget(event, false)) {
// We don't do this at the start of mouse down handling (before calling into WebCore),
......@@ -1714,7 +1717,7 @@ void FrameMac::handleMouseMoveEvent(const MouseEventWithHitTestResults& event)
// No more default handling (like selection), whether we're past the hysteresis bounds or not
return;
}
if (!_mouseDownMayStartSelect) {
if (!_mouseDownMayStartSelect && !_mouseDownMayStartAutoscroll) {
return;
}
......@@ -1723,16 +1726,16 @@ void FrameMac::handleMouseMoveEvent(const MouseEventWithHitTestResults& event)
d->m_view->invalidateClick();
Node* node = event.targetNode();
RenderLayer* layer = 0;
if (node && node->renderer())
layer = node->renderer()->enclosingLayer();
RenderObject* renderer = 0;
if (node)
renderer = node->renderer();
// If the selection is contained in a layer that can scroll, that layer should handle the autoscroll
// Otherwise, let the bridge handle it so the view can scroll itself.
while (layer && !layer->shouldAutoscroll())
layer = layer->parent();
if (layer)
handleAutoscroll(layer);
while (renderer && !renderer->shouldAutoscroll())
renderer = renderer->parent();
if (renderer)
handleAutoscroll(renderer);
else {
if (!d->m_autoscrollTimer.isActive())
startAutoscrollTimer();
......@@ -1965,6 +1968,7 @@ void FrameMac::mouseDown(NSEvent *event)
_mouseDownMayStartDrag = false;
_mouseDownMayStartSelect = false;
_mouseDownMayStartAutoscroll = false;
v->handleMousePressEvent(event);
......
......@@ -379,7 +379,7 @@ input[type="button"], input[type="submit"], input[type="reset"], input[type="fil
box-sizing: border-box
}
input[type="button"]:disabled, input[type="submit"]:disabled, input[type="reset"]:disabled, input[type="file"]::-webkit-file-upload-button:disabled, button:disabled, select:disabled {
input[type="button"]:disabled, input[type="submit"]:disabled, input[type="reset"]:disabled, input[type="file"]::-webkit-file-upload-button:disabled, button:disabled, select:disabled, optgroup:disabled, option:disabled {
color: GrayText
}
......@@ -431,6 +431,14 @@ select[size][multiple] {
color: initial;
border: initial;
background-color: initial;
/*
-webkit-appearance: listbox;
-webkit-box-align: start;
box-sizing: initial;
border: 1px inset gray;
-webkit-border-radius: initial;
white-space: initial;
*/
}
select[size="0"],
......@@ -521,7 +529,7 @@ html:focus, body:focus {
outline: none
}
input:focus, textarea:focus, isindex:focus {
input:focus, textarea:focus, isindex:focus, select:focus {
outline-offset: -2px
}
......
......@@ -29,6 +29,7 @@
#include "Document.h"
#include "ExceptionCode.h"
#include "EventNames.h"
#include "HTMLNames.h"
#include "HTMLSelectElement.h"
#include "RenderMenuList.h"
......@@ -39,6 +40,7 @@
namespace WebCore {
using namespace HTMLNames;
using namespace EventNames;
HTMLOptionElement::HTMLOptionElement(Document* doc, HTMLFormElement* f)
: HTMLGenericFormElement(optionTag, doc, f)
......@@ -169,7 +171,7 @@ void HTMLOptionElement::setValue(const String& value)
void HTMLOptionElement::setSelected(bool selected)
{
if (m_selected == selected)
if (m_selected == selected || disabled())
return;
m_selected = selected;
if (HTMLSelectElement* select = getSelect())
......@@ -238,4 +240,9 @@ String HTMLOptionElement::optionText()
return itemText;
}
bool HTMLOptionElement::disabled() const
{
return HTMLGenericFormElement::disabled() || (parentNode() && static_cast<HTMLGenericFormElement*>(parentNode())->disabled());
}
} // namespace
......@@ -79,6 +79,8 @@ public:
void setLabel(const String&);
String optionText();
virtual bool disabled() const;
private:
String m_value;
......
......@@ -33,15 +33,19 @@
#include "Event.h"
#include "EventNames.h"
#include "FormDataList.h"
#include "Frame.h"
#include "HTMLFormElement.h"
#include "HTMLNames.h"
#include "HTMLOptionElement.h"
#include "HTMLOptionsCollection.h"
#include "KeyboardEvent.h"
#include "MouseEvent.h"
#include "RenderListBox.h"
#include "RenderMenuList.h"
#include "RenderPopupMenu.h"
#include "cssstyleselector.h"
#include <wtf/Vector.h>
#include <math.h>
#if PLATFORM(MAC)
#define ARROW_KEYS_POP_MENU 1
......@@ -49,6 +53,8 @@
#define ARROW_KEYS_POP_MENU 0
#endif
using namespace std;
namespace WebCore {
using namespace EventNames;
......@@ -84,8 +90,10 @@ bool HTMLSelectElement::checkDTD(const Node* newChild)
void HTMLSelectElement::recalcStyle( StyleChange ch )
{
if (hasChangedChild() && renderer()) {
if (shouldUseMenuList())
if (usesMenuList())
static_cast<RenderMenuList*>(renderer())->setOptionsChanged(true);
else if (renderer() && renderer()->style()->appearance() == ListboxAppearance)
static_cast<RenderListBox*>(renderer())->setOptionsChanged(true);
else
static_cast<DeprecatedRenderSelect*>(renderer())->setOptionsChanged(true);
}
......@@ -93,7 +101,6 @@ void HTMLSelectElement::recalcStyle( StyleChange ch )
HTMLGenericFormElement::recalcStyle( ch );
}
const AtomicString& HTMLSelectElement::type() const
{
static const AtomicString selectMultiple("select-multiple");
......@@ -104,34 +111,59 @@ const AtomicString& HTMLSelectElement::type() const
int HTMLSelectElement::selectedIndex() const
{
// return the number of the first option selected
unsigned o = 0;
unsigned index = 0;
const Vector<HTMLElement*>& items = listItems();
for (unsigned int i = 0; i < items.size(); i++) {
if (items[i]->hasLocalName(optionTag)) {
if (static_cast<HTMLOptionElement*>(items[i])->selected())
return o;
o++;
return index;
index++;
}
}
return -1;
}
void HTMLSelectElement::setSelectedIndex(int index, bool deselect)
int HTMLSelectElement::lastSelectedListIndex() const
{
// deselect all other options and select only the new one
// return the number of the last option selected
unsigned index = 0;
bool found = false;
const Vector<HTMLElement*>& items = listItems();
int listIndex;
if (deselect) {
for (listIndex = 0; listIndex < int(items.size()); listIndex++) {
if (items[listIndex]->hasLocalName(optionTag))
static_cast<HTMLOptionElement*>(items[listIndex])->setSelected(false);
for (unsigned int i = 0; i < items.size(); i++) {
if (items[i]->hasLocalName(optionTag)) {
if (static_cast<HTMLOptionElement*>(items[i])->selected()) {
index = i;
found = true;
}
}
}
listIndex = optionToListIndex(index);
if (listIndex >= 0)
static_cast<HTMLOptionElement*>(items[listIndex])->setSelected(true);
return found ? index : -1;
}
setChanged(true);
void HTMLSelectElement::deselectItems(HTMLOptionElement* excludeElement)
{
const Vector<HTMLElement*>& items = listItems();
unsigned i;
for (i = 0; i < items.size(); i++) {
if (items[i]->hasLocalName(optionTag) && (items[i] != excludeElement)) {
HTMLOptionElement* element = static_cast<HTMLOptionElement*>(items[i]);
element->m_selected = false;
element->setChanged();
}
}
}
void HTMLSelectElement::setSelectedIndex(int index, bool deselect)
{
const Vector<HTMLElement*>& items = listItems();
int listIndex = optionToListIndex(index);
HTMLOptionElement* element = 0;
if (listIndex >= 0) {
element = static_cast<HTMLOptionElement*>(items[listIndex]);
element->setSelected(true);
}
if (deselect)
deselectItems(element);
}
int HTMLSelectElement::length() const
......@@ -264,10 +296,10 @@ ContainerNode* HTMLSelectElement::addChild(PassRefPtr<Node> newChild)
void HTMLSelectElement::parseMappedAttribute(MappedAttribute *attr)
{
bool oldShouldUseMenuList = shouldUseMenuList();
bool oldUsesMenuList = usesMenuList();
if (attr->name() == sizeAttr) {
m_size = max(attr->value().toInt(), 1);
if (oldShouldUseMenuList != shouldUseMenuList() && attached()) {
if (oldUsesMenuList != usesMenuList() && attached()) {
detach();
attach();
}
......@@ -275,7 +307,7 @@ void HTMLSelectElement::parseMappedAttribute(MappedAttribute *attr)
m_minwidth = max(attr->value().toInt(), 0);
} else if (attr->name() == multipleAttr) {
m_multiple = (!attr->isNull());
if (oldShouldUseMenuList != shouldUseMenuList() && attached()) {
if (oldUsesMenuList != usesMenuList() && attached()) {
detach();
attach();
}
......@@ -293,22 +325,24 @@ void HTMLSelectElement::parseMappedAttribute(MappedAttribute *attr)
bool HTMLSelectElement::isKeyboardFocusable() const
{
if (renderer() && shouldUseMenuList())
if (renderer() && (usesMenuList() || renderer()->style()->appearance() == ListboxAppearance))
return isFocusable();
return HTMLGenericFormElement::isKeyboardFocusable();
}
bool HTMLSelectElement::isMouseFocusable() const
{
if (renderer() && shouldUseMenuList())
if (renderer() && (usesMenuList() || renderer()->style()->appearance() == ListboxAppearance))
return isFocusable();
return HTMLGenericFormElement::isMouseFocusable();
}
RenderObject *HTMLSelectElement::createRenderer(RenderArena *arena, RenderStyle *style)
{
if (shouldUseMenuList())
if (usesMenuList())
return new (arena) RenderMenuList(this);
if (style->appearance() == ListboxAppearance)
return new (arena) RenderListBox(this);
return new (arena) DeprecatedRenderSelect(this);
}
......@@ -394,7 +428,7 @@ void HTMLSelectElement::recalcListItems() const
}
if (current->hasTagName(optionTag)) {
m_listItems.append(static_cast<HTMLElement*>(current));
if (!foundSelected && !m_multiple && m_size <= 1) {
if (!foundSelected && (usesMenuList() || (!m_multiple && static_cast<HTMLOptionElement*>(current)->selected()))) {
foundSelected = static_cast<HTMLOptionElement*>(current);
foundSelected->m_selected = true;
} else if (foundSelected && !m_multiple && static_cast<HTMLOptionElement*>(current)->selected()) {
......@@ -426,8 +460,10 @@ void HTMLSelectElement::setRecalcListItems()
{
m_recalcListItems = true;
if (renderer()) {
if (shouldUseMenuList())
if (usesMenuList())
static_cast<RenderMenuList*>(renderer())->setOptionsChanged(true);
else if (renderer() && renderer()->style()->appearance() == ListboxAppearance)
static_cast<RenderListBox*>(renderer())->setOptionsChanged(true);
else
static_cast<DeprecatedRenderSelect*>(renderer())->setOptionsChanged(true);
}
......@@ -454,29 +490,34 @@ void HTMLSelectElement::reset()
}
if (!optionSelected && firstOption)
firstOption->setSelected(true);
if (renderer() && !shouldUseMenuList())
static_cast<DeprecatedRenderSelect*>(renderer())->setSelectionChanged(true);
setChanged(true);
}
void HTMLSelectElement::notifyOptionSelected(HTMLOptionElement *selectedOption, bool selected)
{
if (selected && !m_multiple) {
// deselect all other options
const Vector<HTMLElement*>& items = listItems();
unsigned i;
for (i = 0; i < items.size(); i++) {
if (items[i]->hasLocalName(optionTag))
static_cast<HTMLOptionElement*>(items[i])->m_selected = (items[i] == selectedOption);
}
}
if (renderer() && !shouldUseMenuList())
static_cast<DeprecatedRenderSelect*>(renderer())->setSelectionChanged(true);
{
if (selected && !m_multiple)
deselectItems(selectedOption);
if (renderer() && !usesMenuList()) {
if (renderer()->style()->appearance() == ListboxAppearance)
static_cast<RenderListBox*>(renderer())->setSelectionChanged(true);
else
static_cast<DeprecatedRenderSelect*>(renderer())->setSelectionChanged(true);
}
setChanged(true);
}
void HTMLSelectElement::defaultEventHandler(Event *evt)
void HTMLSelectElement::defaultEventHandler(Event* evt)
{
if (usesMenuList())
menuListDefaultEventHandler(evt);
else if (renderer() && renderer()->isListBox() && renderer()->style()->appearance() == ListboxAppearance)
listBoxDefaultEventHandler(evt);
HTMLGenericFormElement::defaultEventHandler(evt);
}
void HTMLSelectElement::menuListDefaultEventHandler(Event* evt)
{
RenderMenuList* menuList = static_cast<RenderMenuList*>(renderer());
......@@ -495,7 +536,7 @@ void HTMLSelectElement::defaultEventHandler(Event *evt)
form()->submitClick();
handled = true;
}
if ((keyIdentifier == "Down" || keyIdentifier == "Up" || keyIdentifier == "U+000020") && renderer() && shouldUseMenuList()) {
if ((keyIdentifier == "Down" || keyIdentifier == "Up" || keyIdentifier == "U+000020") && renderer() && usesMenuList()) {
focus();
menuList->showPopup();
handled = true;
......@@ -516,16 +557,94 @@ void HTMLSelectElement::defaultEventHandler(Event *evt)
evt->setDefaultHandled();
}
if (evt->type() == mousedownEvent && renderer() && shouldUseMenuList()) {
focus();
if (evt->type() == mousedownEvent) {
focus();
if (menuList->popupIsVisible())
menuList->hidePopup();
else
menuList->showPopup();
evt->setDefaultHandled();
}
}
HTMLGenericFormElement::defaultEventHandler(evt);
void HTMLSelectElement::listBoxDefaultEventHandler(Event* evt)
{
if (evt->type() == mousedownEvent) {
MouseEvent* mEvt = static_cast<MouseEvent*>(evt);
if (HTMLOptionElement* element = static_cast<RenderListBox*>(renderer())->optionAtPoint(mEvt->x(), mEvt->y())) {
bool deselectOtherOptions = true;
bool shouldSelect = true;
bool multiSelectKeyPressed = false;
#if PLATFORM(MAC)
multiSelectKeyPressed = mEvt->metaKey();
#else
multiSelectKeyPressed = mEvt->ctrlKey();
#endif
if (multiple() && multiSelectKeyPressed)
deselectOtherOptions = false;
if (element->selected() && multiSelectKeyPressed)
shouldSelect = false;
int optionIndex = element->index();
if (!shouldSelect) {
optionIndex = -1;
element->m_selected = false;
}
setSelectedIndex(optionIndex, deselectOtherOptions);
}
}