#include "main.h" #include "api__gen_ml.h" #include #include #include #include "../winamp/gen.h" #include "resource.h" #include "../nu/ns_wc.h" #include "config.h" #include "../winamp/ipc_pe.h" #include "../winamp/wa_dlg.h" #include "ml.h" #include "ml_ipc.h" #include "sendto.h" #include "../gen_hotkeys/wa_hotkeys.h" #include "MediaLibraryCOM.h" #include "../nu/CCVersion.h" #include "../nu/AutoWide.h" #include "../nu/AutoChar.h" #include "./navigation.h" #include "./ml_imagelist.h" #include "./ml_imagefilter.h" #include "./imagefilters.h" // default filters #include #include "./ml_ipc_0313.h" #include "./skinning.h" #include "./ml_ratingcolumn.h" #include "./ml_cloudcolumn.h" #include "./colors.h" #include "./stockobjects.h" #include "./service.h" #include "./skinnedbutton.h" #include "../Winamp/wasabicfg.h" #ifdef _DEBUG #define BETA #endif // messages #define WMML_FIRST (WM_APP + 0) #define WMML_UPDATEVIEW (WMML_FIRST + 1) #define WMML_SHOWCONTAINER (WMML_FIRST + 10) #define BLOCK_ACCELTOGGLE_PROP TEXT("BLOCK_ACCELTOGGLE") // timers #define TIMER_UPDATEVIEW_ID 1970 #define TIMER_UPDATEVIEW_DELAY 7 #define TIMER_NAVAUTOSCROLL_ID 1971 #define TIMER_NAVAUTOSCROLL_DELAY 80 #define TIMER_NAVAUTOEXPAND_ID 1972 #define TIMER_NAVAUTOEXPAND_DELAY 500 #define TIMER_UNBLOCKACCELTOGGLE_ID 1973 #define TIMER_UNBLOCKACCELTOGGLE_DELAY 200 #define IDC_CURRENTVIEW 0x1001 #define IDC_NAVIGATION 0x03FD // (this is the same that old versions used) #define MEDIALIBRARY_HELP_URL L"https://help.winamp.com/hc/articles/8105304048660-The-Winamp-Media-Library" SendToMenu *main_sendtomenu; HMENU main_sendto_hmenu; int main_sendto_mode; extern "C" HWND g_ownerwnd; static int ldiv_clickoffs, ldiv_paintleftborder; static WNDPROC ldiv_oldWndProc; static WNDPROC add_oldWndProc; HNAVITEM g_treedrag_lastSel; static HNAVITEM m_query_moving_dragplace; static HNAVITEM m_query_moving_item, m_query_moving_lastdest; static int m_query_moving_dragplaceisbelow; static int m_query_moving; static int m_query_moving_type; HWND m_curview_hwnd = NULL; HNAVCTRL hNavigation = NULL; // navigation control HMLIMGLST hmlilRating = NULL; // default rating images HMLIMGLST hmlilCloud = NULL; // default cloud images UINT ratingGlobalStyle = RATING_DEFAULT_STYLE; static HMLIMGLST hmlilNavigation = NULL; // default navigation image list HMLIMGFLTRMNGR hmlifMngr = NULL; /// default image filters static HRGN g_rgnUpdate = NULL; static INT divider_pos; static BOOL firstShow = TRUE; static BOOL m_nav_autoscroll = FALSE; static HNAVITEM m_nav_autoexpand_item = NULL; static HIMAGELIST m_nav_dragitem_imagelist = NULL; void OpenMediaLibraryPreferences(); typedef struct _LAYOUT { INT id; HWND hwnd; INT x; INT y; INT cx; INT cy; DWORD flags; HRGN rgn; }LAYOUT, PLAYOUT; #define SETLAYOUTPOS(_layout, _x, _y, _cx, _cy) { _layout->x=_x; _layout->y=_y;_layout->cx=_cx;_layout->cy=_cy;_layout->rgn=NULL; } static void LayoutWindows( HWND hwnd, INT divX, BOOL fRedraw ) { static BOOL useDefer = ( GetVersion() < 0x80000000 ); static INT controls[] = { IDC_BTN_LIB, IDC_NAVIGATION, IDC_VDELIM, IDC_CURRENTVIEW, IDC_NO_VIEW }; RECT rc, ri, roTree; LAYOUT layout[ sizeof( controls ) / sizeof( controls[ 0 ] ) ], *pl; INT divCX = 0, btnY; GetClientRect( hwnd, &rc ); if ( rc.bottom == rc.top || rc.left == rc.right ) return; if ( rc.bottom > WASABI_API_APP->getScaleY( 2 ) ) rc.bottom -= WASABI_API_APP->getScaleY( 2 ); HRGN rgn = CreateRectRgn( 0, 0, 0, 0 ); if ( divX > rc.right - WASABI_API_APP->getScaleY( 41 ) ) divX = rc.right - WASABI_API_APP->getScaleY( 9 ); if ( divX < WASABI_API_APP->getScaleY( 32 ) ) divX = 0; else if ( divX > ( rc.right - rc.left ) ) divX = ( rc.right - rc.left ); pl = layout; btnY = rc.bottom; // in case button is broken InvalidateRgn( hwnd, NULL, TRUE ); for ( int i = 0; i < sizeof( controls ) / sizeof( controls[ 0 ] ); i++ ) { pl->id = controls[ i ]; switch ( pl->id ) { case IDC_NAVIGATION: pl->hwnd = NavCtrlI_GetHWND( hNavigation ); break; case IDC_CURRENTVIEW: pl->hwnd = m_curview_hwnd; break; default: pl->hwnd = GetDlgItem( hwnd, pl->id ); break; } if ( !pl->hwnd ) continue; pl->rgn = NULL; GetWindowRect( pl->hwnd, &ri ); MapWindowPoints( HWND_DESKTOP, hwnd, (LPPOINT)&ri, 2 ); pl->flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS; switch ( pl->id ) { case IDC_BTN_LIB: { wchar_t buffer[ 128 ] = { 0 }; GetWindowTextW( pl->hwnd, buffer, ARRAYSIZE( buffer ) ); LRESULT idealSize = MLSkinnedButton_GetIdealSize( pl->hwnd, buffer ); btnY = WASABI_API_APP->getScaleY( HIWORD( idealSize ) ); SETLAYOUTPOS( pl, rc.left, rc.bottom - btnY, rc.left + divX, btnY ); break; } case IDC_NAVIGATION: GetClientRect( pl->hwnd, &roTree ); NavCtrlI_MapPointsTo( hNavigation, hwnd, (LPPOINT)&roTree, 2 ); SETLAYOUTPOS( pl, rc.left, rc.top, rc.left + divX, rc.bottom - btnY - WASABI_API_APP->getScaleY( 3 ) ); ldiv_paintleftborder = ( pl->cx > 0 ); break; case IDC_VDELIM: divCX = ( ri.right - ri.left ); SETLAYOUTPOS( pl, divX + WASABI_API_APP->getScaleX( 1 ), rc.top, divCX, max( 0, rc.bottom - rc.top ) ); break; case IDC_CURRENTVIEW: // current view; SETLAYOUTPOS( pl, divX + divCX, rc.top, max( 0, rc.right - pl->x - WASABI_API_APP->getScaleX( 2 ) ), max( 0, rc.bottom - rc.top ) ); if ( !SendMessage( pl->hwnd, WM_USER + 0x200, 0, 0 ) ) pl->flags &= ~( SWP_NOREDRAW ); break; case IDC_NO_VIEW: SETLAYOUTPOS( pl, divX + divCX + 20, rc.top, max( 0, rc.right - pl->x - WASABI_API_APP->getScaleX( 2 ) - 20 ), max( 0, rc.bottom - rc.top ) ); if ( !SendMessage( pl->hwnd, WM_USER + 0x200, 0, 0 ) ) pl->flags &= ~( SWP_NOREDRAW ); break; } if ( pl->x == ri.left && pl->y == ri.top ) pl->flags |= SWP_NOMOVE; if ( pl->cx == ( ri.right - ri.left ) && pl->cy == ( ri.bottom - ri.top ) ) pl->flags |= SWP_NOSIZE; if ( ( SWP_NOMOVE | SWP_NOSIZE ) != ( ( SWP_NOMOVE | SWP_NOSIZE ) & pl->flags ) ) pl++; else if ( IsWindowVisible( pl->hwnd ) ) { ValidateRect( hwnd, &ri ); if ( GetUpdateRect( pl->hwnd, NULL, FALSE ) ) { GetUpdateRgn( pl->hwnd, rgn, FALSE ); OffsetRgn( rgn, pl->x, pl->y ); InvalidateRgn( hwnd, rgn, FALSE ); } } } if ( pl != layout ) { LAYOUT *pc; HDWP hdwp = ( useDefer ) ? BeginDeferWindowPos( (INT)( pl - layout ) ) : NULL; for ( pc = layout; pc < pl && ( !useDefer || hdwp ); pc++ ) { if ( IDC_CURRENTVIEW == pc->id && ( SWP_NOREDRAW & pc->flags ) && IsWindowVisible( pc->hwnd ) ) { if ( !pc->rgn ) pc->rgn = CreateRectRgn( 0, 0, pc->cx, pc->cy ); GetWindowRect( pc->hwnd, &ri ); NavCtrlI_MapPointsFrom( hNavigation, HWND_DESKTOP, (LPPOINT)&ri, 1 ); SendMessage( pc->hwnd, WM_USER + 0x201, MAKEWPARAM( pc->x - ri.left, pc->y - ri.top ), (LPARAM)pc->rgn ); } if ( useDefer ) hdwp = DeferWindowPos( hdwp, pc->hwnd, NULL, pc->x, pc->y, pc->cx, pc->cy, pc->flags ); else SetWindowPos( pc->hwnd, NULL, pc->x, pc->y, pc->cx, pc->cy, pc->flags ); } if ( hdwp ) EndDeferWindowPos( hdwp ); for ( pc = layout; pc < pl; pc++ ) { if ( IDC_NAVIGATION == pc->id ) { GetWindowRect( pc->hwnd, &ri ); OffsetRect( &ri, -ri.left, -ri.top ); pc->rgn = CreateRectRgnIndirect( &ri ); GetClientRect( pc->hwnd, &ri ); NavCtrlI_MapPointsTo( hNavigation, hwnd, (LPPOINT)&ri, 1 ); IntersectRect( &ri, &roTree, &ri ); SetRectRgn( rgn, ri.left, ri.top, ri.right, ri.bottom ); CombineRgn( pc->rgn, pc->rgn, rgn, RGN_DIFF ); if ( GetUpdateRect( pc->hwnd, NULL, FALSE ) ) { GetUpdateRgn( pc->hwnd, rgn, FALSE ); CombineRgn( pc->rgn, pc->rgn, rgn, RGN_OR ); } } else if ( IDC_CURRENTVIEW == pc->id && pc->rgn ) SendMessage( pc->hwnd, WM_USER + 0x201, 0, 0L ); if ( IsWindowVisible( pc->hwnd ) ) { GetWindowRect( pc->hwnd, &ri ); MapWindowPoints( HWND_DESKTOP, hwnd, (LPPOINT)&ri, 2 ); ValidateRect( hwnd, &ri ); } } if ( fRedraw ) { HRGN rgnTmp = CreateRectRgn( 0, 0, 0, 0 ); GetUpdateRgn( hwnd, rgn, FALSE ); for ( pc = layout; pc < pl; pc++ ) { if ( SWP_NOREDRAW & pc->flags ) { if ( pc->rgn ) OffsetRgn( pc->rgn, pc->x, pc->y ); else SetRectRgn( rgnTmp, pc->x, pc->y, pc->x + pc->cx, pc->y + pc->cy ); CombineRgn( rgn, rgn, ( pc->rgn ) ? pc->rgn : rgnTmp, RGN_OR ); } } DeleteObject( rgnTmp ); RedrawWindow( hwnd, NULL, rgn, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ERASENOW | RDW_ALLCHILDREN ); } else if ( g_rgnUpdate ) { GetUpdateRgn( hwnd, g_rgnUpdate, FALSE ); ValidateRect( hwnd, NULL ); for ( pc = layout; pc < pl; pc++ ) { if ( SWP_NOREDRAW & pc->flags ) { if ( pc->rgn ) OffsetRgn( pc->rgn, pc->x, pc->y ); else SetRectRgn( rgn, pc->x, pc->y, pc->x + pc->cx, pc->y + pc->cy ); CombineRgn( g_rgnUpdate, g_rgnUpdate, ( pc->rgn ) ? pc->rgn : rgn, RGN_OR ); } } } for ( pc = layout; pc < pl; pc++ ) if ( pc->rgn ) DeleteObject( pc->rgn ); } if ( rgn ) DeleteObject( rgn ); } // a default right-pane view to show if a plugin failed to return us an HWND static INT_PTR CALLBACK view_Error( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { if ( uMsg == WM_INITDIALOG ) { ShowWindow( GetDlgItem( g_hwnd, IDC_NO_VIEW ), SW_SHOW ); } return WADlg_handleDialogMsgs( hwndDlg, uMsg, wParam, lParam ); } static void CreateCurrentView( HWND hwndDlg ) { HNAVITEM hItem; DLGPROC proc; proc = view_Error; hItem = NavCtrlI_GetSelection( hNavigation ); if ( hItem ) { INT itemId = NavItemI_GetId( hItem ); #if 0 #ifdef BETA wchar_t pszText[ 32 ] = { 0 }; if ( NavItemI_GetInvariantText( hItem, pszText, 32 ) && !lstrcmpW( pszText, L"winamp_labs" ) ) { OmService *om_service; OmService::CreateInstance( SERVICE_LABS, L"Winamp Labs", &om_service ); if ( AGAVE_OBJ_BROWSER ) { HWND hView = 0; HRESULT hr = AGAVE_OBJ_BROWSER->CreateView( om_service, (HWND)hwndDlg, 0, 0, &hView ); om_service->Release(); if ( SUCCEEDED( hr ) ) { m_curview_hwnd = hView; } } } else #endif #endif m_curview_hwnd = (HWND)plugin_SendMessage( ML_MSG_TREE_ONCREATEVIEW, (INT_PTR)itemId, (INT_PTR)hwndDlg, 0 ); } if ( !IsWindow( m_curview_hwnd ) ) m_curview_hwnd = WASABI_API_CREATEDIALOGPARAMW( IDD_VIEW_EMPTY, hwndDlg, proc, 0 ); else ShowWindow( GetDlgItem( g_hwnd, IDC_NO_VIEW ), SW_HIDE ); if ( IsWindow( m_curview_hwnd ) ) { SetWindowPos( m_curview_hwnd, NavCtrlI_GetHWND( hNavigation ), 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW ); LayoutWindows( hwndDlg, divider_pos, FALSE ); // moved 08/12/09 from start of block to here along with SkinnedWnd::OnSkinChanged(..) change to hopefully resolve bold font issues MLSkinnedWnd_SkinChanged( m_curview_hwnd, TRUE, FALSE ); ShowWindow( m_curview_hwnd, SW_SHOWNORMAL ); RedrawWindow( m_curview_hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN ); PostMessage( m_curview_hwnd, WMML_UPDATEVIEW, 0, 0 ); //refresh view } } static void DisplayItemDragImage( HNAVITEM hItem, LPCWSTR pszTip, HWND hwndOwner, POINT *ppt ) // ppt in hwndOwner coordinates { if ( !hwndOwner ) return; if ( m_nav_dragitem_imagelist ) { ImageList_DragLeave( hwndOwner ); ImageList_EndDrag(); ImageList_Destroy( m_nav_dragitem_imagelist ); } m_nav_dragitem_imagelist = NavItemI_CreateDragImage( hItem, pszTip ); if ( m_nav_dragitem_imagelist ) { INT cx, cy; ImageList_GetIconSize( m_nav_dragitem_imagelist, &cx, &cy ); if ( ImageList_BeginDrag( m_nav_dragitem_imagelist, 0, cx / 2, cy / 2 ) ) { NavCtrlI_Update( hNavigation ); ImageList_DragEnter( hwndOwner, ppt->x, ppt->y ); } } } VOID CALLBACK CreateViewTimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ) { if ( idEvent == TIMER_UPDATEVIEW_ID ) { KillTimer( hwnd, TIMER_UPDATEVIEW_ID ); CreateCurrentView( hwnd ); } } static void CALLBACK OnNavCtrl_Selected( HNAVCTRL hMngr, HNAVITEM hItemOld, HNAVITEM hItemNew ) { KillTimer( g_hwnd, TIMER_UPDATEVIEW_ID ); if ( IsWindow( m_curview_hwnd ) ) { RedrawWindow( g_hwnd, NULL, NULL, RDW_UPDATENOW | RDW_ALLCHILDREN ); SendMessageW( g_hwnd, WM_SETREDRAW, FALSE, 0L ); // freeze window ShowWindow( m_curview_hwnd, SW_HIDE ); SendMessageW( g_hwnd, WM_SETREDRAW, TRUE, 0L ); DestroyWindow( m_curview_hwnd ); m_curview_hwnd = NULL; } // 07/05/2010 DRO - changed to use a callback proc as ml_disc was managing to trigger // the same timer message multiple times on (at least) older XP machines which was // causing multiple ml view dialogs to be created but hidden behind the currently // opened view - intermittent issue i've been seeing for a year on my XP machine. SetTimer( g_hwnd, TIMER_UPDATEVIEW_ID, TIMER_UPDATEVIEW_DELAY, CreateViewTimerProc ); } static BOOL CALLBACK OnNavCtrl_Click( HNAVCTRL hMngr, HNAVITEM hItem, INT actionId ) { if ( hItem ) { INT mlAction = -1; switch ( actionId ) { case ACTION_CLICKL_I: mlAction = ML_ACTION_LCLICK; break; case ACTION_CLICKR_I: mlAction = ML_ACTION_RCLICK; break; case ACTION_ENTER_I: mlAction = ML_ACTION_ENTER; break; case ACTION_DBLCLICKL_I: mlAction = ML_ACTION_DBLCLICK; break; case ACTION_DBLCLICKR_I: break; } if ( -1 != mlAction ) { BOOL ret = (BOOL)plugin_SendMessage( ML_MSG_TREE_ONCLICK, NavItemI_GetId( hItem ), mlAction, (INT_PTR)GetParent( NavCtrlI_GetHWND( hMngr ) ) ); if ( mlAction != ML_ACTION_LCLICK ) return ret; } } return FALSE; } static BOOL CALLBACK OnNavCtrl_KeyDown( HNAVCTRL hMngr, HNAVITEM hItem, NMTVKEYDOWN *ptvkd ) { return ( hItem ) ? (BOOL)plugin_SendMessage( ML_MSG_TREE_ONKEYDOWN, NavItemI_GetId( hItem ), (INT_PTR)ptvkd, (INT_PTR)NavCtrlI_GetHWND( hMngr ) ) : FALSE; } static BOOL CALLBACK OnNavCtrl_BeginTitleEdit( HNAVCTRL hMngr, HNAVITEM hItem ) { return !(BOOL)plugin_SendMessage( ML_MSG_NAVIGATION_ONBEGINTITLEEDIT, (INT_PTR)hItem, 0, 0 ); } static BOOL CALLBACK OnNavCtrl_EndTitleEdit( HNAVCTRL hMngr, HNAVITEM hItem, LPCWSTR pszNewTitle ) { return (BOOL)plugin_SendMessage( ML_MSG_NAVIGATION_ONENDTITLEEDIT, (INT_PTR)hItem, (INT_PTR)pszNewTitle, 0 ); } static void CALLBACK OnNavItem_Delete( HNAVCTRL hMngr, HNAVITEM hItem ) { plugin_SendMessage( ML_MSG_NAVIGATION_ONDELETE, (INT_PTR)hItem, 0, 0 ); } static void CALLBACK OnNavCtrl_Destroy( HNAVCTRL hMngr ) { plugin_SendMessage( ML_MSG_NAVIGATION_ONDESTROY, 0, 0, 0 ); } static INT CALLBACK OnNavItem_CustomDraw( HNAVCTRL hMngr, HNAVITEM hItem, NAVITEMDRAW_I *pnicd, LPARAM lParam ) { INT result = (INT)plugin_SendMessage( ML_MSG_NAVIGATION_ONCUSTOMDRAW, (INT_PTR)hItem, (INT_PTR)pnicd, (INT_PTR)lParam ); if ( NICDRF_NOTMINE == result ) result = NICDRF_DODEFAULT_I; return result; } static INT CALLBACK OnNavItem_SetCursor( HNAVCTRL hMngr, HNAVITEM hItem, LPARAM lParam ) { INT result = (INT)plugin_SendMessage( ML_MSG_NAVIGATION_ONSETCURSOR, (INT_PTR)hItem, (INT_PTR)0, (INT_PTR)lParam ); return ( result > 0 ); } static void CALLBACK OnNavItem_HitTest( HNAVCTRL hMngr, POINT pt, UINT *pHitFlags, HNAVITEM *phItem, LPARAM lParam ) { NAVHITTEST ht; ht.flags = *pHitFlags; ht.pt = pt; ht.hItem = *phItem; if ( 0 != plugin_SendMessage( ML_MSG_NAVIGATION_ONHITTEST, (INT_PTR)*phItem, (INT_PTR)&ht, (INT_PTR)lParam ) ) { *pHitFlags = ht.flags; *phItem = ht.hItem; } } static void CALLBACK OnNavCtrl_BeginDrag( HNAVCTRL hMngr, HNAVITEM hItem, POINT pt ) { #ifdef BETA wchar_t pszText[ 32 ] = { 0 }; if ( ( !( sneak & 4 ) ) && NavItemI_GetInvariantText( hItem, pszText, 32 ) && !lstrcmpW( pszText, L"winamp_labs" ) ) { return; } #endif if ( plugin_SendMessage( ML_MSG_TREE_ONDRAG, NavItemI_GetId( hItem ), (INT_PTR)&pt, (INT_PTR)&m_query_moving_type ) < 1 ) { HNAVITEM hParent; hParent = NavItemI_GetParent( hItem ); m_query_moving_type = ( NULL == hParent || NIS_ALLOWCHILDMOVE_I == NavItemI_GetStyle( hParent, NIS_ALLOWCHILDMOVE_I ) ) ? ML_TYPE_TREEITEM : ML_TYPE_UNKNOWN; } m_query_moving = 1; m_query_moving_item = hItem; m_query_moving_dragplace = NULL; m_query_moving_lastdest = NULL; m_query_moving_dragplaceisbelow = FALSE; HWND hwndDlg = GetParent( NavCtrlI_GetHWND( hMngr ) ); NavCtrlI_MapPointsTo( hMngr, hwndDlg, &pt, 1 ); DisplayItemDragImage( hItem, NULL, hwndDlg, &pt ); SetCapture( g_hwnd ); } static INT CALLBACK OnNavCtrl_GetImageIndex( HNAVCTRL hMngr, HNAVITEM hItem, INT imageType ) { if ( NavItemI_HasChildren( hItem ) ) { INT_PTR tag; tag = ( NavItemI_HasChildrenReal( hItem ) ) ? ( ( NavItemI_IsExpanded( hItem ) ) ? MLTREEIMAGE_BRANCH_EXPANDED : MLTREEIMAGE_BRANCH_COLLAPSED ) : MLTREEIMAGE_BRANCH_NOCHILD; INT mlilIndex = MLImageListI_GetIndexFromTag( NavCtrlI_GetImageList( hMngr ), tag ); return ( -1 != mlilIndex ) ? mlilIndex : 0; } return 0; } static void OnWindowPosChanged( HWND hwnd, WINDOWPOS *pwp ) { if ( SWP_NOSIZE != ( ( SWP_NOSIZE | SWP_FRAMECHANGED | SWP_SHOWWINDOW ) & pwp->flags ) ) { LayoutWindows( hwnd, divider_pos, ( 0 == ( SWP_NOREDRAW & pwp->flags ) ) ); } } HWND wa3wnd_fixwnd( HWND h ) { if ( IsChild( h, g_hwnd ) ) return h; // if the library window is a child of this window, don't touch it if ( IsChild( h, g_PEWindow ) ) return g_PEWindow; // if the playlist window is a child of this window, treat it as the playlist window HWND hParent = (HWND)SENDWAIPC( plugin.hwndParent, IPC_GETDIALOGBOXPARENT, 0 ); if ( plugin.hwndParent != hParent && h == hParent ) h = plugin.hwndParent; //DWORD pid; //DWORD threadID = GetWindowThreadProcessId(h, &pid); //if (pid != GetCurrentProcessId() || threadID != GetCurrentThreadId()) return h; // if other process, dont mangle //char buf[64] = {0}; //GetClassName(h, buf, sizeof(buf) - 1); //if (!strcmp(buf, "BaseWindow_RootWnd")) return plugin.hwndParent; // if a wa3 window, treat as main window return h; } static void CALLBACK OnDividerMoved( HWND hdiv, INT nPos, LPARAM param ) { HWND hwndParent; divider_pos = nPos; hwndParent = GetParent( hdiv ); LayoutWindows( hwndParent, nPos, TRUE ); } static void Navigation_DropHelper( HWND hwndDlg, HWND hwndNav, HNAVITEM hItemHit, UINT hitFlags, POINT pt ) { if ( hItemHit && ( ( NAVHT_ONITEMINDENT_I | NAVHT_ONITEMRIGHT_I | NAVHT_ONITEM_I | NAVHT_ONITEMBUTTON_I ) & hitFlags ) ) { RECT rc; GetClientRect( hwndNav, &rc ); if ( !m_nav_autoscroll && ( rc.left <= pt.x && rc.right >= pt.x ) ) { INT sbCommand; if ( rc.top <= pt.y && pt.y < ( rc.top + 24 ) ) sbCommand = 1; else if ( ( rc.bottom - 24 ) < pt.y && pt.y <= rc.bottom ) sbCommand = 2; else sbCommand = 0; if ( sbCommand ) { SCROLLINFO si = { 0 }; si.cbSize = sizeof( SCROLLINFO ); si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; if ( !GetScrollInfo( hwndNav, SB_VERT, &si ) ) ZeroMemory( &si, sizeof( SCROLLINFO ) ); if ( ( 1 == sbCommand && si.nMin < si.nPos ) || ( 2 == sbCommand && si.nMax >= (INT)( si.nPos + si.nPage ) ) ) { if ( SetTimer( hwndDlg, TIMER_NAVAUTOSCROLL_ID, TIMER_NAVAUTOSCROLL_DELAY, NULL ) ) m_nav_autoscroll = TRUE; } } } if ( ( NAVHT_ONITEMBUTTON_I & hitFlags ) && m_nav_autoexpand_item != hItemHit && !NavItemI_IsExpanded( hItemHit ) ) { KillTimer( hwndDlg, TIMER_NAVAUTOEXPAND_ID ); if ( SetTimer( hwndDlg, TIMER_NAVAUTOEXPAND_ID, TIMER_NAVAUTOEXPAND_DELAY, NULL ) ) m_nav_autoexpand_item = hItemHit; } } } int handleDragDropMove( HWND hwndDlg, int type, POINT p, int do_cursors ) { BOOL valid = FALSE; HWND h = WindowFromPoint( p ); HNAVITEM hItemPrevHilited = g_treedrag_lastSel; g_treedrag_lastSel = NULL; if ( h ) { h = wa3wnd_fixwnd( h ); if ( IsChild( plugin.hwndParent, h ) ) h = plugin.hwndParent; else if ( g_PEWindow && IsChild( g_PEWindow, h ) ) h = g_PEWindow; else { HWND vid = (HWND)SendMessage( plugin.hwndParent, WM_WA_IPC, IPC_GETWND_VIDEO, IPC_GETWND ); if ( vid ) { if ( h == vid || IsChild( vid, h ) ) h = plugin.hwndParent; } } if ( h && ( h == plugin.hwndParent || h == g_PEWindow ) ) { valid = ( type == ML_TYPE_ITEMRECORDLISTW || type == ML_TYPE_ITEMRECORDLIST || type == ML_TYPE_FILENAMES || type == ML_TYPE_STREAMNAMES || type == ML_TYPE_CDTRACKS || type == ML_TYPE_FILENAMESW || type == ML_TYPE_STREAMNAMESW ); } else if ( h == NavCtrlI_GetHWND( hNavigation ) ) { HNAVITEM hItemHit, hItemSel; UINT hitFlags; POINT pt = p; MapWindowPoints( HWND_DESKTOP, h, &pt, 1 ); hItemHit = NavCtrlI_HitTest( hNavigation, &pt, &hitFlags ); hItemSel = NavCtrlI_GetSelection( hNavigation ); Navigation_DropHelper( hwndDlg, h, hItemHit, hitFlags, pt ); if ( hItemHit && hItemHit != hItemSel && ( !m_query_moving_item || NavItemI_GetParent( m_query_moving_item ) != hItemHit ) ) { valid = ( plugin_SendMessage( ML_MSG_TREE_ONDROPTARGET, NavItemI_GetId( hItemHit ), type, NULL ) > 0 ); if ( valid ) g_treedrag_lastSel = hItemHit; } } else if ( IsWindow( m_curview_hwnd ) && IsWindow( h ) && ( h == m_curview_hwnd || IsChild( m_curview_hwnd, h ) ) ) { mlDropItemStruct dis = { 0, }; dis.type = type; dis.p = p; while ( 1 ) { SendMessage( h, WM_ML_CHILDIPC, (WPARAM)&dis, ML_CHILDIPC_DROPITEM ); if ( dis.result || h == m_curview_hwnd ) break; h = GetParent( h ); // traverse up the tree } valid = dis.result > 0; } } if ( g_treedrag_lastSel != hItemPrevHilited ) { ImageList_DragShowNolock( FALSE ); if ( hItemPrevHilited ) NavItemI_SetState( hItemPrevHilited, 0, NIS_DROPHILITED_I ); if ( g_treedrag_lastSel ) NavItemI_SetState( g_treedrag_lastSel, NIS_DROPHILITED_I, NIS_DROPHILITED_I ); NavCtrlI_Update( hNavigation ); ImageList_DragShowNolock( TRUE ); } if ( do_cursors ) SetCursor( ( valid ) ? hDragNDropCursor : LoadCursor( NULL, IDC_NO ) ); return valid; } static void CancelNavigationMove( void ) { m_query_moving_dragplace = NULL; ImageList_DragShowNolock( FALSE ); NavCtrlI_SetInsertMark( hNavigation, NULL, FALSE ); NavCtrlI_Update( hNavigation ); ImageList_DragShowNolock( TRUE ); } static void OnInitMenuPopUp( HMENU menu ); static void OnDisplayChange( HWND hwndDlg, UINT imgDepth, UINT hRes, UINT vRes ); static int OnInitDialog( HWND hwndDlg ); static void OnDestroy( HWND hwndDlg ); static void OnClose( HWND hwndDlg ); static void OnSize( HWND hwndDlg, UINT type, int cx, int cy ); static void OnShowWindow( HWND hwndDlg, BOOL fShow ); LRESULT OnMediaLibraryIPC( HWND hwndDlg, WPARAM wParam, LPARAM lParam ); static void OnGetMaxMinInfo( MINMAXINFO *info ); static void OnBtnLibraryClick( HWND hwndBtn ); static HWND hwndTweak = NULL; static BOOL CALLBACK RatingTweak_OnApplyChanges( UINT fStyle, BOOL bClosing ) { ratingGlobalStyle = fStyle; g_config->WriteInt( L"rating_style", ratingGlobalStyle ); MLRatingColumnI_Update(); if ( IsWindow( m_curview_hwnd ) ) PostMessage( m_curview_hwnd, WM_DISPLAYCHANGE, 0, MAKELPARAM( 0, 0 ) ); if ( bClosing ) hwndTweak = NULL; return TRUE; } static void OnTimer_NavAutoScroll( HWND hwndDlg ) { RECT rc; POINT pt; HWND hwndNav = NavCtrlI_GetHWND( hNavigation ); INT command = 0; KillTimer( hwndDlg, TIMER_NAVAUTOSCROLL_ID ); if ( !hwndNav || !IsWindowVisible( hwndNav ) ) { m_nav_autoscroll = FALSE; return; } GetCursorPos( &pt ); NavCtrlI_MapPointsFrom( hNavigation, HWND_DESKTOP, &pt, 1 ); GetClientRect( hwndNav, &rc ); if ( rc.left <= pt.x && rc.right >= pt.x ) { if ( rc.top <= pt.y && pt.y < ( rc.top + 24 ) ) command = 1; else if ( ( rc.bottom - 24 ) < pt.y && pt.y <= rc.bottom ) command = 2; } if ( command ) { SCROLLINFO si = { 0 }; si.cbSize = sizeof( SCROLLINFO ); si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; if ( !GetScrollInfo( hwndNav, SB_VERT, &si ) ) ZeroMemory( &si, sizeof( SCROLLINFO ) ); if ( ( 1 == command && si.nMin == si.nPos ) || ( 2 == command && si.nMax < (INT)( si.nPos + si.nPage ) ) ) command = 0; else { ImageList_DragShowNolock( FALSE ); SendMessageW( hwndNav, WM_VSCROLL, MAKEWPARAM( ( 1 == command ) ? SB_LINEUP : SB_LINEDOWN, 0 ), NULL ); NavCtrlI_Update( hNavigation ); ImageList_DragShowNolock( TRUE ); SetTimer( hwndDlg, TIMER_NAVAUTOSCROLL_ID, TIMER_NAVAUTOSCROLL_DELAY, NULL ); } } if ( !command ) m_nav_autoscroll = FALSE; } static void OnTimer_NavAutoExpand( HWND hwndDlg ) { POINT pt; HWND hwndNav = NavCtrlI_GetHWND( hNavigation ); HNAVITEM hItem; UINT hitFlags; KillTimer( hwndDlg, TIMER_NAVAUTOEXPAND_ID ); if ( !hwndNav || !IsWindowVisible( hwndNav ) ) return; GetCursorPos( &pt ); NavCtrlI_MapPointsFrom( hNavigation, HWND_DESKTOP, &pt, 1 ); hItem = NavCtrlI_HitTest( hNavigation, &pt, &hitFlags ); if ( NAVHT_ONITEMBUTTON_I & hitFlags && hItem == m_nav_autoexpand_item ) { ImageList_DragShowNolock( FALSE ); NavCtrlI_SetInsertMark( hNavigation, NULL, FALSE ); NavItemI_Expand( hItem, NAVITEM_EXPAND_I ); NavCtrlI_Update( hNavigation ); ImageList_DragShowNolock( TRUE ); } m_nav_autoexpand_item = NULL; } static void OnTimer( HWND hwndDlg, UINT_PTR idTimer ) { switch ( idTimer ) { case TIMER_NAVAUTOSCROLL_ID: OnTimer_NavAutoScroll( hwndDlg ); break; case TIMER_NAVAUTOEXPAND_ID: OnTimer_NavAutoExpand( hwndDlg ); break; case TIMER_UNBLOCKACCELTOGGLE_ID: KillTimer( hwndDlg, idTimer ); RemoveProp( hwndDlg, BLOCK_ACCELTOGGLE_PROP ); break; } } static HMLIMGLST CreateNavigationImages( HMLIMGFLTRMNGR filterManager ) { MLIMAGESOURCE_I is = { 0 }; static INT resourceId[] = { IDB_TREEITEM_DEFAULT, IDB_TREEITEM_COLLAPSED, IDB_TREEITEM_EXPANDED, IDB_TREEITEM_NOCHILD }; static INT_PTR imageTag[] = { MLTREEIMAGE_DEFAULT, MLTREEIMAGE_BRANCH_COLLAPSED, MLTREEIMAGE_BRANCH_EXPANDED, MLTREEIMAGE_BRANCH_NOCHILD }; HMLIMGLST hmlil = MLImageListI_Create( 16, 16, 24, 30, 2, 3, filterManager ); if ( !hmlil ) return NULL; is.bpp = 24; is.hInst = plugin.hDllInstance; is.type = SRC_TYPE_BMP_I; is.flags = ISF_FORCE_BPP_I; for ( INT index = 0; index < sizeof( resourceId ) / sizeof( resourceId[ 0 ] ); index++ ) { is.lpszName = MAKEINTRESOURCEW( resourceId[ index ] ); MLImageListI_Add( hmlil, &is, MLIF_FILTER1_UID, imageTag[ index ] ); } return hmlil; } static void OnMouseMove( HWND hwndDlg, POINT pt, UINT flags ) { RECT rc; if ( !m_query_moving ) return; MapWindowPoints( hwndDlg, HWND_DESKTOP, &pt, 1 ); GetWindowRect( hwndDlg, &rc ); ImageList_DragMove( pt.x - rc.left, pt.y - rc.top ); HWND hWndHit = WindowFromPoint( pt ); if ( hWndHit == NavCtrlI_GetHWND( hNavigation ) ) { POINT ptMy = pt; UINT hitFlags; HNAVITEM hItem; MapWindowPoints( HWND_DESKTOP, hWndHit, &ptMy, 1 ); hItem = NavCtrlI_HitTest( hNavigation, &ptMy, &hitFlags ); if ( !hItem ) { HNAVITEM hItemLast; hItemLast = NavCtrlI_GetLastVisible( hNavigation ); if ( hItemLast ) { RECT ri; if ( NavItemI_GetRect( hItemLast, &ri, FALSE ) && ri.bottom < ptMy.y ) { HNAVITEM hMovingParent, hLastParent; hMovingParent = NavItemI_GetParent( m_query_moving_item ); while ( NULL != ( hLastParent = NavItemI_GetParent( hItemLast ) ) && hLastParent != hMovingParent ) hItemLast = hLastParent; if ( hMovingParent == hLastParent ) { hItem = hItemLast; hitFlags = NAVHT_ONITEM_I; } } } } if ( ( NAVHT_ONITEMINDENT_I | NAVHT_ONITEMRIGHT_I | NAVHT_ONITEM_I | NAVHT_ONITEMBUTTON_I ) & hitFlags ) { HNAVITEM tempItem; Navigation_DropHelper( hwndDlg, hWndHit, hItem, hitFlags, ptMy ); if ( ML_TYPE_UNKNOWN == m_query_moving_type ) { SetCursor( LoadCursor( NULL, IDC_NO ) ); return; } tempItem = hItem; while ( tempItem && tempItem != m_query_moving_item ) tempItem = NavItemI_GetParent( tempItem ); if ( tempItem == m_query_moving_item ) hItem = m_query_moving_item; if ( hItem ) { BOOL hitBelow; if ( NavItemI_GetParent( hItem ) != NavItemI_GetParent( m_query_moving_item ) ) { // TODO: I think regular drag-n-drop goes here? //SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_NO))); CancelNavigationMove(); m_query_moving_lastdest = NULL; mlDropItemStruct dropItem; ZeroMemory( &dropItem, sizeof( mlDropItemStruct ) ); dropItem.p = pt; dropItem.type = m_query_moving_type; OnMediaLibraryIPC( hwndDlg, (WPARAM)&dropItem, ML_IPC_HANDLEDRAG ); //handleDragDropMove(hwndDlg, m_query_moving_type, pt, 1); //goto outside_window; return; } if ( g_treedrag_lastSel ) { NavItemI_SetState( g_treedrag_lastSel, 0, NIS_DROPHILITED_I ); g_treedrag_lastSel = NULL; } NavItemI_GetRect( hItem, &rc, FALSE ); hitBelow = ( ptMy.y > ( rc.bottom - ( rc.bottom - rc.top ) / 2 ) ); SetCursor( LoadCursor( NULL, MAKEINTRESOURCE( IDC_ARROW ) ) ); m_query_moving_lastdest = hItem; if ( m_query_moving_dragplace != hItem || m_query_moving_dragplaceisbelow != hitBelow ) { m_query_moving_dragplace = hItem; m_query_moving_dragplaceisbelow = hitBelow; ImageList_DragShowNolock( FALSE ); NavCtrlI_SetInsertMark( hNavigation, hItem, hitBelow ); NavCtrlI_Update( hNavigation ); ImageList_DragShowNolock( TRUE ); } } } } else { int type = ML_TYPE_TREEITEM; bool canDrag; CancelNavigationMove(); canDrag = ( m_query_moving_item && ( plugin_SendMessage( ML_MSG_TREE_ONDRAG, NavItemI_GetId( m_query_moving_item ), (INT_PTR)&pt, (INT_PTR)&type ) < 0 ) ); if ( !canDrag ) { mlDropItemStruct dropItem; ZeroMemory( &dropItem, sizeof( mlDropItemStruct ) ); dropItem.p = pt; dropItem.type = type; OnMediaLibraryIPC( hwndDlg, (WPARAM)&dropItem, ML_IPC_HANDLEDRAG ); //pluginHandleIpcMessage(hwndDlg, ML_IPC_HANDLEDRAG, (WPARAM)&m); //SetCursor(dropItem.result > 0 ? hDragNDropCursor : LoadCursor(NULL, IDC_NO)); //SetCursor(LoadCursor(NULL, IDC_NO)); } m_query_moving_dragplace = NULL; m_query_moving_lastdest = NULL; } } static void OnLButtonUp( HWND hwndDlg, POINT pt, UINT flags ) { HWND hwndHit; if ( !m_query_moving ) return; SetCursor( LoadCursor( NULL, MAKEINTRESOURCE( IDC_ARROW ) ) ); ImageList_DragLeave( hwndDlg ); ImageList_EndDrag(); if ( m_nav_dragitem_imagelist ) { ImageList_Destroy( m_nav_dragitem_imagelist ); m_nav_dragitem_imagelist = NULL; } MapWindowPoints( hwndDlg, HWND_DESKTOP, &pt, 1 ); hwndHit = WindowFromPoint( pt ); if ( ML_TYPE_UNKNOWN != m_query_moving_type && hwndHit && m_query_moving_item ) { if ( m_query_moving_dragplace ) { //move item in the tree if ( ML_TYPE_TREEITEM == m_query_moving_type && m_query_moving_item != m_query_moving_lastdest ) { WORD orderOld; orderOld = NavItemI_GetOrder( m_query_moving_item ); if ( NavItemI_Move( m_query_moving_item, m_query_moving_lastdest, m_query_moving_dragplaceisbelow ) ) { plugin_SendMessage( ML_MSG_NAVIGATION_ONMOVE, (INT_PTR)m_query_moving_item, orderOld, NavItemI_GetOrder( m_query_moving_item ) ); } } else { HNAVITEM whereinsert; whereinsert = m_query_moving_lastdest; if ( !m_query_moving_dragplaceisbelow ) { BOOL fTest; fTest = ( whereinsert == m_query_moving_item ); whereinsert = NavItemI_GetPrevious( whereinsert ); if ( !whereinsert && !fTest ) whereinsert = NavItemI_GetParent( m_query_moving_lastdest ); } if ( whereinsert && m_query_moving_item != whereinsert ) plugin_SendMessage( ML_MSG_TREE_ONDROP, NavItemI_GetId( m_query_moving_item ), (INT_PTR)&pt, NavItemI_GetId( whereinsert ) ); } } else plugin_SendMessage( ML_MSG_TREE_ONDROP, NavItemI_GetId( m_query_moving_item ), (INT_PTR)&pt, 0 ); } m_query_moving = 0; if ( g_treedrag_lastSel ) { NavItemI_SetState( g_treedrag_lastSel, 0, NIS_DROPHILITED_I ); g_treedrag_lastSel = NULL; } if ( m_query_moving_dragplace ) CancelNavigationMove(); ReleaseCapture(); } void listbuild( wchar_t **buf, int &buf_size, int &buf_pos, const wchar_t *tbuf ) { if ( !*buf ) { *buf = (wchar_t *)calloc( 4096, sizeof( wchar_t ) ); if ( *buf ) { buf_size = 4096; buf_pos = 0; } else { buf_size = buf_pos = 0; } } int newsize = buf_pos + lstrlenW( tbuf ) + 1; if ( newsize < buf_size ) { size_t old_buf_size = buf_size; buf_size = newsize + 4096; wchar_t *data = (wchar_t *)realloc( *buf, ( buf_size + 1 ) * sizeof( wchar_t ) ); if ( data ) { *buf = data; } else { data = (wchar_t *)malloc( ( buf_size + 1 ) * sizeof( wchar_t ) ); if ( data ) { memcpy( data, *buf, sizeof( wchar_t ) * old_buf_size ); free( *buf ); *buf = data; } else buf_size = old_buf_size; } } StringCchCopyW( *buf + buf_pos, buf_size, tbuf ); buf_pos = newsize; } /*wchar_t * getSelectedList() { wchar_t* path=NULL; int buf_pos=0, buf_size=0; int download=-1; while (GetDownload(download)) { if(listContents[download]->f) listbuild(&path,buf_size,buf_pos,listContents[download]->f->path); } if(path) path[buf_pos] = 0; return path; }*/ static void OnDragDrop( HWND hwndDlg, HDROP hdrop ) { UINT hitFlags = NAVHT_NOWHERE_I; POINT pt = { 0 }; DragQueryPoint( hdrop, &pt ); HNAVITEM hItemHit = NavCtrlI_HitTest( hNavigation, &pt, &hitFlags ); if ( hItemHit ) { if ( plugin_SendMessage( ML_MSG_TREE_ONDROPTARGET, NavItemI_GetId( hItemHit ), ML_TYPE_FILENAMESW, NULL ) > 0 ) { wchar_t temp[ MAX_PATH ] = { 0 }; int y = DragQueryFileW( hdrop, 0xffffffff, temp, 1024 ); if ( y > 0 ) { wchar_t *paths = NULL; int buf_pos = 0, buf_size = 0; for ( int x = 0; x < y; x++ ) { if ( DragQueryFileW( hdrop, x, temp, MAX_PATH ) ) { listbuild( &paths, buf_size, buf_pos, temp ); } } if ( paths ) { paths[ buf_pos ] = 0; plugin_SendMessage( ML_MSG_TREE_ONDROPTARGET, NavItemI_GetId( hItemHit ), ML_TYPE_FILENAMESW, (INT_PTR)paths ); if ( IsWindow( m_curview_hwnd ) ) SendMessage( m_curview_hwnd, WM_APP + 1, 0, 0 ); //update current view free( paths ); } } DragFinish( hdrop ); } } } static void MlView_ShowWindow( HWND hwnd, BOOL fShow, UINT nStatus ) { if ( SW_PARENTOPENING == nStatus ) { BOOL fStored = ( 0 != g_config->ReadInt( L"visible", 1 ) ); if ( fShow != fStored ) { PostMessageW( hwnd, WMML_SHOWCONTAINER, ( 0 == fStored ) ? SW_HIDE : SW_SHOWNA, 0 ); return; } } ShowWindow( hwnd, ( FALSE != fShow ) ? SW_SHOWNA : SW_HIDE ); if ( 0 == nStatus ) { if ( NULL != g_config ) g_config->WriteInt( L"visible", ( FALSE != fShow ) ); UINT menuFlags = ( FALSE != fShow ) ? MF_CHECKED : MF_UNCHECKED; menuFlags |= MF_BYCOMMAND; INT szMenu[] = { 0, 4, }; for ( INT i = 0; i < ARRAYSIZE( szMenu ); i++ ) { HMENU hMenu = (HMENU)SendMessage( plugin.hwndParent, WM_WA_IPC, szMenu[ i ], IPC_GET_HMENU ); if ( NULL != hMenu ) CheckMenuItem( hMenu, WA_MENUITEM_ID, menuFlags ); } MLVisibleChanged( FALSE != fShow ); if ( FALSE != fShow ) { SendMessageW( g_ownerwnd, 0x0127/*WM_CHANGEUISTATE*/, MAKEWPARAM( 1/*UIS_SET*/, 3/*(UISF_HIDEACCEL | UISF_HIDEFOCUS)*/ ), 0L ); HWND hRoot = GetAncestor( g_ownerwnd, GA_ROOT ); if ( NULL != hRoot ) SetForegroundWindow( hRoot ); } } } static LRESULT MlView_OnContainerNotify( HWND hwnd, NMHDR *pnmh ) { switch ( pnmh->code ) { case EWN_SHOWWINDOW: MlView_ShowWindow( hwnd, ( (EMBEDSHOW *)pnmh )->fShow, ( (EMBEDSHOW *)pnmh )->nStatus ); break; } return 0; } static LRESULT MlView_OnNotify( HWND hwnd, INT controlId, NMHDR *pnmh ) { if ( pnmh->hwndFrom == g_ownerwnd ) { return MlView_OnContainerNotify( hwnd, pnmh ); } return 0; } static LRESULT MlView_OnContextMenu( HWND hwnd, HWND hOwner, POINTS pts ) { HWND hNav = NavCtrlI_GetHWND( hNavigation ); if ( NULL != hNav && hOwner == hNav ) { HNAVITEM hItem; POINT pt; POINTSTOPOINT( pt, pts ); if ( -1 == pt.x || -1 == pt.y ) { hItem = NavCtrlI_GetSelection( hNavigation ); if ( NULL != hItem ) { RECT itemRect; if ( NavItemI_GetRect( hItem, &itemRect, FALSE ) ) { pt.x = itemRect.left + 1; pt.y = itemRect.top + 1; MapWindowPoints( hNav, HWND_DESKTOP, &pt, 1 ); } } } else { UINT hitFlags; MapWindowPoints( HWND_DESKTOP, hNav, &pt, 1 ); hItem = NavCtrlI_HitTest( hNavigation, &pt, &hitFlags ); pt.x = pts.x; pt.y = pts.y; } if ( NULL == hItem ) return 0; UINT itemState = NavItemI_GetState( hItem, NIS_DROPHILITED_I | NIS_SELECTED_I ); if ( 0 == ( ( NIS_DROPHILITED_I | NIS_SELECTED_I ) & itemState ) ) NavItemI_SetState( hItem, NIS_DROPHILITED_I, NIS_DROPHILITED_I ); INT_PTR result = plugin_SendMessage( ML_MSG_NAVIGATION_CONTEXTMENU, (INT_PTR)hItem, (INT_PTR)hNav, MAKELONG( pt.x, pt.y ) ); if ( 0 == ( ( NIS_DROPHILITED_I | NIS_SELECTED_I ) & itemState ) ) NavItemI_SetState( hItem, 0, NIS_DROPHILITED_I ); return ( 0 != result ); } return 0; } static BOOL MlView_OnHelp( HWND hwnd, HELPINFO *helpInfo ) { // TODO review this for handling Shift+F1 as view specific help? // make sure we're only doing it for the expect help actions // i.e. not Ctrl+F1 which opens the global about dialog if ( ( GetAsyncKeyState( VK_CONTROL ) & 0x8000 ) ) return FALSE; // for view specific handling, we use Shift+F1 if ( NULL != helpInfo && HELPINFO_WINDOW == helpInfo->iContextType && ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) ) { HWND navigationWindow; navigationWindow = NavCtrlI_GetHWND( hNavigation ); if ( navigationWindow == helpInfo->hItemHandle ) { HNAVITEM selectedItem; selectedItem = NavCtrlI_GetSelection( hNavigation ); if ( NULL != selectedItem && 0 != plugin_SendMessage( ML_MSG_NAVIGATION_HELP, (INT_PTR)selectedItem, (INT_PTR)navigationWindow, MAKELONG( helpInfo->MousePos.x, helpInfo->MousePos.y ) ) ) { return TRUE; } return TRUE; } } // otherwise we treat it as a generic help request return MediaLibrary_OpenHelpUrl( MEDIALIBRARY_HELP_URL ); } INT_PTR CALLBACK dialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ) { case WM_MOUSEMOVE: case WM_LBUTTONUP: { POINT pt = { GET_X_LPARAM( lParam ),GET_Y_LPARAM( lParam ) }; if ( WM_MOUSEMOVE == uMsg ) OnMouseMove( hwndDlg, pt, (UINT)wParam ); else if ( WM_LBUTTONUP == uMsg ) OnLButtonUp( hwndDlg, pt, (UINT)wParam ); } return TRUE; case WM_COMMAND: switch ( LOWORD( wParam ) ) { case IDC_BTN_LIB: if ( BN_CLICKED == HIWORD( wParam ) ) OnBtnLibraryClick( (HWND)lParam ); break; case IDM_LIBRARY_CONFIG: OpenMediaLibraryPreferences(); break; case IDM_LIBRARY_HELP: MediaLibrary_OpenHelpUrl( MEDIALIBRARY_HELP_URL ); break; case ID_TOGGLE_LIBRARY: if ( 0 == GetProp( hwndDlg, BLOCK_ACCELTOGGLE_PROP ) ) { toggleVisible( 0 ); SetProp( hwndDlg, BLOCK_ACCELTOGGLE_PROP, (HANDLE)(INT_PTR)1 ); SetTimer( hwndDlg, TIMER_UNBLOCKACCELTOGGLE_ID, TIMER_UNBLOCKACCELTOGGLE_DELAY, NULL ); } break; case ID_WINDOW_CLOSE: if ( IsVisible() ) toggleVisible( 0 ); break; case ID_SHOW_RATINGTWEAK: if ( !IsWindow( hwndTweak ) ) hwndTweak = MLRatingColumnI_TweakDialog( hwndDlg, ratingGlobalStyle, RatingTweak_OnApplyChanges, TRUE ); else SetWindowPos( hwndTweak, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW ); break; case ID_GO_TO_VIEW_SEARCHBAR: SendMessage( m_curview_hwnd, WM_ML_CHILDIPC, 0, ML_CHILDIPC_GO_TO_SEARCHBAR ); break; case ID_REFRESH_SEARCH: SendMessage( m_curview_hwnd, WM_ML_CHILDIPC, 0, ML_CHILDIPC_REFRESH_SEARCH ); break; case ID_NEW_PLAYLIST: { // only process if not in an edit control // (as shift+insert is a legacy OS paste shortcut) wchar_t szClass[ 32 ] = { 0 }; HWND hFocus = GetFocus(); if ( GetClassNameW( hFocus, szClass, sizeof( szClass ) / sizeof( szClass[ 0 ] ) ) && CSTR_EQUAL != CompareStringW( CSTR_INVARIANT, NORM_IGNORECASE, szClass, -1, WC_EDITW, -1 ) ) { #define ID_MLFILE_NEWPLAYLIST 40359 SendMessageW( plugin.hwndParent, WM_COMMAND, MAKEWPARAM( ID_MLFILE_NEWPLAYLIST, 0 ), 0 ); } else SendMessageW( hFocus, WM_PASTE, 0, 0L ); } break; case ID_SHOW_HELP: // do nothing, just need to still F1 from Winamp break; } break; case WM_NOTIFY: { LRESULT result; result = 0; if ( !NavCtrlI_ProcessNotifications( hNavigation, (LPNMHDR)lParam, &result ) ) result = MlView_OnNotify( hwndDlg, (INT)wParam, (NMHDR *)lParam ); SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, (LONGX86)(LONG_PTR)result ); return TRUE; } case WM_CAPTURECHANGED: { POINT pt = { MAXLONG,MAXLONG }; OnLButtonUp( hwndDlg, pt, 0 ); break; } case WM_DROPFILES: OnDragDrop( hwndDlg, (HDROP)wParam ); break; case WM_INITMENUPOPUP: OnInitMenuPopUp( (HMENU)wParam ); return TRUE; case WM_DISPLAYCHANGE: OnDisplayChange( hwndDlg, (UINT)wParam, LOWORD( lParam ), HIWORD( lParam ) ); return TRUE; case WM_INITDIALOG: return OnInitDialog( hwndDlg ); case WM_DESTROY: OnDestroy( hwndDlg ); break; case WM_WINDOWPOSCHANGED: OnWindowPosChanged( hwndDlg, (WINDOWPOS *)lParam ); return TRUE; case WM_CLOSE: OnClose( hwndDlg ); break; case WM_GETMINMAXINFO: OnGetMaxMinInfo( (LPMINMAXINFO)lParam ); return TRUE; case WM_TIMER: OnTimer( hwndDlg, (UINT_PTR)wParam ); return TRUE; case WM_ML_IPC: return OnMediaLibraryIPC( hwndDlg, wParam, lParam ); case WM_USER + 0x200: SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, TRUE ); return TRUE; case WM_USER + 0x201: g_rgnUpdate = (HRGN)lParam; return TRUE;// parent supports region updates. lParam is a HRGN to set HRGN coordinate mapped to parent client area (this message sent prior to WM_WINDOWPOSCHANGED. case WM_SHOWWINDOW: { if ( wParam ) PostMessage( hwndDlg, WM_USER + 31, wParam, 0 ); else OnShowWindow( hwndDlg, (BOOL)wParam ); return TRUE; } case WM_USER + 30: { SetWindowRedraw( hwndDlg, FALSE ); DestroyWindow( m_curview_hwnd ); SetWindowRedraw( hwndDlg, TRUE ); CreateCurrentView( hwndDlg ); break; } case WM_USER + 31: // double-pump this to work around slower plugins loading up if ( !lParam ) PostMessage( hwndDlg, WM_USER + 31, wParam, 1 ); else { OnShowWindow( hwndDlg, (BOOL)wParam ); NavItemI_EnsureVisible( NavCtrlI_GetSelection( hNavigation ) ); } break; case WM_CONTEXTMENU: MSGRESULT( hwndDlg, MlView_OnContextMenu( hwndDlg, (HWND)wParam, MAKEPOINTS( lParam ) ) ); case WM_HELP: MSGRESULT( hwndDlg, MlView_OnHelp( hwndDlg, (HELPINFO *)lParam ) ); case WMML_SHOWCONTAINER: ShowWindow( g_ownerwnd, (INT)wParam ); return TRUE; } return FALSE; } void OnInitMenuPopUp( HMENU menu ) { if ( main_sendtomenu || !main_sendto_hmenu || menu != main_sendto_hmenu ) return; main_sendtomenu = new SendToMenu(); main_sendtomenu->buildmenu( menu, main_sendto_mode, 0 ); } void OnDisplayChange( HWND hwndDlg, UINT imgDepth, UINT hRes, UINT vRes ) { ResetColors( TRUE ); // must be first MlStockObjects_Reset(); ratingGlobalStyle = g_config->ReadInt( L"rating_style", RATING_DEFAULT_STYLE ); MLRatingColumnI_Update(); if ( IsWindow( m_curview_hwnd ) ) { RECT rc; GetClientRect( m_curview_hwnd, &rc ); RedrawWindow( m_curview_hwnd, &rc, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN | RDW_ERASENOW/* | RDW_UPDATENOW*/ ); MLSkinnedWnd_SkinChanged( m_curview_hwnd, TRUE, TRUE ); SendNotifyMessageW( m_curview_hwnd, WM_DISPLAYCHANGE, imgDepth, MAKELPARAM( hRes, vRes ) ); } NavCtrlI_UpdateLook( hNavigation ); MLSkinnedWnd_SkinChanged( GetDlgItem( hwndDlg, IDC_BTN_LIB ), TRUE, TRUE ); MLSkinnedWnd_SkinChanged( GetDlgItem( hwndDlg, IDC_VDELIM ), TRUE, TRUE ); MLSkinnedWnd_SkinChanged( GetDlgItem( hwndDlg, IDC_NO_VIEW ), TRUE, TRUE ); LayoutWindows( hwndDlg, divider_pos, TRUE ); } #include "mldwm.h" int OnInitDialog( HWND hwndDlg ) { firstShow = TRUE; MlStockObjects_Init(); if ( S_OK == MlDwm_LoadLibrary() ) { DWMNCRENDERINGPOLICY ncrp = DWMNCRP_DISABLED; BOOL allow = FALSE; MlDwm_SetWindowAttribute( GetParent( hwndDlg ), DWMWA_NCRENDERING_POLICY, &ncrp, sizeof( ncrp ) ); MlDwm_SetWindowAttribute( GetParent( hwndDlg ), DWMWA_ALLOW_NCPAINT, &allow, sizeof( allow ) ); } MLSkinWindow2( hwndDlg, hwndDlg, SKINNEDWND_TYPE_DIALOG, SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS ); HWND hctrl = GetDlgItem( hwndDlg, IDC_BTN_LIB ); MLSkinWindow2( hwndDlg, hctrl, SKINNEDWND_TYPE_BUTTON, SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS ); hctrl = GetDlgItem( hwndDlg, IDC_VDELIM ); MLSkinWindow2( hwndDlg, hctrl, SKINNEDWND_TYPE_DIVIDER, SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWDIV_VERT ); MLSkinnedDivider_SetCallback( hctrl, OnDividerMoved, NULL ); hctrl = GetDlgItem( hwndDlg, IDC_NO_VIEW ); MLSkinWindow2( hwndDlg, hctrl, SKINNEDWND_TYPE_STATIC, SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWDIV_VERT ); if ( !hmlifMngr ) // Initialize Image Filter manager { hmlifMngr = MLImageFilterI_CreateManager( 8, 4 ); if ( hmlifMngr ) { RegisterImageFilters( hmlifMngr ); SkinnedButton::RegisterImageFilter( hmlifMngr ); } } if ( !hNavigation ) { hNavigation = NavCtrlI_Create( hwndDlg ); if ( hNavigation ) { if ( !hmlilNavigation ) hmlilNavigation = CreateNavigationImages( hmlifMngr ); NavCtrlI_SetConfig( hNavigation, g_config ); NavCtrlI_SetImageList( hNavigation, hmlilNavigation ); NavCtrlI_RegisterCallback( hNavigation, OnNavCtrl_Selected, CALLBACK_ONSELECTED_I ); NavCtrlI_RegisterCallback( hNavigation, OnNavCtrl_Click, CALLBACK_ONCLICK_I ); NavCtrlI_RegisterCallback( hNavigation, OnNavCtrl_KeyDown, CALLBACK_ONKEYDOWN_I ); NavCtrlI_RegisterCallback( hNavigation, OnNavCtrl_BeginDrag, CALLBACK_ONBEGINDRAG_I ); NavCtrlI_RegisterCallback( hNavigation, OnNavCtrl_GetImageIndex, CALLBACK_ONGETIMAGEINDEX_I ); NavCtrlI_RegisterCallback( hNavigation, OnNavCtrl_BeginTitleEdit, CALLBACK_ONBEGINTITLEEDIT_I ); NavCtrlI_RegisterCallback( hNavigation, OnNavCtrl_EndTitleEdit, CALLBACK_ONENDTITLEEDIT_I ); NavCtrlI_RegisterCallback( hNavigation, OnNavItem_Delete, CALLBACK_ONITEMDELETE_I ); NavCtrlI_RegisterCallback( hNavigation, OnNavItem_CustomDraw, CALLBACK_ONITEMDRAW_I ); NavCtrlI_RegisterCallback( hNavigation, OnNavItem_SetCursor, CALLBACK_ONSETCURSOR_I ); NavCtrlI_RegisterCallback( hNavigation, OnNavItem_HitTest, CALLBACK_ONHITTEST_I ); NavCtrlI_RegisterCallback( hNavigation, OnNavCtrl_Destroy, CALLBACK_ONDESTROY_I ); hctrl = NavCtrlI_GetHWND( hNavigation ); SetWindowLongPtr( hctrl, GWLP_ID, IDC_NAVIGATION ); SetWindowLongPtr( hctrl, GWL_STYLE, GetWindowLongPtr( hctrl, GWL_STYLE ) | WS_GROUP ); } } if ( hNavigation ) SetWindowPos( GetDlgItem( hwndDlg, IDC_BTN_LIB ), NavCtrlI_GetHWND( hNavigation ), 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE ); divider_pos = g_config->ReadInt( L"ldivpos", 135 ); if ( !hmlilRating ) { hmlilRating = MLImageListI_Create( 44, 12, MLILC_COLOR24_I, 1, 1, 4, hmlifMngr ); if ( hmlilRating ) { MLIMAGESOURCE_I is = { 0 }; is.hInst = plugin.hDllInstance; is.lpszName = MAKEINTRESOURCEW( IDB_RATING ); is.type = SRC_TYPE_PNG_I; MLImageListI_Add( hmlilRating, &is, MLIF_FILTER1_UID, 0 ); } } ratingGlobalStyle = g_config->ReadInt( L"rating_style", RATING_DEFAULT_STYLE ); MLRatingColumnI_Initialize(); #ifdef CLOUD if ( !hmlilCloud ) { hmlilCloud = MLImageListI_Create( 16, 16, MLILC_COLOR24_I, 1, 1, 4, hmlifMngr ); if ( hmlilCloud ) { MLIMAGESOURCE_I is = { 0 }; is.hInst = plugin.hDllInstance; is.lpszName = MAKEINTRESOURCEW( IDB_CLOUD_IS_IN ); is.type = SRC_TYPE_PNG_I; MLImageListI_Add( hmlilCloud, &is, MLIF_FILTER1_UID, 0 ); is.lpszName = MAKEINTRESOURCEW( IDB_CLOUD_PARTIAL ); MLImageListI_Add( hmlilCloud, &is, MLIF_FILTER1_UID, 0 ); is.lpszName = MAKEINTRESOURCEW( IDB_CLOUD_UNAVAIL ); MLImageListI_Add( hmlilCloud, &is, MLIF_FILTER1_UID, 0 ); is.lpszName = MAKEINTRESOURCEW( IDB_CLOUD_UPLOAD ); MLImageListI_Add( hmlilCloud, &is, MLIF_FILTER1_UID, 0 ); is.lpszName = MAKEINTRESOURCEW( IDB_CLOUD_UPLOADING ); MLImageListI_Add( hmlilCloud, &is, MLIF_FILTER1_UID, 0 ); } } MLCloudColumnI_Initialize(); #endif OnDisplayChange( hwndDlg, 0, 0, 0 ); HACCEL hAccel = WASABI_API_LOADACCELERATORSW( IDR_ACCELERATOR_GLOBAL ); if ( hAccel ) WASABI_API_APP->app_addAccelerators( hwndDlg, &hAccel, 1, TRANSLATE_MODE_GLOBAL ); hAccel = WASABI_API_LOADACCELERATORSW( IDR_ACCELERATOR_MAIN ); if ( hAccel ) WASABI_API_APP->app_addAccelerators( hwndDlg, &hAccel, 1, TRANSLATE_MODE_CHILD ); return TRUE; } static void OnDestroy( HWND hwndDlg ) { HNAVITEM hItem = NavCtrlI_GetSelection( hNavigation ); if ( hItem ) { wchar_t name[ 1024 ] = { 0 }; if ( NavItemI_GetFullName( hItem, name, 1024 ) ) g_config->WriteString( "last_view", AutoChar( name, CP_UTF8 ) ); } g_config->WriteInt( L"ldivpos", divider_pos ); NavCtrlI_Destroy( hNavigation ); hNavigation = NULL; MLImageListI_Destroy( hmlilNavigation ); hmlilNavigation = NULL; MLImageFilterI_DestroyManager( hmlifMngr ); hmlifMngr = NULL; MLImageListI_Destroy( hmlilRating ); hmlilRating = NULL; MLImageListI_Destroy( hmlilCloud ); hmlilCloud = NULL; RemoveProp( hwndDlg, BLOCK_ACCELTOGGLE_PROP ); MlStockObjects_Free(); } static void OnClose( HWND hwndDlg ) { toggleVisible( 1 ); } static void OnShowWindow( HWND hwndDlg, BOOL fShow ) { if ( firstShow && fShow ) { firstShow = FALSE; MLVisibleChanged( TRUE ); // setting things to a more user friendly default than just the Local Media view char *lastTitleA = g_config->ReadString( "last_view", "Local Media/Audio" ); HNAVITEM hDefItem = NULL; if ( lastTitleA && *lastTitleA ) { wchar_t textW[ 2048 ] = { 0 }; if ( MultiByteToWideCharSZ( CP_UTF8, 0, lastTitleA, -1, textW, 2048 ) ) hDefItem = NavCtrlI_FindItemByFullName( hNavigation, LOCALE_INVARIANT, NICF_INVARIANT_I | NICF_DISPLAY_I | NICF_IGNORECASE_I, textW, -1, TRUE ); } if ( !hDefItem ) hDefItem = NavCtrlI_GetRoot( hNavigation ); NavItemI_Select( hDefItem ); NavCtrlI_Show( hNavigation, SW_SHOWNA ); } } LRESULT OnMediaLibraryIPC( HWND hwndDlg, WPARAM wParam, LPARAM lParam ) { SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, (LONGX86)(LONG_PTR)pluginHandleIpcMessage( hwndDlg, (INT)lParam, (INT_PTR)wParam ) ); return TRUE; } void OnGetMaxMinInfo( MINMAXINFO *info ) { info->ptMinTrackSize.x = 300; info->ptMinTrackSize.y = 200; } void OnBtnLibraryClick( HWND hwndBtn ) { RECT r; GetWindowRect( hwndBtn, &r ); SendMessageW( hwndBtn, BM_SETSTATE, TRUE, 0L ); MediaLibrary_TrackPopup( GetSubMenu( g_context_menus, 0 ), TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_BOTTOMALIGN | TPM_LEFTALIGN | TPM_VERNEGANIMATION, r.left, r.top, GetParent( hwndBtn ) ); SendMessageW( hwndBtn, BM_SETSTATE, FALSE, 0L ); UpdateWindow( hwndBtn ); Sleep( 100 ); MSG msg; while ( PeekMessageW( &msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) ); //eat return }