Update to v088r11 release.
byuu says:
Changelog:
- phoenix has added Window::setModal(bool modal = true);
- file dialog is now modal. This allows emulation cores to request data
and get it immediately before continuing the loading process
- save data is hooked up for most systems, still need to handle
subsystem slot saves (Sufami Turbo, basically.)
- toggle fullscreen key binding added (Alt+Enter for now. I think F11 is
probably better though, Enter is often mapped to game start button.)
- video scaling is in (center, scale, stretch), works the same in
windowed and fullscreen mode (stretch hides resize window option), all
in the settings menu now
- enough structure to map all saved paths for the browser and to load
BS-X slotted carts, BS-X carts, single Sufami Turbo carts
Caveats / Missing:
- Super Game Boy input doesn't work yet (due to change in callback
binding)
- doesn't load secondary Sufami Turbo slot yet
- BS-X BIOS isn't show the data pack games to load for some reason (ugh,
I hate the shit out of debugging BS-X stuff ...)
- need mute audio, sync audio+video toggle, save/load state menu and
quick keys, XML mapping information window
- need cheat editor and cheat database
- need state manager
- need to sort subsystems below main systems in load menu (basically
just see if media.slot.size() > 0)
- need video shaders (will probably leave off filters for the time being
... due to that 24/30-bit thing)
- need video adjustments (contrast etc, overscan masks)
- need audio adjustments (frequency, latency, resampler, volume,
per-system frequency)
- need driver selection and input focus policy (driver crash detection
would be nice too)
- need NSS DIP switch settings (that one will be really fun)
- need to save and load window geometry settings
- need to hook up controller selection (won't be fun), create a map to
hide controllers with no inputs to reassign
2012-05-03 12:36:47 +00:00
|
|
|
vector<pWindow*> pWindow::modal;
|
|
|
|
|
|
|
|
void pWindow::updateModality() {
|
|
|
|
for(auto &object : pObject::objects) {
|
|
|
|
if(dynamic_cast<pWindow*>(object) == nullptr) continue;
|
|
|
|
pWindow *p = (pWindow*)object;
|
|
|
|
if(modal.size() == 0) EnableWindow(p->hwnd, true);
|
|
|
|
else EnableWindow(p->hwnd, modal.find(p));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-27 09:11:01 +00:00
|
|
|
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;
|
2011-02-24 09:25:20 +00:00
|
|
|
|
2012-08-07 13:28:00 +00:00
|
|
|
Window& pWindow::none() {
|
|
|
|
static Window *window = nullptr;
|
|
|
|
if(window == nullptr) window = new Window;
|
|
|
|
return *window;
|
|
|
|
}
|
|
|
|
|
2011-02-24 09:25:20 +00:00
|
|
|
void pWindow::append(Layout &layout) {
|
|
|
|
Geometry geom = window.state.geometry;
|
|
|
|
geom.x = geom.y = 0;
|
|
|
|
layout.setGeometry(geom);
|
|
|
|
}
|
|
|
|
|
|
|
|
void pWindow::append(Menu &menu) {
|
2011-09-09 04:16:25 +00:00
|
|
|
menu.p.parentWindow = &window;
|
2011-02-24 09:25:20 +00:00
|
|
|
updateMenu();
|
|
|
|
}
|
|
|
|
|
|
|
|
void pWindow::append(Widget &widget) {
|
2011-09-05 03:48:23 +00:00
|
|
|
widget.p.parentWindow = &window;
|
|
|
|
widget.p.orphan();
|
|
|
|
if(widget.state.font != "") widget.p.setFont(widget.state.font);
|
|
|
|
else if(window.state.widgetFont != "") widget.p.setFont(window.state.widgetFont);
|
|
|
|
else widget.p.setFont("Tahoma, 8");
|
2011-02-24 09:25:20 +00:00
|
|
|
}
|
|
|
|
|
2011-08-06 14:03:52 +00:00
|
|
|
Color pWindow::backgroundColor() {
|
|
|
|
if(window.state.backgroundColorOverride) return window.state.backgroundColor;
|
|
|
|
DWORD color = GetSysColor(COLOR_3DFACE);
|
|
|
|
return { (uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color >> 0), 255 };
|
|
|
|
}
|
|
|
|
|
2011-02-24 09:25:20 +00:00
|
|
|
bool pWindow::focused() {
|
|
|
|
return (GetForegroundWindow() == hwnd);
|
|
|
|
}
|
|
|
|
|
2011-02-27 09:05:10 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
return { abs(rc.left), abs(rc.top), (rc.right - rc.left) - 640, (rc.bottom - rc.top) + statusHeight - 480 };
|
|
|
|
}
|
|
|
|
|
2011-02-24 09:25:20 +00:00
|
|
|
Geometry pWindow::geometry() {
|
|
|
|
Geometry margin = frameMargin();
|
2011-06-05 03:45:04 +00:00
|
|
|
|
2011-08-06 14:03:52 +00:00
|
|
|
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);
|
|
|
|
}
|
2011-02-24 09:25:20 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
return { x, y, width, height };
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
void pWindow::remove(Layout &layout) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void pWindow::remove(Menu &menu) {
|
|
|
|
updateMenu();
|
|
|
|
}
|
|
|
|
|
|
|
|
void pWindow::remove(Widget &widget) {
|
|
|
|
widget.p.orphan();
|
|
|
|
}
|
|
|
|
|
2011-08-06 14:03:52 +00:00
|
|
|
void pWindow::setBackgroundColor(const Color &color) {
|
2011-02-24 09:25:20 +00:00
|
|
|
if(brush) DeleteObject(brush);
|
2011-08-06 14:03:52 +00:00
|
|
|
brushColor = RGB(color.red, color.green, color.blue);
|
2011-02-24 09:25:20 +00:00
|
|
|
brush = CreateSolidBrush(brushColor);
|
|
|
|
}
|
|
|
|
|
|
|
|
void pWindow::setFocused() {
|
|
|
|
if(window.state.visible == false) setVisible(true);
|
|
|
|
SetFocus(hwnd);
|
|
|
|
}
|
|
|
|
|
|
|
|
void pWindow::setFullScreen(bool fullScreen) {
|
2011-02-24 09:27:21 +00:00
|
|
|
locked = true;
|
|
|
|
if(fullScreen == false) {
|
|
|
|
SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | (window.state.resizable ? ResizableStyle : FixedStyle));
|
|
|
|
setGeometry(window.state.geometry);
|
|
|
|
} else {
|
|
|
|
SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
|
|
|
|
Geometry margin = frameMargin();
|
|
|
|
setGeometry({ margin.x, margin.y, GetSystemMetrics(SM_CXSCREEN) - margin.width, GetSystemMetrics(SM_CYSCREEN) - margin.height });
|
|
|
|
}
|
|
|
|
locked = false;
|
2011-02-24 09:25:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void pWindow::setGeometry(const 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);
|
2011-09-27 11:55:02 +00:00
|
|
|
for(auto &layout : window.state.layout) {
|
2011-02-24 09:25:20 +00:00
|
|
|
Geometry geom = this->geometry();
|
|
|
|
geom.x = geom.y = 0;
|
|
|
|
layout.setGeometry(geom);
|
|
|
|
}
|
|
|
|
locked = false;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
void pWindow::setMenuFont(const string &font) {
|
2011-02-24 09:25:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void pWindow::setMenuVisible(bool visible) {
|
|
|
|
locked = true;
|
|
|
|
SetMenu(hwnd, visible ? hmenu : 0);
|
|
|
|
setGeometry(window.state.geometry);
|
|
|
|
locked = false;
|
|
|
|
}
|
|
|
|
|
Update to v088r11 release.
byuu says:
Changelog:
- phoenix has added Window::setModal(bool modal = true);
- file dialog is now modal. This allows emulation cores to request data
and get it immediately before continuing the loading process
- save data is hooked up for most systems, still need to handle
subsystem slot saves (Sufami Turbo, basically.)
- toggle fullscreen key binding added (Alt+Enter for now. I think F11 is
probably better though, Enter is often mapped to game start button.)
- video scaling is in (center, scale, stretch), works the same in
windowed and fullscreen mode (stretch hides resize window option), all
in the settings menu now
- enough structure to map all saved paths for the browser and to load
BS-X slotted carts, BS-X carts, single Sufami Turbo carts
Caveats / Missing:
- Super Game Boy input doesn't work yet (due to change in callback
binding)
- doesn't load secondary Sufami Turbo slot yet
- BS-X BIOS isn't show the data pack games to load for some reason (ugh,
I hate the shit out of debugging BS-X stuff ...)
- need mute audio, sync audio+video toggle, save/load state menu and
quick keys, XML mapping information window
- need cheat editor and cheat database
- need state manager
- need to sort subsystems below main systems in load menu (basically
just see if media.slot.size() > 0)
- need video shaders (will probably leave off filters for the time being
... due to that 24/30-bit thing)
- need video adjustments (contrast etc, overscan masks)
- need audio adjustments (frequency, latency, resampler, volume,
per-system frequency)
- need driver selection and input focus policy (driver crash detection
would be nice too)
- need NSS DIP switch settings (that one will be really fun)
- need to save and load window geometry settings
- need to hook up controller selection (won't be fun), create a map to
hide controllers with no inputs to reassign
2012-05-03 12:36:47 +00:00
|
|
|
void pWindow::setModal(bool modality) {
|
|
|
|
if(modality == false) {
|
|
|
|
if(auto position = modal.find(this)) modal.remove(position());
|
|
|
|
} else {
|
|
|
|
modal.appendonce(this);
|
|
|
|
}
|
|
|
|
updateModality();
|
|
|
|
}
|
|
|
|
|
2011-02-24 09:25:20 +00:00
|
|
|
void pWindow::setResizable(bool resizable) {
|
|
|
|
SetWindowLongPtr(hwnd, GWL_STYLE, window.state.resizable ? ResizableStyle : FixedStyle);
|
|
|
|
setGeometry(window.state.geometry);
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
void pWindow::setStatusFont(const string &font) {
|
|
|
|
if(hstatusfont) DeleteObject(hstatusfont);
|
|
|
|
hstatusfont = pFont::create(font);
|
|
|
|
SendMessage(hstatus, WM_SETFONT, (WPARAM)hstatusfont, 0);
|
2011-02-24 09:25:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void pWindow::setStatusText(const 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(const string &text) {
|
|
|
|
SetWindowText(hwnd, utf16_t(text));
|
|
|
|
}
|
|
|
|
|
|
|
|
void pWindow::setVisible(bool visible) {
|
|
|
|
ShowWindow(hwnd, visible ? SW_SHOWNORMAL : SW_HIDE);
|
Update to v088r15 release.
byuu says:
Changelog:
- default placement of presentation window optimized for 1024x768
displays or larger (sorry if yours is smaller, move the window
yourself.)
- Direct3D waits until a previous Vblank ends before waiting for the
next Vblank to begin (fixes video timing analysis, and ---really---
fast computers.)
- Window::setVisible(false) clears modality, but also fixed in Browser
code as well (fixes loading images on Windows hanging)
- Browser won't consume full CPU resources (but timing analysis will,
I don't want stalls to affect the results.)
- closing settings window while analyzing stops analysis
- you can load the SGB BIOS without a game (why the hell you would want
to ...)
- escape closes the Browser window (it won't close other dialogs, it has
to be hooked up per-window)
- just for fun, joypad hat up/down moves in Browser file list, any
joypad button loads selected game [not very useful, lacks repeat, and
there aren't GUI load file open buttons]
- Super Scope and Justifier crosshairs render correctly (probably
doesn't belong in the core, but it's not something I suspect people
want to do themselves ...)
- you can load GB, SGB, GB, SGB ... without problems (not happy with how
I did this, but I don't want to add an Interface::setInterface()
function yet)
- PAL timing works as I want now (if you want 50fps on a 60hz monitor,
you must not use sync video) [needed to update the DSP frequency when
toggling video/audio sync]
- not going to save input port selection for now (lot of work), but it
will properly keep your port setting across cartridge loads at least
[just goes to controller on emulator restart]
- SFC overscan on and off both work as expected now (off centers image,
on shows entire image)
- laevateinn compiles properly now
- ethos goes to ~/.config/bsnes now that target-ui is dead [honestly,
I recommend deleting the old folder and starting over]
- Emulator::Interface callbacks converted to virtual binding structure
that GUI inherits from (simplifies binding callbacks)
- this breaks Super Game Boy for a bit, I need to rethink
system-specific bindings without direct inheritance
Timing analysis works spectacularly well on Windows, too. You won't get
your 100% perfect rate (unless maybe you leave the analysis running
overnight?), but it'll get really freaking close this way.
2012-05-07 23:29:03 +00:00
|
|
|
if(visible == false) setModal(false);
|
2011-02-24 09:25:20 +00:00
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
void pWindow::setWidgetFont(const string &font) {
|
2011-09-27 11:55:02 +00:00
|
|
|
for(auto &widget : window.state.widget) {
|
2011-09-05 03:48:23 +00:00
|
|
|
if(widget.state.font == "") widget.setFont(font);
|
2011-02-24 09:25:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2011-09-05 03:48:23 +00:00
|
|
|
hstatusfont = 0;
|
|
|
|
setStatusFont("Tahoma, 8");
|
2011-02-24 09:25:20 +00:00
|
|
|
|
|
|
|
//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);
|
|
|
|
setGeometry({ 128, 128, 256, 256 });
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
void pWindow::destructor() {
|
|
|
|
DeleteObject(hstatusfont);
|
|
|
|
DestroyWindow(hstatus);
|
|
|
|
DestroyMenu(hmenu);
|
|
|
|
DestroyWindow(hwnd);
|
|
|
|
}
|
|
|
|
|
2011-02-24 09:25:20 +00:00
|
|
|
void pWindow::updateMenu() {
|
|
|
|
if(hmenu) DestroyMenu(hmenu);
|
|
|
|
hmenu = CreateMenu();
|
|
|
|
|
2011-09-27 11:55:02 +00:00
|
|
|
for(auto &menu : window.state.menu) {
|
2011-09-05 03:48:23 +00:00
|
|
|
menu.p.update(window);
|
2011-09-09 04:16:25 +00:00
|
|
|
if(menu.visible()) {
|
|
|
|
AppendMenu(hmenu, MF_STRING | MF_POPUP, (UINT_PTR)menu.p.hmenu, utf16_t(menu.state.text));
|
|
|
|
}
|
2011-02-24 09:25:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SetMenu(hwnd, window.state.menuVisible ? hmenu : 0);
|
|
|
|
}
|