|
|
/*--------------------------------------------------------------------------*
* * Microsoft Windows * Copyright (C) Microsoft Corporation, 1992 - 1999 * * File: ftab.h * * Contents: Implementation file for CFolderTab, CFolderTabView * * History: 06-May-99 vivekj Created * *--------------------------------------------------------------------------*/
#include "stdafx.h"
#include "ftab.h"
#include "amcview.h"
#include <oleacc.h>
/*
* if we're supporting old platforms, we need to build MSAA stubs */ #if (_WINNT_WIN32 < 0x0500)
#include <winable.h>
#define COMPILE_MSAA_STUBS
#include "msaastub.h"
#define WM_GETOBJECT 0x003D
#endif
#ifdef DBG
CTraceTag tagTabAccessibility (_T("Accessibility"), _T("Tab Control")); #endif
/*+-------------------------------------------------------------------------*
* ValueOf * * Returns the value contained in the given variant. The variant is * expected to be of type VT_I4. *--------------------------------------------------------------------------*/
inline LONG ValueOf (VARIANT& var) { ASSERT (V_VT (&var) == VT_I4); // prevalidation is expected
return (V_I4 (&var)); }
/*+-------------------------------------------------------------------------*
* CTabAccessible * * Implements the accessibility interface IAccessible for CFolderTabView. *--------------------------------------------------------------------------*/
class CTabAccessible : public CMMCIDispatchImpl<IAccessible, &GUID_NULL, &LIBID_Accessibility>, public CTiedComObject<CFolderTabView> { typedef CTabAccessible ThisClass; typedef CFolderTabView CMyTiedObject;
public: BEGIN_MMC_COM_MAP(ThisClass) END_MMC_COM_MAP()
DECLARE_NOT_AGGREGATABLE(ThisClass)
public: // *** IAccessible methods ***
MMC_METHOD1 (get_accParent, IDispatch** /*ppdispParent*/); MMC_METHOD1 (get_accChildCount, long* /*pChildCount*/); MMC_METHOD2 (get_accChild, VARIANT /*varChildID*/, IDispatch ** /*ppdispChild*/); MMC_METHOD2 (get_accName, VARIANT /*varChildID*/, BSTR* /*pszName*/); MMC_METHOD2 (get_accValue, VARIANT /*varChildID*/, BSTR* /*pszValue*/); MMC_METHOD2 (get_accDescription, VARIANT /*varChildID*/, BSTR* /*pszDescription*/); MMC_METHOD2 (get_accRole, VARIANT /*varChildID*/, VARIANT */*pvarRole*/); MMC_METHOD2 (get_accState, VARIANT /*varChildID*/, VARIANT */*pvarState*/); MMC_METHOD2 (get_accHelp, VARIANT /*varChildID*/, BSTR* /*pszHelp*/); MMC_METHOD3 (get_accHelpTopic, BSTR* /*pszHelpFile*/, VARIANT /*varChildID*/, long* /*pidTopic*/); MMC_METHOD2 (get_accKeyboardShortcut, VARIANT /*varChildID*/, BSTR* /*pszKeyboardShortcut*/); MMC_METHOD1 (get_accFocus, VARIANT * /*pvarFocusChild*/); MMC_METHOD1 (get_accSelection, VARIANT * /*pvarSelectedChildren*/); MMC_METHOD2 (get_accDefaultAction, VARIANT /*varChildID*/, BSTR* /*pszDefaultAction*/); MMC_METHOD2 (accSelect, long /*flagsSelect*/, VARIANT /*varChildID*/); MMC_METHOD5 (accLocation, long* /*pxLeft*/, long* /*pyTop*/, long* /*pcxWidth*/, long* /*pcyHeight*/, VARIANT /*varChildID*/); MMC_METHOD3 (accNavigate, long /*navDir*/, VARIANT /*varStart*/, VARIANT * /*pvarEndUpAt*/); MMC_METHOD3 (accHitTest, long /*xLeft*/, long /*yTop*/, VARIANT * /*pvarChildAtPoint*/); MMC_METHOD1 (accDoDefaultAction, VARIANT /*varChildID*/); MMC_METHOD2 (put_accName, VARIANT /*varChildID*/, BSTR /*szName*/); MMC_METHOD2 (put_accValue, VARIANT /*varChildID*/, BSTR /*pszValue*/); };
//############################################################################
//############################################################################
//
// Implementation of class CFolderTabMetrics
//
//############################################################################
//############################################################################
CFolderTabMetrics::CFolderTabMetrics() : m_dwStyle(0), m_textHeight(0) { }
int CFolderTabMetrics::GetXOffset() const {return 8;} int CFolderTabMetrics::GetXMargin() const {return 2;} int CFolderTabMetrics::GetYMargin() const {return 1;} int CFolderTabMetrics::GetYBorder() const {return 1;} int CFolderTabMetrics::GetExtraYSpace() const {return 0;} int CFolderTabMetrics::GetTabHeight() const {return GetTextHeight() + 2 * GetYMargin() + 2 * GetYBorder();} int CFolderTabMetrics::GetUpDownWidth() const {return 2*GetTabHeight();} //for nice square buttons
int CFolderTabMetrics::GetUpDownHeight()const {return GetTabHeight();} // the up-down control is as tall as the tabs
//############################################################################
//############################################################################
//
// Implementation of class CFolderTab
//
//############################################################################
//############################################################################
CFolderTab::CFolderTab() { }
CFolderTab::CFolderTab(const CFolderTab &other) { *this = other; }
CFolderTab & CFolderTab::operator = (const CFolderTab &other) { if((CFolderTab *) this == (CFolderTab *) &other) return *this;
m_sText = other.m_sText; m_rect = other.m_rect; m_clsid = other.m_clsid; m_dwStyle = other.m_dwStyle; m_textHeight = other.m_textHeight;
return *this; }
/*+-------------------------------------------------------------------------*
* * CFolderTab::GetWidth * * PURPOSE: Returns the width of the tab. * * RETURNS: * int * *+-------------------------------------------------------------------------*/ int CFolderTab::GetWidth() const { return m_rect.Width() + 1; // rect.Width() returns right-left, need to add 1 for inclusive width.
}
/*+-------------------------------------------------------------------------*
* * CFolderTab::SetWidth * * PURPOSE: Sets the width of the tab. * * PARAMETERS: * int nWidth : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CFolderTab::SetWidth(int nWidth) { ASSERT(nWidth > 0); ASSERT(GetWidth() >= nWidth);
int delta = nWidth - (m_rect.Width() + 1); m_rect.right = m_rect.left + nWidth -1;
m_rgPts[2].x+=delta; m_rgPts[3].x+=delta; SetRgn(); }
/*+-------------------------------------------------------------------------*
* * CFolderTab::Offset * * PURPOSE: Adds a certain offset to the internal array of points. * * PARAMETERS: * const CPoint : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CFolderTab::Offset(const CPoint &point) { m_rect.OffsetRect(point); m_rgPts[0].Offset(point); m_rgPts[1].Offset(point); m_rgPts[2].Offset(point); m_rgPts[3].Offset(point); m_rgn.OffsetRgn(point); }
void CFolderTab::SetRgn() { m_rgn.DeleteObject(); m_rgn.CreatePolygonRgn(m_rgPts, 4, WINDING); }
/*+-------------------------------------------------------------------------*
* * CFolderTab::ComputeRgn * * PURPOSE: Compute the the points, rect and region for a tab. * Input x is starting x pos. * * PARAMETERS: * CDC& dc : * int x : * * RETURNS: * int: The actual width of the tab * *+-------------------------------------------------------------------------*/ int CFolderTab::ComputeRgn(CDC& dc, int x) {
CRect& rc = m_rect; rc.SetRectEmpty();
// calculate desired text rectangle
dc.DrawText(m_sText, &rc, DT_CALCRECT); rc.right += 2*GetXOffset() + 2*GetXMargin(); // add margins
rc.bottom = rc.top + GetTabHeight(); rc += CPoint(x,0); // shift right
// create region
GetTrapezoid(rc, m_rgPts); SetRgn();
return rc.Width(); }
/*+-------------------------------------------------------------------------*
* * CFolderTab::GetTrapezoid * * PURPOSE: Given the bounding rect, compute trapezoid region. * Note that the right and bottom edges not included in rect or * trapezoid; these are normal rules of geometry. * * PARAMETERS: * const CRect : * CPoint* pts : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CFolderTab::GetTrapezoid(const CRect& rc, CPoint* pts) const { pts[0] = CPoint(rc.left, rc.top ); pts[1] = CPoint(rc.left + GetXOffset(), rc.bottom ); pts[2] = CPoint(rc.right- GetXOffset()-1, rc.bottom ); pts[3] = CPoint(rc.right-1, rc.top ); }
//////////////////
// Draw tab in normal or highlighted state
//
int CFolderTab::Draw(CDC& dc, CFont& font, BOOL bSelected, bool bFocused) { return DrawTrapezoidal(dc, font, bSelected, bFocused); }
/*+-------------------------------------------------------------------------*
* * CFolderTab::DrawTrapezoidal * * PURPOSE: Draws a trapezoidal tab. * * PARAMETERS: * CDC& dc : * CFont& font : * BOOL bSelected : * bool bFocused : * * RETURNS: * int * *+-------------------------------------------------------------------------*/ int CFolderTab::DrawTrapezoidal(CDC& dc, CFont& font, BOOL bSelected, bool bFocused) { COLORREF bgColor = GetSysColor(bSelected ? COLOR_WINDOW : COLOR_3DFACE); COLORREF fgColor = GetSysColor(bSelected ? COLOR_WINDOWTEXT : COLOR_BTNTEXT);
CBrush brush(bgColor); // background brush
dc.SetBkColor(bgColor); // text background
dc.SetTextColor(fgColor); // text color = fg color
CPen blackPen (PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME)); CPen shadowPen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW));
// Fill trapezoid
CPoint pts[4]; CRect rc = m_rect; GetTrapezoid(rc, pts); CPen* pOldPen = dc.SelectObject(&blackPen); dc.FillRgn(&m_rgn, &brush);
// Draw edges. This is requires two corrections:
// 1) Trapezoid dimensions don't include the right and bottom edges,
// so must use one pixel less on bottom (cybottom)
// 2) the endpoint of LineTo is not included when drawing the line, so
// must add one pixel (cytop)
//
{ pts[1].y--; // correction #1: true bottom edge y-coord
pts[2].y--; // ...ditto
pts[3].y--; // correction #2: extend final LineTo
} dc.MoveTo(pts[0]); // upper left
dc.LineTo(pts[1]); // bottom left
dc.SelectObject(&shadowPen); // bottom line is shadow color
dc.MoveTo(pts[1]); // line is inside trapezoid bottom
dc.LineTo(pts[2]); // ...
dc.SelectObject(&blackPen); // upstroke is black
dc.LineTo(pts[3]); // y-1 to include endpoint
if(!bSelected) { // if not highlighted, upstroke has a 3D shadow, one pixel inside
pts[2].x--; // offset left one pixel
pts[3].x--; // ...ditto
dc.SelectObject(&shadowPen); dc.MoveTo(pts[2]); dc.LineTo(pts[3]); } dc.SelectObject(pOldPen);
// draw text
rc.DeflateRect(GetXOffset() + GetXMargin(), GetYMargin()); CFont* pOldFont = dc.SelectObject(&font); dc.DrawText(m_sText, &rc, DT_CENTER|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS); dc.SelectObject(pOldFont);
if(bFocused) // draw the focus rectangle
{ // make some more space.
rc.top--; rc.bottom++; rc.left--; rc.right++;
dc.DrawFocusRect(&rc); }
return m_rect.right; }
//############################################################################
//############################################################################
//
// Implementation of class CFolderTabView
//
//############################################################################
//############################################################################
IMPLEMENT_DYNAMIC(CFolderTabView, CView) BEGIN_MESSAGE_MAP(CFolderTabView, CView) ON_WM_PAINT() ON_WM_LBUTTONDOWN() ON_WM_SETFOCUS() ON_WM_KILLFOCUS() ON_WM_MOUSEACTIVATE() ON_WM_KEYDOWN() ON_WM_SETTINGCHANGE() ON_WM_SIZE() ON_WM_HSCROLL() ON_MESSAGE(WM_GETOBJECT, OnGetObject) END_MESSAGE_MAP()
CFolderTabView::CFolderTabView(CView *pParentView) : m_bVisible(false), m_pParentView(pParentView) { m_iCurItem = -1; // nothing currently selected
m_dwStyle = 0; m_textHeight = 0; m_sizeX = 0; m_sizeY = 0; m_hWndUpDown = NULL; m_nPos = 0; // the first tab is the one drawn
m_fHaveFocus = false; }
CFolderTabView::~CFolderTabView() { }
/*+-------------------------------------------------------------------------*
* CFolderTabView::ScFireAccessibilityEvent * * Fires accessibility events for the folder tab view *--------------------------------------------------------------------------*/
SC CFolderTabView::ScFireAccessibilityEvent ( DWORD dwEvent, /* I:event to fire */ LONG idObject) /* I:object generating the event */ { DECLARE_SC (sc, _T("CFolderTabView::ScFireAccessibilityEvent"));
/*
* Accessibility events are fired after the event takes place (e.g. * EVENT_OBJECT_CREATE is sent after the child is created, not before). * Because of this the child ID for EVENT_OBJECT_DESTROY is not * necessarily valid, so we shouldn't validate in that case. */ if (dwEvent != EVENT_OBJECT_DESTROY) { sc = ScValidateChildID (idObject); if (sc) return (sc); }
NotifyWinEvent (dwEvent, m_hWnd, OBJID_CLIENT, idObject); // returns void
return (sc); }
/*+-------------------------------------------------------------------------*
* * CFolderTabView::OnHScroll * * PURPOSE: Called when the position of the scroll bar is changed * * PARAMETERS: * UINT nSBCode : * UINT nPos : * CScrollBar* pScrollBar : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CFolderTabView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar ) { // we're only interested in SB_THUMBPOSITION
if(nSBCode != SB_THUMBPOSITION) return;
// if the position has not changed, do nothing.
if(nPos == m_nPos) return;
m_nPos = nPos; // change the position
RecomputeLayout(); InvalidateRect(NULL, true); // redraw everything.
}
/*+-------------------------------------------------------------------------*
* CFolderTabView::OnSetFocus * * WM_SETFOCUS handler for CFolderTabView. *--------------------------------------------------------------------------*/
void CFolderTabView::OnSetFocus(CWnd* pOldWnd) { m_fHaveFocus = true;
InvalidateRect(NULL); BC::OnSetFocus(pOldWnd);
/*
* If we have any tabs, one of them will get the focus. Fire the * focus accessibility event, ignoring errors. We do this after * calling the base class, so this focus event will override the * "focus to the window" event sent by the system on our behalf. */ if (GetItemCount() > 0) ScFireAccessibilityEvent (EVENT_OBJECT_FOCUS, m_iCurItem+1 /*1-based*/); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::OnKillFocus * * WM_KILLFOCUS handler for CFolderTabView. *--------------------------------------------------------------------------*/
void CFolderTabView::OnKillFocus(CWnd* pNewWnd) { m_fHaveFocus = false;
InvalidateRect(NULL); BC::OnKillFocus(pNewWnd); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::OnMouseActivate * * WM_MOUSEACTIVATE handler for CFolderTabView. *--------------------------------------------------------------------------*/
int CFolderTabView::OnMouseActivate( CWnd* pDesktopWnd, UINT nHitTest, UINT message ) { //short-circuit the MFC base class code, which sets the keyboard focus here as well...
return MA_ACTIVATE; }
/*+-------------------------------------------------------------------------*
* CFolderTabView::OnCmdMsg * * WM_COMMAND handler for CFolderTabView. *--------------------------------------------------------------------------*/
BOOL CFolderTabView::OnCmdMsg( UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo ) { // Do normal command routing
if (BC::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE;
// if view didn't handle it, give parent view a chance
if (m_pParentView != NULL) return static_cast<CWnd*>(m_pParentView)->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); else return FALSE; }
/*+-------------------------------------------------------------------------*
* CFolderTabView::OnKeyDown * * WM_KEYDOWN handler for CFolderTabView. *--------------------------------------------------------------------------*/
void CFolderTabView::OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags ) { int cSize = m_tabList.size();
if( (cSize == 0) || ( (nChar != VK_LEFT) && (nChar != VK_RIGHT) ) ) { BC::OnKeyDown(nChar, nRepCnt, nFlags); return; }
ASSERT( (nChar == VK_LEFT) || (nChar == VK_RIGHT) );
int iNew = GetSelectedItem() + (nChar==VK_LEFT ? -1 : 1); if(iNew < 0) iNew = 0; // does not wrap
if(iNew >= cSize) iNew = cSize -1; // does not wrap
SelectItem(iNew, true /*bEnsureVisible*/); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::OnSettingChange * * WM_SETTINGCHANGE handler for CFolderTabView. *--------------------------------------------------------------------------*/
void CFolderTabView::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) { CView::OnSettingChange(uFlags, lpszSection);
if (uFlags == SPI_SETNONCLIENTMETRICS) { DeleteFonts (); CreateFonts (); InvalidateRect(NULL, true); // redraw everything.
RecomputeLayout (); } }
//////////////////
// Create folder tab control from static control.
// Destroys the static control. This is convenient for dialogs
//
BOOL CFolderTabView::CreateFromStatic(UINT nID, CWnd* pParent) { CStatic wndStatic; if(!wndStatic.SubclassDlgItem(nID, pParent)) return FALSE; CRect rc; wndStatic.GetWindowRect(&rc); pParent->ScreenToClient(&rc); wndStatic.DestroyWindow(); rc.bottom = rc.top + GetDesiredHeight(); return Create(WS_CHILD|WS_VISIBLE, rc, pParent, nID); }
/*+-------------------------------------------------------------------------*
* * CFolderTabView::Create * * PURPOSE: Creates the folder tab control * * PARAMETERS: * DWORD dwStyle : * const RECT : * CWnd* pParent : * UINT nID : * DWORD dwFtabStyle : * * RETURNS: * BOOL * *+-------------------------------------------------------------------------*/ BOOL CFolderTabView::Create(DWORD dwStyle, const RECT& rc, CWnd* pParent, UINT nID, DWORD dwFtabStyle) { ASSERT(pParent); ASSERT(dwStyle & WS_CHILD);
m_dwStyle = dwFtabStyle;
static LPCTSTR lpClassName = _T("AMCCustomTab"); static BOOL bRegistered = FALSE; // registered?
if(!bRegistered) { WNDCLASS wc; memset(&wc, 0, sizeof(wc)); wc.lpfnWndProc = ::DefWindowProc; // will get hooked by MFC
wc.hInstance = AfxGetInstanceHandle(); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_3DFACE+1); wc.lpszMenuName = NULL; wc.lpszClassName = lpClassName; if(!AfxRegisterClass(&wc)) { TRACE(_T("*** CFolderTabView::AfxRegisterClass failed!\n")); return FALSE; } bRegistered = TRUE; } if(!BC::CreateEx(0, lpClassName, NULL, dwStyle, rc, pParent, nID)) return FALSE;
// initialize fonts
CreateFonts();
/*
* Bug 141015: Create a buddy window for the up-down control. It will * never be visible, but we need it so UDM_GETPOS sent to the up-down * will work. Narrator will send this message when the up-down becomes * visible, but it will fail if there's no buddy (sad, but true). It * fails by returning an LRESULT with a non-zero high-order word * (specifically, 0x00010000), so Narrator translates and announces * "65536" instead of the true value. * * This is only required for Narrator support, so if it fails it's * not sufficient reason to fail CFolderTabView creation altogether. */ HWND hwndBuddy = CreateWindow (_T("edit"), NULL, WS_CHILD, 0, 0, 0, 0, m_hWnd, 0, AfxGetInstanceHandle(), NULL);
// create the up-down control
DWORD dwUpDownStyle = WS_CHILD | WS_BORDER | UDS_SETBUDDYINT | // for Narrator support
UDS_HORZ /*to display the arrows left to right*/; // NOTE: the control is created invisible on purpose.
m_hWndUpDown = CreateUpDownControl(dwUpDownStyle, 0, 0, GetUpDownWidth(), //width
GetUpDownHeight(), //height
m_hWnd, 1 /*nID*/, AfxGetInstanceHandle(), hwndBuddy, 0 /*nUpper*/, 0 /*nLower*/, 0 /*nPos*/);
return TRUE; }
void CFolderTabView::CreateFonts () { LOGFONT lf; SystemParametersInfo (SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, false); m_fontNormal.CreateFontIndirect(&lf);
// Get the font height (converting from points to pixels)
CClientDC dc(NULL); TEXTMETRIC tm; CFont *pFontOld = dc.SelectObject(&m_fontNormal); dc.GetTextMetrics(&tm);
m_textHeight = tm.tmHeight;
// set the old font back.
dc.SelectObject(pFontOld);
lf.lfWeight = FW_BOLD; m_fontSelected.CreateFontIndirect(&lf); }
void CFolderTabView::DeleteFonts () { m_fontNormal.DeleteObject(); m_fontSelected.DeleteObject(); }
//////////////////
// copy a font
//
static void CopyFont(CFont& dst, CFont& src) { dst.DeleteObject(); LOGFONT lf; VERIFY(src.GetLogFont(&lf)); dst.CreateFontIndirect(&lf); }
//////////////////
// Set normal, selected fonts
//
void CFolderTabView::SetFonts(CFont& fontNormal, CFont& fontSelected) { CopyFont(m_fontNormal, fontNormal); CopyFont(m_fontSelected, fontSelected); }
//////////////////
// Paint function
//
void CFolderTabView::OnDraw(CDC* pDC) { }
void CFolderTabView::OnPaint() { Paint (m_fHaveFocus); }
/*+-------------------------------------------------------------------------*
* * CFolderTabView::EnsureVisible * * PURPOSE: Changes the layout to ensure that the specified tab is visible. * * NOTE: Does NOT invalidate the rect, for efficiency. * * PARAMETERS: * UINT iTab : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CFolderTabView::EnsureVisible(int iTab) { if((iTab < 0) || (iTab > m_tabList.size())) { ASSERT(0 && "Should not come here."); return; }
if(!::IsWindowVisible(m_hWndUpDown)) return; // the up-down control is hidden, meaning that all tabs are visible
RecomputeLayout(); // make sure we have the correct dimensions
if(m_nPos == iTab) return; // the tab already shows as much as it can.
if(m_nPos > iTab) // the first visible tab is to the right of iTab. Make iTab the first visible tab
{ m_nPos = iTab; RecomputeLayout(); return; }
iterator iter = m_tabList.begin(); std::advance(iter, iTab); // get the correct item
CRect rcCurTab = iter->GetRect();
// loop: Increase the start tab position until the right edge of iTab fits.
while((m_nPos < iTab) && (rcCurTab.right > m_sizeX)) { m_nPos++; RecomputeLayout(); rcCurTab = iter->GetRect(); } }
/*+-------------------------------------------------------------------------*
* * CFolderTabView::Paint * * PURPOSE: Completely redraws the tab control. * * PARAMETERS: * bool bFocused : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CFolderTabView::Paint(bool bFocused) { CPaintDC dc(this); // device context for painting
CRect rc; GetClientRect(&rc);
// draw all the normal (non-selected) tabs
iterator iterSelected = m_tabList.end(); int i = 0; bool bDraw = true; for(iterator iter= m_tabList.begin(); iter!= m_tabList.end(); ++iter, i++) { if(i!=m_iCurItem) { if(bDraw && iter->Draw(dc, m_fontNormal, FALSE, false) > rc.right) bDraw = false; } else { iterSelected = iter; } }
ASSERT(iterSelected != m_tabList.end());
/*
* Bug 350942: selected tab shouldn't be bold */ // draw selected tab last so it will be "on top" of the others
iterSelected->Draw(dc, /*m_fontSelected*/ m_fontNormal, TRUE, bFocused);
// draw border: line along the top edge, excluding seleted tab
CPoint pts[4]; CRect rcCurTab = iterSelected->GetRect(); iterSelected->GetTrapezoid(&rcCurTab, pts);
CPen blackPen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME));
CPen* pOldPen = dc.SelectObject(&blackPen); int y = pts[0].y; dc.MoveTo(rc.left, y); dc.LineTo(pts[0].x, y); dc.MoveTo(pts[3].x, y); dc.LineTo(rc.right, y);
dc.SelectObject(pOldPen); }
/*+-------------------------------------------------------------------------*
* * CFolderTabView::OnLButtonDown * * PURPOSE: Selects the tab pointed to on a left mouse click * * PARAMETERS: * UINT nFlags : * CPoint pt : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CFolderTabView::OnLButtonDown(UINT nFlags, CPoint pt) { int iTab = HitTest(pt); if(iTab>=0 && iTab!=m_iCurItem) { SelectItem(iTab, true /*bEnsureVisible*/); } }
/*+-------------------------------------------------------------------------*
* * CFolderTabView::HitTest * * PURPOSE: Computes which tab is at the specified point. * * PARAMETERS: * CPoint pt : * * RETURNS: * int: The tab index, or -1 if none. * *+-------------------------------------------------------------------------*/ int CFolderTabView::HitTest(CPoint pt) { CRect rc; GetClientRect(&rc); if(rc.PtInRect(pt)) { int i = 0; for( iterator iter= m_tabList.begin(); iter!= m_tabList.end(); ++iter, i++) { if(iter->HitTest(pt)) return i; } } return -1; }
/*+-------------------------------------------------------------------------*
* * CFolderTabView::SelectItem * * PURPOSE: Selects the iTab'th tab and returns the index of the tab selected, * or -1 if an error occurred. * * PARAMETERS: * int iTab : * bool bEnsureVisible : If true, repositions the tab to make it visible. * * RETURNS: * int * *+-------------------------------------------------------------------------*/ int CFolderTabView::SelectItem(int iTab, bool bEnsureVisible) { if(iTab<0 || iTab>=GetItemCount()) return -1; // bad
bool bSendTabChanged = (iTab != m_iCurItem); // send a message only if a different item got selected
// repaint the control
m_iCurItem = iTab; // set new selected tab
if(bEnsureVisible) EnsureVisible(iTab); else RecomputeLayout();
InvalidateRect(NULL, true);
if(bSendTabChanged) { /*
* If the selection changed, fire the selection accessibility event. * We do it before sending FTN_TABCHANGED so that if the FTN_TABCHANGED * handler selects another item, observers will get the selection * events in the right order (ignore errors) */ ScFireAccessibilityEvent (EVENT_OBJECT_SELECTION, m_iCurItem+1 /*1-based*/);
/*
* if our window has the focus, focus changes with selection, * so send focus event, too (ignore errors) */ if (m_fHaveFocus) ScFireAccessibilityEvent (EVENT_OBJECT_FOCUS, m_iCurItem+1 /*1-based*/);
// send the FTN_TABCHANGED message
NMFOLDERTAB nm; nm.hwndFrom = m_hWnd; nm.idFrom = GetDlgCtrlID(); nm.code = FTN_TABCHANGED; nm.iItem = iTab; CWnd* pParent = GetParent(); pParent->SendMessage(WM_NOTIFY, nm.idFrom, (LPARAM)&nm); }
return m_iCurItem; }
int CFolderTabView::SelectItemByClsid(const CLSID& clsid) { bool bFound = false; int i=0; for(iterator iter= m_tabList.begin(); iter!= m_tabList.end(); ++iter, i++) { if(IsEqualGUID(iter->GetClsid(),clsid)) { bFound = true; break; } }
if(!bFound) { ASSERT(0 && "Invalid folder tab."); return -1; }
return SelectItem(i); }
CFolderTab & CFolderTabView::GetItem(int iPos) { ASSERT(!(iPos<0 || iPos>=GetItemCount()));
CFolderTabList::iterator iter = m_tabList.begin(); std::advance(iter, iPos); return *iter; }
int CFolderTabView::AddItem(LPCTSTR lpszText, const CLSID& clsid) { CFolderTab tab; tab.SetText(lpszText); tab.SetClsid(clsid); tab.SetStyle(m_dwStyle); tab.SetTextHeight(m_textHeight);
m_tabList.push_back(tab);
RecomputeLayout(); InvalidateRect(NULL, true);
int nNewItemIndex = m_tabList.size() - 1; // 0-based
/*
* tell observers we created a new tab, after it's been created (ignore errors) */ ScFireAccessibilityEvent (EVENT_OBJECT_CREATE, nNewItemIndex+1 /*1-based*/);
return (nNewItemIndex); }
BOOL CFolderTabView::RemoveItem(int iPos) { if( (iPos < 0) || (iPos>= m_tabList.size()) ) return false;
CFolderTabList::iterator iter = m_tabList.begin(); std::advance(iter, iPos); m_tabList.erase(iter);
/*
* tell observers we destroyed a tab, after it's been destroyed but before * we might send selection/focus notifications in SelectItem (ignore errors) */ ScFireAccessibilityEvent (EVENT_OBJECT_DESTROY, iPos+1 /*1-based*/);
/*
* If we're deleting the currently selected tab, the selection needs to * move somewhere else. If there are tabs following the current one, * we'll move the selection to the next tab; otherwise, we'll move to * the previous one. */ if ((iPos == m_iCurItem) && !m_tabList.empty()) { /*
* if there are tabs to the following the one we just deleted, * increment m_iCurItem so the subsequent call to SelectItem * will recognize that the selection change and send the proper * notifications. */ if (m_iCurItem < m_tabList.size()) m_iCurItem++;
SelectItem (m_iCurItem-1, true /*bEnsureVisible*/); } else { /*
* if we deleted a tab before the selected tab, decrement the * selected tab index to keep things in sync * m_iCurItem will become -1 when the last tab is removed, which is correct */ if (iPos <= m_iCurItem) m_iCurItem--;
InvalidateRect(NULL, true); RecomputeLayout(); }
return true; }
void CFolderTabView::DeleteAllItems() { const int cChildren = m_tabList.size(); m_tabList.clear(); m_iCurItem = -1; // nothing is selected
InvalidateRect(NULL, true); RecomputeLayout();
/*
* Tell accessibility observers that each tab is destroyed. Notify * in last-to-first order so IDs remain sane during this process. */ for (int idChild = cChildren /*1-based*/; idChild >= 1; idChild--) { ScFireAccessibilityEvent (EVENT_OBJECT_DESTROY, idChild); }
/*
* If we have the focus, tell accessibility observers that the * control itself has the focus. We do this to be consistent with * other controls (like the list view) */ if (m_fHaveFocus) ScFireAccessibilityEvent (EVENT_OBJECT_FOCUS, CHILDID_SELF); }
void CFolderTabView::OnSize(UINT nType, int cx, int cy) { m_sizeX = cx; m_sizeY = cy;
CView::OnSize(nType, cx, cy);
if (nType != SIZE_MINIMIZED) { RecomputeLayout(); }
}
/*+-------------------------------------------------------------------------*
* * CFolderTabView::ShowUpDownControl * * PURPOSE: Shows or hides the up/down control * * PARAMETERS: * BOOL bShow : true to show, false to hide. * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CFolderTabView::ShowUpDownControl(BOOL bShow) { BOOL bVisible = (m_hWndUpDown != NULL) && ::IsWindowVisible(m_hWndUpDown); // was the up-down control visible previously?
if(bShow) { if(!bVisible) { ::SendMessage(m_hWndUpDown, UDM_SETRANGE32, (WPARAM) 0 /*iLow*/, (LPARAM) m_tabList.size()-1 /*zero-based*/); ::SendMessage(m_hWndUpDown, UDM_SETPOS, (WPARAM) 0, (LPARAM) m_nPos /*nPos*/); ::ShowWindow(m_hWndUpDown, SW_SHOW);
InvalidateRect(NULL, true); } } else { // hide the updown control
if(m_hWndUpDown) ::ShowWindow(m_hWndUpDown, SW_HIDE);
if(bVisible) // invalidate only on a transition from visible to invisible
InvalidateRect(NULL, true);
m_nPos = 0; }
}
/*+-------------------------------------------------------------------------*
* * CFolderTabView::GetTotalTabWidth * * PURPOSE: Computes the total width of all the tabs. * * PARAMETERS: * CClientDC& dc : * * RETURNS: * int * *+-------------------------------------------------------------------------*/ int CFolderTabView::GetTotalTabWidth(CClientDC& dc) { int x = 0;
// compute the width "as is", ie without taking into account the actual space available.
for(iterator iter = m_tabList.begin(); iter!= m_tabList.end(); ++iter) { x += iter->ComputeRgn(dc, x) - GetXOffset(); }
return x; }
/*+-------------------------------------------------------------------------*
* * CFolderTabView::ComputeRegion * * PURPOSE: Computes the location and regions for all the tabs * * PARAMETERS: * CClientDC& dc : * * RETURNS: * int * *+-------------------------------------------------------------------------*/ int CFolderTabView::ComputeRegion(CClientDC& dc) { int x = GetTotalTabWidth(dc);
// subtract the top-left x coordinate of the m_nPos'th tab from all x coordinates, thereby creating a shift
iterator iter = m_tabList.begin(); std::advance(iter, m_nPos); // advance to the m_nPos'th tab
int xOffset = iter->GetRect().left;
x = GetUpDownWidth() - xOffset; // shift everything to the left by xOffset
for(iterator iterTemp = m_tabList.begin(); iterTemp!= m_tabList.end(); ++iterTemp) { x += iterTemp->ComputeRgn(dc, x) - GetXOffset(); }
return x; }
/*+-------------------------------------------------------------------------*
* * CFolderTabView::RecomputeLayout * * PURPOSE: Determines the location of all the tabs, and whether or not the * up/down control should be displayed. * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CFolderTabView::RecomputeLayout() { // set the size of the updown control
if(m_hWndUpDown) ::SetWindowPos(m_hWndUpDown, NULL /*hWndInsertAfter*/, 0 /*left*/, 0 /*top*/, GetUpDownWidth(), GetUpDownHeight(), SWP_NOMOVE| SWP_NOZORDER);
// set the correct text height for the tabs
for(iterator iterTemp = m_tabList.begin(); iterTemp!= m_tabList.end(); ++iterTemp) iterTemp->SetTextHeight(GetTextHeight());
CClientDC dc(this); CFont* pOldFont = dc.SelectObject(&m_fontSelected); // use the bold font to compute with.
int totalWidth = GetTotalTabWidth(dc); // the width of ALL tabs
if(totalWidth <= m_sizeX) { // there's enough space to show all tabs. Hide the updown control
ShowUpDownControl(false); } else { // not enough width for all tabs.
BOOL bVisible = ::IsWindowVisible(m_hWndUpDown); // was the up-down control visible previously?
if(!bVisible) // the up-down control was not visible, so make it visible.
{ m_nPos = 0; ShowUpDownControl(true); }
ComputeRegion(dc); // make sure we leave space for the tab
}
dc.SelectObject(pOldFont); }
void CFolderTabView::Layout(CRect& rectTotal, CRect& rectFTab) { int cy = GetTabHeight() + GetExtraYSpace(); rectFTab = rectTotal; if(!IsVisible()) return;
rectFTab.top = rectFTab.bottom - cy; rectTotal.bottom= rectFTab.top; }
/*+-------------------------------------------------------------------------*
* CFolderTabView::OnGetObject * * WM_GETOBJECT handler for CFolderTabView. *--------------------------------------------------------------------------*/
LRESULT CFolderTabView::OnGetObject (WPARAM wParam, LPARAM lParam) { DECLARE_SC (sc, _T("CFolderTabView::OnGetObject"));
/*
* ignore requests for objects other than OBJID_CLIENT */ if (lParam != OBJID_CLIENT) { Trace (tagTabAccessibility, _T("WM_GETOBJECT: (lParam != OBJID_CLIENT), returning 0")); return (0); }
/*
* create our accessibility object */ if ((sc = CTiedComObjectCreator<CTabAccessible>::ScCreateAndConnect(*this, m_spTabAcc)).IsError() || (sc = ScCheckPointers (m_spTabAcc, E_UNEXPECTED)).IsError()) { sc.TraceAndClear(); Trace (tagTabAccessibility, _T("WM_GETOBJECT: error creating IAccessible object, returning 0")); return (0); }
/*
* return a pointer to the IAccessible interface */ Trace (tagTabAccessibility, _T("WM_GETOBJECT: returning IAccessible*")); return (LresultFromObject (IID_IAccessible, wParam, m_spTabAcc)); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::Scget_accParent * * Retrieves the IDispatch interface of the object's parent. *--------------------------------------------------------------------------*/
SC CFolderTabView::Scget_accParent(IDispatch ** ppdispParent) { DECLARE_SC (sc, TEXT("CFolderTabView::Scget_accParent")); Trace (tagTabAccessibility, TEXT("CFolderTabView::Scget_accParent"));
sc = ScCheckPointers (ppdispParent); if(sc) return (sc);
/*
* return the accessibility interface for the OBJID_WINDOW object */ sc = AccessibleObjectFromWindow (m_hWnd, OBJID_WINDOW, IID_IDispatch, (void **)ppdispParent); return (sc); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::Scget_accChildCount * * Retrieves the number of children belonging to this object. *--------------------------------------------------------------------------*/
SC CFolderTabView::Scget_accChildCount(long* pChildCount) { DECLARE_SC (sc, TEXT("CFolderTabView::Scget_accChildCount"));
sc = ScCheckPointers (pChildCount); if(sc) return (sc);
*pChildCount = GetItemCount(); Trace (tagTabAccessibility, TEXT("CFolderTabView::Scget_accChildCount: returning %d"), GetItemCount());
return (sc); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::Scget_accChild * * Retrieves the address of an IDispatch interface for the specified child. *--------------------------------------------------------------------------*/
SC CFolderTabView::Scget_accChild(VARIANT varChildID, IDispatch ** ppdispChild) { DECLARE_SC (sc, TEXT("CFolderTabView::Scget_accChild")); Trace (tagTabAccessibility, TEXT("CFolderTabView::Scget_accChild"));
sc = ScCheckPointers (ppdispChild); if (sc) return (sc);
// init out parameter
(*ppdispChild) = NULL;
sc = ScValidateChildID (varChildID); if(sc) return (sc);
/*
* all children are simple elements exposed through their parent, * not accessible objects in their own right */ sc = S_FALSE;
Trace (tagTabAccessibility, TEXT("returning parent's IDispatch for child %d"), ValueOf(varChildID)); return (sc); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::Scget_accName * * Retrieves the name of the specified object. *--------------------------------------------------------------------------*/
SC CFolderTabView::Scget_accName(VARIANT varChildID, BSTR* pbstrName) { DECLARE_SC (sc, TEXT("CFolderTabView::Scget_accName"));
sc = ScCheckPointers (pbstrName); if(sc) return (sc);
// init out parameter
*pbstrName = NULL;
sc = ScValidateChildID (varChildID); if(sc) return (sc);
/*
* the tab control itself doesn't have a name; otherwise, get the * name of the requested tab */ LONG idChild = ValueOf (varChildID); if (idChild == CHILDID_SELF) { sc = S_FALSE; } else { CFolderTab& tab = GetItem (idChild-1); CComBSTR bstrName (tab.GetText()); *pbstrName = bstrName.Detach(); }
#ifdef DBG
USES_CONVERSION; Trace (tagTabAccessibility, TEXT("CFolderTabView::Scget_accName: child %d, returning \"%s\""), idChild, (*pbstrName) ? W2T(*pbstrName) : _T("<None>")); #endif
return (sc); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::Scget_accValue * * Retrieves the value of the specified object. Not all objects have a value. *--------------------------------------------------------------------------*/
SC CFolderTabView::Scget_accValue(VARIANT varChildID, BSTR* pbstrValue) { DECLARE_SC (sc, TEXT("CFolderTabView::Scget_accValue")); Trace (tagTabAccessibility, TEXT("CFolderTabView::Scget_accValue"));
sc = ScValidateChildID (varChildID); if(sc) return (sc);
/*
* tabs don't have values */ sc = S_FALSE;
return (sc); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::Scget_accDescription * * Retrieves a string that describes the visual appearance of the specified * object. Not all objects have a description. *--------------------------------------------------------------------------*/
SC CFolderTabView::Scget_accDescription(VARIANT varChildID, BSTR* pbstrDescription) { DECLARE_SC (sc, TEXT("CFolderTabView::Scget_accDescription")); Trace (tagTabAccessibility, TEXT("CFolderTabView::Scget_accDescription"));
sc = ScValidateChildID (varChildID); if(sc) return (sc);
/*
* tabs don't have descriptions */ sc = S_FALSE;
return (sc); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::Scget_accRole * * Retrieves information that describes the role of the specified object. *--------------------------------------------------------------------------*/
SC CFolderTabView::Scget_accRole(VARIANT varChildID, VARIANT *pvarRole) { DECLARE_SC (sc, TEXT("CFolderTabView::Scget_accRole")); Trace (tagTabAccessibility, TEXT("CFolderTabView::Scget_accRole"));
sc = ScCheckPointers (pvarRole); if(sc) return (sc);
// init out parameter
VariantInit (pvarRole);
sc = ScValidateChildID (varChildID); if(sc) return (sc);
/*
* the tab control has a "page tab list" role; an individual tab has a * "page tab" role */ V_VT(pvarRole) = VT_I4; V_I4(pvarRole) = (ValueOf (varChildID) == CHILDID_SELF) ? ROLE_SYSTEM_PAGETABLIST : ROLE_SYSTEM_PAGETAB;
return (sc); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::Scget_accState * * Retrieves the current state of the specified object. *--------------------------------------------------------------------------*/
SC CFolderTabView::Scget_accState(VARIANT varChildID, VARIANT *pvarState) { DECLARE_SC (sc, TEXT("CFolderTabView::Scget_accState"));
sc = ScValidateChildID (varChildID); if(sc) return (sc);
LONG idChild = ValueOf (varChildID);
/*
* all items are focusable */ V_VT(pvarState) = VT_I4; V_I4(pvarState) = STATE_SYSTEM_FOCUSABLE;
/*
* is this for a tab? */ if (idChild != CHILDID_SELF) { /*
* all tabs are selectable */ V_I4(pvarState) |= STATE_SYSTEM_SELECTABLE;
/*
* if this is the selected item, give it the selected state */ if ((idChild - 1 /*1-based*/) == GetSelectedItem()) { V_I4(pvarState) |= STATE_SYSTEM_SELECTED;
/*
* if the tab control also has the focus, give the selected * item the focused state as well */ if (m_fHaveFocus) V_I4(pvarState) |= STATE_SYSTEM_FOCUSED; } } else { if (m_fHaveFocus) V_I4(pvarState) |= STATE_SYSTEM_FOCUSED; }
Trace (tagTabAccessibility, TEXT("CFolderTabView::Scget_accState: child %d, returning 0x%08x"), idChild, V_I4(pvarState)); return (sc); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::Scget_accHelp * * Retrieves an object's Help property string. Not all objects need to * support this property. *--------------------------------------------------------------------------*/
SC CFolderTabView::Scget_accHelp(VARIANT varChildID, BSTR* pbstrHelp) { DECLARE_SC (sc, TEXT("CFolderTabView::Scget_accHelp"));
sc = ScCheckPointers (pbstrHelp); if (sc) return (sc);
/*
* no help */ *pbstrHelp = NULL;
sc = ScValidateChildID (varChildID); if (sc) return (sc);
return (sc = S_FALSE); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::Scget_accHelpTopic * * Retrieves the full path of the WinHelp file associated with the specified * object and the identifier of the appropriate topic within that file. Not * all objects need to support this property. *--------------------------------------------------------------------------*/
SC CFolderTabView::Scget_accHelpTopic(BSTR* pbstrHelpFile, VARIANT varChildID, long* pidTopic) { DECLARE_SC (sc, TEXT("CFolderTabView::Scget_accHelpTopic"));
sc = ScCheckPointers (pbstrHelpFile, pidTopic); if (sc) return (sc);
/*
* no help topic */ *pbstrHelpFile = NULL; *pidTopic = 0;
sc = ScValidateChildID (varChildID); if (sc) return (sc);
return (sc = S_FALSE); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::Scget_accKeyboardShortcut * * Retrieves the specified object's shortcut key or access key (also known * as the mnemonic). All objects that have a shortcut key or access key * should support this property. *--------------------------------------------------------------------------*/
SC CFolderTabView::Scget_accKeyboardShortcut(VARIANT varChildID, BSTR* pbstrKeyboardShortcut) { DECLARE_SC (sc, TEXT("CFolderTabView::Scget_accKeyboardShortcut"));
sc = ScCheckPointers (pbstrKeyboardShortcut); if (sc) return (sc);
/*
* no shortcut keys */ *pbstrKeyboardShortcut = NULL;
sc = ScValidateChildID (varChildID); if (sc) return (sc);
return (sc = S_FALSE); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::Scget_accFocus * * Retrieves the object that has the keyboard focus. *--------------------------------------------------------------------------*/
SC CFolderTabView::Scget_accFocus(VARIANT * pvarFocusChild) { DECLARE_SC (sc, TEXT("CFolderTabView::Scget_accFocus"));
sc = ScCheckPointers (pvarFocusChild); if (sc) return (sc);
/*
* if we have the focus, return the (1-based) ID of the selected tab; * otherwise, return VT_EMPTY */ if (m_fHaveFocus) { V_VT(pvarFocusChild) = VT_I4; V_I4(pvarFocusChild) = GetSelectedItem() + 1; Trace (tagTabAccessibility, TEXT("CFolderTabView::Scget_accFocus: returning %d"), V_I4(pvarFocusChild)); } else { V_VT(pvarFocusChild) = VT_EMPTY; Trace (tagTabAccessibility, TEXT("CFolderTabView::Scget_accFocus: returning VT_EMPTY")); }
return (sc); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::Scget_accSelection * * Retrieves the selected children of this object. *--------------------------------------------------------------------------*/
SC CFolderTabView::Scget_accSelection(VARIANT * pvarSelectedChildren) { DECLARE_SC (sc, TEXT("CFolderTabView::Scget_accSelection"));
sc = ScCheckPointers (pvarSelectedChildren); if (sc) return (sc);
/*
* return the (1-based) ID of the selected tab, if there is one */ if (GetSelectedItem() != -1) { V_VT(pvarSelectedChildren) = VT_I4; V_I4(pvarSelectedChildren) = GetSelectedItem() + 1; Trace (tagTabAccessibility, TEXT("CFolderTabView::Scget_accSelection: returning %d"), V_I4(pvarSelectedChildren)); } else { V_VT(pvarSelectedChildren) = VT_EMPTY; Trace (tagTabAccessibility, TEXT("CFolderTabView::Scget_accSelection: returning VT_EMPTY")); }
return (sc); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::Scget_accDefaultAction * * Retrieves a string that describes the object's default action. Not all * objects have a default action. *--------------------------------------------------------------------------*/
SC CFolderTabView::Scget_accDefaultAction(VARIANT varChildID, BSTR* pbstrDefaultAction) { DECLARE_SC (sc, TEXT("CFolderTabView::Scget_accDefaultAction"));
sc = ScCheckPointers (pbstrDefaultAction); if (sc) return (sc);
/*
* default to "no default action" */ *pbstrDefaultAction = NULL;
sc = ScValidateChildID (varChildID); if(sc) return (sc);
/*
* individual tabs have a default action of "Switch", just like WC_TABCONTROL */ if (ValueOf(varChildID) != CHILDID_SELF) { CString strDefaultAction (MAKEINTRESOURCE (IDS_TabAccessiblity_DefaultAction)); CComBSTR bstrDefaultAction (strDefaultAction);
*pbstrDefaultAction = bstrDefaultAction.Detach(); } else { sc = S_FALSE; // no default action
}
#ifdef DBG
USES_CONVERSION; Trace (tagTabAccessibility, TEXT("CFolderTabView::Scget_accDefaultAction: child %d, returning \"%s\""), ValueOf(varChildID), (*pbstrDefaultAction) ? W2T(*pbstrDefaultAction) : _T("<None>")); #endif
return (sc); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::ScaccSelect * * Modifies the selection or moves the keyboard focus of the specified * object. *--------------------------------------------------------------------------*/
SC CFolderTabView::ScaccSelect(long flagsSelect, VARIANT varChildID) { DECLARE_SC (sc, TEXT("CFolderTabView::ScaccSelect")); Trace (tagTabAccessibility, TEXT("CFolderTabView::ScaccSelect"));
sc = ScValidateChildID (varChildID); if(sc) return (sc);
LONG idChild = ValueOf(varChildID);
/*
* can't select the tab control itself, only child elements */ if (idChild == CHILDID_SELF) return (sc = E_INVALIDARG);
/*
* the tab control doesn't support multiple selection, so reject * requests dealing with multiple selection */ const long lInvalidFlags = SELFLAG_EXTENDSELECTION | SELFLAG_ADDSELECTION | SELFLAG_REMOVESELECTION;
if (flagsSelect & lInvalidFlags) return (sc = E_INVALIDARG);
/*
* activate this view, if we're requested to take the focus */ if (flagsSelect & SELFLAG_TAKEFOCUS) { CFrameWnd* pFrame = GetParentFrame(); sc = ScCheckPointers (pFrame, E_FAIL); if (sc) return (sc);
pFrame->SetActiveView (this); }
/*
* select the given tab, if requested */ if (flagsSelect & SELFLAG_TAKESELECTION) { if (SelectItem (idChild - 1 /*0-based*/, true /*bEnsureVisible*/) == -1) return (sc = E_FAIL); }
return (sc); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::ScaccLocation * * Retrieves the specified object's current screen location. *--------------------------------------------------------------------------*/
SC CFolderTabView::ScaccLocation ( long* pxLeft, long* pyTop, long* pcxWidth, long* pcyHeight, VARIANT varChildID) { DECLARE_SC (sc, TEXT("CFolderTabView::ScaccLocation")); Trace (tagTabAccessibility, TEXT("CFolderTabView::ScaccLocation"));
sc = ScCheckPointers (pxLeft, pyTop, pcxWidth, pcyHeight); if(sc) return (sc);
// init out parameters
*pxLeft = *pyTop = *pcxWidth = *pcyHeight = 0;
sc = ScValidateChildID (varChildID); if(sc) return (sc);
LONG idChild = ValueOf(varChildID); CRect rectLocation;
/*
* for the tab control itself, get the location of the entire window */ if (idChild == CHILDID_SELF) GetWindowRect (rectLocation);
/*
* otherwise, get the rectangle of the tab and convert it to screen coords */ else { rectLocation = GetItem(idChild-1).GetRect(); MapWindowPoints (NULL, rectLocation); }
*pxLeft = rectLocation.left; *pyTop = rectLocation.top; *pcxWidth = rectLocation.Width(); *pcyHeight = rectLocation.Height();
return (sc); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::ScaccNavigate * * Traverses to another user interface element within a container and if * possible, retrieves the object. *--------------------------------------------------------------------------*/
SC CFolderTabView::ScaccNavigate (long lNavDir, VARIANT varStart, VARIANT * pvarEndUpAt) { DECLARE_SC (sc, TEXT("CFolderTabView::ScaccNavigate"));
sc = ScCheckPointers (pvarEndUpAt); if (sc) return (sc);
// init out parameters
VariantInit (pvarEndUpAt);
sc = ScValidateChildID (varStart); if (sc) return (sc);
LONG idFrom = ValueOf (varStart); LONG idTo = -1;
Trace (tagTabAccessibility, TEXT("CFolderTabView::ScaccNavigate: start=%d, direction=%d"), idFrom, lNavDir);
switch (lNavDir) { case NAVDIR_UP: case NAVDIR_DOWN: /*
* the tab control doesn't have the concept of up and down, * so there's no screen element in that direction; just leave * idTo == -1 and the code below the switch will take care * of the rest */ break;
case NAVDIR_FIRSTCHILD: case NAVDIR_LASTCHILD: /*
* NAVDIR_FIRSTCHILD and NAVDIR_LASTCHILD must be relative * to CHILDID_SELF */ if (idFrom != CHILDID_SELF) return (sc = E_INVALIDARG);
idTo = (lNavDir == NAVDIR_FIRSTCHILD) ? 1 : GetItemCount(); break;
case NAVDIR_LEFT: case NAVDIR_PREVIOUS: /*
* if we're moving relative to a child element, bump idTo; * if not, just leave idTo == -1 and the code below the switch * will take of the rest */ if (idFrom != CHILDID_SELF) idTo = idFrom - 1; break;
case NAVDIR_RIGHT: case NAVDIR_NEXT: /*
* if we're moving relative to a child element, bump idTo; * if not, just leave idTo == -1 and the code below the switch * will take of the rest */ if (idFrom != CHILDID_SELF) idTo = idFrom + 1; break;
default: return (sc = E_INVALIDARG); break; }
/*
* if we're trying to navigate to an invalid child ID, return "no element * in that direction" */ if ((idTo < 1) || (idTo > GetItemCount())) { V_VT(pvarEndUpAt) = VT_EMPTY; sc = S_FALSE; Trace (tagTabAccessibility, TEXT("CFolderTabView::ScaccNavigate: VT_EMPTY")); }
/*
* otherwise return the new child ID (don't change the selection here; * the client will call IAccessible::accSelect to do that) */ else { V_VT(pvarEndUpAt) = VT_I4; V_I4(pvarEndUpAt) = idTo; Trace (tagTabAccessibility, TEXT("CFolderTabView::ScaccNavigate: end=%d"), idTo); }
return (sc); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::ScaccHitTest * * Retrieves the child element or child object at a given point on the screen. *--------------------------------------------------------------------------*/
SC CFolderTabView::ScaccHitTest (long x, long y, VARIANT* pvarChildAtPoint) { DECLARE_SC (sc, TEXT("CFolderTabView::ScaccHitTest"));
sc = ScCheckPointers (pvarChildAtPoint); if(sc) return (sc);
// init out parameters
VariantInit (pvarChildAtPoint);
/*
* hit-test the given point, converted to client coordinates */ CPoint pt (x, y); ScreenToClient (&pt); int nHitTest = HitTest (pt); Trace (tagTabAccessibility, TEXT("CFolderTabView::ScaccHitTest: x=%d y=%d"), x, y);
/*
* not on a tab? see if it's within the client rect */ if (nHitTest == -1) { CRect rectClient; GetClientRect (rectClient);
if (rectClient.PtInRect (pt)) { V_VT(pvarChildAtPoint) = VT_I4; V_I4(pvarChildAtPoint) = CHILDID_SELF; } else { V_VT(pvarChildAtPoint) = VT_EMPTY; sc = S_FALSE; // no element there
} }
/*
* otherwise, it is on a tab; return the 1-based ID */ else { V_VT(pvarChildAtPoint) = VT_I4; V_I4(pvarChildAtPoint) = nHitTest + 1; }
#ifdef DBG
if (V_VT(pvarChildAtPoint) == VT_I4) Trace (tagTabAccessibility, TEXT("CFolderTabView::ScaccHitTest: returning %d"), ValueOf (*pvarChildAtPoint)); else Trace (tagTabAccessibility, TEXT("CFolderTabView::ScaccHitTest: returning VT_EMPTY")); #endif
return (sc); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::ScaccDoDefaultAction * * Performs the specified object's default action. Not all objects have a * default action. *--------------------------------------------------------------------------*/
SC CFolderTabView::ScaccDoDefaultAction (VARIANT varChildID) { DECLARE_SC (sc, TEXT("CFolderTabView::ScaccDoDefaultAction"));
sc = ScValidateChildID (varChildID); if(sc) return (sc);
/*
* the tab control doesn't have a default action */ LONG idChild = ValueOf (varChildID); Trace (tagTabAccessibility, TEXT("CFolderTabView::ScaccDoDefaultAction: child %d"), idChild); if (idChild == CHILDID_SELF) return (sc = E_INVALIDARG);
/*
* select the given tab item */ if (SelectItem (idChild - 1 /*0-based*/, true /*bEnsureVisible*/) == -1) return (sc = E_FAIL);
return (sc); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::Scput_accName * * This is no longer supported. The SetWindowText or control-specific APIs * should be used in place of this method. *--------------------------------------------------------------------------*/
SC CFolderTabView::Scput_accName(VARIANT varChildID, BSTR bstrName) { DECLARE_SC (sc, TEXT("CFolderTabView::Scput_accName"));
sc = ScValidateChildID (varChildID); if (sc) return (sc);
return (sc = E_NOTIMPL); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::Scput_accValue * * This is no longer supported. Control-specific APIs should be used in * place of this method. *--------------------------------------------------------------------------*/
SC CFolderTabView::Scput_accValue(VARIANT varChildID, BSTR bstrValue) { DECLARE_SC (sc, TEXT("CFolderTabView::Scput_accValue"));
sc = ScValidateChildID (varChildID); if (sc) return (sc);
return (sc = E_NOTIMPL); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::ScValidateChildID * * Determines if the supplied variant represents a valid child ID. *--------------------------------------------------------------------------*/
SC CFolderTabView::ScValidateChildID (VARIANT &var) { DECLARE_SC (sc, TEXT("CFolderTabView::ScValidateChildID"));
/*
* child IDs must be VT_I4's */ if (V_VT(&var) != VT_I4) return (sc = E_INVALIDARG);
return (ScValidateChildID (ValueOf(var))); }
/*+-------------------------------------------------------------------------*
* CFolderTabView::ScValidateChildID * * Determines if the supplied ID is valid child ID. *--------------------------------------------------------------------------*/
SC CFolderTabView::ScValidateChildID (LONG idChild) { DECLARE_SC (sc, TEXT("CFolderTabView::ScValidateChildID"));
/*
* child ID must be either CHILDID_SELF or a valid tab index */ if ((idChild < CHILDID_SELF) || (idChild > GetItemCount())) return (sc = E_INVALIDARG);
return (sc); }
|