2013-03-15 13:11:33 +00:00
|
|
|
namespace phoenix {
|
|
|
|
|
|
|
|
static bool Application_keyboardProc(HWND, UINT, WPARAM, LPARAM);
|
|
|
|
static void Application_processDialogMessage(MSG&);
|
|
|
|
static LRESULT CALLBACK Application_windowProc(HWND, UINT, WPARAM, LPARAM);
|
|
|
|
|
|
|
|
void pApplication::run() {
|
|
|
|
MSG msg;
|
|
|
|
if(Application::main) {
|
|
|
|
while(applicationState.quit == false) {
|
|
|
|
Application::main();
|
|
|
|
processEvents();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
MSG msg;
|
|
|
|
while(GetMessage(&msg, 0, 0, 0)) {
|
|
|
|
Application_processDialogMessage(msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool pApplication::pendingEvents() {
|
|
|
|
MSG msg;
|
|
|
|
return PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void pApplication::processEvents() {
|
|
|
|
while(pendingEvents()) {
|
|
|
|
MSG msg;
|
|
|
|
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
|
|
|
|
Application_processDialogMessage(msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
void Application_processDialogMessage(MSG& msg) {
|
2013-03-15 13:11:33 +00:00
|
|
|
if(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP
|
|
|
|
|| msg.message == WM_SYSKEYDOWN || msg.message == WM_SYSKEYUP) {
|
|
|
|
if(Application_keyboardProc(msg.hwnd, msg.message, msg.wParam, msg.lParam)) {
|
|
|
|
DispatchMessage(&msg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!IsDialogMessage(GetForegroundWindow(), &msg)) {
|
|
|
|
TranslateMessage(&msg);
|
|
|
|
DispatchMessage(&msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void pApplication::quit() {
|
|
|
|
PostQuitMessage(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void pApplication::initialize() {
|
|
|
|
CoInitialize(0);
|
|
|
|
InitCommonControls();
|
|
|
|
|
|
|
|
WNDCLASS wc;
|
|
|
|
wc.cbClsExtra = 0;
|
|
|
|
wc.cbWndExtra = 0;
|
|
|
|
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
|
|
|
|
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
|
|
|
wc.hIcon = LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(2));
|
|
|
|
wc.hInstance = GetModuleHandle(0);
|
|
|
|
wc.lpfnWndProc = Application_windowProc;
|
|
|
|
wc.lpszClassName = L"phoenix_window";
|
|
|
|
wc.lpszMenuName = 0;
|
|
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
|
|
RegisterClass(&wc);
|
|
|
|
|
|
|
|
wc.cbClsExtra = 0;
|
|
|
|
wc.cbWndExtra = 0;
|
|
|
|
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
|
|
|
|
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
|
|
|
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
|
|
|
wc.hInstance = GetModuleHandle(0);
|
|
|
|
wc.lpfnWndProc = Canvas_windowProc;
|
|
|
|
wc.lpszClassName = L"phoenix_canvas";
|
|
|
|
wc.lpszMenuName = 0;
|
|
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
|
|
RegisterClass(&wc);
|
|
|
|
|
|
|
|
wc.cbClsExtra = 0;
|
|
|
|
wc.cbWndExtra = 0;
|
|
|
|
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
|
|
|
|
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
|
|
|
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
|
|
|
wc.hInstance = GetModuleHandle(0);
|
|
|
|
wc.lpfnWndProc = Label_windowProc;
|
|
|
|
wc.lpszClassName = L"phoenix_label";
|
|
|
|
wc.lpszMenuName = 0;
|
|
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
|
|
RegisterClass(&wc);
|
|
|
|
|
|
|
|
wc.cbClsExtra = 0;
|
|
|
|
wc.cbWndExtra = 0;
|
|
|
|
wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
|
|
|
|
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
|
|
|
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
|
|
|
wc.hInstance = GetModuleHandle(0);
|
|
|
|
wc.lpfnWndProc = Viewport_windowProc;
|
|
|
|
wc.lpszClassName = L"phoenix_viewport";
|
|
|
|
wc.lpszMenuName = 0;
|
|
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
|
|
RegisterClass(&wc);
|
|
|
|
|
|
|
|
settings = new Settings;
|
|
|
|
pKeyboard::initialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool Application_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
|
|
|
if(msg != WM_KEYDOWN && msg != WM_SYSKEYDOWN && msg != WM_KEYUP && msg != WM_SYSKEYUP) return false;
|
|
|
|
|
|
|
|
GUITHREADINFO info;
|
|
|
|
memset(&info, 0, sizeof(GUITHREADINFO));
|
|
|
|
info.cbSize = sizeof(GUITHREADINFO);
|
|
|
|
GetGUIThreadInfo(GetCurrentThreadId(), &info);
|
2013-05-02 11:25:45 +00:00
|
|
|
Object* object = (Object*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA);
|
2013-03-15 13:11:33 +00:00
|
|
|
if(object == nullptr) return false;
|
|
|
|
|
|
|
|
if(dynamic_cast<Window*>(object)) {
|
2013-05-02 11:25:45 +00:00
|
|
|
Window& window = (Window&)*object;
|
2013-03-15 13:11:33 +00:00
|
|
|
if(pWindow::modal.size() > 0 && !pWindow::modal.find(&window.p)) return false;
|
|
|
|
Keyboard::Keycode keysym = Keysym(wparam, lparam);
|
|
|
|
if(keysym != Keyboard::Keycode::None) {
|
|
|
|
if((msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) && window.onKeyPress) window.onKeyPress(keysym);
|
|
|
|
if((msg == WM_KEYUP || msg == WM_SYSKEYUP) && window.onKeyRelease) window.onKeyRelease(keysym);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(msg == WM_KEYDOWN) {
|
|
|
|
if(dynamic_cast<ListView*>(object)) {
|
2013-05-02 11:25:45 +00:00
|
|
|
ListView& listView = (ListView&)*object;
|
2013-03-15 13:11:33 +00:00
|
|
|
if(wparam == VK_RETURN) {
|
Update to v093r01 release.
byuu says:
Changelog:
- added SA-1 MDR; fixes bug in SD Gundam G-Next where the main
battleship was unable to fire
- added out-of-the-box support for any BSD running Clang 3.3+ (FreeBSD
10+, notably)
- added new video shader, "Display Emulation", which changes the shader
based on the emulated system
- fixed the home button to go to your default library path
- phoenix: Windows port won't send onActivate unless an item is selected
(prevents crashing on pressing enter in file dialog)
- ruby: removed vec4 position from out Vertex {} (helps AMD cards)
- shaders: updated all shaders to use texture() instead of texture2D()
(helps AMD cards)
The "Display Emulation" option works like this: when selected, it tries
to load "<path>/Video Shaders/Emulation/<systemName>.shader/"; otherwise
it falls back to the blur shader. <path> is the usual (next to binary,
then in <config>/higan, then in /usr/share/higan, etc); and <systemName>
is "Famicom", "Super Famicom", "Game Boy", "Game Boy Color", "Game Boy
Advance"
To support BSD, I had to modify the $(platform) variable to
differentiate between Linux and BSD.
As such, the new $(platform) values are:
win -> windows
osx -> macosx
x -> linux or bsd
I am also checking uname -s instead of uname -a now. No reason to
potentially match the hostname to the wrong OS type.
2013-10-21 11:45:39 +00:00
|
|
|
if(listView.state.text.size() && listView.selected()) {
|
|
|
|
if(listView.onActivate) listView.onActivate();
|
|
|
|
}
|
2013-03-15 13:11:33 +00:00
|
|
|
}
|
|
|
|
} else if(dynamic_cast<LineEdit*>(object)) {
|
2013-05-02 11:25:45 +00:00
|
|
|
LineEdit& lineEdit = (LineEdit&)*object;
|
2013-03-15 13:11:33 +00:00
|
|
|
if(wparam == VK_RETURN) {
|
|
|
|
if(lineEdit.onActivate) lineEdit.onActivate();
|
|
|
|
}
|
|
|
|
} else if(dynamic_cast<TextEdit*>(object)) {
|
2013-05-02 11:25:45 +00:00
|
|
|
TextEdit& textEdit = (TextEdit&)*object;
|
2013-03-15 13:11:33 +00:00
|
|
|
if(wparam == 'A' && GetKeyState(VK_CONTROL) < 0) {
|
|
|
|
//Ctrl+A = select all text
|
|
|
|
//note: this is not a standard accelerator on Windows
|
|
|
|
Edit_SetSel(textEdit.p.hwnd, 0, ~0);
|
|
|
|
return true;
|
|
|
|
} else if(wparam == 'V' && GetKeyState(VK_CONTROL) < 0) {
|
|
|
|
//Ctrl+V = paste text
|
|
|
|
//note: this formats Unix (LF) and OS9 (CR) line-endings to Windows (CR+LF) line-endings
|
|
|
|
//this is necessary as the EDIT control only supports Windows line-endings
|
|
|
|
OpenClipboard(hwnd);
|
|
|
|
HANDLE handle = GetClipboardData(CF_UNICODETEXT);
|
|
|
|
if(handle) {
|
2013-05-02 11:25:45 +00:00
|
|
|
wchar_t* text = (wchar_t*)GlobalLock(handle);
|
2013-03-15 13:11:33 +00:00
|
|
|
if(text) {
|
|
|
|
string data = (const char*)utf8_t(text);
|
|
|
|
data.replace("\r\n", "\n");
|
|
|
|
data.replace("\r", "\n");
|
|
|
|
data.replace("\n", "\r\n");
|
|
|
|
GlobalUnlock(handle);
|
|
|
|
utf16_t output(data);
|
|
|
|
HGLOBAL resource = GlobalAlloc(GMEM_MOVEABLE, (wcslen(output) + 1) * sizeof(wchar_t));
|
|
|
|
if(resource) {
|
2013-05-02 11:25:45 +00:00
|
|
|
wchar_t* write = (wchar_t*)GlobalLock(resource);
|
2013-03-15 13:11:33 +00:00
|
|
|
if(write) {
|
|
|
|
wcscpy(write, output);
|
|
|
|
GlobalUnlock(write);
|
|
|
|
if(SetClipboardData(CF_UNICODETEXT, resource) == FALSE) {
|
|
|
|
GlobalFree(resource);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CloseClipboard();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static LRESULT CALLBACK Application_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
2013-05-02 11:25:45 +00:00
|
|
|
Object* object = (Object*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
2013-03-15 13:11:33 +00:00
|
|
|
if(!object || !dynamic_cast<Window*>(object)) return DefWindowProc(hwnd, msg, wparam, lparam);
|
2013-05-02 11:25:45 +00:00
|
|
|
Window& window = (Window&)*object;
|
2013-03-15 13:11:33 +00:00
|
|
|
|
|
|
|
bool process = true;
|
|
|
|
if(pWindow::modal.size() > 0 && !pWindow::modal.find(&window.p)) process = false;
|
|
|
|
if(applicationState.quit) process = false;
|
|
|
|
|
|
|
|
if(process) switch(msg) {
|
|
|
|
case WM_CLOSE: {
|
|
|
|
if(window.onClose) window.onClose();
|
|
|
|
else window.setVisible(false);
|
|
|
|
if(window.state.modal && !window.visible()) window.setModal(false);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
case WM_MOVE: {
|
|
|
|
if(window.p.locked) break;
|
|
|
|
|
|
|
|
Geometry geometry = window.geometry();
|
|
|
|
window.state.geometry.x = geometry.x;
|
|
|
|
window.state.geometry.y = geometry.y;
|
|
|
|
|
|
|
|
if(window.onMove) window.onMove();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case WM_SIZE: {
|
|
|
|
if(window.p.locked) break;
|
|
|
|
SetWindowPos(window.p.hstatus, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED);
|
|
|
|
|
|
|
|
Geometry geometry = window.geometry();
|
|
|
|
window.state.geometry.width = geometry.width;
|
|
|
|
window.state.geometry.height = geometry.height;
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
for(auto& layout : window.state.layout) {
|
2013-03-15 13:11:33 +00:00
|
|
|
Geometry geom = window.geometry();
|
|
|
|
geom.x = geom.y = 0;
|
|
|
|
layout.setGeometry(geom);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(window.onSize) window.onSize();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case WM_GETMINMAXINFO: {
|
2013-05-02 11:25:45 +00:00
|
|
|
MINMAXINFO* mmi = (MINMAXINFO*)lparam;
|
2013-03-15 13:11:33 +00:00
|
|
|
//mmi->ptMinTrackSize.x = 256 + window.p.frameMargin().width;
|
|
|
|
//mmi->ptMinTrackSize.y = 256 + window.p.frameMargin().height;
|
|
|
|
//return TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-07-29 09:42:45 +00:00
|
|
|
case WM_ENTERMENULOOP:
|
|
|
|
case WM_ENTERSIZEMOVE: {
|
|
|
|
if(Application::Windows::onModalBegin) Application::Windows::onModalBegin();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
case WM_EXITMENULOOP:
|
|
|
|
case WM_EXITSIZEMOVE: {
|
|
|
|
if(Application::Windows::onModalEnd) Application::Windows::onModalEnd();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
case WM_ERASEBKGND: {
|
|
|
|
if(window.p.brush == 0) break;
|
|
|
|
RECT rc;
|
|
|
|
GetClientRect(window.p.hwnd, &rc);
|
|
|
|
PAINTSTRUCT ps;
|
|
|
|
BeginPaint(window.p.hwnd, &ps);
|
|
|
|
FillRect(ps.hdc, &rc, window.p.brush);
|
|
|
|
EndPaint(window.p.hwnd, &ps);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
case WM_CTLCOLORBTN:
|
|
|
|
case WM_CTLCOLORSTATIC: {
|
2013-05-02 11:25:45 +00:00
|
|
|
Object* object = (Object*)GetWindowLongPtr((HWND)lparam, GWLP_USERDATA);
|
Update to v093r02 release.
byuu says:
Changelog:
- nall: fixed major memory leak in string class
- ruby: video shaders support #define-based settings now
- phoenix/GTK+: support > 256x256 icons for window / task bar / alt-tab
- sfc: remove random/ and config/, merge into system/
- ethos: delete higan.png (48x48), replace with higan512.png (512x512)
as new higan.png
- ethos: default gamma to 100% (no color adjustment)
- ethos: use "Video Shaders/Display Emulation/" instead of "Video
Shaders/Emulation/"
- use g++ instead of g++-4.7 (g++ -v must be >= 4.7)
- use -std=c++11 instead of -std=gnu++11
- applied a few patches from Debian upstream to make their packaging job
easier
So because colors are normalized in GLSL, I won't be able to offer video
shaders absolute color literals. We will have to perform basic color
conversion inside the core.
As such, the current plan is to create some sort of Emulator::Settings
interface. With that, I'll connect an option for color correction, which
will be on by default. For FC/SFC, that will mean gamma correction
(darker / stronger colors), and for GB/GBC/GBA, it will mean simulating
the weird brightness levels of the displays. I am undecided on whether
to use pea soup green for the GB or not. By not doing so, it'll be
easier for the display emulation shader to do it.
2013-11-09 11:45:54 +00:00
|
|
|
if(object == nullptr) break;
|
|
|
|
if(dynamic_cast<HexEdit*>(object) || dynamic_cast<LineEdit*>(object) || dynamic_cast<TextEdit*>(object)) {
|
|
|
|
//text edit controls, when disabled, use CTLCOLORSTATIC instead of CTLCOLOREDIT
|
|
|
|
//override this behavior: we do not want read-only edit controls to use the parent window background color
|
|
|
|
return DefWindowProc(hwnd, WM_CTLCOLOREDIT, wparam, lparam);
|
|
|
|
} else if(window.p.brush) {
|
2013-03-15 13:11:33 +00:00
|
|
|
HDC hdc = (HDC)wparam;
|
|
|
|
SetBkColor((HDC)wparam, window.p.brushColor);
|
|
|
|
return (INT_PTR)window.p.brush;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-07-29 09:42:45 +00:00
|
|
|
case WM_DROPFILES: {
|
|
|
|
lstring paths = DropPaths(wparam);
|
|
|
|
if(paths.empty() == false) {
|
|
|
|
if(window.onDrop) window.onDrop(paths);
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
case WM_COMMAND: {
|
|
|
|
unsigned id = LOWORD(wparam);
|
|
|
|
HWND control = GetDlgItem(window.p.hwnd, id);
|
|
|
|
if(control == 0) {
|
2013-05-02 11:25:45 +00:00
|
|
|
pObject* object = (pObject*)pObject::find(id);
|
2013-03-15 13:11:33 +00:00
|
|
|
if(!object) break;
|
|
|
|
if(dynamic_cast<pItem*>(object)) {
|
2013-05-02 11:25:45 +00:00
|
|
|
Item& item = ((pItem*)object)->item;
|
2013-03-15 13:11:33 +00:00
|
|
|
if(item.onActivate) item.onActivate();
|
|
|
|
} else if(dynamic_cast<pCheckItem*>(object)) {
|
2013-05-02 11:25:45 +00:00
|
|
|
CheckItem& checkItem = ((pCheckItem*)object)->checkItem;
|
2013-03-15 13:11:33 +00:00
|
|
|
checkItem.setChecked(!checkItem.state.checked);
|
|
|
|
if(checkItem.onToggle) checkItem.onToggle();
|
|
|
|
} else if(dynamic_cast<pRadioItem*>(object)) {
|
2013-05-02 11:25:45 +00:00
|
|
|
RadioItem& radioItem = ((pRadioItem*)object)->radioItem;
|
2013-03-15 13:11:33 +00:00
|
|
|
if(radioItem.state.checked == false) {
|
|
|
|
radioItem.setChecked();
|
|
|
|
if(radioItem.onActivate) radioItem.onActivate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2013-05-02 11:25:45 +00:00
|
|
|
Object* object = (Object*)GetWindowLongPtr(control, GWLP_USERDATA);
|
2013-03-15 13:11:33 +00:00
|
|
|
if(!object) break;
|
|
|
|
if(dynamic_cast<Button*>(object)) {
|
2013-05-02 11:25:45 +00:00
|
|
|
Button& button = (Button&)*object;
|
2013-03-15 13:11:33 +00:00
|
|
|
if(button.onActivate) button.onActivate();
|
|
|
|
} else if(dynamic_cast<CheckButton*>(object)) {
|
2013-05-02 11:25:45 +00:00
|
|
|
CheckButton& checkButton = (CheckButton&)*object;
|
2013-03-15 13:11:33 +00:00
|
|
|
checkButton.setChecked(!checkButton.state.checked);
|
|
|
|
if(checkButton.onToggle) checkButton.onToggle();
|
|
|
|
} else if(dynamic_cast<ComboButton*>(object)) {
|
2013-05-02 11:25:45 +00:00
|
|
|
ComboButton& comboButton = (ComboButton&)*object;
|
2013-03-15 13:11:33 +00:00
|
|
|
if(HIWORD(wparam) == CBN_SELCHANGE) {
|
|
|
|
if(comboButton.state.selection != comboButton.selection()) {
|
|
|
|
comboButton.state.selection = comboButton.selection();
|
|
|
|
if(comboButton.onChange) comboButton.onChange();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if(dynamic_cast<LineEdit*>(object)) {
|
2013-05-02 11:25:45 +00:00
|
|
|
LineEdit& lineEdit = (LineEdit&)*object;
|
2013-03-15 13:11:33 +00:00
|
|
|
if(HIWORD(wparam) == EN_CHANGE) {
|
|
|
|
if(lineEdit.p.locked == false && lineEdit.onChange) lineEdit.onChange();
|
|
|
|
}
|
|
|
|
} else if(dynamic_cast<RadioButton*>(object)) {
|
2013-05-02 11:25:45 +00:00
|
|
|
RadioButton& radioButton = (RadioButton&)*object;
|
2013-03-15 13:11:33 +00:00
|
|
|
if(radioButton.state.checked == false) {
|
|
|
|
radioButton.setChecked();
|
|
|
|
if(radioButton.onActivate) radioButton.onActivate();
|
|
|
|
}
|
|
|
|
} else if(dynamic_cast<TextEdit*>(object)) {
|
2013-05-02 11:25:45 +00:00
|
|
|
TextEdit& textEdit = (TextEdit&)*object;
|
2013-03-15 13:11:33 +00:00
|
|
|
if(HIWORD(wparam) == EN_CHANGE) {
|
|
|
|
if(textEdit.p.locked == false && textEdit.onChange) textEdit.onChange();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case WM_NOTIFY: {
|
|
|
|
unsigned id = LOWORD(wparam);
|
|
|
|
HWND control = GetDlgItem(window.p.hwnd, id);
|
|
|
|
if(control == 0) break;
|
2013-05-02 11:25:45 +00:00
|
|
|
Object* object = (Object*)GetWindowLongPtr(control, GWLP_USERDATA);
|
|
|
|
if(object == nullptr) break;
|
2013-03-15 13:11:33 +00:00
|
|
|
if(dynamic_cast<ListView*>(object)) {
|
2013-05-02 11:25:45 +00:00
|
|
|
ListView& listView = (ListView&)*object;
|
2013-03-15 13:11:33 +00:00
|
|
|
LPNMHDR nmhdr = (LPNMHDR)lparam;
|
|
|
|
LPNMLISTVIEW nmlistview = (LPNMLISTVIEW)lparam;
|
|
|
|
|
|
|
|
if(nmhdr->code == LVN_ITEMCHANGED && (nmlistview->uChanged & LVIF_STATE)) {
|
|
|
|
unsigned imagemask = ((nmlistview->uNewState & LVIS_STATEIMAGEMASK) >> 12) - 1;
|
|
|
|
if(imagemask == 0 || imagemask == 1) {
|
|
|
|
if(listView.p.locked == false && listView.onToggle) listView.onToggle(nmlistview->iItem);
|
|
|
|
} else if((nmlistview->uOldState & LVIS_FOCUSED) && !(nmlistview->uNewState & LVIS_FOCUSED)) {
|
|
|
|
listView.p.lostFocus = true;
|
|
|
|
} else if(!(nmlistview->uOldState & LVIS_SELECTED) && (nmlistview->uNewState & LVIS_SELECTED)) {
|
|
|
|
listView.p.lostFocus = false;
|
|
|
|
listView.state.selected = true;
|
|
|
|
listView.state.selection = listView.selection();
|
|
|
|
if(listView.p.locked == false && listView.onChange) listView.onChange();
|
|
|
|
} else if(listView.p.lostFocus == false && listView.selected() == false) {
|
|
|
|
listView.p.lostFocus = false;
|
|
|
|
listView.state.selected = false;
|
|
|
|
listView.state.selection = 0;
|
|
|
|
if(listView.p.locked == false && listView.onChange) listView.onChange();
|
|
|
|
}
|
|
|
|
} else if(nmhdr->code == LVN_ITEMACTIVATE) {
|
Update to v093r01 release.
byuu says:
Changelog:
- added SA-1 MDR; fixes bug in SD Gundam G-Next where the main
battleship was unable to fire
- added out-of-the-box support for any BSD running Clang 3.3+ (FreeBSD
10+, notably)
- added new video shader, "Display Emulation", which changes the shader
based on the emulated system
- fixed the home button to go to your default library path
- phoenix: Windows port won't send onActivate unless an item is selected
(prevents crashing on pressing enter in file dialog)
- ruby: removed vec4 position from out Vertex {} (helps AMD cards)
- shaders: updated all shaders to use texture() instead of texture2D()
(helps AMD cards)
The "Display Emulation" option works like this: when selected, it tries
to load "<path>/Video Shaders/Emulation/<systemName>.shader/"; otherwise
it falls back to the blur shader. <path> is the usual (next to binary,
then in <config>/higan, then in /usr/share/higan, etc); and <systemName>
is "Famicom", "Super Famicom", "Game Boy", "Game Boy Color", "Game Boy
Advance"
To support BSD, I had to modify the $(platform) variable to
differentiate between Linux and BSD.
As such, the new $(platform) values are:
win -> windows
osx -> macosx
x -> linux or bsd
I am also checking uname -s instead of uname -a now. No reason to
potentially match the hostname to the wrong OS type.
2013-10-21 11:45:39 +00:00
|
|
|
if(listView.state.text.size() && listView.selected()) {
|
|
|
|
if(listView.onActivate) listView.onActivate();
|
|
|
|
}
|
2013-03-15 13:11:33 +00:00
|
|
|
} else if(nmhdr->code == NM_CUSTOMDRAW) {
|
|
|
|
LPNMLVCUSTOMDRAW lvcd = (LPNMLVCUSTOMDRAW)nmhdr;
|
|
|
|
switch(lvcd->nmcd.dwDrawStage) {
|
|
|
|
case CDDS_PREPAINT:
|
|
|
|
return CDRF_NOTIFYITEMDRAW;
|
|
|
|
case CDDS_ITEMPREPAINT:
|
|
|
|
if(listView.state.headerText.size() >= 2) {
|
|
|
|
//draw alternating row colors of there are two or more columns
|
|
|
|
if(lvcd->nmcd.dwItemSpec % 2) lvcd->clrTextBk = GetSysColor(COLOR_WINDOW) ^ 0x070707;
|
|
|
|
}
|
|
|
|
return CDRF_DODEFAULT;
|
|
|
|
default:
|
|
|
|
return CDRF_DODEFAULT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case WM_HSCROLL:
|
|
|
|
case WM_VSCROLL: {
|
2013-05-02 11:25:45 +00:00
|
|
|
Object* object = nullptr;
|
2013-03-15 13:11:33 +00:00
|
|
|
if(lparam) {
|
|
|
|
object = (Object*)GetWindowLongPtr((HWND)lparam, GWLP_USERDATA);
|
|
|
|
} else {
|
|
|
|
unsigned id = LOWORD(wparam);
|
|
|
|
HWND control = GetDlgItem(window.p.hwnd, id);
|
|
|
|
if(control == 0) break;
|
|
|
|
object = (Object*)GetWindowLongPtr(control, GWLP_USERDATA);
|
|
|
|
}
|
2013-05-02 11:25:45 +00:00
|
|
|
if(object == nullptr) break;
|
2013-03-15 13:11:33 +00:00
|
|
|
|
|
|
|
if(dynamic_cast<HorizontalScroller*>(object)
|
|
|
|
|| dynamic_cast<VerticalScroller*>(object)) {
|
|
|
|
SCROLLINFO info;
|
|
|
|
memset(&info, 0, sizeof(SCROLLINFO));
|
|
|
|
info.cbSize = sizeof(SCROLLINFO);
|
|
|
|
info.fMask = SIF_ALL;
|
|
|
|
GetScrollInfo((HWND)lparam, SB_CTL, &info);
|
|
|
|
|
|
|
|
switch(LOWORD(wparam)) {
|
|
|
|
case SB_LEFT: info.nPos = info.nMin; break;
|
|
|
|
case SB_RIGHT: info.nPos = info.nMax; break;
|
|
|
|
case SB_LINELEFT: info.nPos--; break;
|
|
|
|
case SB_LINERIGHT: info.nPos++; break;
|
|
|
|
case SB_PAGELEFT: info.nPos -= info.nMax >> 3; break;
|
|
|
|
case SB_PAGERIGHT: info.nPos += info.nMax >> 3; break;
|
|
|
|
case SB_THUMBTRACK: info.nPos = info.nTrackPos; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
info.fMask = SIF_POS;
|
|
|
|
SetScrollInfo((HWND)lparam, SB_CTL, &info, TRUE);
|
|
|
|
|
|
|
|
//Windows may clamp position to scroller range
|
|
|
|
GetScrollInfo((HWND)lparam, SB_CTL, &info);
|
|
|
|
|
|
|
|
if(dynamic_cast<HorizontalScroller*>(object)) {
|
2013-05-02 11:25:45 +00:00
|
|
|
HorizontalScroller& horizontalScroller = (HorizontalScroller&)*object;
|
2013-03-15 13:11:33 +00:00
|
|
|
if(horizontalScroller.state.position != info.nPos) {
|
|
|
|
horizontalScroller.state.position = info.nPos;
|
|
|
|
if(horizontalScroller.onChange) horizontalScroller.onChange();
|
|
|
|
}
|
|
|
|
} else {
|
2013-05-02 11:25:45 +00:00
|
|
|
VerticalScroller& verticalScroller = (VerticalScroller&)*object;
|
2013-03-15 13:11:33 +00:00
|
|
|
if(verticalScroller.state.position != info.nPos) {
|
|
|
|
verticalScroller.state.position = info.nPos;
|
|
|
|
if(verticalScroller.onChange) verticalScroller.onChange();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(dynamic_cast<HorizontalSlider*>(object)) {
|
2013-05-02 11:25:45 +00:00
|
|
|
HorizontalSlider& horizontalSlider = (HorizontalSlider&)*object;
|
2013-03-15 13:11:33 +00:00
|
|
|
if(horizontalSlider.state.position != horizontalSlider.position()) {
|
|
|
|
horizontalSlider.state.position = horizontalSlider.position();
|
|
|
|
if(horizontalSlider.onChange) horizontalSlider.onChange();
|
|
|
|
}
|
|
|
|
} else if(dynamic_cast<VerticalSlider*>(object)) {
|
2013-05-02 11:25:45 +00:00
|
|
|
VerticalSlider& verticalSlider = (VerticalSlider&)*object;
|
2013-03-15 13:11:33 +00:00
|
|
|
if(verticalSlider.state.position != verticalSlider.position()) {
|
|
|
|
verticalSlider.state.position = verticalSlider.position();
|
|
|
|
if(verticalSlider.onChange) verticalSlider.onChange();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return DefWindowProc(hwnd, msg, wparam, lparam);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|