UI hacking.
This commit is contained in:
parent
c1df273600
commit
d839359b4a
|
@ -107,3 +107,13 @@ int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR command_line, int) {
|
||||||
LocalFree(argv);
|
LocalFree(argv);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined _M_IX86
|
||||||
|
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
||||||
|
#elif defined _M_IA64
|
||||||
|
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
||||||
|
#elif defined _M_X64
|
||||||
|
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
||||||
|
#else
|
||||||
|
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
||||||
|
#endif
|
||||||
|
|
|
@ -52,5 +52,6 @@
|
||||||
],
|
],
|
||||||
|
|
||||||
'includes': [
|
'includes': [
|
||||||
|
'ui/sources.gypi',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <poly/ui/control.h>
|
||||||
|
|
||||||
|
namespace poly {
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
Control::Control(Control* parent, uint32_t flags)
|
||||||
|
: parent_(parent),
|
||||||
|
flags_(flags),
|
||||||
|
width_(0),
|
||||||
|
height_(0),
|
||||||
|
is_cursor_visible_(true),
|
||||||
|
is_enabled_(true),
|
||||||
|
is_visible_(true),
|
||||||
|
has_focus_(false) {}
|
||||||
|
|
||||||
|
Control::~Control() { children_.clear(); }
|
||||||
|
|
||||||
|
void Control::AddChild(Control* child_control) {
|
||||||
|
AddChild(ControlPtr(child_control, [](Control* control) {}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Control::AddChild(std::unique_ptr<Control> child_control) {
|
||||||
|
AddChild(ControlPtr(child_control.release(),
|
||||||
|
[](Control* control) { delete control; }));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Control::AddChild(ControlPtr control) {
|
||||||
|
auto control_ptr = control.get();
|
||||||
|
children_.emplace_back(std::move(control));
|
||||||
|
OnChildAdded(control_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Control::RemoveChild(Control* child_control) {
|
||||||
|
for (auto& it = children_.begin(); it != children_.end(); ++it) {
|
||||||
|
if (it->get() == child_control) {
|
||||||
|
children_.erase(it);
|
||||||
|
OnChildRemoved(child_control);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Control::OnResize(UIEvent& e) { on_resize(e); }
|
||||||
|
|
||||||
|
void Control::OnVisible(UIEvent& e) { on_visible(e); }
|
||||||
|
|
||||||
|
void Control::OnHidden(UIEvent& e) { on_hidden(e); }
|
||||||
|
|
||||||
|
void Control::OnGotFocus(UIEvent& e) { on_got_focus(e); }
|
||||||
|
|
||||||
|
void Control::OnLostFocus(UIEvent& e) { on_lost_focus(e); }
|
||||||
|
|
||||||
|
void Control::OnKeyDown(KeyEvent& e) { on_key_down(e); }
|
||||||
|
|
||||||
|
void Control::OnKeyUp(KeyEvent& e) { on_key_up(e); }
|
||||||
|
|
||||||
|
void Control::OnMouseDown(MouseEvent& e) { on_mouse_down(e); }
|
||||||
|
|
||||||
|
void Control::OnMouseMove(MouseEvent& e) { on_mouse_move(e); }
|
||||||
|
|
||||||
|
void Control::OnMouseUp(MouseEvent& e) { on_mouse_up(e); }
|
||||||
|
|
||||||
|
void Control::OnMouseWheel(MouseEvent& e) { on_mouse_wheel(e); }
|
||||||
|
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace poly
|
|
@ -0,0 +1,120 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef POLY_UI_CONTROL_H_
|
||||||
|
#define POLY_UI_CONTROL_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <poly/delegate.h>
|
||||||
|
#include <poly/ui/ui_event.h>
|
||||||
|
|
||||||
|
namespace poly {
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
class Control {
|
||||||
|
public:
|
||||||
|
typedef std::unique_ptr<Control, void (*)(Control*)> ControlPtr;
|
||||||
|
enum Flags {
|
||||||
|
// Control paints itself, so disable platform drawing.
|
||||||
|
kFlagOwnPaint = 1 << 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~Control();
|
||||||
|
|
||||||
|
Control* parent() const { return parent_; }
|
||||||
|
|
||||||
|
void AddChild(Control* child_control);
|
||||||
|
void AddChild(std::unique_ptr<Control> child_control);
|
||||||
|
void AddChild(ControlPtr child_control);
|
||||||
|
void RemoveChild(Control* child_control);
|
||||||
|
|
||||||
|
int32_t width() const { return width_; }
|
||||||
|
int32_t height() const { return height_; }
|
||||||
|
virtual void Resize(int32_t width, int32_t height) = 0;
|
||||||
|
virtual void Resize(int32_t left, int32_t top, int32_t right,
|
||||||
|
int32_t bottom) = 0;
|
||||||
|
virtual void ResizeToFill(int32_t pad_left, int32_t pad_top,
|
||||||
|
int32_t pad_right, int32_t pad_bottom) = 0;
|
||||||
|
|
||||||
|
// TODO(benvanik): colors/brushes/etc.
|
||||||
|
// TODO(benvanik): fonts.
|
||||||
|
|
||||||
|
bool is_cursor_visible() const { return is_cursor_visible_; }
|
||||||
|
virtual void set_cursor_visible(bool value) { is_cursor_visible_ = value; }
|
||||||
|
|
||||||
|
bool is_enabled() const { return is_enabled_; }
|
||||||
|
virtual void set_enabled(bool value) { is_enabled_ = value; }
|
||||||
|
|
||||||
|
bool is_visible() const { return is_visible_; }
|
||||||
|
virtual void set_visible(bool value) { is_visible_ = value; }
|
||||||
|
|
||||||
|
bool has_focus() const { return has_focus_; }
|
||||||
|
virtual void set_focus(bool value) { has_focus_ = value; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
poly::Delegate<UIEvent> on_resize;
|
||||||
|
|
||||||
|
poly::Delegate<UIEvent> on_visible;
|
||||||
|
poly::Delegate<UIEvent> on_hidden;
|
||||||
|
|
||||||
|
poly::Delegate<UIEvent> on_got_focus;
|
||||||
|
poly::Delegate<UIEvent> on_lost_focus;
|
||||||
|
|
||||||
|
poly::Delegate<KeyEvent> on_key_down;
|
||||||
|
poly::Delegate<KeyEvent> on_key_up;
|
||||||
|
|
||||||
|
poly::Delegate<MouseEvent> on_mouse_down;
|
||||||
|
poly::Delegate<MouseEvent> on_mouse_move;
|
||||||
|
poly::Delegate<MouseEvent> on_mouse_up;
|
||||||
|
poly::Delegate<MouseEvent> on_mouse_wheel;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Control(Control* parent, uint32_t flags);
|
||||||
|
|
||||||
|
virtual void OnCreate() {}
|
||||||
|
virtual void OnDestroy() {}
|
||||||
|
|
||||||
|
virtual void OnChildAdded(Control* child_control) {}
|
||||||
|
virtual void OnChildRemoved(Control* child_control) {}
|
||||||
|
|
||||||
|
virtual void OnResize(UIEvent& e);
|
||||||
|
|
||||||
|
virtual void OnVisible(UIEvent& e);
|
||||||
|
virtual void OnHidden(UIEvent& e);
|
||||||
|
|
||||||
|
virtual void OnGotFocus(UIEvent& e);
|
||||||
|
virtual void OnLostFocus(UIEvent& e);
|
||||||
|
|
||||||
|
virtual void OnKeyDown(KeyEvent& e);
|
||||||
|
virtual void OnKeyUp(KeyEvent& e);
|
||||||
|
|
||||||
|
virtual void OnMouseDown(MouseEvent& e);
|
||||||
|
virtual void OnMouseMove(MouseEvent& e);
|
||||||
|
virtual void OnMouseUp(MouseEvent& e);
|
||||||
|
virtual void OnMouseWheel(MouseEvent& e);
|
||||||
|
|
||||||
|
uint32_t flags_;
|
||||||
|
Control* parent_;
|
||||||
|
std::vector<ControlPtr> children_;
|
||||||
|
|
||||||
|
int32_t width_;
|
||||||
|
int32_t height_;
|
||||||
|
|
||||||
|
bool is_cursor_visible_;
|
||||||
|
bool is_enabled_;
|
||||||
|
bool is_visible_;
|
||||||
|
bool has_focus_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace poly
|
||||||
|
|
||||||
|
#endif // POLY_UI_CONTROL_H_
|
|
@ -7,18 +7,25 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <xenia/ui/menu_item.h>
|
#ifndef POLY_UI_LOOP_H_
|
||||||
|
#define POLY_UI_LOOP_H_
|
||||||
|
|
||||||
namespace xe {
|
#include <functional>
|
||||||
|
|
||||||
|
namespace poly {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
MenuItem::MenuItem(Window* window) : window_(window), parent_item_(nullptr) {}
|
class Loop {
|
||||||
|
public:
|
||||||
|
Loop() = default;
|
||||||
|
virtual ~Loop() = default;
|
||||||
|
|
||||||
MenuItem::~MenuItem() {}
|
virtual void Post(std::function<void()> fn) = 0;
|
||||||
|
|
||||||
void MenuItem::AddChild(std::unique_ptr<MenuItem> child_item) {
|
virtual void Quit() = 0;
|
||||||
children_.emplace_back(std::move(child_item));
|
};
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
} // namespace xe
|
} // namespace poly
|
||||||
|
|
||||||
|
#endif // POLY_UI_LOOP_H_
|
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <poly/ui/menu_item.h>
|
||||||
|
|
||||||
|
namespace poly {
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
MenuItem::MenuItem(Type type) : type_(type), parent_item_(nullptr) {}
|
||||||
|
|
||||||
|
MenuItem::~MenuItem() = default;
|
||||||
|
|
||||||
|
void MenuItem::AddChild(MenuItem* child_item) {
|
||||||
|
AddChild(MenuItemPtr(child_item, [](MenuItem* item) {}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MenuItem::AddChild(std::unique_ptr<MenuItem> child_item) {
|
||||||
|
AddChild(
|
||||||
|
MenuItemPtr(child_item.release(), [](MenuItem* item) { delete item; }));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MenuItem::AddChild(MenuItemPtr child_item) {
|
||||||
|
auto child_item_ptr = child_item.get();
|
||||||
|
children_.emplace_back(std::move(child_item));
|
||||||
|
OnChildAdded(child_item_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MenuItem::RemoveChild(MenuItem* child_item) {
|
||||||
|
for (auto& it = children_.begin(); it != children_.end(); ++it) {
|
||||||
|
if (it->get() == child_item) {
|
||||||
|
children_.erase(it);
|
||||||
|
OnChildRemoved(child_item);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MenuItem::OnSelected(UIEvent& e) {
|
||||||
|
on_selected(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace poly
|
|
@ -0,0 +1,61 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef POLY_UI_MENU_ITEM_H_
|
||||||
|
#define POLY_UI_MENU_ITEM_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <poly/delegate.h>
|
||||||
|
#include <poly/ui/ui_event.h>
|
||||||
|
|
||||||
|
namespace poly {
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
class Window;
|
||||||
|
|
||||||
|
class MenuItem {
|
||||||
|
public:
|
||||||
|
typedef std::unique_ptr<MenuItem, void (*)(MenuItem*)> MenuItemPtr;
|
||||||
|
|
||||||
|
enum class Type {
|
||||||
|
kNormal,
|
||||||
|
kSeparator,
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~MenuItem();
|
||||||
|
|
||||||
|
MenuItem* parent_item() const { return parent_item_; }
|
||||||
|
|
||||||
|
void AddChild(MenuItem* child_item);
|
||||||
|
void AddChild(std::unique_ptr<MenuItem> child_item);
|
||||||
|
void AddChild(MenuItemPtr child_item);
|
||||||
|
void RemoveChild(MenuItem* child_item);
|
||||||
|
|
||||||
|
poly::Delegate<UIEvent> on_selected;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MenuItem(Type type);
|
||||||
|
|
||||||
|
virtual void OnChildAdded(MenuItem* child_item) {}
|
||||||
|
virtual void OnChildRemoved(MenuItem* child_item) {}
|
||||||
|
|
||||||
|
virtual void OnSelected(UIEvent& e);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Type type_;
|
||||||
|
MenuItem* parent_item_;
|
||||||
|
std::vector<MenuItemPtr> children_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace poly
|
||||||
|
|
||||||
|
#endif // POLY_UI_MENU_ITEM_H_
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Copyright 2014 Ben Vanik. All Rights Reserved.
|
||||||
|
{
|
||||||
|
'sources': [
|
||||||
|
'control.cc',
|
||||||
|
'control.h',
|
||||||
|
'loop.h',
|
||||||
|
'menu_item.cc',
|
||||||
|
'menu_item.h',
|
||||||
|
'ui_event.h',
|
||||||
|
'window.h',
|
||||||
|
],
|
||||||
|
|
||||||
|
'conditions': [
|
||||||
|
['OS == "win"', {
|
||||||
|
'includes': [
|
||||||
|
'win32/sources.gypi',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
}
|
|
@ -7,32 +7,29 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef XENIA_UI_UI_EVENT_H_
|
#ifndef POLY_UI_UI_EVENT_H_
|
||||||
#define XENIA_UI_UI_EVENT_H_
|
#define POLY_UI_UI_EVENT_H_
|
||||||
|
|
||||||
#include <xenia/common.h>
|
namespace poly {
|
||||||
|
|
||||||
namespace xe {
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
class App;
|
class Control;
|
||||||
class Window;
|
|
||||||
|
|
||||||
class UIEvent {
|
class UIEvent {
|
||||||
public:
|
public:
|
||||||
UIEvent(Window* window = NULL) : window_(window) {}
|
UIEvent(Control* control = nullptr) : control_(control) {}
|
||||||
virtual ~UIEvent() = default;
|
virtual ~UIEvent() = default;
|
||||||
|
|
||||||
Window* window() const { return window_; }
|
Control* control() const { return control_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Window* window_;
|
Control* control_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class KeyEvent : public UIEvent {
|
class KeyEvent : public UIEvent {
|
||||||
public:
|
public:
|
||||||
KeyEvent(Window* window, int key_code)
|
KeyEvent(Control* control, int key_code)
|
||||||
: UIEvent(window), key_code_(key_code) {}
|
: UIEvent(control), key_code_(key_code) {}
|
||||||
~KeyEvent() override = default;
|
~KeyEvent() override = default;
|
||||||
|
|
||||||
int key_code() const { return key_code_; }
|
int key_code() const { return key_code_; }
|
||||||
|
@ -43,19 +40,19 @@ class KeyEvent : public UIEvent {
|
||||||
|
|
||||||
class MouseEvent : public UIEvent {
|
class MouseEvent : public UIEvent {
|
||||||
public:
|
public:
|
||||||
enum Button {
|
enum class Button {
|
||||||
MOUSE_BUTTON_NONE = 0,
|
kNone = 0,
|
||||||
MOUSE_BUTTON_LEFT,
|
kLeft,
|
||||||
MOUSE_BUTTON_RIGHT,
|
kRight,
|
||||||
MOUSE_BUTTON_MIDDLE,
|
kMiddle,
|
||||||
MOUSE_BUTTON_X1,
|
kX1,
|
||||||
MOUSE_BUTTON_X2,
|
kX2,
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MouseEvent(Window* window, Button button, int32_t x, int32_t y,
|
MouseEvent(Control* control, Button button, int32_t x, int32_t y,
|
||||||
int32_t dx = 0, int32_t dy = 0)
|
int32_t dx = 0, int32_t dy = 0)
|
||||||
: UIEvent(window), button_(button), x_(x), y_(y), dx_(dx), dy_(dy) {}
|
: UIEvent(control), button_(button), x_(x), y_(y), dx_(dx), dy_(dy) {}
|
||||||
~MouseEvent() override = default;
|
~MouseEvent() override = default;
|
||||||
|
|
||||||
Button button() const { return button_; }
|
Button button() const { return button_; }
|
||||||
|
@ -73,6 +70,6 @@ class MouseEvent : public UIEvent {
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
} // namespace xe
|
} // namespace poly
|
||||||
|
|
||||||
#endif // XENIA_UI_UI_EVENT_H_
|
#endif // POLY_UI_UI_EVENT_H_
|
|
@ -1,6 +1,8 @@
|
||||||
# Copyright 2014 Ben Vanik. All Rights Reserved.
|
# Copyright 2014 Ben Vanik. All Rights Reserved.
|
||||||
{
|
{
|
||||||
'sources': [
|
'sources': [
|
||||||
|
'win32_control.cc',
|
||||||
|
'win32_control.h',
|
||||||
'win32_loop.cc',
|
'win32_loop.cc',
|
||||||
'win32_loop.h',
|
'win32_loop.h',
|
||||||
'win32_menu_item.cc',
|
'win32_menu_item.cc',
|
|
@ -0,0 +1,314 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <poly/ui/win32/win32_control.h>
|
||||||
|
|
||||||
|
namespace poly {
|
||||||
|
namespace ui {
|
||||||
|
namespace win32 {
|
||||||
|
|
||||||
|
LRESULT CALLBACK
|
||||||
|
Win32Control::WndProcThunk(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||||
|
Win32Control* control = 0;
|
||||||
|
if (message == WM_NCCREATE) {
|
||||||
|
auto create_struct = reinterpret_cast<LPCREATESTRUCT>(lParam);
|
||||||
|
control = reinterpret_cast<Win32Control*>(create_struct->lpCreateParams);
|
||||||
|
SetWindowLongPtr(hWnd, GWLP_USERDATA, (__int3264)(LONG_PTR)control);
|
||||||
|
} else {
|
||||||
|
control =
|
||||||
|
reinterpret_cast<Win32Control*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
|
||||||
|
}
|
||||||
|
if (control) {
|
||||||
|
return control->WndProc(hWnd, message, wParam, lParam);
|
||||||
|
} else {
|
||||||
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Win32Control::Win32Control(Control* parent, uint32_t flags)
|
||||||
|
: Control(parent, flags), hwnd_(nullptr) {}
|
||||||
|
|
||||||
|
Win32Control::~Win32Control() {
|
||||||
|
if (hwnd_) {
|
||||||
|
CloseWindow(hwnd_);
|
||||||
|
hwnd_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32Control::OnCreate() {
|
||||||
|
Control::OnCreate();
|
||||||
|
if (!is_cursor_visible_) {
|
||||||
|
ShowCursor(FALSE);
|
||||||
|
}
|
||||||
|
if (!is_enabled_) {
|
||||||
|
EnableWindow(hwnd_, false);
|
||||||
|
}
|
||||||
|
if (!is_visible_) {
|
||||||
|
ShowWindow(hwnd_, SW_HIDE);
|
||||||
|
}
|
||||||
|
if (has_focus_) {
|
||||||
|
SetFocus(hwnd_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32Control::Resize(int32_t width, int32_t height) {
|
||||||
|
MoveWindow(hwnd_, 0, 0, width, height, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32Control::Resize(int32_t left, int32_t top, int32_t right,
|
||||||
|
int32_t bottom) {
|
||||||
|
MoveWindow(hwnd_, left, top, right - left, bottom - top, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32Control::ResizeToFill(int32_t pad_left, int32_t pad_top,
|
||||||
|
int32_t pad_right, int32_t pad_bottom) {
|
||||||
|
if (!parent_) {
|
||||||
|
// TODO(benvanik): screen?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RECT parent_rect;
|
||||||
|
auto parent_control = static_cast<Win32Control*>(parent_);
|
||||||
|
GetClientRect(parent_control->hwnd(), &parent_rect);
|
||||||
|
MoveWindow(hwnd_, parent_rect.left + pad_left, parent_rect.top + pad_top,
|
||||||
|
parent_rect.right - pad_right - pad_left,
|
||||||
|
parent_rect.right - pad_bottom - pad_top, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32Control::set_cursor_visible(bool value) {
|
||||||
|
if (is_cursor_visible_ == value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (value) {
|
||||||
|
ShowCursor(TRUE);
|
||||||
|
SetCursor(nullptr);
|
||||||
|
} else {
|
||||||
|
ShowCursor(FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32Control::set_enabled(bool value) {
|
||||||
|
if (is_enabled_ == value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (hwnd_) {
|
||||||
|
EnableWindow(hwnd_, value);
|
||||||
|
} else {
|
||||||
|
is_enabled_ = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32Control::set_visible(bool value) {
|
||||||
|
if (is_visible_ == value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (hwnd_) {
|
||||||
|
ShowWindow(hwnd_, value ? SW_SHOWNOACTIVATE : SW_HIDE);
|
||||||
|
} else {
|
||||||
|
is_visible_ = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32Control::set_focus(bool value) {
|
||||||
|
if (has_focus_ == value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (hwnd_) {
|
||||||
|
if (value) {
|
||||||
|
SetFocus(hwnd_);
|
||||||
|
} else {
|
||||||
|
SetFocus(nullptr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
has_focus_ = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT Win32Control::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||||
|
LPARAM lParam) {
|
||||||
|
if (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) {
|
||||||
|
if (HandleMouse(message, wParam, lParam)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||||
|
}
|
||||||
|
} else if (message >= WM_KEYFIRST && message <= WM_KEYLAST) {
|
||||||
|
if (HandleKeyboard(message, wParam, lParam)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (message) {
|
||||||
|
case WM_NCCREATE:
|
||||||
|
hwnd_ = hWnd;
|
||||||
|
break;
|
||||||
|
case WM_CREATE:
|
||||||
|
OnCreate();
|
||||||
|
break;
|
||||||
|
case WM_DESTROY:
|
||||||
|
OnDestroy();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_MOVING:
|
||||||
|
break;
|
||||||
|
case WM_MOVE:
|
||||||
|
break;
|
||||||
|
case WM_SIZING:
|
||||||
|
break;
|
||||||
|
case WM_SIZE: {
|
||||||
|
RECT client_rect;
|
||||||
|
GetClientRect(hwnd_, &client_rect);
|
||||||
|
int32_t width = client_rect.right - client_rect.left;
|
||||||
|
int32_t height = client_rect.bottom - client_rect.top;
|
||||||
|
if (width != width_ || height != height_) {
|
||||||
|
width_ = width;
|
||||||
|
height_ = height;
|
||||||
|
auto e = UIEvent(this);
|
||||||
|
OnResize(e);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WM_PAINT:
|
||||||
|
if (flags_ & kFlagOwnPaint) {
|
||||||
|
PAINTSTRUCT ps;
|
||||||
|
HDC hdc = BeginPaint(hWnd, &ps);
|
||||||
|
EndPaint(hWnd, &ps);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_ERASEBKGND:
|
||||||
|
if (flags_ & kFlagOwnPaint) {
|
||||||
|
return 0; // ignore
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_DISPLAYCHANGE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_SHOWWINDOW: {
|
||||||
|
if (wParam == TRUE) {
|
||||||
|
auto e = UIEvent(this);
|
||||||
|
OnVisible(e);
|
||||||
|
} else {
|
||||||
|
auto e = UIEvent(this);
|
||||||
|
OnHidden(e);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WM_KILLFOCUS: {
|
||||||
|
has_focus_ = false;
|
||||||
|
auto e = UIEvent(this);
|
||||||
|
OnLostFocus(e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WM_SETFOCUS: {
|
||||||
|
has_focus_ = true;
|
||||||
|
auto e = UIEvent(this);
|
||||||
|
OnGotFocus(e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Win32Control::HandleMouse(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||||
|
int32_t x = GET_X_LPARAM(lParam);
|
||||||
|
int32_t y = GET_Y_LPARAM(lParam);
|
||||||
|
if (message == WM_MOUSEWHEEL) {
|
||||||
|
POINT pt = {x, y};
|
||||||
|
ScreenToClient(hwnd_, &pt);
|
||||||
|
x = pt.x;
|
||||||
|
y = pt.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseEvent::Button button = MouseEvent::Button::kNone;
|
||||||
|
int32_t dx = 0;
|
||||||
|
int32_t dy = 0;
|
||||||
|
switch (message) {
|
||||||
|
case WM_LBUTTONDOWN:
|
||||||
|
case WM_LBUTTONUP:
|
||||||
|
button = MouseEvent::Button::kLeft;
|
||||||
|
break;
|
||||||
|
case WM_RBUTTONDOWN:
|
||||||
|
case WM_RBUTTONUP:
|
||||||
|
button = MouseEvent::Button::kRight;
|
||||||
|
break;
|
||||||
|
case WM_MBUTTONDOWN:
|
||||||
|
case WM_MBUTTONUP:
|
||||||
|
button = MouseEvent::Button::kMiddle;
|
||||||
|
break;
|
||||||
|
case WM_XBUTTONDOWN:
|
||||||
|
case WM_XBUTTONUP:
|
||||||
|
switch (GET_XBUTTON_WPARAM(wParam)) {
|
||||||
|
case XBUTTON1:
|
||||||
|
button = MouseEvent::Button::kX1;
|
||||||
|
break;
|
||||||
|
case XBUTTON2:
|
||||||
|
button = MouseEvent::Button::kX2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_MOUSEMOVE:
|
||||||
|
button = MouseEvent::Button::kNone;
|
||||||
|
break;
|
||||||
|
case WM_MOUSEWHEEL:
|
||||||
|
button = MouseEvent::Button::kNone;
|
||||||
|
dx = 0; // ?
|
||||||
|
dy = GET_WHEEL_DELTA_WPARAM(wParam);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Double click/etc?
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto e = MouseEvent(this, button, x, y, dx, dy);
|
||||||
|
switch (message) {
|
||||||
|
case WM_LBUTTONDOWN:
|
||||||
|
case WM_RBUTTONDOWN:
|
||||||
|
case WM_MBUTTONDOWN:
|
||||||
|
case WM_XBUTTONDOWN:
|
||||||
|
OnMouseDown(e);
|
||||||
|
break;
|
||||||
|
case WM_LBUTTONUP:
|
||||||
|
case WM_RBUTTONUP:
|
||||||
|
case WM_MBUTTONUP:
|
||||||
|
case WM_XBUTTONUP:
|
||||||
|
OnMouseUp(e);
|
||||||
|
break;
|
||||||
|
case WM_MOUSEMOVE:
|
||||||
|
OnMouseMove(e);
|
||||||
|
break;
|
||||||
|
case WM_MOUSEWHEEL:
|
||||||
|
OnMouseWheel(e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Win32Control::HandleKeyboard(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||||
|
auto e = KeyEvent(this, (int)wParam);
|
||||||
|
switch (message) {
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
OnKeyDown(e);
|
||||||
|
return true;
|
||||||
|
case WM_KEYUP:
|
||||||
|
OnKeyUp(e);
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace win32
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace poly
|
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef POLY_UI_WIN32_WIN32_CONTROL_H_
|
||||||
|
#define POLY_UI_WIN32_WIN32_CONTROL_H_
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <windowsx.h>
|
||||||
|
|
||||||
|
#include <poly/ui/control.h>
|
||||||
|
|
||||||
|
namespace poly {
|
||||||
|
namespace ui {
|
||||||
|
namespace win32 {
|
||||||
|
|
||||||
|
class Win32Control : public Control {
|
||||||
|
public:
|
||||||
|
~Win32Control() override;
|
||||||
|
|
||||||
|
HWND hwnd() const { return hwnd_; }
|
||||||
|
|
||||||
|
void Resize(int32_t width, int32_t height) override;
|
||||||
|
void Resize(int32_t left, int32_t top, int32_t right,
|
||||||
|
int32_t bottom) override;
|
||||||
|
void ResizeToFill(int32_t pad_left, int32_t pad_top, int32_t pad_right,
|
||||||
|
int32_t pad_bottom) override;
|
||||||
|
|
||||||
|
void set_cursor_visible(bool value) override;
|
||||||
|
void set_enabled(bool value) override;
|
||||||
|
void set_visible(bool value) override;
|
||||||
|
void set_focus(bool value) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Win32Control(Control* parent, uint32_t flags);
|
||||||
|
|
||||||
|
virtual bool CreateHWND() = 0;
|
||||||
|
|
||||||
|
void OnCreate() override;
|
||||||
|
|
||||||
|
static LRESULT CALLBACK
|
||||||
|
WndProcThunk(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||||||
|
virtual LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||||
|
LPARAM lParam);
|
||||||
|
|
||||||
|
HWND hwnd_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool HandleMouse(UINT message, WPARAM wParam, LPARAM lParam);
|
||||||
|
bool HandleKeyboard(UINT message, WPARAM wParam, LPARAM lParam);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace win32
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace poly
|
||||||
|
|
||||||
|
#endif // POLY_UI_WIN32_WIN32_CONTROL_H_
|
|
@ -0,0 +1,72 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <poly/ui/win32/win32_loop.h>
|
||||||
|
|
||||||
|
namespace poly {
|
||||||
|
namespace ui {
|
||||||
|
namespace win32 {
|
||||||
|
|
||||||
|
const DWORD kWmWin32LoopPost = WM_APP + 0x100;
|
||||||
|
const DWORD kWmWin32LoopQuit = WM_APP + 0x101;
|
||||||
|
|
||||||
|
class PostedFn {
|
||||||
|
public:
|
||||||
|
explicit PostedFn(std::function<void()> fn) : fn_(std::move(fn)) {}
|
||||||
|
void Call() { fn_(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::function<void()> fn_;
|
||||||
|
};
|
||||||
|
|
||||||
|
Win32Loop::Win32Loop() : thread_id_(0) {
|
||||||
|
thread_ = std::thread([this]() {
|
||||||
|
thread_id_ = GetCurrentThreadId();
|
||||||
|
ThreadMain();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Win32Loop::~Win32Loop() = default;
|
||||||
|
|
||||||
|
void Win32Loop::ThreadMain() {
|
||||||
|
MSG msg;
|
||||||
|
while (GetMessage(&msg, nullptr, 0, 0)) {
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
switch (msg.message) {
|
||||||
|
case kWmWin32LoopPost:
|
||||||
|
if (msg.wParam == reinterpret_cast<WPARAM>(this)) {
|
||||||
|
auto posted_fn = reinterpret_cast<PostedFn*>(msg.lParam);
|
||||||
|
posted_fn->Call();
|
||||||
|
delete posted_fn;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case kWmWin32LoopQuit:
|
||||||
|
if (msg.wParam == reinterpret_cast<WPARAM>(this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32Loop::Post(std::function<void()> fn) {
|
||||||
|
PostThreadMessage(thread_id_, kWmWin32LoopPost,
|
||||||
|
reinterpret_cast<WPARAM>(this),
|
||||||
|
reinterpret_cast<LPARAM>(new PostedFn(std::move(fn))));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32Loop::Quit() {
|
||||||
|
PostThreadMessage(thread_id_, kWmWin32LoopQuit,
|
||||||
|
reinterpret_cast<WPARAM>(this), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace win32
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace poly
|
|
@ -7,30 +7,38 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef XENIA_UI_WIN32_WIN32_LOOP_H_
|
#ifndef POLY_UI_WIN32_WIN32_LOOP_H_
|
||||||
#define XENIA_UI_WIN32_WIN32_LOOP_H_
|
#define POLY_UI_WIN32_WIN32_LOOP_H_
|
||||||
|
|
||||||
#include <xenia/common.h>
|
#include <windows.h>
|
||||||
|
#include <windowsx.h>
|
||||||
|
|
||||||
#include <xenia/ui/menu_item.h>
|
#include <thread>
|
||||||
|
|
||||||
namespace xe {
|
#include <poly/ui/loop.h>
|
||||||
|
|
||||||
|
namespace poly {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
namespace win32 {
|
namespace win32 {
|
||||||
|
|
||||||
class Win32Loop {
|
class Win32Loop : public Loop {
|
||||||
public:
|
public:
|
||||||
Win32Loop();
|
Win32Loop();
|
||||||
~Win32Loop();
|
~Win32Loop();
|
||||||
|
|
||||||
bool Run();
|
void Post(std::function<void()> fn) override;
|
||||||
void Quit();
|
|
||||||
|
void Quit() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void ThreadMain();
|
||||||
|
|
||||||
|
std::thread thread_;
|
||||||
|
DWORD thread_id_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace win32
|
} // namespace win32
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
} // namespace xe
|
} // namespace poly
|
||||||
|
|
||||||
#endif // XENIA_UI_WIN32_WIN32_LOOP_H_
|
#endif // POLY_UI_WIN32_WIN32_LOOP_H_
|
|
@ -0,0 +1,37 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <poly/ui/win32/win32_menu_item.h>
|
||||||
|
|
||||||
|
namespace poly {
|
||||||
|
namespace ui {
|
||||||
|
namespace win32 {
|
||||||
|
|
||||||
|
Win32MenuItem::Win32MenuItem(Type type)
|
||||||
|
: MenuItem(type), handle_(CreateMenu()) {}
|
||||||
|
|
||||||
|
Win32MenuItem::~Win32MenuItem() {
|
||||||
|
if (handle_) {
|
||||||
|
DestroyMenu(handle_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32MenuItem::OnChildAdded(MenuItem* generic_child_item) {
|
||||||
|
auto child_item = static_cast<Win32MenuItem*>(generic_child_item);
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32MenuItem::OnChildRemoved(MenuItem* generic_child_item) {
|
||||||
|
auto child_item = static_cast<Win32MenuItem*>(generic_child_item);
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace win32
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace poly
|
|
@ -7,26 +7,34 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef XENIA_UI_WIN32_WIN32_MENU_ITEM_H_
|
#ifndef POLY_UI_WIN32_WIN32_MENU_ITEM_H_
|
||||||
#define XENIA_UI_WIN32_WIN32_MENU_ITEM_H_
|
#define POLY_UI_WIN32_WIN32_MENU_ITEM_H_
|
||||||
|
|
||||||
#include <xenia/common.h>
|
#include <windows.h>
|
||||||
#include <xenia/ui/menu_item.h>
|
#include <windowsx.h>
|
||||||
|
|
||||||
namespace xe {
|
#include <poly/ui/menu_item.h>
|
||||||
|
|
||||||
|
namespace poly {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
namespace win32 {
|
namespace win32 {
|
||||||
|
|
||||||
class Win32MenuItem : public MenuItem {
|
class Win32MenuItem : public MenuItem {
|
||||||
public:
|
public:
|
||||||
Win32MenuItem(Window* window);
|
|
||||||
~Win32MenuItem() override;
|
~Win32MenuItem() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void OnChildAdded(MenuItem* child_item) override;
|
||||||
|
void OnChildRemoved(MenuItem* child_item) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Win32MenuItem(Type type);
|
||||||
|
|
||||||
|
HMENU handle_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace win32
|
} // namespace win32
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
} // namespace xe
|
} // namespace poly
|
||||||
|
|
||||||
#endif // XENIA_UI_WIN32_WIN32_MENU_ITEM_H_
|
#endif // POLY_UI_WIN32_WIN32_MENU_ITEM_H_
|
|
@ -0,0 +1,189 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <poly/ui/win32/win32_window.h>
|
||||||
|
|
||||||
|
#include <dwmapi.h>
|
||||||
|
#include <tpcshrd.h>
|
||||||
|
#include <windowsx.h>
|
||||||
|
|
||||||
|
#include <poly/logging.h>
|
||||||
|
|
||||||
|
namespace poly {
|
||||||
|
namespace ui {
|
||||||
|
namespace win32 {
|
||||||
|
|
||||||
|
Win32Window::Win32Window(const std::wstring& title)
|
||||||
|
: Window(title), main_menu_(nullptr), closing_(false) {}
|
||||||
|
|
||||||
|
Win32Window::~Win32Window() {}
|
||||||
|
|
||||||
|
bool Win32Window::CreateHWND() {
|
||||||
|
HINSTANCE hInstance = GetModuleHandle(nullptr);
|
||||||
|
|
||||||
|
WNDCLASSEX wcex;
|
||||||
|
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||||
|
wcex.style = CS_OWNDC;
|
||||||
|
wcex.lpfnWndProc = Win32Control::WndProcThunk;
|
||||||
|
wcex.cbClsExtra = 0;
|
||||||
|
wcex.cbWndExtra = 0;
|
||||||
|
wcex.hInstance = hInstance;
|
||||||
|
wcex.hIcon = nullptr; // LoadIcon(hInstance, (LPCTSTR)IDI_TUTORIAL1);
|
||||||
|
wcex.hIconSm = nullptr; // LoadIcon(hInstance, (LPCTSTR)IDI_TUTORIAL1);
|
||||||
|
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||||
|
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||||
|
wcex.lpszMenuName = nullptr;
|
||||||
|
wcex.lpszClassName = L"XeniaWindowClass";
|
||||||
|
if (!RegisterClassEx(&wcex)) {
|
||||||
|
PLOGE("RegisterClassEx failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup initial size.
|
||||||
|
DWORD window_style = WS_OVERLAPPEDWINDOW;
|
||||||
|
DWORD window_ex_style = WS_EX_APPWINDOW;
|
||||||
|
RECT rc = {0, 0, width_, height_};
|
||||||
|
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
|
||||||
|
|
||||||
|
// Create window.
|
||||||
|
hwnd_ = CreateWindowEx(window_ex_style, L"XeniaWindowClass", L"Xenia",
|
||||||
|
window_style, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||||
|
rc.right - rc.left, rc.bottom - rc.top, nullptr,
|
||||||
|
nullptr, hInstance, this);
|
||||||
|
if (!hwnd_) {
|
||||||
|
PLOGE("CreateWindow failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
main_menu_ = CreateMenu();
|
||||||
|
SetMenu(hwnd_, main_menu_);
|
||||||
|
|
||||||
|
// Disable flicks.
|
||||||
|
ATOM atom = GlobalAddAtom(L"MicrosoftTabletPenServiceProperty");
|
||||||
|
const DWORD_PTR dwHwndTabletProperty =
|
||||||
|
TABLET_DISABLE_PRESSANDHOLD | // disables press and hold (right-click)
|
||||||
|
// gesture
|
||||||
|
TABLET_DISABLE_PENTAPFEEDBACK | // disables UI feedback on pen up (waves)
|
||||||
|
TABLET_DISABLE_PENBARRELFEEDBACK | // disables UI feedback on pen button
|
||||||
|
// down (circle)
|
||||||
|
TABLET_DISABLE_FLICKS | // disables pen flicks (back, forward, drag down,
|
||||||
|
// drag up)
|
||||||
|
TABLET_DISABLE_TOUCHSWITCH | TABLET_DISABLE_SMOOTHSCROLLING |
|
||||||
|
TABLET_DISABLE_TOUCHUIFORCEON | TABLET_ENABLE_MULTITOUCHDATA;
|
||||||
|
SetProp(hwnd_, L"MicrosoftTabletPenServiceProperty",
|
||||||
|
reinterpret_cast<HANDLE>(dwHwndTabletProperty));
|
||||||
|
GlobalDeleteAtom(atom);
|
||||||
|
|
||||||
|
// Enable DWM elevation.
|
||||||
|
EnableMMCSS();
|
||||||
|
|
||||||
|
ShowWindow(hwnd_, SW_SHOWNORMAL);
|
||||||
|
UpdateWindow(hwnd_);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32Window::EnableMMCSS() {
|
||||||
|
HMODULE hLibrary = LoadLibrary(L"DWMAPI.DLL");
|
||||||
|
if (!hLibrary) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef HRESULT(__stdcall * PDwmEnableMMCSS)(BOOL);
|
||||||
|
PDwmEnableMMCSS pDwmEnableMMCSS =
|
||||||
|
(PDwmEnableMMCSS)GetProcAddress(hLibrary, "DwmEnableMMCSS");
|
||||||
|
if (pDwmEnableMMCSS) {
|
||||||
|
pDwmEnableMMCSS(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef HRESULT(__stdcall * PDwmSetPresentParameters)(
|
||||||
|
HWND, DWM_PRESENT_PARAMETERS*);
|
||||||
|
PDwmSetPresentParameters pDwmSetPresentParameters =
|
||||||
|
(PDwmSetPresentParameters)GetProcAddress(hLibrary,
|
||||||
|
"DwmSetPresentParameters");
|
||||||
|
if (pDwmSetPresentParameters) {
|
||||||
|
DWM_PRESENT_PARAMETERS pp;
|
||||||
|
memset(&pp, 0, sizeof(DWM_PRESENT_PARAMETERS));
|
||||||
|
pp.cbSize = sizeof(DWM_PRESENT_PARAMETERS);
|
||||||
|
pp.fQueue = FALSE;
|
||||||
|
pp.cBuffer = 2;
|
||||||
|
pp.fUseSourceRate = FALSE;
|
||||||
|
pp.cRefreshesPerFrame = 1;
|
||||||
|
pp.eSampling = DWM_SOURCE_FRAME_SAMPLING_POINT;
|
||||||
|
pDwmSetPresentParameters(hwnd_, &pp);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeLibrary(hLibrary);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Win32Window::set_title(const std::wstring& title) {
|
||||||
|
if (!Window::set_title(title)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetWindowText(hwnd_, title.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bool Win32Window::SetSize(uint32_t width, uint32_t height) {
|
||||||
|
// RECT rc = {0, 0, static_cast<LONG>(width), static_cast<LONG>(height)};
|
||||||
|
// AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
|
||||||
|
// // TODO(benvanik): center?
|
||||||
|
// MoveWindow(handle_, 0, 0, rc.right - rc.left, rc.bottom - rc.top, TRUE);
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
void Win32Window::OnClose() {
|
||||||
|
if (!closing_ && hwnd_) {
|
||||||
|
closing_ = true;
|
||||||
|
CloseWindow(hwnd_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||||
|
LPARAM lParam) {
|
||||||
|
switch (message) {
|
||||||
|
case WM_ACTIVATEAPP:
|
||||||
|
if (wParam) {
|
||||||
|
// Made active.
|
||||||
|
OnShow();
|
||||||
|
} else {
|
||||||
|
// Made inactive.
|
||||||
|
OnHide();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_CLOSE:
|
||||||
|
closing_ = true;
|
||||||
|
Close();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_TABLET_QUERYSYSTEMGESTURESTATUS:
|
||||||
|
return TABLET_DISABLE_PRESSANDHOLD | // disables press and hold
|
||||||
|
// (right-click) gesture
|
||||||
|
TABLET_DISABLE_PENTAPFEEDBACK | // disables UI feedback on pen up
|
||||||
|
// (waves)
|
||||||
|
TABLET_DISABLE_PENBARRELFEEDBACK | // disables UI feedback on pen
|
||||||
|
// button down (circle)
|
||||||
|
TABLET_DISABLE_FLICKS | // disables pen flicks (back, forward,
|
||||||
|
// drag down, drag up)
|
||||||
|
TABLET_DISABLE_TOUCHSWITCH | TABLET_DISABLE_SMOOTHSCROLLING |
|
||||||
|
TABLET_DISABLE_TOUCHUIFORCEON | TABLET_ENABLE_MULTITOUCHDATA;
|
||||||
|
|
||||||
|
case WM_COMMAND:
|
||||||
|
switch (LOWORD(wParam)) {
|
||||||
|
// TODO(benvanik): dispatch to menu.
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace win32
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace poly
|
|
@ -7,47 +7,42 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef XENIA_UI_WIN32_WIN32_WINDOW_H_
|
#ifndef POLY_UI_WIN32_WIN32_WINDOW_H_
|
||||||
#define XENIA_UI_WIN32_WIN32_WINDOW_H_
|
#define POLY_UI_WIN32_WIN32_WINDOW_H_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <xenia/common.h>
|
#include <poly/ui/win32/win32_control.h>
|
||||||
#include <xenia/ui/window.h>
|
#include <poly/ui/window.h>
|
||||||
|
|
||||||
namespace xe {
|
namespace poly {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
namespace win32 {
|
namespace win32 {
|
||||||
|
|
||||||
class Win32Window : public Window {
|
class Win32Window : public Window<Win32Control> {
|
||||||
public:
|
public:
|
||||||
Win32Window();
|
Win32Window(const std::wstring& title);
|
||||||
~Win32Window() override;
|
~Win32Window() override;
|
||||||
|
|
||||||
int Initialize(const std::wstring& title, uint32_t width,
|
|
||||||
uint32_t height) override;
|
|
||||||
|
|
||||||
bool set_title(const std::wstring& title) override;
|
bool set_title(const std::wstring& title) override;
|
||||||
bool set_cursor_visible(bool value) override;
|
|
||||||
HWND handle() const { return handle_; }
|
|
||||||
|
|
||||||
LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool SetSize(uint32_t width, uint32_t height) override;
|
bool CreateHWND() override;
|
||||||
|
|
||||||
void OnClose() override;
|
void OnClose() override;
|
||||||
|
|
||||||
|
LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||||
|
LPARAM lParam) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void EnableMMCSS();
|
void EnableMMCSS();
|
||||||
bool HandleMouse(UINT message, WPARAM wParam, LPARAM lParam);
|
|
||||||
bool HandleKeyboard(UINT message, WPARAM wParam, LPARAM lParam);
|
|
||||||
|
|
||||||
HWND handle_;
|
HMENU main_menu_;
|
||||||
bool closing_;
|
bool closing_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace win32
|
} // namespace win32
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
} // namespace xe
|
} // namespace poly
|
||||||
|
|
||||||
#endif // XENIA_UI_WIN32_WIN32_WINDOW_H_
|
#endif // POLY_UI_WIN32_WIN32_WINDOW_H_
|
|
@ -0,0 +1,84 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef POLY_UI_WINDOW_H_
|
||||||
|
#define POLY_UI_WINDOW_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <poly/delegate.h>
|
||||||
|
#include <poly/ui/control.h>
|
||||||
|
#include <poly/ui/ui_event.h>
|
||||||
|
|
||||||
|
namespace poly {
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Window : public T {
|
||||||
|
public:
|
||||||
|
~Window() override = default;
|
||||||
|
|
||||||
|
virtual bool Initialize() { return true; }
|
||||||
|
|
||||||
|
const std::wstring& title() const { return title_; }
|
||||||
|
virtual bool set_title(const std::wstring& title) {
|
||||||
|
if (title == title_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
title_ = title;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Close() {
|
||||||
|
auto e = UIEvent(this);
|
||||||
|
on_closing(e);
|
||||||
|
|
||||||
|
OnClose();
|
||||||
|
|
||||||
|
e = UIEvent(this);
|
||||||
|
on_closed(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
poly::Delegate<UIEvent> on_shown;
|
||||||
|
poly::Delegate<UIEvent> on_hidden;
|
||||||
|
poly::Delegate<UIEvent> on_closing;
|
||||||
|
poly::Delegate<UIEvent> on_closed;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Window(const std::wstring& title) : T(nullptr, 0), title_(title) {}
|
||||||
|
|
||||||
|
void OnShow() {
|
||||||
|
if (is_visible_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
is_visible_ = true;
|
||||||
|
auto e = UIEvent(this);
|
||||||
|
on_shown(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnHide() {
|
||||||
|
if (!is_visible_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
is_visible_ = false;
|
||||||
|
auto e = UIEvent(this);
|
||||||
|
on_hidden(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void OnClose() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::wstring title_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace poly
|
||||||
|
|
||||||
|
#endif // POLY_UI_WINDOW_H_
|
|
@ -20,7 +20,7 @@
|
||||||
#include <xenia/kernel/modules.h>
|
#include <xenia/kernel/modules.h>
|
||||||
#include <xenia/kernel/fs/filesystem.h>
|
#include <xenia/kernel/fs/filesystem.h>
|
||||||
#include <xenia/memory.h>
|
#include <xenia/memory.h>
|
||||||
#include <xenia/ui/window.h>
|
#include <xenia/ui/main_window.h>
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ using namespace xe::kernel::fs;
|
||||||
using namespace xe::ui;
|
using namespace xe::ui;
|
||||||
|
|
||||||
Emulator::Emulator(const std::wstring& command_line)
|
Emulator::Emulator(const std::wstring& command_line)
|
||||||
: command_line_(command_line), main_window_(nullptr) {}
|
: command_line_(command_line) {}
|
||||||
|
|
||||||
Emulator::~Emulator() {
|
Emulator::~Emulator() {
|
||||||
// Note that we delete things in the reverse order they were initialized.
|
// Note that we delete things in the reverse order they were initialized.
|
||||||
|
@ -43,10 +43,6 @@ Emulator::~Emulator() {
|
||||||
ev->type = xdb::protocol::EventType::PROCESS_EXIT;
|
ev->type = xdb::protocol::EventType::PROCESS_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (main_window_) {
|
|
||||||
main_window_->Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
debug_agent_.reset();
|
debug_agent_.reset();
|
||||||
|
|
||||||
xam_.reset();
|
xam_.reset();
|
||||||
|
@ -66,11 +62,20 @@ Emulator::~Emulator() {
|
||||||
processor_.reset();
|
processor_.reset();
|
||||||
|
|
||||||
export_resolver_.reset();
|
export_resolver_.reset();
|
||||||
|
|
||||||
|
// Kill the window last, as until the graphics system/etc is dead it's needed.
|
||||||
|
main_window_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
X_STATUS Emulator::Setup() {
|
X_STATUS Emulator::Setup() {
|
||||||
X_STATUS result = X_STATUS_UNSUCCESSFUL;
|
X_STATUS result = X_STATUS_UNSUCCESSFUL;
|
||||||
|
|
||||||
|
// Create the main window. Other parts will hook into this.
|
||||||
|
main_window_ = std::make_unique<ui::MainWindow>();
|
||||||
|
if (!main_window_->Initialize()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
debug_agent_.reset(new DebugAgent(this));
|
debug_agent_.reset(new DebugAgent(this));
|
||||||
result = debug_agent_->Initialize();
|
result = debug_agent_->Initialize();
|
||||||
if (result) {
|
if (result) {
|
||||||
|
@ -141,16 +146,6 @@ X_STATUS Emulator::Setup() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emulator::set_main_window(Window* window) {
|
|
||||||
assert_null(main_window_);
|
|
||||||
main_window_ = window;
|
|
||||||
|
|
||||||
window->closed.AddListener([](UIEvent& e) {
|
|
||||||
// TODO(benvanik): call module API to kill? this is a bad shutdown.
|
|
||||||
exit(1);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
X_STATUS Emulator::LaunchXexFile(const std::wstring& path) {
|
X_STATUS Emulator::LaunchXexFile(const std::wstring& path) {
|
||||||
// We create a virtual filesystem pointing to its directory and symlink
|
// We create a virtual filesystem pointing to its directory and symlink
|
||||||
// that to the game filesystem.
|
// that to the game filesystem.
|
||||||
|
|
|
@ -37,7 +37,7 @@ class XamModule;
|
||||||
class XboxkrnlModule;
|
class XboxkrnlModule;
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
namespace ui {
|
namespace ui {
|
||||||
class Window;
|
class MainWindow;
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
@ -52,8 +52,7 @@ class Emulator {
|
||||||
|
|
||||||
const std::wstring& command_line() const { return command_line_; }
|
const std::wstring& command_line() const { return command_line_; }
|
||||||
|
|
||||||
ui::Window* main_window() const { return main_window_; }
|
ui::MainWindow* main_window() const { return main_window_.get(); }
|
||||||
void set_main_window(ui::Window* window);
|
|
||||||
|
|
||||||
Memory* memory() const { return memory_.get(); }
|
Memory* memory() const { return memory_.get(); }
|
||||||
|
|
||||||
|
@ -85,8 +84,7 @@ class Emulator {
|
||||||
|
|
||||||
std::wstring command_line_;
|
std::wstring command_line_;
|
||||||
|
|
||||||
// TODO(benvanik): remove from here?
|
std::unique_ptr<ui::MainWindow> main_window_;
|
||||||
ui::Window* main_window_;
|
|
||||||
|
|
||||||
std::unique_ptr<Memory> memory_;
|
std::unique_ptr<Memory> memory_;
|
||||||
|
|
||||||
|
|
|
@ -7,16 +7,33 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <xenia/ui/win32/win32_menu_item.h>
|
#include <xenia/ui/main_window.h>
|
||||||
|
|
||||||
|
#include <poly/logging.h>
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
namespace win32 {
|
|
||||||
|
|
||||||
Win32MenuItem::Win32MenuItem(Window* window) : MenuItem(window) {}
|
MainWindow::MainWindow() : PlatformWindow(L"xenia") {}
|
||||||
|
|
||||||
Win32MenuItem::~Win32MenuItem() {}
|
MainWindow::~MainWindow() {}
|
||||||
|
|
||||||
|
void MainWindow::Start() {
|
||||||
|
loop_.Post([this]() {
|
||||||
|
if (!Initialize()) {
|
||||||
|
PFATAL("Failed to initialize main window");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::Initialize() {
|
||||||
|
if (!Window::Initialize()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace win32
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
} // namespace xe
|
} // namespace xe
|
|
@ -7,36 +7,37 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef XENIA_UI_MENU_ITEM_H_
|
#ifndef XENIA_UI_MAIN_WINDOW_H_
|
||||||
#define XENIA_UI_MENU_ITEM_H_
|
#define XENIA_UI_MAIN_WINDOW_H_
|
||||||
|
|
||||||
#include <memory>
|
#include <poly/ui/window.h>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <xenia/common.h>
|
// TODO(benvanik): only on windows.
|
||||||
|
#include <poly/ui/win32/win32_loop.h>
|
||||||
|
#include <poly/ui/win32/win32_window.h>
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
class Window;
|
using PlatformLoop = poly::ui::win32::Win32Loop;
|
||||||
|
using PlatformWindow = poly::ui::win32::Win32Window;
|
||||||
|
|
||||||
class MenuItem {
|
class MainWindow : public PlatformWindow {
|
||||||
public:
|
public:
|
||||||
MenuItem(Window* window);
|
MainWindow();
|
||||||
virtual ~MenuItem();
|
~MainWindow();
|
||||||
|
|
||||||
Window* window() const { return window_; }
|
PlatformLoop* loop() { return &loop_; }
|
||||||
MenuItem* parent_item() const { return parent_item_; }
|
|
||||||
|
|
||||||
virtual void AddChild(std::unique_ptr<MenuItem> child_item);
|
void Start();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Window* window_;
|
bool Initialize();
|
||||||
MenuItem* parent_item_;
|
|
||||||
std::vector<std::unique_ptr<MenuItem>> children_;
|
PlatformLoop loop_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
#endif // XENIA_UI_MENU_ITEM_H_
|
#endif // XENIA_UI_MAIN_WINDOW_H_
|
|
@ -1,18 +1,7 @@
|
||||||
# Copyright 2014 Ben Vanik. All Rights Reserved.
|
# Copyright 2014 Ben Vanik. All Rights Reserved.
|
||||||
{
|
{
|
||||||
'sources': [
|
'sources': [
|
||||||
'menu_item.cc',
|
'main_window.cc',
|
||||||
'menu_item.h',
|
'main_window.h',
|
||||||
'ui_event.h',
|
|
||||||
'window.cc',
|
|
||||||
'window.h',
|
|
||||||
],
|
|
||||||
|
|
||||||
'conditions': [
|
|
||||||
['OS == "win"', {
|
|
||||||
'includes': [
|
|
||||||
'win32/sources.gypi',
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
|
||||||
******************************************************************************
|
|
||||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
|
||||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <xenia/ui/win32/win32_loop.h>
|
|
||||||
|
|
||||||
namespace xe {
|
|
||||||
namespace ui {
|
|
||||||
namespace win32 {
|
|
||||||
|
|
||||||
const DWORD kWmWin32LoopQuit = WM_APP + 0x100;
|
|
||||||
|
|
||||||
Win32Loop::Win32Loop() {}
|
|
||||||
|
|
||||||
Win32Loop::~Win32Loop() {}
|
|
||||||
|
|
||||||
bool Win32Loop::Run() {
|
|
||||||
MSG msg;
|
|
||||||
while (GetMessage(&msg, nullptr, 0, 0)) {
|
|
||||||
TranslateMessage(&msg);
|
|
||||||
DispatchMessage(&msg);
|
|
||||||
switch (msg.message) {
|
|
||||||
case kWmWin32LoopQuit:
|
|
||||||
if (msg.wParam == reinterpret_cast<WPARAM>(this)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Win32Loop::Quit() {
|
|
||||||
PostMessage(nullptr, kWmWin32LoopQuit, reinterpret_cast<WPARAM>(this), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace win32
|
|
||||||
} // namespace ui
|
|
||||||
} // namespace xe
|
|
|
@ -1,352 +0,0 @@
|
||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
|
||||||
******************************************************************************
|
|
||||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
|
||||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <xenia/ui/win32/win32_window.h>
|
|
||||||
|
|
||||||
#include <dwmapi.h>
|
|
||||||
#include <tpcshrd.h>
|
|
||||||
#include <windowsx.h>
|
|
||||||
|
|
||||||
namespace xe {
|
|
||||||
namespace ui {
|
|
||||||
namespace win32 {
|
|
||||||
|
|
||||||
static LRESULT CALLBACK
|
|
||||||
Win32WindowWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
|
||||||
Win32Window* window = 0;
|
|
||||||
if (message == WM_NCCREATE) {
|
|
||||||
LPCREATESTRUCT create_struct = (LPCREATESTRUCT)lParam;
|
|
||||||
window = (Win32Window*)create_struct->lpCreateParams;
|
|
||||||
SetWindowLongPtr(hWnd, GWLP_USERDATA, (__int3264)(LONG_PTR)window);
|
|
||||||
} else {
|
|
||||||
window = (Win32Window*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
||||||
}
|
|
||||||
if (window) {
|
|
||||||
return window->WndProc(hWnd, message, wParam, lParam);
|
|
||||||
} else {
|
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Win32Window::Win32Window() : handle_(0), closing_(false) {}
|
|
||||||
|
|
||||||
Win32Window::~Win32Window() {
|
|
||||||
if (handle_) {
|
|
||||||
CloseWindow(handle_);
|
|
||||||
handle_ = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int Win32Window::Initialize(const std::wstring& title, uint32_t width,
|
|
||||||
uint32_t height) {
|
|
||||||
int result = Window::Initialize(title, width, height);
|
|
||||||
if (result) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
HINSTANCE hInstance = GetModuleHandle(NULL);
|
|
||||||
|
|
||||||
WNDCLASSEX wcex;
|
|
||||||
wcex.cbSize = sizeof(WNDCLASSEX);
|
|
||||||
wcex.style = CS_OWNDC;
|
|
||||||
wcex.lpfnWndProc = Win32WindowWndProc;
|
|
||||||
wcex.cbClsExtra = 0;
|
|
||||||
wcex.cbWndExtra = 0;
|
|
||||||
wcex.hInstance = hInstance;
|
|
||||||
wcex.hIcon = NULL; // LoadIcon(hInstance, (LPCTSTR)IDI_TUTORIAL1);
|
|
||||||
wcex.hIconSm = NULL; // LoadIcon(hInstance, (LPCTSTR)IDI_TUTORIAL1);
|
|
||||||
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
||||||
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
|
||||||
wcex.lpszMenuName = NULL;
|
|
||||||
wcex.lpszClassName = L"XeniaWindowClass";
|
|
||||||
if (!RegisterClassEx(&wcex)) {
|
|
||||||
XELOGE("RegisterClassEx failed");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup initial size.
|
|
||||||
DWORD window_style = WS_OVERLAPPEDWINDOW;
|
|
||||||
DWORD window_ex_style = WS_EX_APPWINDOW;
|
|
||||||
RECT rc = {0, 0, static_cast<LONG>(width), static_cast<LONG>(height)};
|
|
||||||
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
|
|
||||||
|
|
||||||
// Create window.
|
|
||||||
handle_ = CreateWindowEx(window_ex_style, L"XeniaWindowClass", L"Xenia",
|
|
||||||
window_style, CW_USEDEFAULT, CW_USEDEFAULT,
|
|
||||||
rc.right - rc.left, rc.bottom - rc.top, NULL, NULL,
|
|
||||||
hInstance, this);
|
|
||||||
if (!handle_) {
|
|
||||||
XELOGE("CreateWindow failed");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable flicks.
|
|
||||||
ATOM atom = GlobalAddAtom(L"MicrosoftTabletPenServiceProperty");
|
|
||||||
const DWORD_PTR dwHwndTabletProperty =
|
|
||||||
TABLET_DISABLE_PRESSANDHOLD | // disables press and hold (right-click)
|
|
||||||
// gesture
|
|
||||||
TABLET_DISABLE_PENTAPFEEDBACK | // disables UI feedback on pen up (waves)
|
|
||||||
TABLET_DISABLE_PENBARRELFEEDBACK | // disables UI feedback on pen button
|
|
||||||
// down (circle)
|
|
||||||
TABLET_DISABLE_FLICKS | // disables pen flicks (back, forward, drag down,
|
|
||||||
// drag up)
|
|
||||||
TABLET_DISABLE_TOUCHSWITCH | TABLET_DISABLE_SMOOTHSCROLLING |
|
|
||||||
TABLET_DISABLE_TOUCHUIFORCEON | TABLET_ENABLE_MULTITOUCHDATA;
|
|
||||||
SetProp(handle_, L"MicrosoftTabletPenServiceProperty",
|
|
||||||
reinterpret_cast<HANDLE>(dwHwndTabletProperty));
|
|
||||||
GlobalDeleteAtom(atom);
|
|
||||||
|
|
||||||
// Enable DWM elevation.
|
|
||||||
EnableMMCSS();
|
|
||||||
|
|
||||||
ShowWindow(handle_, SW_SHOWNORMAL);
|
|
||||||
UpdateWindow(handle_);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Win32Window::EnableMMCSS() {
|
|
||||||
HMODULE hLibrary = LoadLibrary(L"DWMAPI.DLL");
|
|
||||||
if (!hLibrary) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef HRESULT(__stdcall * PDwmEnableMMCSS)(BOOL);
|
|
||||||
PDwmEnableMMCSS pDwmEnableMMCSS =
|
|
||||||
(PDwmEnableMMCSS)GetProcAddress(hLibrary, "DwmEnableMMCSS");
|
|
||||||
if (pDwmEnableMMCSS) {
|
|
||||||
pDwmEnableMMCSS(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef HRESULT(__stdcall * PDwmSetPresentParameters)(
|
|
||||||
HWND, DWM_PRESENT_PARAMETERS*);
|
|
||||||
PDwmSetPresentParameters pDwmSetPresentParameters =
|
|
||||||
(PDwmSetPresentParameters)GetProcAddress(hLibrary,
|
|
||||||
"DwmSetPresentParameters");
|
|
||||||
if (pDwmSetPresentParameters) {
|
|
||||||
DWM_PRESENT_PARAMETERS pp;
|
|
||||||
memset(&pp, 0, sizeof(DWM_PRESENT_PARAMETERS));
|
|
||||||
pp.cbSize = sizeof(DWM_PRESENT_PARAMETERS);
|
|
||||||
pp.fQueue = FALSE;
|
|
||||||
pp.cBuffer = 2;
|
|
||||||
pp.fUseSourceRate = FALSE;
|
|
||||||
pp.cRefreshesPerFrame = 1;
|
|
||||||
pp.eSampling = DWM_SOURCE_FRAME_SAMPLING_POINT;
|
|
||||||
pDwmSetPresentParameters(handle_, &pp);
|
|
||||||
}
|
|
||||||
|
|
||||||
FreeLibrary(hLibrary);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Win32Window::set_title(const std::wstring& title) {
|
|
||||||
if (!Window::set_title(title)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
SetWindowText(handle_, title.c_str());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Win32Window::set_cursor_visible(bool value) {
|
|
||||||
if (!Window::set_cursor_visible(value)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (value) {
|
|
||||||
ShowCursor(TRUE);
|
|
||||||
SetCursor(NULL);
|
|
||||||
} else {
|
|
||||||
ShowCursor(FALSE);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Win32Window::SetSize(uint32_t width, uint32_t height) {
|
|
||||||
RECT rc = {0, 0, static_cast<LONG>(width), static_cast<LONG>(height)};
|
|
||||||
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
|
|
||||||
// TODO(benvanik): center?
|
|
||||||
MoveWindow(handle_, 0, 0, rc.right - rc.left, rc.bottom - rc.top, TRUE);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Win32Window::OnClose() {
|
|
||||||
if (!closing_ && handle_) {
|
|
||||||
closing_ = true;
|
|
||||||
CloseWindow(handle_);
|
|
||||||
handle_ = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Win32Window::HandleMouse(UINT message, WPARAM wParam, LPARAM lParam) {
|
|
||||||
int32_t x = GET_X_LPARAM(lParam);
|
|
||||||
int32_t y = GET_Y_LPARAM(lParam);
|
|
||||||
if (message == WM_MOUSEWHEEL) {
|
|
||||||
POINT pt = {x, y};
|
|
||||||
ScreenToClient(handle_, &pt);
|
|
||||||
x = pt.x;
|
|
||||||
y = pt.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseEvent::Button button = MouseEvent::MOUSE_BUTTON_NONE;
|
|
||||||
int32_t dx = 0;
|
|
||||||
int32_t dy = 0;
|
|
||||||
switch (message) {
|
|
||||||
case WM_LBUTTONDOWN:
|
|
||||||
case WM_LBUTTONUP:
|
|
||||||
button = MouseEvent::MOUSE_BUTTON_LEFT;
|
|
||||||
break;
|
|
||||||
case WM_RBUTTONDOWN:
|
|
||||||
case WM_RBUTTONUP:
|
|
||||||
button = MouseEvent::MOUSE_BUTTON_RIGHT;
|
|
||||||
break;
|
|
||||||
case WM_MBUTTONDOWN:
|
|
||||||
case WM_MBUTTONUP:
|
|
||||||
button = MouseEvent::MOUSE_BUTTON_MIDDLE;
|
|
||||||
break;
|
|
||||||
case WM_XBUTTONDOWN:
|
|
||||||
case WM_XBUTTONUP:
|
|
||||||
switch (GET_XBUTTON_WPARAM(wParam)) {
|
|
||||||
case XBUTTON1:
|
|
||||||
button = MouseEvent::MOUSE_BUTTON_X1;
|
|
||||||
break;
|
|
||||||
case XBUTTON2:
|
|
||||||
button = MouseEvent::MOUSE_BUTTON_X2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case WM_MOUSEMOVE:
|
|
||||||
button = MouseEvent::MOUSE_BUTTON_NONE;
|
|
||||||
break;
|
|
||||||
case WM_MOUSEWHEEL:
|
|
||||||
button = MouseEvent::MOUSE_BUTTON_NONE;
|
|
||||||
dx = 0; // ?
|
|
||||||
dy = GET_WHEEL_DELTA_WPARAM(wParam);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Double click/etc?
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto e = MouseEvent(this, button, x, y, dx, dy);
|
|
||||||
switch (message) {
|
|
||||||
case WM_LBUTTONDOWN:
|
|
||||||
case WM_RBUTTONDOWN:
|
|
||||||
case WM_MBUTTONDOWN:
|
|
||||||
case WM_XBUTTONDOWN:
|
|
||||||
mouse_down(e);
|
|
||||||
break;
|
|
||||||
case WM_LBUTTONUP:
|
|
||||||
case WM_RBUTTONUP:
|
|
||||||
case WM_MBUTTONUP:
|
|
||||||
case WM_XBUTTONUP:
|
|
||||||
mouse_up(e);
|
|
||||||
break;
|
|
||||||
case WM_MOUSEMOVE:
|
|
||||||
mouse_move(e);
|
|
||||||
break;
|
|
||||||
case WM_MOUSEWHEEL:
|
|
||||||
mouse_wheel(e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Win32Window::HandleKeyboard(UINT message, WPARAM wParam, LPARAM lParam) {
|
|
||||||
auto e = KeyEvent(this, (int)wParam);
|
|
||||||
switch (message) {
|
|
||||||
case WM_KEYDOWN:
|
|
||||||
key_down(e);
|
|
||||||
return true;
|
|
||||||
case WM_KEYUP:
|
|
||||||
key_up(e);
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LRESULT Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
|
||||||
LPARAM lParam) {
|
|
||||||
if (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) {
|
|
||||||
if (HandleMouse(message, wParam, lParam)) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
||||||
}
|
|
||||||
} else if (message >= WM_KEYFIRST && message <= WM_KEYLAST) {
|
|
||||||
if (HandleKeyboard(message, wParam, lParam)) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (message) {
|
|
||||||
case WM_NCCREATE:
|
|
||||||
handle_ = hWnd;
|
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
||||||
case WM_ACTIVATEAPP:
|
|
||||||
if (wParam) {
|
|
||||||
// Made active.
|
|
||||||
OnShow();
|
|
||||||
} else {
|
|
||||||
// Made inactive.
|
|
||||||
OnHide();
|
|
||||||
}
|
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
||||||
case WM_CLOSE:
|
|
||||||
closing_ = true;
|
|
||||||
Close();
|
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
||||||
case WM_DESTROY:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case WM_PAINT: {
|
|
||||||
PAINTSTRUCT ps;
|
|
||||||
HDC hdc = BeginPaint(hWnd, &ps);
|
|
||||||
EndPaint(hWnd, &ps);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
case WM_ERASEBKGND:
|
|
||||||
return 0; // ignore
|
|
||||||
case WM_DISPLAYCHANGE:
|
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
||||||
|
|
||||||
case WM_MOVE:
|
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
||||||
case WM_SIZING:
|
|
||||||
BeginResizing();
|
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
||||||
case WM_SIZE: {
|
|
||||||
RECT frame;
|
|
||||||
GetClientRect(handle_, &frame);
|
|
||||||
OnResize(frame.right - frame.left, frame.bottom - frame.top);
|
|
||||||
EndResizing();
|
|
||||||
}
|
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
||||||
|
|
||||||
case WM_TABLET_QUERYSYSTEMGESTURESTATUS:
|
|
||||||
return TABLET_DISABLE_PRESSANDHOLD | // disables press and hold
|
|
||||||
// (right-click) gesture
|
|
||||||
TABLET_DISABLE_PENTAPFEEDBACK | // disables UI feedback on pen up
|
|
||||||
// (waves)
|
|
||||||
TABLET_DISABLE_PENBARRELFEEDBACK | // disables UI feedback on pen
|
|
||||||
// button down (circle)
|
|
||||||
TABLET_DISABLE_FLICKS | // disables pen flicks (back, forward,
|
|
||||||
// drag down, drag up)
|
|
||||||
TABLET_DISABLE_TOUCHSWITCH | TABLET_DISABLE_SMOOTHSCROLLING |
|
|
||||||
TABLET_DISABLE_TOUCHUIFORCEON | TABLET_ENABLE_MULTITOUCHDATA;
|
|
||||||
default:
|
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace win32
|
|
||||||
} // namespace ui
|
|
||||||
} // namespace xe
|
|
|
@ -1,114 +0,0 @@
|
||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
|
||||||
******************************************************************************
|
|
||||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
|
||||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <xenia/ui/window.h>
|
|
||||||
|
|
||||||
namespace xe {
|
|
||||||
namespace ui {
|
|
||||||
|
|
||||||
Window::Window()
|
|
||||||
: title_(L"Window"),
|
|
||||||
is_visible_(true),
|
|
||||||
is_cursor_visible_(true),
|
|
||||||
width_(0),
|
|
||||||
height_(0) {}
|
|
||||||
|
|
||||||
Window::~Window() {}
|
|
||||||
|
|
||||||
int Window::Initialize(const std::wstring& title, uint32_t width,
|
|
||||||
uint32_t height) {
|
|
||||||
title_ = title;
|
|
||||||
width_ = width;
|
|
||||||
height_ = height;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Window::set_title(const std::wstring& title) {
|
|
||||||
if (title == title_) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
title_ = title;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Window::set_cursor_visible(bool value) {
|
|
||||||
if (value == is_cursor_visible_) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
is_cursor_visible_ = value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::OnShow() {
|
|
||||||
if (is_visible_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
is_visible_ = true;
|
|
||||||
auto e = UIEvent(this);
|
|
||||||
shown(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::OnHide() {
|
|
||||||
if (!is_visible_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
is_visible_ = false;
|
|
||||||
auto e = UIEvent(this);
|
|
||||||
hidden(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::Resize(uint32_t width, uint32_t height) {
|
|
||||||
BeginResizing();
|
|
||||||
SetSize(width, height);
|
|
||||||
OnResize(width, height); // redundant?
|
|
||||||
EndResizing();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::BeginResizing() {
|
|
||||||
if (resizing_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resizing_ = true;
|
|
||||||
auto e = UIEvent(this);
|
|
||||||
resizing(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Window::OnResize(uint32_t width, uint32_t height) {
|
|
||||||
if (!resizing_) {
|
|
||||||
BeginResizing();
|
|
||||||
}
|
|
||||||
if (width == width_ && height == height_) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
width_ = width;
|
|
||||||
height_ = height;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::EndResizing() {
|
|
||||||
assert_true(resizing_);
|
|
||||||
resizing_ = false;
|
|
||||||
auto e = UIEvent(this);
|
|
||||||
resized(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::Close() {
|
|
||||||
auto e = UIEvent(this);
|
|
||||||
closing(e);
|
|
||||||
|
|
||||||
OnClose();
|
|
||||||
|
|
||||||
e = UIEvent(this);
|
|
||||||
closed(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::OnClose() {}
|
|
||||||
|
|
||||||
} // namespace ui
|
|
||||||
} // namespace xe
|
|
|
@ -1,80 +0,0 @@
|
||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
|
||||||
******************************************************************************
|
|
||||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
|
||||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef XENIA_UI_WINDOW_H_
|
|
||||||
#define XENIA_UI_WINDOW_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <poly/delegate.h>
|
|
||||||
#include <xenia/common.h>
|
|
||||||
#include <xenia/ui/ui_event.h>
|
|
||||||
|
|
||||||
namespace xe {
|
|
||||||
namespace ui {
|
|
||||||
|
|
||||||
class Window {
|
|
||||||
public:
|
|
||||||
Window();
|
|
||||||
virtual ~Window();
|
|
||||||
|
|
||||||
virtual int Initialize(const std::wstring& title, uint32_t width,
|
|
||||||
uint32_t height);
|
|
||||||
|
|
||||||
const std::wstring& title() const { return title_; }
|
|
||||||
virtual bool set_title(const std::wstring& title);
|
|
||||||
bool is_visible() const { return is_visible_; }
|
|
||||||
bool is_cursor_visible() const { return is_cursor_visible_; }
|
|
||||||
virtual bool set_cursor_visible(bool value);
|
|
||||||
uint32_t width() const { return width_; }
|
|
||||||
uint32_t height() const { return height_; }
|
|
||||||
void Resize(uint32_t width, uint32_t height);
|
|
||||||
|
|
||||||
void Close();
|
|
||||||
|
|
||||||
public:
|
|
||||||
poly::Delegate<UIEvent> shown;
|
|
||||||
poly::Delegate<UIEvent> hidden;
|
|
||||||
poly::Delegate<UIEvent> resizing;
|
|
||||||
poly::Delegate<UIEvent> resized;
|
|
||||||
poly::Delegate<UIEvent> closing;
|
|
||||||
poly::Delegate<UIEvent> closed;
|
|
||||||
|
|
||||||
poly::Delegate<KeyEvent> key_down;
|
|
||||||
poly::Delegate<KeyEvent> key_up;
|
|
||||||
|
|
||||||
poly::Delegate<MouseEvent> mouse_down;
|
|
||||||
poly::Delegate<MouseEvent> mouse_move;
|
|
||||||
poly::Delegate<MouseEvent> mouse_up;
|
|
||||||
poly::Delegate<MouseEvent> mouse_wheel;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void OnShow();
|
|
||||||
void OnHide();
|
|
||||||
|
|
||||||
void BeginResizing();
|
|
||||||
virtual bool OnResize(uint32_t width, uint32_t height);
|
|
||||||
void EndResizing();
|
|
||||||
virtual bool SetSize(uint32_t width, uint32_t height) = 0;
|
|
||||||
|
|
||||||
virtual void OnClose();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::wstring title_;
|
|
||||||
bool is_visible_;
|
|
||||||
bool is_cursor_visible_;
|
|
||||||
bool resizing_;
|
|
||||||
uint32_t width_;
|
|
||||||
uint32_t height_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace ui
|
|
||||||
} // namespace xe
|
|
||||||
|
|
||||||
#endif // XENIA_UI_WINDOW_H_
|
|
Loading…
Reference in New Issue