diff --git a/ui/screen.cpp b/ui/screen.cpp index 5ce710abaa..5b2357cc65 100644 --- a/ui/screen.cpp +++ b/ui/screen.cpp @@ -15,50 +15,50 @@ ScreenManager::~ScreenManager() { } void ScreenManager::switchScreen(Screen *screen) { - if (dialog_.size()) - { - WLOG("Switching screens - dropping the whole dialog stack"); - while (dialog_.size()) - pop(); - } - // TODO: is this still true? - // Note that if a dialog is found, this will be a silent background switch that - // will only become apparent if the dialog is closed. The previous screen will stick around - // until that switch. - if (nextScreen_ != 0) { - FLOG("WTF? Already had a nextScreen_"); - } - if (screen != currentScreen_) { - nextScreen_ = screen; + if (dialog_.size()) + { + WLOG("Switching screens - dropping the whole dialog stack"); + while (dialog_.size()) + pop(); + } + // TODO: is this still true? + // Note that if a dialog is found, this will be a silent background switch that + // will only become apparent if the dialog is closed. The previous screen will stick around + // until that switch. + if (nextScreen_ != 0) { + FLOG("WTF? Already had a nextScreen_"); + } + if (screen != currentScreen_) { + nextScreen_ = screen; nextScreen_->setScreenManager(this); - } + } } void ScreenManager::update(InputState &input) { - if (dialog_.size()) { - dialog_.back()->update(input); - return; - } + if (dialog_.size()) { + dialog_.back()->update(input); + return; + } if (nextScreen_) { - ILOG("Screen switch!"); - Screen *temp = currentScreen_; + ILOG("Screen switch!"); + Screen *temp = currentScreen_; currentScreen_ = nextScreen_; - delete temp; - temp = 0; + delete temp; + temp = 0; nextScreen_ = 0; } if (currentScreen_) { currentScreen_->update(input); - } + } } void ScreenManager::render() { - if (dialog_.size()) { - dialog_.back()->render(); - return; - } + if (dialog_.size()) { + dialog_.back()->render(); + return; + } if (currentScreen_) { currentScreen_->render(); } @@ -76,53 +76,53 @@ void ScreenManager::deviceLost() } Screen *ScreenManager::topScreen() { - if (dialog_.size()) - return dialog_.back(); - else - return currentScreen_; + if (dialog_.size()) + return dialog_.back(); + else + return currentScreen_; } void ScreenManager::shutdown() { - if (nextScreen_) { - delete nextScreen_; - nextScreen_ = 0; - } - if (currentScreen_) { - delete currentScreen_; - currentScreen_ = 0; - } + if (nextScreen_) { + delete nextScreen_; + nextScreen_ = 0; + } + if (currentScreen_) { + delete currentScreen_; + currentScreen_ = 0; + } } void ScreenManager::push(Screen *screen) { screen->setScreenManager(this); - dialog_.push_back(screen); + dialog_.push_back(screen); } void ScreenManager::pop() { - if (dialog_.size()) { - delete dialog_.back(); - dialog_.pop_back(); - } else { - ELOG("Can't push when no dialog is shown"); - } + if (dialog_.size()) { + delete dialog_.back(); + dialog_.pop_back(); + } else { + ELOG("Can't push when no dialog is shown"); + } } void ScreenManager::finishDialog(const Screen *dialog, DialogResult result) { - if (!dialog_.size()) { - ELOG("Must be in a dialog to finishDialog"); - return; - } - Screen *dlg = dialog_.back(); - if (dialog != dialog_.back()) - { - ELOG("Wrong dialog being finished!"); - return; - } - if (dialog_.size()) { - dialog_.pop_back(); - } - Screen *caller = topScreen(); - caller->dialogFinished(dialog, result); - delete dialog; + if (!dialog_.size()) { + ELOG("Must be in a dialog to finishDialog"); + return; + } + Screen *dlg = dialog_.back(); + if (dialog != dialog_.back()) + { + ELOG("Wrong dialog being finished!"); + return; + } + if (dialog_.size()) { + dialog_.pop_back(); + } + Screen *caller = topScreen(); + caller->dialogFinished(dialog, result); + delete dialog; } diff --git a/ui/screen.h b/ui/screen.h index 36d4993f9f..4c6af7bccb 100644 --- a/ui/screen.h +++ b/ui/screen.h @@ -21,10 +21,10 @@ struct InputState; enum DialogResult { - DR_OK, - DR_CANCEL, - DR_YES, - DR_NO, + DR_OK, + DR_CANCEL, + DR_YES, + DR_NO, }; class ScreenManager; @@ -36,14 +36,14 @@ public: virtual void update(InputState &input) = 0; virtual void render() {} virtual void deviceLost() {} - virtual void dialogFinished(const Screen *dialog, DialogResult result) {} + virtual void dialogFinished(const Screen *dialog, DialogResult result) {} ScreenManager *screenManager() { return screenManager_; } void setScreenManager(ScreenManager *sm) { screenManager_ = sm; } private: ScreenManager *screenManager_; - DISALLOW_COPY_AND_ASSIGN(Screen); + DISALLOW_COPY_AND_ASSIGN(Screen); }; class Transition { @@ -60,22 +60,22 @@ public: void update(InputState &input); void render(); void deviceLost(); - void shutdown(); + void shutdown(); - // Push a dialog box in front. Currently 1-level only. - void push(Screen *screen); + // Push a dialog box in front. Currently 1-level only. + void push(Screen *screen); - // Pops the dialog away. - void finishDialog(const Screen *dialog, DialogResult result = DR_OK); + // Pops the dialog away. + void finishDialog(const Screen *dialog, DialogResult result = DR_OK); private: - void pop(); - Screen *topScreen(); - // Base screen. These don't "stack" and you can move in any order between them. + void pop(); + Screen *topScreen(); + // Base screen. These don't "stack" and you can move in any order between them. Screen *currentScreen_; Screen *nextScreen_; - // Dialog stack. These are shown "on top" of base screens and the Android back button works as expected. - // Used for options, in-game menus and other things you expect to be able to back out from onto something. - std::list dialog_; + // Dialog stack. These are shown "on top" of base screens and the Android back button works as expected. + // Used for options, in-game menus and other things you expect to be able to back out from onto something. + std::list dialog_; }; diff --git a/ui/ui.cpp b/ui/ui.cpp index 99fbedc10a..aabebbab0a 100644 --- a/ui/ui.cpp +++ b/ui/ui.cpp @@ -19,29 +19,29 @@ static const Atlas *themeAtlas; static UITheme theme; void UIInit(const Atlas *atlas, const UITheme &ui_theme) { - ui_draw2d.SetAtlas(atlas); - ui_draw2d_front.SetAtlas(atlas); - themeAtlas = atlas; - theme = ui_theme; - memset(&uistate, 0, sizeof(uistate)); + ui_draw2d.SetAtlas(atlas); + ui_draw2d_front.SetAtlas(atlas); + themeAtlas = atlas; + theme = ui_theme; + memset(&uistate, 0, sizeof(uistate)); } void UIUpdateMouse(int i, float x, float y, bool down) { - if (down && !uistate.mousedown[i]) { - uistate.mousepressed[i] = 1; - uistate.mouseStartX[i] = x; - uistate.mouseStartY[i] = y; - } else { - uistate.mousepressed[i] = 0; - } - if (uistate.mousedown[i]) - uistate.mouseframesdown[i]++; - else - uistate.mouseframesdown[i] = 0; + if (down && !uistate.mousedown[i]) { + uistate.mousepressed[i] = 1; + uistate.mouseStartX[i] = x; + uistate.mouseStartY[i] = y; + } else { + uistate.mousepressed[i] = 0; + } + if (uistate.mousedown[i]) + uistate.mouseframesdown[i]++; + else + uistate.mouseframesdown[i] = 0; - uistate.mousex[i] = x; - uistate.mousey[i] = y; - uistate.mousedown[i] = down; + uistate.mousex[i] = x; + uistate.mousey[i] = y; + uistate.mousedown[i] = down; } void UIReset() { @@ -49,259 +49,265 @@ void UIReset() { } bool UIRegionHit(int i, int x, int y, int w, int h, int margin) { - // Input handling - if (uistate.mousex[i] < x - margin || - uistate.mousey[i] < y - margin || - uistate.mousex[i] >= x + w + margin || - uistate.mousey[i] >= y + h + margin) { - return false; - } else { - return true; - } + // Input handling + if (uistate.mousex[i] < x - margin || + uistate.mousey[i] < y - margin || + uistate.mousex[i] >= x + w + margin || + uistate.mousey[i] >= y + h + margin) { + return false; + } else { + return true; + } } void UIBegin() { - for (int i = 0; i < MAX_POINTERS; i++) - uistate.hotitem[i] = 0; - ui_draw2d.Begin(); - ui_draw2d_front.Begin(); + for (int i = 0; i < MAX_POINTERS; i++) + uistate.hotitem[i] = 0; + ui_draw2d.Begin(); + ui_draw2d_front.Begin(); } void UIEnd() { - for (int i = 0; i < MAX_POINTERS; i++) { - if (uistate.mousedown[i] == 0) { - uistate.activeitem[i] = 0; - } else { - if (uistate.activeitem[i] == 0) { - uistate.activeitem[i] = -1; - } - } - } - ui_draw2d.End(); - ui_draw2d_front.End(); + for (int i = 0; i < MAX_POINTERS; i++) { + if (uistate.mousedown[i] == 0) { + uistate.activeitem[i] = 0; + } else { + if (uistate.activeitem[i] == 0) { + uistate.activeitem[i] = -1; + } + } + } + ui_draw2d.End(); + ui_draw2d_front.End(); - if (uistate.ui_tick > 0) - uistate.ui_tick--; + if (uistate.ui_tick > 0) + uistate.ui_tick--; } void UIText(int x, int y, const char *text, uint32_t color, float scale, int align) { - UIText(theme.uiFont, x, y, text, color, scale, align); + UIText(theme.uiFont, x, y, text, color, scale, align); } void UIText(int font, int x, int y, const char *text, uint32_t color, float scale, int align) { - ui_draw2d.SetFontScale(scale, scale); - ui_draw2d.DrawTextShadow(font, text, x, y, color, align); - ui_draw2d.SetFontScale(1.0f, 1.0f); + ui_draw2d.SetFontScale(scale, scale); + ui_draw2d.DrawTextShadow(font, text, x, y, color, align); + ui_draw2d.SetFontScale(1.0f, 1.0f); } int UIButton(int id, const LayoutManager &layout, float w, const char *text, int button_align) { - float h = themeAtlas->images[theme.buttonImage].h; + float h = themeAtlas->images[theme.buttonImage].h; - float x, y; - layout.GetPos(&w, &h, &x, &y); + float x, y; + layout.GetPos(&w, &h, &x, &y); - if (button_align & ALIGN_HCENTER) x -= w / 2; - if (button_align & ALIGN_VCENTER) y -= h / 2; - if (button_align & ALIGN_RIGHT) x -= w; - if (button_align & ALIGN_BOTTOMRIGHT) y -= h; + if (button_align & ALIGN_HCENTER) x -= w / 2; + if (button_align & ALIGN_VCENTER) y -= h / 2; + if (button_align & ALIGN_RIGHT) x -= w; + if (button_align & ALIGN_BOTTOMRIGHT) y -= h; - int txOffset = 0; + int txOffset = 0; - int clicked = 0; - for (int i = 0; i < MAX_POINTERS; i++) { - // Check whether the button should be hot, use a generous margin for touch ease - if (UIRegionHit(i, x, y, w, h, 8)) { - uistate.hotitem[i] = id; - if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) { - uistate.activeitem[i] = id; + int clicked = 0; + for (int i = 0; i < MAX_POINTERS; i++) { + // Check whether the button should be hot, use a generous margin for touch ease + if (UIRegionHit(i, x, y, w, h, 8)) { + uistate.hotitem[i] = id; + if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) { + uistate.activeitem[i] = id; } - } + } - if (uistate.hotitem[i] == id) { - if (uistate.activeitem[i] == id) { - // Button is both 'hot' and 'active' - txOffset = 2; - } else { - // Button is merely 'hot' - } - } else { - // button is not hot, but it may be active - } + if (uistate.hotitem[i] == id) { + if (uistate.activeitem[i] == id) { + // Button is both 'hot' and 'active' + txOffset = 2; + } else { + // Button is merely 'hot' + } + } else { + // button is not hot, but it may be active + } - // If button is hot and active, but mouse button is not - // down, the user must have clicked the button. - if (uistate.mousedown[i] == 0 && - uistate.hotitem[i] == id && + // If button is hot and active, but mouse button is not + // down, the user must have clicked the button. + if (uistate.mousedown[i] == 0 && + uistate.hotitem[i] == id && uistate.activeitem[i] == id) { - clicked = 1; - } - } + clicked = 1; + } + } - // Render button + // Render button - ui_draw2d.DrawImage2GridH(theme.buttonImage, x, y, x + w); - ui_draw2d.DrawTextShadow(theme.uiFont, text, x + w/2, y + h/2 + txOffset, 0xFFFFFFFF, ALIGN_HCENTER | ALIGN_VCENTER); + ui_draw2d.DrawImage2GridH(theme.buttonImage, x, y, x + w); + ui_draw2d.DrawTextShadow(theme.uiFont, text, x + w/2, y + h/2 + txOffset, 0xFFFFFFFF, ALIGN_HCENTER | ALIGN_VCENTER); - uistate.lastwidget = id; - return clicked; + uistate.lastwidget = id; + return clicked; } int UIImageButton(int id, const LayoutManager &layout, float w, int image, int button_align) { - float h = 64; - float x, y; - layout.GetPos(&w, &h, &x, &y); + float h = 64; + float x, y; + layout.GetPos(&w, &h, &x, &y); - if (button_align & ALIGN_HCENTER) x -= w / 2; - if (button_align & ALIGN_VCENTER) y -= h / 2; - if (button_align & ALIGN_RIGHT) x -= w; - if (button_align & ALIGN_BOTTOMRIGHT) y -= h; + if (button_align & ALIGN_HCENTER) x -= w / 2; + if (button_align & ALIGN_VCENTER) y -= h / 2; + if (button_align & ALIGN_RIGHT) x -= w; + if (button_align & ALIGN_BOTTOMRIGHT) y -= h; - int txOffset = 0; - int clicked = 0; - for (int i = 0; i < MAX_POINTERS; i++) { - // Check whether the button should be hot, use a generous margin for touch ease - if (UIRegionHit(i, x, y, w, h, 8)) { - uistate.hotitem[i] = id; - if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) - uistate.activeitem[i] = id; - } + int txOffset = 0; + int clicked = 0; + for (int i = 0; i < MAX_POINTERS; i++) { + // Check whether the button should be hot, use a generous margin for touch ease + if (UIRegionHit(i, x, y, w, h, 8)) { + uistate.hotitem[i] = id; + if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) + uistate.activeitem[i] = id; + } - if (uistate.hotitem[i] == id) { - if (uistate.activeitem[i] == id) { - // Button is both 'hot' and 'active' - txOffset = 2; - } else { - // Button is merely 'hot' - } - } else { - // button is not hot, but it may be active - } + if (uistate.hotitem[i] == id) { + if (uistate.activeitem[i] == id) { + // Button is both 'hot' and 'active' + txOffset = 2; + } else { + // Button is merely 'hot' + } + } else { + // button is not hot, but it may be active§ + } - // If button is hot and active, but mouse button is not - // down, the user must have clicked the button. - if (uistate.mousedown[i] == 0 && - uistate.hotitem[i] == id && - uistate.activeitem[i] == id) { - clicked = 1; - } - } + // If button is hot and active, but mouse button is not + // down, the user must have clicked the button. + if (uistate.mousedown[i] == 0 && + uistate.hotitem[i] == id && + uistate.activeitem[i] == id) { + clicked = 1; + } + } - // Render button + // Render button - ui_draw2d.DrawImage2GridH(theme.buttonImage, x, y, x + w); - ui_draw2d.DrawImage(image, x + w/2, y + h/2 + txOffset, 1.0f, 0xFFFFFFFF, ALIGN_HCENTER | ALIGN_VCENTER); + ui_draw2d.DrawImage2GridH(theme.buttonImage, x, y, x + w); + ui_draw2d.DrawImage(image, x + w/2, y + h/2 + txOffset, 1.0f, 0xFFFFFFFF, ALIGN_HCENTER | ALIGN_VCENTER); - uistate.lastwidget = id; - return clicked; + uistate.lastwidget = id; + return clicked; } int UICheckBox(int id, int x, int y, const char *text, int align, bool *value) { - const int h = 64; - float tw, th; - ui_draw2d.MeasureText(theme.uiFont, text, &tw, &th); - int w = themeAtlas->images[theme.checkOn].w + UI_SPACE + tw; - if (align & ALIGN_HCENTER) x -= w / 2; - if (align & ALIGN_VCENTER) y -= h / 2; - if (align & ALIGN_RIGHT) x -= w; - if (align & ALIGN_BOTTOMRIGHT) y -= h; + const int h = 64; + float tw, th; + ui_draw2d.MeasureText(theme.uiFont, text, &tw, &th); + int w = themeAtlas->images[theme.checkOn].w + UI_SPACE + tw; + if (align & ALIGN_HCENTER) x -= w / 2; + if (align & ALIGN_VCENTER) y -= h / 2; + if (align & ALIGN_RIGHT) x -= w; + if (align & ALIGN_BOTTOMRIGHT) y -= h; - int txOffset = 0; - int clicked = 0; - for (int i = 0; i < MAX_POINTERS; i++) { + int txOffset = 0; + int clicked = 0; + for (int i = 0; i < MAX_POINTERS; i++) { - // Check whether the button should be hot - if (UIRegionHit(i, x, y, w, h, 8)) { - uistate.hotitem[i] = id; - if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) - uistate.activeitem[i] = id; - } + // Check whether the button should be hot + if (UIRegionHit(i, x, y, w, h, 8)) { + uistate.hotitem[i] = id; + if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) + uistate.activeitem[i] = id; + } - // Render button + // Render button - if (uistate.hotitem[i] == id) { - if (uistate.activeitem[i] == id) { - // Button is both 'hot' and 'active' - txOffset = 2; - } else { - // Button is merely 'hot' - } - } else { - // button is not hot, but it may be active - } - // If button is hot and active, but mouse button is not - // down, the user must have clicked the button. - if (uistate.mousedown[i] == 0 && - uistate.hotitem[i] == id && - uistate.activeitem[i] == id) { - *value = !(*value); - clicked = 1; - } - } + if (uistate.hotitem[i] == id) { + if (uistate.activeitem[i] == id) { + // Button is both 'hot' and 'active' + txOffset = 2; + } else { + // Button is merely 'hot' + } + } else { + // button is not hot, but it may be active + } + // If button is hot and active, but mouse button is not + // down, the user must have clicked the button. + if (uistate.mousedown[i] == 0 && + uistate.hotitem[i] == id && + uistate.activeitem[i] == id) { + *value = !(*value); + clicked = 1; + } + } - ui_draw2d.DrawImage((*value) ? theme.checkOn : theme.checkOff, x, y+h/2, 1.0f, 0xFFFFFFFF, ALIGN_LEFT | ALIGN_VCENTER); - ui_draw2d.DrawTextShadow(theme.uiFont, text, x + themeAtlas->images[theme.checkOn].w + UI_SPACE, y + txOffset + h/2, 0xFFFFFFFF, ALIGN_LEFT | ALIGN_VCENTER); + ui_draw2d.DrawImage((*value) ? theme.checkOn : theme.checkOff, x, y+h/2, 1.0f, 0xFFFFFFFF, ALIGN_LEFT | ALIGN_VCENTER); + ui_draw2d.DrawTextShadow(theme.uiFont, text, x + themeAtlas->images[theme.checkOn].w + UI_SPACE, y + txOffset + h/2, 0xFFFFFFFF, ALIGN_LEFT | ALIGN_VCENTER); - uistate.lastwidget = id; - return clicked; + uistate.lastwidget = id; + return clicked; } void StringVectorListAdapter::drawItem(int item, int x, int y, int w, int h, bool selected) const { - ui_draw2d.DrawImage2GridH(theme.buttonImage, x, y, x + w); - ui_draw2d.DrawTextShadow(theme.uiFont, (*items_)[item].c_str(), x + UI_SPACE , y, 0xFFFFFFFF, ALIGN_LEFT | ALIGN_VCENTER); + ui_draw2d.DrawImage2GridH(theme.buttonImage, x, y, x + w); + ui_draw2d.DrawTextShadow(theme.uiFont, (*items_)[item].c_str(), x + UI_SPACE , y, 0xFFFFFFFF, ALIGN_LEFT | ALIGN_VCENTER); } -UIList::UIList() +UIList::UIList() : scrollY(0.0f), startDragY(0.0f), dragFinger(-1), selected(-1) { + movedDistanceY = 0.0f; } int UIList::Do(int id, int x, int y, int w, int h, UIListAdapter *adapter) { - int clicked = 0; + bool pointerDown = false; - for (int i = 0; i < MAX_POINTERS; i++) { - // Check whether the button should be hot - if (UIRegionHit(i, x, y, w, h, 0)) { - uistate.hotitem[i] = id; - if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) - uistate.activeitem[i] = id; - } + // UIList only cares about the first pointer for simplicity. + // Probably not much need to scroll one of these while dragging something + // else. + for (int i = 0; i < 1; i++) { + // Check for hover + if (UIRegionHit(i, x, y, w, h, 0)) { + uistate.hotitem[i] = id; + if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) { + // Mousedown + uistate.activeitem[i] = id; + } + } - // If button is hot and active, but mouse button is not - // down, the user must have clicked a list item (unless after the last item). - if (uistate.mousedown[i] == 0 && - uistate.hotitem[i] == id && - uistate.activeitem[i] == id && - selected != -1) { - clicked = 1; - } - } + // If button is hot and active, but mouse button is not + // down, the user must have clicked a list item (unless after the last item). + if (uistate.mousedown[i] == 0 && + uistate.hotitem[i] == id && + uistate.activeitem[i] == id && + selected != -1) { + clicked = 1; + } + } - // render items - int itemHeight = adapter->itemHeight(0); - int numItems = adapter->getCount(); - for (int i = 0; i < numItems; i++) { - int item_y = y + i * itemHeight - scrollY; + // render items + int itemHeight = adapter->itemHeight(0); + int numItems = adapter->getCount(); + for (int i = 0; i < numItems; i++) { + int item_y = y + i * itemHeight - scrollY; for (int k = 0; k < MAX_POINTERS; k++) { if (uistate.mousedown[k] && uistate.mouseframesdown[k] > 10 && - adapter->itemEnabled(i) && - item_y >= y - itemHeight && + adapter->itemEnabled(i) && + item_y >= y - itemHeight && item_y <= y + h && UIRegionHit(k, x, item_y, w, itemHeight, 0)) { printf("%i", item_y); selected = i; } } - adapter->drawItem(i, x, item_y, w, itemHeight, i == selected); - } - uistate.lastwidget = id; + adapter->drawItem(i, x, item_y, w, itemHeight, i == selected); + } + uistate.lastwidget = id; - // Otherwise, no clicky. - return clicked; + // Otherwise, no clicky. + return clicked; } /* @@ -311,7 +317,7 @@ int image; uint32_t bgColor; }; -struct SlideState +struct SlideState { float scroll; @@ -323,49 +329,49 @@ void UISlideChoice(int id, int y, const SlideItem *items, int numItems, SlideSta // TODO int UIHSlider(int id, int x, int y, int w, int max, int *value) { - // Calculate mouse cursor's relative y offset - int xpos = ((256 - 16) * *value) / max; + // Calculate mouse cursor's relative y offset + int xpos = ((256 - 16) * *value) / max; - for (int i = 0; i < MAX_POINTERS; i++) { - // Check for hotness - if (UIRegionHit(i, x+8, y+8, 16, 255, 0)) { - uistate.hotitem[i] = id; - if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) - uistate.activeitem[i] = id; - } + for (int i = 0; i < MAX_POINTERS; i++) { + // Check for hotness + if (UIRegionHit(i, x+8, y+8, 16, 255, 0)) { + uistate.hotitem[i] = id; + if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) + uistate.activeitem[i] = id; + } - // Update widget value - if (uistate.activeitem[i] == id) { - int mousepos = uistate.mousey[i] - (y + 8); - if (mousepos < 0) mousepos = 0; - if (mousepos > 255) mousepos = 255; - int v = (mousepos * max) / 255; - if (v != *value) { - *value = v; - return 1; - } - } - } - // Render the scrollbar - ui_draw2d.Rect(x, y, 32, 256+16, 0x777777); + // Update widget value + if (uistate.activeitem[i] == id) { + int mousepos = uistate.mousey[i] - (y + 8); + if (mousepos < 0) mousepos = 0; + if (mousepos > 255) mousepos = 255; + int v = (mousepos * max) / 255; + if (v != *value) { + *value = v; + return 1; + } + } + } + // Render the scrollbar + ui_draw2d.Rect(x, y, 32, 256+16, 0x777777); - ui_draw2d.Rect(x+8+xpos, y+8, 16, 16, 0xffffff); + ui_draw2d.Rect(x+8+xpos, y+8, 16, 16, 0xffffff); - return 0; + return 0; } /* // TODO int UIVSlider(int id, int x, int y, int h, int max, int *value) { - // Calculate mouse cursor's relative y offset - int ypos = ((256 - 16) * *value) / max; + // Calculate mouse cursor's relative y offset + int ypos = ((256 - 16) * *value) / max; - // Check for hotness - if (UIRegionHit(x+8, y+8, 16, 255, 0)) { - uistate.hotitem = id; - if (uistate.activeitem == 0 && uistate.mousedown) - uistate.activeitem = id; - } + // Check for hotness + if (UIRegionHit(x+8, y+8, 16, 255, 0)) { + uistate.hotitem = id; + if (uistate.activeitem == 0 && uistate.mousedown) + uistate.activeitem = id; + } // Update widget value if (uistate.activeitem == id) { int mousepos = uistate.mousey - (y + 8); @@ -377,12 +383,12 @@ int UIVSlider(int id, int x, int y, int h, int max, int *value) { return 1; } } - // Render the scrollbar - ui_draw2d.Rect(x, y, 32, 256+16, 0x777777); - - ui_draw2d.Rect(x+8, y+8 + ypos, 16, 16, 0xffffff); + // Render the scrollbar + ui_draw2d.Rect(x, y, 32, 256+16, 0x777777); - - return 0; + ui_draw2d.Rect(x+8, y+8 + ypos, 16, 16, 0xffffff); + + + return 0; } */ diff --git a/ui/ui.h b/ui/ui.h index 8e8bb52eaf..35089b0ff4 100644 --- a/ui/ui.h +++ b/ui/ui.h @@ -31,84 +31,84 @@ class LayoutManager { public: - virtual void GetPos(float *w, float *h, float *x, float *y) const = 0; + virtual void GetPos(float *w, float *h, float *x, float *y) const = 0; }; class Pos : public LayoutManager { public: - Pos(float x, float y) : x_(x), y_(y) {} - virtual void GetPos(float *w, float *h, float *x, float *y) const { - *x = x_; - *y = y_; - } + Pos(float x, float y) : x_(x), y_(y) {} + virtual void GetPos(float *w, float *h, float *x, float *y) const { + *x = x_; + *y = y_; + } private: - float x_; - float y_; + float x_; + float y_; }; class HLinear : public LayoutManager { public: - HLinear(float x, float y, float spacing = 2.0f) : x_(x), y_(y), spacing_(spacing) {} - virtual void GetPos(float *w, float *h, float *x, float *y) const { - *x = x_; - *y = y_; - x_ += *w + spacing_; - } - void Space(float x) { - x_ += x; - } + HLinear(float x, float y, float spacing = 2.0f) : x_(x), y_(y), spacing_(spacing) {} + virtual void GetPos(float *w, float *h, float *x, float *y) const { + *x = x_; + *y = y_; + x_ += *w + spacing_; + } + void Space(float x) { + x_ += x; + } private: - mutable float x_; - float y_; - float spacing_; + mutable float x_; + float y_; + float spacing_; }; class VLinear : public LayoutManager { public: - VLinear(float x, float y, float spacing = 2.0f) : x_(x), y_(y), spacing_(spacing) {} - virtual void GetPos(float *w, float *h, float *x, float *y) const { - *x = x_; - *y = y_; - y_ += *h + spacing_; - } + VLinear(float x, float y, float spacing = 2.0f) : x_(x), y_(y), spacing_(spacing) {} + virtual void GetPos(float *w, float *h, float *x, float *y) const { + *x = x_; + *y = y_; + y_ += *h + spacing_; + } private: - float x_; - mutable float y_; - float spacing_; + float x_; + mutable float y_; + float spacing_; }; #ifndef MAX_POINTERS #define MAX_POINTERS 8 #endif -// Mouse out of habit, applies just as well to touch events. -// UI does not yet support multitouch. +// "Mouse" out of habit, applies just as well to touch events. +// TODO: Change to "pointer" // This struct is zeroed on init, so should be valid at that state. // Never inherit from this. struct UIState { - int mousex[MAX_POINTERS]; - int mousey[MAX_POINTERS]; - bool mousedown[MAX_POINTERS]; - bool mousepressed[MAX_POINTERS]; - short mouseframesdown[MAX_POINTERS]; + int mousex[MAX_POINTERS]; + int mousey[MAX_POINTERS]; + bool mousedown[MAX_POINTERS]; + bool mousepressed[MAX_POINTERS]; + short mouseframesdown[MAX_POINTERS]; - int mouseStartX[MAX_POINTERS]; - int mouseStartY[MAX_POINTERS]; + int mouseStartX[MAX_POINTERS]; + int mouseStartY[MAX_POINTERS]; - int hotitem[MAX_POINTERS]; - int activeitem[MAX_POINTERS]; + int hotitem[MAX_POINTERS]; + int activeitem[MAX_POINTERS]; - // keyboard focus, not currently used - int kbdwidget; - int lastwidget; + // keyboard focus, not currently used + int kbdwidget; + int lastwidget; - // Used by controls that need to keep track of the initial value for drags, for example. - // Should probably be indexed by finger - would be neat to be able to move two knobs at the same time. - float tempfloat; + // Used by controls that need to keep track of the initial value for drags, for example. + // Should probably be indexed by finger - would be neat to be able to move two knobs at the same time. + float tempfloat; - int ui_tick; + int ui_tick; }; // This needs to be extern so that additional UI controls can be developed outside this file. @@ -119,15 +119,15 @@ struct Atlas; // This is the drawbuffer used for UI. Remember to flush it at the end of the frame. // TODO: One should probably pass it in through UIInit. extern DrawBuffer ui_draw2d; -extern DrawBuffer ui_draw2d_front; // for things that need to be on top of the rest +extern DrawBuffer ui_draw2d_front; // for things that need to be on top of the rest struct UITheme { - int uiFont; - int uiFontSmall; - int uiFontSmaller; - int buttonImage; - int checkOn; - int checkOff; + int uiFont; + int uiFontSmall; + int uiFontSmaller; + int buttonImage; + int checkOn; + int checkOff; }; // The atlas needs to stick around, the theme is copied. @@ -143,32 +143,32 @@ const int LARGE_BUTTON_WIDTH = 192; const int BUTTON_HEIGHT = 72; struct SlideItem { - const char *text; - int image; - uint32_t bgColor; + const char *text; + int image; + uint32_t bgColor; }; struct UISlideState { - float scroll; + float scroll; }; // Implement this interface to style your lists class UIListAdapter { public: - virtual size_t getCount() const = 0; - virtual void drawItem(int item, int x, int y, int w, int h, bool active) const = 0; - virtual float itemHeight(int itemIndex) const { return 64; } - virtual bool itemEnabled(int itemIndex) const { return true; } + virtual size_t getCount() const = 0; + virtual void drawItem(int item, int x, int y, int w, int h, bool active) const = 0; + virtual float itemHeight(int itemIndex) const { return 64; } + virtual bool itemEnabled(int itemIndex) const { return true; } }; class StringVectorListAdapter : public UIListAdapter { public: - StringVectorListAdapter(const std::vector *items) : items_(items) {} - virtual size_t getCount() const { return items_->size(); } - virtual void drawItem(int item, int x, int y, int w, int h, bool active) const; + StringVectorListAdapter(const std::vector *items) : items_(items) {} + virtual size_t getCount() const { return items_->size(); } + virtual void drawItem(int item, int x, int y, int w, int h, bool active) const; private: - const std::vector *items_; + const std::vector *items_; }; @@ -185,7 +185,7 @@ void UIReset(); // Returns 1 if clicked int UIButton(int id, const LayoutManager &layout, float w, const char *text, int button_align); -int UIImageButton(int id, const LayoutManager &layout, float w, int image_id, int button_align); // uses current UI atlas for fetching images. +int UIImageButton(int id, const LayoutManager &layout, float w, int image_id, int button_align); // uses current UI atlas for fetching images. // Returns 1 if clicked, puts the value in *value (where it also gets the current state). int UICheckBox(int id, int x, int y, const char *text, int align, bool *value); @@ -205,17 +205,23 @@ void UISlideChoice(int id, int y, const SlideItem *items, int numItems, UISlideS class UIList { - public: - UIList(); - float scrollY; - float startDragY; - int dragFinger; - int selected; - // List view. - // return -1 = no selection - int Do(int id, int x, int y, int w, int h, UIListAdapter *adapter); - private: - DISALLOW_COPY_AND_ASSIGN(UIList); +public: + UIList(); + + bool scrolling; + int activePointer; + float scrollY; + float startDragY; + float movedDistanceY; + + int dragFinger; + int selected; + // List view. + // return -1 = no selection + int Do(int id, int x, int y, int w, int h, UIListAdapter *adapter); + +private: + DISALLOW_COPY_AND_ASSIGN(UIList); }; // Call at end of frame. diff --git a/ui/virtual_input.cpp b/ui/virtual_input.cpp index bb4b443507..953073f83e 100644 --- a/ui/virtual_input.cpp +++ b/ui/virtual_input.cpp @@ -10,13 +10,13 @@ TouchButton::TouchButton(const Atlas *atlas, int imageIndex, int overlayImageInd memset(pointerDown, 0, sizeof(pointerDown)); w_ = atlas_->images[imageIndex_].w; h_ = atlas_->images[imageIndex_].h; - rotationAngle_ = (float)rotationAngle * 3.1415927 / 180.0f; - isDown_ = false; + rotationAngle_ = (float)rotationAngle * 3.1415927 / 180.0f; + isDown_ = false; } void TouchButton::update(InputState &input_state) { - isDown_ = false; + isDown_ = false; for (int i = 0; i < MAX_POINTERS; i++) { if (input_state.pointer_down[i] && isInside(input_state.pointer_x[i], input_state.pointer_y[i])) isDown_ = true; @@ -31,12 +31,12 @@ void TouchButton::update(InputState &input_state) void TouchButton::draw(DrawBuffer &db) { - uint32_t color = 0xAAFFFFFF; - float scale = 1.0f; - if (isDown_) { - color = 0xFFFFFFFF; - scale = 2.0f; - } + uint32_t color = 0xAAFFFFFF; + float scale = 1.0f; + if (isDown_) { + color = 0xFFFFFFFF; + scale = 2.0f; + } db.DrawImageRotated(imageIndex_, x_ + w_/2, y_ + h_/2, scale, rotationAngle_, color); if (overlayImageIndex_ != -1) db.DrawImageRotated(overlayImageIndex_, x_ + w_/2, y_ + h_/2, scale, rotationAngle_, color); diff --git a/ui/virtual_input.h b/ui/virtual_input.h index 765bdccb55..ee336ab6b5 100644 --- a/ui/virtual_input.h +++ b/ui/virtual_input.h @@ -37,16 +37,16 @@ private: float w_; float h_; - bool isDown_; + bool isDown_; // TODO: simplify into flags. bool pointerDown[MAX_POINTERS]; }; -// Multi-touch enabled virtual joystick +// Multi-touch enabled virtual joystick // (any finger will work, simultaneously with other virtual button/stick actions). -class TouchStick +class TouchStick { public: TouchStick(const Atlas *atlas, int bgImageIndex, int stickImageIndex, int stick);