diff --git a/DDrawCompat/Config/EnumListSetting.cpp b/DDrawCompat/Config/EnumListSetting.cpp index c067f8c..c9d1380 100644 --- a/DDrawCompat/Config/EnumListSetting.cpp +++ b/DDrawCompat/Config/EnumListSetting.cpp @@ -27,7 +27,7 @@ namespace Config throw ParsingError("empty list is not allowed"); } - std::vector result; + std::vector result; for (auto valueName : values) { auto it = std::find(m_enumNames.begin(), m_enumNames.end(), valueName); @@ -36,7 +36,7 @@ namespace Config throw ParsingError("invalid value: '" + valueName + "'"); } - unsigned value = it - m_enumNames.begin(); + int value = it - m_enumNames.begin(); if (std::find(result.begin(), result.end(), value) == result.end()) { result.push_back(value); diff --git a/DDrawCompat/Config/EnumListSetting.h b/DDrawCompat/Config/EnumListSetting.h index b02fcc9..45879e9 100644 --- a/DDrawCompat/Config/EnumListSetting.h +++ b/DDrawCompat/Config/EnumListSetting.h @@ -13,12 +13,12 @@ namespace Config virtual std::string getValueStr() const override; - const std::vector& get() const { return m_values; } + const std::vector& get() const { return m_values; } private: void setValues(const std::vector& values) override; const std::vector m_enumNames; - std::vector m_values; + std::vector m_values; }; } diff --git a/DDrawCompat/Config/Settings/StatsRows.h b/DDrawCompat/Config/Settings/StatsRows.h index ba521df..3bb0c5a 100644 --- a/DDrawCompat/Config/Settings/StatsRows.h +++ b/DDrawCompat/Config/Settings/StatsRows.h @@ -24,7 +24,8 @@ namespace Config LOCKRATE, LOCKTIME, DDIUSAGE, - GDIOBJECTS + GDIOBJECTS, + DEBUG }; StatsRows() @@ -44,7 +45,8 @@ namespace Config "lockrate", "locktime", "ddiusage", - "gdiobjects" + "gdiobjects", + "debug" }) { } diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index c5936f5..288863a 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -352,6 +352,7 @@ namespace { if (!isOverlayOnly) { + statsWindow->m_presentCount++; statsWindow->m_present.add(); } statsWindow->update(); diff --git a/DDrawCompat/Overlay/ButtonControl.cpp b/DDrawCompat/Overlay/ButtonControl.cpp index f2ab0b8..c154bce 100644 --- a/DDrawCompat/Overlay/ButtonControl.cpp +++ b/DDrawCompat/Overlay/ButtonControl.cpp @@ -7,7 +7,7 @@ namespace Overlay ButtonControl::ButtonControl(Control& parent, const RECT& rect, const std::string& label, ClickHandler clickHandler) : Control(&parent, rect, WS_BORDER | WS_TABSTOP | WS_VISIBLE) , m_clickHandler(clickHandler) - , m_label(*this, rect, label, DT_CENTER) + , m_label(*this, rect, label, TA_CENTER) { } diff --git a/DDrawCompat/Overlay/ComboBoxControl.cpp b/DDrawCompat/Overlay/ComboBoxControl.cpp index 7dc66c7..a981e25 100644 --- a/DDrawCompat/Overlay/ComboBoxControl.cpp +++ b/DDrawCompat/Overlay/ComboBoxControl.cpp @@ -6,25 +6,22 @@ namespace Overlay { ComboBoxControl::ComboBoxControl(Control& parent, const RECT& rect, const std::vector& values) : Control(&parent, rect, WS_BORDER | WS_VISIBLE) + , m_label(*this, { rect.left, rect.top, rect.right - ARROW_SIZE, rect.bottom }, std::string(), 0) , m_dropDown(*this, values) { } void ComboBoxControl::setValue(const std::string& value) { - m_value = value; + m_label.setLabel(value); m_dropDown.select(value); - invalidate(); } void ComboBoxControl::draw(HDC dc) { RECT rect = m_rect; - rect.left = m_rect.right - 17; + rect.left = m_label.getRect().right; drawArrow(dc, rect, DFCS_SCROLLDOWN); - - rect.left = m_rect.left + BORDER; - CALL_ORIG_FUNC(DrawTextA)(dc, m_value.c_str(), m_value.size(), &rect, DT_NOCLIP | DT_SINGLELINE | DT_VCENTER); } void ComboBoxControl::onLButtonDown(POINT /*pos*/) diff --git a/DDrawCompat/Overlay/ComboBoxControl.h b/DDrawCompat/Overlay/ComboBoxControl.h index d4ac7d0..7a36c12 100644 --- a/DDrawCompat/Overlay/ComboBoxControl.h +++ b/DDrawCompat/Overlay/ComboBoxControl.h @@ -5,6 +5,7 @@ #include #include +#include namespace Overlay { @@ -13,14 +14,14 @@ namespace Overlay public: ComboBoxControl(Control& parent, const RECT& rect, const std::vector& values); - std::string getValue() const { return m_value; } + const std::string& getValue() const { return m_label.getLabel(); } void setValue(const std::string& value); private: virtual void draw(HDC dc) override; virtual void onLButtonDown(POINT pos) override; - std::string m_value; + LabelControl m_label; ComboBoxDropDown m_dropDown; }; } diff --git a/DDrawCompat/Overlay/ComboBoxDropDown.cpp b/DDrawCompat/Overlay/ComboBoxDropDown.cpp index 191d78c..bc546a5 100644 --- a/DDrawCompat/Overlay/ComboBoxDropDown.cpp +++ b/DDrawCompat/Overlay/ComboBoxDropDown.cpp @@ -17,7 +17,7 @@ namespace Overlay { m_labels.emplace_back(*this, RECT{ 2, i * ARROW_SIZE + 2, m_rect.right - m_rect.left - 2, (i + 1) * ARROW_SIZE + 2 }, - values[i], DT_SINGLELINE | DT_VCENTER, WS_VISIBLE | WS_TABSTOP); + values[i], TA_LEFT, WS_VISIBLE | WS_TABSTOP); } } diff --git a/DDrawCompat/Overlay/LabelControl.cpp b/DDrawCompat/Overlay/LabelControl.cpp index 24c2a1b..f95f329 100644 --- a/DDrawCompat/Overlay/LabelControl.cpp +++ b/DDrawCompat/Overlay/LabelControl.cpp @@ -3,20 +3,39 @@ namespace Overlay { - LabelControl::LabelControl(Control& parent, const RECT& rect, const std::string& label, UINT format, DWORD style) + LabelControl::LabelControl(Control& parent, const RECT& rect, const std::string& label, UINT align, DWORD style) : Control(&parent, rect, style) , m_label(label) - , m_format(format) + , m_wlabel(label.begin(), label.end()) + , m_align(align) , m_color(FOREGROUND_COLOR) { } void LabelControl::draw(HDC dc) { - RECT r = { m_rect.left + BORDER, m_rect.top, m_rect.right - BORDER, m_rect.bottom }; + LONG x = 0; + const LONG y = (m_rect.top + m_rect.bottom) / 2 - 7; + + switch (m_align) + { + case TA_LEFT: + x = m_rect.left + BORDER; + break; + case TA_CENTER: + x = (m_rect.left + m_rect.right) / 2; + break; + case TA_RIGHT: + x = m_rect.right - BORDER; + break; + default: + return; + } + auto prevColor = SetTextColor(dc, (FOREGROUND_COLOR == m_color && !isEnabled()) ? DISABLED_COLOR : m_color ); - CALL_ORIG_FUNC(DrawTextA)(dc, m_label.c_str(), m_label.size(), &r, - m_format | DT_NOCLIP | DT_SINGLELINE | DT_VCENTER); + auto prevTextAlign = SetTextAlign(dc, m_align); + CALL_ORIG_FUNC(ExtTextOutW)(dc, x, y, ETO_IGNORELANGUAGE, nullptr, m_wlabel.c_str(), m_wlabel.length(), nullptr); + SetTextAlign(dc, prevTextAlign); SetTextColor(dc, prevColor); } @@ -39,6 +58,7 @@ namespace Overlay if (m_label != label) { m_label = label; + m_wlabel.assign(label.begin(), label.end()); invalidate(); } } diff --git a/DDrawCompat/Overlay/LabelControl.h b/DDrawCompat/Overlay/LabelControl.h index 4e33e3d..0eb2188 100644 --- a/DDrawCompat/Overlay/LabelControl.h +++ b/DDrawCompat/Overlay/LabelControl.h @@ -23,7 +23,8 @@ namespace Overlay virtual void draw(HDC dc) override; std::string m_label; - UINT m_format; + std::wstring m_wlabel; + UINT m_align; COLORREF m_color; }; } diff --git a/DDrawCompat/Overlay/StatsControl.cpp b/DDrawCompat/Overlay/StatsControl.cpp index c8628ee..ee31662 100644 --- a/DDrawCompat/Overlay/StatsControl.cpp +++ b/DDrawCompat/Overlay/StatsControl.cpp @@ -14,8 +14,15 @@ namespace Overlay : Control(&parent, rect, style) , m_updateFunc(updateFunc) { + if (style & WS_GROUP) + { + m_labels.emplace_back(*this, rect, std::string(), TA_RIGHT); + return; + } + auto& columns = Config::statsColumns.get(); RECT r = rect; + r.left += (r.right - r.left) - getWidth(); for (unsigned i = 0; i < columns.size(); ++i) { r.right = r.left + getColumnWidth(i); @@ -25,7 +32,7 @@ namespace Overlay } else { - m_labels.emplace_back(*this, r, std::string(), DT_RIGHT); + m_labels.emplace_back(*this, r, std::string(), TA_RIGHT); } r.left = r.right; } @@ -55,6 +62,12 @@ namespace Overlay void StatsControl::update(StatsQueue::TickCount tickCount) { auto stats = m_updateFunc(tickCount); + if (m_style & WS_GROUP) + { + m_labels.front().setLabel(stats[0]); + return; + } + auto& columns = Config::statsColumns.get(); auto label = m_labels.begin(); for (unsigned i = 0; i < columns.size(); ++i) diff --git a/DDrawCompat/Overlay/StatsWindow.cpp b/DDrawCompat/Overlay/StatsWindow.cpp index 649205a..b5a20a0 100644 --- a/DDrawCompat/Overlay/StatsWindow.cpp +++ b/DDrawCompat/Overlay/StatsWindow.cpp @@ -1,6 +1,8 @@ +#include #include #include +#include #include #include #include @@ -47,11 +49,11 @@ namespace char buf[20] = {}; if (0 == unitIndex) { - snprintf(buf, sizeof(buf), "%.0f", stat); + sprintf_s(buf, "%.0f", stat); return buf; } - auto len = snprintf(buf, sizeof(buf), "%.2f", stat); + auto len = sprintf_s(buf, "%.2f", stat); const auto decimalPoint = strchr(buf, '.'); const auto intLen = decimalPoint ? decimalPoint - buf : len; if (len > 4) @@ -67,14 +69,31 @@ namespace }; const int ROW_HEIGHT = 15; + + std::array getDebugInfo(StatsQueue::TickCount /*tickCount*/) + { + const uint32_t presentCount = Gdi::GuiThread::getStatsWindow()->m_presentCount; + static uint32_t updateCount = 0; + ++updateCount; + + SYSTEMTIME st = {}; + GetLocalTime(&st); + LOG_DEBUG << "Stats debuginfo: " << presentCount << " " << updateCount; + + char debuginfo[60]; + sprintf_s(debuginfo, "%u %u %02hu:%02hu:%02hu.%03hu", presentCount, updateCount, + st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); + return { debuginfo }; + } } namespace Overlay { StatsWindow::StatsWindow() : Window(nullptr, - { 0, 0, StatsControl::getWidth(), static_cast(Config::statsRows.get().size()) * ROW_HEIGHT + BORDER }, + { 0, 0, getWidth(), static_cast(Config::statsRows.get().size()) * ROW_HEIGHT + BORDER }, 0, Config::statsTransparency.get(), Config::statsHotKey.get()) + , m_presentCount(0) { m_statsRows.push_back({ "", [](auto) { return std::array{ "cur", "avg", "min", "max" }; }, WS_VISIBLE | WS_DISABLED }); @@ -92,6 +111,7 @@ namespace Overlay m_statsRows.push_back({ "Lock time", UpdateStats(m_lock.m_time) }); m_statsRows.push_back({ "DDI usage", UpdateStats(m_ddiUsage) }); m_statsRows.push_back({ "GDI objects", UpdateStats(m_gdiObjects) }); + m_statsRows.push_back({ "", &getDebugInfo, WS_VISIBLE | WS_GROUP }); for (auto statsRowIndex : Config::statsRows.get()) { @@ -126,12 +146,30 @@ namespace Overlay return (configWindow && configWindow->isVisible()) ? configWindow->getWindow() : Window::getTopmost(); } + LONG StatsWindow::getWidth() + { + LONG width = StatsControl::getWidth(); + const auto& statsRows = Config::statsRows.get(); + if (std::find(statsRows.begin(), statsRows.end(), Config::Settings::StatsRows::DEBUG) != statsRows.end()) + { + width = std::max(width, 140L); + } + return width; + } + void StatsWindow::updateStats() { static auto prevTickCount = StatsQueue::getTickCount() - 1; m_tickCount = StatsQueue::getTickCount(); if (m_tickCount == prevTickCount) { + for (auto& statsControl : m_statsControls) + { + if (statsControl.getStyle() & WS_GROUP) + { + statsControl.update(m_tickCount); + } + } return; } diff --git a/DDrawCompat/Overlay/StatsWindow.h b/DDrawCompat/Overlay/StatsWindow.h index 9ba8d51..12c88cf 100644 --- a/DDrawCompat/Overlay/StatsWindow.h +++ b/DDrawCompat/Overlay/StatsWindow.h @@ -20,6 +20,7 @@ namespace Overlay void updateStats(); + uint32_t m_presentCount; StatsEventGroup m_present; StatsEventGroup m_flip; StatsEventGroup m_blit; @@ -40,6 +41,8 @@ namespace Overlay virtual RECT calculateRect(const RECT& monitorRect) const override; virtual HWND getTopmost() const override; + static LONG getWidth(); + std::list m_statsControls; std::vector m_statsRows; uint64_t m_tickCount;