mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-04-02 10:42:14 -04:00
byuu says: Changelog: - fixed major nall/vector/prepend bug - renamed hiro/ListView to hiro/TableView - added new hiro/ListView control which is a simplified abstraction of hiro/TableView - updated higan's cheat database window and icarus' scan dialog to use the new ListView control - compilation works once again on all platforms (Windows, Cocoa, GTK, Qt) - the loki skeleton compiles once again (removed nall/DSP references; updated port/device ID names) Small catch: need to capture layout resize events internally in Windows to call resizeColumns. For now, just resize the icarus window to get it to use the full window width for list view items.
280 lines
7.5 KiB
C++
280 lines
7.5 KiB
C++
#if defined(Hiro_Window)
|
|
|
|
namespace hiro {
|
|
|
|
static const unsigned FixedStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_BORDER | WS_CLIPCHILDREN;
|
|
static const unsigned ResizableStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CLIPCHILDREN;
|
|
|
|
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});
|
|
|
|
windows.append(self().instance);
|
|
}
|
|
|
|
auto pWindow::destruct() -> void {
|
|
if(auto position = windows.find(self().instance)) windows.remove(*position);
|
|
|
|
if(hbrush) { DeleteObject(hbrush); hbrush = nullptr; }
|
|
DestroyWindow(hwnd);
|
|
}
|
|
|
|
auto pWindow::append(sLayout layout) -> void {
|
|
}
|
|
|
|
auto pWindow::append(sMenuBar menuBar) -> void {
|
|
}
|
|
|
|
auto pWindow::append(sStatusBar statusBar) -> void {
|
|
}
|
|
|
|
auto pWindow::focused() const -> bool {
|
|
return (GetForegroundWindow() == hwnd);
|
|
}
|
|
|
|
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};
|
|
}
|
|
|
|
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 {
|
|
if(auto layout = state().layout) {
|
|
if(auto self = layout->self()) self->setEnabled(layout->enabled(true));
|
|
}
|
|
}
|
|
|
|
auto pWindow::setFocused() -> void {
|
|
if(!self().visible()) self().setVisible(true);
|
|
SetFocus(hwnd);
|
|
}
|
|
|
|
auto pWindow::setFont(const Font& font) -> void {
|
|
if(auto layout = state().layout) {
|
|
if(auto self = layout->self()) self->setFont(layout->font(true));
|
|
}
|
|
}
|
|
|
|
auto pWindow::setFullScreen(bool fullScreen) -> void {
|
|
auto style = GetWindowLongPtr(hwnd, GWL_STYLE) & WS_VISIBLE;
|
|
lock();
|
|
if(fullScreen) {
|
|
windowedGeometry = self().geometry();
|
|
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, style | WS_POPUP);
|
|
Geometry margin = frameMargin();
|
|
self().setGeometry({
|
|
geometry.x() + margin.x(), geometry.y() + margin.y(),
|
|
geometry.width() - margin.width(), geometry.height() - margin.height()
|
|
});
|
|
} else {
|
|
SetWindowLongPtr(hwnd, GWL_STYLE, style | (state().resizable ? ResizableStyle : FixedStyle));
|
|
self().setGeometry(windowedGeometry);
|
|
}
|
|
unlock();
|
|
}
|
|
|
|
auto pWindow::setGeometry(Geometry geometry) -> void {
|
|
lock();
|
|
Geometry margin = frameMargin();
|
|
SetWindowPos(
|
|
hwnd, nullptr,
|
|
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) {
|
|
_modalityUpdate();
|
|
while(state().modal) {
|
|
Application::processEvents();
|
|
if(Application::state.onMain) {
|
|
Application::doMain();
|
|
} else {
|
|
usleep(20 * 1000);
|
|
}
|
|
}
|
|
_modalityUpdate();
|
|
}
|
|
}
|
|
|
|
auto pWindow::setResizable(bool resizable) -> void {
|
|
auto style = GetWindowLongPtr(hwnd, GWL_STYLE) & WS_VISIBLE;
|
|
SetWindowLongPtr(hwnd, GWL_STYLE, 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);
|
|
|
|
if(auto layout = state().layout) {
|
|
if(auto self = layout->self()) self->setVisible(layout->visible(true));
|
|
}
|
|
}
|
|
|
|
//
|
|
|
|
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) 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;
|
|
if(IsIconic(hwnd)) {
|
|
//GetWindowRect returns -32000(x),-32000(y) when window is minimized
|
|
WINDOWPLACEMENT wp;
|
|
GetWindowPlacement(hwnd, &wp);
|
|
rc = wp.rcNormalPosition;
|
|
} else {
|
|
GetWindowRect(hwnd, &rc);
|
|
}
|
|
|
|
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};
|
|
}
|
|
|
|
auto pWindow::_modalityCount() -> unsigned {
|
|
unsigned modalWindows = 0;
|
|
for(auto& weak : windows) {
|
|
if(auto object = weak.acquire()) {
|
|
if(auto window = dynamic_cast<mWindow*>(object.data())) {
|
|
if(window->modal()) modalWindows++;
|
|
}
|
|
}
|
|
}
|
|
return modalWindows;
|
|
}
|
|
|
|
auto pWindow::_modalityDisabled() -> bool {
|
|
if(_modalityCount() == 0) return false;
|
|
return !state().modal;
|
|
}
|
|
|
|
auto pWindow::_modalityUpdate() -> void {
|
|
unsigned modalWindows = _modalityCount();
|
|
for(auto& weak : windows) {
|
|
if(auto object = weak.acquire()) {
|
|
if(auto window = dynamic_cast<mWindow*>(object.data())) {
|
|
if(auto self = window->self()) {
|
|
bool enabled = !modalWindows || window->modal();
|
|
if(IsWindowEnabled(self->hwnd) != enabled) {
|
|
EnableWindow(self->hwnd, enabled);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|