blob: 8137365d00a6c8eb0ab66179b9e0a3462b5fab14 [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 */
yangsu@google.com654d72f2011-08-01 17:27:33 +00007#include <stdarg.h>
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkOSMenu.h"
yangsu@google.com654d72f2011-08-01 17:27:33 +00009#include "SkThread.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[]) {
14 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.come55f5332011-08-05 22:11:41 +000026void SkOSMenu::assignKeyEquivalentToItem(int itemID, SkUnichar key) {
27 for (int i = 0; i < fItems.count(); ++i) {
28 if (itemID == fItems[i]->getID())
29 fItems[i]->setKeyEquivalent(key);
30 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000031}
32
yangsu@google.come55f5332011-08-05 22:11:41 +000033bool SkOSMenu::handleKeyEquivalent(SkUnichar key) {
34 int value = 0, size = 0;
35 bool state;
36 SkOSMenu::TriState tristate;
37 for (int i = 0; i < fItems.count(); ++i) {
38 Item* item = fItems[i];
39 if (item->getKeyEquivalent()== key) {
40 SkString list;
41 switch (item->getType()) {
42 case kList_Type:
43 SkOSMenu::FindListItemCount(item->getEvent(), &size);
44 SkOSMenu::FindListIndex(item->getEvent(), item->getSlotName(), &value);
45 value = (value + 1) % size;
46 item->postEventWithInt(value);
47 break;
48 case kSwitch_Type:
49 SkOSMenu::FindSwitchState(item->getEvent(), item->getSlotName(), &state);
50 item->postEventWithBool(!state);
51 break;
52 case kTriState_Type:
53 SkOSMenu::FindTriState(item->getEvent(), item->getSlotName(), &tristate);
54 if (kOnState == tristate)
55 tristate = kMixedState;
56 else
57 tristate = (SkOSMenu::TriState)((int)tristate + 1);
58 item->postEventWithInt(tristate);
59 break;
60 case kAction_Type:
61 case kCustom_Type:
62 case kSlider_Type:
63 case kTextField_Type:
64 default:
65 item->postEvent();
66 break;
67 }
68 return true;
69 }
70 }
71 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +000072}
73
yangsu@google.com654d72f2011-08-01 17:27:33 +000074////////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000075
yangsu@google.com654d72f2011-08-01 17:27:33 +000076SkOSMenu::Item::Item(const char label[], SkOSMenu::Type type,
yangsu@google.come55f5332011-08-05 22:11:41 +000077 const char slotName[], SkEvent* evt) {
yangsu@google.com654d72f2011-08-01 17:27:33 +000078 fLabel.set(label);
79 fSlotName.set(slotName);
80 fType = type;
yangsu@google.com654d72f2011-08-01 17:27:33 +000081 fEvent = evt;
yangsu@google.come55f5332011-08-05 22:11:41 +000082 fKey = 0;
yangsu@google.com654d72f2011-08-01 17:27:33 +000083 fID = sk_atomic_inc(&gOSMenuCmd);
reed@android.com8a1c16f2008-12-17 15:59:43 +000084}
85
yangsu@google.com654d72f2011-08-01 17:27:33 +000086void SkOSMenu::Item::postEventWithBool(bool value) const {
87 SkASSERT(SkOSMenu::kSwitch_Type == fType);
88 fEvent->setBool(fSlotName.c_str(), value);
89 this->postEvent();
reed@android.com8a1c16f2008-12-17 15:59:43 +000090}
91
yangsu@google.com654d72f2011-08-01 17:27:33 +000092void SkOSMenu::Item::postEventWithScalar(SkScalar value) const {
93 SkASSERT(SkOSMenu::kSlider_Type == fType);
94 fEvent->setScalar(fSlotName.c_str(), value);
95 this->postEvent();
96}
97
98void SkOSMenu::Item::postEventWithInt(int value) const {
99 SkASSERT(SkOSMenu::kList_Type == fType || SkOSMenu::kTriState_Type == fType);
100 fEvent->setS32(fSlotName.c_str(), value);
101 this->postEvent();
102}
103
104void SkOSMenu::Item::postEventWithString(const char value[]) const {
105 SkASSERT(SkOSMenu::kTextField_Type == fType);
106 fEvent->setString(fSlotName.c_str(), value);
107 this->postEvent();
108}
109
110////////////////////////////////////////////////////////////////////////////////
111
yangsu@google.come55f5332011-08-05 22:11:41 +0000112static const char* gMenuEventType = "SkOSMenuEventType";
113static const char* gSlider_Min_Scalar = "SkOSMenuSlider_Min";
114static const char* gSlider_Max_Scalar = "SkOSMenuSlider_Max";
115static const char* gDelimiter = "|";
116static const char* gList_Items_Str = "SkOSMenuList_Items";
117static const char* gList_ItemCount_S32 = "SkOSMenuList_ItemCount";
yangsu@google.com654d72f2011-08-01 17:27:33 +0000118
119int SkOSMenu::appendItem(const char label[], Type type, const char slotName[],
yangsu@google.come55f5332011-08-05 22:11:41 +0000120 SkEvent* evt) {
121 SkOSMenu::Item* item = new Item(label, type, slotName, evt);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000122 fItems.append(1, &item);
123 return item->getID();
124}
125
126int SkOSMenu::appendAction(const char label[], SkEventSinkID target) {
yangsu@google.come55f5332011-08-05 22:11:41 +0000127 SkEvent* evt = new SkEvent(gMenuEventType, target);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000128 //Store label in event so it can be used to identify the action later
yangsu@google.come55f5332011-08-05 22:11:41 +0000129 evt->setString(label, label);
130 return appendItem(label, SkOSMenu::kAction_Type, "", evt);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000131}
132
133int SkOSMenu::appendList(const char label[], const char slotName[],
134 SkEventSinkID target, int index, const char option[], ...) {
yangsu@google.come55f5332011-08-05 22:11:41 +0000135 SkEvent* evt = new SkEvent(gMenuEventType, target);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000136 va_list args;
137 if (option) {
138 SkString str(option);
139 va_start(args, option);
yangsu@google.come55f5332011-08-05 22:11:41 +0000140 int count = 1;
yangsu@google.com654d72f2011-08-01 17:27:33 +0000141 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 +0000142 str += gDelimiter;
yangsu@google.com654d72f2011-08-01 17:27:33 +0000143 str += arg;
yangsu@google.come55f5332011-08-05 22:11:41 +0000144 ++count;
yangsu@google.com654d72f2011-08-01 17:27:33 +0000145 }
146 va_end(args);
yangsu@google.come55f5332011-08-05 22:11:41 +0000147 evt->setString(gList_Items_Str, str);
148 evt->setS32(gList_ItemCount_S32, count);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000149 evt->setS32(slotName, index);
150 }
yangsu@google.come55f5332011-08-05 22:11:41 +0000151 return appendItem(label, SkOSMenu::kList_Type, slotName, evt);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000152}
153
154int SkOSMenu::appendSlider(const char label[], const char slotName[],
155 SkEventSinkID target, SkScalar min, SkScalar max,
156 SkScalar defaultValue) {
yangsu@google.come55f5332011-08-05 22:11:41 +0000157 SkEvent* evt = new SkEvent(gMenuEventType, target);
158 evt->setScalar(gSlider_Min_Scalar, min);
159 evt->setScalar(gSlider_Max_Scalar, max);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000160 evt->setScalar(slotName, defaultValue);
yangsu@google.come55f5332011-08-05 22:11:41 +0000161 return appendItem(label, SkOSMenu::kSlider_Type, slotName, evt);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000162}
163
164int SkOSMenu::appendSwitch(const char label[], const char slotName[],
165 SkEventSinkID target, bool defaultState) {
yangsu@google.come55f5332011-08-05 22:11:41 +0000166 SkEvent* evt = new SkEvent(gMenuEventType, target);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000167 evt->setBool(slotName, defaultState);
yangsu@google.come55f5332011-08-05 22:11:41 +0000168 return appendItem(label, SkOSMenu::kSwitch_Type, slotName, evt);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000169}
170
171int SkOSMenu::appendTriState(const char label[], const char slotName[],
172 SkEventSinkID target, SkOSMenu::TriState defaultState) {
yangsu@google.come55f5332011-08-05 22:11:41 +0000173 SkEvent* evt = new SkEvent(gMenuEventType, target);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000174 evt->setS32(slotName, defaultState);
yangsu@google.come55f5332011-08-05 22:11:41 +0000175 return appendItem(label, SkOSMenu::kTriState_Type, slotName, evt);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000176}
177
178int SkOSMenu::appendTextField(const char label[], const char slotName[],
179 SkEventSinkID target, const char placeholder[]) {
yangsu@google.come55f5332011-08-05 22:11:41 +0000180 SkEvent* evt = new SkEvent(gMenuEventType, target);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000181 evt->setString(slotName, placeholder);
yangsu@google.come55f5332011-08-05 22:11:41 +0000182 return appendItem(label, SkOSMenu::kTextField_Type, slotName, evt);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000183}
184
yangsu@google.come55f5332011-08-05 22:11:41 +0000185bool SkOSMenu::FindListItemCount(const SkEvent* evt, int* count) {
186 return evt->isType(gMenuEventType) && evt->findS32(gList_ItemCount_S32, count);
187}
188
189bool SkOSMenu::FindListItems(const SkEvent* evt, SkString items[]) {
190 if (evt->isType(gMenuEventType) && NULL != items) {
191 const char* text = evt->findString(gList_Items_Str);
192 char temp[strlen(text)];
193 memcpy(temp, text, strlen(text) + 1); //make sure to copy the null terminator
194 char* token = strtok(temp, gDelimiter);
195 int index = 0;
196 while (token != NULL) {
197 items[index].set(token, strlen(token));
198 token = strtok (NULL, gDelimiter);
199 ++index;
200 }
201 return true;
202 }
203 return false;
204}
205
206bool SkOSMenu::FindSliderMin(const SkEvent* evt, SkScalar* min) {
207 return evt->isType(gMenuEventType) && evt->findScalar(gSlider_Min_Scalar, min);
208}
209
210bool SkOSMenu::FindSliderMax(const SkEvent* evt, SkScalar* max) {
211 return evt->isType(gMenuEventType) && evt->findScalar(gSlider_Max_Scalar, max);
212}
yangsu@google.com654d72f2011-08-01 17:27:33 +0000213
214bool SkOSMenu::FindAction(const SkEvent* evt, const char label[]) {
yangsu@google.come55f5332011-08-05 22:11:41 +0000215 return evt->isType(gMenuEventType) && evt->findString(label);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000216}
217
yangsu@google.come55f5332011-08-05 22:11:41 +0000218bool SkOSMenu::FindListIndex(const SkEvent* evt, const char slotName[], int* value) {
219 return evt->isType(gMenuEventType) && evt->findS32(slotName, value);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000220}
221
222bool SkOSMenu::FindSliderValue(const SkEvent* evt, const char slotName[], SkScalar* value) {
yangsu@google.come55f5332011-08-05 22:11:41 +0000223 return evt->isType(gMenuEventType) && evt->findScalar(slotName, value);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000224}
225
226bool SkOSMenu::FindSwitchState(const SkEvent* evt, const char slotName[], bool* value) {
yangsu@google.come55f5332011-08-05 22:11:41 +0000227 return evt->isType(gMenuEventType) && evt->findBool(slotName, value);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000228}
229
yangsu@google.come55f5332011-08-05 22:11:41 +0000230bool SkOSMenu::FindTriState(const SkEvent* evt, const char slotName[], SkOSMenu::TriState* value) {
231 return evt->isType(gMenuEventType) && evt->findS32(slotName, (int*)value);
yangsu@google.com654d72f2011-08-01 17:27:33 +0000232}
233
234bool SkOSMenu::FindText(const SkEvent* evt, const char slotName[], SkString* value) {
yangsu@google.come55f5332011-08-05 22:11:41 +0000235 if (evt->isType(gMenuEventType)) {
yangsu@google.com654d72f2011-08-01 17:27:33 +0000236 const char* text = evt->findString(slotName);
237 if (!text || !*text)
238 return false;
239 else {
240 value->set(text);
241 return true;
242 }
243 }
244 return false;
245}