mirror of https://github.com/axmolengine/axmol.git
514 lines
14 KiB
C++
514 lines
14 KiB
C++
#include "../effects/CCGrid.h"
|
||
#include "NdCxList.h"
|
||
|
||
namespace NdCxControl
|
||
{
|
||
#define FLOAT_EQUAL(x,y) (fabs((x)-(y)) < 0.0001f)
|
||
|
||
NdCxList::NdCxList(float row_height, ccColor4B bg_color, CCSize size)
|
||
: sel_item_(NULL)
|
||
, row_height_(row_height)
|
||
, old_y_(0.f)
|
||
, min_y_(0.f)
|
||
, max_y_(0.f)
|
||
, touch_began_y_(0.f)
|
||
, touch_ended_y_(0.f)
|
||
, snap_flag_(false)
|
||
, list_state_(LS_WAITING)
|
||
, item_click_listener_(NULL)
|
||
{
|
||
if (size.width <= 0 || size.height <= 0)
|
||
{
|
||
size = CCDirector::sharedDirector()->getWinSize();
|
||
}
|
||
|
||
initWithColorWidthHeight(bg_color, size.width, size.height);
|
||
|
||
inner_panel_ = CCLayer::node();
|
||
inner_panel_->setPosition(CCPointZero);
|
||
inner_panel_->setContentSize(size);
|
||
CCLayerColor::addChild(inner_panel_);
|
||
|
||
line_color_ = ccc3(0xBD, 0xBD, 0xBD);
|
||
sel_item_end_color_ = ccc3(0, 0xFF, 0xFF);
|
||
sel_item_start_color_ = ccc3(0xFF, 0xFF, 0);
|
||
}
|
||
|
||
NdCxList::~NdCxList(void)
|
||
{
|
||
inner_panel_->removeAllChildrenWithCleanup(true);
|
||
}
|
||
|
||
int NdCxList::addChild(NdCxListItem *item, bool scroll_to_view)
|
||
{
|
||
inner_panel_->addChild(item);
|
||
item->release();
|
||
|
||
CCArray *children = inner_panel_->getChildren();
|
||
int item_count = children->count();
|
||
if (1 == item_count)
|
||
{
|
||
item->setDrawTopLine(true);
|
||
}
|
||
|
||
CCSize panel_size = inner_panel_->getContentSize();
|
||
|
||
item->setLineColor(line_color_);
|
||
item->setSelectedColor(sel_item_start_color_, sel_item_end_color_);
|
||
item->initWithWidthHeight(panel_size.width, row_height_);
|
||
item->requestLayout();
|
||
|
||
// 计算位置,item的高度可能在调用requestLayout后有所变化
|
||
float item_y_pos = 0.f;
|
||
CCSize item_size = item->getContentSize();
|
||
if (item_count > 1)
|
||
{
|
||
CCNode *last_child = (CCNode *)children->objectAtIndex(item_count - 2);
|
||
item_y_pos = last_child->getPosition().y - item_size.height;
|
||
}
|
||
else
|
||
{
|
||
item_y_pos = panel_size.height - item_size.height;
|
||
}
|
||
|
||
item->setPosition(CCPointMake(0, item_y_pos));
|
||
|
||
float total_height = 0.f;
|
||
for (int i = 0; i < (int)children->count(); ++i)
|
||
{
|
||
total_height += ((CCNode *)children->objectAtIndex(i))->getContentSize().height;
|
||
}
|
||
|
||
if (total_height > panel_size.height)
|
||
{
|
||
max_y_ = total_height - panel_size.height;
|
||
}
|
||
else
|
||
{
|
||
max_y_ = 0;
|
||
}
|
||
|
||
int rst = children->count() - 1;
|
||
if (scroll_to_view && (rst + 1) * row_height_ > panel_size.height)
|
||
{
|
||
doFitPos(max_y_);
|
||
}
|
||
|
||
return rst;
|
||
}
|
||
|
||
NdCxListItem *NdCxList::getChild(int row_index)
|
||
{
|
||
return (NdCxListItem *)inner_panel_->getChildren()->objectAtIndex(row_index);
|
||
}
|
||
|
||
void NdCxList::clear(void)
|
||
{
|
||
inner_panel_->removeAllChildrenWithCleanup(true);
|
||
sel_item_ = NULL;
|
||
old_y_ = 0.f;
|
||
min_y_ = 0.f;
|
||
max_y_ = 0.f;
|
||
touch_began_y_ = 0.f;
|
||
touch_ended_y_ = 0.f;
|
||
snap_flag_ = false;
|
||
list_state_ = LS_WAITING;
|
||
inner_panel_->setPosition(CCPointZero);
|
||
}
|
||
|
||
void NdCxList::onEnter(void)
|
||
{
|
||
setIsTouchEnabled(true);
|
||
CCLayerColor::onEnter();
|
||
}
|
||
|
||
void NdCxList::onExit(void)
|
||
{
|
||
setIsTouchEnabled(false);
|
||
CCLayerColor::onExit();
|
||
}
|
||
|
||
void NdCxList::registerWithTouchDispatcher()
|
||
{
|
||
CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this, INT_MIN+9999, false);
|
||
}
|
||
|
||
bool NdCxList::ccTouchBegan(CCTouch* touch, CCEvent* event)
|
||
{
|
||
if (!containsTouchLocation(touch) || !getIsVisible())
|
||
{
|
||
return false;
|
||
}
|
||
|
||
CCArray *children = inner_panel_->getChildren();
|
||
if (LS_WAITING != list_state_ || !m_bIsVisible || !children)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
list_state_ = LS_TRACKINGTOUCH;
|
||
CCPoint touchPoint = touch->locationInView(touch->view());
|
||
old_y_ = inner_panel_->getPosition().y;
|
||
touch_began_y_ = touch_ended_y_ = CCDirector::sharedDirector()->convertToGL(touchPoint).y;
|
||
|
||
snap_flag_ = true;
|
||
|
||
NdCxListItem *sel_item = itemForTouch(touch);
|
||
if (sel_item && sel_item != sel_item_)
|
||
{
|
||
sel_item->selected();
|
||
if (sel_item_)
|
||
{
|
||
sel_item_->unselected();
|
||
}
|
||
}
|
||
|
||
sel_item_ = sel_item;
|
||
|
||
//CCTime::gettimeofdayCocos2d(&touch_began_time_, NULL);
|
||
touch_began_time_ = clock();
|
||
|
||
return true;
|
||
}
|
||
|
||
void NdCxList::doFitPos(float y_pos)
|
||
{
|
||
inner_panel_->stopAllActions();
|
||
|
||
CCMoveTo *move_to = new CCMoveTo();
|
||
move_to->initWithDuration(0.66f, CCPointMake(0, y_pos));
|
||
CCEaseExponentialOut *ease_action = new CCEaseExponentialOut();
|
||
ease_action->initWithAction(move_to);
|
||
move_to->release();
|
||
inner_panel_->runAction(ease_action);
|
||
ease_action->release();
|
||
}
|
||
|
||
void NdCxList::ccTouchEnded(CCTouch* touch, CCEvent* event)
|
||
{
|
||
if (LS_TRACKINGTOUCH != list_state_)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (sel_item_)
|
||
{
|
||
if (FLOAT_EQUAL(touch_began_y_, touch_ended_y_))
|
||
{
|
||
if (item_click_listener_)
|
||
{
|
||
item_click_listener_->onClick(
|
||
inner_panel_->getChildren()->indexOfObject(sel_item_), sel_item_);
|
||
}
|
||
#ifdef ENABLE_LUA
|
||
else if (m_scriptSeletor.size())
|
||
{
|
||
CCLuaScriptModule::sharedLuaScriptModule()->executeListItem(m_scriptSeletor,
|
||
inner_panel_->getChildren()->indexOfObject(sel_item_), sel_item_);
|
||
}
|
||
#endif
|
||
|
||
onItemClick(inner_panel_->getChildren()->indexOfObject(sel_item_), sel_item_);
|
||
}
|
||
}
|
||
|
||
// 如果超出范围,则反弹回去。
|
||
CCPoint pos = inner_panel_->getPosition();
|
||
if (FLOAT_EQUAL(min_y_, max_y_))
|
||
{
|
||
if (!FLOAT_EQUAL(pos.y, 0.f))
|
||
{
|
||
doFitPos(0.f);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (pos.y < min_y_)
|
||
{
|
||
doFitPos(min_y_);
|
||
}
|
||
else if (pos.y > max_y_)
|
||
{
|
||
doFitPos(max_y_);
|
||
}
|
||
else
|
||
{
|
||
if (!FLOAT_EQUAL(touch_began_y_, touch_ended_y_))
|
||
{
|
||
float acce_val = 0.f;
|
||
float fit_pos = inner_panel_->getPosition().y;
|
||
float abs_distance = fabs(touch_ended_y_ - touch_began_y_);
|
||
|
||
/*cc_timeval end_time, sub_time;
|
||
CCTime::gettimeofdayCocos2d(&end_time, NULL);
|
||
CCTime::timersubCocos2d(&sub_time, &touch_began_time_, &end_time);
|
||
int time_consume = sub_time.tv_sec * 1000 + sub_time.tv_usec/1000;*/
|
||
int time_consume = clock() - touch_began_time_;
|
||
if (time_consume < 400 && abs_distance > row_height_)
|
||
{
|
||
acce_val = (abs_distance / row_height_) * 3.f * row_height_;
|
||
}
|
||
else
|
||
{
|
||
acce_val = float((int)row_height_ / 3);
|
||
}
|
||
|
||
// 向下拖拽
|
||
if (touch_began_y_ > touch_ended_y_)
|
||
{
|
||
fit_pos -= acce_val;
|
||
if (fit_pos < min_y_)
|
||
{
|
||
fit_pos = min_y_;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
fit_pos += acce_val;
|
||
if (fit_pos > max_y_)
|
||
{
|
||
fit_pos = max_y_;
|
||
}
|
||
}
|
||
|
||
doFitPos(fit_pos);
|
||
}
|
||
}
|
||
}
|
||
|
||
list_state_ = LS_WAITING;
|
||
}
|
||
|
||
void NdCxList::ccTouchCancelled(CCTouch *touch, CCEvent *event)
|
||
{
|
||
list_state_ = LS_WAITING;
|
||
}
|
||
|
||
void NdCxList::ccTouchMoved(CCTouch* touch, CCEvent* event)
|
||
{
|
||
if (LS_TRACKINGTOUCH != list_state_)
|
||
{
|
||
return;
|
||
}
|
||
|
||
CCPoint touchPoint = touch->locationInView(touch->view());
|
||
touchPoint = CCDirector::sharedDirector()->convertToGL(touchPoint);
|
||
touch_ended_y_ = touchPoint.y;
|
||
|
||
if (snap_flag_ && fabs(touch_ended_y_ - touch_began_y_) < 15.f)
|
||
{
|
||
return;
|
||
}
|
||
|
||
snap_flag_ = false;
|
||
|
||
inner_panel_->setPosition(CCPointMake(inner_panel_->getPosition().x,
|
||
old_y_ + (touch_ended_y_ - touch_began_y_)));
|
||
}
|
||
|
||
void NdCxList::destroy(void)
|
||
{
|
||
release();
|
||
}
|
||
|
||
void NdCxList::keep(void)
|
||
{
|
||
retain();
|
||
}
|
||
|
||
NdCxListItem* NdCxList::itemForTouch(CCTouch * touch)
|
||
{
|
||
CCArray *children = inner_panel_->getChildren();
|
||
if (!children || !children->count())
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
CCPoint touch_loc = touch->locationInView(touch->view());
|
||
touch_loc = CCDirector::sharedDirector()->convertToGL(touch_loc);
|
||
CCPoint local_loc = inner_panel_->convertToNodeSpace(touch_loc);
|
||
|
||
for (int i = 0, l = (int)children->count(); i != l; ++i)
|
||
{
|
||
CCNode *node = (CCNode *)children->objectAtIndex(i);
|
||
if (CCRect::CCRectContainsPoint(node->boundingBox(), local_loc))
|
||
{
|
||
return (NdCxListItem*)node;
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
void NdCxList::selectChild(int row_index)
|
||
{
|
||
CCArray *children = inner_panel_->getChildren();
|
||
if (!children || !children->count() || row_index < 0 || row_index >= (int)children->count())
|
||
{
|
||
return;
|
||
}
|
||
|
||
NdCxListItem *sel_item = (NdCxListItem *)children->objectAtIndex(row_index);
|
||
if (sel_item != sel_item_)
|
||
{
|
||
sel_item->selected();
|
||
|
||
if (sel_item_)
|
||
{
|
||
sel_item_->unselected();
|
||
}
|
||
|
||
sel_item_ = sel_item;
|
||
|
||
CCSize panel_size = inner_panel_->getContentSize();
|
||
CCArray *children = inner_panel_->getChildren();
|
||
float inc_height = 0.f;
|
||
for (int i = 0; i <= row_index; ++i)
|
||
{
|
||
inc_height += ((CCNode *)children->objectAtIndex(i))->getContentSize().height;
|
||
}
|
||
|
||
if (inc_height > panel_size.height)
|
||
{
|
||
doFitPos(inc_height - panel_size.height);
|
||
}
|
||
}
|
||
}
|
||
|
||
NdCxListItem *NdCxList::getSelectedChild(void)
|
||
{
|
||
return sel_item_;
|
||
}
|
||
|
||
void NdCxList::setLineColor(ccColor3B &color)
|
||
{
|
||
line_color_ = color;
|
||
}
|
||
|
||
void NdCxList::setSelectedItemColor(ccColor3B &start_color, ccColor3B &end_color)
|
||
{
|
||
sel_item_start_color_ = start_color;
|
||
sel_item_end_color_ = end_color;
|
||
}
|
||
|
||
int NdCxList::getChildCount(void)
|
||
{
|
||
CCArray *children = inner_panel_->getChildren();
|
||
if (!children)
|
||
{
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
return children->count();
|
||
}
|
||
}
|
||
|
||
void NdCxList::setRowHeight(float height)
|
||
{
|
||
row_height_ = height;
|
||
}
|
||
|
||
float NdCxList::getRowHeight(void)
|
||
{
|
||
return row_height_;
|
||
}
|
||
|
||
void NdCxList::registerItemClickListener(NdCxListItemClickListener *listener)
|
||
{
|
||
item_click_listener_ = listener;
|
||
}
|
||
|
||
void NdCxList::unregisterItemClickListener(void)
|
||
{
|
||
item_click_listener_ = NULL;
|
||
|
||
#ifdef ENABLE_LUA
|
||
m_scriptSeletor.clear();
|
||
#endif
|
||
}
|
||
#ifdef ENABLE_LUA
|
||
void NdCxList::registerItemClickListener(const char* szSeletor)
|
||
{
|
||
if (szSeletor)
|
||
{
|
||
m_scriptSeletor = szSeletor;
|
||
}
|
||
else
|
||
{
|
||
CCLog("registerItemClickListener Error szSelector == null");
|
||
}
|
||
}
|
||
#endif
|
||
|
||
void NdCxList::visit(void)
|
||
{
|
||
// quick return if not visible
|
||
if (!m_bIsVisible)
|
||
{
|
||
return;
|
||
}
|
||
glPushMatrix();
|
||
|
||
/*if (m_pGrid && m_pGrid->isActive())
|
||
{
|
||
m_pGrid->beforeDraw();
|
||
this->transformAncestors();
|
||
}*/
|
||
|
||
this->transform();
|
||
|
||
CCNode* pNode = NULL;
|
||
unsigned int i = 0;
|
||
|
||
if(m_pChildren && m_pChildren->count() > 0)
|
||
{
|
||
// draw children zOrder < 0
|
||
ccArray *arrayData = m_pChildren->data;
|
||
for( ; i < arrayData->num; i++ )
|
||
{
|
||
pNode = (CCNode*) arrayData->arr[i];
|
||
|
||
if ( pNode && pNode->getZOrder() < 0 )
|
||
{
|
||
pNode->visit();
|
||
}
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// self draw
|
||
this->draw();
|
||
|
||
// 左下角世界坐标
|
||
CCPoint world_pt = convertToWorldSpace(CCPointZero);
|
||
CCPoint ui_pt = CCDirector::sharedDirector()->convertToUI(world_pt);
|
||
CCPoint gl_pt = CCDirector::sharedDirector()->convertToGL(ui_pt);
|
||
|
||
glEnable(GL_SCISSOR_TEST);
|
||
glScissor((GLsizei)gl_pt.x, (GLsizei)gl_pt.y, (GLsizei)m_tContentSize.width, (GLsizei)m_tContentSize.height);
|
||
|
||
// draw children zOrder >= 0
|
||
if (m_pChildren && m_pChildren->count() > 0)
|
||
{
|
||
ccArray *arrayData = m_pChildren->data;
|
||
for( ; i < arrayData->num; i++ )
|
||
{
|
||
pNode = (CCNode*) arrayData->arr[i];
|
||
if (pNode)
|
||
{
|
||
pNode->visit();
|
||
}
|
||
}
|
||
}
|
||
|
||
glDisable(GL_SCISSOR_TEST);
|
||
|
||
glPopMatrix();
|
||
}
|
||
}
|
||
|