/*****************************************************************************
Open Source MIT License

Copyright (c) 2017 Matthew Ahmed

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*****************************************************************************/

// ParentDlg.cpp: implementation of the CParentDlg class.
//
//////////////////////////////////////////////////////////////////////

#include "Headers.h"

// Using stc32 in OpenFileName template warns of redefinition
#pragma warning(push)
#pragma warning(disable : 4005)
#include "resource.h"
// Restore settings in effect at warning(push) above
#pragma warning(pop)

#include "Settings.h"
#include "ParentDlg.h"
#include "MinDlg.h"
#include "CopyDlg.h"
#include "PrefDlg.h"
#include "CopyOptDlg.h"
#include "LogOptDlg.h"
#include "AboutDlg.h"

CParentDlg * pParentDlg;

//BOOL ParentDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
INT_PTR CALLBACK ParentDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	return pParentDlg->OwnProc(hDlg, message, wParam, lParam);
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CParentDlg::CParentDlg(HINSTANCE hInst, CSettings * pSet,
								 LPCTSTR sCapt1, LPCTSTR sCapt2, ZWin * pOwner,
                 ZWinAppData * pzwd)
	: ZDlg(hInst, sCapt1, sCapt2, pOwner, pzwd)
{
	ini = pSet;
	pParentDlg = this;
	//m_pProc = ParentDlgProc;
	m_uID = IDD_PARENT;

  m_pCopyDlg = NULL;
  m_pMinDlg = NULL;
  m_bMouseInPref = FALSE;
  m_bMouseInHelp = FALSE;
  m_bHelpMenuOn = FALSE;
  m_bPrefMenuOn = FALSE;
  //m_bMinPaintPending = FALSE;
  m_bIsStartUp = TRUE;
}

CParentDlg::~CParentDlg()
{
  //if (m_pCopyDlg)
  //{
  //  m_pCopyDlg->DestroyWindow();
  //  delete m_pCopyDlg;
  //}
  //if (m_pMinDlg)
  //{
  //  DestroyWindow(m_pMinDlg->GetWnd());
  //  delete m_pMinDlg;
  //}
}

void CParentDlg::OnClose()
{
  // Zdlg virtual WM_CLOSE handler calls this
  if (m_pCopyDlg)
  {
    m_pCopyDlg->DestroyWindow();
    delete m_pCopyDlg;
  }
  if (m_pMinDlg)
  {
    DestroyWindow(m_pMinDlg->GetWnd());
    delete m_pMinDlg;
  }
}

// Override ZDlg, so can set Proc as INT_PTR CALLBACK
INT CParentDlg::Run() // Usual modal dialog
{
	return DialogBox(m_hInst, MAKEINTRESOURCE(m_uID),
//											m_hOwner, (DLGPROC) m_pProc);
											m_hOwner, ParentDlgProc);
}

//BOOL CParentDlg::OwnProc(HWND hDlg, UINT uMsg, WPARAM wP, LPARAM lP)
INT_PTR CALLBACK CParentDlg::OwnProc(HWND hDlg, UINT uMsg, WPARAM wP, LPARAM lP)
{
	switch (uMsg)
	{
    NMHDR* pnmh;

    case WM_NOTIFY:
      pnmh = (NMHDR*) lP;

      if (pnmh->code == TCN_SELCHANGE && pnmh->hwndFrom == m_hTab)
        OnTcnSelChange(pnmh);
        // Then drop through to return 0;
      break;

// Forget all this, just let CMinDlg repaint on regular interval
    //// Child CMInDlg doesn't get all notifications when its bitmap needs repaint.
    //// Tell MinDlg every time Parent repaints, instead of individual cases below.
    //case WM_PAINT:
    //  //if (m_bMinIsActive)
    //  //{
    //  //  //PostMessage(m_hActiveChild, WMU_PAINTMIN, 0, 0);

    //  //  //OnWmPaint();
    //  //}

    //  //if (m_bMinIsActive && !m_bMinPaintPending)
    //  //{
    //  //  // Let whatever else is going on here finish before post to MinDlg
    //  //  m_bMinPaintPending = TRUE;
    //  //  PostMessage(m_hWnd, WMU_PAINTMIN, 0, 0);
    //  //}

    //  // This works fine except it doesn't draw stars on start up
    //  // OK if CMinDlg has a timer delay to repaint
    //  if (m_bMinIsActive && !m_bMinPaintPending)
    //  {
    //    // Set CMinDlg to repaint stars bitmap only if in invalidated region
    //    RECT rcInvalid;
    //    if (GetUpdateRect(m_hWnd, &rcInvalid, FALSE) &&
    //        RectanglesOverlap(&m_rcStarsFrame, &rcInvalid) )
    //    {
    //      // Let whatever else is going on here finish before post to MinDlg
    //      m_bMinPaintPending = TRUE;
    //      PostMessage(m_hWnd, WMU_PAINTMIN, 0, 0);
    //    }
    //    // else nothing in CMinDlg that needs reminder from parent to paint
    //  } // if (m_bMinIsActive && !m_bMinPaintPending)
    //  break;

    //case WMU_PAINTMIN:
    //  // Receive this from self after something that might create repaint need,
    //  // including window messages below and menu activity
    //  if (m_bMinIsActive)
    //  {
    //    PostMessage(m_hActiveChild, WMU_PAINTMIN, 0, 0);
    //    SetTimer(m_hWnd, U_TIMER_NO_POSTPAINT, 100, NULL);
    //  }
    //  // Still "m_bMinPaintPending" (name no longer accurate) until timer expires
    //  break;

    //case WM_TIMER:
    //  // Briefly ignored WMU_PAINTMIN from parent to avoid feedback. Resume normal
    //  if (wP == U_TIMER_NO_POSTPAINT)
    //  {
    //    KillTimer(m_hWnd, U_TIMER_NO_POSTPAINT);
    //    m_bMinPaintPending = FALSE;
    //  }
    //  break;

    //case WM_SIZE:
    //  if ( (wP == SIZE_RESTORED || wP == SIZE_MAXIMIZED)
    //      && m_bMinIsActive && !m_bMinPaintPending)
    //  {
    //    // Let the sizing get processed before repaint is triggered
    //    m_bMinPaintPending = TRUE;
    //    PostMessage(m_hWnd, WMU_PAINTMIN, 0, 0);
    //  }
    //  break;

    //case WM_WINDOWPOSCHANGED:
    //  // This still misses case
    //  if (m_bMinIsActive && !m_bMinPaintPending)
    //  {
    //    m_bMinPaintPending = TRUE;
    //    PostMessage(m_hWnd, WMU_PAINTMIN, 0, 0);
    //  }
    //  break;

    //case WM_ACTIVATE: // If above missed something, at least fix when activated
    //  if (LOWORD(wP) != WA_INACTIVE && m_bMinIsActive && !m_bMinPaintPending)
    //  {
    //    m_bMinPaintPending = TRUE;
    //    PostMessage(m_hWnd, WMU_PAINTMIN, 0, 0);
    //  }
    //  break;


    case WMU_CLOSEALL:
      CloseAllReally();
      return TRUE;

    case WM_CTLCOLORSTATIC:
      return OnWmCtlColorStatic(wP, lP);

    case WMU_HELP_MENU_OFF:
      m_bHelpMenuOn = FALSE;
      return TRUE;

    case WMU_PREF_MENU_OFF:
      m_bPrefMenuOn = FALSE;
      return TRUE;

		// Insert DTAKEMSG(WM_WHATEVER, OnWhatever); except for WM_COMMAND
    DSEEMSG(WM_SHOWWINDOW, OnShowWindow);
    DSEEMSGPARMS(WM_LBUTTONDOWN, OnLButtonDown);
    DSEEMSGPARMS(WM_MOUSEMOVE, OnWmMouseMove);
//    DSEEMSGPARMS(WM_TIMER, OnWmTimer);
    DSEEMSG(WM_MOUSELEAVE, OnWmMouseLeave);

    // Insert WM_INITDIALOG usually handled by ZDlg::OwnProc
    case WM_INITDIALOG:
			m_hWnd = hDlg;
			if (!OnInitDialog()) // base virtual always returns TRUE
				EndDialog(m_hWnd, FALSE);
			return TRUE;



// Don't bitch about no cases in WM_COMMAND's switch(wP) (warning 4065)
#pragma warning(push)
#pragma warning(disable : 4065)
		case WM_COMMAND:
			switch(LOWORD(wP))
			{
        // These two from ZDlg::OwnProc
				DTAKECMD(IDOK, OnOk);
				DTAKECMD(IDCANCEL, OnCancel);

				// Insert DTAKECMD(IDC_BN_ETC, OnEtc);

        //DTAKECMD(IDC_PBN_TEST, OnBnTest);

				default : break;

			} // END switch(LOWORD(wP))
// Restore settings in effect at warning(push) above
#pragma warning(pop)

		default : break;
	}

	// ZDlg already calls OnInitDialog, OnOK, OnCancel, or returns FALSE
	//return ZDlg::OwnProc(hDlg, uMsg, wP, lP);
  return 0;
}


BOOL CParentDlg::OnInitDialog()
{
	SendMessage(m_hWnd, WM_SETICON, ICON_BIG,
							(LPARAM) LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_MAIN)));
	SendMessage(m_hWnd, WM_SETICON, ICON_SMALL,
							(LPARAM) LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_MAIN)));

  //// Stars bitmap in CMinDlg - need to do painting from here
  //m_hnMinImgStars = LoadImage(m_hInst, MAKEINTRESOURCE(IDB_STARS_LVIEW),
  //                            IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
  //// Don't include LR_LOADTRANSPARENT if painting with TransparentBlt

  m_hTab = GetItem(IDC_PTAB);

  // For plain static text controls being used as menu bar
  // Convert from screen to client units, same as WM_LBUTTONDOWN lParam
  m_hTxtPref = GetItem(IDCP_TXT_MENUP);
  //GetWindowRect(m_hTxtPref, &m_rectPref);
  //m_rectPref.left -= p.x;
  //m_rectPref.top -= p.y;
  //m_rectPref.right -= p.x;
  //m_rectPref.bottom -= p.y;
  GetControlRect(m_hTxtPref, &m_rectPref);

  m_hTxtHelp = GetItem(IDCP_TXT_MENUH);
  GetControlRect(m_hTxtHelp, &m_rectHelp);

  // Frames to define the highlighted area when mouse is over "menu"
  m_hFrPref = GetItem(IDCP_FR_PREF);
  GetControlRect(m_hFrPref, &m_rFrPref);

  m_hFrHelp = GetItem(IDCP_FR_HELP);
  GetControlRect(m_hFrHelp, &m_rFrHelp);

  m_pMinDlg = new CMinDlg(m_hInst, ini, m_sCapt, NULL, this, m_pzwd);
  if (m_pMinDlg)
  {
    if (!m_pMinDlg->RunModeless())
      fnSysErr(_T("Error starting Jukebox Shuffle child window"));
  }
  else fnSysErr(_T("Error creating Jukebox Shuffle child window"));

  m_pCopyDlg = new CCopyDlg(m_hInst, ini, m_sCapt, NULL, this,
                            (ZWinAppDataClone *) m_pzwd);
  if (m_pCopyDlg)
  {
    //if (!m_pCopyDlg->RunModeless())
    if (m_pCopyDlg->Create(IDD_COPY)) m_pCopyDlg->ShowWindow(SW_SHOW);
    else fnErr(_T("Error starting Album Art child window"));

  }
  else fnSysErr(_T("Error creating Album Art child window"));

  TCITEM tabItem;
  tabItem.mask = TCIF_TEXT;

//  tabItem.pszText = _T("  Playlist Custom Shuffle   ");
  tabItem.pszText = _T("  Jukebox Custom Shuffle   ");
  if (TabCtrl_InsertItem(m_hTab, 0, &tabItem) == -1)
    fnErr(_T("Error insert tab for"), tabItem.pszText); 

  tabItem.pszText = _T("  Copy Album Art to Player   ");
  if (TabCtrl_InsertItem(m_hTab, 1, &tabItem) == -1)
    fnErr(_T("Error insert tab for"), tabItem.pszText);

//  if (!GetOwnDirSlash(m_sOwnDirSlash))
//  {
//    fnErr(_T("Error determining own folder."),
//          _T("Help file won't be found and may be errors if logging turned on"),
//          m_sOwnDirSlash);
//    m_sHelpPath[0];
//  }
//  else _stprintf(m_sHelpPath, _T("%sShaker.chm"), m_sOwnDirSlash);
  _stprintf(m_sHelpPath, _T("%sShaker.chm"), m_pzwd->sProgDirSlash);

  // Set m_rcTab with display area to place child dialogs in
  GetClientRect(m_hWnd, &m_rcTab);

  // Before adjust rect, set fixed tab sizes with room for manually placed menu
//  TabCtrl_SetItemSize(m_hTab, (m_rcTab.right - m_rcTab.left) / 3, 20);
  TabCtrl_SetItemSize(m_hTab, (m_rcTab.right - m_rcTab.left) / 3, 21);

  TabCtrl_AdjustRect(m_hTab, FALSE, &m_rcTab);
  // Doesn't come out just right with SetWindowPos in ShowTab; tweak
  m_rcTab.left -= 3;
  m_rcTab.right += 1;
  //m_rcTab.top -= 1;
  m_rcTab.bottom += 3;

  // At start up, MinDlg (shuffle) is active tab 
  ShowTab(0);

  // For clearing highlight of menu labels when mouse quickly leaves
  DWORD dwTrackSize = sizeof(TRACKMOUSEEVENT);

  m_tme_StartTrackMouse.cbSize = dwTrackSize;
  m_tme_StartTrackMouse.dwFlags = TME_LEAVE;
  m_tme_StartTrackMouse.hwndTrack = m_hWnd;
  m_tme_StartTrackMouse.dwHoverTime = 0;

  m_tme_StopTrackMouse.cbSize = dwTrackSize;
  m_tme_StopTrackMouse.dwFlags = TME_CANCEL;
  m_tme_StopTrackMouse.hwndTrack = m_hWnd;
  m_tme_StopTrackMouse.dwHoverTime = 0;

	return ZDlg::OnInitDialog(); // always TRUE
}

void CParentDlg::OnShowWindow() // Only happens once, at start up
{
  if (!m_bIsStartUp) return; // Apparently never happens, but right if it does

  //// Get Rectangle needed for painting CMinDlg's stars bitmap
  //HWND hPlacementFrame = m_pMinDlg->GetStarsFrameHwnd();
  //// Cloned from Zdlg:GetControlRect
  //POINT p;
  //p.x = 0;
  //p.y = 0;
  //ClientToScreen(hPlacementFrame, &p);
  //GetWindowRect(m_hWnd, &m_rcStarsFrame);
  //m_rcStarsFrame.left -= p.x;
  //m_rcStarsFrame.top -= p.y;
  ////m_rcStarsFrame.right -= p.x;
  ////m_rcStarsFrame.bottom -= p.y;
  //// CMinDlg's WM_PAINT handler will ensure upper left is right
  //// Use bitmap size to set lower right
  //m_rcStarsFrame.right = m_rcStarsFrame.left + 162;
  //m_rcStarsFrame.bottom = m_rcStarsFrame.top + 18;

  ShowTab(0); // On startup Jukebox is the active tab
}

void CParentDlg::ShowTab(INT nTab)
{
  INT nTabCount = 2;
  
  if (nTab < nTabCount && nTab >= 0)
  {
    // With CopyDlg changed to CDialog, can't use array, 
    HWND hInactive;
    if (nTab == 0) // MinDlg
    {
      m_hActiveChild = m_pMinDlg->GetWnd();
      hInactive = m_pCopyDlg->GetSafeHwnd();
      m_bMinIsActive = TRUE;
//      m_bMinPaintPending = FALSE;
    }
    else
    {
      m_hActiveChild = m_pCopyDlg->GetSafeHwnd();
      hInactive = m_pMinDlg->GetWnd();
      m_bMinIsActive = FALSE;
    }
    ini->SetDlg(m_hActiveChild);

    ShowWindow(hInactive, SW_HIDE);

    SetWindowPos(m_hActiveChild, HWND_TOP, m_rcTab.left, m_rcTab.top,
                    m_rcTab.right - m_rcTab.left, m_rcTab.bottom - m_rcTab.top,
                    SWP_SHOWWINDOW);

    //// Make sure stars image gets painted when CMinDlg first appears
    //if (m_bMinIsActive)
    //{
    //  PostMessage(m_hWnd, WMU_PAINTMIN, 0, 0);
    //  if (m_bIsStartUp)
    //  {
    //    m_pMinDlg->SetFailsafePaintTimer();
    //    m_bIsStartUp = FALSE;
    //  }
    //}

    // Turn CMinDlg image painting on or off
    m_pMinDlg->SetPaintMonitor(m_bMinIsActive);
    if (m_bIsStartUp)
    {
      // Tell MinDlg to load library while it's first shown (dont delay display)
//      PostMessage(m_pMinDlg->GetWnd(), WMU_AFTERSHOW, 0, 0); // Handle inside CMinDlg
      m_bIsStartUp = FALSE;
    }

  } // if (nTab < nTabCount && nTab >= 0)

} // void CParentDlg::ShowTab(INT nTab)

void CParentDlg::OnTcnSelChange(NMHDR* pnmh)
{
  // If select has switched away from dialog in process, restore selection to it
  if (m_pMinDlg->InProgress() || m_pCopyDlg->InProgress())
    TabCtrl_SetCurSel(m_hTab,
                      TabCtrl_GetCurSel(m_hTab) == IX_MINDLG ? IX_COPYDLG
                                                             : IX_MINDLG);
  else ShowTab(TabCtrl_GetCurSel(m_hTab)); // Normal case
}

void CParentDlg::OnWmMouseMove(WPARAM, LPARAM lp_XloYhi)
{
  static INT x;
  static LONG y;
  BOOL bNowInHelp = FALSE; // unless reset below
  BOOL bNowInPref = FALSE;

  // Where mouse is in client coord.
  x = LOWORD(lp_XloYhi); 
  y = HIWORD(lp_XloYhi);

  // Vast majority of time, quickly rule out that mouse is in either control 
  if (! (y < m_rectPref.top || y > m_rectPref.bottom ||
         x < m_rectPref.left || x > m_rectHelp.right) )
  {
    // y definitely ok. Is either in one of the controls, or x between them
    if (x >= m_rectHelp.left) bNowInHelp = TRUE;
    else if (x <= m_rectPref.right) bNowInPref = TRUE;
    // else between the controls, leave both FALSE
  }
  // else can't possibly be in either control, leave both FALSE

  // Know where the mouse is, see if it's a change
  if (bNowInHelp)
  {
    if (!m_bMouseInHelp) return SetMouseInHelp(TRUE);
    else return; // No change, nothing to do
  }
  else if (bNowInPref)
  {
    if (!m_bMouseInPref) return SetMouseInPref(TRUE);
    else return;
  }
  else  // In neither. See if it just left either rectangle
  {
    if (m_bMouseInHelp) return SetMouseInHelp(FALSE);
    else if (m_bMouseInPref)  return SetMouseInPref(FALSE);
    // else no change, isn't & wasn't in either
  }

} // void CParentDlg::OnWmMouseMove(WPARAM, LPARAM lp)

void CParentDlg::SetMouseInHelp(BOOL bIn, BOOL bSetTrack)
{
  if (bSetTrack) TrackMouseEvent(bIn ? &m_tme_StartTrackMouse 
                                     : &m_tme_StopTrackMouse);
  m_bMouseInHelp = bIn;
  //InvalidateRect(m_hWnd, &m_rectHelp, TRUE);
  InvalidateRect(m_hWnd, &m_rFrHelp, TRUE);
}

void CParentDlg::SetMouseInPref(BOOL bIn, BOOL bSetTrack)
{
  if (bSetTrack) TrackMouseEvent(bIn ? &m_tme_StartTrackMouse 
                                     : &m_tme_StopTrackMouse);
  m_bMouseInPref = bIn;
  //InvalidateRect(m_hWnd, &m_rectPref, TRUE);
  InvalidateRect(m_hWnd, &m_rFrPref, TRUE);
}

void CParentDlg::OnWmMouseLeave()
{
  if (m_bMouseInPref && !m_bPrefMenuOn) SetMouseInPref(FALSE, FALSE);
  if (m_bMouseInHelp && !m_bHelpMenuOn) SetMouseInHelp(FALSE, FALSE);
}

//void CParentDlg::HiLiteControl(HWND hCtl, RECT rc, LPCTSTR sTxt, BOOL bHiLite)
//{
//  COLORREF clrPrevText, clrPrevBkgnd; 
//  HFONT hfntPrev;
//  HDC hDC = GetDC(hCtl);
//  if (!hDC) return;
//
//  clrPrevText = SetTextColor(hDC, GetSysColor(bHiLite ? COLOR_HIGHLIGHTTEXT
//                                                      : COLOR_3DFACE));
//  clrPrevBkgnd = SetBkColor(hDC, GetSysColor(bHiLite ? COLOR_HIGHLIGHT
//                                                     : COLOR_BTNTEXT));
//
//  hfntPrev = (HFONT) SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT));
//
//
//  if (!ExtTextOut(hDC, rc.left, rc.top, ETO_OPAQUE, &rc, sTxt, 4, NULL))
//    fnSysErr("!ExtTextOut");
//
//  if (!DrawText(hDC, sTxt, 4,  &rc, DT_INTERNAL))
//    fnSysErr("!DrawText");
//
//  if (!TextOut(hDC, rc.left, rc.top, sTxt, 4))
//    fnSysErr("!DrawText");
//
// // SetWindowText(hCtl, sTxt);
//
//
//  SetTextColor(hDC, clrPrevText); 
//  SetBkColor(hDC, clrPrevBkgnd); 
//  ReleaseDC(hCtl, hDC);
//
//
//} // void CParentDlg::HiLiteControl(HWND hCtl, BOOL bHiLite)

void CParentDlg::OnLButtonDown(WPARAM, LPARAM lp_XloYhi)
{
  static INT x;
  static LONG y;

  // Where mouse was clicked (client coord). Ignore all except on menu text.
  x = LOWORD(lp_XloYhi); 
  y = HIWORD(lp_XloYhi);

  // Both "menu" text controls have same y coordinates, see if above/below
  if (y < m_rectPref.top || y > m_rectPref.bottom) return;

  // See if outside the horizontal range of both controls
  if (x < m_rectPref.left || x > m_rectHelp.right) return;

  // Could be between menus (not adjacent)
//  if (x >= m_rectHelp.left) return ShowMenu(FALSE); // Help menu
//  if (x <= m_rectPref.right) return ShowMenu(TRUE); // Preferences menu
  if (x >= m_rectHelp.left) return ShowHelpMenu(); // Help menu
  if (x <= m_rectPref.right) return ShowPrefMenu(); // Preferences menu

  // if here, was between menus
} // void CParentDlg::OnLButtonDown(WPARAM, LPARAM lp)

LRESULT CParentDlg::OnWmCtlColorStatic(WPARAM wp_hDC, LPARAM lp_hCtl)
{
  if ( (m_bMouseInHelp && (HWND) lp_hCtl == m_hTxtHelp) ||
       (m_bMouseInPref && (HWND) lp_hCtl == m_hTxtPref) )
  {
    SetTextColor((HDC)wp_hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
    SetBkColor((HDC)wp_hDC, GetSysColor(COLOR_HIGHLIGHT));

    // Restore default for others
    return (LRESULT) GetSysColorBrush(COLOR_3DFACE); 
  }
  return FALSE; // Default handling
}

void CParentDlg::ShowHelpMenu()
{
  //// Can be this or other menu covered part of MinDlg image, and now is retracting.
  //// Tell MinDlg to repaint after any such changes are completed.
  //if (m_bMinIsActive && !m_bMinPaintPending)
  //{
  //  m_bMinPaintPending = TRUE; // Otherwise fast clicking back & forth could back up
  //  PostMessage(m_hWnd, WMU_PAINTMIN, 0, 0);
  //}

  if (m_bHelpMenuOn)
  {
    // Clicked menu label when open, let the click dismiss menu without reopening
    m_bHelpMenuOn = FALSE;
    return;
  }
  m_bHelpMenuOn = TRUE;

  TrackMouseEvent(&m_tme_StopTrackMouse);
  SetMouseInHelp(TRUE, FALSE);  // Sometimes redundant, ok if so

  HMENU hmu = CreatePopupMenu();
  RECT rect; // Can't use member rect, need screen units

  MENUINFO minfo;
  minfo.cbSize = sizeof(MENUINFO);
  minfo.fMask = MIM_STYLE;
  minfo.dwStyle = MNS_AUTODISMISS | MNS_NOCHECK;
  if (!SetMenuInfo(hmu, &minfo)) fnSysErr(_T("Error setting Help menu appearance."));

  if (!AppendMenu(hmu, 0, IDM_HELP, _T("Help Contents ...")))
    fnErr(_T("Error adding help contents menu item")); // but keep going

  if (!AppendMenu(hmu, 0, IDM_ABOUT, _T("About Shaken, not stirred")))
    fnErr(_T("Error adding help about menu item")); // but keep going

  GetWindowRect(m_hFrHelp, &rect);
  //INT nRet = TrackPopupMenuEx(hmu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD,
  //                            rect.left + 1, rect.bottom - 1, m_hWnd, 0);
  INT nRet = TrackPopupMenuEx(hmu, TPM_RIGHTALIGN | TPM_TOPALIGN | TPM_RETURNCMD |
                                   TPM_VERPOSANIMATION | TPM_HORNEGANIMATION,
                              rect.right - 1, rect.bottom - 1, m_hWnd, 0);

  switch (nRet)
  {
    // On all flow paths, clear "menu bar" highlight when select item or dismiss menu
    case IDM_HELP:
      SetMouseInHelp(FALSE);
      ShowHelp(NULL);
      break;

    case IDM_ABOUT:
      SetMouseInHelp(FALSE);
      //MB("Placeholder About window");
      RunAbout();
      break;

    default:
      // Menu has been dismissed, clear highlight
      SetMouseInHelp(FALSE);
      break;
  } // switch (nRet) i.e. TrackPopupMenuEx

  // In case clicked on menu label while open, delay so menu dismissed by click
  PostMessage(m_hWnd, WMU_HELP_MENU_OFF, 0, 0);

  //// Part of MinDlg image was covered by menu, now needs repaint
  //if (m_bMinIsActive && !m_bMinPaintPending)
  //{
  //  m_bMinPaintPending = TRUE;
  //  PostMessage(m_hWnd, WMU_PAINTMIN, 0, 0);
  //}
} // void CParentDlg::ShowHelpMenu()

void CParentDlg::ShowPrefMenu()
{
  //// Can be this or other menu covered part of MinDlg image, and now is retracting.
  //// Tell MinDlg to repaint after any such changes are completed
  //if (m_bMinIsActive && !m_bMinPaintPending)
  //{
  //  m_bMinPaintPending = TRUE; // Otherwise fast clicking back & forth could back up
  //  PostMessage(m_hWnd, WMU_PAINTMIN, 0, 0);
  //}

  if (m_bPrefMenuOn)
  {
    // Clicked menu label when open, let the click dismiss menu without reopening
    m_bPrefMenuOn = FALSE;
    return;
  }
  m_bPrefMenuOn = TRUE;

  TrackMouseEvent(&m_tme_StopTrackMouse);
  SetMouseInPref(TRUE, FALSE);  // Sometimes redundant, ok if so

  HMENU hmu = CreatePopupMenu();
  RECT rect; // Can't use member rect, need screen units

  MENUINFO minfo;
  minfo.cbSize = sizeof(MENUINFO);
  minfo.fMask = MIM_STYLE;
  minfo.dwStyle = MNS_AUTODISMISS | MNS_NOCHECK;
  if (!SetMenuInfo(hmu, &minfo))
    fnSysErr(_T("Error setting Settings menu appearance."));

  if (!AppendMenu(hmu, 0, IDM_OPT_SHUFFLE, _T("Jukebox Shuffle options ...")))
    fnErr(_T("Error adding shuffle options menu item")); // but keep going

  if (!AppendMenu(hmu, 0, IDM_OPT_ART, _T("Album Art options ...")))
    fnErr(_T("Error adding album options menu item")); // but keep going

  if (!AppendMenu(hmu, 0, IDM_OPT_LOG, _T("Logging options ...")))
    fnErr(_T("Error adding logging options menu item")); // but keep going

  GetWindowRect(m_hFrPref, &rect);
  //INT nRet = TrackPopupMenuEx(hmu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD,
  //                            rect.left + 1, rect.bottom - 1, m_hWnd, 0);
  INT nRet = TrackPopupMenuEx(hmu, TPM_RIGHTALIGN | TPM_TOPALIGN | TPM_RETURNCMD |
                                   TPM_VERPOSANIMATION | TPM_HORNEGANIMATION,
                              rect.right - 1, rect.bottom - 1, m_hWnd, 0);

  switch (nRet)
  {
    // On all flow paths, clear "menu bar" highlight when select item or dismiss menu
    case IDM_OPT_SHUFFLE:
      SetMouseInPref(FALSE);
      RunShufflePref();
      //m_pMinDlg->UpdatePref();
      break;

    case IDM_OPT_ART:
      SetMouseInPref(FALSE);
      RunOptCopy();
      break;

    case IDM_OPT_LOG:
      SetMouseInPref(FALSE);
      RunOptLog();
      break;

    default:
      // Menu has been dismissed, clear highlight
      SetMouseInPref(FALSE);
      break;
  } // switch (nRet) i.e. TrackPopupMenuEx

  // In case clicked on menu label while open, let m_bPrefMenuOn == TRUE stop
  // menu from opening before this message sets m_bPrefMenuOn = FALSE
  PostMessage(m_hWnd, WMU_PREF_MENU_OFF, 0, 0);

  //// Part of MinDlg image was covered by menu, now needs repaint
  //if (m_bMinIsActive && !m_bMinPaintPending)
  //{
  //  m_bMinPaintPending = TRUE;
  //  PostMessage(m_hWnd, WMU_PAINTMIN, 0, 0);
  //}
} // CParentDlg::ShowPrefMenu()

void CParentDlg::RunShufflePref()
{
	CPrefDlg* pDlg = NULL;
	//pDlg = new CPrefDlg(m_hInst, ini, m_sOwnDirSlash, m_sCapt,
 //                     _T("Jukebox Shuffle Options"), this);
	pDlg = new CPrefDlg(m_hInst, ini, m_sCapt, _T("Jukebox Shuffle Options"),
                      this, m_pzwd);
	if (!pDlg) RET_V(_T("Error creating Shuffle Preferences dialog"))

  pDlg->Run(); // Ignore return, dlg's ok/cancel decides whether ini updated

  delete pDlg; // Had no problem while this was forgotten. Just wasted memory?

  m_pMinDlg->UpdatePref(); // No effect if dialog was cancelled

  ini->SetDlg(m_hActiveChild);
} // CParentDlg::RunShufflePref()

void CParentDlg::RunOptCopy()
{
	CCopyOptDlg* pDlg = NULL;
	pDlg = new CCopyOptDlg(m_hInst, ini, m_sCapt,
                        _T("Album Art Options"), this, m_pzwd);

	if (!pDlg) RET_V(_T("Error creating Album Art Preferences dialog"))

  INT nRet = pDlg->Run();

  delete pDlg;

  if (nRet == IDOK) m_pCopyDlg->UpdateForPref();

  ini->SetDlg(m_hActiveChild);
} // CParentDlg::RunOptCopy()

void CParentDlg::RunOptLog()
{
	CLogOptDlg* pDlg = NULL;
	pDlg = new CLogOptDlg(m_hInst, ini, m_sCapt,
                        _T("Logging Options"), this, m_pzwd);

	if (!pDlg) RET_V(_T("Error creating Logging Options dialog"))

  INT nRet = pDlg->Run();

  delete pDlg;

  if (nRet == IDOK)
  {
    // Changes may affect either or both. OK if no effect.
    m_pCopyDlg->UpdateForPref();
    m_pMinDlg->UpdatePref();
  }

  ini->SetDlg(m_hActiveChild);
} // CParentDlg::RunOptLog()

void CParentDlg::RunAbout()
{
	CAboutDlg* pDlg = NULL;
	pDlg = new CAboutDlg(m_hInst, ini, _T("About \"Shaken, not stirred\""),
                       NULL, this);

	if (!pDlg) RET_V(_T("Error creating Album Art dialog"))

  INT nRet = pDlg->Run();

  delete pDlg;
}

void CParentDlg::ShowHelp(LPCTSTR sHelpPage)
{
  if (m_sHelpPath[0])
  {
    if (sHelpPage) _stprintf(sBS, _T("%s::/%s"), m_sHelpPath, sHelpPage);
    else _tcscpy(sBS, m_sHelpPath);
    HtmlHelp(GetDesktopWindow(), sBS, HH_DISPLAY_TOC, NULL);
  }
}

void CParentDlg::CloseAll() // Called by one of the tabs
{
/*
  m_pCopyDlg->Close();
  m_pMinDlg->Close();
  ZDlg::OnOk();
*/
  // Change CloseAll to post message, so child dialog's call to this
  // function is completed before this dialog closes it.
  // (Works with closing from here, but seems risky)
  if (m_bMinIsActive) m_pMinDlg->SetPaintMonitor(FALSE);
  PostMessage(m_hWnd, WMU_CLOSEALL, 0, 0);
}

void CParentDlg::CloseAllReally() // In response to WMU_CLOSEALL
{
//  KillTimer(m_hWnd, m_uTimerIdCheckMenus);
  m_pCopyDlg->Close();
  m_pMinDlg->Close();
  ZDlg::OnOk();
}

void CParentDlg::OnCancel() // Clicked X button at top of dialog
{
  CloseAllReally();
}

void CParentDlg::OnOk()
{
	// Do nothing, just trap Enter
	//ZDlg::OnOk();
}

//void CParentDlg::OnWmPaint()
//{
//  HDC hdc = GetDC(m_hWnd);
//  HDC image_dc = CreateCompatibleDC(hdc);
//  SelectObject(image_dc, m_hnMinImgStars);
//
//  BOOL bRet = TransparentBlt(
//                  hdc,        // handle to destination DC
//                  m_rcStarsFrame.left,  // x-coord of destination upper-left corner
//                  m_rcStarsFrame.top,   // y-coord of destination upper-left corner
//                  162,  // width of destination rectangle  <== Set height/width of rect to
//                  18,   // height of destination rectangle     same as image for OnWmPaint
//                  image_dc,         // handle to source DC
//                  0,    // x-coord of source upper-left corner
//                  0,    // y-coord of source upper-left corner
//                  162,  // width of source rectangle   <== Same dimensions as destination
//                  18,   // height of source rectangle
//                  //0xFF0000  // color to make transparent
//                  RGB(255, 0, 0)  // color to make transparent
//              );
//
//  DeleteDC(image_dc); // Won't paint on subsequent calls without this
//}

//void CParentDlg::ValidateStarsRect()
//{
//  ValidateRect(m_hWnd, &m_rcStarsFrame);
//}
