1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00

Added highlighting and focus to config overlay

This commit is contained in:
narzoul 2022-02-08 23:38:06 +01:00
parent 9d7f36c45b
commit 0d85ab5dc6
18 changed files with 223 additions and 106 deletions

View File

@ -170,7 +170,7 @@ namespace
configWindow->update();
}
auto capture = Input::getCapture();
auto capture = Input::getCaptureWindow();
if (capture)
{
capture->update();

View File

@ -533,8 +533,10 @@ namespace Gdi
if (configWindow && configWindow->isVisible())
{
GetWindowRect(configWindow->getWindow(), &wr);
layeredWindows.push_back({ configWindow->getWindow(), wr, nullptr });
auto capture = Input::getCapture();
auto visibleRegion(getWindowRegion(configWindow->getWindow()));
visibleRegion.offset(wr.left, wr.top);
layeredWindows.push_back({ configWindow->getWindow(), wr, visibleRegion });
auto capture = Input::getCaptureWindow();
if (capture && capture != configWindow)
{
GetWindowRect(capture->getWindow(), &wr);

View File

@ -24,7 +24,7 @@ namespace
HANDLE g_bmpArrow = nullptr;
SIZE g_bmpArrowSize = {};
Overlay::Window* g_capture = nullptr;
Overlay::Control* g_capture = nullptr;
POINT g_cursorPos = {};
HWND g_cursorWindow = nullptr;
std::map<Input::HotKey, HotKeyData> g_hotKeys;
@ -61,6 +61,20 @@ namespace
return CALL_ORIG_FUNC(DefWindowProcA)(hwnd, uMsg, wParam, lParam);
}
POINT getRelativeCursorPos()
{
auto captureWindow = Input::getCaptureWindow();
const RECT rect = captureWindow->getRect();
const int scaleFactor = captureWindow->getScaleFactor();
auto cp = g_cursorPos;
cp.x /= scaleFactor;
cp.y /= scaleFactor;
cp.x -= rect.left;
cp.y -= rect.top;
return cp;
}
LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (HC_ACTION == nCode && (WM_KEYDOWN == wParam || WM_SYSKEYDOWN == wParam))
@ -85,23 +99,21 @@ namespace
{
if (HC_ACTION == nCode)
{
POINT cp = g_cursorPos;
POINT origCp = {};
GetCursorPos(&origCp);
if (WM_MOUSEMOVE == wParam)
{
POINT cp = g_cursorPos;
POINT origCp = {};
GetCursorPos(&origCp);
auto& llHook = *reinterpret_cast<MSLLHOOKSTRUCT*>(lParam);
cp.x += (llHook.pt.x - origCp.x);
cp.y += (llHook.pt.y - origCp.y);
cp.x = min(max(g_monitorRect.left, cp.x), g_monitorRect.right);
cp.y = min(max(g_monitorRect.top, cp.y), g_monitorRect.bottom);
g_cursorPos = cp;
auto& llHook = *reinterpret_cast<MSLLHOOKSTRUCT*>(lParam);
cp.x += (llHook.pt.x - origCp.x);
cp.y += (llHook.pt.y - origCp.y);
cp.x = min(max(g_monitorRect.left, cp.x), g_monitorRect.right);
cp.y = min(max(g_monitorRect.top, cp.y), g_monitorRect.bottom);
g_cursorPos = cp;
}
const RECT rect = g_capture->getRect();
const int scaleFactor = g_capture->getScaleFactor();
cp.x /= scaleFactor;
cp.y /= scaleFactor;
cp.x -= rect.left;
cp.y -= rect.top;
auto cp = getRelativeCursorPos();
switch (wParam)
{
@ -199,11 +211,21 @@ namespace Input
return toTuple(lhs) < toTuple(rhs);
}
Overlay::Window* getCapture()
Overlay::Control* getCapture()
{
return g_capture;
}
Overlay::Window* getCaptureWindow()
{
return g_capture ? static_cast<Overlay::Window*>(&g_capture->getRoot()) : nullptr;
}
POINT getCursorPos()
{
return g_cursorPos;
}
HWND getCursorWindow()
{
return g_cursorWindow;
@ -230,11 +252,18 @@ namespace Input
}
}
void setCapture(Overlay::Window* window)
void setCapture(Overlay::Control* control)
{
g_capture = window;
if (window)
if (control && !control->isVisible())
{
control = nullptr;
}
g_capture = control;
if (control)
{
auto window = getCaptureWindow();
MONITORINFO mi = {};
mi.cbSize = sizeof(mi);
GetMonitorInfo(MonitorFromWindow(window->getWindow(), MONITOR_DEFAULTTOPRIMARY), &mi);
@ -246,10 +275,10 @@ namespace Input
CALL_ORIG_FUNC(SetWindowLongA)(g_cursorWindow, GWL_WNDPROC, reinterpret_cast<LONG>(&cursorWindowProc));
CALL_ORIG_FUNC(SetLayeredWindowAttributes)(g_cursorWindow, RGB(0xFF, 0xFF, 0xFF), 0, LWA_COLORKEY);
RECT r = window->getRect();
g_cursorPos = { (r.left + r.right) / 2, (r.top + r.bottom) / 2 };
g_cursorPos = { (g_monitorRect.left + g_monitorRect.right) / 2, (g_monitorRect.top + g_monitorRect.bottom) / 2 };
CALL_ORIG_FUNC(SetWindowPos)(g_cursorWindow, HWND_TOPMOST, g_cursorPos.x, g_cursorPos.y,
g_bmpArrowSize.cx, g_bmpArrowSize.cy, SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
g_capture->onMouseMove(getRelativeCursorPos());
resetMouseHook();
}

View File

@ -7,6 +7,7 @@
namespace Overlay
{
class Control;
class Window;
}
@ -20,10 +21,12 @@ namespace Input
bool operator<(const HotKey& lhs, const HotKey& rhs);
Overlay::Window* getCapture();
Overlay::Control* getCapture();
Overlay::Window* getCaptureWindow();
POINT getCursorPos();
HWND getCursorWindow();
void installHooks();
void registerHotKey(const HotKey& hotKey, std::function<void(void*)> action, void* context);
void setCapture(Overlay::Window* window);
void setCapture(Overlay::Control* control);
void updateCursor();
}

View File

@ -13,6 +13,7 @@ namespace Overlay
void ComboBoxControl::setValue(const std::string& value)
{
m_value = value;
m_dropDown.select(value);
invalidate();
}

View File

@ -14,9 +14,7 @@ namespace Overlay
ComboBoxControl(Control& parent, const RECT& rect, const std::vector<std::string>& values);
std::string getValue() const { return m_value; }
std::vector<std::string> getValues() const { return m_dropDown.getValues(); }
void setValue(const std::string& value);
void setValues(const std::vector<std::string>& values) { m_dropDown.setValues(values); }
private:
virtual void draw(HDC dc) override;

View File

@ -1,4 +1,7 @@
#include <Common/Hook.h>
#include <Common/Log.h>
#include <Config/Parser.h>
#include <Input/Input.h>
#include <Overlay/ComboBoxControl.h>
#include <Overlay/ComboBoxDropDown.h>
@ -8,21 +11,26 @@ namespace Overlay
: Window(&static_cast<Window&>(parent.getRoot()), calculateRect(parent, values.size()))
, m_parent(parent)
{
setValues(values);
for (int i = 0; i < static_cast<int>(values.size()); ++i)
{
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);
}
}
RECT ComboBoxDropDown::calculateRect(ComboBoxControl& parent, DWORD itemCount)
{
const RECT parentRect = parent.getRect();
return { parentRect.left, parentRect.bottom, parentRect.right,
parentRect.bottom + static_cast<int>(itemCount) * ARROW_SIZE };
parentRect.bottom + static_cast<int>(itemCount) * ARROW_SIZE + 4 };
}
RECT ComboBoxDropDown::calculateRect(const RECT& /*monitorRect*/) const
{
const Window& rootWindow = static_cast<const Window&>(m_parent.getRoot());
const RECT rootRect = rootWindow.getRect();
RECT r = calculateRect(m_parent, m_values.size());
RECT r = calculateRect(m_parent, m_labels.size());
OffsetRect(&r, rootRect.left, rootRect.top);
return r;
}
@ -31,11 +39,12 @@ namespace Overlay
{
if (PtInRect(&m_rect, { m_rect.left + pos.x, m_rect.top + pos.y }))
{
propagateMouseEvent(&Control::onLButtonDown, pos);
Control::onLButtonDown(pos);
}
else
{
setVisible(false);
Input::setCapture(m_parent.getParent());
}
}
@ -45,17 +54,27 @@ namespace Overlay
m_parent.getParent()->onNotify(*m_parent.getParent());
}
void ComboBoxDropDown::setValues(const std::vector<std::string>& values)
void ComboBoxDropDown::select(const std::string& value)
{
m_values = values;
m_labels.clear();
int i = 0;
for (const auto& v : values)
const auto valueWithoutParam(Config::Parser::removeParam(value));
for (auto& label : m_labels)
{
m_labels.emplace_back(*this,
RECT{ BORDER, i * ARROW_SIZE, m_rect.right - m_rect.left - BORDER, (i + 1) * ARROW_SIZE },
v, DT_SINGLELINE | DT_VCENTER);
++i;
if (Config::Parser::removeParam(label.getLabel()) == valueWithoutParam)
{
label.setLabel(value);
label.setColor(HIGHLIGHT_COLOR);
}
else
{
label.setColor(FOREGROUND_COLOR);
}
}
invalidate();
}
void ComboBoxDropDown::setVisible(bool visible)
{
m_highlightedChild = nullptr;
Window::setVisible(visible);
}
}

View File

@ -9,26 +9,24 @@
namespace Overlay
{
class ComboBoxControl;
class LabelControl;
class ComboBoxDropDown : public Window
{
public:
ComboBoxDropDown(ComboBoxControl& parent, const std::vector<std::string>& values);
virtual void onLButtonDown(POINT pos) override;
virtual void onNotify(Control& control) override;
virtual void setVisible(bool visible) override;
std::vector<std::string> getValues() const { return m_values; }
void setValues(const std::vector<std::string>& values);
void select(const std::string& value);
private:
static RECT calculateRect(ComboBoxControl& parent, DWORD itemCount);
virtual RECT calculateRect(const RECT& monitorRect) const override;
virtual void onLButtonDown(POINT pos) override;
ComboBoxControl& m_parent;
std::vector<std::string> m_values;
std::list<LabelControl> m_labels;
};
}

View File

@ -1,5 +1,7 @@
#include <Common/Hook.h>
#include <Config/Config.h>
#include <Gdi/GuiThread.h>
#include <Input/Input.h>
#include <Overlay/ConfigWindow.h>
#include <Overlay/SettingControl.h>
@ -7,6 +9,7 @@ namespace Overlay
{
ConfigWindow::ConfigWindow()
: Window(nullptr, { 0, 0, SettingControl::TOTAL_WIDTH, 200 }, { VK_F11, {} })
, m_focus(nullptr)
{
addControl(Config::alternatePixelCenter);
addControl(Config::antialiasing);
@ -32,4 +35,38 @@ namespace Overlay
monitorRect.top + (monitorRect.bottom - monitorRect.top - r.bottom) / 2);
return r;
}
void ConfigWindow::setFocus(SettingControl* control)
{
if (m_focus == control)
{
return;
}
m_focus = control;
Input::setCapture(m_focus ? static_cast<Control*>(m_focus) : this);
if (m_focus)
{
RECT r = m_focus->getHighlightRect();
int sf = getScaleFactor();
r = { r.left * sf, r.top * sf, r.right * sf, r.bottom * sf };
Gdi::GuiThread::setWindowRgn(m_hwnd, r);
}
else
{
Gdi::GuiThread::setWindowRgn(m_hwnd, nullptr);
}
invalidate();
}
void ConfigWindow::setVisible(bool isVisible)
{
if (isVisible != Window::isVisible())
{
Window::setVisible(isVisible);
setFocus(nullptr);
}
}
}

View File

@ -12,11 +12,16 @@ namespace Overlay
public:
ConfigWindow();
virtual void setVisible(bool isVisible) override;
void setFocus(SettingControl* control);
private:
virtual RECT calculateRect(const RECT& monitorRect) const override;
void addControl(Config::Setting& setting);
std::list<SettingControl> m_controls;
SettingControl* m_focus;
};
}

View File

@ -3,12 +3,11 @@
namespace Overlay
{
Control* g_capture = nullptr;
Control::Control(Control* parent, const RECT& rect, DWORD style)
: m_parent(parent)
, m_rect(rect)
, m_style(style)
, m_highlightedChild(nullptr)
{
if (parent)
{
@ -42,6 +41,14 @@ namespace Overlay
}
CALL_ORIG_FUNC(Rectangle)(dc, r.left, r.top, r.right, r.bottom);
}
if (m_highlightedChild)
{
RECT r = m_highlightedChild->getHighlightRect();
SetDCPenColor(dc, HIGHLIGHT_COLOR);
CALL_ORIG_FUNC(Rectangle)(dc, r.left, r.top, r.right, r.bottom);
SetDCPenColor(dc, FOREGROUND_COLOR);
}
}
void Control::drawArrow(HDC dc, RECT rect, UINT state)
@ -83,11 +90,6 @@ namespace Overlay
CALL_ORIG_FUNC(Polygon)(dc, poly, 3);
}
Control* Control::getCapture()
{
return g_capture;
}
const Control& Control::getRoot() const
{
if (m_parent)
@ -122,17 +124,22 @@ namespace Overlay
void Control::onMouseMove(POINT pos)
{
auto prevHighlightedChild = m_highlightedChild;
m_highlightedChild = nullptr;
propagateMouseEvent(&Control::onMouseMove, pos);
if (m_highlightedChild != prevHighlightedChild)
{
invalidate();
}
if (m_parent && (m_style & WS_TABSTOP))
{
m_parent->m_highlightedChild = this;
invalidate();
}
}
void Control::propagateMouseEvent(void(Control::* onEvent)(POINT), POINT pos)
{
if (g_capture)
{
(g_capture->*onEvent)(pos);
return;
}
for (auto child : m_children)
{
if (PtInRect(&child->m_rect, pos))
@ -143,11 +150,6 @@ namespace Overlay
}
}
void Control::setCapture(Control* control)
{
g_capture = control;
}
void Control::setVisible(bool isVisible)
{
if (isVisible != Control::isVisible())

View File

@ -21,6 +21,7 @@ namespace Overlay
Control& operator=(Control&&) = delete;
virtual void draw(HDC /*dc*/) {}
virtual RECT getHighlightRect() const { return m_rect; }
virtual void invalidate();
virtual void onLButtonDown(POINT pos);
virtual void onLButtonUp(POINT pos);
@ -36,15 +37,16 @@ namespace Overlay
bool isVisible() const { return m_style & WS_VISIBLE; }
protected:
static const COLORREF FOREGROUND_COLOR = RGB(0, 255, 0);
static const COLORREF HIGHLIGHT_COLOR = RGB(255, 255, 0);
void drawArrow(HDC dc, RECT rect, UINT state);
void propagateMouseEvent(void(Control::* onEvent)(POINT), POINT pos);
static Control* getCapture();
static void setCapture(Control* control);
Control* m_parent;
RECT m_rect;
DWORD m_style;
std::set<Control*> m_children;
Control* m_highlightedChild;
};
}

View File

@ -3,22 +3,31 @@
namespace Overlay
{
LabelControl::LabelControl(Control& parent, const RECT& rect, const std::string& label, UINT format)
: Control(&parent, rect, WS_VISIBLE)
LabelControl::LabelControl(Control& parent, const RECT& rect, const std::string& label, UINT format, DWORD style)
: Control(&parent, rect, style)
, m_label(label)
, m_format(format)
, 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 };
SetTextColor(dc, m_color);
CALL_ORIG_FUNC(DrawTextA)(dc, m_label.c_str(), m_label.size(), &r,
m_format | DT_NOCLIP | DT_SINGLELINE | DT_VCENTER);
SetTextColor(dc, FOREGROUND_COLOR);
}
void LabelControl::onLButtonDown(POINT /*pos*/)
{
m_parent->onNotify(*this);
}
void LabelControl::setColor(COLORREF color)
{
m_color = color;
invalidate();
}
}

View File

@ -11,16 +11,19 @@ namespace Overlay
class LabelControl : public Control
{
public:
LabelControl(Control& parent, const RECT& rect, const std::string& label, UINT format);
LabelControl(Control& parent, const RECT& rect, const std::string& label, UINT format, DWORD style = WS_VISIBLE);
virtual void onLButtonDown(POINT pos) override;
std::string getLabel() const { return m_label; }
const std::string& getLabel() const { return m_label; }
void setLabel(const std::string label) { m_label = label; }
void setColor(COLORREF color);
private:
virtual void draw(HDC dc) override;
std::string m_label;
UINT m_format;
COLORREF m_color;
};
}

View File

@ -1,6 +1,7 @@
#pragma once
#include <Common/Hook.h>
#include <Input/Input.h>
#include <Overlay/ScrollBarControl.h>
namespace
@ -46,7 +47,7 @@ namespace Overlay
void ScrollBarControl::onLButtonDown(POINT pos)
{
setCapture(this);
Input::setCapture(this);
if (PtInRect(&m_leftArrow, pos))
{
setPos(m_pos - 1);
@ -77,9 +78,12 @@ namespace Overlay
void ScrollBarControl::onLButtonUp(POINT /*pos*/)
{
setCapture(nullptr);
stopRepeatTimer();
m_state = State::IDLE;
if (Input::getCapture() == this)
{
Input::setCapture(m_parent);
stopRepeatTimer();
m_state = State::IDLE;
}
}
void ScrollBarControl::onMouseMove(POINT pos)
@ -119,7 +123,7 @@ namespace Overlay
void CALLBACK ScrollBarControl::repeatTimerProc(HWND /*hwnd*/, UINT /*message*/, UINT_PTR /*iTimerID*/, DWORD /*dwTime*/)
{
static_cast<ScrollBarControl*>(Overlay::Control::getCapture())->onRepeat();
static_cast<ScrollBarControl*>(Input::getCapture())->onRepeat();
}
void ScrollBarControl::setPos(int pos)

View File

@ -1,9 +1,8 @@
#include <Config/Config.h>
#include <Config/Parser.h>
#include <Config/Setting.h>
#include <D3dDdi/Device.h>
#include <DDraw/RealPrimarySurface.h>
#include <Overlay/ComboBoxControl.h>
#include <Overlay/ConfigWindow.h>
#include <Overlay/SettingControl.h>
namespace
@ -26,8 +25,8 @@ namespace
namespace Overlay
{
SettingControl::SettingControl(Control& parent, const RECT& rect, Config::Setting& setting)
: Control(&parent, rect, WS_VISIBLE)
SettingControl::SettingControl(ConfigWindow& parent, const RECT& rect, Config::Setting& setting)
: Control(&parent, rect, WS_VISIBLE | WS_TABSTOP)
, m_setting(setting)
, m_settingLabel(*this, { rect.left, rect.top, rect.left + SETTING_LABEL_WIDTH, rect.bottom }, setting.getName() + ':', 0)
{
@ -36,7 +35,13 @@ namespace Overlay
m_valueControl.reset(new ComboBoxControl(*this, r, getValueStrings(setting)));
getValueComboBox().setValue(setting.getValueStr());
onValueChanged();
updateValuesParam();
}
RECT SettingControl::getHighlightRect() const
{
RECT r = m_rect;
InflateRect(&r, -BORDER / 2, 0);
return r;
}
ComboBoxControl& SettingControl::getValueComboBox() const
@ -44,6 +49,21 @@ namespace Overlay
return static_cast<ComboBoxControl&>(*m_valueControl);
}
void SettingControl::onLButtonDown(POINT pos)
{
auto configWindow = static_cast<ConfigWindow*>(m_parent);
if (PtInRect(&m_rect, pos))
{
configWindow->setFocus(this);
Control::onLButtonDown(pos);
}
else
{
configWindow->setFocus(nullptr);
configWindow->onMouseMove(pos);
}
}
void SettingControl::onNotify(Control& control)
{
if (&control == m_paramControl.get())
@ -72,7 +92,6 @@ namespace Overlay
'(' + std::to_string(m_paramControl->getPos()) + ')');
m_setting.set(value);
getValueComboBox().setValue(value);
updateValuesParam();
}
void SettingControl::onValueChanged()
@ -100,19 +119,4 @@ namespace Overlay
m_paramControl->setPos(m_setting.getParam());
}
}
void SettingControl::updateValuesParam()
{
const auto currentValue(Config::Parser::removeParam(m_setting.getValueStr()));
auto values(getValueComboBox().getValues());
for (auto& v : values)
{
if (Config::Parser::removeParam(v) == currentValue)
{
v = m_setting.getValueStr();
getValueComboBox().setValues(values);
break;
}
}
}
}

View File

@ -1,7 +1,6 @@
#pragma once
#include <memory>
#include <string>
#include <Overlay/LabelControl.h>
#include <Overlay/ScrollBarControl.h>
@ -14,6 +13,7 @@ namespace Config
namespace Overlay
{
class ComboBoxControl;
class ConfigWindow;
class SettingControl : public Control
{
@ -25,15 +25,16 @@ namespace Overlay
static const int TOTAL_WIDTH =
SETTING_LABEL_WIDTH + SETTING_CONTROL_WIDTH + PARAM_LABEL_WIDTH + PARAM_CONTROL_WIDTH + BORDER;
SettingControl(Control& parent, const RECT& rect, Config::Setting& setting);
SettingControl(ConfigWindow& parent, const RECT& rect, Config::Setting& setting);
virtual RECT getHighlightRect() const override;
virtual void onLButtonDown(POINT pos) override;
virtual void onNotify(Control& control) override;
private:
ComboBoxControl& getValueComboBox() const;
void onParamChanged();
void onValueChanged();
void updateValuesParam();
Config::Setting& m_setting;
LabelControl m_settingLabel;

View File

@ -127,7 +127,7 @@ namespace Overlay
}
else
{
auto capture = Input::getCapture();
auto capture = Input::getCaptureWindow();
if (capture && capture != this && capture->m_parentWindow == this)
{
capture->setVisible(false);
@ -162,8 +162,8 @@ namespace Overlay
SelectObject(m_dc, GetStockObject(NULL_BRUSH));
SetBkColor(m_dc, RGB(0, 0, 0));
SetDCBrushColor(m_dc, RGB(0, 0, 0));
SetDCPenColor(m_dc, RGB(0, 255, 0));
SetTextColor(m_dc, RGB(0, 255, 0));
SetDCPenColor(m_dc, FOREGROUND_COLOR);
SetTextColor(m_dc, FOREGROUND_COLOR);
RECT rect = { 0, 0, m_rect.right - m_rect.left, m_rect.bottom - m_rect.top };
CALL_ORIG_FUNC(FillRect)(m_dc, &rect, static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)));
@ -217,9 +217,9 @@ namespace Overlay
CALL_ORIG_FUNC(SetWindowPos)(m_hwnd, HWND_TOPMOST, m_rect.left * m_scaleFactor, m_rect.top * m_scaleFactor,
(m_rect.right - m_rect.left) * m_scaleFactor, (m_rect.bottom - m_rect.top) * m_scaleFactor, SWP_NOACTIVATE);
if (Input::getCapture() == this)
if (Input::getCaptureWindow() == this)
{
Input::setCapture(this);
Input::setCapture(Input::getCapture());
}
invalidate();