/*************************************************************************** * Copyright (C) 2011 * by Dimok * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any * damages arising from the use of this software. * * Permission is granted to anyone to use this software for any * purpose, including commercial applications, and to alter it and * redistribute it freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you * must not claim that you wrote the original software. If you use * this software in a product, an acknowledgment in the product * documentation would be appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and * must not be misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source * distribution. ***************************************************************************/ #include "themes/Resources.h" #include "menu/menus.h" #include "gui_scrollbar.hpp" #include "utils/tools.h" GuiScrollbar::GuiScrollbar(int h, u8 m) { SelItem = 0; SelInd = 0; RowSize = 0; PageSize = 0; EntrieCount = 0; ScrollSpeed = 15; ButtonScroll = 0; ButtonScrollSpeed = 20; ScrollState = 0; pressedChan = -1; AllowDPad = true; Mode = m; listChanged.connect(this, &GuiScrollbar::setScrollboxPosition); scrollbarTop = Resources::GetImageData("scrollBarTop.png"); scrollbarBottom = Resources::GetImageData("scrollBarBottom.png"); scrollbarTile = Resources::GetImageData("scrollBarTile.png"); arrowDown = Resources::GetImageData("scrollbar_arrowdown.png"); arrowDownOver = Resources::GetImageData("scrollbar_arrowdown.png"); arrowUp = Resources::GetImageData("scrollbar_arrowup.png"); arrowUpOver = Resources::GetImageData("scrollbar_arrowup.png"); scrollbarBox = Resources::GetImageData("scrollbar_box.png"); scrollbarBoxOver = Resources::GetImageData("scrollbar_box.png"); oneButtonScrollImgData = Resources::GetImageData("oneButtonScroll.png"); height = h; width = MAX(scrollbarBox->GetWidth(), scrollbarTile->GetWidth()); MinHeight = arrowUp->GetHeight(); MaxHeight = height-scrollbarBox->GetHeight()-arrowDown->GetHeight(); trigHeldA = new GuiTrigger; trigHeldA->SetHeldTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); int Tiles = (height-scrollbarTop->GetHeight()-scrollbarBottom->GetHeight())/4; int PositionY = 0; ButtonPositionX = 0; oneButtonScrollImg = new GuiImage(oneButtonScrollImgData); scrollbarTopImg = new GuiImage(scrollbarTop); scrollbarTopImg->SetParent(this); scrollbarTopImg->SetAlignment(ALIGN_CENTER, ALIGN_TOP); scrollbarTopImg->SetPosition(0, PositionY); PositionY += scrollbarTop->GetHeight(); scrollbarTileImg = new GuiImage(scrollbarTile); scrollbarTileImg->SetParent(this); scrollbarTileImg->SetAlignment(ALIGN_CENTER, ALIGN_TOP); scrollbarTileImg->SetPosition(0, PositionY); scrollbarTileImg->SetTileVertical(Tiles); PositionY += Tiles*scrollbarTile->GetHeight(); scrollbarBottomImg = new GuiImage(scrollbarBottom); scrollbarBottomImg->SetParent(this); scrollbarBottomImg->SetAlignment(ALIGN_CENTER, ALIGN_TOP); scrollbarBottomImg->SetPosition(0, PositionY); arrowDownImg = new GuiImage(arrowDown); arrowDownOverImg = new GuiImage(arrowDownOver); arrowUpImg = new GuiImage(arrowUp); arrowUpOverImg = new GuiImage(arrowUpOver); scrollbarBoxImg = new GuiImage(scrollbarBox); scrollbarBoxOverImg = new GuiImage(scrollbarBoxOver); arrowUpBtn = new GuiButton(arrowUpImg->GetWidth(), arrowUpImg->GetHeight()); arrowUpBtn->SetParent(this); arrowUpBtn->SetImage(arrowUpImg); arrowUpBtn->SetImageOver(arrowUpOverImg); arrowUpBtn->SetAlignment(ALIGN_CENTER, ALIGN_TOP); arrowUpBtn->SetPosition(ButtonPositionX, 0); arrowUpBtn->SetHoldable(true); arrowUpBtn->SetTrigger(trigHeldA); arrowUpBtn->SetSoundOver(btnSoundOver); arrowUpBtn->SetSoundClick(btnSoundClick); arrowUpBtn->Held.connect(this, &GuiScrollbar::OnUpButtonHold); arrowDownBtn = new GuiButton(arrowDownImg->GetWidth(), arrowDownImg->GetHeight()); arrowDownBtn->SetParent(this); arrowDownBtn->SetImage(arrowDownImg); arrowDownBtn->SetImageOver(arrowDownOverImg); arrowDownBtn->SetAlignment(ALIGN_CENTER, ALIGN_BOTTOM); arrowDownBtn->SetPosition(ButtonPositionX, 0); arrowDownBtn->SetHoldable(true); arrowDownBtn->SetTrigger(trigHeldA); arrowDownBtn->SetSoundOver(btnSoundOver); arrowDownBtn->SetSoundClick(btnSoundClick); arrowDownBtn->Held.connect(this, &GuiScrollbar::OnDownButtonHold); scrollbarBoxBtn = new GuiButton(scrollbarBoxImg->GetWidth(), scrollbarBoxImg->GetHeight()); scrollbarBoxBtn->SetParent(this); scrollbarBoxBtn->SetImage(scrollbarBoxImg); scrollbarBoxBtn->SetImageOver(scrollbarBoxOverImg); scrollbarBoxBtn->SetAlignment(ALIGN_CENTER, ALIGN_TOP); scrollbarBoxBtn->SetPosition(ButtonPositionX, MinHeight); scrollbarBoxBtn->SetMinY(MinHeight); scrollbarBoxBtn->SetMaxY(MaxHeight); scrollbarBoxBtn->SetHoldable(true); scrollbarBoxBtn->SetTrigger(trigHeldA); scrollbarBoxBtn->Held.connect(this, &GuiScrollbar::OnBoxButtonHold); } GuiScrollbar::~GuiScrollbar() { delete scrollbarTop; delete scrollbarBottom; delete scrollbarTile; delete arrowDown; delete arrowDownOver; delete arrowUp; delete arrowUpOver; delete scrollbarBox; delete scrollbarBoxOver; delete oneButtonScrollImg; delete arrowUpBtn; delete arrowDownBtn; delete scrollbarBoxBtn; delete scrollbarTopImg; delete scrollbarBottomImg; delete scrollbarTileImg; delete arrowDownImg; delete arrowDownOverImg; delete arrowUpImg; delete arrowUpOverImg; delete scrollbarBoxImg; delete scrollbarBoxOverImg; delete oneButtonScrollImgData; delete trigHeldA; } void GuiScrollbar::ScrollOneUp() { if(Mode == ICONMODE) { if(SelInd+SelItem-RowSize >= 0) { SelItem = SelItem-RowSize; if(SelItem < 0) { // move list up by 1 SelInd = SelInd-RowSize; SelItem = SelItem+RowSize; } } } else if(Mode == LISTMODE) { if(SelItem == 0 && SelInd > 0) { // move list up by 1 --SelInd; } else if(SelInd+SelItem > 0) { --SelItem; } } } void GuiScrollbar::ScrollOneDown() { if(Mode == ICONMODE) { int i = RowSize; while(SelInd+SelItem+RowSize >= EntrieCount && i > 0 && SelItem > 0 && RowSize < EntrieCount) { --i; --SelItem; } if(SelInd+SelItem+RowSize < EntrieCount) { SelItem = SelItem+RowSize; if(SelItem >= PageSize) { // move list down by 1 SelInd += RowSize; SelItem = SelItem-RowSize; } } } else if(Mode == LISTMODE) { if(SelInd+SelItem + 1 < EntrieCount) { if(SelItem == PageSize-1) { // move list down by 1 SelInd++; } else { SelItem++; } } } } void GuiScrollbar::OnUpButtonHold(GuiButton *sender, int pointer, const POINT &p) { if(ScrollState < ScrollSpeed) return; ScrollOneUp(); ScrollState = 0; listChanged(SelItem, SelInd); } void GuiScrollbar::OnDownButtonHold(GuiButton *sender, int pointer, const POINT &p) { if(ScrollState < ScrollSpeed) return; ScrollOneDown(); ScrollState = 0; listChanged(SelItem, SelInd); } void GuiScrollbar::OnBoxButtonHold(GuiButton *sender, int pointer, const POINT &p) { if(ScrollState < ScrollSpeed) return; if(!userInput[pointer].wpad.ir.valid) return; int y = p.y-this->GetTop()-scrollbarBox->GetHeight()/2; int positionWiimote = LIMIT(y-MinHeight, 0, MaxHeight-MinHeight); int newSelected = (int) ((float) positionWiimote / (float) (MaxHeight-MinHeight) * (float) (EntrieCount-1)); if(Mode == ICONMODE) { int rows = (int) floor(((float) (newSelected-SelInd-SelItem)) / ((float) RowSize)); while(SelInd+rows*RowSize >= EntrieCount-PageSize+RowSize) rows--; int pageIndex = LIMIT(SelInd+rows*RowSize, 0, EntrieCount-1-RowSize); if(newSelected <= 0) SelItem = 0; else if(newSelected >= EntrieCount-1) SelItem = EntrieCount-1-pageIndex; SelInd = pageIndex; } else if(Mode == LISTMODE) { int diff = newSelected-SelInd-SelItem; if(newSelected <= 0) { SelItem = 0; SelInd = 0; } else if(newSelected >= EntrieCount-1) { SelItem = (PageSize-1 < EntrieCount-1) ? PageSize-1 : EntrieCount-1; SelInd = EntrieCount-PageSize; } else if(newSelected < PageSize && SelInd == 0 && diff < 0) { SelItem = MAX(SelItem+diff, 0); } else if(EntrieCount-newSelected < PageSize && SelInd == EntrieCount-PageSize && diff > 0) { SelItem = MIN(SelItem+diff, PageSize-1); } else { SelInd = LIMIT(SelInd+diff, 0, ((EntrieCount-PageSize < 0) ? 0 : EntrieCount-PageSize)); } } ScrollState = 0; listChanged(SelItem, SelInd); } void GuiScrollbar::SetPageSize(int size) { if(PageSize == size) return; PageSize = size; listChanged(SelItem, SelInd); } void GuiScrollbar::SetRowSize(int size) { if(RowSize == size) return; RowSize = size; listChanged(SelItem, SelInd); } void GuiScrollbar::SetSelectedItem(int pos) { if(SelItem == pos) return; SelItem = pos; } void GuiScrollbar::SetSelectedIndex(int pos) { if(SelInd == pos) return; SelInd = pos; listChanged(SelItem, SelInd); } void GuiScrollbar::SetEntrieCount(int cnt) { if(EntrieCount == cnt) return; EntrieCount = cnt; listChanged(SelItem, SelInd); } void GuiScrollbar::setScrollboxPosition(int SelItem, int SelInd) { if(Mode == ICONMODE) { u8 row = (u8) floor((float) SelItem / (float) RowSize); int position = MinHeight+(MaxHeight-MinHeight)*(SelInd+row*RowSize)/(EntrieCount-1); if(position < MinHeight) position = MinHeight; else if(position > MaxHeight || ((SelInd+PageSize >= (EntrieCount-1)) && row > 1)) position = MaxHeight; scrollbarBoxBtn->SetPosition(ButtonPositionX, position); } else if(Mode == LISTMODE) { int position = MinHeight+(MaxHeight-MinHeight)*(SelInd+SelItem)/(EntrieCount-1); if(position < MinHeight) position = MinHeight; else if(position > MaxHeight || (SelInd+SelItem >= EntrieCount-1)) position = MaxHeight; scrollbarBoxBtn->SetPosition(ButtonPositionX, position); } } void GuiScrollbar::CheckDPadControls(GuiTrigger *t) { if(t->Up()) { ScrollOneUp(); listChanged(SelItem, SelInd); } else if(t->Down()) { ScrollOneDown(); listChanged(SelItem, SelInd); } else if(t->Left() && Mode == LISTMODE) { SelInd -= PageSize; if(SelInd < 0) { SelInd = 0; SelItem = 0; } listChanged(SelItem, SelInd); } else if(t->Right() && Mode == LISTMODE) { SelInd += PageSize; if(SelInd+PageSize >= EntrieCount) { SelInd = EntrieCount-PageSize; SelItem = PageSize-1; } listChanged(SelItem, SelInd); } } void GuiScrollbar::ScrollByButton(GuiTrigger *t) { static int pressedPosition = -1; if(!t->wpad.ir.valid || ScrollState < ButtonScrollSpeed-ButtonScrollSpeed*fabs(pressedPosition-t->wpad.ir.y)/250.f) return; if(pressedChan == -1 && (t->wpad.btns_d & ButtonScroll) && parentElement && parentElement->IsInside(t->wpad.ir.x, t->wpad.ir.y)) { pressedPosition = t->wpad.ir.y; pressedChan = t->chan; oneButtonScrollImg->SetPosition(t->wpad.ir.x-oneButtonScrollImg->GetWidth()/2, t->wpad.ir.y-oneButtonScrollImg->GetHeight()/2); } if(pressedChan == t->chan && (t->wpad.btns_h & ButtonScroll)) { if(pressedPosition-oneButtonScrollImg->GetHeight()/2 > t->wpad.ir.y) ScrollOneUp(); else if(pressedPosition+oneButtonScrollImg->GetHeight()/2 < t->wpad.ir.y) ScrollOneDown(); ScrollState = 0; listChanged(SelItem, SelInd); } if(pressedChan == t->chan && !t->wpad.btns_d && !t->wpad.btns_h) { pressedChan = -1; pressedPosition = -1; } } void GuiScrollbar::Draw() { scrollbarTileImg->Draw(); scrollbarTopImg->Draw(); scrollbarBottomImg->Draw(); arrowUpBtn->Draw(); arrowDownBtn->Draw(); scrollbarBoxBtn->Draw(); if(pressedChan >= 0 && userInput[pressedChan].wpad.ir.valid) oneButtonScrollImg->Draw(); UpdateEffects(); } void GuiScrollbar::Update(GuiTrigger * t) { arrowUpBtn->Update(t); arrowDownBtn->Update(t); scrollbarBoxBtn->Update(t); if(AllowDPad) CheckDPadControls(t); if(ButtonScroll) ScrollByButton(t); ++ScrollState; }