michael@0: /* michael@0: * Copyright 2011 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: #include michael@0: #include "SkOSMenu.h" michael@0: #include "SkThread.h" michael@0: michael@0: static int gOSMenuCmd = 7000; michael@0: michael@0: SkOSMenu::SkOSMenu(const char title[]) { michael@0: fTitle.set(title); michael@0: } michael@0: michael@0: SkOSMenu::~SkOSMenu() { michael@0: this->reset(); michael@0: } michael@0: michael@0: void SkOSMenu::reset() { michael@0: fItems.deleteAll(); michael@0: fTitle.reset(); michael@0: } michael@0: michael@0: const SkOSMenu::Item* SkOSMenu::getItemByID(int itemID) const { michael@0: for (int i = 0; i < fItems.count(); ++i) { michael@0: if (itemID == fItems[i]->getID()) michael@0: return fItems[i]; michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: void SkOSMenu::getItems(const SkOSMenu::Item* items[]) const { michael@0: if (NULL != items) { michael@0: for (int i = 0; i < fItems.count(); ++i) { michael@0: items[i] = fItems[i]; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void SkOSMenu::assignKeyEquivalentToItem(int itemID, SkUnichar key) { michael@0: for (int i = 0; i < fItems.count(); ++i) { michael@0: if (itemID == fItems[i]->getID()) michael@0: fItems[i]->setKeyEquivalent(key); michael@0: } michael@0: } michael@0: michael@0: bool SkOSMenu::handleKeyEquivalent(SkUnichar key) { michael@0: int value = 0, size = 0; michael@0: bool state; michael@0: SkOSMenu::TriState tristate; michael@0: for (int i = 0; i < fItems.count(); ++i) { michael@0: Item* item = fItems[i]; michael@0: if (item->getKeyEquivalent()== key) { michael@0: SkString list; michael@0: switch (item->getType()) { michael@0: case kList_Type: michael@0: SkOSMenu::FindListItemCount(*item->getEvent(), &size); michael@0: SkOSMenu::FindListIndex(*item->getEvent(), item->getSlotName(), &value); michael@0: value = (value + 1) % size; michael@0: item->setInt(value); michael@0: break; michael@0: case kSwitch_Type: michael@0: SkOSMenu::FindSwitchState(*item->getEvent(), item->getSlotName(), &state); michael@0: item->setBool(!state); michael@0: break; michael@0: case kTriState_Type: michael@0: SkOSMenu::FindTriState(*item->getEvent(), item->getSlotName(), &tristate); michael@0: if (kOnState == tristate) michael@0: tristate = kMixedState; michael@0: else michael@0: tristate = (SkOSMenu::TriState)((int)tristate + 1); michael@0: item->setTriState(tristate); michael@0: break; michael@0: case kAction_Type: michael@0: case kCustom_Type: michael@0: case kSlider_Type: michael@0: case kTextField_Type: michael@0: default: michael@0: break; michael@0: } michael@0: item->postEvent(); michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: SkOSMenu::Item::Item(const char label[], SkOSMenu::Type type, michael@0: const char slotName[], SkEvent* evt) { michael@0: fLabel.set(label); michael@0: fSlotName.set(slotName); michael@0: fType = type; michael@0: fEvent = evt; michael@0: fKey = 0; michael@0: fID = sk_atomic_inc(&gOSMenuCmd); michael@0: } michael@0: michael@0: void SkOSMenu::Item::setBool(bool value) const { michael@0: SkASSERT(SkOSMenu::kSwitch_Type == fType); michael@0: fEvent->setBool(fSlotName.c_str(), value); michael@0: } michael@0: michael@0: void SkOSMenu::Item::setScalar(SkScalar value) const { michael@0: SkASSERT(SkOSMenu::kSlider_Type == fType); michael@0: fEvent->setScalar(fSlotName.c_str(), value); michael@0: } michael@0: michael@0: void SkOSMenu::Item::setInt(int value) const { michael@0: SkASSERT(SkOSMenu::kList_Type == fType); michael@0: fEvent->setS32(fSlotName.c_str(), value); michael@0: } michael@0: michael@0: void SkOSMenu::Item::setTriState(TriState value) const { michael@0: SkASSERT(SkOSMenu::kTriState_Type == fType); michael@0: fEvent->setS32(fSlotName.c_str(), value); michael@0: } michael@0: michael@0: void SkOSMenu::Item::setString(const char value[]) const { michael@0: SkASSERT(SkOSMenu::kTextField_Type == fType); michael@0: fEvent->setString(fSlotName.c_str(), value); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: static const char* gMenuEventType = "SkOSMenuEventType"; michael@0: static const char* gSlider_Min_Scalar = "SkOSMenuSlider_Min"; michael@0: static const char* gSlider_Max_Scalar = "SkOSMenuSlider_Max"; michael@0: static const char* gDelimiter = "|"; michael@0: static const char* gList_Items_Str = "SkOSMenuList_Items"; michael@0: static const char* gList_ItemCount_S32 = "SkOSMenuList_ItemCount"; michael@0: michael@0: int SkOSMenu::appendItem(const char label[], Type type, const char slotName[], michael@0: SkEvent* evt) { michael@0: SkOSMenu::Item* item = new Item(label, type, slotName, evt); michael@0: fItems.append(1, &item); michael@0: return item->getID(); michael@0: } michael@0: michael@0: int SkOSMenu::appendAction(const char label[], SkEventSinkID target) { michael@0: SkEvent* evt = new SkEvent(gMenuEventType, target); michael@0: //Store label in event so it can be used to identify the action later michael@0: evt->setString(label, label); michael@0: return appendItem(label, SkOSMenu::kAction_Type, "", evt); michael@0: } michael@0: michael@0: int SkOSMenu::appendList(const char label[], const char slotName[], michael@0: SkEventSinkID target, int index, const char option[], ...) { michael@0: SkEvent* evt = new SkEvent(gMenuEventType, target); michael@0: va_list args; michael@0: if (option) { michael@0: SkString str(option); michael@0: va_start(args, option); michael@0: int count = 1; michael@0: for (const char* arg = va_arg(args, const char*); arg != NULL; arg = va_arg(args, const char*)) { michael@0: str += gDelimiter; michael@0: str += arg; michael@0: ++count; michael@0: } michael@0: va_end(args); michael@0: evt->setString(gList_Items_Str, str); michael@0: evt->setS32(gList_ItemCount_S32, count); michael@0: evt->setS32(slotName, index); michael@0: } michael@0: return appendItem(label, SkOSMenu::kList_Type, slotName, evt); michael@0: } michael@0: michael@0: int SkOSMenu::appendSlider(const char label[], const char slotName[], michael@0: SkEventSinkID target, SkScalar min, SkScalar max, michael@0: SkScalar defaultValue) { michael@0: SkEvent* evt = new SkEvent(gMenuEventType, target); michael@0: evt->setScalar(gSlider_Min_Scalar, min); michael@0: evt->setScalar(gSlider_Max_Scalar, max); michael@0: evt->setScalar(slotName, defaultValue); michael@0: return appendItem(label, SkOSMenu::kSlider_Type, slotName, evt); michael@0: } michael@0: michael@0: int SkOSMenu::appendSwitch(const char label[], const char slotName[], michael@0: SkEventSinkID target, bool defaultState) { michael@0: SkEvent* evt = new SkEvent(gMenuEventType, target); michael@0: evt->setBool(slotName, defaultState); michael@0: return appendItem(label, SkOSMenu::kSwitch_Type, slotName, evt); michael@0: } michael@0: michael@0: int SkOSMenu::appendTriState(const char label[], const char slotName[], michael@0: SkEventSinkID target, SkOSMenu::TriState defaultState) { michael@0: SkEvent* evt = new SkEvent(gMenuEventType, target); michael@0: evt->setS32(slotName, defaultState); michael@0: return appendItem(label, SkOSMenu::kTriState_Type, slotName, evt); michael@0: } michael@0: michael@0: int SkOSMenu::appendTextField(const char label[], const char slotName[], michael@0: SkEventSinkID target, const char placeholder[]) { michael@0: SkEvent* evt = new SkEvent(gMenuEventType, target); michael@0: evt->setString(slotName, placeholder); michael@0: return appendItem(label, SkOSMenu::kTextField_Type, slotName, evt); michael@0: } michael@0: michael@0: bool SkOSMenu::FindListItemCount(const SkEvent& evt, int* count) { michael@0: return evt.isType(gMenuEventType) && evt.findS32(gList_ItemCount_S32, count); michael@0: } michael@0: michael@0: bool SkOSMenu::FindListItems(const SkEvent& evt, SkString items[]) { michael@0: if (evt.isType(gMenuEventType) && NULL != items) { michael@0: const char* text = evt.findString(gList_Items_Str); michael@0: if (text != NULL) { michael@0: SkString temp(text); michael@0: char* token = strtok((char*)temp.c_str(), gDelimiter); michael@0: int index = 0; michael@0: while (token != NULL) { michael@0: items[index].set(token, strlen(token)); michael@0: token = strtok (NULL, gDelimiter); michael@0: ++index; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: bool SkOSMenu::FindSliderMin(const SkEvent& evt, SkScalar* min) { michael@0: return evt.isType(gMenuEventType) && evt.findScalar(gSlider_Min_Scalar, min); michael@0: } michael@0: michael@0: bool SkOSMenu::FindSliderMax(const SkEvent& evt, SkScalar* max) { michael@0: return evt.isType(gMenuEventType) && evt.findScalar(gSlider_Max_Scalar, max); michael@0: } michael@0: michael@0: bool SkOSMenu::FindAction(const SkEvent& evt, const char label[]) { michael@0: return evt.isType(gMenuEventType) && evt.findString(label); michael@0: } michael@0: michael@0: bool SkOSMenu::FindListIndex(const SkEvent& evt, const char slotName[], int* value) { michael@0: return evt.isType(gMenuEventType) && evt.findS32(slotName, value); michael@0: } michael@0: michael@0: bool SkOSMenu::FindSliderValue(const SkEvent& evt, const char slotName[], SkScalar* value) { michael@0: return evt.isType(gMenuEventType) && evt.findScalar(slotName, value); michael@0: } michael@0: michael@0: bool SkOSMenu::FindSwitchState(const SkEvent& evt, const char slotName[], bool* value) { michael@0: return evt.isType(gMenuEventType) && evt.findBool(slotName, value); michael@0: } michael@0: michael@0: bool SkOSMenu::FindTriState(const SkEvent& evt, const char slotName[], SkOSMenu::TriState* value) { michael@0: return evt.isType(gMenuEventType) && evt.findS32(slotName, (int*)value); michael@0: } michael@0: michael@0: bool SkOSMenu::FindText(const SkEvent& evt, const char slotName[], SkString* value) { michael@0: if (evt.isType(gMenuEventType)) { michael@0: const char* text = evt.findString(slotName); michael@0: if (!text || !*text) michael@0: return false; michael@0: else { michael@0: value->set(text); michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: }