Merge pull request #583 from ZobyTwo/deck_viewer_1

Cleanup, usability fixes and source code documentation for DeckView.h and GridDeckView.h
This commit is contained in:
Xawotihs
2013-12-09 11:51:40 -08:00
7 changed files with 520 additions and 124 deletions
+7 -4
View File
@@ -11,6 +11,7 @@ private:
static const float x_center; static const float x_center;
static const float right_border; static const float right_border;
static const float slide_animation_duration; static const float slide_animation_duration;
static const float scroll_animation_duration;
public: public:
CarouselDeckView(); CarouselDeckView();
@@ -18,19 +19,21 @@ public:
void Reset(); void Reset();
void UpdateViewState(float dt); void UpdateViewState(float dt);
void UpdateCardPosition(CardRep &rep, int index); void UpdateCardPosition(int index);
void renderCard(int index) void renderCard(int index)
{ {
int alpha = (int) (255 * (getCardRep(index).scale + 1.0 - max_scale)); int alpha = (int) (255 * (mCards[index].scale + 1.0 - max_scale));
DeckView::renderCard(index, alpha); DeckView::renderCard(index, alpha);
} }
void Render(); void Render();
bool ButtonPressed(Buttons button);
MTGCard * Click(int x, int y); MTGCard * Click(int x, int y);
MTGCard * Click();
void changePosition(int offset); void changePositionAnimated(int offset);
void changeFilter(int offset); void changeFilterAnimated(int offset);
MTGCard *getActiveCard(); MTGCard *getActiveCard();
private: private:
+190 -12
View File
@@ -9,55 +9,233 @@
#include "WResourceManager.h" #include "WResourceManager.h"
#include "Pos.h" #include "Pos.h"
/*! \brief A abstract base class for deck views
*
* The deck editor uses a deck view to present the cards
* e.g. in a circular "Carousel" layout or in a flat grid
* layout. Both layouts inherit this base class to ensure
* a common interface which the deck editor can rely on.
*/
class DeckView class DeckView
{ {
protected: protected:
/*! \brief defines the delay until additional card informations get shown
*
* \note I am not entirely sure about that
*/
static const float no_user_activity_show_card_delay; static const float no_user_activity_show_card_delay;
public: /*! \brief Represents a card for internal use in the deck view
*
* It stores positional information and a pointer to the actual card structure.
*/
struct CardRep{ struct CardRep{
float x; float x;
float y; float y;
float scale; float scale;
MTGCard * card; MTGCard * card;
}; };
public:
/*! \brief Defines if the filter needs an update
*
* The owner of the deck that is shown is responsible for updating the filters.
*/
bool dirtyFilters; bool dirtyFilters;
/*! \brief Defines if the card positions need an update
*
* If the card positions are dirty, UpdateCardPosition will get called on
* all cards during Update(float dt);
*
* \see Update
* \see UpdateCardPosition
*/
bool dirtyCardPos; bool dirtyCardPos;
/*! \brief Constructs the view and initializes datamembers
*
* It sets the dirty states to true, the currently shown deck to NULL and selects filter 0.
*
* \param numberOfCards the number of cards the view handles (this includes hidden cards for caching)
*/
DeckView(int numberOfCards); DeckView(int numberOfCards);
/*! \brief Does nothing but is needed to ensure proper deletion of derived classes.
*/
virtual ~DeckView(); virtual ~DeckView();
/*! \brief Resets nearly all datamembers to their initial values
*
* Does not reset mCards.
*/
virtual void Reset(); virtual void Reset();
//advances the view and card representations /*! \brief Advances the view by dt time units
*
* This method calls UpdateViewState unconditionally and UpdateCardPosition on every card
* if dirtyCardPos is set. It then resets dirtyCardPos.
*
* \param dt the number of time units to advance
* \see UpdateViewState
* \see UpdateCardPosition
*/
void Update(float dt); void Update(float dt);
virtual void SetDeck(DeckDataWrapper *toShow);
/*! \brief Sets the deck that this view shows
*
* This method replaces the currently shown deck with toShow, sets all dirty states and
* reloads the mtg cards. No ownership changes.
*
* \param toShow the deck to show
* \see reloadIndexes
*/
void SetDeck(DeckDataWrapper *toShow);
/*! \brief Returns a pointer to the current deck.
*/
DeckDataWrapper *deck(); DeckDataWrapper *deck();
void SwitchFilter(int delta);
void SwitchPosition(int delta); /*! \brief Performs an immediate switch of the filter without animations
*
* This method rotates the currently selected filter by delta and sets dirtyFilters.
*
* \param delta the filter to select relatively to the currently selected filter
* \see dirtyFilters
*/
void changeFilter(int delta);
/*! \brief Performs an immediate switch of the position without animations
*
* If the i-th card stored in mCards points to the j-th card in the deck, it will point
* to the (j+delta)-th card after this method is called. No dirty states are set.
*
* \param delta the number of cards to advances
* \see mCards
*/
void changePosition(int delta);
/*! \brief Returns the number of the currently selected filter
*
* \return the currently selected filter
*/
int filter(); int filter();
/*! \brief Reloads the mtg card pointers of mCards from the deck
*
* This is called when: We change the position in the deck or the deck structure changes
* (due to filtering or addition or removal of cards).
*/
void reloadIndexes(); void reloadIndexes();
/*! \brief Returns the current position in the deck
*/
int getPosition(); int getPosition();
/*! \brief Renders the view
*/
virtual void Render() = 0; virtual void Render() = 0;
/*! \brief Reacts to selections by a pointer device (e. g. mouse, touch)
*
* If the selection in view internal i. e. a card got selected, there is
* no outside action performed and this method will return NULL. If a action got
* triggered i. e. a selected card was activated, it returns that card
* for further handling by the caller.
*
* \param x the x coordinate of the pointer during the action
* \param y the y coordinate of the pointer during the action
* \returns the card the action corresponds to
*/
virtual MTGCard * Click(int x, int y) = 0; virtual MTGCard * Click(int x, int y) = 0;
bool ButtonPressed(Buttons button);
/*! \brief Reacts to selections by pointerless devices (e. g. buttons)
*
* \see Click(int x, int y)
* \returns the card the actions corresponds to
*/
virtual MTGCard * Click() = 0;
/*! \brief Handles ordinary button presses
*
* \param the pressed JButton
* \returns true if the view reacted to the button and false otherwise
*/
virtual bool ButtonPressed(Buttons button) = 0;
/*! \brief Returns the currently active card
*/
virtual MTGCard *getActiveCard() = 0; virtual MTGCard *getActiveCard() = 0;
virtual void changePosition(int offset) = 0;
virtual void changeFilter(int offset) = 0; /*! \brief Changes the position by a given offset
*
* Advances the view by offset cards and animates the change.
*
* \param offset the number of positions to advance
*/
virtual void changePositionAnimated(int offset) = 0;
/*! \brief Changes the filter by a given offset
*
* Rotates the selected filter by the given offset and animates the change.
*/
virtual void changeFilterAnimated(int offset) = 0;
protected: protected:
/*! \brief The number of time units since an user activity occurred
*/
float last_user_activity; float last_user_activity;
/*! \brief The currently selected filter
*/
int mFilter; int mFilter;
/*! \brief The currently selected deck
*
* This class does not take ownership of the deck
*/
DeckDataWrapper *mCurrentDeck; DeckDataWrapper *mCurrentDeck;
/*! \brief The card positions and pointers
*/
vector<CardRep> mCards; vector<CardRep> mCards;
CardRep& getCardRep(unsigned int index); /*! \brief Renders a card with given alpha value
*
* \param index of the card in mCards to render
* \param alpha the alpha value of the card
* \param asThumbnail renders the thumbnail image of the card if set to true
*
* \see mCards
*/
void renderCard(int index, int alpha, bool asThumbnail = false); void renderCard(int index, int alpha, bool asThumbnail = false);
/*! \brief Returns the index in mCards of the card that is nearest to the given point
*
* \note This method uses the euclidian distance to the center of the card
*
* \param x the reference points x coordinate
* \param y the reference points y coordinate
* \returns the index of the nearest card to the reference point and -1 of mCards is empty
*/
int getCardIndexNextTo(int x, int y); int getCardIndexNextTo(int x, int y);
private: private:
/*! \brief Updates the state of the view e. g. view transitions
*
* \param dt the passes time since the last update
*/
virtual void UpdateViewState(float dt) = 0; virtual void UpdateViewState(float dt) = 0;
virtual void UpdateCardPosition(CardRep& rep, int index) = 0;
/*! \brief Updates the given card reps positional members
*
* This method is called from Update when dirtyCardPos is set
*
* \param index the index in mCards of the card to update
*
* \see Update
* \see mCards
*/
virtual void UpdateCardPosition(int index) = 0;
}; };
#endif // _DECK_VIEW_H_ #endif // _DECK_VIEW_H_
+122 -6
View File
@@ -4,6 +4,15 @@
#include "DeckView.h" #include "DeckView.h"
#include "Easing.h" #include "Easing.h"
/*! \brief Implements a grid view
*
* This view displays 12 cards in two rows as thumbnails. The currently
* selected card is dislayed bigger than the rest and uses the fullsize
* image. Scrolling the view horizontally and toggeling filters is
* animated and uses quadratic easing.
*
* It also implements a button mode for pointerless devices.
*/
class GridDeckView : public DeckView class GridDeckView : public DeckView
{ {
private: private:
@@ -12,27 +21,134 @@ private:
static const float card_scale_small; static const float card_scale_small;
static const float card_scale_big; static const float card_scale_big;
public: public:
/*! \brief Constructs a grid view with no decks set
*/
GridDeckView(); GridDeckView();
/*! \brief Does nothing but is needed to ensure proper deletion of derived classes.
*/
virtual ~GridDeckView(); virtual ~GridDeckView();
/*! \brief Resets almost all member variables but mRows and mCols
*/
void Reset(); void Reset();
/*! \brief Advances scrolling and sliding animations
*
* \param dt the time since the last update
*
* \see DeckView::UpdateViewState()
*/
void UpdateViewState(float dt); void UpdateViewState(float dt);
void UpdateCardPosition(CardRep &rep, int index);
/*! \brief Updates the cards position
*
* \see DeckView::UpdateCardPosition()
*/
void UpdateCardPosition(int index);
/*! \brief Renders the view
*
* This method prefetches all rendered cards as thumbnails except the
* selected card to reduce cache pressure.
*/
void Render(); void Render();
/*! \brief Handles button presses
*
* The mapping is as follows:
* JGE_BTN_LEFT moves the position to the left if not in button mode
* moves the selection otherwise
* JGE_BTN_RIGHT move the position to the right if not in button mode
* moves the selection otherwise
* JGE_BTN_UP select the previous filter if not in button mode
* moves the selection otherwise
* JGE_BTN_DOWN select the next filter if not in button mode
* moves the selection otherwise
* JGE_BTN_CTRL deactivate button mode
*
* \param button the pressed button
* \returns if the view handled the button
*/
bool ButtonPressed(Buttons button);
/*! \brief Handles clicks and triggers scrolling and the selection of cards
*
* This method deactivates the button mode and searches for the nearest
* card to the given position. If this card is in column 0 or 1 it scrolls
* left. If it is in column (mCols-1) or (mCols-2) it scrolls to the right.
* In any other case, it selects the card.
*
* \param x the clicks x coordinate
* \param y the clicks y coordinate
*
* \return selected card c if c was already selected and no animation is running, NULL otherwise
*/
MTGCard * Click(int x, int y); MTGCard * Click(int x, int y);
void changePosition(int offset); /*! \brief Handles pointerless clicks (JGE_BTN_OK)
void changeFilter(int offset); *
* If no card is selected, this method activates button mode and selects a card.
*
* \returns selected card, NULL otherwise
*/
MTGCard * Click();
/*! \brief Scrolls the view horizontally
*
* \param offset the number of columns to scroll
*/
void changePositionAnimated(int offset);
/*! \brief Rotates the selected filter and slides vertically
*
* \param the number of filters to rotate
*/
void changeFilterAnimated(int offset);
/*! \brief Returns the currently selected card
*
* \returns card c if c is selected and in column 4 to 6 and NULL otherwise*/
MTGCard *getActiveCard(); MTGCard *getActiveCard();
private: private:
int mCols; /*! \brief The amount of columns (visible and hidden)
int mRows; */
float mScrollOffset, mSlideOffset; const int mCols;
/*! \brief The amount of rows
*/
const int mRows;
/*! \brief The current scrolling offset
*/
float mScrollOffset;
/*! \brief The current sliding offset
*/
float mSlideOffset;
/*! \brief The easing functor that gets applied while scrolling
*/
InOutQuadEasing mScrollEasing; InOutQuadEasing mScrollEasing;
/*! \brief The easing functor that gets applied while sliding
*/
InOutQuadEasing mSlideEasing; InOutQuadEasing mSlideEasing;
/*! \brief The current selected card index
*/
int mCurrentSelection; int mCurrentSelection;
/*! \brief Stores if we are in button mode.
*/
bool mButtonMode;
/*! \brief Moves the card selection by an offset.
*
* \param offset the offset to move the selection
* \param alignIfOutOfBounds the view will scroll if the selection moves out of bound if set to true
*/
void moveSelection(int offset, bool alignIfOutOfBounds);
}; };
#endif //_GRID_DECK_VIEW_H #endif //_GRID_DECK_VIEW_H
+59 -25
View File
@@ -4,6 +4,7 @@ const float CarouselDeckView::max_scale = 0.96f;
const float CarouselDeckView::x_center = 180; const float CarouselDeckView::x_center = 180;
const float CarouselDeckView::right_border = SCREEN_WIDTH + 180; const float CarouselDeckView::right_border = SCREEN_WIDTH + 180;
const float CarouselDeckView::slide_animation_duration = 0.6f; const float CarouselDeckView::slide_animation_duration = 0.6f;
const float CarouselDeckView::scroll_animation_duration = 0.3f;
CarouselDeckView::CarouselDeckView() : CarouselDeckView::CarouselDeckView() :
DeckView(10), mScrollOffset(0), mSlideOffset(0), mScrollEasing(mScrollOffset), mSlideEasing(mSlideOffset) DeckView(10), mScrollOffset(0), mSlideOffset(0), mScrollEasing(mScrollOffset), mSlideEasing(mSlideOffset)
@@ -21,12 +22,12 @@ void CarouselDeckView::UpdateViewState(float dt)
if(mScrollOffset <= -1.0f) if(mScrollOffset <= -1.0f)
{ {
SwitchPosition(-1); changePosition(-1);
mScrollEasing.translate(1.0f); mScrollEasing.translate(1.0f);
} }
else if(mScrollOffset >= 1.0f) else if(mScrollOffset >= 1.0f)
{ {
SwitchPosition(1); changePosition(1);
mScrollEasing.translate(-1.0f); mScrollEasing.translate(-1.0f);
} }
@@ -43,7 +44,7 @@ void CarouselDeckView::UpdateViewState(float dt)
if(mSlideOffset < -1.0f) if(mSlideOffset < -1.0f)
{ {
mSlideEasing.translate(2.0f); mSlideEasing.translate(2.0f);
SwitchFilter(1); changeFilter(1);
} }
} }
else if(mSlideOffset > mSlideEasing.start_value) else if(mSlideOffset > mSlideEasing.start_value)
@@ -52,7 +53,7 @@ void CarouselDeckView::UpdateViewState(float dt)
if(mSlideOffset > 1.0f) if(mSlideOffset > 1.0f)
{ {
mSlideEasing.translate(-2.0f); mSlideEasing.translate(-2.0f);
SwitchFilter(-1); changeFilter(-1);
} }
} }
@@ -60,8 +61,10 @@ void CarouselDeckView::UpdateViewState(float dt)
} }
} }
void CarouselDeckView::UpdateCardPosition(CardRep &rep, int index) void CarouselDeckView::UpdateCardPosition(int index)
{ {
CardRep &rep = mCards[index];
float rotation = mScrollOffset + 8 - index; float rotation = mScrollOffset + 8 - index;
rep.x = x_center + cos((rotation) * M_PI / 12) * (right_border - x_center); rep.x = x_center + cos((rotation) * M_PI / 12) * (right_border - x_center);
@@ -84,13 +87,13 @@ void CarouselDeckView::Render()
// in a different order, ie the center card should appear first, then the adjacent ones // in a different order, ie the center card should appear first, then the adjacent ones
if (WResourceManager::Instance()->IsThreaded()) if (WResourceManager::Instance()->IsThreaded())
{ {
WResourceManager::Instance()->RetrieveCard(getCardRep(0).card); WResourceManager::Instance()->RetrieveCard(mCards[0].card);
WResourceManager::Instance()->RetrieveCard(getCardRep(3).card); WResourceManager::Instance()->RetrieveCard(mCards[3].card);
WResourceManager::Instance()->RetrieveCard(getCardRep(4).card); WResourceManager::Instance()->RetrieveCard(mCards[4].card);
WResourceManager::Instance()->RetrieveCard(getCardRep(2).card); WResourceManager::Instance()->RetrieveCard(mCards[2].card);
WResourceManager::Instance()->RetrieveCard(getCardRep(5).card); WResourceManager::Instance()->RetrieveCard(mCards[5].card);
WResourceManager::Instance()->RetrieveCard(getCardRep(1).card); WResourceManager::Instance()->RetrieveCard(mCards[1].card);
WResourceManager::Instance()->RetrieveCard(getCardRep(6).card); WResourceManager::Instance()->RetrieveCard(mCards[6].card);
} }
renderCard(6); renderCard(6);
@@ -118,6 +121,31 @@ void CarouselDeckView::Render()
} }
} }
bool CarouselDeckView::ButtonPressed(Buttons button)
{
switch(button)
{
case JGE_BTN_LEFT:
changePositionAnimated(-1);
last_user_activity = 0;
break;
case JGE_BTN_RIGHT:
changePositionAnimated(1);
last_user_activity = 0;
break;
case JGE_BTN_UP:
changeFilterAnimated(1);
last_user_activity = 0;
break;
case JGE_BTN_DOWN:
changeFilterAnimated(-1);
last_user_activity = 0;
break;
default:
return false;
}
return true;
}
MTGCard * CarouselDeckView::Click(int x, int y) MTGCard * CarouselDeckView::Click(int x, int y)
{ {
int n = getCardIndexNextTo(x, y); int n = getCardIndexNextTo(x, y);
@@ -132,35 +160,41 @@ MTGCard * CarouselDeckView::Click(int x, int y)
} }
else else
{ {
changePosition(n - 2); changePositionAnimated(n - 2);
} }
} }
return NULL; return NULL;
} }
void CarouselDeckView::changePosition(int offset) MTGCard *CarouselDeckView::Click()
{ {
mScrollEasing.start((float)offset, (float)(0.3f*abs(offset))); if(mSlideEasing.finished() && mScrollEasing.finished())
{
return getActiveCard();
}
else
{
return NULL;
}
}
void CarouselDeckView::changePositionAnimated(int offset)
{
if(mScrollEasing.finished())
mScrollEasing.start((float)offset, (float)(scroll_animation_duration * abs(offset)));
last_user_activity = 0; last_user_activity = 0;
} }
void CarouselDeckView::changeFilter(int offset) void CarouselDeckView::changeFilterAnimated(int offset)
{ {
if(offset < 0) if(mSlideEasing.finished())
{ mSlideEasing.start(2.0f * float(offset), float(slide_animation_duration * abs(offset)));
mSlideEasing.start(-2.0f, slide_animation_duration);
}
else if(offset > 0)
{
mSlideEasing.start(2.0f, slide_animation_duration);
}
last_user_activity = 0; last_user_activity = 0;
} }
MTGCard *CarouselDeckView::getActiveCard() MTGCard *CarouselDeckView::getActiveCard()
{ {
return getCardRep(2).card; return mCards[2].card;
} }
+5 -36
View File
@@ -35,38 +35,12 @@ void DeckView::Update(float dt)
{ {
for(unsigned int i = 0; i < mCards.size(); ++i) for(unsigned int i = 0; i < mCards.size(); ++i)
{ {
UpdateCardPosition(mCards[i], i); UpdateCardPosition(i);
} }
dirtyCardPos = false; dirtyCardPos = false;
} }
} }
bool DeckView::ButtonPressed(Buttons button)
{
switch(button)
{
case JGE_BTN_LEFT:
changePosition(-1);
last_user_activity = 0;
break;
case JGE_BTN_RIGHT:
changePosition(1);
last_user_activity = 0;
break;
case JGE_BTN_UP:
changeFilter(1);
last_user_activity = 0;
break;
case JGE_BTN_DOWN:
changeFilter(-1);
last_user_activity = 0;
break;
default:
return false;
}
return true;
}
void DeckView::SetDeck(DeckDataWrapper *toShow) void DeckView::SetDeck(DeckDataWrapper *toShow)
{ {
mCurrentDeck = toShow; mCurrentDeck = toShow;
@@ -80,14 +54,14 @@ DeckDataWrapper* DeckView::deck()
return mCurrentDeck; return mCurrentDeck;
} }
void DeckView::SwitchFilter(int delta) void DeckView::changeFilter(int delta)
{ {
unsigned int FilterCount = Constants::NB_Colors + 1; unsigned int FilterCount = Constants::NB_Colors + 1;
mFilter = (FilterCount + mFilter + delta) % FilterCount; mFilter = (FilterCount + mFilter + delta) % FilterCount;
dirtyFilters = true; dirtyFilters = true;
} }
void DeckView::SwitchPosition(int delta) void DeckView::changePosition(int delta)
{ {
for(int i = 0; i < delta; ++i) for(int i = 0; i < delta; ++i)
{ {
@@ -118,16 +92,11 @@ void DeckView::reloadIndexes()
} }
} }
DeckView::CardRep& DeckView::getCardRep(unsigned int index)
{
return mCards[index];
}
void DeckView::renderCard(int index, int alpha, bool asThumbnail) void DeckView::renderCard(int index, int alpha, bool asThumbnail)
{ {
WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT);
const CardRep& cardPosition = getCardRep(index); const CardRep& cardPosition = mCards[index];
if (!cardPosition.card) return; if (!cardPosition.card) return;
@@ -213,7 +182,7 @@ int DeckView::getCardIndexNextTo(int x, int y)
for(unsigned int i = 0; i < mCards.size(); i++) for(unsigned int i = 0; i < mCards.size(); i++)
{ {
const CardRep& cardPosition = getCardRep(i); const CardRep& cardPosition = mCards[i];
float dx = (x - cardPosition.x); float dx = (x - cardPosition.x);
float dy = (y - cardPosition.y); float dy = (y - cardPosition.y);
+28 -17
View File
@@ -407,9 +407,8 @@ void GameStateDeckViewer::Update(float dt)
case JGE_BTN_RIGHT: case JGE_BTN_RIGHT:
case JGE_BTN_UP: case JGE_BTN_UP:
case JGE_BTN_DOWN: case JGE_BTN_DOWN:
if(last_user_activity > 0.2) if(mView->ButtonPressed(button))
{ {
mView->ButtonPressed(button);
last_user_activity = 0; last_user_activity = 0;
mStage = STAGE_WAITING; mStage = STAGE_WAITING;
} }
@@ -443,19 +442,21 @@ void GameStateDeckViewer::Update(float dt)
int x, y; int x, y;
if (mEngine->GetLeftClickCoordinates(x, y)) if (mEngine->GetLeftClickCoordinates(x, y))
{ {
last_user_activity = 0;
mEngine->LeftClickedProcessed(); mEngine->LeftClickedProcessed();
if(mView->Click(x, y) == mView->getActiveCard()) if(mView->Click(x, y) != NULL)
{ {
addRemove(mView->getActiveCard()); addRemove(mView->getActiveCard());
} }
} }
else else
{ {
last_user_activity = 0; if(mView->Click() != NULL)
addRemove(mView->getActiveCard()); {
addRemove(mView->getActiveCard());
}
} }
last_user_activity = 0;
mStage = STAGE_WAITING; mStage = STAGE_WAITING;
break; break;
} }
@@ -468,17 +469,20 @@ void GameStateDeckViewer::Update(float dt)
buildEditorMenu(); buildEditorMenu();
break; break;
case JGE_BTN_CTRL: case JGE_BTN_CTRL:
mStage = STAGE_FILTERS; if(!mView->ButtonPressed(JGE_BTN_CTRL))
if (!filterMenu)
{ {
filterMenu = NEW WGuiFilters("Filter by...", NULL); mStage = STAGE_FILTERS;
if (source) if (!filterMenu)
SAFE_DELETE(source); {
source = NEW WSrcDeckViewer(myDeck, myCollection); filterMenu = NEW WGuiFilters("Filter by...", NULL);
filterMenu->setSrc(source); if (source)
if (mView->deck() != myDeck) source->swapSrc(); SAFE_DELETE(source);
source = NEW WSrcDeckViewer(myDeck, myCollection);
filterMenu->setSrc(source);
if (mView->deck() != myDeck) source->swapSrc();
}
filterMenu->Entering(JGE_BTN_NONE);
} }
filterMenu->Entering(JGE_BTN_NONE);
break; break;
case JGE_BTN_PREV: case JGE_BTN_PREV:
if (last_user_activity < NO_USER_ACTIVITY_HELP_DELAY) if (last_user_activity < NO_USER_ACTIVITY_HELP_DELAY)
@@ -1527,11 +1531,18 @@ void GameStateDeckViewer::OnScroll(int inXVelocity, int inYVelocity)
{ {
//FIXME: this 500 is a bit arbitrary //FIXME: this 500 is a bit arbitrary
int numCards = (magnitude / 500) % 8; int numCards = (magnitude / 500) % 8;
mView->changePosition(flickRight ? numCards : - numCards); mView->changePositionAnimated(flickRight ? numCards : - numCards);
} }
} }
else else
mView->changeFilter(flickUp ? 1 : -1); {
if(abs(inYVelocity) > 300)
{
//FIXME: this 500 is a bit arbitrary
int numFilters = (magnitude / 500);
mView->changeFilterAnimated(flickUp ? numFilters : - numFilters);
}
}
last_user_activity = 0; last_user_activity = 0;
} }
+109 -24
View File
@@ -7,7 +7,8 @@ const float GridDeckView::card_scale_big = 0.7f;
GridDeckView::GridDeckView() GridDeckView::GridDeckView()
: DeckView(16), mCols(8), mRows(2), mScrollOffset(0), mSlideOffset(0), : DeckView(16), mCols(8), mRows(2), mScrollOffset(0), mSlideOffset(0),
mScrollEasing(mScrollOffset), mSlideEasing(mSlideOffset), mCurrentSelection(-1) mScrollEasing(mScrollOffset), mSlideEasing(mSlideOffset), mCurrentSelection(-1),
mButtonMode(false)
{ {
} }
@@ -23,6 +24,7 @@ void GridDeckView::Reset()
mScrollEasing.finish(); mScrollEasing.finish();
mCurrentSelection = 0; mCurrentSelection = 0;
mButtonMode = false;
DeckView::Reset(); DeckView::Reset();
} }
@@ -35,15 +37,15 @@ void GridDeckView::UpdateViewState(float dt)
if(mScrollOffset <= -1.0f) if(mScrollOffset <= -1.0f)
{ {
SwitchPosition(2); changePosition(2);
moveSelection(-2, false);
mScrollEasing.translate(1.0f); mScrollEasing.translate(1.0f);
mCurrentSelection = (mCurrentSelection >= 6) ? mCurrentSelection - 2 : -1;
} }
else if(mScrollOffset >= 1.0f) else if(mScrollOffset >= 1.0f)
{ {
SwitchPosition(-2); changePosition(-2);
moveSelection(2, false);
mScrollEasing.translate(-1.0f); mScrollEasing.translate(-1.0f);
mCurrentSelection = (mCurrentSelection >= 0 && mCurrentSelection < 10) ? mCurrentSelection + 2 : -1;
} }
dirtyCardPos = true; dirtyCardPos = true;
@@ -56,20 +58,22 @@ void GridDeckView::UpdateViewState(float dt)
if(mSlideOffset < -1.0f) if(mSlideOffset < -1.0f)
{ {
mSlideEasing.translate(2.0f); mSlideEasing.translate(2.0f);
SwitchFilter(1); changeFilter(1);
} }
else if(mSlideOffset > 1.0f) else if(mSlideOffset > 1.0f)
{ {
mSlideEasing.translate(-2.0f); mSlideEasing.translate(-2.0f);
SwitchFilter(-1); changeFilter(-1);
} }
dirtyCardPos = true; dirtyCardPos = true;
} }
} }
void GridDeckView::UpdateCardPosition(CardRep &rep, int index) void GridDeckView::UpdateCardPosition(int index)
{ {
CardRep &rep = mCards[index];
int col = index / mRows; int col = index / mRows;
int row = index % mRows; int row = index % mRows;
float colWidth = SCREEN_WIDTH_F / (mCols - 3); float colWidth = SCREEN_WIDTH_F / (mCols - 3);
@@ -119,7 +123,7 @@ void GridDeckView::Render()
{ {
if (WResourceManager::Instance()->IsThreaded()) if (WResourceManager::Instance()->IsThreaded())
{ {
WResourceManager::Instance()->RetrieveCard(getCardRep(i).card, RETRIEVE_THUMB); WResourceManager::Instance()->RetrieveCard(mCards[i].card, RETRIEVE_THUMB);
} }
renderCard(i, 255, true); renderCard(i, 255, true);
} }
@@ -127,7 +131,7 @@ void GridDeckView::Render()
{ {
if (WResourceManager::Instance()->IsThreaded()) if (WResourceManager::Instance()->IsThreaded())
{ {
WResourceManager::Instance()->RetrieveCard(getCardRep(i).card); WResourceManager::Instance()->RetrieveCard(mCards[i].card);
} }
} }
} }
@@ -138,10 +142,50 @@ void GridDeckView::Render()
} }
} }
bool GridDeckView::ButtonPressed(Buttons button)
{
switch(button)
{
case JGE_BTN_LEFT:
if(mButtonMode && mScrollEasing.finished()) moveSelection(-2, true);
else if(!mButtonMode) changePositionAnimated(-1);
last_user_activity = 0;
break;
case JGE_BTN_RIGHT:
if(mButtonMode && mScrollEasing.finished()) moveSelection(2, true);
else if(!mButtonMode) changePositionAnimated(1);
last_user_activity = 0;
break;
case JGE_BTN_UP:
if(mButtonMode && mScrollEasing.finished()) moveSelection(-1, true);
else if(!mButtonMode) changeFilterAnimated(1);
last_user_activity = 0;
break;
case JGE_BTN_DOWN:
if(mButtonMode && mScrollEasing.finished()) moveSelection(1, true);
else if(!mButtonMode) changeFilterAnimated(-1);
last_user_activity = 0;
break;
case JGE_BTN_CTRL:
if(mButtonMode)
{
mButtonMode = false;
dirtyCardPos = true;
mCurrentSelection = -1;
}
else return false;
break;
default:
return false;
}
return true;
}
MTGCard * GridDeckView::Click(int x, int y) MTGCard * GridDeckView::Click(int x, int y)
{ {
int n = getCardIndexNextTo(x, y); int n = getCardIndexNextTo(x, y);
last_user_activity = 0; last_user_activity = 0;
mButtonMode = false;
if(mScrollEasing.finished() && mSlideEasing.finished()) if(mScrollEasing.finished() && mSlideEasing.finished())
{ //clicked and no animations running { //clicked and no animations running
@@ -151,11 +195,11 @@ MTGCard * GridDeckView::Click(int x, int y)
} }
else if(n < 4) else if(n < 4)
{ {
changePosition(-1); changePositionAnimated(-1);
} }
else if(n >= 12) else if(n >= 12)
{ {
changePosition(1); changePositionAnimated(1);
} }
else else
{ {
@@ -167,28 +211,43 @@ MTGCard * GridDeckView::Click(int x, int y)
return NULL; return NULL;
} }
void GridDeckView::changePosition(int offset) MTGCard * GridDeckView::Click()
{ {
mScrollEasing.start(-1.0f * offset, scroll_animation_duration * abs(offset)); if(mScrollEasing.finished() && mSlideEasing.finished())
{
MTGCard *active = getActiveCard();
if(active != NULL)
{
return active;
}
else
{
mButtonMode = true;
dirtyCardPos = true;
mCurrentSelection = 4;
}
}
return NULL;
}
void GridDeckView::changePositionAnimated(int offset)
{
if(mScrollEasing.finished())
mScrollEasing.start(-1.0f * offset, scroll_animation_duration * abs(offset));
last_user_activity = 0; last_user_activity = 0;
} }
void GridDeckView::changeFilter(int offset) void GridDeckView::changeFilterAnimated(int offset)
{ {
if(offset < 0) if(mSlideEasing.finished())
{ mSlideEasing.start(2.0f * offset, float(slide_animation_duration * abs(offset)));
mSlideEasing.start(-2.0f, slide_animation_duration);
}
else if(offset > 0)
{
mSlideEasing.start(2.0f, slide_animation_duration);
}
last_user_activity = 0; last_user_activity = 0;
} }
MTGCard* GridDeckView::getActiveCard() MTGCard* GridDeckView::getActiveCard()
{ {
if(mCurrentSelection >= 0 && mCurrentSelection < int(mCards.size())) if(mCurrentSelection >= 4 && mCurrentSelection < int(mCards.size())-4)
{ {
return mCards[mCurrentSelection].card; return mCards[mCurrentSelection].card;
} }
@@ -197,3 +256,29 @@ MTGCard* GridDeckView::getActiveCard()
return NULL; return NULL;
} }
} }
void GridDeckView::moveSelection(int offset, bool alignIfOutOfBounds)
{
mCurrentSelection += offset;
if(alignIfOutOfBounds)
{
if(mCurrentSelection < 4)
{
changePositionAnimated(-1);
}
else if(mCurrentSelection >= 12)
{
changePositionAnimated(1);
}
}
else
{
if(mCurrentSelection < 4 || mCurrentSelection >= 12)
{
mCurrentSelection = -1;
}
}
dirtyCardPos = true;
}