From e55f533f4c80818d542c2beac14a37600c3718f8 Mon Sep 17 00:00:00 2001 From: "yangsu@google.com" Date: Fri, 5 Aug 2011 22:11:41 +0000 Subject: [PATCH] Updated SkOSMenu to use the updated SkEvents http://codereview.appspot.com/4809075/ git-svn-id: http://skia.googlecode.com/svn/trunk@2055 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/views/SkOSMenu.h | 140 +++++++++++++++++++++------------- src/views/SkOSMenu.cpp | 160 +++++++++++++++++++++++++++------------ 2 files changed, 199 insertions(+), 101 deletions(-) diff --git a/include/views/SkOSMenu.h b/include/views/SkOSMenu.h index 54c7dbe249..763499e073 100644 --- a/include/views/SkOSMenu.h +++ b/include/views/SkOSMenu.h @@ -18,7 +18,6 @@ public: explicit SkOSMenu(const char title[] = ""); ~SkOSMenu(); - void reset(); /** * Each of these (except action) has an associated value, which is stored in * the event payload for the item. @@ -32,12 +31,6 @@ public: * TriState : TriState * Custom : custom object/value */ - enum TriState { - kMixedState = -1, - kOffState = 0, - kOnState = 1 - }; - enum Type { kAction_Type, kList_Type, @@ -48,59 +41,90 @@ public: kCustom_Type }; + enum TriState { + kMixedState = -1, + kOffState = 0, + kOnState = 1 + }; + class Item { public: - //Auto increments a global to generate an unique ID for each new item - //Thread safe + /** + * Auto increments a global to generate an unique ID for each new item + * Note: Thread safe + */ Item(const char label[], SkOSMenu::Type type, const char slotName[], - SkEvent* evt, SkEventSinkID target); + SkEvent* evt); ~Item() { delete fEvent; } - SkEvent* getEvent() const { return fEvent; } - int getID() { return fID; } + SkEvent* getEvent() const { return fEvent; } + int getID() const { return fID; } const char* getLabel() const { return fLabel.c_str(); } const char* getSlotName() const { return fSlotName.c_str(); } - Type getType() const { return fType; } + Type getType() const { return fType; } + void setKeyEquivalent(SkUnichar key) { fKey = key; } + SkUnichar getKeyEquivalent() const { return fKey; } - //Post event associated with the menu item to target, any changes to the - //associated event must be made prior to calling this method. - void postEvent() const { - (new SkEvent(*(fEvent)))->setTargetID(fTarget)->post(); - } + /** + * Post event associated with the menu item to target, any changes to + * the associated event must be made prior to calling this method + */ + void postEvent() const { (new SkEvent(*(fEvent)))->post(); } - //Helper functions for predefined types - void postEventWithBool(bool value) const; //For Switch - void postEventWithScalar(SkScalar value) const; //For Slider - void postEventWithInt(int value) const; //For List, TriState + /** + * Helper functions for predefined types + */ + void postEventWithBool(bool value) const; //For Switch + void postEventWithScalar(SkScalar value) const; //For Slider + void postEventWithInt(int value) const; //For List, TriState void postEventWithString(const char value[]) const; //For TextField - private: int fID; SkEvent* fEvent; SkString fLabel; SkString fSlotName; - SkEventSinkID fTarget; Type fType; + SkUnichar fKey; }; - //The following functions append new items to the menu and returns their - //associated unique id, which can be used to by the client to refer to - //the menu item created and change its state. slotName specifies the string - //identifier of any state/value to be returned in the item's SkEvent object - //NOTE: evt must be dynamically allocated + void reset(); + const char* getTitle() const { return fTitle.c_str(); } + void setTitle (const char title[]) { fTitle.set(title); } + int countItems() const { return fItems.count(); } + const Item* getItem(int index) const { return fItems[index]; } + + /** + * Assign key to the menu item with itemID, will do nothing if there's no + * item with the id given + */ + void assignKeyEquivalentToItem(int itemID, SkUnichar key); + /** + * Call this in a SkView's onHandleChar to trigger any menu items with the + * given key equivalent. If such an item is found, the method will return + * true and its corresponding event will be triggered (default behavior + * defined for switches(toggling), tristates(cycle), and lists(cycle), + * for anything else, the event attached is posted without state changes) + * If no menu item can be matched with the key, false will be returned + */ + bool handleKeyEquivalent(SkUnichar key); + + /** + * The following functions append new items to the menu and returns their + * associated unique id, which can be used to by the client to refer to + * the menu item created and change its state. slotName specifies the string + * identifier of any state/value to be returned in the item's SkEvent object + * NOTE: evt must be dynamically allocated + */ int appendItem(const char label[], Type type, const char slotName[], - SkEvent* evt, SkEventSinkID target); + SkEvent* evt); - //Predefined items and helper functions: - //Identifiers - static const char* EventType; - static const char* Delimiter; - static const char* List_Items_Str; - static const char* Slider_Min_Scalar; - static const char* Slider_Max_Scalar; - - //Create predefined items with the given parameters. To be used with the + /** + * Create predefined items with the given parameters. To be used with the + * other helper functions below to retrive/update state information. + * Note: the helper functions below assume that slotName is UNIQUE for all + * menu items of the same type since it's used to identify the event + */ int appendAction(const char label[], SkEventSinkID target); int appendList(const char label[], const char slotName[], SkEventSinkID target, int defaultIndex, const char[] ...); @@ -110,26 +134,40 @@ public: int appendSwitch(const char label[], const char slotName[], SkEventSinkID target, bool defaultState = false); int appendTriState(const char label[], const char slotName[], - SkEventSinkID target, SkOSMenu::TriState defaultState = kOffState); + SkEventSinkID target, TriState defaultState = kOffState); int appendTextField(const char label[], const char slotName[], SkEventSinkID target, const char placeholder[] = ""); - //Returns true if the event is of type SkOSMenu::EventType and retrieves - //value stored in the evt that corresponds to the slotName. Otherwise, - //returns false and leaves value unchanged + + /** + * Helper functions to retrieve information other than the stored value for + * some predefined types + */ + static bool FindListItemCount(const SkEvent* evt, int* count); + /** + * Ensure that the items array can store n SkStrings where n is the count + * extracted using FindListItemCount + */ + static bool FindListItems(const SkEvent* evt, SkString items[]); + static bool FindSliderMin(const SkEvent* evt, SkScalar* min); + static bool FindSliderMax(const SkEvent* evt, SkScalar* max); + + /** + * Returns true if an action with the given label is found, false otherwise + */ static bool FindAction(const SkEvent* evt, const char label[]); - static bool FindListIndex(const SkEvent* evt, const char slotName[], int* selected); + /** + * The following helper functions will return true if evt is generated from + * a predefined item type and retrieve the corresponding state information. + * They will return false and leave value unchanged if there's a type + * mismatch or slotName is incorrect + */ + static bool FindListIndex(const SkEvent* evt, const char slotName[], int* value); static bool FindSliderValue(const SkEvent* evt, const char slotName[], SkScalar* value); static bool FindSwitchState(const SkEvent* evt, const char slotName[], bool* value); - static bool FindTriState(const SkEvent* evt, const char slotName[], TriState* state); + static bool FindTriState(const SkEvent* evt, const char slotName[], TriState* value); static bool FindText(const SkEvent* evt, const char slotName[], SkString* value); - const char* getTitle() const { return fTitle.c_str(); } - void setTitle (const char title[]) { fTitle.set(title); } - // called by SkOSWindow when it receives an OS menu event - int countItems() const; - const Item* getItem(int index) const; - private: SkString fTitle; SkTDArray fItems; diff --git a/src/views/SkOSMenu.cpp b/src/views/SkOSMenu.cpp index a8856cccd7..8137365d00 100644 --- a/src/views/SkOSMenu.cpp +++ b/src/views/SkOSMenu.cpp @@ -23,23 +23,63 @@ void SkOSMenu::reset() { fTitle.reset(); } -int SkOSMenu::countItems() const { - return fItems.count(); +void SkOSMenu::assignKeyEquivalentToItem(int itemID, SkUnichar key) { + for (int i = 0; i < fItems.count(); ++i) { + if (itemID == fItems[i]->getID()) + fItems[i]->setKeyEquivalent(key); + } } -const SkOSMenu::Item* SkOSMenu::getItem(int index) const{ - return fItems[index]; +bool SkOSMenu::handleKeyEquivalent(SkUnichar key) { + int value = 0, size = 0; + bool state; + SkOSMenu::TriState tristate; + for (int i = 0; i < fItems.count(); ++i) { + Item* item = fItems[i]; + if (item->getKeyEquivalent()== key) { + SkString list; + switch (item->getType()) { + case kList_Type: + SkOSMenu::FindListItemCount(item->getEvent(), &size); + SkOSMenu::FindListIndex(item->getEvent(), item->getSlotName(), &value); + value = (value + 1) % size; + item->postEventWithInt(value); + break; + case kSwitch_Type: + SkOSMenu::FindSwitchState(item->getEvent(), item->getSlotName(), &state); + item->postEventWithBool(!state); + break; + case kTriState_Type: + SkOSMenu::FindTriState(item->getEvent(), item->getSlotName(), &tristate); + if (kOnState == tristate) + tristate = kMixedState; + else + tristate = (SkOSMenu::TriState)((int)tristate + 1); + item->postEventWithInt(tristate); + break; + case kAction_Type: + case kCustom_Type: + case kSlider_Type: + case kTextField_Type: + default: + item->postEvent(); + break; + } + return true; + } + } + return false; } //////////////////////////////////////////////////////////////////////////////// SkOSMenu::Item::Item(const char label[], SkOSMenu::Type type, - const char slotName[], SkEvent* evt, SkEventSinkID target) { + const char slotName[], SkEvent* evt) { fLabel.set(label); fSlotName.set(slotName); fType = type; - fTarget = target; fEvent = evt; + fKey = 0; fID = sk_atomic_inc(&gOSMenuCmd); } @@ -69,110 +109,130 @@ void SkOSMenu::Item::postEventWithString(const char value[]) const { //////////////////////////////////////////////////////////////////////////////// -const char* SkOSMenu::EventType = "SkOSMenuEventType"; -const char* SkOSMenu::Delimiter = "|"; -const char* SkOSMenu::Slider_Min_Scalar = "SkOSMenuSlider_Min"; -const char* SkOSMenu::Slider_Max_Scalar = "SkOSMenuSlider_Max"; -const char* SkOSMenu::List_Items_Str = "SkOSMenuList_Items"; +static const char* gMenuEventType = "SkOSMenuEventType"; +static const char* gSlider_Min_Scalar = "SkOSMenuSlider_Min"; +static const char* gSlider_Max_Scalar = "SkOSMenuSlider_Max"; +static const char* gDelimiter = "|"; +static const char* gList_Items_Str = "SkOSMenuList_Items"; +static const char* gList_ItemCount_S32 = "SkOSMenuList_ItemCount"; int SkOSMenu::appendItem(const char label[], Type type, const char slotName[], - SkEvent* evt, SkEventSinkID target) { - SkOSMenu::Item* item = new Item(label, type, slotName, evt, target); + SkEvent* evt) { + SkOSMenu::Item* item = new Item(label, type, slotName, evt); fItems.append(1, &item); return item->getID(); } int SkOSMenu::appendAction(const char label[], SkEventSinkID target) { - SkEvent* evt = new SkEvent(SkOSMenu::EventType); - SkOSMenu::Item* item = new Item(label, SkOSMenu::kAction_Type, "", evt, target); + SkEvent* evt = new SkEvent(gMenuEventType, target); //Store label in event so it can be used to identify the action later - evt->setString(label, ""); - fItems.append(1, &item); - return item->getID(); + evt->setString(label, label); + return appendItem(label, SkOSMenu::kAction_Type, "", evt); } int SkOSMenu::appendList(const char label[], const char slotName[], SkEventSinkID target, int index, const char option[], ...) { - SkEvent* evt = new SkEvent(SkOSMenu::EventType); + SkEvent* evt = new SkEvent(gMenuEventType, target); va_list args; if (option) { SkString str(option); va_start(args, option); + int count = 1; for (const char* arg = va_arg(args, const char*); arg != NULL; arg = va_arg(args, const char*)) { - str += SkOSMenu::Delimiter; + str += gDelimiter; str += arg; + ++count; } va_end(args); - evt->setString(SkOSMenu::List_Items_Str, str); + evt->setString(gList_Items_Str, str); + evt->setS32(gList_ItemCount_S32, count); evt->setS32(slotName, index); } - SkOSMenu::Item* item = new Item(label, SkOSMenu::kList_Type, slotName, evt, target); - fItems.append(1, &item); - return item->getID(); + return appendItem(label, SkOSMenu::kList_Type, slotName, evt); } int SkOSMenu::appendSlider(const char label[], const char slotName[], SkEventSinkID target, SkScalar min, SkScalar max, SkScalar defaultValue) { - SkEvent* evt = new SkEvent(SkOSMenu::EventType); - evt->setScalar(SkOSMenu::Slider_Min_Scalar, min); - evt->setScalar(SkOSMenu::Slider_Max_Scalar, max); + SkEvent* evt = new SkEvent(gMenuEventType, target); + evt->setScalar(gSlider_Min_Scalar, min); + evt->setScalar(gSlider_Max_Scalar, max); evt->setScalar(slotName, defaultValue); - SkOSMenu::Item* item = new Item(label, SkOSMenu::kSlider_Type, slotName, evt, target); - fItems.append(1, &item); - return item->getID(); + return appendItem(label, SkOSMenu::kSlider_Type, slotName, evt); } int SkOSMenu::appendSwitch(const char label[], const char slotName[], SkEventSinkID target, bool defaultState) { - SkEvent* evt = new SkEvent(SkOSMenu::EventType); + SkEvent* evt = new SkEvent(gMenuEventType, target); evt->setBool(slotName, defaultState); - SkOSMenu::Item* item = new Item(label, SkOSMenu::kSwitch_Type, slotName, evt, target); - fItems.append(1, &item); - return item->getID(); + return appendItem(label, SkOSMenu::kSwitch_Type, slotName, evt); } int SkOSMenu::appendTriState(const char label[], const char slotName[], SkEventSinkID target, SkOSMenu::TriState defaultState) { - SkEvent* evt = new SkEvent(SkOSMenu::EventType); + SkEvent* evt = new SkEvent(gMenuEventType, target); evt->setS32(slotName, defaultState); - SkOSMenu::Item* item = new Item(label, SkOSMenu::kTriState_Type, slotName, evt, target); - fItems.append(1, &item); - return item->getID(); + return appendItem(label, SkOSMenu::kTriState_Type, slotName, evt); } int SkOSMenu::appendTextField(const char label[], const char slotName[], SkEventSinkID target, const char placeholder[]) { - SkEvent* evt = new SkEvent(SkOSMenu::EventType); + SkEvent* evt = new SkEvent(gMenuEventType, target); evt->setString(slotName, placeholder); - SkOSMenu::Item* item = new Item(label, SkOSMenu::kTextField_Type, slotName, evt, target); - fItems.append(1, &item); - return item->getID(); + return appendItem(label, SkOSMenu::kTextField_Type, slotName, evt); } +bool SkOSMenu::FindListItemCount(const SkEvent* evt, int* count) { + return evt->isType(gMenuEventType) && evt->findS32(gList_ItemCount_S32, count); +} + +bool SkOSMenu::FindListItems(const SkEvent* evt, SkString items[]) { + if (evt->isType(gMenuEventType) && NULL != items) { + const char* text = evt->findString(gList_Items_Str); + char temp[strlen(text)]; + memcpy(temp, text, strlen(text) + 1); //make sure to copy the null terminator + char* token = strtok(temp, gDelimiter); + int index = 0; + while (token != NULL) { + items[index].set(token, strlen(token)); + token = strtok (NULL, gDelimiter); + ++index; + } + return true; + } + return false; +} + +bool SkOSMenu::FindSliderMin(const SkEvent* evt, SkScalar* min) { + return evt->isType(gMenuEventType) && evt->findScalar(gSlider_Min_Scalar, min); +} + +bool SkOSMenu::FindSliderMax(const SkEvent* evt, SkScalar* max) { + return evt->isType(gMenuEventType) && evt->findScalar(gSlider_Max_Scalar, max); +} bool SkOSMenu::FindAction(const SkEvent* evt, const char label[]) { - return evt->isType(SkOSMenu::EventType) && evt->findString(label); + return evt->isType(gMenuEventType) && evt->findString(label); } -bool SkOSMenu::FindListIndex(const SkEvent* evt, const char slotName[], int* selected) { - return evt->isType(SkOSMenu::EventType) && evt->findS32(slotName, selected); +bool SkOSMenu::FindListIndex(const SkEvent* evt, const char slotName[], int* value) { + return evt->isType(gMenuEventType) && evt->findS32(slotName, value); } bool SkOSMenu::FindSliderValue(const SkEvent* evt, const char slotName[], SkScalar* value) { - return evt->isType(SkOSMenu::EventType) && evt->findScalar(slotName, value); + return evt->isType(gMenuEventType) && evt->findScalar(slotName, value); } bool SkOSMenu::FindSwitchState(const SkEvent* evt, const char slotName[], bool* value) { - return evt->isType(SkOSMenu::EventType) && evt->findBool(slotName, value); + return evt->isType(gMenuEventType) && evt->findBool(slotName, value); } -bool SkOSMenu::FindTriState(const SkEvent* evt, const char slotName[], SkOSMenu::TriState* state) { - return evt->isType(SkOSMenu::EventType) && evt->findS32(slotName, (int*)state); +bool SkOSMenu::FindTriState(const SkEvent* evt, const char slotName[], SkOSMenu::TriState* value) { + return evt->isType(gMenuEventType) && evt->findS32(slotName, (int*)value); } bool SkOSMenu::FindText(const SkEvent* evt, const char slotName[], SkString* value) { - if (evt->isType(SkOSMenu::EventType)) { + if (evt->isType(gMenuEventType)) { const char* text = evt->findString(slotName); if (!text || !*text) return false;