Code cleanup: moving poly::ui to xe::ui
This commit is contained in:
@@ -142,7 +142,8 @@ GL4ProfilerDisplay::GL4ProfilerDisplay(WGLControl* control)
|
||||
vao_(0),
|
||||
font_texture_(0),
|
||||
font_handle_(0),
|
||||
vertex_buffer_(MICROPROFILE_MAX_VERTICES * sizeof(Vertex) * 10, sizeof(Vertex)),
|
||||
vertex_buffer_(MICROPROFILE_MAX_VERTICES * sizeof(Vertex) * 10,
|
||||
sizeof(Vertex)),
|
||||
draw_command_count_(0) {
|
||||
if (!SetupFont() || !SetupState() || !SetupShaders()) {
|
||||
// Hrm.
|
||||
@@ -150,32 +151,32 @@ GL4ProfilerDisplay::GL4ProfilerDisplay(WGLControl* control)
|
||||
}
|
||||
|
||||
// Pass through mouse events.
|
||||
control->on_mouse_down.AddListener([](poly::ui::MouseEvent& e) {
|
||||
Profiler::OnMouseDown(e.button() == poly::ui::MouseEvent::Button::kLeft,
|
||||
e.button() == poly::ui::MouseEvent::Button::kRight);
|
||||
control->on_mouse_down.AddListener([](xe::ui::MouseEvent& e) {
|
||||
Profiler::OnMouseDown(e.button() == xe::ui::MouseEvent::Button::kLeft,
|
||||
e.button() == xe::ui::MouseEvent::Button::kRight);
|
||||
e.set_handled(true);
|
||||
});
|
||||
control->on_mouse_up.AddListener([](poly::ui::MouseEvent& e) {
|
||||
control->on_mouse_up.AddListener([](xe::ui::MouseEvent& e) {
|
||||
Profiler::OnMouseUp();
|
||||
e.set_handled(true);
|
||||
});
|
||||
control->on_mouse_move.AddListener([](poly::ui::MouseEvent& e) {
|
||||
control->on_mouse_move.AddListener([](xe::ui::MouseEvent& e) {
|
||||
Profiler::OnMouseMove(e.x(), e.y());
|
||||
e.set_handled(true);
|
||||
});
|
||||
control->on_mouse_wheel.AddListener([](poly::ui::MouseEvent& e) {
|
||||
control->on_mouse_wheel.AddListener([](xe::ui::MouseEvent& e) {
|
||||
Profiler::OnMouseWheel(e.x(), e.y(), -e.dy());
|
||||
e.set_handled(true);
|
||||
});
|
||||
|
||||
// Watch for toggle/mode keys and such.
|
||||
control->on_key_down.AddListener([](poly::ui::KeyEvent& e) {
|
||||
control->on_key_down.AddListener([](xe::ui::KeyEvent& e) {
|
||||
Profiler::OnKeyDown(e.key_code());
|
||||
//e.set_handled(true);
|
||||
// e.set_handled(true);
|
||||
});
|
||||
control->on_key_up.AddListener([](poly::ui::KeyEvent& e) {
|
||||
control->on_key_up.AddListener([](xe::ui::KeyEvent& e) {
|
||||
Profiler::OnKeyUp(e.key_code());
|
||||
//e.set_handled(true);
|
||||
// e.set_handled(true);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -258,7 +259,7 @@ struct VertexData { \n\
|
||||
};\n\
|
||||
";
|
||||
const std::string vertex_shader_source = header +
|
||||
"\n\
|
||||
"\n\
|
||||
layout(location = 0) uniform mat4 projection_matrix; \n\
|
||||
struct VertexFetch { \n\
|
||||
vec2 pos; \n\
|
||||
@@ -274,7 +275,7 @@ void main() { \n\
|
||||
} \n\
|
||||
";
|
||||
const std::string fragment_shader_source = header +
|
||||
"\n\
|
||||
"\n\
|
||||
layout(location = 1, bindless_sampler) uniform sampler2D font_texture; \n\
|
||||
layout(location = 2) uniform float font_height; \n\
|
||||
layout(location = 0) in VertexData vtx; \n\
|
||||
|
||||
@@ -21,8 +21,8 @@ namespace gl4 {
|
||||
extern "C" GLEWContext* glewGetContext();
|
||||
extern "C" WGLEWContext* wglewGetContext();
|
||||
|
||||
WGLControl::WGLControl(poly::ui::Loop* loop)
|
||||
: poly::ui::win32::Win32Control(Flags::kFlagOwnPaint), loop_(loop) {}
|
||||
WGLControl::WGLControl(xe::ui::Loop* loop)
|
||||
: xe::ui::win32::Win32Control(Flags::kFlagOwnPaint), loop_(loop) {}
|
||||
|
||||
WGLControl::~WGLControl() = default;
|
||||
|
||||
@@ -70,7 +70,7 @@ bool WGLControl::Create() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void WGLControl::OnLayout(poly::ui::UIEvent& e) { Control::ResizeToFill(); }
|
||||
void WGLControl::OnLayout(xe::ui::UIEvent& e) { Control::ResizeToFill(); }
|
||||
|
||||
LRESULT WGLControl::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
LPARAM lParam) {
|
||||
@@ -89,7 +89,7 @@ LRESULT WGLControl::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
current_paint_callback_ = nullptr;
|
||||
}
|
||||
|
||||
poly::ui::UIEvent e(this);
|
||||
xe::ui::UIEvent e(this);
|
||||
OnPaint(e);
|
||||
|
||||
// TODO(benvanik): profiler present.
|
||||
|
||||
@@ -13,17 +13,17 @@
|
||||
#include <functional>
|
||||
|
||||
#include "poly/threading.h"
|
||||
#include "poly/ui/loop.h"
|
||||
#include "poly/ui/win32/win32_control.h"
|
||||
#include "xenia/gpu/gl4/gl_context.h"
|
||||
#include "xenia/ui/loop.h"
|
||||
#include "xenia/ui/win32/win32_control.h"
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
namespace gl4 {
|
||||
|
||||
class WGLControl : public poly::ui::win32::Win32Control {
|
||||
class WGLControl : public xe::ui::win32::Win32Control {
|
||||
public:
|
||||
WGLControl(poly::ui::Loop* loop);
|
||||
WGLControl(xe::ui::Loop* loop);
|
||||
~WGLControl() override;
|
||||
|
||||
GLContext* context() { return &context_; }
|
||||
@@ -33,13 +33,13 @@ class WGLControl : public poly::ui::win32::Win32Control {
|
||||
protected:
|
||||
bool Create() override;
|
||||
|
||||
void OnLayout(poly::ui::UIEvent& e) override;
|
||||
void OnLayout(xe::ui::UIEvent& e) override;
|
||||
|
||||
LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
LPARAM lParam) override;
|
||||
|
||||
private:
|
||||
poly::ui::Loop* loop_;
|
||||
xe::ui::Loop* loop_;
|
||||
GLContext context_;
|
||||
std::function<void()> current_paint_callback_;
|
||||
};
|
||||
|
||||
@@ -767,7 +767,7 @@ class TraceReader {
|
||||
|
||||
class TracePlayer : public TraceReader {
|
||||
public:
|
||||
TracePlayer(poly::ui::Loop* loop, GraphicsSystem* graphics_system)
|
||||
TracePlayer(xe::ui::Loop* loop, GraphicsSystem* graphics_system)
|
||||
: loop_(loop),
|
||||
graphics_system_(graphics_system),
|
||||
current_frame_index_(0),
|
||||
@@ -827,7 +827,7 @@ class TracePlayer : public TraceReader {
|
||||
}
|
||||
|
||||
private:
|
||||
poly::ui::Loop* loop_;
|
||||
xe::ui::Loop* loop_;
|
||||
GraphicsSystem* graphics_system_;
|
||||
int current_frame_index_;
|
||||
int current_command_index_;
|
||||
@@ -2213,7 +2213,7 @@ int trace_viewer_main(std::vector<std::wstring>& args) {
|
||||
}
|
||||
|
||||
auto control = window->child(0);
|
||||
control->on_key_char.AddListener([graphics_system](poly::ui::KeyEvent& e) {
|
||||
control->on_key_char.AddListener([graphics_system](xe::ui::KeyEvent& e) {
|
||||
auto& io = ImGui::GetIO();
|
||||
if (e.key_code() > 0 && e.key_code() < 0x10000) {
|
||||
if (e.key_code() == 0x74 /* VK_F5 */) {
|
||||
@@ -2224,41 +2224,41 @@ int trace_viewer_main(std::vector<std::wstring>& args) {
|
||||
}
|
||||
e.set_handled(true);
|
||||
});
|
||||
control->on_mouse_down.AddListener([](poly::ui::MouseEvent& e) {
|
||||
control->on_mouse_down.AddListener([](xe::ui::MouseEvent& e) {
|
||||
auto& io = ImGui::GetIO();
|
||||
io.MousePos = ImVec2(float(e.x()), float(e.y()));
|
||||
switch (e.button()) {
|
||||
case poly::ui::MouseEvent::Button::kLeft:
|
||||
case xe::ui::MouseEvent::Button::kLeft:
|
||||
io.MouseDown[0] = true;
|
||||
break;
|
||||
case poly::ui::MouseEvent::Button::kRight:
|
||||
case xe::ui::MouseEvent::Button::kRight:
|
||||
io.MouseDown[1] = true;
|
||||
break;
|
||||
}
|
||||
});
|
||||
control->on_mouse_move.AddListener([](poly::ui::MouseEvent& e) {
|
||||
control->on_mouse_move.AddListener([](xe::ui::MouseEvent& e) {
|
||||
auto& io = ImGui::GetIO();
|
||||
io.MousePos = ImVec2(float(e.x()), float(e.y()));
|
||||
});
|
||||
control->on_mouse_up.AddListener([](poly::ui::MouseEvent& e) {
|
||||
control->on_mouse_up.AddListener([](xe::ui::MouseEvent& e) {
|
||||
auto& io = ImGui::GetIO();
|
||||
io.MousePos = ImVec2(float(e.x()), float(e.y()));
|
||||
switch (e.button()) {
|
||||
case poly::ui::MouseEvent::Button::kLeft:
|
||||
case xe::ui::MouseEvent::Button::kLeft:
|
||||
io.MouseDown[0] = false;
|
||||
break;
|
||||
case poly::ui::MouseEvent::Button::kRight:
|
||||
case xe::ui::MouseEvent::Button::kRight:
|
||||
io.MouseDown[1] = false;
|
||||
break;
|
||||
}
|
||||
});
|
||||
control->on_mouse_wheel.AddListener([](poly::ui::MouseEvent& e) {
|
||||
control->on_mouse_wheel.AddListener([](xe::ui::MouseEvent& e) {
|
||||
auto& io = ImGui::GetIO();
|
||||
io.MousePos = ImVec2(float(e.x()), float(e.y()));
|
||||
io.MouseWheel += float(e.dy() / 120.0f);
|
||||
});
|
||||
|
||||
control->on_paint.AddListener([&](poly::ui::UIEvent& e) {
|
||||
control->on_paint.AddListener([&](xe::ui::UIEvent& e) {
|
||||
static bool imgui_setup = false;
|
||||
if (!imgui_setup) {
|
||||
ImImpl_Setup();
|
||||
|
||||
132
src/xenia/ui/control.cc
Normal file
132
src/xenia/ui/control.cc
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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/control.h"
|
||||
|
||||
#include "poly/assert.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
|
||||
Control::Control(uint32_t flags)
|
||||
: flags_(flags),
|
||||
parent_(nullptr),
|
||||
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) {
|
||||
assert_null(control->parent());
|
||||
control->parent_ = this;
|
||||
auto control_ptr = control.get();
|
||||
children_.emplace_back(std::move(control));
|
||||
OnChildAdded(control_ptr);
|
||||
}
|
||||
|
||||
Control::ControlPtr Control::RemoveChild(Control* child_control) {
|
||||
assert_true(child_control->parent() == this);
|
||||
for (auto& it = children_.begin(); it != children_.end(); ++it) {
|
||||
if (it->get() == child_control) {
|
||||
auto control_ptr = std::move(*it);
|
||||
child_control->parent_ = nullptr;
|
||||
children_.erase(it);
|
||||
OnChildRemoved(child_control);
|
||||
return control_ptr;
|
||||
}
|
||||
}
|
||||
return ControlPtr(nullptr, [](Control*) {});
|
||||
}
|
||||
|
||||
void Control::Layout() {
|
||||
auto e = UIEvent(this);
|
||||
OnLayout(e);
|
||||
for (auto& child_control : children_) {
|
||||
child_control->OnLayout(e);
|
||||
}
|
||||
}
|
||||
|
||||
void Control::OnResize(UIEvent& e) { on_resize(e); }
|
||||
|
||||
void Control::OnLayout(UIEvent& e) { on_layout(e); }
|
||||
|
||||
void Control::OnPaint(UIEvent& e) { on_paint(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);
|
||||
if (parent_ && !e.is_handled()) {
|
||||
parent_->OnKeyDown(e);
|
||||
}
|
||||
}
|
||||
|
||||
void Control::OnKeyUp(KeyEvent& e) {
|
||||
on_key_up(e);
|
||||
if (parent_ && !e.is_handled()) {
|
||||
parent_->OnKeyUp(e);
|
||||
}
|
||||
}
|
||||
|
||||
void Control::OnKeyChar(KeyEvent& e) {
|
||||
on_key_char(e);
|
||||
if (parent_ && !e.is_handled()) {
|
||||
parent_->OnKeyChar(e);
|
||||
}
|
||||
}
|
||||
|
||||
void Control::OnMouseDown(MouseEvent& e) {
|
||||
on_mouse_down(e);
|
||||
if (parent_ && !e.is_handled()) {
|
||||
parent_->OnMouseDown(e);
|
||||
}
|
||||
}
|
||||
|
||||
void Control::OnMouseMove(MouseEvent& e) {
|
||||
on_mouse_move(e);
|
||||
if (parent_ && !e.is_handled()) {
|
||||
parent_->OnMouseMove(e);
|
||||
}
|
||||
}
|
||||
|
||||
void Control::OnMouseUp(MouseEvent& e) {
|
||||
on_mouse_up(e);
|
||||
if (parent_ && !e.is_handled()) {
|
||||
parent_->OnMouseUp(e);
|
||||
}
|
||||
}
|
||||
|
||||
void Control::OnMouseWheel(MouseEvent& e) {
|
||||
on_mouse_wheel(e);
|
||||
if (parent_ && !e.is_handled()) {
|
||||
parent_->OnMouseWheel(e);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
134
src/xenia/ui/control.h
Normal file
134
src/xenia/ui/control.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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_CONTROL_H_
|
||||
#define XENIA_UI_CONTROL_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "poly/delegate.h"
|
||||
#include "xenia/ui/ui_event.h"
|
||||
|
||||
namespace xe {
|
||||
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_; }
|
||||
|
||||
size_t child_count() const { return children_.size(); }
|
||||
Control* child(size_t i) const { return children_[i].get(); }
|
||||
void AddChild(Control* child_control);
|
||||
void AddChild(std::unique_ptr<Control> child_control);
|
||||
void AddChild(ControlPtr child_control);
|
||||
ControlPtr 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;
|
||||
void ResizeToFill() { ResizeToFill(0, 0, 0, 0); }
|
||||
virtual void ResizeToFill(int32_t pad_left, int32_t pad_top,
|
||||
int32_t pad_right, int32_t pad_bottom) = 0;
|
||||
void Layout();
|
||||
virtual void Invalidate() {}
|
||||
|
||||
// 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_layout;
|
||||
poly::Delegate<UIEvent> on_paint;
|
||||
|
||||
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<KeyEvent> on_key_char;
|
||||
|
||||
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:
|
||||
explicit Control(uint32_t flags);
|
||||
|
||||
virtual bool Create() = 0;
|
||||
virtual void Destroy() {}
|
||||
|
||||
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 OnLayout(UIEvent& e);
|
||||
virtual void OnPaint(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 OnKeyChar(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 xe
|
||||
|
||||
#endif // XENIA_UI_CONTROL_H_
|
||||
32
src/xenia/ui/loop.h
Normal file
32
src/xenia/ui/loop.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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_LOOP_H_
|
||||
#define XENIA_UI_LOOP_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
|
||||
class Loop {
|
||||
public:
|
||||
Loop() = default;
|
||||
virtual ~Loop() = default;
|
||||
|
||||
virtual void Post(std::function<void()> fn) = 0;
|
||||
|
||||
virtual void Quit() = 0;
|
||||
virtual void AwaitQuit() = 0;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_UI_LOOP_H_
|
||||
@@ -46,7 +46,7 @@ bool MainWindow::Initialize() {
|
||||
return false;
|
||||
}
|
||||
Resize(1280, 720);
|
||||
on_key_down.AddListener([this](poly::ui::KeyEvent& e) {
|
||||
on_key_down.AddListener([this](KeyEvent& e) {
|
||||
bool handled = true;
|
||||
switch (e.key_code()) {
|
||||
case 0x73: { // VK_F4
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
#ifndef XENIA_UI_MAIN_WINDOW_H_
|
||||
#define XENIA_UI_MAIN_WINDOW_H_
|
||||
|
||||
#include "poly/ui/window.h"
|
||||
#include "xenia/ui/window.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
// TODO(benvanik): only on windows.
|
||||
#include "poly/ui/win32/win32_loop.h"
|
||||
#include "poly/ui/win32/win32_window.h"
|
||||
#include "xenia/ui/win32/win32_loop.h"
|
||||
#include "xenia/ui/win32/win32_window.h"
|
||||
|
||||
namespace xe {
|
||||
class Emulator;
|
||||
@@ -24,8 +24,8 @@ class Emulator;
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
|
||||
using PlatformLoop = poly::ui::win32::Win32Loop;
|
||||
using PlatformWindow = poly::ui::win32::Win32Window;
|
||||
using PlatformLoop = xe::ui::win32::Win32Loop;
|
||||
using PlatformWindow = xe::ui::win32::Win32Window;
|
||||
|
||||
class MainWindow : public PlatformWindow {
|
||||
public:
|
||||
|
||||
47
src/xenia/ui/menu_item.cc
Normal file
47
src/xenia/ui/menu_item.cc
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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/menu_item.h"
|
||||
|
||||
namespace xe {
|
||||
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 xe
|
||||
61
src/xenia/ui/menu_item.h
Normal file
61
src/xenia/ui/menu_item.h
Normal file
@@ -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 XENIA_UI_MENU_ITEM_H_
|
||||
#define XENIA_UI_MENU_ITEM_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "poly/delegate.h"
|
||||
#include "xenia/ui/ui_event.h"
|
||||
|
||||
namespace xe {
|
||||
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 xe
|
||||
|
||||
#endif // XENIA_UI_MENU_ITEM_H_
|
||||
@@ -1,7 +1,22 @@
|
||||
# Copyright 2014 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'control.cc',
|
||||
'control.h',
|
||||
'loop.h',
|
||||
'main_window.cc',
|
||||
'main_window.h',
|
||||
'menu_item.cc',
|
||||
'menu_item.h',
|
||||
'ui_event.h',
|
||||
'window.h',
|
||||
],
|
||||
|
||||
'conditions': [
|
||||
['OS == "win"', {
|
||||
'includes': [
|
||||
'win32/sources.gypi',
|
||||
],
|
||||
}],
|
||||
],
|
||||
}
|
||||
|
||||
89
src/xenia/ui/ui_event.h
Normal file
89
src/xenia/ui/ui_event.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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_UI_EVENT_H_
|
||||
#define XENIA_UI_UI_EVENT_H_
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
|
||||
class Control;
|
||||
|
||||
class UIEvent {
|
||||
public:
|
||||
UIEvent(Control* control = nullptr) : control_(control) {}
|
||||
virtual ~UIEvent() = default;
|
||||
|
||||
Control* control() const { return control_; }
|
||||
|
||||
private:
|
||||
Control* control_;
|
||||
};
|
||||
|
||||
class KeyEvent : public UIEvent {
|
||||
public:
|
||||
KeyEvent(Control* control, int key_code)
|
||||
: UIEvent(control), handled_(false), key_code_(key_code) {}
|
||||
~KeyEvent() override = default;
|
||||
|
||||
bool is_handled() const { return handled_; }
|
||||
void set_handled(bool value) { handled_ = value; }
|
||||
|
||||
int key_code() const { return key_code_; }
|
||||
|
||||
private:
|
||||
bool handled_;
|
||||
int key_code_;
|
||||
};
|
||||
|
||||
class MouseEvent : public UIEvent {
|
||||
public:
|
||||
enum class Button {
|
||||
kNone = 0,
|
||||
kLeft,
|
||||
kRight,
|
||||
kMiddle,
|
||||
kX1,
|
||||
kX2,
|
||||
};
|
||||
|
||||
public:
|
||||
MouseEvent(Control* control, Button button, int32_t x, int32_t y,
|
||||
int32_t dx = 0, int32_t dy = 0)
|
||||
: UIEvent(control),
|
||||
handled_(false),
|
||||
button_(button),
|
||||
x_(x),
|
||||
y_(y),
|
||||
dx_(dx),
|
||||
dy_(dy) {}
|
||||
~MouseEvent() override = default;
|
||||
|
||||
bool is_handled() const { return handled_; }
|
||||
void set_handled(bool value) { handled_ = value; }
|
||||
|
||||
Button button() const { return button_; }
|
||||
int32_t x() const { return x_; }
|
||||
int32_t y() const { return y_; }
|
||||
int32_t dx() const { return dx_; }
|
||||
int32_t dy() const { return dy_; }
|
||||
|
||||
private:
|
||||
bool handled_;
|
||||
Button button_;
|
||||
int32_t x_;
|
||||
int32_t y_;
|
||||
int32_t dx_;
|
||||
int32_t dy_;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_UI_UI_EVENT_H_
|
||||
13
src/xenia/ui/win32/sources.gypi
Normal file
13
src/xenia/ui/win32/sources.gypi
Normal file
@@ -0,0 +1,13 @@
|
||||
# Copyright 2014 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'win32_control.cc',
|
||||
'win32_control.h',
|
||||
'win32_loop.cc',
|
||||
'win32_loop.h',
|
||||
'win32_menu_item.cc',
|
||||
'win32_menu_item.h',
|
||||
'win32_window.cc',
|
||||
'win32_window.h',
|
||||
],
|
||||
}
|
||||
368
src/xenia/ui/win32/win32_control.cc
Normal file
368
src/xenia/ui/win32/win32_control.cc
Normal file
@@ -0,0 +1,368 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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_control.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace win32 {
|
||||
|
||||
Win32Control::Win32Control(uint32_t flags) : Control(flags), hwnd_(nullptr) {}
|
||||
|
||||
Win32Control::~Win32Control() {
|
||||
if (hwnd_) {
|
||||
CloseWindow(hwnd_);
|
||||
hwnd_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Win32Control::OnCreate() {
|
||||
Control::OnCreate();
|
||||
|
||||
// Create all children, if needed.
|
||||
for (auto& child_control : children_) {
|
||||
auto win32_control = static_cast<Win32Control*>(child_control.get());
|
||||
if (!win32_control->hwnd()) {
|
||||
win32_control->Create();
|
||||
} else {
|
||||
SetParent(win32_control->hwnd(), hwnd());
|
||||
}
|
||||
win32_control->Layout();
|
||||
}
|
||||
|
||||
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::OnDestroy() {
|
||||
// Destroy all children, if needed.
|
||||
for (auto& child_control : children_) {
|
||||
auto win32_control = static_cast<Win32Control*>(child_control.get());
|
||||
if (!win32_control->hwnd()) {
|
||||
win32_control->Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Win32Control::OnChildAdded(Control* child_control) {
|
||||
auto win32_control = static_cast<Win32Control*>(child_control);
|
||||
if (hwnd_) {
|
||||
if (!win32_control->hwnd()) {
|
||||
win32_control->Create();
|
||||
} else {
|
||||
SetParent(win32_control->hwnd(), hwnd());
|
||||
}
|
||||
child_control->Layout();
|
||||
}
|
||||
}
|
||||
|
||||
void Win32Control::OnChildRemoved(Control* child_control) {
|
||||
auto win32_control = static_cast<Win32Control*>(child_control);
|
||||
if (win32_control->hwnd()) {
|
||||
SetParent(win32_control->hwnd(), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
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.bottom - pad_bottom - pad_top, TRUE);
|
||||
}
|
||||
|
||||
void Win32Control::OnResize(UIEvent& e) {
|
||||
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;
|
||||
Layout();
|
||||
for (auto& child_control : children_) {
|
||||
auto win32_control = static_cast<Win32Control*>(child_control.get());
|
||||
win32_control->OnResize(e);
|
||||
win32_control->Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Win32Control::Invalidate() {
|
||||
InvalidateRect(hwnd_, nullptr, FALSE);
|
||||
for (auto& child_control : children_) {
|
||||
auto win32_control = static_cast<Win32Control*>(child_control.get());
|
||||
win32_control->Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
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 CALLBACK Win32Control::WndProcThunk(HWND hWnd, UINT message,
|
||||
WPARAM wParam, LPARAM lParam) {
|
||||
Win32Control* control = nullptr;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT Win32Control::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
LPARAM lParam) {
|
||||
if (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) {
|
||||
if (HandleMouse(message, wParam, lParam)) {
|
||||
SetFocus(hwnd_);
|
||||
return 0;
|
||||
} else {
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
} else if (message >= WM_KEYFIRST && message <= WM_KEYLAST) {
|
||||
if (HandleKeyboard(message, wParam, lParam)) {
|
||||
SetFocus(hwnd_);
|
||||
return 0;
|
||||
} else {
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
switch (message) {
|
||||
case WM_NCCREATE:
|
||||
break;
|
||||
case WM_CREATE:
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
OnDestroy();
|
||||
break;
|
||||
|
||||
case WM_MOVING:
|
||||
break;
|
||||
case WM_MOVE:
|
||||
break;
|
||||
case WM_SIZING:
|
||||
break;
|
||||
case WM_SIZE: {
|
||||
auto e = UIEvent(this);
|
||||
OnResize(e);
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_PAINT:
|
||||
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 e.is_handled();
|
||||
}
|
||||
|
||||
bool Win32Control::HandleKeyboard(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
auto e = KeyEvent(this, (int)wParam);
|
||||
switch (message) {
|
||||
case WM_KEYDOWN:
|
||||
OnKeyDown(e);
|
||||
break;
|
||||
case WM_KEYUP:
|
||||
OnKeyUp(e);
|
||||
break;
|
||||
case WM_CHAR:
|
||||
OnKeyChar(e);
|
||||
break;
|
||||
}
|
||||
return e.is_handled();
|
||||
}
|
||||
|
||||
} // namespace win32
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
70
src/xenia/ui/win32/win32_control.h
Normal file
70
src/xenia/ui/win32/win32_control.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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_WIN32_WIN32_CONTROL_H_
|
||||
#define XENIA_UI_WIN32_WIN32_CONTROL_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
|
||||
#include "xenia/ui/control.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace win32 {
|
||||
|
||||
class Win32Control : public Control {
|
||||
public:
|
||||
~Win32Control() override;
|
||||
|
||||
HWND hwnd() const { return hwnd_; }
|
||||
HWND parent_hwnd() const {
|
||||
return parent_ ? static_cast<Win32Control*>(parent_)->hwnd() : nullptr;
|
||||
}
|
||||
|
||||
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 Invalidate() 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:
|
||||
explicit Win32Control(uint32_t flags);
|
||||
|
||||
void OnCreate() override;
|
||||
void OnDestroy() override;
|
||||
|
||||
void OnChildAdded(Control* child_control) override;
|
||||
void OnChildRemoved(Control* child_control) override;
|
||||
|
||||
void OnResize(UIEvent& e) 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 xe
|
||||
|
||||
#endif // XENIA_UI_WIN32_WIN32_CONTROL_H_
|
||||
92
src/xenia/ui/win32/win32_loop.cc
Normal file
92
src/xenia/ui/win32/win32_loop.cc
Normal file
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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"
|
||||
|
||||
#include "poly/assert.h"
|
||||
|
||||
namespace xe {
|
||||
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) {
|
||||
poly::threading::Fence init_fence;
|
||||
thread_ = std::thread([&]() {
|
||||
poly::threading::set_name("Win32 Loop");
|
||||
thread_id_ = GetCurrentThreadId();
|
||||
|
||||
// Make a Win32 call to enable the thread queue.
|
||||
MSG msg;
|
||||
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
|
||||
|
||||
init_fence.Signal();
|
||||
|
||||
ThreadMain();
|
||||
|
||||
quit_fence_.Signal();
|
||||
});
|
||||
init_fence.Wait();
|
||||
}
|
||||
|
||||
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) {
|
||||
assert_true(thread_id_ != 0);
|
||||
if (!PostThreadMessage(
|
||||
thread_id_, kWmWin32LoopPost, reinterpret_cast<WPARAM>(this),
|
||||
reinterpret_cast<LPARAM>(new PostedFn(std::move(fn))))) {
|
||||
assert_always("Unable to post message to thread queue");
|
||||
}
|
||||
}
|
||||
|
||||
void Win32Loop::Quit() {
|
||||
assert_true(thread_id_ != 0);
|
||||
PostThreadMessage(thread_id_, kWmWin32LoopQuit,
|
||||
reinterpret_cast<WPARAM>(this), 0);
|
||||
}
|
||||
|
||||
void Win32Loop::AwaitQuit() { quit_fence_.Wait(); }
|
||||
|
||||
} // namespace win32
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
50
src/xenia/ui/win32/win32_loop.h
Normal file
50
src/xenia/ui/win32/win32_loop.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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_WIN32_WIN32_LOOP_H_
|
||||
#define XENIA_UI_WIN32_WIN32_LOOP_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include "poly/threading.h"
|
||||
#include "xenia/ui/loop.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace win32 {
|
||||
|
||||
class Win32Loop : public Loop {
|
||||
public:
|
||||
Win32Loop();
|
||||
~Win32Loop() override;
|
||||
|
||||
void Post(std::function<void()> fn) override;
|
||||
|
||||
void Quit() override;
|
||||
void AwaitQuit() override;
|
||||
|
||||
private:
|
||||
void ThreadMain();
|
||||
|
||||
std::thread thread_;
|
||||
DWORD thread_id_;
|
||||
poly::threading::Fence quit_fence_;
|
||||
};
|
||||
|
||||
} // namespace win32
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_UI_WIN32_WIN32_LOOP_H_
|
||||
37
src/xenia/ui/win32/win32_menu_item.cc
Normal file
37
src/xenia/ui/win32/win32_menu_item.cc
Normal file
@@ -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 "xenia/ui/win32/win32_menu_item.h"
|
||||
|
||||
namespace xe {
|
||||
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 xe
|
||||
40
src/xenia/ui/win32/win32_menu_item.h
Normal file
40
src/xenia/ui/win32/win32_menu_item.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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_WIN32_WIN32_MENU_ITEM_H_
|
||||
#define XENIA_UI_WIN32_WIN32_MENU_ITEM_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
|
||||
#include "xenia/ui/menu_item.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace win32 {
|
||||
|
||||
class Win32MenuItem : public MenuItem {
|
||||
public:
|
||||
~Win32MenuItem() override;
|
||||
|
||||
protected:
|
||||
void OnChildAdded(MenuItem* child_item) override;
|
||||
void OnChildRemoved(MenuItem* child_item) override;
|
||||
|
||||
private:
|
||||
Win32MenuItem(Type type);
|
||||
|
||||
HMENU handle_;
|
||||
};
|
||||
|
||||
} // namespace win32
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_UI_WIN32_WIN32_MENU_ITEM_H_
|
||||
212
src/xenia/ui/win32/win32_window.cc
Normal file
212
src/xenia/ui/win32/win32_window.cc
Normal file
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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>
|
||||
|
||||
#include "poly/logging.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace win32 {
|
||||
|
||||
Win32Window::Win32Window(const std::wstring& title)
|
||||
: Window(title), main_menu_(nullptr), closing_(false) {}
|
||||
|
||||
Win32Window::~Win32Window() {}
|
||||
|
||||
bool Win32Window::Initialize() {
|
||||
Create();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Win32Window::Create() {
|
||||
HINSTANCE hInstance = GetModuleHandle(nullptr);
|
||||
|
||||
WNDCLASSEX wcex;
|
||||
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW | 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 | WS_EX_CONTROLPARENT;
|
||||
RECT rc = {0, 0, width_, height_};
|
||||
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
|
||||
|
||||
// Create window.
|
||||
hwnd_ = CreateWindowEx(window_ex_style, L"XeniaWindowClass", L"Xenia",
|
||||
window_style, rc.left, rc.top, rc.right - rc.left,
|
||||
rc.bottom - rc.top, nullptr, nullptr, hInstance, this);
|
||||
if (!hwnd_) {
|
||||
PLOGE("CreateWindow failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
main_menu_ = CreateMenu();
|
||||
AppendMenu(main_menu_, MF_STRING, 0, L"TODO");
|
||||
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;
|
||||
}
|
||||
|
||||
void Win32Window::Resize(int32_t width, int32_t height) {
|
||||
RECT rc = {0, 0, width, height};
|
||||
bool has_menu = main_menu_ ? true : false;
|
||||
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, has_menu);
|
||||
if (true) {
|
||||
rc.right += 100 - rc.left;
|
||||
rc.left = 100;
|
||||
rc.bottom += 100 - rc.top;
|
||||
rc.top = 100;
|
||||
}
|
||||
Window::Resize(rc.left, rc.top, rc.right, rc.bottom);
|
||||
}
|
||||
|
||||
void Win32Window::Resize(int32_t left, int32_t top, int32_t right,
|
||||
int32_t bottom) {
|
||||
RECT rc = {left, top, right, bottom};
|
||||
bool has_menu = main_menu_ ? true : false;
|
||||
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, has_menu);
|
||||
Window::Resize(rc.left, rc.top, rc.right, rc.bottom);
|
||||
}
|
||||
|
||||
void Win32Window::ResizeToFill(int32_t pad_left, int32_t pad_top,
|
||||
int32_t pad_right, int32_t pad_bottom) {
|
||||
// TODO(benvanik): fullscreen.
|
||||
}
|
||||
|
||||
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 Win32Control::WndProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
} // namespace win32
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
55
src/xenia/ui/win32/win32_window.h
Normal file
55
src/xenia/ui/win32/win32_window.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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_WIN32_WIN32_WINDOW_H_
|
||||
#define XENIA_UI_WIN32_WIN32_WINDOW_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "xenia/ui/win32/win32_control.h"
|
||||
#include "xenia/ui/window.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace win32 {
|
||||
|
||||
class Win32Window : public Window<Win32Control> {
|
||||
public:
|
||||
Win32Window(const std::wstring& title);
|
||||
~Win32Window() override;
|
||||
|
||||
bool Initialize() override;
|
||||
|
||||
bool set_title(const std::wstring& title) override;
|
||||
|
||||
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;
|
||||
|
||||
protected:
|
||||
bool Create() override;
|
||||
void OnClose() override;
|
||||
|
||||
LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
LPARAM lParam) override;
|
||||
|
||||
private:
|
||||
void EnableMMCSS();
|
||||
|
||||
HMENU main_menu_;
|
||||
bool closing_;
|
||||
};
|
||||
|
||||
} // namespace win32
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_UI_WIN32_WIN32_WINDOW_H_
|
||||
84
src/xenia/ui/window.h
Normal file
84
src/xenia/ui/window.h
Normal file
@@ -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 XENIA_UI_WINDOW_H_
|
||||
#define XENIA_UI_WINDOW_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "poly/delegate.h"
|
||||
#include "xenia/ui/control.h"
|
||||
#include "xenia/ui/ui_event.h"
|
||||
|
||||
namespace xe {
|
||||
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(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 xe
|
||||
|
||||
#endif // XENIA_UI_WINDOW_H_
|
||||
Reference in New Issue
Block a user