void TextEdit::Draw(UIContext &dc) { dc.PushScissor(bounds_); dc.SetFontStyle(dc.theme->uiFont); dc.FillRect(HasFocus() ? UI::Drawable(0x80000000) : UI::Drawable(0x30000000), bounds_); float textX = bounds_.x; float w, h; // Hack to find the caret position. Might want to find a better way... dc.MeasureTextCount(dc.theme->uiFont, text_.c_str(), caret_, &w, &h, ALIGN_VCENTER | ALIGN_LEFT); float caretX = w; if (caretX > bounds_.w) { // Scroll text to the left if the caret won't fit. Not ideal but looks better than not scrolling it. textX -= caretX - bounds_.w; } caretX += textX; Bounds textBounds = bounds_; textBounds.x = textX; if (text_.empty()) { if (placeholderText_.size()) { dc.DrawTextRect(placeholderText_.c_str(), bounds_, 0x50FFFFFF, ALIGN_CENTER); } } else { dc.DrawTextRect(text_.c_str(), textBounds, 0xFFFFFFFF, ALIGN_VCENTER | ALIGN_LEFT); } dc.FillRect(UI::Drawable(0xFFFFFFFF), Bounds(caretX - 1, bounds_.y + 2, 3, bounds_.h - 4)); dc.PopScissor(); }
void TextView::Draw(UIContext &dc) { bool clip = false; if (measuredWidth_ > bounds_.w || measuredHeight_ > bounds_.h) clip = true; if (bounds_.w < 0 || bounds_.h < 0 || !clip_) { // We have a layout but, but try not to screw up rendering. // TODO: Fix properly. clip = false; } if (clip) { dc.Flush(); dc.PushScissor(bounds_); } // In case it's been made focusable. if (HasFocus()) { UI::Style style = dc.theme->itemFocusedStyle; style.background.color &= 0x7fffffff; dc.FillRect(style.background, bounds_); } dc.SetFontStyle(small_ ? dc.theme->uiFontSmall : dc.theme->uiFont); if (shadow_) { uint32_t shadowColor = 0x80000000; dc.DrawTextRect(text_.c_str(), bounds_, shadowColor, textAlign_); } dc.DrawTextRect(text_.c_str(), bounds_, textColor_, textAlign_); if (clip) { dc.PopScissor(); } }
void Button::Draw(UIContext &dc) { Style style = dc.theme->buttonStyle; if (HasFocus()) style = dc.theme->buttonFocusedStyle; if (down_) style = dc.theme->buttonDownStyle; if (!IsEnabled()) style = dc.theme->buttonDisabledStyle; // dc.Draw()->DrawImage4Grid(style.image, bounds_.x, bounds_.y, bounds_.x2(), bounds_.y2(), style.bgColor); dc.FillRect(style.background, bounds_); float tw, th; dc.MeasureText(dc.theme->uiFont, text_.c_str(), &tw, &th); if (tw > bounds_.w || imageID_ != -1) { dc.PushScissor(bounds_); } dc.SetFontStyle(dc.theme->uiFont); if (imageID_ != -1 && text_.empty()) { dc.Draw()->DrawImage(imageID_, bounds_.centerX(), bounds_.centerY(), 1.0f, 0xFFFFFFFF, ALIGN_CENTER); } else if (!text_.empty()) { dc.DrawText(text_.c_str(), bounds_.centerX(), bounds_.centerY(), style.fgColor, ALIGN_CENTER); if (imageID_ != -1) { const AtlasImage &img = dc.Draw()->GetAtlas()->images[imageID_]; dc.Draw()->DrawImage(imageID_, bounds_.centerX() - tw / 2 - 5 - img.w/2, bounds_.centerY(), 1.0f, 0xFFFFFFFF, ALIGN_CENTER); } } if (tw > bounds_.w || imageID_ != -1) { dc.PopScissor(); } }
void PopupSliderChoiceFloat::Draw(UIContext &dc) { Choice::Draw(dc); char temp[32]; sprintf(temp, "%2.2f", *value_); dc.SetFontStyle(dc.theme->uiFont); dc.DrawText(temp, bounds_.x2() - 12, bounds_.centerY(), 0xFFFFFFFF, ALIGN_RIGHT | ALIGN_VCENTER); }
void ChoiceWithValueDisplay::Draw(UIContext &dc) { Style style = dc.theme->itemStyle; if (!IsEnabled()) { style = dc.theme->itemDisabledStyle; } int paddingX = 12; dc.SetFontStyle(dc.theme->uiFont); I18NCategory *category = GetI18NCategory(category_); std::ostringstream valueText; if (sValue_ != nullptr) { if (category) valueText << category->T(*sValue_); else valueText << *sValue_; } else if (iValue_ != nullptr) { valueText << *iValue_; } float ignore; dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, valueText.str().c_str(), &textPadding_.right, &ignore, ALIGN_RIGHT | ALIGN_VCENTER); textPadding_.right += paddingX; Choice::Draw(dc); dc.DrawText(valueText.str().c_str(), bounds_.x2() - paddingX, bounds_.centerY(), style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER); }
void ProgressBar::Draw(UIContext &dc) { char temp[32]; sprintf(temp, "%i%%", (int)(progress_ * 100.0f)); dc.Draw()->DrawImageStretch(dc.theme->whiteImage, bounds_.x, bounds_.y, bounds_.x + bounds_.w * progress_, bounds_.y2(), 0xc0c0c0c0); dc.SetFontStyle(dc.theme->uiFont); dc.DrawTextRect(temp, bounds_, 0xFFFFFFFF, ALIGN_CENTER); }
void OnScreenMessagesView::Draw(UIContext &dc) { // First, clean out old messages. osm.Lock(); osm.Clean(); // Get height float w, h; dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, "Wg", &w, &h); float y = 10.0f; // Then draw them all. const std::list<OnScreenMessages::Message> &messages = osm.Messages(); for (auto iter = messages.begin(); iter != messages.end(); ++iter) { float alpha = (iter->endTime - time_now_d()) * 4.0f; if (alpha > 1.0) alpha = 1.0f; if (alpha < 0.0) alpha = 0.0f; // Messages that are wider than the screen are left-aligned instead of centered. float tw, th; dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, iter->text.c_str(), &tw, &th); float x = bounds_.centerX(); int align = ALIGN_TOP | ALIGN_HCENTER; if (tw > bounds_.w) { align = ALIGN_TOP | ALIGN_LEFT; x = 2; } dc.SetFontStyle(dc.theme->uiFont); dc.DrawTextShadow(iter->text.c_str(), x, y, colorAlpha(iter->color, alpha), align); y += h; } osm.Unlock(); }
void PopupHeader::Draw(UIContext &dc) { const float paddingHorizontal = 12; const float availableWidth = bounds_.w - paddingHorizontal * 2; float tw, th; dc.SetFontStyle(dc.theme->uiFont); dc.MeasureText(dc.GetFontStyle(), 1.0f, 1.0f, text_.c_str(), &tw, &th, 0); float sineWidth = std::max(0.0f, (tw - availableWidth)) / 2.0f; float tx = paddingHorizontal; if (availableWidth < tw) { float overageRatio = 1.5f * availableWidth * 1.0f / tw; tx -= (1.0f + sin(time_now_d() * overageRatio)) * sineWidth; Bounds tb = bounds_; tb.x = bounds_.x + paddingHorizontal; tb.w = bounds_.w - paddingHorizontal * 2; dc.PushScissor(tb); } dc.DrawText(text_.c_str(), bounds_.x + tx, bounds_.centerY(), dc.theme->popupTitle.fgColor, ALIGN_LEFT | ALIGN_VCENTER); dc.Draw()->DrawImageStretch(dc.theme->whiteImage, bounds_.x, bounds_.y2()-2, bounds_.x2(), bounds_.y2(), dc.theme->popupTitle.fgColor); if (availableWidth < tw) { dc.PopScissor(); } }
void Choice::Draw(UIContext &dc) { if (!IsSticky()) { ClickableItem::Draw(dc); } else { Style style = dc.theme->itemStyle; if (down_) { style = dc.theme->itemDownStyle; } if (HasFocus()) { style = dc.theme->itemFocusedStyle; } dc.FillRect(style.background, bounds_); } Style style = dc.theme->itemStyle; if (!IsEnabled()) style = dc.theme->itemDisabledStyle; if (atlasImage_ != -1) { dc.Draw()->DrawImage(atlasImage_, bounds_.centerX(), bounds_.centerY(), 1.0f, style.fgColor, ALIGN_CENTER); } else { int paddingX = 12; dc.SetFontStyle(dc.theme->uiFont); dc.DrawText(text_.c_str(), bounds_.x + paddingX, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); } if (selected_) { dc.Draw()->DrawImage(dc.theme->checkOn, bounds_.x2() - 40, bounds_.centerY(), 1.0f, style.fgColor, ALIGN_CENTER); } }
void InfoItem::Draw(UIContext &dc) { Item::Draw(dc); int paddingX = 12; dc.SetFontStyle(dc.theme->uiFont); dc.DrawText(text_.c_str(), bounds_.x + paddingX, bounds_.centerY(), 0xFFFFFFFF, ALIGN_VCENTER); dc.DrawText(rightText_.c_str(), bounds_.x2() - paddingX, bounds_.centerY(), 0xFFFFFFFF, ALIGN_VCENTER | ALIGN_RIGHT); // dc.Draw()->DrawImageStretch(dc.theme->whiteImage, bounds_.x, bounds_.y, bounds_.x2(), bounds_.y + 2, dc.theme->itemDownStyle.bgColor); }
void PopupTextInputChoice::Draw(UIContext &dc) { Style style = dc.theme->itemStyle; if (!IsEnabled()) { style = dc.theme->itemDisabledStyle; } Choice::Draw(dc); dc.SetFontStyle(dc.theme->uiFont); dc.DrawText(value_->c_str(), bounds_.x2() - 12, bounds_.centerY(), style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER); }
void PopupMultiChoice::Draw(UIContext &dc) { Style style = dc.theme->itemStyle; if (!IsEnabled()) { style = dc.theme->itemDisabledStyle; } Choice::Draw(dc); int paddingX = 12; dc.SetFontStyle(dc.theme->uiFont); dc.DrawText(valueText_.c_str(), bounds_.x2() - paddingX, bounds_.centerY(), style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER); }
void SliderFloat::Draw(UIContext &dc) { bool focus = HasFocus(); float knobX = (*value_ - minValue_) / (maxValue_ - minValue_) * (bounds_.w - paddingLeft_ - paddingRight_) + (bounds_.x + paddingLeft_); dc.FillRect(Drawable(focus ? dc.theme->popupTitle.fgColor : 0xFFFFFFFF), Bounds(bounds_.x + paddingLeft_, bounds_.centerY() - 2, knobX - (bounds_.x + paddingLeft_), 4)); dc.FillRect(Drawable(0xFF808080), Bounds(knobX, bounds_.centerY() - 2, (bounds_.x + bounds_.w - paddingRight_ - knobX), 4)); dc.Draw()->DrawImage(dc.theme->sliderKnob, knobX, bounds_.centerY(), 1.0f, 0xFFFFFFFF, ALIGN_CENTER); char temp[64]; sprintf(temp, "%0.2f", *value_); dc.SetFontStyle(dc.theme->uiFont); dc.DrawText(temp, bounds_.x2() - 22, bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER); }
void PopupSliderChoiceFloat::Draw(UIContext &dc) { Style style = dc.theme->itemStyle; if (!IsEnabled()) { style = dc.theme->itemDisabledStyle; } Choice::Draw(dc); char temp[32]; sprintf(temp, "%2.2f", *value_); dc.SetFontStyle(dc.theme->uiFont); dc.DrawText(temp, bounds_.x2() - 12, bounds_.centerY(), style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER); }
void InfoItem::Draw(UIContext &dc) { Item::Draw(dc); if (HasFocus()) { UI::Style style = dc.theme->itemFocusedStyle; style.background.color &= 0x7fffffff; dc.FillRect(style.background, bounds_); } int paddingX = 12; dc.SetFontStyle(dc.theme->uiFont); dc.DrawText(text_.c_str(), bounds_.x + paddingX, bounds_.centerY(), 0xFFFFFFFF, ALIGN_VCENTER); dc.DrawText(rightText_.c_str(), bounds_.x2() - paddingX, bounds_.centerY(), 0xFFFFFFFF, ALIGN_VCENTER | ALIGN_RIGHT); // dc.Draw()->DrawImageStretch(dc.theme->whiteImage, bounds_.x, bounds_.y, bounds_.x2(), bounds_.y + 2, dc.theme->itemDownStyle.bgColor); }
void CheckBox::Draw(UIContext &dc) { ClickableItem::Draw(dc); int paddingX = 12; int image = *toggle_ ? dc.theme->checkOn : dc.theme->checkOff; Style style = dc.theme->itemStyle; if (!IsEnabled()) style = dc.theme->itemDisabledStyle; dc.SetFontStyle(dc.theme->uiFont); dc.DrawText(text_.c_str(), bounds_.x + paddingX, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); dc.Draw()->DrawImage(image, bounds_.x2() - paddingX, bounds_.centerY(), 1.0f, style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER); }
void Choice::Draw(UIContext &dc) { if (!IsSticky()) { ClickableItem::Draw(dc); } else { Style style = dc.theme->itemStyle; if (highlighted_) { style = dc.theme->itemHighlightedStyle; } if (down_) { style = dc.theme->itemDownStyle; } if (HasFocus()) { style = dc.theme->itemFocusedStyle; } dc.FillRect(style.background, bounds_); } Style style = dc.theme->itemStyle; if (!IsEnabled()) { style = dc.theme->itemDisabledStyle; } if (atlasImage_ != -1) { dc.Draw()->DrawImage(atlasImage_, bounds_.centerX(), bounds_.centerY(), 1.0f, style.fgColor, ALIGN_CENTER); } else { dc.SetFontStyle(dc.theme->uiFont); const int paddingX = 12; const float availWidth = bounds_.w - paddingX * 2 - textPadding_.horiz(); float scale = CalculateTextScale(dc, availWidth); dc.SetFontScale(scale, scale); if (centered_) { dc.DrawTextRect(text_.c_str(), bounds_, style.fgColor, ALIGN_CENTER | FLAG_WRAP_TEXT); } else { if (iconImage_ != -1) { dc.Draw()->DrawImage(iconImage_, bounds_.x2() - 32 - paddingX, bounds_.centerY(), 0.5f, style.fgColor, ALIGN_CENTER); } Bounds textBounds(bounds_.x + paddingX + textPadding_.left, bounds_.y, availWidth, bounds_.h); dc.DrawTextRect(text_.c_str(), textBounds, style.fgColor, ALIGN_VCENTER | FLAG_WRAP_TEXT); } dc.SetFontScale(1.0f, 1.0f); } if (selected_) { dc.Draw()->DrawImage(dc.theme->checkOn, bounds_.x2() - 40, bounds_.centerY(), 1.0f, style.fgColor, ALIGN_CENTER); } }
void PopupTextInputChoice::Draw(UIContext &dc) { Style style = dc.theme->itemStyle; if (!IsEnabled()) { style = dc.theme->itemDisabledStyle; } int paddingX = 12; dc.SetFontStyle(dc.theme->uiFont); float ignore; dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, value_->c_str(), &textPadding_.right, &ignore, ALIGN_RIGHT | ALIGN_VCENTER); textPadding_.right += paddingX; Choice::Draw(dc); dc.DrawText(value_->c_str(), bounds_.x2() - 12, bounds_.centerY(), style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER); }
void PopupSliderChoiceFloat::Draw(UIContext &dc) { Style style = dc.theme->itemStyle; if (!IsEnabled()) { style = dc.theme->itemDisabledStyle; } Choice::Draw(dc); char temp[32]; if (zeroLabel_.size() && *value_ == 0.0f) { strcpy(temp, zeroLabel_.c_str()); } else { sprintf(temp, fmt_, *value_); } dc.SetFontStyle(dc.theme->uiFont); dc.DrawText(temp, bounds_.x2() - 12, bounds_.centerY(), style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER); }
void Slider::Draw(UIContext &dc) { bool focus = HasFocus(); uint32_t linecolor = dc.theme->popupTitle.fgColor; uint32_t knobcolor = (down_ || focus) ? dc.theme->popupTitle.fgColor : 0xFFFFFFFF; float knobX = ((float)(*value_) - minValue_) / (maxValue_ - minValue_) * (bounds_.w - paddingLeft_ - paddingRight_) + (bounds_.x + paddingLeft_); dc.FillRect(Drawable(linecolor), Bounds(bounds_.x + paddingLeft_, bounds_.centerY() - 2, knobX - (bounds_.x + paddingLeft_), 4)); dc.FillRect(Drawable(0xFF808080), Bounds(knobX, bounds_.centerY() - 2, (bounds_.x + bounds_.w - paddingRight_ - knobX), 4)); dc.Draw()->DrawImage(dc.theme->sliderKnob, knobX, bounds_.centerY(), 1.0f, knobcolor, ALIGN_CENTER); char temp[64]; if (showPercent_) sprintf(temp, "%i%%", *value_); else sprintf(temp, "%i", *value_); dc.SetFontStyle(dc.theme->uiFont); dc.DrawText(temp, bounds_.x2() - 22, bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER); }
void ChoiceWithValueDisplay::Draw(UIContext &dc) { Style style = dc.theme->itemStyle; std::ostringstream valueText; Choice::Draw(dc); dc.SetFontStyle(dc.theme->uiFont); if (sValue_ != nullptr) { if (category_) valueText << category_->T(*sValue_); else valueText << *sValue_; } else if (iValue_ != nullptr) { valueText << *iValue_; } dc.DrawText(valueText.str().c_str(), bounds_.x2() - 12, bounds_.centerY(), style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER); }
void Button::Draw(UIContext &dc) { Style style = dc.theme->buttonStyle; if (HasFocus()) style = dc.theme->buttonFocusedStyle; if (down_) style = dc.theme->buttonDownStyle; if (!enabled_) style = dc.theme->buttonDisabledStyle; // dc.Draw()->DrawImage4Grid(style.image, bounds_.x, bounds_.y, bounds_.x2(), bounds_.y2(), style.bgColor); dc.FillRect(style.background, bounds_); float tw, th; dc.MeasureText(dc.theme->uiFont, text_.c_str(), &tw, &th); if (tw > bounds_.w) { dc.PushScissor(bounds_); } dc.SetFontStyle(dc.theme->uiFont); dc.DrawText(text_.c_str(), bounds_.centerX(), bounds_.centerY(), style.fgColor, ALIGN_CENTER); if (tw > bounds_.w) { dc.PopScissor(); } }
void PopupSliderChoiceFloat::Draw(UIContext &dc) { Style style = dc.theme->itemStyle; if (!IsEnabled()) { style = dc.theme->itemDisabledStyle; } int paddingX = 12; dc.SetFontStyle(dc.theme->uiFont); char temp[32]; if (zeroLabel_.size() && *value_ == 0.0f) { strcpy(temp, zeroLabel_.c_str()); } else { sprintf(temp, fmt_, *value_); } float ignore; dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, temp, &textPadding_.right, &ignore, ALIGN_RIGHT | ALIGN_VCENTER); textPadding_.right += paddingX; Choice::Draw(dc); dc.DrawText(temp, bounds_.x2() - paddingX, bounds_.centerY(), style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER); }
void CheckBox::Draw(UIContext &dc) { Style style = dc.theme->itemStyle; if (!IsEnabled()) style = dc.theme->itemDisabledStyle; dc.SetFontStyle(dc.theme->uiFont); ClickableItem::Draw(dc); int image = *toggle_ ? dc.theme->checkOn : dc.theme->checkOff; float imageW, imageH; dc.Draw()->MeasureImage(image, &imageW, &imageH); const int paddingX = 12; // Padding right of the checkbox image too. const float availWidth = bounds_.w - paddingX * 2 - imageW - paddingX; float scale = CalculateTextScale(dc, availWidth); dc.SetFontScale(scale, scale); Bounds textBounds(bounds_.x + paddingX, bounds_.y, availWidth, bounds_.h); dc.DrawTextRect(text_.c_str(), textBounds, style.fgColor, ALIGN_VCENTER | FLAG_WRAP_TEXT); dc.Draw()->DrawImage(image, bounds_.x2() - paddingX, bounds_.centerY(), 1.0f, style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER); dc.SetFontScale(1.0f, 1.0f); }
void PopupMultiChoice::Draw(UIContext &dc) { Choice::Draw(dc); int paddingX = 12; dc.SetFontStyle(dc.theme->uiFont); dc.DrawText(valueText_.c_str(), bounds_.x2() - paddingX, bounds_.centerY(), 0xFFFFFFFF, ALIGN_RIGHT | ALIGN_VCENTER); }
void PopupHeader::Draw(UIContext &dc) { dc.SetFontStyle(dc.theme->uiFont); dc.DrawText(text_.c_str(), bounds_.x + 12, bounds_.centerY(), dc.theme->popupTitle.fgColor, ALIGN_LEFT | ALIGN_VCENTER); dc.Draw()->DrawImageStretch(dc.theme->whiteImage, bounds_.x, bounds_.y2()-2, bounds_.x2(), bounds_.y2(), dc.theme->popupTitle.fgColor); }
void ItemHeader::Draw(UIContext &dc) { dc.SetFontStyle(dc.theme->uiFontSmall); dc.DrawText(text_.c_str(), bounds_.x + 4, bounds_.centerY(), 0xFFFFFFFF, ALIGN_LEFT | ALIGN_VCENTER); dc.Draw()->DrawImageStretch(dc.theme->whiteImage, bounds_.x, bounds_.y2()-2, bounds_.x2(), bounds_.y2(), 0xFFFFFFFF); }
void SavedataButton::Draw(UIContext &dc) { GameInfo *ginfo = g_gameInfoCache->GetInfo(dc.GetDrawContext(), savePath_, GAMEINFO_WANTSIZE); Draw::Texture *texture = 0; u32 color = 0, shadowColor = 0; using namespace UI; if (ginfo->icon.texture) { texture = ginfo->icon.texture->GetTexture(); } int x = bounds_.x; int y = bounds_.y; int w = 144; int h = bounds_.h; UI::Style style = dc.theme->itemStyle; if (down_) style = dc.theme->itemDownStyle; h = bounds_.h; if (HasFocus()) style = down_ ? dc.theme->itemDownStyle : dc.theme->itemFocusedStyle; Drawable bg = style.background; dc.Draw()->Flush(); dc.RebindTexture(); dc.FillRect(bg, bounds_); dc.Draw()->Flush(); if (texture) { color = whiteAlpha(ease((time_now_d() - ginfo->icon.timeLoaded) * 2)); shadowColor = blackAlpha(ease((time_now_d() - ginfo->icon.timeLoaded) * 2)); float tw = texture->Width(); float th = texture->Height(); // Adjust position so we don't stretch the image vertically or horizontally. // TODO: Add a param to specify fit? The below assumes it's never too wide. float nw = h * tw / th; x += (w - nw) / 2.0f; w = nw; } int txOffset = down_ ? 4 : 0; txOffset = 0; Bounds overlayBounds = bounds_; // Render button int dropsize = 10; if (texture) { if (txOffset) { dropsize = 3; y += txOffset * 2; overlayBounds.y += txOffset * 2; } if (HasFocus()) { dc.Draw()->Flush(); dc.RebindTexture(); float pulse = sinf(time_now() * 7.0f) * 0.25 + 0.8; dc.Draw()->DrawImage4Grid(dc.theme->dropShadow4Grid, x - dropsize*1.5f, y - dropsize*1.5f, x + w + dropsize*1.5f, y + h + dropsize*1.5f, alphaMul(color, pulse), 1.0f); dc.Draw()->Flush(); } else { dc.Draw()->Flush(); dc.RebindTexture(); dc.Draw()->DrawImage4Grid(dc.theme->dropShadow4Grid, x - dropsize, y - dropsize*0.5f, x + w + dropsize, y + h + dropsize*1.5, alphaMul(shadowColor, 0.5f), 1.0f); dc.Draw()->Flush(); } } if (texture) { dc.Draw()->Flush(); dc.GetDrawContext()->BindTexture(0, texture); dc.Draw()->DrawTexRect(x, y, x + w, y + h, 0, 0, 1, 1, color); dc.Draw()->Flush(); } dc.Draw()->Flush(); dc.RebindTexture(); dc.SetFontStyle(dc.theme->uiFont); float tw, th; dc.Draw()->Flush(); dc.PushScissor(bounds_); const std::string currentTitle = ginfo->GetTitle(); if (!currentTitle.empty()) { title_ = CleanSaveString(currentTitle); } if (subtitle_.empty() && ginfo->gameSize > 0) { std::string savedata_title = ginfo->paramSFO.GetValueString("SAVEDATA_TITLE"); subtitle_ = CleanSaveString(savedata_title) + StringFromFormat(" (%d kB)", ginfo->gameSize / 1024); } dc.MeasureText(dc.GetFontStyle(), 1.0f, 1.0f, title_.c_str(), &tw, &th, 0); int availableWidth = bounds_.w - 150; float sineWidth = std::max(0.0f, (tw - availableWidth)) / 2.0f; float tx = 150; if (availableWidth < tw) { float overageRatio = 1.5f * availableWidth * 1.0f / tw; tx -= (1.0f + sin(time_now_d() * overageRatio)) * sineWidth; Bounds tb = bounds_; tb.x = bounds_.x + 150; tb.w = bounds_.w - 150; dc.PushScissor(tb); } dc.DrawText(title_.c_str(), bounds_.x + tx, bounds_.y + 4, style.fgColor, ALIGN_TOPLEFT); dc.SetFontScale(0.6f, 0.6f); dc.DrawText(subtitle_.c_str(), bounds_.x + tx, bounds_.y2() - 7, style.fgColor, ALIGN_BOTTOM); dc.SetFontScale(1.0f, 1.0f); if (availableWidth < tw) { dc.PopScissor(); } dc.Draw()->Flush(); dc.PopScissor(); dc.RebindTexture(); }
void DrawProfile(UIContext &ui) { #ifdef USE_PROFILER int numCategories = Profiler_GetNumCategories(); int historyLength = Profiler_GetHistoryLength(); ui.SetFontStyle(ui.theme->uiFont); static float lastMaxVal = 1.0f / 60.0f; float legendMinVal = lastMaxVal * (1.0f / 120.0f); std::vector<float> history; std::vector<ProfileCatStatus> catStatus; history.resize(historyLength); catStatus.resize(numCategories); float rowH = 30.0f; float legendHeight = 0.0f; float legendWidth = 80.0f; for (int i = 0; i < numCategories; i++) { const char *name = Profiler_GetCategoryName(i); if (!strcmp(name, "timing")) { catStatus[i] = PROFILE_CAT_IGNORE; continue; } Profiler_GetHistory(i, &history[0], historyLength); catStatus[i] = PROFILE_CAT_NOLEGEND; for (int j = 0; j < historyLength; ++j) { if (history[j] > legendMinVal) { catStatus[i] = PROFILE_CAT_VISIBLE; break; } } // So they don't move horizontally, we always measure. float w = 0.0f, h = 0.0f; ui.MeasureText(ui.GetFontStyle(), name, &w, &h); if (w > legendWidth) { legendWidth = w; } legendHeight += rowH; } legendWidth += 20.0f; float legendStartY = legendHeight > ui.GetBounds().centerY() ? ui.GetBounds().y2() - legendHeight : ui.GetBounds().centerY(); float legendStartX = ui.GetBounds().x2() - std::min(legendWidth, 200.0f); const uint32_t opacity = 140 << 24; int legendNum = 0; for (int i = 0; i < numCategories; i++) { const char *name = Profiler_GetCategoryName(i); uint32_t color = nice_colors[i % ARRAY_SIZE(nice_colors)]; if (catStatus[i] == PROFILE_CAT_VISIBLE) { float y = legendStartY + legendNum++ * rowH; ui.FillRect(UI::Drawable(opacity | color), Bounds(legendStartX, y, rowH - 2, rowH - 2)); ui.DrawTextShadow(name, legendStartX + rowH + 2, y, 0xFFFFFFFF, ALIGN_VBASELINE); } } float graphWidth = ui.GetBounds().x2() - legendWidth - 20.0f; float graphHeight = ui.GetBounds().h * 0.8f; float dx = graphWidth / historyLength; /* ui.Flush(); ui.BeginNoTex(); */ bool area = true; float minVal = 0.0f; float maxVal = lastMaxVal; // TODO - adjust to frame length if (maxVal < 0.001f) maxVal = 0.001f; if (maxVal > 1.0f / 15.0f) maxVal = 1.0f / 15.0f; float scale = (graphHeight) / (maxVal - minVal); float y_60th = ui.GetBounds().y2() - 10 - (1.0f / 60.0f) * scale; float y_1ms = ui.GetBounds().y2() - 10 - (1.0f / 1000.0f) * scale; ui.FillRect(UI::Drawable(0x80FFFF00), Bounds(0, y_60th, graphWidth, 2)); ui.FillRect(UI::Drawable(0x80FFFF00), Bounds(0, y_1ms, graphWidth, 2)); ui.DrawTextShadow("1/60s", 5, y_60th, 0x80FFFF00); ui.DrawTextShadow("1ms", 5, y_1ms, 0x80FFFF00); std::vector<float> total; total.resize(historyLength); maxVal = 0.0f; float maxTotal = 0.0f; for (int i = 0; i < numCategories; i++) { if (catStatus[i] == PROFILE_CAT_IGNORE) { continue; } Profiler_GetHistory(i, &history[0], historyLength); float x = 10; uint32_t col = nice_colors[i % ARRAY_SIZE(nice_colors)]; if (area) col = opacity | (col & 0xFFFFFF); UI::Drawable color(col); UI::Drawable outline((opacity >> 1) | 0xFFFFFF); if (area) { for (int n = 0; n < historyLength; n++) { float val = history[n]; float valY1 = ui.GetBounds().y2() - 10 - (val + total[n]) * scale; float valY2 = ui.GetBounds().y2() - 10 - total[n] * scale; ui.FillRect(outline, Bounds(x, valY2, dx, 1.0f)); ui.FillRect(color, Bounds(x, valY1, dx, valY2 - valY1)); x += dx; total[n] += val; } } else { for (int n = 0; n < historyLength; n++) { float val = history[n]; if (val > maxVal) maxVal = val; float valY = ui.GetBounds().y2() - 10 - history[n] * scale; ui.FillRect(color, Bounds(x, valY, dx, 5)); x += dx; } } } for (int n = 0; n < historyLength; n++) { if (total[n] > maxTotal) maxTotal = total[n]; } if (area) { maxVal = maxTotal; } lastMaxVal = lastMaxVal * 0.95f + maxVal * 0.05f; #endif }
void TextView::Draw(UIContext &dc) { dc.SetFontStyle(small_ ? dc.theme->uiFontSmall : dc.theme->uiFont); dc.DrawTextRect(text_.c_str(), bounds_, 0xFFFFFFFF, textAlign_); }