Add support for a double-click in the ListView to invoke a 'default action'.
Because we receive both NM_CLICK and then NM_DBCLK, reduce the area of a pop-up column which is sensitive to a click to the drop-down button (which opens a focus-stealing pop-up menu), so the rest of the area can receive a click (which does nothing) or a double-click (which does the default action). For a package, this default action is to toggle between the currently installed version (or uninstalled, if not installed), and the highest non-test version. There is no keyboard acceleration for this action currently. Signed-off-by: Jon Turney <jon.tur...@dronecode.org.uk> --- ListView.cc | 38 +++++++++++++++++++++++++++++++++++++- ListView.h | 1 + PickCategoryLine.cc | 6 ++++++ PickCategoryLine.h | 1 + PickPackageLine.cc | 11 +++++++++++ PickPackageLine.h | 1 + package_meta.cc | 21 +++++++++++++++++++++ package_meta.h | 1 + 8 files changed, 79 insertions(+), 1 deletion(-) diff --git a/ListView.cc b/ListView.cc index d58780b..a6dc56d 100644 --- a/ListView.cc +++ b/ListView.cc @@ -345,9 +345,19 @@ ListView::OnNotify (NMHDR *pNmHdr, LRESULT *pResult) if (headers[iCol].type == ListView::ControlType::popup) { POINT p; - // position pop-up menu at the location of the click GetCursorPos(&p); + RECT r; + ListView_GetSubItemRect(hWndListView, iRow, iCol, LVIR_BOUNDS, &r); + POINT cp = p; + ::ScreenToClient(hWndListView, &cp); + + // if the click isn't over the pop-up button, do nothing yet (but this + // might be followed by a NM_DBLCLK) + if (cp.x < r.right - GetSystemMetrics(SM_CXVSCROLL)) + return true; + + // position pop-up menu at the location of the click update = popup_menu(iRow, iCol, p); } else @@ -366,6 +376,32 @@ ListView::OnNotify (NMHDR *pNmHdr, LRESULT *pResult) } break; + case NM_DBLCLK: + { + NMITEMACTIVATE *pNmItemAct = (NMITEMACTIVATE *) pNmHdr; +#if DEBUG + Log (LOG_BABBLE) << "NM_DBLCLICK: pnmitem->iItem " << pNmItemAct->iItem << " pNmItemAct->iSubItem " << pNmItemAct->iSubItem << endLog; +#endif + int iRow = pNmItemAct->iItem; + int iCol = pNmItemAct->iSubItem; + if (iRow < 0) + return false; + + int update = 0; + + // Inform the item of the double-click + update = (*contents)[iRow]->do_default_action(iCol ); + + // Update items, if needed + if (update > 0) + { + ListView_RedrawItems(hWndListView, iRow, iRow + update -1); + } + + return true; + } + break; + case NM_CUSTOMDRAW: { NMLVCUSTOMDRAW *pNmLvCustomDraw = (NMLVCUSTOMDRAW *)pNmHdr; diff --git a/ListView.h b/ListView.h index 97b138a..519b61a 100644 --- a/ListView.h +++ b/ListView.h @@ -37,6 +37,7 @@ class ListViewLine virtual int get_indent() const = 0; virtual ActionList *get_actions(int col) const = 0; virtual int do_action(int col, int id) = 0; + virtual int do_default_action(int col) = 0; virtual bool map_key_to_action(WORD vkey, int *col_num, int *action_id) const = 0; }; diff --git a/PickCategoryLine.cc b/PickCategoryLine.cc index c088cd4..7aa1f28 100644 --- a/PickCategoryLine.cc +++ b/PickCategoryLine.cc @@ -56,6 +56,12 @@ PickCategoryLine::do_action(int col_num, int action_id) return 1; } +int +PickCategoryLine::do_default_action(int col_num) +{ + return 0; +} + ActionList * PickCategoryLine::get_actions(int col) const { diff --git a/PickCategoryLine.h b/PickCategoryLine.h index 9486904..35b90e6 100644 --- a/PickCategoryLine.h +++ b/PickCategoryLine.h @@ -40,6 +40,7 @@ public: int get_indent() const; ActionList *get_actions(int col) const; int do_action(int col, int action_id); + int do_default_action(int col); bool map_key_to_action(WORD vkey, int *col_num, int *action_id) const; private: diff --git a/PickPackageLine.cc b/PickPackageLine.cc index 1f884be..685d632 100644 --- a/PickPackageLine.cc +++ b/PickPackageLine.cc @@ -144,6 +144,17 @@ PickPackageLine::do_action(int col_num, int action_id) return 0; } +int +PickPackageLine::do_default_action(int col_num) +{ + if (col_num == new_col) + { + pkg.toggle_action(); + return 1; + } + return 0; +} + ActionList * PickPackageLine::get_actions(int col_num) const { diff --git a/PickPackageLine.h b/PickPackageLine.h index a35f399..3877a4b 100644 --- a/PickPackageLine.h +++ b/PickPackageLine.h @@ -36,6 +36,7 @@ public: int get_indent() const; ActionList *get_actions(int col_num) const; int do_action(int col, int action_id); + int do_default_action(int col); bool map_key_to_action(WORD vkey, int *col_num, int *action_id) const; private: packagemeta & pkg; diff --git a/package_meta.cc b/package_meta.cc index cbb7388..3509f05 100644 --- a/package_meta.cc +++ b/package_meta.cc @@ -465,6 +465,27 @@ packagemeta::select_action (int id, trusts const deftrust) user_picked = true; } +// toggle between the currently installed version (or uninstalled, if not +// installed), and the naively preferred version (the highest non-test version) +void +packagemeta::toggle_action () +{ + if (desired != installed) + { + set_action(Default_action, installed); + } + else + { + packageversion naively_preferred; + std::set<packageversion>::iterator i = versions.begin (); + for (i = versions.begin (); i != versions.end (); ++i) + if (!packagedb::solver.is_test_package(*i)) + naively_preferred = *i; + + set_action(Install_action, naively_preferred); + } +} + ActionList * packagemeta::list_actions(trusts const trust) { diff --git a/package_meta.h b/package_meta.h index 0eff8d0..c9bfe7c 100644 --- a/package_meta.h +++ b/package_meta.h @@ -63,6 +63,7 @@ public: void set_action (_actions, packageversion const & default_version); ActionList *list_actions(trusts const trust); void select_action (int id, trusts const deftrust); + void toggle_action (); void set_message (const std::string& message_id, const std::string& message_string) { -- 2.17.0