CCMenu.cpp

Look for addTouchEvent() - DipankarDas, 2014-03-08 00:03

Download (13.5 kB)

 
1
/****************************************************************************
2
Copyright (c) 2008-2010 Ricardo Quesada
3
Copyright (c) 2010-2012 cocos2d-x.org
4
Copyright (c) 2013-2014 Chukong Technologies Inc.
5

    
6
http://www.cocos2d-x.org
7

    
8
Permission is hereby granted, free of charge, to any person obtaining a copy
9
of this software and associated documentation files (the "Software"), to deal
10
in the Software without restriction, including without limitation the rights
11
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
copies of the Software, and to permit persons to whom the Software is
13
furnished to do so, subject to the following conditions:
14

    
15
The above copyright notice and this permission notice shall be included in
16
all copies or substantial portions of the Software.
17

    
18
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
THE SOFTWARE.
25
****************************************************************************/
26
#include "CCMenu.h"
27
#include "CCDirector.h"
28
#include "CCApplication.h"
29
#include "CCTouch.h"
30
#include "CCStdC.h"
31
#include "CCInteger.h"
32
#include "CCEventListenerTouch.h"
33
#include "CCString.h"
34

    
35
#include <vector>
36
#include <stdarg.h>
37

    
38
using namespace std;
39

    
40
NS_CC_BEGIN
41

    
42
enum 
43
{
44
    kDefaultPadding =  5,
45
};
46

    
47
//
48
//CCMenu
49
//
50

    
51
Menu::~Menu()
52
{
53
    CCLOGINFO("In the destructor of Menu. %p", this);
54
}
55

    
56
Menu* Menu::create()
57
{
58
    return Menu::create(nullptr, nullptr);
59
}
60

    
61
Menu * Menu::create(MenuItem* item, ...)
62
{
63
    va_list args;
64
    va_start(args,item);
65
    
66
    Menu *ret = Menu::createWithItems(item, args);
67
    
68
    va_end(args);
69
    
70
    return ret;
71
}
72

    
73
Menu* Menu::createWithArray(const Vector<MenuItem*>& arrayOfItems)
74
{
75
    auto ret = new Menu();
76
    if (ret && ret->initWithArray(arrayOfItems))
77
    {
78
        ret->autorelease();
79
    }
80
    else
81
    {
82
        CC_SAFE_DELETE(ret);
83
    }
84
    
85
    return ret;
86
}
87

    
88
Menu* Menu::createWithItems(MenuItem* item, va_list args)
89
{
90
    Vector<MenuItem*> items;
91
    if( item )
92
    {
93
        items.pushBack(item);
94
        MenuItem *i = va_arg(args, MenuItem*);
95
        while(i)
96
        {
97
            items.pushBack(i);
98
            i = va_arg(args, MenuItem*);
99
        }
100
    }
101
    
102
    return Menu::createWithArray(items);
103
}
104

    
105
Menu* Menu::createWithItem(MenuItem* item)
106
{
107
    return Menu::create(item, nullptr);
108
}
109

    
110
bool Menu::init()
111
{
112
    return initWithArray(Vector<MenuItem*>());
113
}
114

    
115
bool Menu::initWithArray(const Vector<MenuItem*>& arrayOfItems)
116
{
117
    if (Layer::init())
118
    {
119
        _enabled = true;
120
        // menu in the center of the screen
121
        Size s = Director::getInstance()->getWinSize();
122

    
123
        this->ignoreAnchorPointForPosition(true);
124
        setAnchorPoint(Point(0.5f, 0.5f));
125
        this->setContentSize(s);
126

    
127
        setPosition(Point(s.width/2, s.height/2));
128
        
129
        int z=0;
130
        
131
        for (auto& item : arrayOfItems)
132
        {
133
            this->addChild(item, z);
134
            z++;
135
        }
136
    
137
        _selectedItem = nullptr;
138
        _state = Menu::State::WAITING;
139
        
140
        // enable cascade color and opacity on menus
141
        setCascadeColorEnabled(true);
142
        setCascadeOpacityEnabled(true);
143
      
144
        //adds even listener for Menu
145
        addTouchEvent();
146
      
147
        return true;
148
    }
149
    return false;
150
}
151

    
152
/*
153
 * adds even listener for Menu 
154
 */
155

    
156
void Menu::addTouchEvent()
157
{
158
  auto touchListener = EventListenerTouchOneByOne::create();
159
  touchListener->setSwallowTouches(true);
160
  
161
  touchListener->onTouchBegan = CC_CALLBACK_2(Menu::onTouchBegan, this);
162
  touchListener->onTouchMoved = CC_CALLBACK_2(Menu::onTouchMoved, this);
163
  touchListener->onTouchEnded = CC_CALLBACK_2(Menu::onTouchEnded, this);
164
  touchListener->onTouchCancelled = CC_CALLBACK_2(Menu::onTouchCancelled, this);
165
  
166
  _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
167
}
168

    
169

    
170
/*
171
* override add:
172
*/
173
void Menu::addChild(Node * child)
174
{
175
    Layer::addChild(child);
176
}
177

    
178
void Menu::addChild(Node * child, int zOrder)
179
{
180
    Layer::addChild(child, zOrder);
181
}
182

    
183
void Menu::addChild(Node * child, int zOrder, int tag)
184
{
185
    CCASSERT( dynamic_cast<MenuItem*>(child) != nullptr, "Menu only supports MenuItem objects as children");
186
    Layer::addChild(child, zOrder, tag);
187
}
188

    
189
void Menu::onEnter()
190
{
191
    Layer::onEnter();
192
}
193

    
194
void Menu::onExit()
195
{
196
    if (_state == Menu::State::TRACKING_TOUCH)
197
    {
198
        if (_selectedItem)
199
        {
200
            _selectedItem->unselected();
201
            _selectedItem = nullptr;
202
        }
203
        
204
        _state = Menu::State::WAITING;
205
    }
206

    
207
    Layer::onExit();
208
}
209

    
210
void Menu::removeChild(Node* child, bool cleanup)
211
{
212
    MenuItem *menuItem = dynamic_cast<MenuItem*>(child);
213
    CCASSERT(menuItem != nullptr, "Menu only supports MenuItem objects as children");
214
    
215
    if (_selectedItem == menuItem)
216
    {
217
        _selectedItem = nullptr;
218
    }
219
    
220
    Node::removeChild(child, cleanup);
221
}
222

    
223
//Menu - Events
224

    
225
bool Menu::onTouchBegan(Touch* touch, Event* event)
226
{
227
    if (_state != Menu::State::WAITING || ! _visible || !_enabled)
228
    {
229
        return false;
230
    }
231
    
232
    for (Node *c = this->_parent; c != nullptr; c = c->getParent())
233
    {
234
        if (c->isVisible() == false)
235
        {
236
            return false;
237
        }
238
    }
239
    
240
    _selectedItem = this->getItemForTouch(touch);
241
    if (_selectedItem)
242
    {
243
        _state = Menu::State::TRACKING_TOUCH;
244
        _selectedItem->selected();
245
        
246
        return true;
247
    }
248
    
249
    return false;
250
}
251

    
252
void Menu::onTouchEnded(Touch* touch, Event* event)
253
{
254
    CCASSERT(_state == Menu::State::TRACKING_TOUCH, "[Menu ccTouchEnded] -- invalid state");
255
    this->retain();
256
    if (_selectedItem)
257
    {
258
        _selectedItem->unselected();
259
        _selectedItem->activate();
260
    }
261
    _state = Menu::State::WAITING;
262
    this->release();
263
}
264

    
265
void Menu::onTouchCancelled(Touch* touch, Event* event)
266
{
267
    CCASSERT(_state == Menu::State::TRACKING_TOUCH, "[Menu ccTouchCancelled] -- invalid state");
268
    this->retain();
269
    if (_selectedItem)
270
    {
271
        _selectedItem->unselected();
272
    }
273
    _state = Menu::State::WAITING;
274
    this->release();
275
}
276

    
277
void Menu::onTouchMoved(Touch* touch, Event* event)
278
{
279
    CCASSERT(_state == Menu::State::TRACKING_TOUCH, "[Menu ccTouchMoved] -- invalid state");
280
    MenuItem *currentItem = this->getItemForTouch(touch);
281
    if (currentItem != _selectedItem)
282
    {
283
        if (_selectedItem)
284
        {
285
            _selectedItem->unselected();
286
        }
287
        _selectedItem = currentItem;
288
        if (_selectedItem)
289
        {
290
            _selectedItem->selected();
291
        }
292
    }
293
}
294

    
295
//Menu - Alignment
296
void Menu::alignItemsVertically()
297
{
298
    this->alignItemsVerticallyWithPadding(kDefaultPadding);
299
}
300

    
301
void Menu::alignItemsVerticallyWithPadding(float padding)
302
{
303
    float height = -padding;
304

    
305
    for(const auto &child : _children)
306
        height += child->getContentSize().height * child->getScaleY() + padding;
307

    
308
    float y = height / 2.0f;
309
    
310
    for(const auto &child : _children) {
311
        child->setPosition(Point(0, y - child->getContentSize().height * child->getScaleY() / 2.0f));
312
        y -= child->getContentSize().height * child->getScaleY() + padding;
313
    }
314
}
315

    
316
void Menu::alignItemsHorizontally(void)
317
{
318
    this->alignItemsHorizontallyWithPadding(kDefaultPadding);
319
}
320

    
321
void Menu::alignItemsHorizontallyWithPadding(float padding)
322
{
323
    float width = -padding;
324
    for(const auto &child : _children)
325
        width += child->getContentSize().width * child->getScaleX() + padding;
326

    
327
    float x = -width / 2.0f;
328
    
329
    for(const auto &child : _children) {
330
        child->setPosition(Point(x + child->getContentSize().width * child->getScaleX() / 2.0f, 0));
331
        x += child->getContentSize().width * child->getScaleX() + padding;
332
    }
333
}
334

    
335
void Menu::alignItemsInColumns(int columns, ...)
336
{
337
    va_list args;
338
    va_start(args, columns);
339

    
340
    this->alignItemsInColumns(columns, args);
341

    
342
    va_end(args);
343
}
344

    
345
void Menu::alignItemsInColumns(int columns, va_list args)
346
{
347
    CCASSERT(columns >= 0, "Columns must be >= 0");
348
    ValueVector rows;
349
    while (columns)
350
    {
351
        rows.push_back(Value(columns));
352
        columns = va_arg(args, int);
353
    }
354
    alignItemsInColumnsWithArray(rows);
355
}
356

    
357
void Menu::alignItemsInColumnsWithArray(const ValueVector& rows)
358
{
359
    int height = -5;
360
    size_t row = 0;
361
    int rowHeight = 0;
362
    int columnsOccupied = 0;
363
    int rowColumns = 0;
364

    
365
    for(const auto &child : _children) {
366
        CCASSERT(row < rows.size(), "");
367
        
368
        rowColumns = rows[row].asInt();
369
        // can not have zero columns on a row
370
        CCASSERT(rowColumns, "");
371
        
372
        float tmp = child->getContentSize().height;
373
        rowHeight = (unsigned int)((rowHeight >= tmp || isnan(tmp)) ? rowHeight : tmp);
374
        
375
        ++columnsOccupied;
376
        if (columnsOccupied >= rowColumns)
377
        {
378
            height += rowHeight + 5;
379
            
380
            columnsOccupied = 0;
381
            rowHeight = 0;
382
            ++row;
383
        }
384
    }
385

    
386
    // check if too many rows/columns for available menu items
387
    CCASSERT(! columnsOccupied, "");
388

    
389
    Size winSize = Director::getInstance()->getWinSize();
390

    
391
    row = 0;
392
    rowHeight = 0;
393
    rowColumns = 0;
394
    float w = 0.0;
395
    float x = 0.0;
396
    float y = (float)(height / 2);
397

    
398
    for(const auto &child : _children) {
399
        if (rowColumns == 0)
400
        {
401
            rowColumns = rows[row].asInt();
402
            w = winSize.width / (1 + rowColumns);
403
            x = w;
404
        }
405

    
406
        float tmp = child->getContentSize().height;
407
        rowHeight = (unsigned int)((rowHeight >= tmp || isnan(tmp)) ? rowHeight : tmp);
408

    
409
        child->setPosition(Point(x - winSize.width / 2,
410
                               y - child->getContentSize().height / 2));
411

    
412
        x += w;
413
        ++columnsOccupied;
414

    
415
        if (columnsOccupied >= rowColumns)
416
        {
417
            y -= rowHeight + 5;
418

    
419
            columnsOccupied = 0;
420
            rowColumns = 0;
421
            rowHeight = 0;
422
            ++row;
423
        }
424
    }
425
}
426

    
427
void Menu::alignItemsInRows(int rows, ...)
428
{
429
    va_list args;
430
    va_start(args, rows);
431

    
432
    this->alignItemsInRows(rows, args);
433

    
434
    va_end(args);
435
}
436

    
437
void Menu::alignItemsInRows(int rows, va_list args)
438
{
439
    ValueVector array;
440
    while (rows)
441
    {
442
        array.push_back(Value(rows));
443
        rows = va_arg(args, int);
444
    }
445
    alignItemsInRowsWithArray(array);
446
}
447

    
448
void Menu::alignItemsInRowsWithArray(const ValueVector& columns)
449
{
450
    vector<int> columnWidths;
451
    vector<int> columnHeights;
452

    
453
    int width = -10;
454
    int columnHeight = -5;
455
    size_t column = 0;
456
    int columnWidth = 0;
457
    int rowsOccupied = 0;
458
    int columnRows;
459

    
460
    for(const auto &child : _children) {
461
        // check if too many menu items for the amount of rows/columns
462
        CCASSERT(column < columns.size(), "");
463

    
464
        columnRows = columns[column].asInt();
465
        // can't have zero rows on a column
466
        CCASSERT(columnRows, "");
467

    
468
        // columnWidth = fmaxf(columnWidth, [item contentSize].width);
469
        float tmp = child->getContentSize().width;
470
        columnWidth = (unsigned int)((columnWidth >= tmp || isnan(tmp)) ? columnWidth : tmp);
471

    
472
        columnHeight += (int)(child->getContentSize().height + 5);
473
        ++rowsOccupied;
474

    
475
        if (rowsOccupied >= columnRows)
476
        {
477
            columnWidths.push_back(columnWidth);
478
            columnHeights.push_back(columnHeight);
479
            width += columnWidth + 10;
480

    
481
            rowsOccupied = 0;
482
            columnWidth = 0;
483
            columnHeight = -5;
484
            ++column;
485
        }
486
    }
487

    
488
    // check if too many rows/columns for available menu items.
489
    CCASSERT(! rowsOccupied, "");
490

    
491
    Size winSize = Director::getInstance()->getWinSize();
492

    
493
    column = 0;
494
    columnWidth = 0;
495
    columnRows = 0;
496
    float x = (float)(-width / 2);
497
    float y = 0.0;
498

    
499
    for(const auto &child : _children) {
500
        if (columnRows == 0)
501
        {
502
            columnRows = columns[column].asInt();
503
            y = (float) columnHeights[column];
504
        }
505

    
506
        // columnWidth = fmaxf(columnWidth, [item contentSize].width);
507
        float tmp = child->getContentSize().width;
508
        columnWidth = (unsigned int)((columnWidth >= tmp || isnan(tmp)) ? columnWidth : tmp);
509

    
510
        child->setPosition(Point(x + columnWidths[column] / 2,
511
                               y - winSize.height / 2));
512

    
513
        y -= child->getContentSize().height + 10;
514
        ++rowsOccupied;
515

    
516
        if (rowsOccupied >= columnRows)
517
        {
518
            x += columnWidth + 5;
519
            rowsOccupied = 0;
520
            columnRows = 0;
521
            columnWidth = 0;
522
            ++column;
523
        }
524
    }
525
}
526

    
527
MenuItem* Menu::getItemForTouch(Touch *touch)
528
{
529
    Point touchLocation = touch->getLocation();
530

    
531
    if (!_children.empty())
532
    {
533
        for (auto iter = _children.crbegin(); iter != _children.crend(); ++iter)
534
        {
535
            MenuItem* child = dynamic_cast<MenuItem*>(*iter);
536
            if (child && child->isVisible() && child->isEnabled())
537
            {
538
                Point local = child->convertToNodeSpace(touchLocation);
539
                Rect r = child->rect();
540
                r.origin = Point::ZERO;
541
                
542
                if (r.containsPoint(local))
543
                {
544
                    return child;
545
                }
546
            }
547
        }
548
    }
549

    
550
    return nullptr;
551
}
552

    
553
std::string Menu::getDescription() const
554
{
555
    return StringUtils::format("<Menu | Tag = %d>", _tag);
556
}
557

    
558
NS_CC_END