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 <stdarg.h> 8#include "SkOSMenu.h" 9#include "SkThread.h" 10 11static int gOSMenuCmd = 7000; 12 13SkOSMenu::SkOSMenu(const char title[]) { 14 fTitle.set(title); 15} 16 17SkOSMenu::~SkOSMenu() { 18 this->reset(); 19} 20 21void SkOSMenu::reset() { 22 fItems.deleteAll(); 23 fTitle.reset(); 24} 25 26const 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 { 35 if (NULL != items) { 36 for (int i = 0; i < fItems.count(); ++i) { 37 items[i] = fItems[i]; 38 } 39 } 40} 41 42void 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 49bool 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 92SkOSMenu::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 102void SkOSMenu::Item::setBool(bool value) const { 103 SkASSERT(SkOSMenu::kSwitch_Type == fType); 104 fEvent->setBool(fSlotName.c_str(), value); 105} 106 107void SkOSMenu::Item::setScalar(SkScalar value) const { 108 SkASSERT(SkOSMenu::kSlider_Type == fType); 109 fEvent->setScalar(fSlotName.c_str(), value); 110} 111 112void SkOSMenu::Item::setInt(int value) const { 113 SkASSERT(SkOSMenu::kList_Type == fType); 114 fEvent->setS32(fSlotName.c_str(), value); 115} 116 117void 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 { 123 SkASSERT(SkOSMenu::kTextField_Type == fType); 124 fEvent->setString(fSlotName.c_str(), value); 125} 126 127//////////////////////////////////////////////////////////////////////////////// 128 129static 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"; 135 136int 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 143int 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 150int 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 != NULL; 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 171int 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 181int 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 188int 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 195int 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 202bool SkOSMenu::FindListItemCount(const SkEvent& evt, int* count) { 203 return evt.isType(gMenuEventType) && evt.findS32(gList_ItemCount_S32, count); 204} 205 206bool SkOSMenu::FindListItems(const SkEvent& evt, SkString items[]) { 207 if (evt.isType(gMenuEventType) && NULL != items) { 208 const char* text = evt.findString(gList_Items_Str); 209 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 } 218 } 219 return true; 220 } 221 return false; 222} 223 224bool SkOSMenu::FindSliderMin(const SkEvent& evt, SkScalar* min) { 225 return evt.isType(gMenuEventType) && evt.findScalar(gSlider_Min_Scalar, min); 226} 227 228bool SkOSMenu::FindSliderMax(const SkEvent& evt, SkScalar* max) { 229 return evt.isType(gMenuEventType) && evt.findScalar(gSlider_Max_Scalar, max); 230} 231 232bool SkOSMenu::FindAction(const SkEvent& evt, const char label[]) { 233 return evt.isType(gMenuEventType) && evt.findString(label); 234} 235 236bool SkOSMenu::FindListIndex(const SkEvent& evt, const char slotName[], int* value) { 237 return evt.isType(gMenuEventType) && evt.findS32(slotName, value); 238} 239 240bool SkOSMenu::FindSliderValue(const SkEvent& evt, const char slotName[], SkScalar* value) { 241 return evt.isType(gMenuEventType) && evt.findScalar(slotName, value); 242} 243 244bool SkOSMenu::FindSwitchState(const SkEvent& evt, const char slotName[], bool* value) { 245 return evt.isType(gMenuEventType) && evt.findBool(slotName, value); 246} 247 248bool SkOSMenu::FindTriState(const SkEvent& evt, const char slotName[], SkOSMenu::TriState* value) { 249 return evt.isType(gMenuEventType) && evt.findS32(slotName, (int*)value); 250} 251 252bool 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