From bc7456246c0c25234e53737da9540ad64bd9828f Mon Sep 17 00:00:00 2001 From: byuu <2107894+byuu@users.noreply.github.com> Date: Thu, 1 Aug 2019 02:40:35 +0900 Subject: [PATCH] v108.3 * add support for TableView::onActivate(TableViewCell) to Windows, macOS ** allows the new input/hotkey mapping panels to work on Windows, macOS * polish BrowserDialog behavior --- bsnes/emulator/emulator.hpp | 2 +- bsnes/target-bsnes/input/input.hpp | 5 ---- hiro/cocoa/widget/table-view.cpp | 25 +++++++++++------ hiro/cocoa/widget/table-view.hpp | 1 - hiro/extension/browser-dialog.cpp | 45 ++++++++++++++++++++++++------ hiro/windows/utility.cpp | 14 ++++++++-- hiro/windows/widget/table-view.cpp | 15 ++++++++++ hiro/windows/widget/table-view.hpp | 1 + 8 files changed, 80 insertions(+), 28 deletions(-) diff --git a/bsnes/emulator/emulator.hpp b/bsnes/emulator/emulator.hpp index 3baae31d..9bcba588 100644 --- a/bsnes/emulator/emulator.hpp +++ b/bsnes/emulator/emulator.hpp @@ -31,7 +31,7 @@ using namespace nall; namespace Emulator { static const string Name = "bsnes"; - static const string Version = "108.2"; + static const string Version = "108.3"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "https://byuu.org"; diff --git a/bsnes/target-bsnes/input/input.hpp b/bsnes/target-bsnes/input/input.hpp index d93d078f..342c0810 100644 --- a/bsnes/target-bsnes/input/input.hpp +++ b/bsnes/target-bsnes/input/input.hpp @@ -1,9 +1,4 @@ -#if defined(PLATFORM_WINDOWS) || defined(PLATFORM_MACOS) -//TODO: hiro support for TableView::activate(TableViewCell) is required for > 1 binding -enum : uint { BindingLimit = 1 }; -#else enum : uint { BindingLimit = 4 }; -#endif struct InputMapping { auto bind() -> void; diff --git a/hiro/cocoa/widget/table-view.cpp b/hiro/cocoa/widget/table-view.cpp index e41bd33b..783a1184 100755 --- a/hiro/cocoa/widget/table-view.cpp +++ b/hiro/cocoa/widget/table-view.cpp @@ -110,13 +110,15 @@ tableView->doChange(); } --(IBAction) activate:(id)sender { - tableView->doActivate({}); -} - -(IBAction) doubleAction:(id)sender { - if([content clickedRow] >= 0) { - [self activate:self]; + int row = [content clickedRow]; + if(row >= 0 && row < tableView->state.items.size()) { + int column = [content clickedColumn]; + if(column >= 0 && column < tableView->state.columns.size()) { + auto item = tableView->state.items[row]; + auto cell = item->cell(column); + tableView->doActivate(cell); + } } } @@ -127,9 +129,14 @@ -(void) keyDown:(NSEvent*)event { auto character = [[event characters] characterAtIndex:0]; if(character == NSEnterCharacter || character == NSCarriageReturnCharacter) { - if([self selectedRow] >= 0) { - [[self delegate] activate:self]; - return; + int row = [self selectedRow]; + if(row >= 0 && row < tableView->state.items.size()) { + int column = max(0, [self selectedColumn]); //can be -1? + if(column >= 0 && column < tableView->state.columns.size()) { + auto item = tableView->state.items[row]; + auto cell = item->cell(column); + tableView->doActivate(cell); + } } } diff --git a/hiro/cocoa/widget/table-view.hpp b/hiro/cocoa/widget/table-view.hpp index 4c08f8df..6c53255b 100755 --- a/hiro/cocoa/widget/table-view.hpp +++ b/hiro/cocoa/widget/table-view.hpp @@ -20,7 +20,6 @@ -(NSString*) tableView:(NSTableView*)table toolTipForCell:(NSCell*)cell rect:(NSRectPointer)rect tableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row mouseLocation:(NSPoint)mouseLocation; -(void) tableView:(NSTableView*)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row; -(void) tableViewSelectionDidChange:(NSNotification*)notification; --(IBAction) activate:(id)sender; -(IBAction) doubleAction:(id)sender; @end diff --git a/hiro/extension/browser-dialog.cpp b/hiro/extension/browser-dialog.cpp index a2ef91dd..1dbca658 100755 --- a/hiro/extension/browser-dialog.cpp +++ b/hiro/extension/browser-dialog.cpp @@ -8,6 +8,8 @@ struct BrowserDialogWindow { auto activate() -> void; auto change() -> void; auto context() -> void; + auto isObject(const string& name) -> bool; + auto isFile(const string& name) -> bool; auto isFolder(const string& name) -> bool; auto isMatch(const string& name) -> bool; auto run() -> BrowserDialog::Response; @@ -43,7 +45,7 @@ private: vector> filters; }; -//accept button clicked, or enter pressed on file name line edit +//accept button clicked, or enter pressed inside file name field //also called by table view activate after special case handling auto BrowserDialogWindow::accept() -> void { auto batched = view.batched(); @@ -51,7 +53,7 @@ auto BrowserDialogWindow::accept() -> void { if(state.action == "openFile" && batched.size() == 1) { string name = batched[0].text(); if(isFolder(name)) return setPath({state.path, name}); - response.selected.append(string{state.path, name}); + response.selected.append({state.path, name}); } if(state.action == "openFiles" && batched) { @@ -63,20 +65,20 @@ auto BrowserDialogWindow::accept() -> void { response.selected.reset(); return; } - response.selected.append(string{state.path, name}); + response.selected.append({state.path, name}); } } if(state.action == "openFolder" && batched.size() == 1) { string name = batched[0].text(); if(!isMatch(name)) return setPath({state.path, name}); - response.selected.append(string{state.path, name, "/"}); + response.selected.append({state.path, name, "/"}); } if(state.action == "openObject" && batched.size() == 1) { string name = batched[0].text(); if(!isMatch(name) && isFolder(name)) return setPath({state.path, name}); - response.selected.append(string{state.path, name, isFolder(name) ? "/" : ""}); + response.selected.append({state.path, name, isFolder(name) ? "/" : ""}); } if(state.action == "saveFile") { @@ -85,7 +87,7 @@ auto BrowserDialogWindow::accept() -> void { if(file::exists({state.path, name})) { if(MessageDialog("File already exists. Overwrite it?").question() != "Yes") return; } - response.selected.append(string{state.path, name}); + response.selected.append({state.path, name}); } if(state.action == "selectFolder") { @@ -93,7 +95,7 @@ auto BrowserDialogWindow::accept() -> void { response.selected.append(state.path); } else if(batched.size() == 1) { string name = batched[0].text(); - if(isFolder(name)) response.selected.append(string{state.path, name, "/"}); + if(isFolder(name)) response.selected.append({state.path, name, "/"}); } } @@ -137,9 +139,13 @@ auto BrowserDialogWindow::change() -> void { acceptButton.setEnabled(batched.size() == 1); } if(state.action == "saveFile") { + string result; if(batched.size() == 1) { string name = batched[0].text(); - if(!isFolder(name)) fileName.setText(name).doChange(); + if(!isFolder(name)) result = name; + } + if(result != fileName.text()) { + fileName.setText(result).doChange(); } } if(state.action == "selectFolder") { @@ -165,6 +171,14 @@ auto BrowserDialogWindow::context() -> void { contextMenu.setVisible(); } +auto BrowserDialogWindow::isObject(const string& name) -> bool { + return inode::exists({state.path, name}); +} + +auto BrowserDialogWindow::isFile(const string& name) -> bool { + return file::exists({state.path, name}); +} + auto BrowserDialogWindow::isFolder(const string& name) -> bool { return directory::exists({state.path, name}); } @@ -217,8 +231,21 @@ auto BrowserDialogWindow::run() -> BrowserDialog::Response { iconSearch.scale(16_sx, 16_sy); searchButton.setIcon(iconSearch).setBordered(false).onActivate([&] { setPath(state.path, fileName.text()); }); fileName.onActivate([&] { + string name = fileName.text(); + if((state.action == "openFile" || state.action == "openFiles") && isFile(name)) { + response.selected.append({state.path, name}); + return (void)window.setModal(false); + } + if((state.action == "openFolder" || state.action == "selectFolder") && isFolder(name)) { + response.selected.append({state.path, name}); + return (void)window.setModal(false); + } + if(state.action == "openObject" && isObject(name)) { + response.selected.append({state.path, name}); + return (void)window.setModal(false); + } if(state.action == "saveFile") return accept(); - setPath(state.path, fileName.text()); + setPath(state.path, name); }).onChange([&] { auto name = fileName.text(); if(state.action == "saveFile") acceptButton.setEnabled(name && !isFolder(name)); diff --git a/hiro/windows/utility.cpp b/hiro/windows/utility.cpp index 951d8bb4..bde5dcd1 100755 --- a/hiro/windows/utility.cpp +++ b/hiro/windows/utility.cpp @@ -447,18 +447,26 @@ static auto CALLBACK Shared_windowProc(WindowProc windowProc, HWND hwnd, UINT ms #if defined(Hiro_TableView) case AppMessage::TableView_doPaint: { if(auto tableView = (mTableView*)lparam) { - if(auto self = tableView->self()) InvalidateRect(self->hwnd, nullptr, true); + if(auto self = tableView->self()) { + InvalidateRect(self->hwnd, nullptr, true); + } } break; } case AppMessage::TableView_onActivate: { - if(auto tableView = (mTableView*)lparam) tableView->doActivate({}); + if(auto tableView = (mTableView*)lparam) { + if(auto self = tableView->self()) { + tableView->doActivate(self->activateCell); + } + } break; } case AppMessage::TableView_onChange: { - if(auto tableView = (mTableView*)lparam) tableView->doChange(); + if(auto tableView = (mTableView*)lparam) { + tableView->doChange(); + } } #endif } diff --git a/hiro/windows/widget/table-view.cpp b/hiro/windows/widget/table-view.cpp index 8e127330..bd5dcdc2 100755 --- a/hiro/windows/widget/table-view.cpp +++ b/hiro/windows/widget/table-view.cpp @@ -105,6 +105,21 @@ auto pTableView::onActivate(LPARAM lparam) -> void { auto nmlistview = (LPNMLISTVIEW)lparam; if(ListView_GetSelectedCount(hwnd) == 0) return; if(!locked()) { + activateCell = TableViewCell(); + LVHITTESTINFO hitTest{}; + GetCursorPos(&hitTest.pt); + ScreenToClient(nmlistview->hdr.hwndFrom, &hitTest.pt); + ListView_SubItemHitTest(nmlistview->hdr.hwndFrom, &hitTest); + if(hitTest.flags & LVHT_ONITEM) { + int row = hitTest.iItem; + if(row >= 0 && row < state().items.size()) { + int column = hitTest.iSubItem; + if(column >= 0 && column < state().columns.size()) { + auto item = state().items[row]; + activateCell = item->cell(column); + } + } + } //LVN_ITEMACTIVATE is not re-entrant until DispatchMessage() completes //thus, we don't call self().doActivate() here PostMessageOnce(_parentHandle(), AppMessage::TableView_onActivate, 0, (LPARAM)&reference); diff --git a/hiro/windows/widget/table-view.hpp b/hiro/windows/widget/table-view.hpp index c8efe055..56bf2de0 100644 --- a/hiro/windows/widget/table-view.hpp +++ b/hiro/windows/widget/table-view.hpp @@ -35,6 +35,7 @@ struct pTableView : pWidget { auto _setIcons() -> void; auto _width(unsigned column) -> unsigned; + TableViewCell activateCell; HIMAGELIST imageList = 0; vector icons; };