/*---------------------------------------------------------------------------* Copyright (C) 2010-2012 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. *---------------------------------------------------------------------------*/ //////////////////////////////////////////////////// // // Double Combo Box functions // //////////////////////////////////////////////////// DoubleComboBox* DoubleComboBox::Add(const DoubleComboBox& item) { ASSERT(item.count > 0 && "Double combo boxes cannot be empty!"); DoubleComboBox* pItem = new DoubleComboBox(item); item.window->menuItems.push_back(pItem); item.window->AddTabbing(pItem); return pItem; } // Determines if the cursor is over this combo box bool DoubleComboBox::CursorOver() { if (CursorColliding(this->x, this->y, this->width, this->height)) return true; //////////////////////////////////////////////////////////////////////////////////////////////////// if (this->status < 2) return false; if (this->bar1.status == 2) return true; int visibleCount = this->count - this->bar1.pos; if (visibleCount > COMBOBOX_COUNT) visibleCount = COMBOBOX_COUNT; float flipMul = 1.0; if (this->flipped) flipMul = -1.0; if (CursorColliding(this->x, this->y - (this->height / 2 + this->height * visibleCount / 2) * flipMul, this->width / 2, this->height * visibleCount, true)) return true; //////////////////////////////////////////////////////////////////////////////////////////////////// if (this->status < 3) return false; if (this->bar2.status == 2) return true; visibleCount = this->data[this->pos1]->GetCount() - this->bar2.pos; if (visibleCount > COMBOBOX_COUNT) visibleCount = COMBOBOX_COUNT; float lOffset = (this->height + this->off * this->height) * flipMul - this->offset; if (CursorColliding(this->x + this->width / 2, this->y + this->height / 2 - this->height * visibleCount / 2 - lOffset, this->width / 2, this->height * visibleCount, true)) return true; return false; } // Updates the combo box bool DoubleComboBox::Update() { // Going back if (NegativeTriggered()) { if (status >= 2) TabSubIndex() = -1; if (this->status >= 3) { this->status = 2; TabSubIndex() = this->pos1 - this->bar1.pos; } else { this->pos1 = (*this->target1); this->pos2 = (*this->target2); this->status = 0; } } // Also going back if (TabIndex() && TabIndex()->object == this && this->status >= 3 && LeftTriggered()) { this->status = 2; TabSubIndex() = this->pos1 - this->bar1.pos; } // Activate tabbing if we're in PAD mode if (this->status >= 2 && !TabIndex() && UsingPad()) { this->bar1.Reset(); this->bar2.Reset(); TabIndex() = window->DummyTab(); TabSubIndex() = 0; while (TabIndex()->object != this) TabIndex() = TabIndex()->next; } float flipMul = 1.0; if (this->flipped) flipMul = -1.0; bool overSecond = false; // The second list of options if (this->status >= 3) { int count = this->data[this->pos1]->GetCount(); float lOffset = (this->height + this->off * this->height) * flipMul - this->offset; int pos = this->pos1; if (this->status == 2) pos = this->over1; int position = this->bar1.pos + 0.5; gIgnoreBounds = true; this->bar2.x = this->x + size.x * 3 / 4 - SCROLLBAR_WIDTH / 2; this->bar2.y = this->y - (5.5 + pos - position) * this->height; this->bar2.count = count; this->bar2.Update(); gIgnoreBounds = false; float widthOffset = 0; int visibleCount = count - this->bar2.pos; if (visibleCount > COMBOBOX_COUNT) visibleCount = COMBOBOX_COUNT; if (count > COMBOBOX_COUNT) widthOffset = this->bar2.width / 2; // Combo boxes deal specially with tabbing if (TabIndex()) { // Tabbed away from us! if (TabIndex()->object != this) { this->pos1 = (*this->target1); this->pos2 = (*this->target2); this->status = 0; this->over1 = -1; this->over2 = -1; return true; } bool downTriggered = false; bool upTriggered = false; downTriggered = DownTriggered(); upTriggered = UpTriggered(); if (downTriggered) { TabSubIndex() ++; if (TabSubIndex() > visibleCount - 1) { TabSubIndex() = visibleCount - 1; this->bar2.pos ++; if (this->bar2.pos > count - COMBOBOX_COUNT) this->bar2.pos --; } } if (upTriggered) { TabSubIndex() --; if (TabSubIndex() < 0) { TabSubIndex() = 0; this->bar2.pos --; if (this->bar2.pos < 0) this->bar2.pos ++; } } CursorY() = window->GetY() + this->y - this->height * TabSubIndex() - lOffset; CursorX() = window->GetX() + this->x + this->width / 2 - widthOffset; } // See if we're over one of the choices if (CursorColliding(this->x + this->width / 2 - widthOffset, this->y + this->height / 2 - this->height * visibleCount / 2 - lOffset, this->width / 2 - widthOffset * 2, this->height * visibleCount, true)) { int choice = (window->GetY() + this->y + this->height / 2 - CursorY() - lOffset) / this->height; if (choice < 0) choice = 0; // We've found our choice! this->over2 = this->bar2.pos + choice; if (PositiveTriggered()) { this->pos2 = this->bar2.pos + choice; this->status = 0; (*this->target1) = this->pos1; (*this->target2) = this->pos2; TabSubIndex() = -1; this->func(this->funcExtra); return false; } } else { this->over2 = -1; } if (CursorColliding(this->x + this->width / 2, this->y + this->height / 2 - this->height * visibleCount / 2 - lOffset, this->width / 2, this->height * visibleCount, true)) overSecond = true; } // The first list of options if (this->status >= 2) { gIgnoreBounds = true; this->bar1.x = this->x + size.x / 4 - SCROLLBAR_WIDTH / 2; this->bar1.y = this->y - this->height * 5.5; this->bar1.count = this->count; this->bar1.Update(); gIgnoreBounds = false; float widthOffset = 0; int visibleCount = this->count - this->bar1.pos; if (visibleCount > COMBOBOX_COUNT) visibleCount = COMBOBOX_COUNT; if (this->count > COMBOBOX_COUNT) widthOffset = this->bar1.width / 2; // Combo boxes deal specially with tabbing if (status == 2 && TabIndex()) { // Tabbed away from us! if (TabIndex()->object != this) { this->pos1 = (*this->target1); this->pos2 = (*this->target2); this->status = 0; return true; } // Just started if (TabSubIndex() == -1) TabSubIndex() = 0; bool downTriggered = false; bool upTriggered = false; if (this->flipped) { downTriggered = UpTriggered(); upTriggered = DownTriggered(); } else { downTriggered = DownTriggered(); upTriggered = UpTriggered(); } if (downTriggered) { TabSubIndex() ++; if (TabSubIndex() > visibleCount - 1) { TabSubIndex() = visibleCount - 1; this->bar1.pos ++; if (this->bar1.pos > this->count - COMBOBOX_COUNT) this->bar1.pos --; } } if (upTriggered) { TabSubIndex() --; if (TabSubIndex() < 0) { TabSubIndex() = 0; this->bar1.pos --; if (this->bar1.pos < 0) this->bar1.pos ++; } } CursorY() = window->GetY() + this->y - (this->height + this->height * TabSubIndex()) * flipMul; CursorX() = window->GetX() + this->x; } // See if we're over one of the choices if (CursorColliding(this->x - widthOffset, this->y - (this->height / 2 + this->height * visibleCount / 2) * flipMul, this->width / 2 - widthOffset * 2, this->height * visibleCount, true)) { int choice = (window->GetY() + this->y - (this->height / 2) * flipMul - CursorY()) / this->height * flipMul; if (choice < 0) choice = 0; // We've found our choice! this->over1 = this->bar1.pos + choice; this->bar2.pos = 0; this->bar2.wasMax = false; if (PositiveTriggered() || (TabIndex() && RightTriggered())) { int old = this->pos1; this->off = choice; this->pos1 = this->bar1.pos + choice; this->pos2 = -1; this->over2 = -1; if (this->status == 4 && old == this->pos1) this->status = 3; else this->status = 4; if (TabIndex()) TabSubIndex() = 0; return false; } if (this->status == 3) { this->status = 2; this->over2 = -1; this->pos2 = -1; } } else if (status >= 3) {} // If we moved to the right, select the choice anyway! else if (this->over1 >= 0 && CursorColliding(this->x + this->width / 2 - widthOffset, this->y - (this->height / 2 + this->height * COMBOBOX_COUNT / 2 + this->over1 * this->height) * flipMul, this->width / 2 - widthOffset * 2, this->height * COMBOBOX_COUNT, true)) { this->off = this->over1 - this->bar1.pos + 0.5; this->pos1 = this->over1; this->pos2 = -1; this->status = 3; return Update(); } else { this->over1 = -1; this->over2 = -1; } if (overSecond || CursorColliding(this->x, this->y - (this->height / 2 + this->height * visibleCount / 2) * flipMul, this->width / 2, this->height * visibleCount, true)) return false; if (PositiveTriggered()) { this->pos1 = (*this->target1); this->pos2 = (*this->target2); this->status = 0; } if (this->CursorOver()) return false; return true; } this->pos1 = (*this->target1); this->pos2 = (*this->target2); this->bar1.Reset(); this->bar2.Reset(); int status; // We don't care as much if the cursor isn't being triggered if (!PositiveTriggered()) status = 1; else status = 2; // See if we just hit something if (CursorColliding(this->x, this->y, this->width, this->height)) this->status = status; else this->status = 0; this->over1 = -1; this->over2 = -1; return (this->status == 0); } // Draws the combo box void DoubleComboBox::Draw() { float arrowWidth = this->height; // The main box itself if (this->status == 1) { DrawBox(CVec3(this->x, this->y, this->z + 0.003), size, CVec4(0.13, 0.13, 0.13)); DrawBox(CVec3(this->x + (this->width - arrowWidth) / 2, this->y, this->z + 0.0035), CVec2(arrowWidth, this->height), CVec4(0.1, 0.1, 0.1)); } else { DrawBox(CVec3(this->x, this->y, this->z + 0.003), size, CVec4(0.03, 0.03, 0.03)); DrawBox(CVec3(this->x + (this->width - arrowWidth) / 2, this->y, this->z + 0.0035), CVec2(arrowWidth, this->height), CVec4(0.0, 0.0, 0.0)); } // The "selected" text char buffer[50]; sprintf(buffer, "%s - %s", this->data[(*this->target1)]->GetName(), this->data[(*this->target1)]->GetPointers()[(*this->target2)]->GetName()); DrawText(buffer, CVec3(this->x - arrowWidth / 2, this->y, this->z + 0.01), CVec2(this->width - arrowWidth, this->height * 0.7), CVec4(1.0, 1.0, 1.0)); // The arrow on the right DrawTexQuad(*GetTexture(CW_TEXTURE_COMBODOWNARROW), CVec3(this->x + (this->width - arrowWidth) / 2, this->y, this->z + 0.005), CVec2(arrowWidth / 2, this->height / 2), CVec4(0.8, 0.8, 0.8)); // If the combo box is selected... if (this->status >= 2) { // Draw regardless of depth GX2SetDepthOnlyControl(GX2_ENABLE, GX2_ENABLE, GX2_COMPARE_ALWAYS); float widthOffset = 0; if (this->count > COMBOBOX_COUNT) widthOffset = this->bar1.width / 2; int count = COMBOBOX_COUNT; if (count > this->count) count = this->count; this->flipped = false; if (window->GetY() + this->y - this->height / 2 - this->height * count < -1.0 && window->GetY() + this->y + this->height / 2 + this->height * count < 1.0) this->flipped = true; float flipMul = 1.0; if (this->flipped) flipMul = -1.0; DrawBox(CVec3(this->x, this->y - (this->height / 2 + this->height * count / 2) * flipMul, this->z + 0.5), CVec2(this->width / 2, this->height * count), CVec4(0.0, 0.0, 0.0)); int position = this->bar1.pos + 0.5; float startY = this->y - this->height * flipMul; // Draw a "highlight" if a choice is over if (this->over1 >= position && this->over1 < position + COMBOBOX_COUNT) DrawQuad(CVec3(this->x, startY - (this->over1 - position) * this->height * flipMul, this->z + 0.51), CVec2(this->width / 2, this->height), CVec4(0.2, 0.2, 0.2)); // Draw a "highlight" if a choice is selected if (this->pos1 >= position && this->pos1 < position + COMBOBOX_COUNT && status >= 3) DrawQuad(CVec3(this->x - widthOffset, startY - (this->pos1 - position) * this->height * flipMul, this->z + 0.52), CVec2(this->width / 2 - widthOffset * 2, this->height), CVec4(0.3, 0.3, 0.3)); if (count > position + COMBOBOX_COUNT) count = position + COMBOBOX_COUNT; // Figure out what color most of them will be float color = 0.4; if (this->status == 2) color = 1.0; // Draw only the elements we want to see! for (int i = 0; i < count; ++i) { float tempColor = color; if (i + position == this->over1 || i + position == this->pos1) tempColor = 1.0; DrawText(this->data[i + position]->GetName(), CVec3(this->x - this->bar1.width / 2, startY, this->z + 0.53), CVec2(this->width / 2 - this->bar1.width, this->height * 0.5), CVec4(tempColor, tempColor, tempColor)); startY -= this->height * flipMul; } // Draw regardless of depth GX2SetDepthOnlyControl(GX2_ENABLE, GX2_ENABLE, GX2_COMPARE_ALWAYS); this->bar1.x = this->x + size.x / 4 - SCROLLBAR_WIDTH / 2; this->bar1.y = this->y - this->height * 5.5 * flipMul; this->bar1.count = this->count; this->bar1.Draw(); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // If an option in the first combo box is selected... int pos = this->pos1; if (this->status == 2) pos = this->over1; if (pos >= 0) { float widthOffset = 0; int count = this->data[pos]->GetCount(); if (count > COMBOBOX_COUNT) { widthOffset = this->bar2.width / 2; count = COMBOBOX_COUNT; } int position = this->bar1.pos + 0.5; int position2 = this->bar2.pos + 0.5; float startY = this->y - (this->height + (pos - position) * this->height) * flipMul; this->offset = 0; if (window->GetY() + startY - this->height / 2 - this->height * count < -1.0) this->offset = -window->GetY() - startY - this->height / 2 + this->height * count - 1.0; startY += this->offset; DrawBox(CVec3(this->x + this->width / 2, this->y + this->height / 2 - this->height * count / 2 - (this->height + (pos - position) * this->height) * flipMul + this->offset, this->z + 0.5), CVec2(this->width / 2, this->height * count), CVec4(0.0, 0.0, 0.0)); // Draw a "highlight" if a choice is over or selected if (this->status >= 3) { if (this->over2 >= position2 && this->over2 < position2 + COMBOBOX_COUNT) DrawQuad(CVec3(this->x - widthOffset + this->width / 2, startY - (this->over2 - position2) * this->height, this->z + 0.51), CVec2(this->width / 2 - widthOffset * 2, this->height), CVec4(0.2, 0.2, 0.2)); } //float arrowY = startY; // Draw only the elements we want to see! SubCombo** pointers = this->data[pos]->GetPointers(); for (int i = 0; i < count; ++i) { DrawText(pointers[i + position2]->GetName(), CVec3(this->x + this->width / 2 - this->bar2.width / 2, startY, this->z + 0.52), CVec2(this->width / 2 - this->bar2.width, this->height * 0.5), CVec4(1.0, 1.0, 1.0)); startY -= this->height; } // Display a helpful arrow to point at the other box! //DrawTexQuad(arrowTex[RIGHTARROW], this->x + this->width / 4, arrowY, this->z + 0.53, this->height * 0.7, this->height * 0.7, 0.8, 0.8, 0.8); this->bar2.count = this->data[pos]->GetCount(); this->bar2.x = this->x + size.x * 3 / 4 - SCROLLBAR_WIDTH / 2; this->bar2.y = startY + this->height / 2 + this->height * count / 2; this->bar2.Draw(); } // Draw normally again GX2SetDepthOnlyControl(GX2_ENABLE, GX2_ENABLE, GX2_COMPARE_LESS); } } void DoubleComboBox::Reset() { if (this->status > 0) this->status = 0; this->bar1.Reset(); this->bar2.Reset(); }