|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 #include "nsCOMPtr.h" |
|
6 #include "nsButtonBoxFrame.h" |
|
7 #include "nsIContent.h" |
|
8 #include "nsIDOMNodeList.h" |
|
9 #include "nsIDOMXULButtonElement.h" |
|
10 #include "nsGkAtoms.h" |
|
11 #include "nsNameSpaceManager.h" |
|
12 #include "nsPresContext.h" |
|
13 #include "nsIPresShell.h" |
|
14 #include "nsIDOMElement.h" |
|
15 #include "nsDisplayList.h" |
|
16 #include "nsContentUtils.h" |
|
17 #include "mozilla/dom/Element.h" |
|
18 #include "mozilla/EventStateManager.h" |
|
19 #include "mozilla/EventStates.h" |
|
20 #include "mozilla/MouseEvents.h" |
|
21 #include "mozilla/TextEvents.h" |
|
22 |
|
23 using namespace mozilla; |
|
24 |
|
25 // |
|
26 // NS_NewXULButtonFrame |
|
27 // |
|
28 // Creates a new Button frame and returns it |
|
29 // |
|
30 nsIFrame* |
|
31 NS_NewButtonBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext) |
|
32 { |
|
33 return new (aPresShell) nsButtonBoxFrame(aPresShell, aContext); |
|
34 } |
|
35 |
|
36 NS_IMPL_FRAMEARENA_HELPERS(nsButtonBoxFrame) |
|
37 |
|
38 void |
|
39 nsButtonBoxFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder, |
|
40 const nsRect& aDirtyRect, |
|
41 const nsDisplayListSet& aLists) |
|
42 { |
|
43 // override, since we don't want children to get events |
|
44 if (aBuilder->IsForEventDelivery()) |
|
45 return; |
|
46 nsBoxFrame::BuildDisplayListForChildren(aBuilder, aDirtyRect, aLists); |
|
47 } |
|
48 |
|
49 nsresult |
|
50 nsButtonBoxFrame::HandleEvent(nsPresContext* aPresContext, |
|
51 WidgetGUIEvent* aEvent, |
|
52 nsEventStatus* aEventStatus) |
|
53 { |
|
54 NS_ENSURE_ARG_POINTER(aEventStatus); |
|
55 if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { |
|
56 return NS_OK; |
|
57 } |
|
58 |
|
59 switch (aEvent->message) { |
|
60 case NS_KEY_DOWN: { |
|
61 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent(); |
|
62 if (!keyEvent) { |
|
63 break; |
|
64 } |
|
65 if (NS_VK_SPACE == keyEvent->keyCode) { |
|
66 EventStateManager* esm = aPresContext->EventStateManager(); |
|
67 // :hover:active state |
|
68 esm->SetContentState(mContent, NS_EVENT_STATE_HOVER); |
|
69 esm->SetContentState(mContent, NS_EVENT_STATE_ACTIVE); |
|
70 } |
|
71 break; |
|
72 } |
|
73 |
|
74 // On mac, Return fires the default button, not the focused one. |
|
75 #ifndef XP_MACOSX |
|
76 case NS_KEY_PRESS: { |
|
77 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent(); |
|
78 if (!keyEvent) { |
|
79 break; |
|
80 } |
|
81 if (NS_VK_RETURN == keyEvent->keyCode) { |
|
82 nsCOMPtr<nsIDOMXULButtonElement> buttonEl(do_QueryInterface(mContent)); |
|
83 if (buttonEl) { |
|
84 MouseClicked(aPresContext, aEvent); |
|
85 *aEventStatus = nsEventStatus_eConsumeNoDefault; |
|
86 } |
|
87 } |
|
88 break; |
|
89 } |
|
90 #endif |
|
91 |
|
92 case NS_KEY_UP: { |
|
93 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent(); |
|
94 if (!keyEvent) { |
|
95 break; |
|
96 } |
|
97 if (NS_VK_SPACE == keyEvent->keyCode) { |
|
98 // only activate on keyup if we're already in the :hover:active state |
|
99 NS_ASSERTION(mContent->IsElement(), "How do we have a non-element?"); |
|
100 EventStates buttonState = mContent->AsElement()->State(); |
|
101 if (buttonState.HasAllStates(NS_EVENT_STATE_ACTIVE | |
|
102 NS_EVENT_STATE_HOVER)) { |
|
103 // return to normal state |
|
104 EventStateManager* esm = aPresContext->EventStateManager(); |
|
105 esm->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE); |
|
106 esm->SetContentState(nullptr, NS_EVENT_STATE_HOVER); |
|
107 MouseClicked(aPresContext, aEvent); |
|
108 } |
|
109 } |
|
110 break; |
|
111 } |
|
112 |
|
113 case NS_MOUSE_CLICK: { |
|
114 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); |
|
115 if (mouseEvent->IsLeftClickEvent()) { |
|
116 MouseClicked(aPresContext, mouseEvent); |
|
117 } |
|
118 break; |
|
119 } |
|
120 } |
|
121 |
|
122 return nsBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus); |
|
123 } |
|
124 |
|
125 void |
|
126 nsButtonBoxFrame::DoMouseClick(WidgetGUIEvent* aEvent, bool aTrustEvent) |
|
127 { |
|
128 // Don't execute if we're disabled. |
|
129 if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled, |
|
130 nsGkAtoms::_true, eCaseMatters)) |
|
131 return; |
|
132 |
|
133 // Execute the oncommand event handler. |
|
134 bool isShift = false; |
|
135 bool isControl = false; |
|
136 bool isAlt = false; |
|
137 bool isMeta = false; |
|
138 if(aEvent) { |
|
139 WidgetInputEvent* inputEvent = aEvent->AsInputEvent(); |
|
140 isShift = inputEvent->IsShift(); |
|
141 isControl = inputEvent->IsControl(); |
|
142 isAlt = inputEvent->IsAlt(); |
|
143 isMeta = inputEvent->IsMeta(); |
|
144 } |
|
145 |
|
146 // Have the content handle the event, propagating it according to normal DOM rules. |
|
147 nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell(); |
|
148 if (shell) { |
|
149 nsContentUtils::DispatchXULCommand(mContent, |
|
150 aEvent ? |
|
151 aEvent->mFlags.mIsTrusted : aTrustEvent, |
|
152 nullptr, shell, |
|
153 isControl, isAlt, isShift, isMeta); |
|
154 } |
|
155 } |