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
diff --git a/include/views/SkOSMenu.h b/include/views/SkOSMenu.h
index 54c7dbe..763499e 100644
--- a/include/views/SkOSMenu.h
+++ b/include/views/SkOSMenu.h
@@ -18,7 +18,6 @@
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 @@
* TriState : TriState
* Custom : custom object/value
*/
- enum TriState {
- kMixedState = -1,
- kOffState = 0,
- kOnState = 1
- };
-
enum Type {
kAction_Type,
kList_Type,
@@ -48,59 +41,90 @@
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 @@
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<Item*> fItems;
diff --git a/src/views/SkOSMenu.cpp b/src/views/SkOSMenu.cpp
index a8856cc..8137365 100644
--- a/src/views/SkOSMenu.cpp
+++ b/src/views/SkOSMenu.cpp
@@ -23,23 +23,63 @@
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 @@
////////////////////////////////////////////////////////////////////////////////
-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;