|
|
//-----------------------------------------------------------------------------
// File: flexcombobox.cpp
//
// Desc: Implements a combo box control similar to Windows combo box.
// CFlexComboBox is derived from CFlexWnd. It is used by the page
// for player list and genre list. When the combo box is open,
// CFlexComboBox uses a CFlexListBox for the list window.
//
// Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
//-----------------------------------------------------------------------------
#include "common.hpp"
CFlexComboBox::CFlexComboBox() : m_nTextHeight(-1), m_hWndNotify(NULL), m_rgbText(RGB(255,255,255)), m_rgbBk(RGB(0,0,0)), m_rgbSelText(RGB(0,0,255)), m_rgbSelBk(RGB(0,0,0)), m_rgbFill(RGB(0,0,255)), m_rgbLine(RGB(0,255,255)), m_dwFlags(0), m_dwListBoxFlags(0), m_bInSelMode(FALSE), m_nSBWidth(11), m_hFont(NULL), m_eCurState(FCBS_CLOSED), m_OldSel(-1) { }
CFlexComboBox::~CFlexComboBox() { }
CFlexComboBox *CreateFlexComboBox(FLEXCOMBOBOXCREATESTRUCT *pcs) { CFlexComboBox *psb = new CFlexComboBox; if (psb && psb->Create(pcs)) return psb; delete psb; return NULL; }
BOOL CFlexComboBox::Create(FLEXCOMBOBOXCREATESTRUCT *pcs) { if (this == NULL) return FALSE;
if (pcs == NULL) return FALSE;
if (pcs->dwSize != sizeof(FLEXCOMBOBOXCREATESTRUCT)) return FALSE;
m_hWndNotify = pcs->hWndNotify ? pcs->hWndNotify : pcs->hWndParent;
m_dwFlags = pcs->dwFlags; m_dwListBoxFlags = pcs->dwListBoxFlags;
SetFont(pcs->hFont); SetColors(pcs->rgbText, pcs->rgbBk, pcs->rgbSelText, pcs->rgbSelBk, pcs->rgbFill, pcs->rgbLine); m_nSBWidth = pcs->nSBWidth; m_rect = pcs->rect;
if (!CFlexWnd::Create(pcs->hWndParent, GetRect(pcs->rect), pcs->bVisible)) return FALSE;
//@@BEGIN_MSINTERNAL
// TODO: make sure that creation sends no notifications.
// all initial notifications should be sent here.
//@@END_MSINTERNAL
return TRUE; }
void CFlexComboBox::OnPaint(HDC hDC) { HDC hBDC = NULL, hODC = NULL; CBitmap *pbm = NULL;
if (!InRenderMode()) { hODC = hDC; pbm = CBitmap::Create(GetClientSize(), RGB(0,0,0), hDC); if (pbm != NULL) { hBDC = pbm->BeginPaintInto(); if (hBDC != NULL) { hDC = hBDC; } } }
InternalPaint(hDC);
if (!InRenderMode()) { if (pbm != NULL) { if (hBDC != NULL) { pbm->EndPaintInto(hBDC); pbm->Draw(hODC); } delete pbm; } } }
void CFlexComboBox::SetSel(int i) { m_ListBox.SelectAndShowSingleItem(i, TRUE); }
int CFlexComboBox::GetSel() { return m_ListBox.GetSel(); }
LPCTSTR CFlexComboBox::GetText() { return m_ListBox.GetSelText(); }
void CFlexComboBox::InternalPaint(HDC hDC) { HGDIOBJ hPen = (HGDIOBJ)CreatePen(PS_SOLID, 1, m_rgbLine); if (hPen != NULL) { HGDIOBJ hOldPen = SelectObject(hDC, hPen);
HGDIOBJ hBrush = (HGDIOBJ)CreateSolidBrush(m_rgbBk); if (hBrush != NULL) { HGDIOBJ hOldBrush = SelectObject(hDC, hBrush);
RECT rect = {0,0,0,0}; GetClientRect(&rect); Rectangle(hDC, rect.left, rect.top, rect.right, rect.bottom);
RECT arect = rect;
arect.left = arect.right - (arect.bottom - arect.top);
// If we are read-only, only draw the text in gray. No border, no arrow.
if (!GetReadOnly()) { MoveToEx(hDC, arect.left, arect.top, NULL); LineTo(hDC, arect.left, arect.bottom); }
rect.left++; rect.top++; rect.right = arect.left; rect.bottom--;
SetTextColor(hDC, m_rgbText); SetBkMode(hDC, TRANSPARENT);
LPTSTR lpText = (LPTSTR)GetText(); if (lpText) { DrawText(hDC, lpText, -1, &rect, DT_NOPREFIX); }
SelectObject(hDC, hOldBrush); DeleteObject(hBrush);
if (!GetReadOnly()) { hBrush = (HGDIOBJ)CreateSolidBrush(m_rgbFill); if (hBrush != NULL) { SelectObject(hDC, hBrush);
InflateRect(&arect, -3, -3); DrawArrow(hDC, arect, TRUE, FALSE);
SelectObject(hDC, hOldBrush); DeleteObject(hBrush); } } }
SelectObject(hDC, hOldPen); DeleteObject(hPen); } }
int CFlexComboBox::AddString(LPCTSTR str) { return m_ListBox.AddString(str); }
LRESULT CFlexComboBox::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { RECT wrect = {-1, -1, -1, -1}; POINT point = {-1, -1}; BOOL bWithin = FALSE;
switch (msg) { case WM_SIZE: Invalidate(); SetRect(); return 0;
case WM_FLEXLISTBOX: assert(lParam == (LPARAM)(LPVOID)&m_ListBox); switch (wParam) { case FLBN_FINALSEL: StateEvent(FCBSE_UPLIST); break; case FLBN_CANCEL: StateEvent(FCBSE_DOWNOFF); break; } return 0;
// make sure flexwnd doesn't do ANYTHING with our mouse messages
case WM_MOUSEMOVE: // We initialize the tooltip to current selection text if the selected text is too long to fit.
RECT rect; GetClientRect(&rect); rect.right = rect.right - (rect.bottom - rect.top); rect.left++; rect.top++; rect.bottom--; RECT ResultRect; ResultRect = rect; HDC hDC; hDC = CreateCompatibleDC(NULL); if (hDC) { LPTSTR lpText = (LPTSTR)GetText(); if (lpText) { DrawText(hDC, lpText, -1, &ResultRect, DT_NOPREFIX|DT_CALCRECT); } DeleteDC(hDC); } if (rect.right < ResultRect.right || rect.bottom < ResultRect.bottom) { CFlexWnd::s_ToolTip.SetToolTipParent(GetParent(m_hWnd)); TOOLTIPINITPARAM ttip; ttip.hWndParent = GetParent(m_hWnd); ttip.iSBWidth = 0; ttip.dwID = 0; ttip.hWndNotify = m_hWnd; ttip.tszCaption = m_ListBox.GetSelText(); CFlexToolTip::UpdateToolTipParam(ttip); } Notify(FCBN_MOUSEOVER);
case WM_LBUTTONUP: case WM_LBUTTONDOWN: case WM_RBUTTONUP: case WM_RBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_RBUTTONDBLCLK: if (msg == WM_LBUTTONDOWN) { HWND hWndParent; hWndParent = GetParent(hWnd); SendMessage(hWndParent, WM_UNHIGHLIGHT, 0, 0); // Send click message to page to unhighlight callout
} GetClientRect(&wrect); point.x = int(LOWORD(lParam)); point.y = int(HIWORD(lParam)); bWithin = PtInRect(&wrect, point); break; case WM_TIMER: case WM_CAPTURECHANGED: break; default: return CFlexWnd::WndProc(hWnd, msg, wParam, lParam); }
switch (msg) { case WM_LBUTTONDOWN: if (!GetReadOnly()) StateEvent(bWithin ? FCBSE_DOWN : FCBSE_DOWNOFF); break;
case WM_LBUTTONUP: if (!GetReadOnly()) StateEvent(bWithin ? FCBSE_UPBOX : FCBSE_UPOFF); break; }
return 0; }
RECT CFlexComboBox::GetListBoxRect() { HWND hParent = GetParent(m_hWnd); RECT rect; GetClientRect(&rect); BOOL bRet = ClientToScreen(m_hWnd, &rect); BOOL bRet2 = ScreenToClient(hParent, &rect);
RECT lrect = m_rect; lrect.top = rect.bottom; lrect.right -= 12; // UNDONE: remove this line when the clipping is working properly (scroll bars don't appear above other windows)
return lrect; }
void CFlexComboBox::DoSel() { if (m_bInSelMode) return; if (m_hWnd == NULL) return;
FLEXLISTBOXCREATESTRUCT cs; cs.dwSize = sizeof(FLEXLISTBOXCREATESTRUCT); cs.dwFlags = m_dwListBoxFlags; cs.hWndParent = GetParent(m_hWnd); cs.hWndNotify = m_hWnd; cs.bVisible = FALSE; cs.rect = GetListBoxRect(); cs.hFont = m_hFont; cs.rgbText = m_rgbText; cs.rgbBk = m_rgbBk; cs.rgbSelText = m_rgbSelText; cs.rgbSelBk = m_rgbSelBk; cs.rgbFill = m_rgbFill; cs.rgbLine = m_rgbLine; cs.nSBWidth = m_nSBWidth;
m_OldSel = m_ListBox.GetSel();
m_bInSelMode = m_ListBox.Create(&cs); if (m_bInSelMode) SetWindowPos(m_ListBox.m_hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); }
void CFlexComboBox::Notify(int code) { if (!m_hWndNotify) return;
SendMessage(m_hWndNotify, WM_FLEXCOMBOBOX, (WPARAM)code, (LPARAM)(LPVOID)this); }
RECT CFlexComboBox::GetRect(const RECT &rect) { int h = GetTextHeight(m_hFont); RECT ret = {rect.left, rect.top, rect.right, rect.top + h + 2}; return ret; }
RECT CFlexComboBox::GetRect() { RECT rect; GetClientRect(&rect); return GetRect(rect); }
void CFlexComboBox::SetFont(HFONT hFont) { m_hFont = hFont;
if (m_hWnd == NULL) return;
Invalidate(); SetRect(); }
void CFlexComboBox::SetRect() { if (m_hWnd == NULL) return;
RECT rect = GetRect(); SetWindowPos(m_hWnd, NULL, rect.left, rect.top, rect.right, rect.bottom, SWP_NOZORDER | SWP_NOMOVE); }
void CFlexComboBox::SetColors(COLORREF text, COLORREF bk, COLORREF seltext, COLORREF selbk, COLORREF fill, COLORREF line) { m_rgbText = text; m_rgbBk = bk; m_rgbSelText = seltext; m_rgbSelBk = selbk; m_rgbFill = fill; m_rgbLine = line; Invalidate(); }
void CFlexComboBox::StateEvent(FCBSTATEEVENT e) { if (e == FCBSE_DOWNOFF) { SetState(FCBS_CANCEL); return; }
switch (m_eCurState) { case FCBS_CLOSED: if (e == FCBSE_DOWN) SetState(FCBS_OPENDOWN); break;
case FCBS_OPENDOWN: switch (e) { case FCBSE_UPLIST: SetState(FCBS_SELECT); break; case FCBSE_UPBOX: SetState(FCBS_OPENUP); break; case FCBSE_UPOFF: SetState(FCBS_CANCEL); break; }
case FCBS_OPENUP: if (e == FCBSE_DOWN) SetState(FCBS_OPENDOWN); break;
default: assert(0); return; } }
void CFlexComboBox::SetState(FCBSTATE s) { FCBSTATE eOldState = m_eCurState; m_eCurState = s;
switch (s) { case FCBS_OPENUP: if (eOldState == FCBS_CLOSED) DoSel(); return;
case FCBS_OPENDOWN: if (eOldState == FCBS_CLOSED) DoSel(); m_ListBox.StartSel(); return;
case FCBS_CANCEL: m_ListBox.SetSel(m_OldSel); CFlexWnd::s_ToolTip.SetEnable(FALSE); SetState(FCBS_CLOSED); return;
case FCBS_SELECT: CFlexWnd::s_ToolTip.SetEnable(FALSE); Invalidate(); Notify(FCBN_SELCHANGE); SetState(FCBS_CLOSED); return;
case FCBS_CLOSED: if (eOldState != FCBS_CLOSED) m_ListBox.Destroy(); m_bInSelMode = FALSE; Invalidate(); return; } }
|