blob: 8c2e47602f4cbbfae857cc8ac964842e2696c437 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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 */
mtklein1b249332015-07-07 12:21:21 -07007#include "SkAtomics.h"
jvanverth02802f62015-07-02 06:42:49 -07008#include "SkOSMenu.h"
mtklein1b249332015-07-07 12:21:21 -07009#include <stdarg.h>
reed@android.com8a1c16f2008-12-17 15:59:43 +000010
11static int gOSMenuCmd = 7000;
12
yangsu@google.com654d72f2011-08-01 17:27:33 +000013SkOSMenu::SkOSMenu(const char title[]) {
rmistry@google.comd6176b02012-08-23 18:14:13 +000014 fTitle.set(title);
reed@android.com8a1c16f2008-12-17 15:59:43 +000015}
16
yangsu@google.com654d72f2011-08-01 17:27:33 +000017SkOSMenu::~SkOSMenu() {
18 this->reset();
reed@android.com8a1c16f2008-12-17 15:59:43 +000019}
20
yangsu@google.com654d72f2011-08-01 17:27:33 +000021void SkOSMenu::reset() {
22 fItems.deleteAll();
23 fTitle.reset();
24}
25
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000026const 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 NULL;
32}
33
34void SkOSMenu::getItems(const SkOSMenu::Item* items[]) const {
bsalomon49f085d2014-09-05 13:34:00 -070035 if (items) {
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000036 for (int i = 0; i < fItems.count(); ++i) {
37 items[i] = fItems[i];
38 }
39 }
40}
41
yangsu@google.come55f5332011-08-05 22:11:41 +000042void 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 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000047}
48
rmistry@google.comd6176b02012-08-23 18:14:13 +000049bool SkOSMenu::handleKeyEquivalent(SkUnichar key) {
yangsu@google.come55f5332011-08-05 22:11:41 +000050 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:
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000059 SkOSMenu::FindListItemCount(*item->getEvent(), &size);
60 SkOSMenu::FindListIndex(*item->getEvent(), item->getSlotName(), &value);
yangsu@google.come55f5332011-08-05 22:11:41 +000061 value = (value + 1) % size;
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000062 item->setInt(value);
yangsu@google.come55f5332011-08-05 22:11:41 +000063 break;
64 case kSwitch_Type:
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000065 SkOSMenu::FindSwitchState(*item->getEvent(), item->getSlotName(), &state);
66 item->setBool(!state);
yangsu@google.come55f5332011-08-05 22:11:41 +000067 break;
68 case kTriState_Type:
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000069 SkOSMenu::FindTriState(*item->getEvent(), item->getSlotName(), &tristate);
yangsu@google.come55f5332011-08-05 22:11:41 +000070 if (kOnState == tristate)
71 tristate = kMixedState;
72 else
73 tristate = (SkOSMenu::TriState)((int)tristate + 1);
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000074 item->setTriState(tristate);
yangsu@google.come55f5332011-08-05 22:11:41 +000075 break;
76 case kAction_Type:
77 case kCustom_Type:
78 case kSlider_Type:
79 case kTextField_Type:
80 default:
yangsu@google.come55f5332011-08-05 22:11:41 +000081 break;
82 }
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000083 item->postEvent();
yangsu@google.come55f5332011-08-05 22:11:41 +000084 return true;
85 }
86 }
87 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +000088}
89
yangsu@google.com654d72f2011-08-01 17:27:33 +000090////////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000091
rmistry@google.comd6176b02012-08-23 18:14:13 +000092SkOSMenu::Item::Item(const char label[], SkOSMenu::Type type,
yangsu@google.come55f5332011-08-05 22:11:41 +000093 const char slotName[], SkEvent* evt) {
yangsu@google.com654d72f2011-08-01 17:27:33 +000094 fLabel.set(label);
95 fSlotName.set(slotName);
96 fType = type;
yangsu@google.com654d72f2011-08-01 17:27:33 +000097 fEvent = evt;
yangsu@google.come55f5332011-08-05 22:11:41 +000098 fKey = 0;
yangsu@google.com654d72f2011-08-01 17:27:33 +000099 fID = sk_atomic_inc(&gOSMenuCmd);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000100}
101
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000102void SkOSMenu::Item::setBool(bool value) const {
yangsu@google.com654d72f2011-08-01 17:27:33 +0000103 SkASSERT(SkOSMenu::kSwitch_Type == fType);
104 fEvent->setBool(fSlotName.c_str(), value);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105}
106
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000107void SkOSMenu::Item::setScalar(SkScalar value) const {
yangsu@google.com654d72f2011-08-01 17:27:33 +0000108 SkASSERT(SkOSMenu::kSlider_Type == fType);
109 fEvent->setScalar(fSlotName.c_str(), value);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000110}
111
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000112void SkOSMenu::Item::setInt(int value) const {
113 SkASSERT(SkOSMenu::kList_Type == fType);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000114 fEvent->setS32(fSlotName.c_str(), value);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000115}
116
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000117void SkOSMenu::Item::setTriState(TriState value) const {
118 SkASSERT(SkOSMenu::kTriState_Type == fType);
119 fEvent->setS32(fSlotName.c_str(), value);
120}
121
122void SkOSMenu::Item::setString(const char value[]) const {
yangsu@google.com654d72f2011-08-01 17:27:33 +0000123 SkASSERT(SkOSMenu::kTextField_Type == fType);
124 fEvent->setString(fSlotName.c_str(), value);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000125}
126
127////////////////////////////////////////////////////////////////////////////////
128
yangsu@google.come55f5332011-08-05 22:11:41 +0000129static const char* gMenuEventType = "SkOSMenuEventType";
130static const char* gSlider_Min_Scalar = "SkOSMenuSlider_Min";
131static const char* gSlider_Max_Scalar = "SkOSMenuSlider_Max";
132static const char* gDelimiter = "|";
133static const char* gList_Items_Str = "SkOSMenuList_Items";
134static const char* gList_ItemCount_S32 = "SkOSMenuList_ItemCount";
yangsu@google.com654d72f2011-08-01 17:27:33 +0000135
rmistry@google.comd6176b02012-08-23 18:14:13 +0000136int SkOSMenu::appendItem(const char label[], Type type, const char slotName[],
yangsu@google.come55f5332011-08-05 22:11:41 +0000137 SkEvent* evt) {
138 SkOSMenu::Item* item = new Item(label, type, slotName, evt);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000139 fItems.append(1, &item);
140 return item->getID();
141}
142
143int SkOSMenu::appendAction(const char label[], SkEventSinkID target) {
yangsu@google.come55f5332011-08-05 22:11:41 +0000144 SkEvent* evt = new SkEvent(gMenuEventType, target);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000145 //Store label in event so it can be used to identify the action later
yangsu@google.come55f5332011-08-05 22:11:41 +0000146 evt->setString(label, label);
147 return appendItem(label, SkOSMenu::kAction_Type, "", evt);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000148}
149
rmistry@google.comd6176b02012-08-23 18:14:13 +0000150int SkOSMenu::appendList(const char label[], const char slotName[],
yangsu@google.com654d72f2011-08-01 17:27:33 +0000151 SkEventSinkID target, int index, const char option[], ...) {
yangsu@google.come55f5332011-08-05 22:11:41 +0000152 SkEvent* evt = new SkEvent(gMenuEventType, target);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000153 va_list args;
154 if (option) {
155 SkString str(option);
156 va_start(args, option);
yangsu@google.come55f5332011-08-05 22:11:41 +0000157 int count = 1;
yangsu@google.com654d72f2011-08-01 17:27:33 +0000158 for (const char* arg = va_arg(args, const char*); arg != NULL; arg = va_arg(args, const char*)) {
yangsu@google.come55f5332011-08-05 22:11:41 +0000159 str += gDelimiter;
yangsu@google.com654d72f2011-08-01 17:27:33 +0000160 str += arg;
yangsu@google.come55f5332011-08-05 22:11:41 +0000161 ++count;
yangsu@google.com654d72f2011-08-01 17:27:33 +0000162 }
163 va_end(args);
yangsu@google.come55f5332011-08-05 22:11:41 +0000164 evt->setString(gList_Items_Str, str);
165 evt->setS32(gList_ItemCount_S32, count);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000166 evt->setS32(slotName, index);
167 }
yangsu@google.come55f5332011-08-05 22:11:41 +0000168 return appendItem(label, SkOSMenu::kList_Type, slotName, evt);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000169}
170
rmistry@google.comd6176b02012-08-23 18:14:13 +0000171int SkOSMenu::appendSlider(const char label[], const char slotName[],
172 SkEventSinkID target, SkScalar min, SkScalar max,
yangsu@google.com654d72f2011-08-01 17:27:33 +0000173 SkScalar defaultValue) {
yangsu@google.come55f5332011-08-05 22:11:41 +0000174 SkEvent* evt = new SkEvent(gMenuEventType, target);
175 evt->setScalar(gSlider_Min_Scalar, min);
176 evt->setScalar(gSlider_Max_Scalar, max);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000177 evt->setScalar(slotName, defaultValue);
yangsu@google.come55f5332011-08-05 22:11:41 +0000178 return appendItem(label, SkOSMenu::kSlider_Type, slotName, evt);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000179}
180
rmistry@google.comd6176b02012-08-23 18:14:13 +0000181int SkOSMenu::appendSwitch(const char label[], const char slotName[],
yangsu@google.com654d72f2011-08-01 17:27:33 +0000182 SkEventSinkID target, bool defaultState) {
yangsu@google.come55f5332011-08-05 22:11:41 +0000183 SkEvent* evt = new SkEvent(gMenuEventType, target);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000184 evt->setBool(slotName, defaultState);
yangsu@google.come55f5332011-08-05 22:11:41 +0000185 return appendItem(label, SkOSMenu::kSwitch_Type, slotName, evt);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000186}
187
188int SkOSMenu::appendTriState(const char label[], const char slotName[],
189 SkEventSinkID target, SkOSMenu::TriState defaultState) {
yangsu@google.come55f5332011-08-05 22:11:41 +0000190 SkEvent* evt = new SkEvent(gMenuEventType, target);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000191 evt->setS32(slotName, defaultState);
yangsu@google.come55f5332011-08-05 22:11:41 +0000192 return appendItem(label, SkOSMenu::kTriState_Type, slotName, evt);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000193}
194
rmistry@google.comd6176b02012-08-23 18:14:13 +0000195int SkOSMenu::appendTextField(const char label[], const char slotName[],
yangsu@google.com654d72f2011-08-01 17:27:33 +0000196 SkEventSinkID target, const char placeholder[]) {
yangsu@google.come55f5332011-08-05 22:11:41 +0000197 SkEvent* evt = new SkEvent(gMenuEventType, target);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000198 evt->setString(slotName, placeholder);
yangsu@google.come55f5332011-08-05 22:11:41 +0000199 return appendItem(label, SkOSMenu::kTextField_Type, slotName, evt);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000200}
201
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000202bool SkOSMenu::FindListItemCount(const SkEvent& evt, int* count) {
203 return evt.isType(gMenuEventType) && evt.findS32(gList_ItemCount_S32, count);
yangsu@google.come55f5332011-08-05 22:11:41 +0000204}
205
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000206bool SkOSMenu::FindListItems(const SkEvent& evt, SkString items[]) {
bsalomon49f085d2014-09-05 13:34:00 -0700207 if (evt.isType(gMenuEventType) && items) {
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000208 const char* text = evt.findString(gList_Items_Str);
yangsu@google.com2f9462d2011-08-05 22:37:18 +0000209 if (text != NULL) {
210 SkString temp(text);
211 char* token = strtok((char*)temp.c_str(), gDelimiter);
212 int index = 0;
213 while (token != NULL) {
214 items[index].set(token, strlen(token));
215 token = strtok (NULL, gDelimiter);
216 ++index;
217 }
yangsu@google.come55f5332011-08-05 22:11:41 +0000218 }
219 return true;
220 }
221 return false;
222}
223
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000224bool SkOSMenu::FindSliderMin(const SkEvent& evt, SkScalar* min) {
225 return evt.isType(gMenuEventType) && evt.findScalar(gSlider_Min_Scalar, min);
yangsu@google.come55f5332011-08-05 22:11:41 +0000226}
227
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000228bool SkOSMenu::FindSliderMax(const SkEvent& evt, SkScalar* max) {
229 return evt.isType(gMenuEventType) && evt.findScalar(gSlider_Max_Scalar, max);
yangsu@google.come55f5332011-08-05 22:11:41 +0000230}
yangsu@google.com654d72f2011-08-01 17:27:33 +0000231
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000232bool SkOSMenu::FindAction(const SkEvent& evt, const char label[]) {
233 return evt.isType(gMenuEventType) && evt.findString(label);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000234}
235
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000236bool SkOSMenu::FindListIndex(const SkEvent& evt, const char slotName[], int* value) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000237 return evt.isType(gMenuEventType) && evt.findS32(slotName, value);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000238}
239
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000240bool SkOSMenu::FindSliderValue(const SkEvent& evt, const char slotName[], SkScalar* value) {
241 return evt.isType(gMenuEventType) && evt.findScalar(slotName, value);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000242}
243
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000244bool SkOSMenu::FindSwitchState(const SkEvent& evt, const char slotName[], bool* value) {
245 return evt.isType(gMenuEventType) && evt.findBool(slotName, value);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000246}
247
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000248bool SkOSMenu::FindTriState(const SkEvent& evt, const char slotName[], SkOSMenu::TriState* value) {
249 return evt.isType(gMenuEventType) && evt.findS32(slotName, (int*)value);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000250}
251
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000252bool SkOSMenu::FindText(const SkEvent& evt, const char slotName[], SkString* value) {
253 if (evt.isType(gMenuEventType)) {
254 const char* text = evt.findString(slotName);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000255 if (!text || !*text)
256 return false;
257 else {
258 value->set(text);
259 return true;
260 }
261 }
262 return false;
263}