Update to v094r24 release.

byuu says:

Finally!! Compilation works once again on Windows.

However, it's pretty buggy. Modality isn't really working right, you can
still poke at other windows, but when you select ListView items, they
redraw as empty boxes (need to process WM_DRAWITEM before checking
modality.)

The program crashes when you close it (probably a ruby driver's term()
function, that's what it usually is.)

The Layout::setEnabled(false) call isn't working right, so you get that
annoying chiming sound and cursor movement when mapping keyboard keys to
game inputs.

The column sizing seems off a bit on first display for the Hotkeys tab.

And probably lots more.
This commit is contained in:
Tim Allen
2015-06-12 23:14:38 +10:00
parent 314aee8c5c
commit f0c17ffc0d
188 changed files with 5474 additions and 3834 deletions

View File

@@ -1,94 +1,210 @@
namespace phoenix {
#if defined(Hiro_Window)
namespace hiro {
vector<pWindow*> pWindow::modal;
//EnableWindow(hwnd, false) sends WM_KILLFOCUS; deactivating said window
//EnableWindow(hwnd, true) does not restore lost focus
//when a modal loop finishes, and the dialog is dismissed, the application loses focus entirely
//due to anti-focus-stealing code in Windows, SetForegroundWindow() cannot restore lost focus
//further, GetActiveWindow() returns nothing when all windows have lost focus
//thus, we must use a focus-stealing hack to reclaim the focus we never intended to dismiss;
//and we must replicate GetActiveWindow() by scanning the Z-order of windows for this process
void pWindow::updateModality() {
//bind thread input to process that currently has input focus
auto threadId = GetWindowThreadProcessId(GetForegroundWindow(), NULL);
AttachThreadInput(threadId, GetCurrentThreadId(), TRUE);
pWindow* topMost = nullptr;
for(auto& object : pObject::objects) {
if(dynamic_cast<pWindow*>(object) == nullptr) continue;
pWindow* p = (pWindow*)object;
bool enable = modal.size() == 0 || modal.find(p);
if(IsWindowEnabled(p->hwnd) != enable) EnableWindow(p->hwnd, enable);
if(enable && p->window.visible()) {
if(topMost == nullptr) topMost = p;
else if(GetWindowZOrder(p->hwnd) < GetWindowZOrder(topMost->hwnd)) topMost = p;
}
}
//set input focus on top-most window
if(topMost) {
SetForegroundWindow(topMost->hwnd);
SetActiveWindow(topMost->hwnd);
}
//unbind thread input hook
AttachThreadInput(threadId, GetCurrentThreadId(), FALSE);
}
static const unsigned FixedStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_BORDER;
static const unsigned ResizableStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
Window& pWindow::none() {
static Window* window = nullptr;
if(window == nullptr) window = new Window;
return *window;
auto pWindow::construct() -> void {
hwnd = CreateWindow(L"hiroWindow", L"", ResizableStyle, 128, 128, 256, 256, 0, 0, GetModuleHandle(0), 0);
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference);
setDroppable(state().droppable);
setGeometry({128, 128, 256, 256});
}
void pWindow::append(Layout& layout) {
Geometry geom = window.state.geometry;
geom.x = geom.y = 0;
layout.setGeometry(geom);
auto pWindow::destruct() -> void {
if(hbrush) { DeleteObject(hbrush); hbrush = nullptr; }
DestroyWindow(hwnd);
}
void pWindow::append(Menu& menu) {
menu.p.parentWindow = &window;
updateMenu();
auto pWindow::append(sLayout layout) -> void {
}
void pWindow::append(Widget& widget) {
if(GetParentWidget(&widget)) {
widget.p.parentHwnd = GetParentWidget(&widget)->p.hwnd;
} else {
widget.p.parentHwnd = window.p.hwnd;
}
widget.p.orphan();
if(widget.font().empty() && !window.state.widgetFont.empty()) {
widget.setFont(window.state.widgetFont);
}
auto pWindow::append(sMenuBar menuBar) -> void {
}
bool pWindow::focused() {
auto pWindow::append(sStatusBar statusBar) -> void {
}
auto pWindow::focused() const -> bool override {
return (GetForegroundWindow() == hwnd);
}
Geometry pWindow::frameMargin() {
unsigned style = window.state.resizable ? ResizableStyle : FixedStyle;
if(window.state.fullScreen) style = 0;
RECT rc = {0, 0, 640, 480};
AdjustWindowRect(&rc, style, window.state.menuVisible);
unsigned statusHeight = 0;
if(window.state.statusVisible) {
RECT src;
GetClientRect(hstatus, &src);
statusHeight = src.bottom - src.top;
auto pWindow::frameMargin() const -> Geometry {
unsigned style = state().resizable ? ResizableStyle : FixedStyle;
if(state().fullScreen) style = 0;
RECT rc{0, 0, 640, 480};
AdjustWindowRect(&rc, style, (bool)GetMenu(hwnd));
signed statusHeight = 0;
if(auto statusBar = state().statusBar) {
if(auto self = statusBar->self()) {
if(statusBar->visible()) {
RECT src;
GetClientRect(self->hwnd, &src);
statusHeight = src.bottom - src.top;
}
}
}
return {abs(rc.left), abs(rc.top), (rc.right - rc.left) - 640, (rc.bottom - rc.top) + statusHeight - 480};
}
Geometry pWindow::geometry() {
auto pWindow::remove(sLayout layout) -> void {
}
auto pWindow::remove(sMenuBar menuBar) -> void {
}
auto pWindow::remove(sStatusBar statusBar) -> void {
}
auto pWindow::setBackgroundColor(Color color) -> void {
hbrushColor = CreateRGB(color);
if(hbrush) { DeleteObject(hbrush); hbrush = nullptr; }
if(color) hbrush = CreateSolidBrush(hbrushColor);
}
auto pWindow::setDroppable(bool droppable) -> void {
DragAcceptFiles(hwnd, droppable);
}
auto pWindow::setEnabled(bool enabled) -> void {
}
auto pWindow::setFocused() -> void {
if(!self().visible()) self().setVisible(true);
SetFocus(hwnd);
}
auto pWindow::setFullScreen(bool fullScreen) -> void {
lock();
if(fullScreen == false) {
SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | (state().resizable ? ResizableStyle : FixedStyle));
setGeometry(state().geometry);
} else {
HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
MONITORINFOEX info;
memset(&info, 0, sizeof(MONITORINFOEX));
info.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &info);
RECT rc = info.rcMonitor;
Geometry geometry = {rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top};
SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
Geometry margin = frameMargin();
setGeometry({
geometry.x() + margin.x(), geometry.y() + margin.y(),
geometry.width() - margin.width(), geometry.height() - margin.height()
});
}
unlock();
}
auto pWindow::setGeometry(Geometry geometry) -> void {
lock();
Geometry margin = frameMargin();
SetWindowPos(
hwnd, NULL,
geometry.x() - margin.x(), geometry.y() - margin.y(),
geometry.width() + margin.width(), geometry.height() + margin.height(),
SWP_NOZORDER | SWP_FRAMECHANGED
);
if(auto statusBar = state().statusBar) {
if(auto self = statusBar->self()) {
SetWindowPos(self->hwnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED);
}
}
if(auto layout = state().layout) {
layout->setGeometry(geometry.setPosition(0, 0));
}
unlock();
}
auto pWindow::setModal(bool modality) -> void {
if(modality) {
modal.appendOnce(this);
while(state().modal) {
Application::processEvents();
if(Application::state.onMain) {
Application::doMain();
} else {
usleep(20 * 1000);
}
}
if(auto position = modal.find(this)) modal.remove(position());
}
}
auto pWindow::setResizable(bool resizable) -> void {
SetWindowLongPtr(hwnd, GWL_STYLE, state().resizable ? ResizableStyle : FixedStyle);
setGeometry(state().geometry);
}
auto pWindow::setTitle(string text) -> void {
SetWindowText(hwnd, utf16_t(text));
}
auto pWindow::setVisible(bool visible) -> void {
ShowWindow(hwnd, visible ? SW_SHOWNORMAL : SW_HIDE);
if(!visible) setModal(false);
}
//
auto pWindow::onClose() -> void {
if(state().onClose) self().doClose();
else self().setVisible(false);
if(state().modal && !self().visible()) self().setModal(false);
}
auto pWindow::onDrop(WPARAM wparam) -> void {
lstring paths = DropPaths(wparam);
if(paths.empty()) return;
self().doDrop(paths);
}
auto pWindow::onEraseBackground() -> bool {
if(hbrush == 0) return false;
RECT rc;
GetClientRect(hwnd, &rc);
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
FillRect(ps.hdc, &rc, hbrush);
EndPaint(hwnd, &ps);
return true;
}
auto pWindow::onModalBegin() -> void {
Application::Windows::doModalChange(true);
}
auto pWindow::onModalEnd() -> void {
Application::Windows::doModalChange(false);
}
auto pWindow::onMove() -> void {
if(locked()) return;
state().geometry.setPosition(_geometry().position());
self().doMove();
}
auto pWindow::onSize() -> void {
if(locked()) return;
if(auto statusBar = state().statusBar) {
if(auto self = statusBar->self()) {
SetWindowPos(self->hwnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED);
}
}
state().geometry.setSize(_geometry().size());
if(auto layout = state().layout) {
layout->setGeometry(_geometry().setPosition(0, 0));
}
self().doSize();
}
//
auto pWindow::_geometry() -> Geometry {
Geometry margin = frameMargin();
RECT rc;
@@ -101,239 +217,14 @@ Geometry pWindow::geometry() {
GetWindowRect(hwnd, &rc);
}
signed x = rc.left + margin.x;
signed y = rc.top + margin.y;
unsigned width = (rc.right - rc.left) - margin.width;
unsigned height = (rc.bottom - rc.top) - margin.height;
signed x = rc.left + margin.x();
signed y = rc.top + margin.y();
signed width = (rc.right - rc.left) - margin.width();
signed height = (rc.bottom - rc.top) - margin.height();
return {x, y, width, height};
}
void pWindow::remove(Layout& layout) {
}
void pWindow::remove(Menu& menu) {
updateMenu();
}
void pWindow::remove(Widget& widget) {
widget.p.orphan();
}
void pWindow::setBackgroundColor(Color color) {
if(brush) DeleteObject(brush);
brushColor = RGB(color.red, color.green, color.blue);
brush = CreateSolidBrush(brushColor);
}
void pWindow::setDroppable(bool droppable) {
DragAcceptFiles(hwnd, droppable);
}
void pWindow::setFocused() {
if(window.state.visible == false) setVisible(true);
SetFocus(hwnd);
}
void pWindow::setFullScreen(bool fullScreen) {
locked = true;
if(fullScreen == false) {
SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | (window.state.resizable ? ResizableStyle : FixedStyle));
setGeometry(window.state.geometry);
} else {
HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
MONITORINFOEX info;
memset(&info, 0, sizeof(MONITORINFOEX));
info.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &info);
RECT rc = info.rcMonitor;
Geometry geometry = {rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top};
SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
Geometry margin = frameMargin();
setGeometry({
geometry.x + margin.x, geometry.y + margin.y,
geometry.width - margin.width, geometry.height - margin.height
});
}
locked = false;
}
void pWindow::setGeometry(Geometry geometry) {
locked = true;
Geometry margin = frameMargin();
SetWindowPos(
hwnd, NULL,
geometry.x - margin.x, geometry.y - margin.y,
geometry.width + margin.width, geometry.height + margin.height,
SWP_NOZORDER | SWP_FRAMECHANGED
);
SetWindowPos(hstatus, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED);
for(auto& layout : window.state.layout) {
Geometry geom = this->geometry();
geom.x = geom.y = 0;
layout.setGeometry(geom);
}
locked = false;
}
void pWindow::setMenuFont(string font) {
}
void pWindow::setMenuVisible(bool visible) {
locked = true;
SetMenu(hwnd, visible ? hmenu : 0);
setGeometry(window.state.geometry);
locked = false;
}
void pWindow::setModal(bool modality) {
if(modality == true) {
modal.appendOnce(this);
updateModality();
while(window.state.modal) {
Application::processEvents();
if(Application::main) {
Application::main();
} else {
usleep(20 * 1000);
}
}
if(auto position = modal.find(this)) modal.remove(position());
updateModality();
}
}
void pWindow::setResizable(bool resizable) {
SetWindowLongPtr(hwnd, GWL_STYLE, window.state.resizable ? ResizableStyle : FixedStyle);
setGeometry(window.state.geometry);
}
void pWindow::setStatusFont(string font) {
if(hstatusfont) DeleteObject(hstatusfont);
hstatusfont = pFont::create(font);
SendMessage(hstatus, WM_SETFONT, (WPARAM)hstatusfont, 0);
}
void pWindow::setStatusText(string text) {
SendMessage(hstatus, SB_SETTEXT, 0, (LPARAM)(wchar_t*)utf16_t(text));
}
void pWindow::setStatusVisible(bool visible) {
locked = true;
ShowWindow(hstatus, visible ? SW_SHOWNORMAL : SW_HIDE);
setGeometry(window.state.geometry);
locked = false;
}
void pWindow::setTitle(string text) {
SetWindowText(hwnd, utf16_t(text));
}
void pWindow::setVisible(bool visible) {
ShowWindow(hwnd, visible ? SW_SHOWNORMAL : SW_HIDE);
if(visible == false) setModal(false);
}
void pWindow::setWidgetFont(string font) {
}
void pWindow::constructor() {
brush = 0;
hwnd = CreateWindow(L"phoenix_window", L"", ResizableStyle, 128, 128, 256, 256, 0, 0, GetModuleHandle(0), 0);
hmenu = CreateMenu();
hstatus = CreateWindow(STATUSCLASSNAME, L"", WS_CHILD, 0, 0, 0, 0, hwnd, 0, GetModuleHandle(0), 0);
hstatusfont = 0;
setStatusFont(Font::sans(8));
//status bar will be capable of receiving tab focus if it is not disabled
SetWindowLongPtr(hstatus, GWL_STYLE, GetWindowLong(hstatus, GWL_STYLE) | WS_DISABLED);
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&window);
setDroppable(window.state.droppable);
setGeometry({128, 128, 256, 256});
DWORD color = GetSysColor(COLOR_3DFACE);
window.state.backgroundColor = Color((uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color >> 0), 255u);
}
void pWindow::destructor() {
DeleteObject(hstatusfont);
DestroyWindow(hstatus);
DestroyMenu(hmenu);
DestroyWindow(hwnd);
}
void pWindow::updateMenu() {
if(hmenu) DestroyMenu(hmenu);
hmenu = CreateMenu();
for(auto& menu : window.state.menu) {
menu.p.update(window);
if(menu.visible()) {
AppendMenu(hmenu, MF_STRING | MF_POPUP, (UINT_PTR)menu.p.hmenu, utf16_t(menu.state.text));
}
}
SetMenu(hwnd, window.state.menuVisible ? hmenu : 0);
}
void pWindow::onClose() {
if(window.onClose) window.onClose();
else window.setVisible(false);
if(window.state.modal && !window.state.visible) window.setModal(false);
}
void pWindow::onDrop(WPARAM wparam) {
lstring paths = DropPaths(wparam);
if(paths.empty()) return;
if(window.onDrop) window.onDrop(paths);
}
bool pWindow::onEraseBackground() {
if(brush == 0) return false;
RECT rc;
GetClientRect(hwnd, &rc);
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
FillRect(ps.hdc, &rc, brush);
EndPaint(hwnd, &ps);
return true;
}
void pWindow::onModalBegin() {
if(Application::Windows::onModalBegin) Application::Windows::onModalBegin();
}
void pWindow::onModalEnd() {
if(Application::Windows::onModalEnd) Application::Windows::onModalEnd();
}
void pWindow::onMove() {
if(locked) return;
Geometry windowGeometry = geometry();
window.state.geometry.x = windowGeometry.x;
window.state.geometry.y = windowGeometry.y;
if(window.onMove) window.onMove();
}
void pWindow::onSize() {
if(locked) return;
SetWindowPos(hstatus, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED);
Geometry windowGeometry = geometry();
window.state.geometry.width = windowGeometry.width;
window.state.geometry.height = windowGeometry.height;
for(auto& layout : window.state.layout) {
Geometry geom = geometry();
geom.x = geom.y = 0;
layout.setGeometry(geom);
}
if(window.onSize) window.onSize();
}
}
#endif