Home | History | Annotate | Download | only in views
      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 
     11 static int gOSMenuCmd = 7000;
     12 
     13 SkOSMenu::SkOSMenu(const char title[]) {
     14     fTitle.set(title);
     15 }
     16 
     17 SkOSMenu::~SkOSMenu() {
     18     this->reset();
     19 }
     20 
     21 void SkOSMenu::reset() {
     22     fItems.deleteAll();
     23     fTitle.reset();
     24 }
     25 
     26 const 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 
     34 void 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 
     42 void 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 
     49 bool 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 
     92 SkOSMenu::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 
    102 void SkOSMenu::Item::setBool(bool value) const {
    103     SkASSERT(SkOSMenu::kSwitch_Type == fType);
    104     fEvent->setBool(fSlotName.c_str(), value);
    105 }
    106 
    107 void SkOSMenu::Item::setScalar(SkScalar value) const {
    108     SkASSERT(SkOSMenu::kSlider_Type == fType);
    109     fEvent->setScalar(fSlotName.c_str(), value);
    110 }
    111 
    112 void SkOSMenu::Item::setInt(int value) const {
    113     SkASSERT(SkOSMenu::kList_Type == fType);
    114     fEvent->setS32(fSlotName.c_str(), value);
    115 }
    116 
    117 void SkOSMenu::Item::setTriState(TriState value) const {
    118     SkASSERT(SkOSMenu::kTriState_Type == fType);
    119     fEvent->setS32(fSlotName.c_str(), value);
    120 }
    121 
    122 void SkOSMenu::Item::setString(const char value[]) const {
    123     SkASSERT(SkOSMenu::kTextField_Type == fType);
    124     fEvent->setString(fSlotName.c_str(), value);
    125 }
    126 
    127 ////////////////////////////////////////////////////////////////////////////////
    128 
    129 static const char* gMenuEventType = "SkOSMenuEventType";
    130 static const char* gSlider_Min_Scalar = "SkOSMenuSlider_Min";
    131 static const char* gSlider_Max_Scalar = "SkOSMenuSlider_Max";
    132 static const char* gDelimiter = "|";
    133 static const char* gList_Items_Str = "SkOSMenuList_Items";
    134 static const char* gList_ItemCount_S32 = "SkOSMenuList_ItemCount";
    135 
    136 int 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 
    143 int 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 
    150 int 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 
    171 int 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 
    181 int 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 
    188 int 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 
    195 int 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 
    202 bool SkOSMenu::FindListItemCount(const SkEvent& evt, int* count) {
    203     return evt.isType(gMenuEventType) && evt.findS32(gList_ItemCount_S32, count);
    204 }
    205 
    206 bool 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 
    224 bool SkOSMenu::FindSliderMin(const SkEvent& evt, SkScalar* min) {
    225     return evt.isType(gMenuEventType) && evt.findScalar(gSlider_Min_Scalar, min);
    226 }
    227 
    228 bool SkOSMenu::FindSliderMax(const SkEvent& evt, SkScalar* max) {
    229     return evt.isType(gMenuEventType) && evt.findScalar(gSlider_Max_Scalar, max);
    230 }
    231 
    232 bool SkOSMenu::FindAction(const SkEvent& evt, const char label[]) {
    233     return evt.isType(gMenuEventType) && evt.findString(label);
    234 }
    235 
    236 bool SkOSMenu::FindListIndex(const SkEvent& evt, const char slotName[], int* value) {
    237     return evt.isType(gMenuEventType) && evt.findS32(slotName, value);
    238 }
    239 
    240 bool SkOSMenu::FindSliderValue(const SkEvent& evt, const char slotName[], SkScalar* value) {
    241     return evt.isType(gMenuEventType) && evt.findScalar(slotName, value);
    242 }
    243 
    244 bool SkOSMenu::FindSwitchState(const SkEvent& evt, const char slotName[], bool* value) {
    245     return evt.isType(gMenuEventType) && evt.findBool(slotName, value);
    246 }
    247 
    248 bool SkOSMenu::FindTriState(const SkEvent& evt, const char slotName[], SkOSMenu::TriState* value) {
    249     return evt.isType(gMenuEventType) && evt.findS32(slotName, (int*)value);
    250 }
    251 
    252 bool 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