226 lines
5.5 KiB
C++
226 lines
5.5 KiB
C++
// Hyperbar.cpp : implementation file
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "OXHyperbar.h"
|
|
|
|
#include "OXHyperbarOverlay.h"
|
|
#include "OXHyperBarRender.h"
|
|
|
|
#include <Winuser.h>
|
|
|
|
#include <algorithm>
|
|
|
|
// COXHyperBar
|
|
|
|
// These constants currently define the size of the overlay window that is generated.
|
|
//The margin specified is applied in both directions, so if OffsetY is 10, then the
|
|
// window is 10 pixels above and below the toolbar itself.
|
|
//
|
|
// A better solution may be to have the window resize itself as the icons resize.
|
|
|
|
int COXHyperBar::OffsetY = 140;
|
|
std::vector<COXHyperBar*> COXHyperBar::m_AllBars;
|
|
|
|
IMPLEMENT_DYNAMIC(COXHyperBar, CToolBar)
|
|
|
|
using std::vector;
|
|
using std::iterator;
|
|
|
|
COXHyperBar::COXHyperBar()
|
|
{
|
|
m_wndInvisible = NULL;
|
|
m_pRender = new COXHyperBarRender(this);
|
|
m_bHasRedrawn = true;
|
|
COXHyperBar::m_AllBars.push_back(this);
|
|
m_backColor = RGB(0, 255, 255);
|
|
}
|
|
|
|
COXHyperBar::~COXHyperBar()
|
|
{
|
|
if (m_wndInvisible)
|
|
{
|
|
m_wndInvisible->DestroyWindow();
|
|
delete m_wndInvisible;
|
|
m_wndInvisible = NULL;
|
|
}
|
|
|
|
if (m_pRender)
|
|
{
|
|
delete m_pRender;
|
|
m_pRender = NULL;
|
|
}
|
|
|
|
std::vector<COXHyperBar*>::iterator it = std::find(m_AllBars.begin(), m_AllBars.end(), this);
|
|
|
|
if (it != m_AllBars.end())
|
|
COXHyperBar::m_AllBars.erase(it);
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(COXHyperBar, CToolBar)
|
|
//{{AFX_MSG_MAP(COXHyperBar)
|
|
ON_WM_PAINT()
|
|
ON_WM_CREATE()
|
|
ON_WM_MOUSEMOVE()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
// COXHyperBar message handlers
|
|
|
|
void COXHyperBar::OnPaint()
|
|
{
|
|
if (!m_wndInvisible->IsWindowVisible())
|
|
{
|
|
CPaintDC dc(this); // device context for painting
|
|
RECT rc;
|
|
this->GetClientRect(&rc);
|
|
|
|
if (m_pRender)
|
|
m_pRender->RenderToolbar(&dc, &rc, m_sizeImage);
|
|
}
|
|
}
|
|
|
|
// To avoid flicker
|
|
BOOL COXHyperBar::OnEraseBkgnd(CDC* /* pDC */)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
int COXHyperBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
|
{
|
|
if (CToolBar::OnCreate(lpCreateStruct) == -1)
|
|
return -1;
|
|
|
|
// Create invisible window
|
|
if (!m_wndInvisible)
|
|
{
|
|
m_wndInvisible = new COXHyperBarOverlay(this, m_pRender, m_sizeImage);
|
|
|
|
RECT rc;
|
|
GetWindowRect(&rc);
|
|
InflateRect(&rc, 0, OffsetY * 2);
|
|
OffsetRect(&rc, 0, -OffsetY);
|
|
|
|
LPCTSTR pstrOwnerClass = AfxRegisterWndClass(0);
|
|
if (!m_wndInvisible->CreateEx(WS_EX_TOOLWINDOW, pstrOwnerClass, _T(""), WS_POPUP | WS_VISIBLE,
|
|
rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
|
|
m_hWnd, 0))
|
|
return FALSE;
|
|
|
|
m_wndInvisible->ShowWindow(SW_HIDE);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// This function is called when our window is about to be shown. It moves the invisible window into place,
|
|
// grabs a shot of the screen area that will be under it, and passes it through.
|
|
void COXHyperBar::RepositionInvisibleWindow()
|
|
{
|
|
RECT rc;
|
|
GetWindowRect(&rc);
|
|
InflateRect(&rc, 0, OffsetY);
|
|
|
|
RECT rcClient;
|
|
GetClientRect(&rcClient);
|
|
ClientToScreen(&rcClient);
|
|
rc.left = rcClient.left;
|
|
rc.right = rcClient.right;
|
|
|
|
// Capture screenshot
|
|
CDC dcScreen;
|
|
dcScreen.Attach(::GetDC(NULL));
|
|
CBitmap * bitmap = new CBitmap();
|
|
bitmap->CreateCompatibleBitmap(&dcScreen, rc.right - rc.left, rc.bottom - rc.top);
|
|
CDC dc;
|
|
dc.CreateCompatibleDC(&dcScreen);
|
|
CBitmap * pOld = dc.SelectObject(bitmap);
|
|
|
|
RECT scrn = rc;
|
|
ClientToScreen(&scrn);
|
|
dc.BitBlt(0, 0, rc.right - rc.left, rc.bottom - rc.top, &dcScreen, rc.left, rc.top, SRCCOPY);
|
|
dc.SelectObject(pOld);
|
|
|
|
m_wndInvisible->SetWindowPos(NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER);
|
|
m_wndInvisible->SetBitmap(bitmap);
|
|
}
|
|
|
|
void COXHyperBar::OnMouseMove(UINT /* nFlags */, CPoint point)
|
|
{
|
|
if(AfxGetMainWnd()->GetActiveWindow())
|
|
// Changed this for VC6 support with no PSDK
|
|
// WINDOWINFO in;
|
|
// AfxGetMainWnd()->GetWindowInfo(&in);
|
|
// if (in.dwWindowStatus == WS_ACTIVECAPTION)
|
|
{
|
|
RECT rcClient;
|
|
GetClientRect(&rcClient);
|
|
|
|
if (PtInRect(&rcClient, point))
|
|
{
|
|
if(!HasVisibleOverlay())
|
|
{
|
|
RepositionInvisibleWindow();
|
|
// Make sure the main window remains active ( in truth, this message generally arrives too late )
|
|
AfxGetMainWnd()->SendMessage(WM_NCACTIVATE, TRUE);
|
|
m_wndInvisible->ShowWindow(SW_SHOW);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// This method is used by the mousemove, to make sure no other bar is visible before showing this one.
|
|
// The m_bHasRedrawn bool is set to true when the unexpanded toolbar has been rendered, all this is needed
|
|
// because we can call Invalidate(), but cannot tell without a flag when the paint message has been processed,
|
|
// returning our window to the correct state for a new window to be drawn.
|
|
bool COXHyperBar::HasVisibleOverlay()
|
|
{
|
|
std::vector<COXHyperBar*>::iterator it = m_AllBars.begin();
|
|
|
|
while(it != m_AllBars.end())
|
|
{
|
|
if (!(*it)->m_bHasRedrawn)
|
|
return true;
|
|
|
|
++it;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Used to expose setting the back col where no class has been changed.
|
|
void COXHyperBar::SetBackColor(COLORREF col)
|
|
{
|
|
m_backColor = col;
|
|
|
|
if (m_wndInvisible->IsWindowVisible())
|
|
{
|
|
m_wndInvisible->Invalidate();
|
|
}
|
|
else
|
|
{
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
// The default render background just fills with a solid color.
|
|
void COXHyperBar::RenderBackground(CDC * pDC, RECT * pRect)
|
|
{
|
|
pDC->FillSolidRect(pRect, m_backColor);
|
|
}
|
|
|
|
// This method exists as a matter of convenience, it's private and the one that takes a RECT is the one users should override.
|
|
// This method is private so it cannot be overridden, eliminating the risk of two methods that do two different things.
|
|
void COXHyperBar::RenderBackground(CDC * pDC, int left, int top, int width, int height)
|
|
{
|
|
RECT rc;
|
|
rc.left = left;
|
|
rc.top = top;
|
|
rc.bottom = height + top;
|
|
rc.right = width + left;
|
|
|
|
RenderBackground(pDC, &rc);
|
|
}
|