From 34e9dbb6af348fd88d1b1676ad9c0e5463ff24fc Mon Sep 17 00:00:00 2001 From: Nick Gammon Date: Fri, 24 Sep 2010 10:55:50 +1000 Subject: [PATCH] Improvements to utils.filterpicker to allow filter function --- dialogs/FunctionListDlg.cpp | 64 +++++++++++++++++++++++++++++++++---- dialogs/FunctionListDlg.h | 4 +++ scripting/lua_utils.cpp | 17 ++++++++++ 3 files changed, 78 insertions(+), 7 deletions(-) diff --git a/dialogs/FunctionListDlg.cpp b/dialogs/FunctionListDlg.cpp index 943b5037..18bc2f70 100644 --- a/dialogs/FunctionListDlg.cpp +++ b/dialogs/FunctionListDlg.cpp @@ -11,6 +11,8 @@ static char THIS_FILE[] = __FILE__; #endif +#pragma warning (disable : 4800) // forcing value to bool 'true' or 'false' (performance warning) + ///////////////////////////////////////////////////////////////////////////// // CFunctionListDlg dialog @@ -22,6 +24,8 @@ CFunctionListDlg::CFunctionListDlg(CWnd* pParent /*=NULL*/) m_strFilter = _T(""); //}}AFX_DATA_INIT m_bFunctions = false; + m_bNoSort = false; + m_L = NULL; } @@ -62,7 +66,6 @@ BOOL CFunctionListDlg::ReloadList () m_ctlFunctions.DeleteAllItems (); - m_strFilter.MakeLower (); m_strFilter.TrimLeft (); m_strFilter.TrimRight (); @@ -77,15 +80,54 @@ BOOL CFunctionListDlg::ReloadList () it != m_data.end (); it++, nKeynum++) { - string sValue = it->sValue_; + CKeyValuePair kv = *it; + string sValue = kv.sValue_; + bool bWanted = false; + + if (m_L && lua_type (m_L, 1) == LUA_TFUNCTION) + { - if (sFilter.empty () || search (sValue.begin (), sValue.end (), + // Lua filter: function f (filter, key, value) ... end + + // filter function (make copy) + lua_pushvalue (m_L, 1); + // what they have currently typed + lua_pushlstring (m_L, sFilter.c_str (), sFilter.size ()); + + // push number or string which is the key + if (kv.bNumber_) + lua_pushnumber (m_L, kv.iKey_); + else + lua_pushlstring (m_L, kv.sKey_.c_str (), kv.sKey_.size ()); + + // push value + lua_pushlstring (m_L, kv.sValue_.c_str (), kv.sValue_.size ()); + + // call the function: arg1: filter field, arg2: key, arg3: value + if (lua_pcall (m_L, 3, 1, 0)) // call with 3 args and 1 result + { + LuaError (m_L); // note that this clears the stack, so we won't call it again + lua_settop (m_L, 0); // clear stack, just in case LuaError changes behaviour + bWanted = false; + } // end of error + else + { + bWanted = lua_toboolean (m_L, -1); + lua_pop (m_L, 1); // pop result + } // end of no error + + } // end of Lua filter function available + else + // no Lua function, just do a substring compare + bWanted = sFilter.empty () || search (sValue.begin (), sValue.end (), sFilter.begin (), sFilter.end (), - nocase_compare) != sValue.end ()) + nocase_compare) != sValue.end (); + + if (bWanted) { int iPos = m_ctlFunctions.InsertItem (nItem, sValue.c_str ()); if (iPos != -1) - m_ctlFunctions.SetItemData (iPos, nKeynum); + m_ctlFunctions.SetItemData (iPos, nKeynum); // sorting changes the position // select the exact match, if any (so, if they highlight world.Note then it is selected) @@ -95,8 +137,8 @@ BOOL CFunctionListDlg::ReloadList () LVIS_FOCUSED | LVIS_SELECTED); nItem++; - } - } + } // end of wanted in list + } // end of for loop // if the filtering results in a single item, select it @@ -108,6 +150,7 @@ BOOL CFunctionListDlg::ReloadList () return FALSE; } + // if no filter value, put focus there so they can type one in if (m_strFilter.IsEmpty ()) { m_ctlFilter.SetFocus (); @@ -132,6 +175,12 @@ BOOL CFunctionListDlg::OnInitDialog() { GetDlgItem(IDC_LUA_FUNCTIONS)->ShowWindow (SW_HIDE); GetDlgItem(IDC_COPY_NAME)->ShowWindow (SW_HIDE); + } + + if (m_bNoSort) + { + m_ctlFunctions.ModifyStyle (LVS_SORTASCENDING, 0); + m_ctlFunctions.ModifyStyle (LVS_SORTDESCENDING, 0); } return ReloadList (); // return TRUE unless you set the focus to a control @@ -201,3 +250,4 @@ void CFunctionListDlg::OnUpdateNeedSelection(CCmdUI* pCmdUI) pCmdUI->Enable(iWhich != -1); } // end of CFunctionListDlg::OnUpdateNeedSelection + diff --git a/dialogs/FunctionListDlg.h b/dialogs/FunctionListDlg.h index dbc01e87..d51d0d0d 100644 --- a/dialogs/FunctionListDlg.h +++ b/dialogs/FunctionListDlg.h @@ -26,6 +26,7 @@ class CFunctionListDlg : public CDialog bool m_bFunctions; + bool m_bNoSort; // dialog title CString m_strTitle; @@ -36,6 +37,9 @@ class CFunctionListDlg : public CDialog // chosen item CKeyValuePair m_result; + // Lua state for filter function + lua_State * m_L; + // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CFunctionListDlg) diff --git a/scripting/lua_utils.cpp b/scripting/lua_utils.cpp index 0178e4f5..06a3b00a 100644 --- a/scripting/lua_utils.cpp +++ b/scripting/lua_utils.cpp @@ -1567,11 +1567,14 @@ static int shell_execute (lua_State *L) // arg1 is dialog title // arg2 is table of key/value pairs - value is shown // arg3 is initial filter +// arg4 is "no sort" boolean +// arg5 is filter function int filterpicker (lua_State *L) { const char * filtertitle = luaL_optstring (L, 2, "Filter"); const char * initialfilter = luaL_optstring (L, 3, ""); + const bool bNoSort = optboolean (L, 4, 0); if (strlen (filtertitle) > 100) luaL_error (L, "title too long (max 100 characters)"); @@ -1585,6 +1588,7 @@ CFunctionListDlg dlg; dlg.m_strTitle = filtertitle; dlg.m_strFilter = initialfilter; + dlg.m_bNoSort = bNoSort; // standard Lua table iteration for (lua_pushnil (L); lua_next (L, table) != 0; lua_pop (L, 1)) @@ -1618,6 +1622,19 @@ CFunctionListDlg dlg; } // end of looping through table + if (lua_gettop (L) > 4) + { + if (!lua_isnil (L, 5)) + { + luaL_checktype (L, 5, LUA_TFUNCTION); + lua_remove (L, 1); // get rid of bottom 4 items + lua_remove (L, 1); + lua_remove (L, 1); + lua_remove (L, 1); + dlg.m_L = L; // function is now at stack item 1 + } + } + if (dlg.DoModal () != IDOK) lua_pushnil (L); else