From 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d Mon Sep 17 00:00:00 2001 From: Jef Date: Tue, 24 Sep 2024 14:54:57 +0200 Subject: Initial community commit --- Src/Plugins/Library/ml_local/queries.cpp | 1639 ++++++++++++++++++++++++++++++ 1 file changed, 1639 insertions(+) create mode 100644 Src/Plugins/Library/ml_local/queries.cpp (limited to 'Src/Plugins/Library/ml_local/queries.cpp') diff --git a/Src/Plugins/Library/ml_local/queries.cpp b/Src/Plugins/Library/ml_local/queries.cpp new file mode 100644 index 00000000..6cfe338a --- /dev/null +++ b/Src/Plugins/Library/ml_local/queries.cpp @@ -0,0 +1,1639 @@ +#include "main.h" +#include "ml_local.h" +#include "resource.h" +#include "..\..\General\gen_ml/gaystring.h" +#include "..\..\General\gen_ml/config.h" +#include "..\..\General\gen_ml/ml_ipc.h" +#include "../nde/nde.h" +#include "editquery.h" +#include "../nu/ComboBox.h" +#include "../replicant/nu/AutoWide.h" +#include "../replicant/nu/AutoChar.h" +#include "../replicant/nu/ns_wc.h" +#include "..\..\General\gen_ml/ml_ipc_0313.h" + +const wchar_t *getFilterName(unsigned int filterId, wchar_t *buffer, size_t bufferSize); + +static int m_edit_item; + +void queryStrEscape(const wchar_t *p, GayStringW &str) +{ + if (!p || !*p) return; + size_t l = wcslen(p); + wchar_t *escaped = (wchar_t *)calloc((l*3+1), sizeof(wchar_t)); + wchar_t *d = escaped; + while (p && *p) { + if (*p == L'%') { *d++ = L'%'; *d++ = L'%'; } + else if (*p == L'\"') { *d++ = L'%'; *d++ = L'2'; *d++ = L'2'; } + else if (*p == L'\'') { *d++ = L'%'; *d++ = L'2'; *d++ = L'7'; } + else if (*p == L'[') { *d++ = L'%'; *d++ = L'5'; *d++ = L'B'; } + else if (*p == L']') { *d++ = L'%'; *d++ = L'5'; *d++ = L'D'; } + else if (*p == L'(') { *d++ = L'%'; *d++ = L'2'; *d++ = L'8'; } + else if (*p == L')') { *d++ = L'%'; *d++ = L'2'; *d++ = L'9'; } + else if (*p == L'#') { *d++ = L'%'; *d++ = L'2'; *d++ = L'3'; } + else *d++ = *p; + p++; + } + *d = 0; + str.Set(escaped); + free(escaped); +} + +static INT_PTR CALLBACK scrollChildHostProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); +static INT_PTR CALLBACK childAdvanced(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); + +int m_item_mode=0,main_oninitdialog; +int m_item_image = MLTREEIMAGE_DEFAULT; +wchar_t m_item_name[256]=L""; +wchar_t m_item_query[1024]=L""; + +typedef struct { + int title; + wchar_t *query; + char sort_by; + char sort_dir; + char *columns; //xff terminated list :). NULL means default columns + int imageIndex; + int mode; +} smartViewPreset; + +#define ARTIST 0x01 +#define ALBUMARTIST 0x02 +#define GENRE 0x03 +#define PUBLISHER 0x04 +#define COMPOSER 0x05 +#define ALBUM 0x06 +#define YEAR 0x07 +#define ARTISTINDEX 0x08 +#define ALBUMARTISTINDEX 0x09 +#define PODCASTCHANNEL 0x0A +#define ALBUMART 0x0B + +#define MAKEVIEW_3FILTER(a, b, c) (a | (b << 8) | (c << 16)) +#define MAKEVIEW_2FILTER(a, b) (a | (b << 8)) + +static smartViewPreset presets[] = { + {IDS_AUDIO, L"type = 0", 0, 0, NULL, TREE_IMAGE_LOCAL_AUDIO, 1}, + {IDS_VIDEO, L"type = 1", 10, 0, "\x7\1\5\x1E\6\3\x20\x8\x9\xA\xff", TREE_IMAGE_LOCAL_VIDEO,MAKEVIEW_2FILTER(GENRE,YEAR)}, + {IDS_MOST_PLAYED, L"playcount > 0", 9, 0, "\x9\0\1\2\3\xA\xff", TREE_IMAGE_LOCAL_MOSTPLAYED,0}, + {IDS_RECENTLY_ADDED, L"dateadded > [3 days ago]", 33, 0, "\x21\0\1\2\3\xff", TREE_IMAGE_LOCAL_RECENTLYADDED,0}, + {IDS_RECENTLY_MODIFIED, L"lastupd > [3 days ago]", 11, 0, "\xB\0\1\2\3\xff", TREE_IMAGE_LOCAL_RECENTLYMODIFIED,0}, + {IDS_RECENTLY_PLAYED, L"lastplay > [2 weeks ago]", 10, 0, "\xA\x9\0\1\2\3\xff", TREE_IMAGE_LOCAL_RECENTLYPLAYED,0}, + {IDS_NEVER_PLAYED, L"playcount = 0 | playcount isempty", 0, 0, "\0\1\2\3\xff", TREE_IMAGE_LOCAL_NEVERPLAYED,0}, + {IDS_TOP_RATED, L"rating >= 3", 8, 0, "\x8\x9\0\1\2\3\xff", TREE_IMAGE_LOCAL_TOPRATED,0}, + {IDS_PODCASTS,L"ispodcast = 1", 0, 0, 0, TREE_IMAGE_LOCAL_PODCASTS, MAKEVIEW_3FILTER(GENRE,PODCASTCHANNEL,YEAR)}, + {IDS_AUDIO_BY_GENRE, L"type = 0", 0, 0, NULL, TREE_IMAGE_LOCAL_AUDIO, MAKEVIEW_3FILTER(GENRE,ARTIST,ALBUM)}, + {IDS_AUDIO_BY_INDEX, L"type = 0", 0, 0, NULL, TREE_IMAGE_LOCAL_AUDIO, MAKEVIEW_3FILTER(ARTISTINDEX,ARTIST,ALBUM)}, + {IDS_SIMPLE_ALBUM, L"type = 0", 0, 0, NULL, TREE_IMAGE_LOCAL_AUDIO, 0x0100000B}, + {IDS_60s_MUSIC, L"type = 0 and year >= 1960 and year < 1970", 0, 0, NULL, TREE_IMAGE_LOCAL_AUDIO, 1}, + {IDS_70s_MUSIC, L"type = 0 and year >= 1970 and year < 1980", 0, 0, NULL, TREE_IMAGE_LOCAL_AUDIO, 1}, + {IDS_80s_MUSIC, L"type = 0 and year >= 1980 and year < 1990", 0, 0, NULL, TREE_IMAGE_LOCAL_AUDIO, 1}, + {IDS_90s_MUSIC, L"type = 0 and year >= 1990 and year < 2000", 0, 0, NULL, TREE_IMAGE_LOCAL_AUDIO, 1}, + {IDS_00s_MUSIC, L"type = 0 and year >= 2000 and year < 2010", 0, 0, NULL, TREE_IMAGE_LOCAL_AUDIO, 1}, + {IDS_ROCK_MUSIC, L"type = 0 and genre has \"Rock\"", 0, 0, NULL, TREE_IMAGE_LOCAL_AUDIO, 1}, + {IDS_CLASSICAL_MUSIC, L"type = 0 and genre has \"Classical\"", 0, 0, NULL, TREE_IMAGE_LOCAL_AUDIO, MAKEVIEW_2FILTER(COMPOSER,ALBUM)}, + {IDS_RECORD_LABELS, L"type = 0", 0, 0, NULL, TREE_IMAGE_LOCAL_AUDIO, MAKEVIEW_3FILTER(PUBLISHER,ALBUMARTIST,ALBUM)}, + {IDS_CUSTOM, L"", 0, 0, NULL, MLTREEIMAGE_DEFAULT, 0}, +}; + +#define NUM_PRESETS (sizeof(presets) / sizeof(smartViewPreset)) + +void showdlgelements(HWND hwndDlg, int nCmdShow) { + const int dlgelems[] = { + IDC_STATIC_FILTER, + IDC_RADIO_SIMPLE, + IDC_IMAGE_SIMPLE, + IDC_STATIC_SIMPLE, + IDC_RADIO_SIMPLEALBUM, + IDC_IMAGE_SIMPLEALBUM, + IDC_STATIC_SIMPLEALBUM, + IDC_RADIO_TWOFILTERS, + IDC_IMAGE_TWOFILTERS, + IDC_STATIC_TWOFILTERS, + IDC_RADIO_THREEFILTERS, + IDC_IMAGE_THREEFILTERS, + IDC_STATIC_THREEFILTERS, + IDC_COMBO_FILTER1, + IDC_COMBO_FILTER2, + IDC_COMBO_FILTER3, + IDC_STATIC_FILTER2, + IDC_STATIC_FILTER3, + }; + for(int i=0; i < (sizeof(dlgelems)/sizeof(int)); i++) + ShowWindow(GetDlgItem(hwndDlg,dlgelems[i]),nCmdShow); +} + +#define SPL_RemoveAll(hwnd) SendMessage(hwnd,WM_USER+41,0,0) +#define SPL_GetQueryString(hwnd) SendMessage(hwnd,WM_USER+40, 0 ,0) +#define SPL_AddFilter(hwnd, filter) (HWND)scrollChildHostProc(hwnd,WM_USER+32, (WPARAM)filter, (LPARAM)1) +#define SPL_AddBlankFilter(hwnd) (HWND)scrollChildHostProc(hwnd,WM_USER+32, 0, (LPARAM)2) +#define SPL_RemoveFilter(hwnd, filterhwnd) SendMessage(hwnd,WM_USER+34,(WPARAM)filterhwnd,(LPARAM)-1) +#define SPL_UpdateScroll(hwnd) SendMessage(hwnd,WM_USER+33,0,0) + +static int m_simple_dirty; + +void SetStaticItemImage(HWND hwndDlg, UINT ctrl_id, UINT ctrl_img) +{ + SendDlgItemMessage(hwndDlg,ctrl_id,STM_SETIMAGE,IMAGE_BITMAP, + (LPARAM)LoadImage(WASABI_API_ORIG_HINST,MAKEINTRESOURCE(ctrl_img),IMAGE_BITMAP,0,0,LR_SHARED)); +} + +int ResizeComboBoxDropDownW(HWND hwndDlg, UINT id, const wchar_t *str, int width){ + SIZE size = {0}; + HWND control = GetDlgItem(hwndDlg, id); + HDC hdc = GetDC(control); + // get and select parent dialog's font so that it'll calculate things correctly + HFONT font = (HFONT)SendMessage(hwndDlg,WM_GETFONT,0,0), oldfont = (HFONT)SelectObject(hdc,font); + GetTextExtentPoint32W(hdc, str, wcslen(str)+1, &size); + + int ret = width; + if(size.cx > width) + { + SendDlgItemMessage(hwndDlg, id, CB_SETDROPPEDWIDTH, size.cx, 0); + ret = size.cx; + } + + SelectObject(hdc, oldfont); + ReleaseDC(control, hdc); + return ret; +} + +struct FiltersContext +{ + HWND last1, last2; + int mode; + HWND m_scrollchild; + int *error; +}; + +static bool EnumFilters(Scanner *scanner, nde_filter_t filter, void *context_in) +{ + FiltersContext *context = (FiltersContext *)context_in; + + HWND x = SPL_AddFilter(context->m_scrollchild,filter); + if(x) { // we have a filter which talks about a field + context->last2=context->last1; + context->last1=x; + context->mode++; + if(context->mode > 2) + context->error[0]=1; // not in our strict form + } else { // we have an AND, OR or a NOT + int f=NDE_Filter_GetOp(filter); + if(f == FILTER_OR) CheckDlgButton(context->last2,IDC_OR,TRUE); + else if(f == FILTER_AND) CheckDlgButton(context->last2,IDC_AND,TRUE); + else context->error[0]=1; // we can't do FILTER_NOT + context->mode--; + if(context->mode != 1) context->error[0]=1; // not in our strict form + } + return !context->error[0]; +} + +static INT_PTR CALLBACK addQueryFrameDialogProc2(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) { + static HWND m_scrollchild; + static int m_editting=0; + static C_Config *conf=0; + static wchar_t * m_item_meta; + static int mode; + switch(uMsg) + { + case WM_INITDIALOG: + { + const int filters[] = {IDC_COMBO_FILTER1, IDC_COMBO_FILTER2,IDC_COMBO_FILTER3}; + HWND controlWindow; + int iItem; + wchar_t buffer[512] = {0}; + + mode=0; + m_item_meta=0; + conf=0; + m_simple_dirty=0; + + openDb(); + + CheckDlgButton(hwndDlg,IDC_RADIO_SIMPLE,TRUE); + SetDlgItemTextW(hwndDlg,IDC_STATIC_INFO, WASABI_API_LNGSTRINGW(IDS_WILLS_UBER_STRING)); + EnableWindow(GetDlgItem(hwndDlg,IDC_HIDE_EXTINFO), g_config->ReadInt(L"useminiinfo2", 0)); + // set up presets combo box + { + controlWindow = GetDlgItem(hwndDlg, IDC_COMBO_PRESETS); + if (NULL != controlWindow) + { + int width = 0; + for(size_t i=0; i < NUM_PRESETS; i++) + { + if (NULL != WASABI_API_LNGSTRINGW_BUF(presets[i].title, buffer, ARRAYSIZE(buffer))) + { + iItem = SendMessageW(controlWindow, CB_ADDSTRING, 0, (LPARAM)buffer); + if (CB_ERR != iItem) + { + width = ResizeComboBoxDropDownW(hwndDlg, IDC_COMBO_PRESETS, buffer, width); + SendMessageW(controlWindow, CB_SETITEMDATA,(WPARAM)iItem, (LPARAM)(i + 1)); + } + } + } + } + } + + for(size_t i=0; i < ARRAYSIZE(filters); i++) + { + controlWindow = GetDlgItem(hwndDlg, filters[i]); + if (NULL != controlWindow) + { + int width = 0; + for(unsigned int filterId = 0;; filterId++) + { + if (NULL == getFilterName(filterId, buffer, ARRAYSIZE(buffer))) + break; + + iItem = SendMessageW(controlWindow, CB_ADDSTRING, 0, (LPARAM)buffer); + if (CB_ERR != iItem) + { + width = ResizeComboBoxDropDownW(hwndDlg, filters[i], buffer, width); + SendMessageW(controlWindow, CB_SETITEMDATA,(WPARAM)iItem, (LPARAM)filterId); + } + } + } + } + + if (lParam == 1) + { + if (m_edit_item == -1) + { + // nothing to do, m_item_name, m_item_query & m_item_mode have been set already + } + else + { + lstrcpynW(m_item_name,m_query_list[m_edit_item]->name,sizeof(m_item_name)/sizeof(wchar_t)); + lstrcpynW(m_item_query,m_query_list[m_edit_item]->query,sizeof(m_item_query)/sizeof(wchar_t)); + m_item_mode = m_query_list[m_edit_item]->mode; + m_item_image = m_query_list[m_edit_item]->imgIndex; + + // re-select the preset name if we can get a match to a known preset (looks nicer and all that) + controlWindow = GetDlgItem(hwndDlg, IDC_COMBO_PRESETS); + if (NULL != controlWindow) + { + for(size_t i=0; i < NUM_PRESETS; i++) + { + if(m_item_query[0] && !_wcsicmp(presets[i].query, m_item_query) + && presets[i].mode == m_item_mode) + { + SendMessageW(controlWindow, CB_SETCURSEL, i, 0); + SendMessage(hwndDlg,WM_COMMAND,(WPARAM)MAKEWPARAM(IDC_COMBO_PRESETS,CBN_SELCHANGE),(LPARAM)GetDlgItem(hwndDlg,IDC_COMBO_PRESETS)); + break; + } + } + } + + // config + wchar_t configDir[MAX_PATH] = {0}; + PathCombineW(configDir, g_viewsDir, m_query_list[m_edit_item]->metafn); + conf = new C_Config(configDir); + CheckDlgButton(hwndDlg, IDC_HIDE_EXTINFO, conf->ReadInt(L"midivvis", 1) ? 0 : 1); + } + SetWindowTextW(hwndDlg,WASABI_API_LNGSTRINGW(IDS_EDIT_SMART_VIEW)); + m_editting=1; + } + else + { + m_editting=0; + if (m_item_mode != -1) m_item_mode=0; + m_item_name[0]=0; + m_item_query[0]=0; + m_item_image = MLTREEIMAGE_DEFAULT; + + wchar_t filename[1024 + 256] = {0}; + extern void makemetafn(wchar_t *filename, wchar_t **out); + makemetafn(filename, &m_item_meta); + conf = new C_Config(filename); + } + + if(!mode) m_scrollchild=WASABI_API_CREATEDIALOGW(IDD_SCROLLCHILDHOST,hwndDlg,scrollChildHostProc); + else m_scrollchild=WASABI_API_CREATEDIALOGW(IDD_ADD_VIEW_CHILD_ADVANCED,hwndDlg,childAdvanced); + + // this will make sure that we've got the little images shown in all languages (done for 5.51+) + SetStaticItemImage(hwndDlg,IDC_IMAGE_SIMPLE,IDB_NEWFILTER_SIMPLE); + SetStaticItemImage(hwndDlg,IDC_IMAGE_SIMPLEALBUM,IDB_NEWFILTER_SIMPLEALBUM); + SetStaticItemImage(hwndDlg,IDC_IMAGE_TWOFILTERS,IDB_NEWFILTER_TWOFILTERS); + SetStaticItemImage(hwndDlg,IDC_IMAGE_THREEFILTERS,IDB_NEWFILTER_THREEFILTERS); + + if(m_editting==0 && g_config->ReadInt(L"newfilter_showhelp",1)) + { + showdlgelements(hwndDlg,SW_HIDE); + ShowWindow(hwndDlg,SW_SHOWNA); + EnableWindow(GetParent(hwndDlg),0); + break; // don't run through + } + else + { + ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC_INFO),SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg,IDC_CHECK_SHOWINFO),SW_HIDE); + // run through + } + } + case WM_USER+9: + { // do stuff when we're shown or preset is changed + showdlgelements(hwndDlg,SW_SHOWNA); + ShowWindow(m_scrollchild,SW_SHOWNA); + // set up filter radio buttons and combo boxes + extern int GetFilter(int mode, int n); + extern int GetNumFilters(int mode); + + int numFilters=GetNumFilters(m_item_mode); + int f[3] = {0}; + f[0] = GetFilter(m_item_mode,0); + f[1] = GetFilter(m_item_mode,1); + f[2] = GetFilter(m_item_mode,2); + + if(numFilters==0) CheckRadioButton(hwndDlg,IDC_RADIO_TWOFILTERS,IDC_RADIO_SIMPLEALBUM,IDC_RADIO_SIMPLE); + else if(numFilters==1) CheckRadioButton(hwndDlg,IDC_RADIO_TWOFILTERS,IDC_RADIO_SIMPLEALBUM,IDC_RADIO_SIMPLEALBUM); + else if(numFilters==2) CheckRadioButton(hwndDlg,IDC_RADIO_TWOFILTERS,IDC_RADIO_SIMPLEALBUM,IDC_RADIO_TWOFILTERS); + else if(numFilters==3) CheckRadioButton(hwndDlg,IDC_RADIO_TWOFILTERS,IDC_RADIO_SIMPLEALBUM,IDC_RADIO_THREEFILTERS); + + for(int i=0; i<3; i++) { + ComboBox comboBox(hwndDlg, (i==0)?IDC_COMBO_FILTER1:((i==1)?IDC_COMBO_FILTER2:IDC_COMBO_FILTER3)); + if(f[i]==0) comboBox.SelectItem(i==0?0:5); + else comboBox.SelectItem(f[i]-1); + } + // set up "name" edit control + SetDlgItemTextW(hwndDlg,IDC_NAME,m_item_name); + + // do the query editor thing... + SendMessage(hwndDlg,WM_USER+11,0,0); + } + // run through + case WM_USER+10: + { // enable filter combo boxes based on radio buttons + int numFilters=0; + if(IsDlgButtonChecked(hwndDlg,IDC_RADIO_SIMPLEALBUM)) numFilters=1; + if(IsDlgButtonChecked(hwndDlg,IDC_RADIO_TWOFILTERS)) numFilters=2; + else if(IsDlgButtonChecked(hwndDlg,IDC_RADIO_THREEFILTERS)) numFilters=3; + EnableWindow(GetDlgItem(hwndDlg,IDC_STATIC_FILTER3),numFilters>2); + EnableWindow(GetDlgItem(hwndDlg,IDC_STATIC_FILTER2),numFilters>1); + EnableWindow(GetDlgItem(hwndDlg,IDC_COMBO_FILTER3),numFilters>2); + EnableWindow(GetDlgItem(hwndDlg,IDC_COMBO_FILTER2),numFilters>1); + EnableWindow(GetDlgItem(hwndDlg,IDC_COMBO_FILTER1),numFilters>1); + + if (WM_INITDIALOG == uMsg) + { + // show edit info window and restore last position as applicable + POINT pt = {g_config->ReadInt(L"smart_x", -1), g_config->ReadInt(L"smart_y", -1)}; + if (!windowOffScreen(hwndDlg, pt)) + SetWindowPos(hwndDlg, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING); + else + ShowWindow(hwndDlg, SW_SHOWNA); + + HWND parentWindow = GetParent(hwndDlg); + if (NULL != parentWindow) + EnableWindow(parentWindow, 0); + } + /*else + ShowWindow(hwndDlg, SW_SHOW);*/ + } + break; + case WM_USER+11: + if(!mode) { + SPL_RemoveAll(m_scrollchild); + + EnterCriticalSection(&g_db_cs); + nde_scanner_t p=NDE_Table_CreateScanner(g_table); + ((Scanner *)p)->disable_date_resolution=1; // TODO: don't use C++ NDE api + + int error=0; // not really an error, just we can't express it properly + + if (m_item_query[0] && !NDE_Scanner_Query(p, m_item_query)) + error=1; // ok, actually an error. + + if (m_item_query[0] && !error) + { + FiltersContext context; + context.error = &error; + context.last1 = 0; + context.last2 = 0; + context.m_scrollchild = m_scrollchild; + context.mode = 0; + ((Scanner *)p)->WalkFilters((Scanner::FilterWalker)EnumFilters, &context); // TODO: don't use C++ NDE api + } + + NDE_Table_DestroyScanner(g_table, p); + LeaveCriticalSection(&g_db_cs); + if(error) { + SPL_RemoveAll(m_scrollchild); + HWND x = SPL_AddBlankFilter(m_scrollchild); + ComboBox c(x,IDC_COMBO1); + int n = c.GetCount(); + for(int i=0; i0 && n<=NUM_PRESETS) { + wchar_t cusStr[16] = {0}; + n--; + // populate with a preset + m_item_mode = presets[n].mode; + m_item_image = presets[n].imageIndex; + if(!_wcsicmp(WASABI_API_LNGSTRINGW_BUF(IDS_CUSTOM,cusStr,16), + WASABI_API_LNGSTRINGW(presets[n].title))) m_item_name[0]=0; + else WASABI_API_LNGSTRINGW_BUF(presets[n].title,m_item_name,256); + lstrcpynW(m_item_query,presets[n].query,sizeof(m_item_query)/sizeof(wchar_t)); + showdlgelements(hwndDlg,SW_SHOWNA); + ShowWindow(m_scrollchild,SW_SHOWNA); + ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC_INFO),SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg,IDC_CHECK_SHOWINFO),SW_HIDE); + SendMessage(hwndDlg,WM_USER+9,0,0); + } + } + break; + } + break; + // filter type radio buttons (simulate clicks on the radio button when the image or static text gets clicked) + case IDC_CHECK_SHOWINFO: + g_config->WriteInt(L"newfilter_showhelp",0); + break; + case IDC_STATIC_SIMPLE: + case IDC_IMAGE_SIMPLE: + SendMessage(GetDlgItem(hwndDlg,IDC_RADIO_SIMPLE),BM_CLICK,0,0); + break; + case IDC_STATIC_SIMPLEALBUM: + case IDC_IMAGE_SIMPLEALBUM: + SendMessage(GetDlgItem(hwndDlg,IDC_RADIO_SIMPLEALBUM),BM_CLICK,0,0); + break; + case IDC_STATIC_TWOFILTERS: + case IDC_IMAGE_TWOFILTERS: + SendMessage(GetDlgItem(hwndDlg,IDC_RADIO_TWOFILTERS),BM_CLICK,0,0); + break; + case IDC_STATIC_THREEFILTERS: + case IDC_IMAGE_THREEFILTERS: + SendMessage(GetDlgItem(hwndDlg,IDC_RADIO_THREEFILTERS),BM_CLICK,0,0); + break; + // enable filter combo boxes based on radio buttons + case IDC_RADIO_SIMPLE: + case IDC_RADIO_SIMPLEALBUM: + case IDC_RADIO_TWOFILTERS: + case IDC_RADIO_THREEFILTERS: + CheckDlgButton(hwndDlg,IDC_RADIO_SIMPLE,0); + CheckDlgButton(hwndDlg,IDC_RADIO_SIMPLEALBUM,0); + CheckDlgButton(hwndDlg,IDC_RADIO_TWOFILTERS,0); + CheckDlgButton(hwndDlg,IDC_RADIO_THREEFILTERS,0); + CheckDlgButton(hwndDlg,LOWORD(wParam),1); + SendMessage(hwndDlg,WM_USER+10,0,0); + break; + // OK and Cancel buttons + case IDOK: + { + //name + GetDlgItemTextW(hwndDlg,IDC_NAME,m_item_name,255); + m_item_name[255]=0; + if(!m_item_name[0]) { + wchar_t title[64] = {0}; + MessageBoxW(hwndDlg,WASABI_API_LNGSTRINGW(IDS_MUST_ENTER_A_NAME), + WASABI_API_LNGSTRINGW_BUF(IDS_ERROR,title,64),MB_OK); + return 0; + } + //query + if (m_simple_dirty) + SPL_GetQueryString(m_scrollchild); + + if(IsDlgButtonChecked(hwndDlg,IDC_RADIO_SIMPLEALBUM)) + { + if(conf) + { + conf->WriteInt(L"adiv2pos",100000); + conf->WriteInt(L"albumartviewmode",2); + } + m_item_mode = 0x0100000B; + } + else + { // mode + int numFilters=3; + if(IsDlgButtonChecked(hwndDlg,IDC_RADIO_SIMPLE)) numFilters=0; + else if(IsDlgButtonChecked(hwndDlg,IDC_RADIO_TWOFILTERS)) numFilters=2; + + int f[3] = {0}; + for(int i=0; i<3; i++) { + ComboBox comboBox(hwndDlg, (i==0)?IDC_COMBO_FILTER1:((i==1)?IDC_COMBO_FILTER2:IDC_COMBO_FILTER3)); + f[i] = (comboBox.GetItemData(comboBox.GetSelection()) + 1) & 0xff; + } + if(f[1] == 6) f[1]=0; + if(numFilters == 2) f[2]=0; + if(numFilters == 0) f[0]=f[1]=f[2]=0; + m_item_mode = f[0] | (f[1] << 8) | (f[2] << 16); + } + + if(conf) { + int v = IsDlgButtonChecked(hwndDlg,IDC_HIDE_EXTINFO)?0:1; + conf->WriteInt(L"midivvis",v); + + ComboBox combo(hwndDlg,IDC_COMBO_PRESETS); + int n = combo.GetItemData(combo.GetSelection()); + if(n>0 && n<=NUM_PRESETS) { + n--; + conf->WriteInt(L"mv_sort_by", presets[n].sort_by); + conf->WriteInt(L"mv_sort_dir", presets[n].sort_dir); + + if(presets[n].columns) { + int cnt = 0; + while ((unsigned char)presets[n].columns[cnt] != 0xff) + { + wchar_t buf[32] = {0}; + StringCchPrintfW(buf, ARRAYSIZE(buf), L"column%d", cnt); + conf->WriteInt(buf, (unsigned char)presets[n].columns[cnt]); + cnt++; + } + conf->WriteInt(L"nbcolumns", cnt); + } + } + } + + if (m_edit_item == -1) { + // nothing to do, return values are m_item_name, m_item_query and m_item_mode + } else { + if(!m_editting) addQueryItem(m_item_name,m_item_query,m_item_mode,1,m_item_meta, m_item_image); + else replaceQueryItem(m_edit_item,m_item_name,m_item_query,m_item_mode, m_item_image); + saveQueryTree(); + } + if(m_editting) PostMessage(plugin.hwndLibraryParent, WM_USER + 30, 0, 0); + } + case IDCANCEL: + { + RECT smart_rect = {0}; + GetWindowRect(hwndDlg, &smart_rect); + g_config->WriteInt(L"smart_x", smart_rect.left); + g_config->WriteInt(L"smart_y", smart_rect.top); + + EndDialog(hwndDlg,(LOWORD(wParam) == IDOK)); + EnableWindow(GetParent(hwndDlg),1); + break; + } + } + break; + } + return 0; +} + +static INT_PTR CALLBACK childAdvanced(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) { + switch (uMsg) + { + case WM_INITDIALOG: + { + RECT r; + HWND parentWindow, controlWindow; + parentWindow = GetAncestor(hwndDlg, GA_PARENT); + if (NULL != parentWindow && + FALSE != GetWindowRect(GetDlgItem(parentWindow,IDC_CHILDFRAME),&r)) + { + MapWindowPoints(HWND_DESKTOP, parentWindow, (POINT*)&r, 2); + SetWindowPos(hwndDlg,NULL,r.left,r.top,r.right-r.left,r.bottom-r.top,SWP_NOZORDER|SWP_NOACTIVATE); + } + + SetDlgItemTextW(hwndDlg,IDC_QUERY,m_item_query); + + controlWindow = GetDlgItem(hwndDlg, IDC_EDIT1); + if (NULL != controlWindow) + { + SetWindowTextA(controlWindow, (char*)WASABI_API_LOADRESFROMFILEW(L"TEXT", MAKEINTRESOURCEW(IDR_QUERIES_TEXT), 0)); + } + } + return 1; + case WM_USER+40: // get query str + GetDlgItemTextW(hwndDlg,IDC_QUERY,m_item_query,1024); + break; + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDC_EDIT: + { + wchar_t query[1024] = {0}; + GetDlgItemTextW(hwndDlg,IDC_QUERY,query, 1024); + wchar_t querybuf[4096] = {0}; + const wchar_t *newquery = editQuery(hwndDlg, query, querybuf, 4096); + if (newquery != NULL) { + SetDlgItemTextW(hwndDlg, IDC_QUERY, newquery); + m_simple_dirty=1; + } + } + break; + case IDC_QUERY: + m_simple_dirty=1; + break; + } + break; + } + + const int controls[] = + { + IDC_EDIT1, + }; + if (FALSE != WASABI_API_APP->DirectMouseWheel_ProcessDialogMessage(hwndDlg, uMsg, wParam, lParam, controls, ARRAYSIZE(controls))) + return TRUE; + + return 0; +} + +BOOL IsDirectMouseWheelMessage(const UINT uMsg) +{ + static UINT WINAMP_WM_DIRECT_MOUSE_WHEEL = WM_NULL; + + if (WM_NULL == WINAMP_WM_DIRECT_MOUSE_WHEEL) + { + WINAMP_WM_DIRECT_MOUSE_WHEEL = RegisterWindowMessageW(L"WINAMP_WM_DIRECT_MOUSE_WHEEL"); + if (WM_NULL == WINAMP_WM_DIRECT_MOUSE_WHEEL) + return FALSE; + } + + return (WINAMP_WM_DIRECT_MOUSE_WHEEL == uMsg); +} + +static INT_PTR CALLBACK filterProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + // populate comboboxes + { + HWND hwndCB=GetDlgItem(hwndDlg,IDC_COMBO1); + int strs[]= + { + IDS_FILENAME, + IDS_TITLE, + IDS_ARTIST, + IDS_ALBUM, + IDS_YEAR, + IDS_GENRE, + IDS_COMMENT, + IDS_TRACK_NUMBER, + IDS_LENGTH, + IDS_IS_VIDEO, + IDS_LAST_UPDATED, + IDS_PLAYED_LAST, + IDS_RATING, + NULL, // fear the 13 + NULL, // gracenote + IDS_PLAY_COUNT, + IDS_FILE_TIME, + IDS_FILE_SIZE_KB, + IDS_BITRATE_KBPS, + IDS_DISC_NUMBER, + IDS_ALBUM_ARTIST, + IDS_ALBUM_GAIN, + IDS_TRACK_GAIN, + IDS_PUBLISHER, + IDS_COMPOSER, + IDS_BPM, // no bpm + IDS_DISCS, + IDS_TRACKS, + IDS_IS_PODCAST, + IDS_PODCAST_CHANNEL, + IDS_PODCAST_PUBLISH_DATE, + NULL, + NULL, + IDS_LOSSLESS, + IDS_CATEGORY, + IDS_CODEC, + IDS_DIRECTOR, + IDS_PRODUCER, + IDS_WIDTH, + IDS_HEIGHT, + NULL, + IDS_DATE_ADDED, + }; + int x; + int cnt = 0, width = 0; + wchar_t * str; + for (x = 0; x < sizeof(strs)/sizeof(strs[0]); x ++) + { + if (strs[x]) + { + int a=SendMessageW(hwndCB, CB_ADDSTRING,0,(LPARAM)(str = WASABI_API_LNGSTRINGW(strs[x]))); + width = ResizeComboBoxDropDownW(hwndDlg, IDC_COMBO1, str, width); + SendMessage(hwndCB,CB_SETITEMDATA,(WPARAM)a,(LPARAM)x); + cnt++; + } + } + + int a=SendMessageW(hwndCB, CB_ADDSTRING,0,(LPARAM)(str = WASABI_API_LNGSTRINGW(IDS_CUSTOM))); + ResizeComboBoxDropDownW(hwndDlg, IDC_COMBO1, str, width); + SendMessage(hwndCB,CB_SETITEMDATA,(WPARAM)a,(LPARAM)0x1ea7c0de); + cnt++; + if (lParam) + { + nde_filter_t filter=(nde_filter_t)lParam; + int a=NDE_Filter_GetID(filter); + if (a != -1) + { + for (x = 0; x < cnt; x ++) + { + int d = SendMessage(hwndCB,CB_GETITEMDATA,(WPARAM)x,0); + if (d == a) + break; + } + if (x < cnt) + { + SendMessage(hwndCB,CB_SETCURSEL,x,0); + SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_COMBO1,CBN_SELCHANGE),(LPARAM)hwndCB); + int filtop=NDE_Filter_GetOp(filter); + HWND hwndCB2=GetDlgItem(hwndDlg,IDC_COMBO2); + cnt=SendMessage(hwndCB2,CB_GETCOUNT,0,0); + for (x = 0; x < cnt; x ++) + { + if (SendMessage(hwndCB2,CB_GETITEMDATA,(WPARAM)x,0) == filtop) + break; + } + if (x < cnt) + { + SendMessage(hwndCB2,CB_SETCURSEL,x,0); + SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_COMBO2,CBN_SELCHANGE),(LPARAM)hwndCB2); + } + } + } + nde_field_t f=NDE_Filter_GetData(filter); + if (f) + { + int ft=NDE_Field_GetType(f); + //hack cause we never actualy get FIELD_LENGTH here. + if (ft==FIELD_INTEGER && a==MAINTABLE_ID_LENGTH) ft=FIELD_LENGTH; + + switch (ft) + { + case FIELD_FILENAME: + case FIELD_STRING: + SetDlgItemTextW(hwndDlg,IDC_EDIT1,NDE_StringField_GetString(f)); + break; + case FIELD_LENGTH: + { + int v=NDE_IntegerField_GetValue(f); + wchar_t buf[128] = {0}; + if (v < 60) + wsprintf(buf,L"%d",v); + else if (v < 60*60) + wsprintf(buf,L"%d:%02d",v/60,v%60); + else + wsprintf(buf,L"%d:%02d:%02d",v/60/60,(v/60)%60,v%60); + + SetDlgItemText(hwndDlg,IDC_EDIT1,buf); + } + break; + case FIELD_INTEGER: + SetDlgItemInt(hwndDlg,IDC_EDIT1,NDE_IntegerField_GetValue(f),TRUE); + break; + } + } + } + } + return 1; + + case WM_USER+29: + if(IsDlgButtonChecked(hwndDlg,IDC_AND)) return 1; + if(IsDlgButtonChecked(hwndDlg,IDC_OR)) return 0; + CheckDlgButton(hwndDlg,wParam?IDC_AND:IDC_OR,TRUE); + return wParam; + case WM_USER+40: + if (wParam && lParam>0) + { + wchar_t *buf=(wchar_t *)wParam; + size_t buf_len=(size_t)lParam; + // produce expression here + HWND hwndCB=GetDlgItem(hwndDlg,IDC_COMBO1); + HWND hwndCB2=GetDlgItem(hwndDlg,IDC_COMBO2); + int x=SendMessage(hwndCB,CB_GETCURSEL,0,0); + if (x != CB_ERR) + { + int Id=SendMessage(hwndCB,CB_GETITEMDATA,x,0); + if(Id == 0x1ea7c0de) { // custom! + GetDlgItemTextW(hwndDlg,IDC_EDIT1,buf,buf_len); + return 0; + } + x = SendMessage(hwndCB2,CB_GETCURSEL,0,0); + if (x != CB_ERR) + { + int Op=SendMessage(hwndCB2,CB_GETITEMDATA,x,0); + + if (Id != -1 && Op != -1) + { + wchar_t res[256] = {0}; + GetDlgItemTextW(hwndDlg,IDC_EDIT1,res,255); + res[255]=0; + nde_field_t p = NDE_Table_GetColumnByID(g_table, (unsigned char)Id); + if (p) + { + const wchar_t *fn=NDE_ColumnField_GetFieldName(p); + + + wchar_t *opstr=NULL; + switch (Op) + { + case FILTER_EQUALS: opstr=L"="; break; + case FILTER_NOTEQUALS: opstr=L"!="; break; + case FILTER_CONTAINS: opstr=L"HAS"; break; + case FILTER_NOTCONTAINS: opstr=L"NOTHAS"; break; + case FILTER_ABOVE: opstr=L">"; break; + case FILTER_BELOW: opstr=L"<"; break; + case FILTER_ABOVEOREQUAL: opstr=L">="; break; + case FILTER_BELOWOREQUAL: opstr=L"<="; break; + case FILTER_BEGINS: opstr=L"BEGINS"; break; + case FILTER_ENDS: opstr=L"ENDS"; break; + case FILTER_LIKE: opstr=L"LIKE"; break; + case FILTER_ISEMPTY: opstr=L"ISEMPTY"; break; + case FILTER_ISNOTEMPTY: opstr=L"ISNOTEMPTY"; break; + } + if (fn && fn[0] && opstr && opstr[0]) + { + if (Op == FILTER_ISEMPTY || Op == FILTER_ISNOTEMPTY) + wsprintfW(buf, L"%s %s",fn,opstr); + else if (NDE_ColumnField_GetDataType(p) == FIELD_DATETIME) + wsprintfW(buf, L"%s %s [%s]",fn,opstr,res); + else + { + GayStringW escaped; + queryStrEscape(res, escaped); + wsprintfW(buf, L"%s %s \"%s\"",fn,opstr,escaped.Get()); + } + } + } + } + } + } + } + return 0; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_BUTTON1: + SendMessage(GetParent(hwndDlg),WM_USER+34,(WPARAM)hwndDlg,-1); + m_simple_dirty=1; + return 0; + case IDC_OR: + case IDC_AND: + m_simple_dirty=1; + break; + case IDC_BUTTON_QUERYBUILD: + { + wchar_t query[1024] = {0}; + GetDlgItemTextW(hwndDlg,IDC_EDIT,query, 1024); + wchar_t querybuf[4096] = {0}; + const wchar_t *newquery = editQuery(hwndDlg, query, querybuf, 4096); + if (newquery != NULL) { + SetDlgItemTextW(hwndDlg, IDC_EDIT, newquery); + m_simple_dirty=1; + } + } + break; + case IDC_BUTTON2: + { + wchar_t query[1024] = {0}; + GetDlgItemTextW(hwndDlg,IDC_EDIT1,query,1024); + + const wchar_t *newquery = editTime(hwndDlg, query); + if (newquery != NULL) SetDlgItemTextW(hwndDlg, IDC_EDIT1, newquery); + } + // todo: date picker + return 0; + case IDC_EDIT1: + if (HIWORD(wParam) == EN_CHANGE) + { + m_simple_dirty=1; + } + return 0; + case IDC_COMBO2: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + m_simple_dirty=1; + HWND hwndCB2=(HWND)lParam; + int x=SendMessage(hwndCB2,CB_GETCURSEL,0,0); + if (x != CB_ERR) + { + int a=SendMessage(hwndCB2,CB_GETITEMDATA,(WPARAM)x,0); + if (a == FILTER_ISEMPTY || a == FILTER_ISNOTEMPTY) + { + EnableWindow(GetDlgItem(hwndDlg,IDC_EDIT1),0); + } + else + { + EnableWindow(GetDlgItem(hwndDlg,IDC_EDIT1),1); + } + } + } + return 0; + case IDC_COMBO1: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + m_simple_dirty=1; + HWND hwndCB=(HWND)lParam; + HWND hwndCB2=GetDlgItem(hwndDlg,IDC_COMBO2); + + int x=SendMessage(hwndCB,CB_GETCURSEL,0,0); +#define GAP 2 + if (x != CB_ERR) + { + int lastsel=SendMessage(hwndCB2,CB_GETCURSEL,0,0); + SendMessage(hwndCB2,CB_RESETCONTENT,0,0); + // populate with proper comparisons for type. give a default, too + int myId = SendMessage(hwndCB,CB_GETITEMDATA,(WPARAM)x,0); + if(myId == 0x1ea7c0de) { // custom! + ShowWindow(GetDlgItem(hwndDlg,IDC_BUTTON_QUERYBUILD),SW_SHOWNA); + ShowWindow(GetDlgItem(hwndDlg,IDC_COMBO2),SW_HIDE); + + RECT r; + GetWindowRect(GetDlgItem(hwndDlg,IDC_BUTTON2),&r); + ScreenToClient(hwndDlg,((LPPOINT)&r)); + + RECT r1; + GetWindowRect(GetDlgItem(hwndDlg,IDC_COMBO1),&r1); + ScreenToClient(hwndDlg,((LPPOINT)&r1)); + ScreenToClient(hwndDlg,((LPPOINT)&r1)+1); + + RECT r2; + GetWindowRect(GetDlgItem(hwndDlg,IDC_EDIT1),&r2); + ScreenToClient(hwndDlg,((LPPOINT)&r2)); + ScreenToClient(hwndDlg,((LPPOINT)&r2)+1); + + SetWindowPos(GetDlgItem(hwndDlg,IDC_EDIT1),0,r1.right+GAP,r1.top,r.left-r1.right-GAP-GAP,r2.bottom-r2.top,/*SWP_NOMOVE|*/SWP_NOACTIVATE|SWP_NOZORDER); + return 0; + } + + ShowWindow(GetDlgItem(hwndDlg,IDC_BUTTON_QUERYBUILD),SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg,IDC_COMBO2),SW_SHOWNA); + + nde_field_t p = (-1 != myId) ? NDE_Table_GetColumnByID(g_table, (unsigned char)myId) : NULL; + if (p) + { + if (NDE_ColumnField_GetDataType(p)==FIELD_DATETIME) + { + //if (!IsWindowVisible(GetDlgItem(hwndDlg,IDC_BUTTON2))) + { + RECT r; + GetWindowRect(GetDlgItem(hwndDlg,IDC_BUTTON2),&r); + ScreenToClient(hwndDlg,((LPPOINT)&r)); + + ShowWindow(GetDlgItem(hwndDlg,IDC_BUTTON2),SW_SHOWNA); + + RECT r1; + GetWindowRect(GetDlgItem(hwndDlg,IDC_COMBO2),&r1); + ScreenToClient(hwndDlg,((LPPOINT)&r1)); + ScreenToClient(hwndDlg,((LPPOINT)&r1)+1); + + RECT r2; + GetWindowRect(GetDlgItem(hwndDlg,IDC_EDIT1),&r2); + ScreenToClient(hwndDlg,((LPPOINT)&r2)); + ScreenToClient(hwndDlg,((LPPOINT)&r2)+1); + SetWindowPos(GetDlgItem(hwndDlg,IDC_EDIT1),0,r1.right+GAP,r1.top,r.left-r1.right-GAP-GAP,r2.bottom-r2.top,/*SWP_NOMOVE|*/SWP_NOACTIVATE|SWP_NOZORDER); + } + } + else + { + //if (IsWindowVisible(GetDlgItem(hwndDlg,IDC_BUTTON2))) + { + RECT r; + GetWindowRect(GetDlgItem(hwndDlg,IDC_BUTTON2),&r); + ScreenToClient(hwndDlg,((LPPOINT)&r) + 1); + + ShowWindow(GetDlgItem(hwndDlg,IDC_BUTTON2),SW_HIDE); + + RECT r1; + GetWindowRect(GetDlgItem(hwndDlg,IDC_COMBO2),&r1); + ScreenToClient(hwndDlg,((LPPOINT)&r1)); + ScreenToClient(hwndDlg,((LPPOINT)&r1)+1); + + RECT r2; + GetWindowRect(GetDlgItem(hwndDlg,IDC_EDIT1),&r2); + ScreenToClient(hwndDlg,((LPPOINT)&r2)); + ScreenToClient(hwndDlg,((LPPOINT)&r2)+1); + SetWindowPos(GetDlgItem(hwndDlg,IDC_EDIT1),0,r1.right+GAP,r1.top,r.right-r1.right-GAP,r2.bottom-r2.top,/*SWP_NOMOVE|*/SWP_NOACTIVATE|SWP_NOZORDER); + } + } +#undef GAP + typedef struct + { + int str; + char id; + } fillT; + + int myfillt_len=0; + fillT *myfillt=NULL; + static fillT foo1[]= + { + {IDS_EQUALS,FILTER_EQUALS}, + {IDS_DOES_NOT_EQUAL,FILTER_NOTEQUALS}, + {IDS_CONTAINS,FILTER_CONTAINS}, + {IDS_DOES_NOT_CONTAIN,FILTER_NOTCONTAINS}, + {IDS_IS_ABOVE,FILTER_ABOVE}, + {IDS_IS_BELOW,FILTER_BELOW}, + {IDS_EQUALS_OR_IS_ABOVE,FILTER_ABOVEOREQUAL}, + {IDS_EQUALS_OR_IS_BELOW,FILTER_BELOWOREQUAL}, + {IDS_IS_EMPTY,FILTER_ISEMPTY}, + {IDS_IS_NOT_EMPTY,FILTER_ISNOTEMPTY}, + {IDS_BEGINS_WITH,FILTER_BEGINS}, + {IDS_ENDS_WITH,FILTER_ENDS}, + {IDS_IS_SIMILAR_TO,FILTER_LIKE}, + }; + static fillT foo2[]= + { + {IDS_AT,FILTER_EQUALS}, + {IDS_NOT_AT,FILTER_NOTEQUALS}, + {IDS_AFTER,FILTER_ABOVE}, + {IDS_BEFORE,FILTER_BELOW}, + {IDS_SINCE,FILTER_ABOVEOREQUAL}, + {IDS_UNTIL,FILTER_BELOWOREQUAL}, + {IDS_IS_EMPTY,FILTER_ISEMPTY}, + {IDS_IS_NOT_EMPTY,FILTER_ISNOTEMPTY}, + }; + switch (NDE_ColumnField_GetDataType(p)) + { + case FIELD_DATETIME: + { + myfillt_len = sizeof(foo2)/sizeof(foo2[0]); + myfillt=foo2; + } + break; + case FIELD_LENGTH: + case FIELD_INTEGER: + { + myfillt_len = sizeof(foo1)/sizeof(foo1[0]) - 3; + myfillt=foo1; + } + break; + case FIELD_FILENAME: + case FIELD_STRING: + { + myfillt_len = sizeof(foo1)/sizeof(foo1[0]); + myfillt=foo1; + } + break; + default: + break; + } + if (myfillt) + { + wchar_t *str; + int width = 0; + while (myfillt_len--) + { + int a=SendMessageW(hwndCB2,CB_ADDSTRING,0,(LPARAM)(str = WASABI_API_LNGSTRINGW(myfillt->str))); + width = ResizeComboBoxDropDownW(hwndDlg, IDC_COMBO2, str, width); + SendMessage(hwndCB2,CB_SETITEMDATA,a,(LPARAM)myfillt->id); + myfillt++; + } + if (lastsel != CB_ERR) + SendMessage(hwndCB2,CB_SETCURSEL,lastsel,0); + } + } + } + } + return 0; + } + return 0; + } + + if (FALSE != IsDirectMouseWheelMessage(uMsg) || + WM_MOUSEWHEEL == uMsg) + { + HWND parentWindow; + parentWindow = GetAncestor(hwndDlg, GA_PARENT); + if (NULL != parentWindow) + { + SendMessageW(parentWindow, WM_MOUSEWHEEL, wParam, lParam); + SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, (long)TRUE); + return TRUE; + } + } + + return 0; +} + + +static INT_PTR CALLBACK scrollChildProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) +{ + static int osize; + switch (uMsg) + { + case WM_INITDIALOG: + { + RECT r; + GetClientRect(hwndDlg,&r); + osize=r.bottom; + } + return 1; + case WM_COMMAND: + if (LOWORD(wParam) == IDC_BUTTON1) + SPL_AddBlankFilter(hwndDlg); + return 0; + case WM_USER+40: // get query string + if (!lParam) + { + // now we go through our children, asking each one for a string, and combine them. + GayStringW str; + HWND h=GetWindow(hwndDlg,GW_CHILD); + wchar_t * nextop=NULL; + while (h) + { + if (h != GetDlgItem(hwndDlg,IDC_BUTTON1)) + { + wchar_t buf[512] = {0}; + buf[0]=0; + SendMessage(h,WM_USER+40,(WPARAM)buf,(LPARAM)sizeof(buf)/sizeof(*buf)); + if (buf[0]) + { + if(nextop) str.Append(nextop); + nextop = IsDlgButtonChecked(h,IDC_AND) ? L" AND " : L" OR "; + //if (str.Get() && str.Get()[0]) str.Append(isOr ? L" OR " : L" AND "); + str.Append(buf); + } + } + h=GetWindow(h,GW_HWNDNEXT); + } + lstrcpynW(m_item_query,str.Get()?str.Get():L"",sizeof(m_item_query)/sizeof(*m_item_query)); + } + return 0; + case WM_USER+41: // remove all + { + HWND h=GetWindow(hwndDlg,GW_CHILD); + std::vector w; + while (h) { + if (h != GetDlgItem(hwndDlg,IDC_BUTTON1)) + w.push_back((void*)h); + h=GetWindow(h,GW_HWNDNEXT); + } + for ( void *l_w : w ) + SendMessage( hwndDlg, WM_USER + 34, (WPARAM)(HWND)l_w, -1 ); + } + break; + case WM_USER+34: // remove filter by hwnd + if (wParam && lParam == -1) + { + HWND hwndRemove = (HWND) wParam; + RECT r; + + GetClientRect(hwndRemove,&r); + int lh=r.bottom; // height to remove + + GetWindowRect(hwndRemove,&r); + ScreenToClient(hwndDlg,(LPPOINT)&r); + int ltop=r.top; + + DestroyWindow(hwndRemove); + + HWND h=GetWindow(hwndDlg,GW_CHILD); + while (h) + { + RECT r; + + GetWindowRect(h,&r); + ScreenToClient(hwndDlg,(LPPOINT)&r); + + if (r.top > ltop) + { + SetWindowPos(h,0,r.left,r.top - lh,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); + } + h=GetWindow(h,GW_HWNDNEXT); + } + + GetClientRect(hwndDlg,&r); + r.bottom -= lh; + SetWindowPos(hwndDlg,0,0,0,r.right,r.bottom,SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE); + + SendMessage(GetParent(hwndDlg),WM_USER+33,17,0); + } + return 0; + case WM_USER+32: // add filter. lParam is mode. 1 means add by filter, 2 means add blank + if(lParam == 2) { + BOOL b=0; + HWND h=GetWindow(hwndDlg,GW_CHILD); + while (h) { + if (h != GetDlgItem(hwndDlg,IDC_BUTTON1)) + b = filterProc(h,WM_USER+29,(WPARAM)b,0); + h=GetWindow(h,GW_HWNDNEXT); + } + } + if ((lParam == 1 && wParam) || (lParam == 2 && !wParam)) + { + HWND newChild=0; + nde_filter_t filter=(nde_filter_t)wParam; + if (lParam == 2 || (NULL != NDE_Table_GetColumnByID(g_table, NDE_Filter_GetID(filter)))) + { + newChild=WASABI_API_CREATEDIALOGPARAMW(IDD_SCROLLCHILDFILTER,hwndDlg,filterProc,(LPARAM)filter); + RECT r,r2; + GetClientRect(hwndDlg,&r); + GetClientRect(newChild,&r2); + SetWindowPos(hwndDlg,0,0,0,r.right,r.bottom + r2.bottom,SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE); + SetWindowPos(newChild,0,0,r.bottom - osize,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); + + HWND h = GetDlgItem(hwndDlg,IDC_BUTTON1); + GetWindowRect(h,&r); + ScreenToClient(hwndDlg,(LPPOINT)&r); + SetWindowPos(h,0,r.left,r.top + r2.bottom,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); + ShowWindow(newChild,SW_SHOWNA); + } + if (lParam == 2) { + // update scroll, hugging bottom + SendMessage(GetParent(hwndDlg),WM_USER+33,16,0); + } + return (intptr_t)newChild; + } + return 0; + } + + if (FALSE != IsDirectMouseWheelMessage(uMsg) || + WM_MOUSEWHEEL == uMsg) + { + HWND parentWindow; + parentWindow = GetAncestor(hwndDlg, GA_PARENT); + if (NULL != parentWindow) + { + SendMessageW(parentWindow, WM_MOUSEWHEEL, wParam, lParam); + SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, (long)TRUE); + return TRUE; + } + } + return 0; +} + +static INT_PTR CALLBACK scrollChildHostProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) +{ + static HWND m_child; + switch (uMsg) + { + case WM_INITDIALOG: + { + RECT r; + GetWindowRect(GetDlgItem(GetParent(hwndDlg),IDC_CHILDFRAME),&r); + ScreenToClient(GetParent(hwndDlg),(LPPOINT)&r); + ScreenToClient(GetParent(hwndDlg),((LPPOINT)&r)+1); + SetWindowPos(hwndDlg,NULL,r.left,r.top,r.right-r.left,r.bottom-r.top,SWP_NOZORDER|SWP_NOACTIVATE); + } + m_child=WASABI_API_CREATEDIALOGW(IDD_SCROLLCHILD,hwndDlg,scrollChildProc); + return 1; + case WM_USER+33: + if (m_child) + { + RECT r; + RECT r2; + GetClientRect(hwndDlg,&r2); + GetClientRect(m_child,&r); + if (r2.bottom < r.bottom) + { + SCROLLINFO si={sizeof(si),SIF_RANGE|SIF_PAGE|SIF_POS,0,r.bottom,r2.bottom,wParam == 16 ? r.bottom : 0,0}; + + if (wParam == 17) + si.fMask &= ~SIF_POS; + + SetScrollInfo(hwndDlg,SB_VERT,&si,TRUE); + + if (wParam != 17) + SetWindowPos(m_child,NULL,0,wParam == 16 ? r2.bottom-r.bottom : 0,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); + } else { + //hide the scrollbar + SetWindowPos(m_child,NULL,0,0,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); + ShowScrollBar(hwndDlg,SB_VERT,FALSE); + } + ShowWindow(m_child,SW_SHOWNA); + } + return 0; + case WM_USER+32: + case WM_USER+41: + case WM_USER+40: + if (m_child) return scrollChildProc(m_child,uMsg,wParam,lParam); + return 0; + case WM_VSCROLL: + { + RECT r; + RECT r2; + GetClientRect(hwndDlg,&r2); + GetClientRect(m_child,&r); + + if (r2.bottom < r.bottom) + { + int v=0; + if (LOWORD(wParam) == SB_THUMBPOSITION || LOWORD(wParam) == SB_THUMBTRACK) + { + SCROLLINFO si={sizeof(si),SIF_TRACKPOS|SIF_POS}; + GetScrollInfo(hwndDlg,SB_VERT,&si); + v=si.nTrackPos; + } + else if (LOWORD(wParam) == SB_TOP) + { + v=0; + } + else if (LOWORD(wParam) == SB_BOTTOM) + { + v=r.bottom-r2.bottom; + } + else if (LOWORD(wParam) == SB_PAGEDOWN || LOWORD(wParam) == SB_LINEDOWN) + { + SCROLLINFO si={sizeof(si),SIF_TRACKPOS|SIF_POS}; + GetScrollInfo(hwndDlg,SB_VERT,&si); + v=si.nPos + r2.bottom; + if (v > r.bottom-r2.bottom) v=r.bottom-r2.bottom; + } + else if (LOWORD(wParam) == SB_PAGEUP || LOWORD(wParam) == SB_LINEUP) + { + SCROLLINFO si={sizeof(si),SIF_TRACKPOS|SIF_POS}; + GetScrollInfo(hwndDlg,SB_VERT,&si); + v=si.nPos - r2.bottom; + if (v < 0) v=0; + } + else return 0; + + SetScrollPos(hwndDlg,SB_VERT,v,!(LOWORD(wParam) == SB_THUMBPOSITION || LOWORD(wParam) == SB_THUMBTRACK)); + SetWindowPos(m_child,NULL,0,0-v,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); + } + else + { + SetScrollPos(hwndDlg,SB_VERT,0,!(LOWORD(wParam) == SB_THUMBPOSITION || LOWORD(wParam) == SB_THUMBTRACK)); + SetWindowPos(m_child,NULL,0,0,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); + } + } + return 0; + } + + if (FALSE != IsDirectMouseWheelMessage(uMsg) || + WM_MOUSEWHEEL == uMsg) + { + WORD scrollCommand; + short delta; + + delta = HIWORD(wParam); + + scrollCommand = (delta > 0) ? SB_LINEUP : SB_LINEDOWN; + + SendMessageW(hwndDlg, WM_VSCROLL, MAKEWPARAM(scrollCommand, 0), 0L); + } + return 0; +} + +void addNewQuery(HWND parent) { + HWND hwnd = WASABI_API_CREATEDIALOGPARAMW(IDD_ADD_VIEW_2, parent, addQueryFrameDialogProc2, 0); + SetActiveWindow(hwnd); +} + +void queryEditItem(int n) +{ + m_edit_item=n; + HWND hwnd = WASABI_API_CREATEDIALOGPARAMW(IDD_ADD_VIEW_2, plugin.hwndLibraryParent, addQueryFrameDialogProc2, 1); + SetActiveWindow(hwnd); +} + +// returns true if edition was validated, false if cancel was clicked +// actual return values are in m_item_query, m_item_name and m_item_mode +int queryEditOther(HWND hwnd, const char *query, const char *viewname, int mode) +{ + int notnew=1; + if (query == NULL || !*query) notnew = 0; + m_edit_item = -1; + if (notnew) + { + MultiByteToWideCharSZ(CP_ACP, 0, viewname, -1, m_item_name, 256); + MultiByteToWideCharSZ(CP_ACP, 0, query, -1, m_item_query, 1024); + } + m_item_mode = mode; + if(mode == -1) + return WASABI_API_DIALOGBOXPARAMW(IDD_ADD_VIEW_2_NF, hwnd, addQueryFrameDialogProc2, notnew); + else + return WASABI_API_DIALOGBOXPARAMW(IDD_ADD_VIEW_2, hwnd, addQueryFrameDialogProc2, notnew); +} + +void queryDeleteItem(HWND parent, int n) +{ + QueryList::iterator iter; + iter = m_query_list.find(n); + if (iter == m_query_list.end()) return; + + wchar_t title[64] = {0}; + queryItem *item = iter->second; + if (MessageBoxW(parent,WASABI_API_LNGSTRINGW(IDS_DELETE_THIS_VIEW), + WASABI_API_LNGSTRINGW_BUF(IDS_CONFIRMATION,title,64), + MB_YESNO|MB_ICONQUESTION) == IDYES) + { + mediaLibrary.RemoveTreeItem(iter->first); + m_query_list.erase(iter->first); + saveQueryTree(); + + // we deleted the item from the tree, which apparently is enough to close the current dialog if it was + // the current dialog. hot. + + for(iter = m_query_list.begin(); iter != m_query_list.end(); iter++) + if(iter->second && iter->second->index > item->index) iter->second->index--; + + wchar_t configDir[MAX_PATH] = {0}; + PathCombineW(configDir, g_viewsDir, item->metafn); + DeleteFileW(configDir); + + free(item->metafn); + free(item->name); + free(item->query); + free(item); + } +} + + + int IPC_LIBRARY_SENDTOMENU; +static librarySendToMenuStruct s_menu; + +static WNDPROC ml_oldWndProc2; +static INT_PTR CALLBACK ml_newWndProc2(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITMENUPOPUP: + if (wParam && (HMENU)wParam == s_menu.build_hMenu && s_menu.mode==1) + { + myMenu = TRUE; + if (SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s_menu, IPC_LIBRARY_SENDTOMENU)==(LRESULT)-1) + s_menu.mode=2; + myMenu = FALSE; + if(ml_oldWndProc2) SetWindowLongPtrW(hwndDlg,GWLP_WNDPROC,(LONG_PTR)ml_oldWndProc2); + ml_oldWndProc2 = NULL; + + } + return 0; + } + if (ml_oldWndProc2) return CallWindowProc(ml_oldWndProc2,hwndDlg,uMsg,wParam,lParam); + return 0; +} + +HMENU main_sendto_hmenu; +int main_sendto_mode; + +void view_queryContextMenu(INT_PTR param1, HWND hHost, POINTS pts, int n) +{ + queryItem *item=m_query_list[n]; + if (item == NULL) return; + + ml_oldWndProc2 = (WNDPROC)SetWindowLongPtrW(hHost, GWLP_WNDPROC, (LONG_PTR)ml_newWndProc2); + + HMENU menu=GetSubMenu(g_context_menus,2); + main_sendto_hmenu=GetSubMenu(menu,2); + + s_menu.mode = 0; + s_menu.hwnd = 0; + s_menu.build_hMenu = 0; + + IPC_LIBRARY_SENDTOMENU = SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&"LibrarySendToMenu", IPC_REGISTER_WINAMP_IPCMESSAGE); + if (IPC_LIBRARY_SENDTOMENU > 65536 && SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)0, IPC_LIBRARY_SENDTOMENU)==(LRESULT)-1) + { + s_menu.mode = 1; + s_menu.hwnd = hHost; + s_menu.data_type = ML_TYPE_ITEMRECORDLIST; + s_menu.ctx[1] = 1; + s_menu.build_hMenu = main_sendto_hmenu; + } + + POINT pt; + POINTSTOPOINT(pt, pts); + if (-1 == pt.x || -1 == pt.y) + { + HNAVITEM hItem = (HNAVITEM)param1; + NAVITEMGETRECT itemRect; + itemRect.fItem = FALSE; + itemRect.hItem = hItem; + if (MLNavItem_GetRect(plugin.hwndLibraryParent, &itemRect)) + { + MapWindowPoints(hHost, HWND_DESKTOP, (POINT*)&itemRect.rc, 2); + pt.x = itemRect.rc.left + 2; + pt.y = itemRect.rc.top + 2; + } + } + + UpdateMenuItems(NULL, menu, IDR_QUERY_ACCELERATORS); + int r = DoTrackPopup(menu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON, + pt.x, pt.y, hHost, NULL); + if(ml_oldWndProc2) SetWindowLongPtrW(hHost,GWLP_WNDPROC,(LONG_PTR)ml_oldWndProc2); + switch(r) + { + case ID_QUERYWND_EDIT: + queryEditItem(n); + break; + case ID_QUERYWND_DELETE: + queryDeleteItem(hHost,n); + break; + case ID_QUERYWND_PLAYQUERY: + { + wchar_t configDir[MAX_PATH] = {0}; + PathCombineW(configDir, g_viewsDir, item->metafn); + C_Config viewconf(configDir); + main_playQuery(&viewconf,item->query,0); + } + break; + case ID_QUERYWND_ENQUEUEQUERY: + { + wchar_t configDir[MAX_PATH] = {0}; + PathCombineW(configDir, g_viewsDir, item->metafn); + C_Config viewconf(configDir); + main_playQuery(&viewconf,item->query,1); + } + break; + case ID_QUERYMENU_ADDNEWQUERY: + addNewQuery(hHost); + break; + default: + if (s_menu.mode == 2) + { + s_menu.menu_id = r; + if (SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s_menu, IPC_LIBRARY_SENDTOMENU) == (LRESULT)-1) + { + // build my data. + s_menu.mode=3; + s_menu.data_type = ML_TYPE_ITEMRECORDLISTW; + wchar_t configDir[MAX_PATH] = {0}; + PathCombineW(configDir, g_viewsDir, item->metafn); + C_Config viewconf(configDir); + + EnterCriticalSection(&g_db_cs); + nde_scanner_t s=NDE_Table_CreateScanner(g_table); + NDE_Scanner_Query(s, item->query); + itemRecordListW obj={0,}; + saveQueryToListW(&viewconf, s, &obj, 0, 0, (resultsniff_funcW)-1); + NDE_Table_DestroyScanner(g_table, s); + LeaveCriticalSection(&g_db_cs); + s_menu.data = (void*)&obj; + + LRESULT result = SendMessage(plugin.hwndWinampParent, WM_WA_IPC,(WPARAM)&s_menu,IPC_LIBRARY_SENDTOMENU); + if (result != 1) + { + s_menu.mode=3; + s_menu.data_type = ML_TYPE_ITEMRECORDLIST; + itemRecordList objA={0,}; + convertRecordList(&objA, &obj); + s_menu.data = (void*)&objA; + SendMessage(plugin.hwndWinampParent, WM_WA_IPC,(WPARAM)&s_menu,IPC_LIBRARY_SENDTOMENU); + freeRecordList(&objA); + } + freeRecordList(&obj); + + } + } + break; + } + if (s_menu.mode) + { + s_menu.mode=4; + SendMessage(plugin.hwndWinampParent, WM_WA_IPC,(WPARAM)&s_menu,IPC_LIBRARY_SENDTOMENU); // cleanup + } + main_sendto_hmenu=0; + EatKeyboard(); +} + +void queriesContextMenu(INT_PTR param1, HWND hHost, POINTS pts) { + POINT pt; + POINTSTOPOINT(pt, pts); + if (-1 == pt.x || -1 == pt.y) + { + HNAVITEM hItem = (HNAVITEM)param1; + NAVITEMGETRECT itemRect; + itemRect.fItem = FALSE; + itemRect.hItem = hItem; + if (MLNavItem_GetRect(plugin.hwndLibraryParent, &itemRect)) + { + MapWindowPoints(hHost, HWND_DESKTOP, (POINT*)&itemRect.rc, 2); + pt.x = itemRect.rc.left + 2; + pt.y = itemRect.rc.top + 2; + } + } + + HMENU menu=GetSubMenu(g_context_menus,3); + int r = DoTrackPopup(menu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_NONOTIFY, + pt.x, pt.y, hHost, NULL); + switch(r) { + case ID_QUERYMENU_ADDNEWQUERY: + addNewQuery(hHost); + break; + case ID_QUERYMENU_PREFERENCES: + SENDWAIPC(plugin.hwndWinampParent, IPC_OPENPREFSTOPAGE, &preferences); + break; + case ID_QUERYMENU_HELP: + SENDWAIPC(plugin.hwndWinampParent, IPC_OPEN_URL, L"https://help.winamp.com/hc/articles/8105304048660-The-Winamp-Media-Library"); + break; + } + EatKeyboard(); +} \ No newline at end of file -- cgit