1 /*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7 #include "SkAtomics.h"
8 #include "SkOSMenu.h"
9 #include <stdarg.h>
10
11 static int gOSMenuCmd = 7000;
12
SkOSMenu(const char title[])13 SkOSMenu::SkOSMenu(const char title[]) {
14 fTitle.set(title);
15 }
16
~SkOSMenu()17 SkOSMenu::~SkOSMenu() {
18 this->reset();
19 }
20
reset()21 void SkOSMenu::reset() {
22 fItems.deleteAll();
23 fTitle.reset();
24 }
25
getItemByID(int itemID) const26 const SkOSMenu::Item* SkOSMenu::getItemByID(int itemID) const {
27 for (int i = 0; i < fItems.count(); ++i) {
28 if (itemID == fItems[i]->getID())
29 return fItems[i];
30 }
31 return nullptr;
32 }
33
getItems(const SkOSMenu::Item * items[]) const34 void SkOSMenu::getItems(const SkOSMenu::Item* items[]) const {
35 if (items) {
36 for (int i = 0; i < fItems.count(); ++i) {
37 items[i] = fItems[i];
38 }
39 }
40 }
41
assignKeyEquivalentToItem(int itemID,SkUnichar key)42 void SkOSMenu::assignKeyEquivalentToItem(int itemID, SkUnichar key) {
43 for (int i = 0; i < fItems.count(); ++i) {
44 if (itemID == fItems[i]->getID())
45 fItems[i]->setKeyEquivalent(key);
46 }
47 }
48
handleKeyEquivalent(SkUnichar key)49 bool SkOSMenu::handleKeyEquivalent(SkUnichar key) {
50 int value = 0, size = 0;
51 bool state;
52 SkOSMenu::TriState tristate;
53 for (int i = 0; i < fItems.count(); ++i) {
54 Item* item = fItems[i];
55 if (item->getKeyEquivalent()== key) {
56 SkString list;
57 switch (item->getType()) {
58 case kList_Type:
59 SkOSMenu::FindListItemCount(*item->getEvent(), &size);
60 SkOSMenu::FindListIndex(*item->getEvent(), item->getSlotName(), &value);
61 value = (value + 1) % size;
62 item->setInt(value);
63 break;
64 case kSwitch_Type:
65 SkOSMenu::FindSwitchState(*item->getEvent(), item->getSlotName(), &state);
66 item->setBool(!state);
67 break;
68 case kTriState_Type:
69 SkOSMenu::FindTriState(*item->getEvent(), item->getSlotName(), &tristate);
70 if (kOnState == tristate)
71 tristate = kMixedState;
72 else
73 tristate = (SkOSMenu::TriState)((int)tristate + 1);
74 item->setTriState(tristate);
75 break;
76 case kAction_Type:
77 case kCustom_Type:
78 case kSlider_Type:
79 case kTextField_Type:
80 default:
81 break;
82 }
83 item->postEvent();
84 return true;
85 }
86 }
87 return false;
88 }
89
90 ////////////////////////////////////////////////////////////////////////////////
91
Item(const char label[],SkOSMenu::Type type,const char slotName[],SkEvent * evt)92 SkOSMenu::Item::Item(const char label[], SkOSMenu::Type type,
93 const char slotName[], SkEvent* evt) {
94 fLabel.set(label);
95 fSlotName.set(slotName);
96 fType = type;
97 fEvent = evt;
98 fKey = 0;
99 fID = sk_atomic_inc(&gOSMenuCmd);
100 }
101
setBool(bool value) const102 void SkOSMenu::Item::setBool(bool value) const {
103 SkASSERT(SkOSMenu::kSwitch_Type == fType);
104 fEvent->setBool(fSlotName.c_str(), value);
105 }
106
setScalar(SkScalar value) const107 void SkOSMenu::Item::setScalar(SkScalar value) const {
108 SkASSERT(SkOSMenu::kSlider_Type == fType);
109 fEvent->setScalar(fSlotName.c_str(), value);
110 }
111
setInt(int value) const112 void SkOSMenu::Item::setInt(int value) const {
113 SkASSERT(SkOSMenu::kList_Type == fType);
114 fEvent->setS32(fSlotName.c_str(), value);
115 }
116
setTriState(TriState value) const117 void SkOSMenu::Item::setTriState(TriState value) const {
118 SkASSERT(SkOSMenu::kTriState_Type == fType);
119 fEvent->setS32(fSlotName.c_str(), value);
120 }
121
setString(const char value[]) const122 void SkOSMenu::Item::setString(const char value[]) const {
123 SkASSERT(SkOSMenu::kTextField_Type == fType);
124 fEvent->setString(fSlotName.c_str(), value);
125 }
126
127 ////////////////////////////////////////////////////////////////////////////////
128
129 static const char* gMenuEventType = "SkOSMenuEventType";
130 static const char* gSlider_Min_Scalar = "SkOSMenuSlider_Min";
131 static const char* gSlider_Max_Scalar = "SkOSMenuSlider_Max";
132 static const char* gDelimiter = "|";
133 static const char* gList_Items_Str = "SkOSMenuList_Items";
134 static const char* gList_ItemCount_S32 = "SkOSMenuList_ItemCount";
135
appendItem(const char label[],Type type,const char slotName[],SkEvent * evt)136 int SkOSMenu::appendItem(const char label[], Type type, const char slotName[],
137 SkEvent* evt) {
138 SkOSMenu::Item* item = new Item(label, type, slotName, evt);
139 fItems.append(1, &item);
140 return item->getID();
141 }
142
appendAction(const char label[],SkEventSinkID target)143 int SkOSMenu::appendAction(const char label[], SkEventSinkID target) {
144 SkEvent* evt = new SkEvent(gMenuEventType, target);
145 //Store label in event so it can be used to identify the action later
146 evt->setString(label, label);
147 return appendItem(label, SkOSMenu::kAction_Type, "", evt);
148 }
149
appendList(const char label[],const char slotName[],SkEventSinkID target,int index,const char option[],...)150 int SkOSMenu::appendList(const char label[], const char slotName[],
151 SkEventSinkID target, int index, const char option[], ...) {
152 SkEvent* evt = new SkEvent(gMenuEventType, target);
153 va_list args;
154 if (option) {
155 SkString str(option);
156 va_start(args, option);
157 int count = 1;
158 for (const char* arg = va_arg(args, const char*); arg != nullptr; arg = va_arg(args, const char*)) {
159 str += gDelimiter;
160 str += arg;
161 ++count;
162 }
163 va_end(args);
164 evt->setString(gList_Items_Str, str);
165 evt->setS32(gList_ItemCount_S32, count);
166 evt->setS32(slotName, index);
167 }
168 return appendItem(label, SkOSMenu::kList_Type, slotName, evt);
169 }
170
appendSlider(const char label[],const char slotName[],SkEventSinkID target,SkScalar min,SkScalar max,SkScalar defaultValue)171 int SkOSMenu::appendSlider(const char label[], const char slotName[],
172 SkEventSinkID target, SkScalar min, SkScalar max,
173 SkScalar defaultValue) {
174 SkEvent* evt = new SkEvent(gMenuEventType, target);
175 evt->setScalar(gSlider_Min_Scalar, min);
176 evt->setScalar(gSlider_Max_Scalar, max);
177 evt->setScalar(slotName, defaultValue);
178 return appendItem(label, SkOSMenu::kSlider_Type, slotName, evt);
179 }
180
appendSwitch(const char label[],const char slotName[],SkEventSinkID target,bool defaultState)181 int SkOSMenu::appendSwitch(const char label[], const char slotName[],
182 SkEventSinkID target, bool defaultState) {
183 SkEvent* evt = new SkEvent(gMenuEventType, target);
184 evt->setBool(slotName, defaultState);
185 return appendItem(label, SkOSMenu::kSwitch_Type, slotName, evt);
186 }
187
appendTriState(const char label[],const char slotName[],SkEventSinkID target,SkOSMenu::TriState defaultState)188 int SkOSMenu::appendTriState(const char label[], const char slotName[],
189 SkEventSinkID target, SkOSMenu::TriState defaultState) {
190 SkEvent* evt = new SkEvent(gMenuEventType, target);
191 evt->setS32(slotName, defaultState);
192 return appendItem(label, SkOSMenu::kTriState_Type, slotName, evt);
193 }
194
appendTextField(const char label[],const char slotName[],SkEventSinkID target,const char placeholder[])195 int SkOSMenu::appendTextField(const char label[], const char slotName[],
196 SkEventSinkID target, const char placeholder[]) {
197 SkEvent* evt = new SkEvent(gMenuEventType, target);
198 evt->setString(slotName, placeholder);
199 return appendItem(label, SkOSMenu::kTextField_Type, slotName, evt);
200 }
201
FindListItemCount(const SkEvent & evt,int * count)202 bool SkOSMenu::FindListItemCount(const SkEvent& evt, int* count) {
203 return evt.isType(gMenuEventType) && evt.findS32(gList_ItemCount_S32, count);
204 }
205
FindListItems(const SkEvent & evt,SkString items[])206 bool SkOSMenu::FindListItems(const SkEvent& evt, SkString items[]) {
207 if (evt.isType(gMenuEventType) && items) {
208 const char* text = evt.findString(gList_Items_Str);
209 if (text != nullptr) {
210 SkString temp(text);
211 char* token = strtok((char*)temp.c_str(), gDelimiter);
212 int index = 0;
213 while (token != nullptr) {
214 items[index].set(token, strlen(token));
215 token = strtok (nullptr, gDelimiter);
216 ++index;
217 }
218 }
219 return true;
220 }
221 return false;
222 }
223
FindSliderMin(const SkEvent & evt,SkScalar * min)224 bool SkOSMenu::FindSliderMin(const SkEvent& evt, SkScalar* min) {
225 return evt.isType(gMenuEventType) && evt.findScalar(gSlider_Min_Scalar, min);
226 }
227
FindSliderMax(const SkEvent & evt,SkScalar * max)228 bool SkOSMenu::FindSliderMax(const SkEvent& evt, SkScalar* max) {
229 return evt.isType(gMenuEventType) && evt.findScalar(gSlider_Max_Scalar, max);
230 }
231
FindAction(const SkEvent & evt,const char label[])232 bool SkOSMenu::FindAction(const SkEvent& evt, const char label[]) {
233 return evt.isType(gMenuEventType) && evt.findString(label);
234 }
235
FindListIndex(const SkEvent & evt,const char slotName[],int * value)236 bool SkOSMenu::FindListIndex(const SkEvent& evt, const char slotName[], int* value) {
237 return evt.isType(gMenuEventType) && evt.findS32(slotName, value);
238 }
239
FindSliderValue(const SkEvent & evt,const char slotName[],SkScalar * value)240 bool SkOSMenu::FindSliderValue(const SkEvent& evt, const char slotName[], SkScalar* value) {
241 return evt.isType(gMenuEventType) && evt.findScalar(slotName, value);
242 }
243
FindSwitchState(const SkEvent & evt,const char slotName[],bool * value)244 bool SkOSMenu::FindSwitchState(const SkEvent& evt, const char slotName[], bool* value) {
245 return evt.isType(gMenuEventType) && evt.findBool(slotName, value);
246 }
247
FindTriState(const SkEvent & evt,const char slotName[],SkOSMenu::TriState * value)248 bool SkOSMenu::FindTriState(const SkEvent& evt, const char slotName[], SkOSMenu::TriState* value) {
249 return evt.isType(gMenuEventType) && evt.findS32(slotName, (int*)value);
250 }
251
FindText(const SkEvent & evt,const char slotName[],SkString * value)252 bool SkOSMenu::FindText(const SkEvent& evt, const char slotName[], SkString* value) {
253 if (evt.isType(gMenuEventType)) {
254 const char* text = evt.findString(slotName);
255 if (!text || !*text)
256 return false;
257 else {
258 value->set(text);
259 return true;
260 }
261 }
262 return false;
263 }
264