// MainFrm.cpp : implementation of the CMainFrame class // #include "stdafx.h" #include "CB32.h" #include "ComboBar.h" #include "MainFrm.h" #include "CB32Doc.h" #include "CB32View.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CMainFrame IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd) BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_MESSAGE(MYWM_NOTIFYICON, On_MYWM_NOTIFYICON) //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ON_WM_CLOSE() ON_COMMAND(ID_VIEW_STATUS_BAR, OnViewStatusBar) ON_COMMAND(ID_EDIT_FIND_COMBO, OnEditFindCombo) ON_WM_NCPAINT() ON_WM_NCACTIVATE() ON_WM_SYSCOLORCHANGE() ON_MESSAGE(WM_SETTEXT, OnSetText) ON_MESSAGE(WM_SETTINGCHANGE, OnSettingChange) ON_COMMAND(ID_VIEW_WNDPOS, OnViewWndpos) ON_WM_SYSCOMMAND() ON_COMMAND(ID_TRAY_SHOW, OnTrayShow) ON_COMMAND(ID_TRAY_EXIT, OnTrayExit) ON_WM_DESTROY() ON_COMMAND(ID_VIEW_FLATBAR, OnViewFlatbar) ON_UPDATE_COMMAND_UI(ID_VIEW_FLATBAR, OnUpdateViewFlatbar) //}}AFX_MSG_MAP ON_UPDATE_COMMAND_UI(ID_VIEW_STATUS_BAR, OnUpdateViewStatusBar) ON_UPDATE_COMMAND_UI(ID_INDICATOR_CLOCK, OnUpdateClock) END_MESSAGE_MAP() // toolbar buttons - IDs are command buttons static UINT BASED_CODE buttons[] = { // same order as in the bitmap 'toolbar.bmp' ID_FILE_NEW, ID_FILE_OPEN, ID_FILE_SAVE, ID_SEPARATOR, ID_ENTRY_ADD, ID_ENTRY_EDIT, ID_ENTRY_DELETE, ID_ENTRY_COPY, ID_SEPARATOR, ID_SEPARATOR, //(10) CComboBox location in the toolbar ID_EDIT_FIND, ID_SEPARATOR, ID_TBAR_DIAL, ID_TBAR_EMAIL, ID_TBAR_WEB, ID_APP_PREFS, ID_SEPARATOR, ID_HELP_INDEX, }; static UINT indicators[] = { ID_SEPARATOR, // status line indicator ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL, ID_INDICATOR_CLOCK, }; ///////////////////////////////////////////////////////////////////////////// // CMainFrame construction/destruction CMainFrame::CMainFrame() { m_bActive = -1; // invalid // init tray icon tracker m_inTray = FALSE; } CMainFrame::~CMainFrame() { } ///////////////////////////////////////////////////////////////////////////// // Helpers for saving/restoring window state BOOL CMainFrame::ReadWindowPlacement(LPWINDOWPLACEMENT pwp) { CString strBuffer = theApp.GetProfileString(_T("Preferences"), _T("WindowPos")); if (strBuffer.IsEmpty()) return FALSE; WINDOWPLACEMENT wp; int nRead = _stscanf(strBuffer, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"), &wp.flags, &wp.showCmd, &wp.ptMinPosition.x, &wp.ptMinPosition.y, &wp.ptMaxPosition.x, &wp.ptMaxPosition.y, &wp.rcNormalPosition.left, &wp.rcNormalPosition.top, &wp.rcNormalPosition.right, &wp.rcNormalPosition.bottom); if (nRead != 10) return FALSE; if (m_inTray) wp.showCmd = SW_HIDE; wp.length = sizeof wp; *pwp = wp; return TRUE; } void CMainFrame::WriteWindowPlacement(LPWINDOWPLACEMENT pwp) { TCHAR szBuffer[sizeof("-32767")*8 + sizeof("65535")*2]; wsprintf(szBuffer, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"), pwp->flags, pwp->showCmd, pwp->ptMinPosition.x, pwp->ptMinPosition.y, pwp->ptMaxPosition.x, pwp->ptMaxPosition.y, pwp->rcNormalPosition.left, pwp->rcNormalPosition.top, pwp->rcNormalPosition.right, pwp->rcNormalPosition.bottom); theApp.WriteProfileString(_T("Preferences"), _T("WindowPos"), szBuffer); } void CMainFrame::SaveWndSize() { WINDOWPLACEMENT wp; wp.length = sizeof wp; if (GetWindowPlacement(&wp)) { wp.flags = 0; if (IsZoomed()) wp.flags |= WPF_RESTORETOMAXIMIZED; if (!IsIconic()) WriteWindowPlacement(&wp); } } ///////////////////////////////////////////////////////////////////////////// // Create main window with toolbar, etc int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; if (theApp.GetProfileInt(_T("Preferences"),_T("StartMinimized"),0)) { TrayMessage(NIM_ADD,IDR_MAINFRAME, AfxGetApp()->LoadIcon(IDR_MAINFRAME), m_strTitle + " " + GetDocTitle()); m_inTray = TRUE; } if (theApp.GetProfileInt(_T("Preferences"),_T("RememberWin"),1)) { WINDOWPLACEMENT wp; if (ReadWindowPlacement(&wp)) SetWindowPlacement(&wp); } if (!m_wndToolBar.Create(this) || !m_wndToolBar.LoadBitmap(IDR_MAINFRAME) || !m_wndToolBar.SetButtons(buttons, sizeof(buttons)/sizeof(UINT))) { TRACE0("Failed to create toolbar\n"); return -1; // fail to create } if (!CreateComboBox()) { TRACE0("Failed to create combobox in toolbar\n"); return -1; // fail to create } // TODO: Remove this if you don't want tool tips or a resizeable toolbar m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); // TODO: Delete these three lines if you don't want the toolbar to // be dockable m_wndToolBar.SetWindowText(_T("ContactBook ToolBar")); m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); m_wndToolBar.SetFlatLook(theApp.GetProfileInt(_T("Preferences"),_T("Flatbar"),1)); if (!m_wndStatusBar.Create(this, WS_CHILD | WS_VISIBLE | CBRS_BOTTOM , AFX_IDW_STATUS_BAR) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))) { TRACE0("Failed to create status bar\n"); return -1; // fail to create } // create the timer to update the status bar clock if(!SetTimer(TIMER_ID, 2000, &CMainFrame::UpdateTime)) return -1; CMainFrame::UpdateTime(m_hWnd, 0, 0, 0); // update the time now return 0; } BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CFrameWnd::PreCreateWindow(cs); } void CMainFrame::OnClose() { KillTimer(TIMER_ID); if (theApp.GetProfileInt(_T("Preferences"),_T("RememberWin"),1)) SaveWndSize(); DeleteTrayIcon(); CFrameWnd::OnClose(); } ///////////////////////////////////////////////////////////////////////////// // CMainFrame diagnostics #ifdef _DEBUG void CMainFrame::AssertValid() const { CFrameWnd::AssertValid(); } void CMainFrame::Dump(CDumpContext& dc) const { CFrameWnd::Dump(dc); } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CMainFrame message handlers // Private MFC function only sets the title if it's different // extern void AFXAPI AfxSetWindowText(HWND, LPCTSTR); ////////////////// // Override to change title--app name first, then doc name void CMainFrame::OnUpdateFrameTitle(BOOL bAddToTitle) { AfxSetWindowText(m_hWnd, m_strTitle + " " + GetDocTitle()); } ////////////////// // Get doc title: I use full path name or "untitled" CString CMainFrame::GetDocTitle() { CString s = ""; CDocument* pDoc = GetActiveDocument(); if (pDoc != NULL) s = pDoc->GetPathName(); return s.IsEmpty() ? "- [Untitled]" : "- ["+s+"]"; } //////////////// // Mini-class to get the caption rectangle of a window in window coords. // This is the area of the title bar inside the window frame, // including the icon but not the min/max/close buttons. class CCaptionRect : public CRect { public: CCaptionRect(const CWnd& wnd); // use reference to deny NULL ptr }; ///////////////// // Paint non-client area: First let Windows paint, then I'll paint over it. // // I use the relatively obscure and poorly documented update region feature // to prevent Windows from painting the title text. This is to get totally // flicker-free painting when the user sizes the window. Note that Windows // sometimes uses WPARAM=1. void CMainFrame::OnNcPaint() { MSG& msg = AfxGetThreadState()->m_lastSentMsg; HRGN hRgn = (HRGN)msg.wParam; CCaptionRect rc(*this); // caption rectangle in window coords CRect rcWin; // window rect GetWindowRect(&rcWin); // .. get window rect rc += rcWin.TopLeft(); // convert caption rect to screen coords // Don't bother painting if the caption doesn't lie within the region. if (msg.wParam > 1 && !::RectInRegion((HRGN)msg.wParam, &rc)) { CFrameWnd::OnNcPaint(); // just do default thing return; // and quit } // Exclude caption from update region HRGN hRgnCaption = ::CreateRectRgnIndirect(&rc); HRGN hRgnNew = ::CreateRectRgnIndirect(&rc); if (msg.wParam > 1) { // wParam is a valid region: subtract caption from it ::CombineRgn(hRgnNew, hRgn, hRgnCaption, RGN_DIFF); } else { // wParam is not a valid region: create one that's the whole // window minus the caption bar HRGN hRgnAll = ::CreateRectRgnIndirect(&rcWin); CombineRgn(hRgnNew, hRgnAll, hRgnCaption, RGN_DIFF); DeleteObject(hRgnAll); } // Call Windows to do WM_NCPAINT with altered update region WPARAM savewp = msg.wParam; // save original wParam msg.wParam = (WPARAM)hRgnNew; // set new region for DefWindowProc CFrameWnd::OnNcPaint(); // call it DeleteObject(hRgnCaption); // clean up DeleteObject(hRgnNew); // ... msg.wParam = savewp; // restore original wParam PaintCaption(); // Now paint my special caption } ////////////////// // Non-client area (de)activated: paint it BOOL CMainFrame::OnNcActivate(BOOL bActive) { // Mimic MFC kludge to stay active if WF_STAYACTIVE bit is on if (m_nFlags & WF_STAYACTIVE) bActive = TRUE; if (!IsWindowEnabled()) // but not if disabled bActive = FALSE; if (bActive==m_bActive) return TRUE; // nothing to do // Turn WS_VISIBLE off before callinf DefWindowProc, // so DefWindowProc won't paint and thereby cause flicker. DWORD dwStyle = GetStyle(); if (dwStyle & WS_VISIBLE) SetWindowLong(m_hWnd, GWL_STYLE, (dwStyle & ~ WS_VISIBLE)); // do not call the base class because it will call Default() // and we may have changed bActive. DefWindowProc(WM_NCACTIVATE, bActive, 0L); if (dwStyle & WS_VISIBLE) SetWindowLong(m_hWnd, GWL_STYLE, dwStyle); // At this point, nothing has happened (since WS_VISIBLE was off). // Now it's time to paint. m_bActive = bActive; // update state SendMessage(WM_NCPAINT); // paint non-client area (frame too) return TRUE; // done OK } ////////////////// // Someone called SetWindowText: paint new text. LRESULT CMainFrame::OnSetText(WPARAM wParam, LPARAM lParam) { // Turn WS_VISIBLE style off before calling Windows to // set the text, then turn it back on again after. DWORD dwStyle = GetStyle(); if (dwStyle & WS_VISIBLE) SetWindowLong(m_hWnd, GWL_STYLE, dwStyle & ~ WS_VISIBLE); LRESULT lRet = DefWindowProc(WM_SETTEXT, wParam, lParam); if (dwStyle & WS_VISIBLE) SetWindowLong(m_hWnd, GWL_STYLE, dwStyle); m_rcCaption.SetRectEmpty(); // invalidate caption SendMessage(WM_NCPAINT); // paint non-client area (frame too) PaintCaption(); // ..and paint it return lRet; } ////////////////// // User changed system settings (possibly font) or colors. // Invalidate everything to generate anew. LRESULT CMainFrame::OnSettingChange(WPARAM, LPARAM) { OnSysColorChange(); return 0; } void CMainFrame::OnSysColorChange() { m_fontCaption.DeleteObject(); // generate new fonts m_fontAcme.DeleteObject(); // ... m_rcCaption.SetRectEmpty(); // will force new bitmap to be created } ////////////////// // Paint custom caption. Flag tells whether active or not. // Just blast the bitmap to the title bar, but not iif minimized (iconic). void CMainFrame::PaintCaption(BOOL bActive) { if (!IsIconic()) { CWindowDC dcWin(this); CDC dc; dc.CreateCompatibleDC(&dcWin); CBitmap* pOldBitmap = dc.SelectObject(GetCaptionBitmap(bActive)); const CRect& rc = m_rcCaption; dcWin.BitBlt(rc.left,rc.top,rc.Width(),rc.Height(),&dc,0,0,SRCCOPY); } } ////////////////// // Helper function to compute the luminosity for an RGB color. // Measures how bright the color is. I use this so I can draw the caption // text using the user's chosen color, unless it's too dark. See MSDN for // definition of luminosity and how to compute it. static int GetLuminosity(COLORREF color) { #define HLSMAX 240 // This is what Display Properties uses #define RGBMAX 255 // max r/g/b value is 255 int r = GetRValue(color); int g = GetGValue(color); int b = GetBValue(color); int rgbMax = max( max(r,g), b); int rgbMin = min( min(r,g), b); return (((rgbMax+rgbMin) * HLSMAX) + RGBMAX ) / (2*RGBMAX); } #define COLOR_WHITE RGB(255,255,255) #define COLOR_BLACK RGB(0,0,0) #define NCOLORSHADES 64 // this many shades in gradient ////////////////// // Helper to paint rectangle with a color. static void PaintRect(CDC& dc, int x, int y, int w, int h, COLORREF color) { CBrush brush(color); CBrush* pOldBrush = dc.SelectObject(&brush); dc.PatBlt(x, y, w, h, PATCOPY); dc.SelectObject(pOldBrush); } ////////////////// // Get the appropriate bitmap whether active/inactive. If the size of // the caption rect has changed since the last time it was generated, // generate it again. // // This is the function that actually does the shading. It creates a // bitmap that's used to paint the caption. It looks horrible, but it's // just a lot of bit-twiddling GDI stuff. CBitmap* CMainFrame::GetCaptionBitmap(BOOL bActive) { CBitmap& bm = m_bmCaption[bActive!=0]; // one of two bitmaps CCaptionRect rcCap(*this); // caption rectangle in win coords if (rcCap != m_rcCaption) { // if changed since last time: m_bmCaption[0].DeleteObject(); // delete both bitmaps, m_bmCaption[1].DeleteObject(); // ..they are bad m_rcCaption = rcCap; // note for next time } if (bm.m_hObject) return &bm; // already have bitmap; return it. // Either the size changed or the bitmap was never created. Create it. rcCap -= rcCap.TopLeft(); // convert caption rectangle origin to (0,0) int w = rcCap.Width(); int h = rcCap.Height(); int cxIcon = GetSystemMetrics(SM_CXSIZE); int cyIcon = GetSystemMetrics(SM_CYSIZE); // Create bitmap same size as caption area and select into memory DC CWindowDC dcWin(this); CDC dc; dc.CreateCompatibleDC(&dcWin); bm.DeleteObject(); bm.CreateCompatibleBitmap(&dcWin, w, h); CBitmap* pOldBitmap = dc.SelectObject(&bm); // Paint shaded background. Note all painting is into memory DC, // not window, so there's no flicker. if (!bActive) { // Inactive caption: don't do shading, just fill w/bg color PaintRect(dc, 0, 0, w, h, GetSysColor(COLOR_INACTIVECAPTION)); } else { // Active caption: do shading COLORREF clrBG = GetSysColor(COLOR_ACTIVECAPTION); // background color int r = GetRValue(clrBG); // red.. int g = GetGValue(clrBG); // ..green int b = GetBValue(clrBG); // ..blue color vals int x = 5*rcCap.right/6; // start 5/6 of the way right int w = x - rcCap.left; // width of area to shade int xDelta= max(w/NCOLORSHADES,1); // width of one shade band // Paint far right 1/6 of caption the background color PaintRect(dc, x, 0, rcCap.right-x, h, clrBG); // Compute new color brush for each band from x to x + xDelta. // Excel uses a linear algorithm from black to normal, i.e. // // color = CaptionColor * r // // where r is the ratio x/w, which ranges from 0 (x=0, left) // to 1 (x=w, right). This results in a mostly black title bar, // since we humans don't distinguish dark colors as well as light // ones. So instead, I use the formula // // color = CaptionColor * [1-(1-r)^2] // // which still equals black when r=0 and CaptionColor when r=1, // but spends more time near CaptionColor. For example, when r=.5, // the multiplier is [1-(1-.5)^2] = .75, closer to 1 than .5. // I leave the algebra to the reader to verify that the above formula // is equivalent to // // color = CaptionColor - (CaptionColor*(w-x)*(w-x))/(w*w) // // The computation looks horrendous, but it's only done once each // time the caption changes size; thereafter BitBlt'ed to the screen. // while (x > xDelta) { // paint bands right to left x -= xDelta; // next band int wmx2 = (w-x)*(w-x); // w minus x squared int w2 = w*w; // w squared PaintRect(dc, x, 0, xDelta, h, RGB(r-(r*wmx2)/w2, g-(g*wmx2)/w2, b-(b*wmx2)/w2)); } PaintRect(dc,0,0,x,h,COLOR_BLACK); // whatever's left ==> black } // Draw icon and caption buttons. // These are all drawn inside a rectangle of dimensions SM_C[XY]SIZE. CRect rcButn(0,0,cxIcon,cyIcon); // Within the basic button rectangle, Windows 95 uses a 1 or 2 pixel border // Icon has 2 pixel border on left, 1 pixel on top/bottom, 0 right rcButn.DeflateRect(0,1); rcButn.left += 2; DrawIconEx(dc.m_hDC, rcButn.left, rcButn.top, (HICON)GetClassLong(m_hWnd, GCL_HICONSM), rcButn.Width(), rcButn.Height(), 0, NULL, DI_NORMAL); // Close box has a 2 pixel border on all sides but left, which is zero rcButn.DeflateRect(0,1); // shrink top/bottom 1 more rcButn += CPoint(w-cxIcon-2,0); // move right dc.DrawFrameControl(&rcButn, DFC_CAPTION, DFCS_CAPTIONCLOSE); DWORD dwStyle = GetStyle(); // Max/restore button is like close box; just shift rectangle left if (dwStyle & WS_MAXIMIZEBOX) { rcButn -= CPoint(cxIcon,0); dc.DrawFrameControl(&rcButn, DFC_CAPTION, IsZoomed() ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX); } // Minimize button has 2 pixel border on all sides but right. if (dwStyle & WS_MINIMIZEBOX) { rcButn -= CPoint(cxIcon-2,0); dc.DrawFrameControl(&rcButn, DFC_CAPTION, DFCS_CAPTIONMIN); } // Now draw text. First Create fonts if needed if (!m_fontCaption.m_hObject) CreateFonts(); // Paint "ACME TEXT" using ACME font, always white //CString s = m_strTitle + " "; // app title CRect rcText = rcCap; // caption rectangle rcText.left += cxIcon+2; // start after icon rcText.right = rcButn.left-2; // don't draw past buttons dc.SetBkMode(TRANSPARENT); // draw on top of our shading //dc.SetTextColor(COLOR_WHITE); // always white CFont* pOldFont = dc.SelectObject(&m_fontAcme); //dc.DrawText(s, &rcText, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS); // Now paint window title (caption) //rcText.left += dc.GetTextExtent(s).cx; // move past "ACME EDIT " if (rcText.right > rcText.left) { // if still room: COLORREF clrText; // text color if (bActive) { // Excel always uses white for title color, but I use the user's // selected color--unless it's too dark, then I use white. clrText = GetSysColor(COLOR_CAPTIONTEXT); if (GetLuminosity(clrText) < 90) // good from trial & error clrText = COLOR_WHITE; } else clrText = GetSysColor(COLOR_INACTIVECAPTIONTEXT); // Paint the text. Use DT_END_ELLIPSIS to draw ellipsis if text // won't fit. Win32 sure is friendly! COLORREF clrColor; clrColor = dc.SetTextColor(clrText); dc.SelectObject(&m_fontCaption); dc.DrawText(m_strTitle + " " + GetDocTitle(), &rcText, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS); dc.SetTextColor(clrColor); } // Restore DC dc.SelectObject(pOldFont); dc.SelectObject(pOldBitmap); return &bm; // return bitmap to caller--whew! } ////////////////// // Helper function to build the fonts I need. // void CMainFrame::CreateFonts() { // Get current system caption font, just to get its size NONCLIENTMETRICS ncm; ncm.cbSize = sizeof(ncm); VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0)); m_fontCaption.CreateFontIndirect(&ncm.lfCaptionFont); // Create "ACME" font same size as caption font, but use Book Antiqua m_fontAcme.CreatePointFont(80, _T("MS Sans Serif")); // 12 pt for now LOGFONT lf; m_fontAcme.GetLogFont(&lf); // get font info m_fontAcme.DeleteObject(); // I don't really want 12 pt lf.lfWeight|=FW_BOLD; // make bold lf.lfHeight = ncm.lfCaptionFont.lfHeight; // same height as caption font m_fontAcme.CreateFontIndirect(&lf); // create font } ////////////////// // CCaptionRect: Constructor conputes caption rectangle in window coords. CCaptionRect::CCaptionRect(const CWnd& wnd) { // Get size of frame around window DWORD dwStyle = wnd.GetStyle(); CSize szFrame = (dwStyle & WS_THICKFRAME) ? CSize(GetSystemMetrics(SM_CXSIZEFRAME), GetSystemMetrics(SM_CYSIZEFRAME)) : CSize(GetSystemMetrics(SM_CXFIXEDFRAME), GetSystemMetrics(SM_CYFIXEDFRAME)); int cxIcon = GetSystemMetrics(SM_CXSIZE); // width of caption icon/button // Compute rectangle wnd.GetWindowRect(this); // window rect in screen coords *this -= CPoint(left, top); // shift origin to (0,0) left += szFrame.cx; // frame right -= szFrame.cx; // frame top += szFrame.cy; // top = end of frame bottom = top + GetSystemMetrics(SM_CYCAPTION) // height of caption - GetSystemMetrics(SM_CYBORDER); // minus gray shadow border } /////////////////////////////////////// // time/combobar int CMainFrame::CreateComboBox() { CRect rect, comboRect; m_wndToolBar.SetButtonInfo(9, IDW_COMBO, TBBS_SEPARATOR, COMBO_WIDTH); m_wndToolBar.GetItemRect(9, &rect); rect.bottom += COMBO_HEIGHT; if (!m_wndToolBar.m_toolBarCombo.Create(CBS_DROPDOWN|WS_VISIBLE|WS_TABSTOP|CBS_AUTOHSCROLL, rect, &m_wndToolBar, IDW_COMBO)) { return FALSE; } // center combo box edit control vertically within tool bar rect.bottom -= COMBO_HEIGHT; m_wndToolBar.m_toolBarCombo.GetWindowRect(&comboRect); m_wndToolBar.m_toolBarCombo.ScreenToClient(&comboRect); m_wndToolBar.m_toolBarCombo.SetWindowPos(&m_wndToolBar.m_toolBarCombo, rect.left, rect.top + (rect.Height() - comboRect.Height())/2+1, 0, 0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE); return TRUE; } void CMainFrame::OnViewStatusBar() { CWnd* pStatusBar; if (pStatusBar = GetDescendantWindow(AFX_IDW_STATUS_BAR)) { pStatusBar->ShowWindow(!(pStatusBar->GetStyle() & WS_VISIBLE)); RecalcLayout(); } } void CMainFrame::OnUpdateViewStatusBar(CCmdUI* pCmdUI) { CWnd* pStatusBar; if (pStatusBar = GetDescendantWindow(AFX_IDW_STATUS_BAR)) pCmdUI->SetCheck((pStatusBar->GetStyle() & WS_VISIBLE)); } void CMainFrame::OnViewWndpos() { SaveWndSize(); AfxMessageBox(IDS_WINDSAVE, MB_ICONINFORMATION); } void CMainFrame::OnUpdateClock(CCmdUI* pCmdUI) { pCmdUI->Enable(TRUE); } void CMainFrame::OnEditFindCombo() { m_wndToolBar.m_toolBarCombo.SetFocus(); } void CALLBACK EXPORT CMainFrame::UpdateTime(HWND hWnd,UINT nMsg, UINT nIDEvent, DWORD dwTime) { CString time; BOOL bPM = TRUE; SYSTEMTIME tm; CMainFrame* pFrame = (CMainFrame*)CWnd::FromHandle(hWnd); CStatusBar* pStatusBar = (CStatusBar*) pFrame->GetDescendantWindow(AFX_IDW_STATUS_BAR); if (pStatusBar == NULL) return; GetLocalTime(&tm); if (tm.wHour >= 0 && tm.wHour < 12) bPM = FALSE; // convert 24 hour clock if (tm.wHour > 12) // 13 - 23 tm.wHour -= 12; else if (tm.wHour == 0) // midnight tm.wHour = 12; time.Format(_T(" %d:%02.2d %s "), tm.wHour, tm.wMinute, ((bPM) ? _T("PM"):_T("AM"))); // get current pane font information and update time UINT nID, nStyle; int nWidth, nIndex = pStatusBar->CommandToIndex(ID_INDICATOR_CLOCK); CClientDC dc(pStatusBar); CFont* pOldFont = dc.SelectObject(pStatusBar->GetFont()); CSize szExtent = dc.GetTextExtent(time, time.GetLength()); dc.SelectObject(pOldFont); pStatusBar->GetPaneInfo(nIndex, nID, nStyle, nWidth); pStatusBar->SetPaneInfo(nIndex, nID, nStyle, szExtent.cx); pStatusBar->SetPaneText(nIndex, time); } void CMainFrame::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID == SC_MINIMIZE) && theApp.GetProfileInt(_T("Preferences"),_T("RememberTray"),1)) { TrayMessage(NIM_ADD,IDR_MAINFRAME, AfxGetApp()->LoadIcon(IDR_MAINFRAME), m_strTitle + " " + GetDocTitle()); m_inTray = TRUE; ShowWindow(SW_HIDE); } else CFrameWnd::OnSysCommand(nID, lParam); } BOOL CMainFrame::TrayMessage(DWORD dwMessage, UINT uID, HICON hIcon, CString pszTip) { BOOL res; tnd.cbSize = sizeof(NOTIFYICONDATA); tnd.hWnd = m_hWnd; tnd.uID = uID; tnd.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP; tnd.uCallbackMessage = MYWM_NOTIFYICON; tnd.hIcon = hIcon; if (!pszTip.IsEmpty()) { lstrcpyn(tnd.szTip, pszTip, sizeof(tnd.szTip)); } else { tnd.szTip[0] = '\0'; } res = Shell_NotifyIcon(dwMessage, &tnd); if (hIcon) DestroyIcon(hIcon); return res; } LONG CMainFrame::On_MYWM_NOTIFYICON(UINT wParam, LONG lParam) { UINT uMouseMsg; uMouseMsg = (UINT) lParam; switch (uMouseMsg) { case WM_LBUTTONUP: { ShowWindow(SW_SHOW); DeleteTrayIcon(); break; } case WM_RBUTTONUP: { CMenu menu; CMenu* pSubMenu = NULL; if (menu.LoadMenu(IDR_TRAYMENU)) pSubMenu = menu.GetSubMenu(0); if (pSubMenu) { ::SetMenuDefaultItem(pSubMenu->m_hMenu, 0, TRUE); CPoint ptCur; ::GetCursorPos(&ptCur); ::SetForegroundWindow(tnd.hWnd); ::TrackPopupMenu(pSubMenu->m_hMenu, 0, ptCur.x, ptCur.y, 0, tnd.hWnd, NULL); } } } return 0; } void CMainFrame::OnTrayShow() { ShowWindow(SW_SHOW); DeleteTrayIcon(); } void CMainFrame::OnTrayExit() { DeleteTrayIcon(); theApp.HideApplication(); CDocument* pDoc = GetActiveDocument(); if (pDoc != NULL) pDoc->SaveModified(); theApp.CloseAllDocuments(FALSE); PostQuitMessage(0); } void CMainFrame::DeleteTrayIcon() { if (m_inTray) { TrayMessage(NIM_DELETE,IDR_MAINFRAME,0,""); m_inTray = FALSE; } } void CMainFrame::OnDestroy() { CFrameWnd::OnDestroy(); DeleteTrayIcon(); } void CMainFrame::OnViewFlatbar() { m_wndToolBar.SetFlatLook(!m_wndToolBar.IsFlatLook()); theApp.WriteProfileInt(_T("Preferences"),_T("Flatbar"), m_wndToolBar.IsFlatLook()); } void CMainFrame::OnUpdateViewFlatbar(CCmdUI* pCmdUI) { pCmdUI->SetCheck(m_wndToolBar.IsFlatLook()); }