Revised SkOSMenu
http://codereview.appspot.com/4827042/
git-svn-id: http://skia.googlecode.com/svn/trunk@2013 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/views/SkOSMenu.h b/include/views/SkOSMenu.h
index c599bd8..2dbc1a5 100644
--- a/include/views/SkOSMenu.h
+++ b/include/views/SkOSMenu.h
@@ -15,30 +15,123 @@
class SkOSMenu {
public:
- explicit SkOSMenu(const char title[]);
+ 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.
+ * Each type has a specific type for its value...
+ * Action : none
+ * List : int (selected index)
+ * Segmented : int (selected index)
+ * Slider : float
+ * Switch : bool
+ * TextField : string
+ * TriState : TriState
+ * Custom : custom object/value
+ */
+ enum TriState {
+ kMixedState = -1,
+ kOffState = 0,
+ kOnState = 1
+ };
+
+ enum Type {
+ kAction_Type,
+ kList_Type,
+ kSlider_Type,
+ kSwitch_Type,
+ kTriState_Type,
+ kTextField_Type,
+ kCustom_Type
+ };
+
+ class Item {
+ public:
+ //Auto increments a global to generate an unique ID for each new item
+ //Thread safe
+ Item(const char label[], SkOSMenu::Type type, const char slotName[],
+ SkEvent* evt, SkEventSinkID target);
+ ~Item() { delete fEvent; }
+
+ SkEvent* getEvent() const { return fEvent; }
+ int getID() { return fID; }
+ const char* getLabel() const { return fLabel.c_str(); }
+ const char* getSlotName() const { return fSlotName.c_str(); }
+ Type getType() const { return fType; }
+
+ //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(fTarget); }
+
+ //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
- const char* getTitle() const { return fTitle; }
-
- void appendItem(const char title[], const char eventType[], int32_t eventData);
-
+
+ private:
+ int fID;
+ SkEvent* fEvent;
+ SkString fLabel;
+ SkString fSlotName;
+ SkEventSinkID fTarget;
+ Type fType;
+ };
+
+ //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);
+
+ //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
+ int appendAction(const char label[], SkEventSinkID target);
+ int appendList(const char label[], const char slotName[],
+ SkEventSinkID target, int defaultIndex, const char[] ...);
+ int appendSlider(const char label[], const char slotName[],
+ SkEventSinkID target, SkScalar min, SkScalar max,
+ SkScalar defaultValue);
+ 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);
+ 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
+ static bool FindAction(const SkEvent* evt, const char label[]);
+ static bool FindListIndex(const SkEvent* evt, const char slotName[], int* selected);
+ 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 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 char* getItem(int index, uint32_t* cmdID) const;
-
- SkEvent* createEvent(uint32_t os_cmd);
+ const Item* getItem(int index) const;
private:
- const char* fTitle;
-
- struct Item {
- const char* fTitle;
- const char* fEventType;
- uint32_t fEventData;
- uint32_t fOSCmd; // internal
- };
- SkTDArray<Item> fItems;
-
+ SkString fTitle;
+ SkTDArray<Item*> fItems;
+
// illegal
SkOSMenu(const SkOSMenu&);
SkOSMenu& operator=(const SkOSMenu&);
diff --git a/include/views/SkWindow.h b/include/views/SkWindow.h
index 64c5bea..eda928c 100644
--- a/include/views/SkWindow.h
+++ b/include/views/SkWindow.h
@@ -51,9 +51,9 @@
bool handleChar(SkUnichar);
bool handleKey(SkKey);
bool handleKeyUp(SkKey);
- bool handleMenu(uint32_t os_cmd);
void addMenu(SkOSMenu*);
+ const SkTDArray<SkOSMenu*>* getMenus() { return &fMenus; }
const char* getTitle() const { return fTitle.c_str(); }
void setTitle(const char title[]);
@@ -73,7 +73,8 @@
virtual bool onHandleChar(SkUnichar);
virtual bool onHandleKey(SkKey);
virtual bool onHandleKeyUp(SkKey);
- virtual void onAddMenu(const SkOSMenu*) {}
+ virtual void onAddMenu(const SkOSMenu*) {};
+ virtual void onUpdateMenu(const SkOSMenu*) {};
virtual void onSetTitle(const char title[]) {}
// overrides from SkView
diff --git a/src/views/SkOSMenu.cpp b/src/views/SkOSMenu.cpp
index 5ce36dc..a8856cc 100644
--- a/src/views/SkOSMenu.cpp
+++ b/src/views/SkOSMenu.cpp
@@ -1,60 +1,185 @@
-
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
+#include <stdarg.h>
#include "SkOSMenu.h"
+#include "SkThread.h"
static int gOSMenuCmd = 7000;
-SkOSMenu::SkOSMenu(const char title[])
-{
- fTitle = title;
+SkOSMenu::SkOSMenu(const char title[]) {
+ fTitle.set(title);
}
-SkOSMenu::~SkOSMenu()
-{
+SkOSMenu::~SkOSMenu() {
+ this->reset();
}
-int SkOSMenu::countItems() const
-{
+void SkOSMenu::reset() {
+ fItems.deleteAll();
+ fTitle.reset();
+}
+
+int SkOSMenu::countItems() const {
return fItems.count();
}
-void SkOSMenu::appendItem(const char title[], const char eventType[], int32_t eventData)
-{
- Item* item = fItems.append();
-
- item->fTitle = title;
- item->fEventType = eventType;
- item->fEventData = eventData;
- item->fOSCmd = ++gOSMenuCmd;
+const SkOSMenu::Item* SkOSMenu::getItem(int index) const{
+ return fItems[index];
}
-SkEvent* SkOSMenu::createEvent(uint32_t os_cmd)
-{
- const Item* iter = fItems.begin();
- const Item* stop = fItems.end();
+////////////////////////////////////////////////////////////////////////////////
- while (iter < stop)
- {
- if (iter->fOSCmd == os_cmd)
- {
- SkEvent* evt = new SkEvent(iter->fEventType);
- evt->setFast32(iter->fEventData);
- return evt;
- }
- iter++;
- }
- return NULL;
+SkOSMenu::Item::Item(const char label[], SkOSMenu::Type type,
+ const char slotName[], SkEvent* evt, SkEventSinkID target) {
+ fLabel.set(label);
+ fSlotName.set(slotName);
+ fType = type;
+ fTarget = target;
+ fEvent = evt;
+ fID = sk_atomic_inc(&gOSMenuCmd);
}
-const char* SkOSMenu::getItem(int index, uint32_t* cmdID) const
-{
- if (cmdID)
- *cmdID = fItems[index].fOSCmd;
- return fItems[index].fTitle;
+void SkOSMenu::Item::postEventWithBool(bool value) const {
+ SkASSERT(SkOSMenu::kSwitch_Type == fType);
+ fEvent->setBool(fSlotName.c_str(), value);
+ this->postEvent();
}
+void SkOSMenu::Item::postEventWithScalar(SkScalar value) const {
+ SkASSERT(SkOSMenu::kSlider_Type == fType);
+ fEvent->setScalar(fSlotName.c_str(), value);
+ this->postEvent();
+}
+
+void SkOSMenu::Item::postEventWithInt(int value) const {
+ SkASSERT(SkOSMenu::kList_Type == fType || SkOSMenu::kTriState_Type == fType);
+ fEvent->setS32(fSlotName.c_str(), value);
+ this->postEvent();
+}
+
+void SkOSMenu::Item::postEventWithString(const char value[]) const {
+ SkASSERT(SkOSMenu::kTextField_Type == fType);
+ fEvent->setString(fSlotName.c_str(), value);
+ this->postEvent();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+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";
+
+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);
+ 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);
+ //Store label in event so it can be used to identify the action later
+ evt->setString(label, "");
+ fItems.append(1, &item);
+ return item->getID();
+}
+
+int SkOSMenu::appendList(const char label[], const char slotName[],
+ SkEventSinkID target, int index, const char option[], ...) {
+ SkEvent* evt = new SkEvent(SkOSMenu::EventType);
+ va_list args;
+ if (option) {
+ SkString str(option);
+ va_start(args, option);
+ for (const char* arg = va_arg(args, const char*); arg != NULL; arg = va_arg(args, const char*)) {
+ str += SkOSMenu::Delimiter;
+ str += arg;
+ }
+ va_end(args);
+ evt->setString(SkOSMenu::List_Items_Str, str);
+ evt->setS32(slotName, index);
+ }
+ SkOSMenu::Item* item = new Item(label, SkOSMenu::kList_Type, slotName, evt, target);
+ fItems.append(1, &item);
+ return item->getID();
+}
+
+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);
+ evt->setScalar(slotName, defaultValue);
+ SkOSMenu::Item* item = new Item(label, SkOSMenu::kSlider_Type, slotName, evt, target);
+ fItems.append(1, &item);
+ return item->getID();
+}
+
+int SkOSMenu::appendSwitch(const char label[], const char slotName[],
+ SkEventSinkID target, bool defaultState) {
+ SkEvent* evt = new SkEvent(SkOSMenu::EventType);
+ evt->setBool(slotName, defaultState);
+ SkOSMenu::Item* item = new Item(label, SkOSMenu::kSwitch_Type, slotName, evt, target);
+ fItems.append(1, &item);
+ return item->getID();
+}
+
+int SkOSMenu::appendTriState(const char label[], const char slotName[],
+ SkEventSinkID target, SkOSMenu::TriState defaultState) {
+ SkEvent* evt = new SkEvent(SkOSMenu::EventType);
+ evt->setS32(slotName, defaultState);
+ SkOSMenu::Item* item = new Item(label, SkOSMenu::kTriState_Type, slotName, evt, target);
+ fItems.append(1, &item);
+ return item->getID();
+}
+
+int SkOSMenu::appendTextField(const char label[], const char slotName[],
+ SkEventSinkID target, const char placeholder[]) {
+ SkEvent* evt = new SkEvent(SkOSMenu::EventType);
+ evt->setString(slotName, placeholder);
+ SkOSMenu::Item* item = new Item(label, SkOSMenu::kTextField_Type, slotName, evt, target);
+ fItems.append(1, &item);
+ return item->getID();
+}
+
+
+bool SkOSMenu::FindAction(const SkEvent* evt, const char label[]) {
+ return evt->isType(SkOSMenu::EventType) && 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::FindSliderValue(const SkEvent* evt, const char slotName[], SkScalar* value) {
+ return evt->isType(SkOSMenu::EventType) && evt->findScalar(slotName, value);
+}
+
+bool SkOSMenu::FindSwitchState(const SkEvent* evt, const char slotName[], bool* value) {
+ return evt->isType(SkOSMenu::EventType) && 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::FindText(const SkEvent* evt, const char slotName[], SkString* value) {
+ if (evt->isType(SkOSMenu::EventType)) {
+ const char* text = evt->findString(slotName);
+ if (!text || !*text)
+ return false;
+ else {
+ value->set(text);
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/views/SkWindow.cpp b/src/views/SkWindow.cpp
index ef3264f..f6054df 100644
--- a/src/views/SkWindow.cpp
+++ b/src/views/SkWindow.cpp
@@ -290,8 +290,7 @@
return false;
}
-void SkWindow::addMenu(SkOSMenu* menu)
-{
+void SkWindow::addMenu(SkOSMenu* menu) {
*fMenus.append() = menu;
this->onAddMenu(menu);
}
@@ -304,20 +303,6 @@
this->onSetTitle(title);
}
-bool SkWindow::handleMenu(uint32_t cmd)
-{
- for (int i = 0; i < fMenus.count(); i++)
- {
- SkEvent* evt = fMenus[i]->createEvent(cmd);
- if (evt)
- {
- evt->post(this->getSinkID());
- return true;
- }
- }
- return false;
-}
-
//////////////////////////////////////////////////////////////////////
bool SkWindow::onEvent(const SkEvent& evt)