// TrayControlCtl.cpp : Implementation of the CTrayControlCtrl ActiveX Control class.
#include "stdafx.h"
#include "TrayControl.h"
#include "TrayControlCtl.h"
#include "TrayControlPpg.h"
#include "MemDC.h"
#include "ColorNames.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNCREATE(CTrayControlCtrl, COleControl)
// from the colourNames posted on CodeProject by Ales Krajnc see url http://www.codeproject.com/gdi/colornames.asp
// set up a table of colours I like
COLORREF default_colours[] =
{
colWhite,
colBlue,
colDarkGreen,
colRed,
colYellow,
colSlateGray,
colCyan,
colPurple,
colRoyalBlue,
colBrown,
colGreen,
colGoldenRod,
colLightSalmon,
colSlateBlue,
colDarkKhaki,
colNavyblue,
colPowderBlue,
colDarkSeaGreen,
colLightGrey,
colLightPink,
colSandyBrown
} ;
/////////////////////////////////////////////////////////////////////////////
// Message map
BEGIN_MESSAGE_MAP(CTrayControlCtrl, COleControl)
//{{AFX_MSG_MAP(CTrayControlCtrl)
ON_WM_SETFOCUS()
ON_WM_KILLFOCUS()
ON_WM_MOUSEMOVE()
ON_WM_ERASEBKGND()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_TIMER()
ON_WM_LBUTTONDBLCLK()
ON_WM_RBUTTONDOWN()
//}}AFX_MSG_MAP
ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// Dispatch map
BEGIN_DISPATCH_MAP(CTrayControlCtrl, COleControl)
//{{AFX_DISPATCH_MAP(CTrayControlCtrl)
DISP_PROPERTY_EX(CTrayControlCtrl, "XSize", GetXSize, SetXSize, VT_I4)
DISP_PROPERTY_EX(CTrayControlCtrl, "YSize", GetYSize, SetYSize, VT_I4)
DISP_PROPERTY_EX(CTrayControlCtrl, "ShowCellTitles", GetShowCellTitles, SetShowCellTitles, VT_I4)
DISP_PROPERTY_EX(CTrayControlCtrl, "ShowLabels", GetShowLabels, SetShowLabels, VT_I4)
DISP_PROPERTY_EX(CTrayControlCtrl, "XLabelsAlpha", GetXLabelsAlpha, SetXLabelsAlpha, VT_I4)
DISP_PROPERTY_EX(CTrayControlCtrl, "YLabelsAlpha", GetYLabelsAlpha, SetYLabelsAlpha, VT_I4)
DISP_PROPERTY_EX(CTrayControlCtrl, "TrayOrieintation", GetTrayOrieintation, SetTrayOrieintation, VT_I4)
DISP_FUNCTION(CTrayControlCtrl, "EnableDoubleBuffering", EnableDoubleBuffering, VT_I4, VTS_I4)
DISP_FUNCTION(CTrayControlCtrl, "GetSampleName", GetSampleName, VT_BSTR, VTS_I4)
DISP_FUNCTION(CTrayControlCtrl, "GetSampleColourIndex", GetSampleColourIndex, VT_I4, VTS_I4)
DISP_FUNCTION(CTrayControlCtrl, "GetColourRGB", GetColourRGB, VT_I4, VTS_I4)
DISP_FUNCTION(CTrayControlCtrl, "SetColourRGB", SetColourRGB, VT_I4, VTS_I4 VTS_I4)
DISP_FUNCTION(CTrayControlCtrl, "SetSampleName", SetSampleName, VT_I4, VTS_I4 VTS_BSTR)
DISP_FUNCTION(CTrayControlCtrl, "SetSampleColour", SetSampleColour, VT_I4, VTS_I4 VTS_I4)
DISP_FUNCTION(CTrayControlCtrl, "SetSampleCellCount", SetSampleCellCount, VT_EMPTY, VTS_I4 VTS_I4)
DISP_FUNCTION(CTrayControlCtrl, "GetSampleCellCount", GetSampleCellCount, VT_I4, VTS_I4)
DISP_FUNCTION(CTrayControlCtrl, "EnableTitleTips", EnableTitleTips, VT_EMPTY, VTS_I4)
DISP_FUNCTION(CTrayControlCtrl, "EnableCherryPicking", EnableCherryPicking, VT_EMPTY, VTS_I4)
DISP_FUNCTION(CTrayControlCtrl, "GetCherryCount", GetCherryCount, VT_I4, VTS_NONE)
DISP_FUNCTION(CTrayControlCtrl, "GetCherryIndex", GetCherryIndex, VT_I4, VTS_I4)
DISP_FUNCTION(CTrayControlCtrl, "RemoveAll", RemoveAll, VT_EMPTY, VTS_NONE)
DISP_FUNCTION(CTrayControlCtrl, "SetFlashState", SetFlashState, VT_EMPTY, VTS_I4)
DISP_FUNCTION(CTrayControlCtrl, "SetFlashIndex", SetFlashIndex, VT_EMPTY, VTS_I4)
DISP_FUNCTION(CTrayControlCtrl, "SetFlashRate", SetFlashRate, VT_EMPTY, VTS_I4)
DISP_FUNCTION(CTrayControlCtrl, "SetSelectionState", SetSelectionState, VT_EMPTY, VTS_I4)
DISP_FUNCTION(CTrayControlCtrl, "GetSampleIndex", GetSampleIndex, VT_I4, VTS_NONE)
DISP_FUNCTION(CTrayControlCtrl, "AddSample", AddSample, VT_BOOL, VTS_BSTR VTS_I4)
DISP_FUNCTION(CTrayControlCtrl, "SetSampleIndex", SetSampleIndex, VT_EMPTY, VTS_I4)
DISP_FUNCTION(CTrayControlCtrl, "SetShowNextInsertPosition", SetShowNextInsertPosition, VT_EMPTY, VTS_I4)
DISP_FUNCTION(CTrayControlCtrl, "GetPositionLabel", GetPositionLabel, VT_BSTR, VTS_I4)
//}}AFX_DISPATCH_MAP
DISP_FUNCTION_ID(CTrayControlCtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
END_DISPATCH_MAP()
/////////////////////////////////////////////////////////////////////////////
// Event map
BEGIN_EVENT_MAP(CTrayControlCtrl, COleControl)
//{{AFX_EVENT_MAP(CTrayControlCtrl)
EVENT_CUSTOM("ControlClicked", FireControlClicked, VTS_I4)
EVENT_CUSTOM("CherryPicked", FireCherryPicked, VTS_NONE)
EVENT_CUSTOM("InsertPointChanged", FireInsertPointChanged, VTS_NONE)
EVENT_CUSTOM("ControlRightClicked", FireControlRightClicked, VTS_I4)
//}}AFX_EVENT_MAP
END_EVENT_MAP()
/////////////////////////////////////////////////////////////////////////////
// Property pages
// TODO: Add more property pages as needed. Remember to increase the count!
BEGIN_PROPPAGEIDS(CTrayControlCtrl, 1)
PROPPAGEID(CTrayControlPropPage::guid)
END_PROPPAGEIDS(CTrayControlCtrl)
/////////////////////////////////////////////////////////////////////////////
// Initialize class factory and guid
IMPLEMENT_OLECREATE_EX(CTrayControlCtrl, "TRAYCONTROL.TrayControlCtrl.1",
0x80ab393a, 0x6f9f, 0x11d5, 0xad, 0x35, 0, 0xb0, 0xd0, 0x65, 0x2e, 0x95)
/////////////////////////////////////////////////////////////////////////////
// Type library ID and version
IMPLEMENT_OLETYPELIB(CTrayControlCtrl, _tlid, _wVerMajor, _wVerMinor)
/////////////////////////////////////////////////////////////////////////////
// Interface IDs
const IID BASED_CODE IID_DTrayControl =
{ 0x80ab3938, 0x6f9f, 0x11d5, { 0xad, 0x35, 0, 0xb0, 0xd0, 0x65, 0x2e, 0x95 } };
const IID BASED_CODE IID_DTrayControlEvents =
{ 0x80ab3939, 0x6f9f, 0x11d5, { 0xad, 0x35, 0, 0xb0, 0xd0, 0x65, 0x2e, 0x95 } };
/////////////////////////////////////////////////////////////////////////////
// Control type information
static const DWORD BASED_CODE _dwTrayControlOleMisc =
OLEMISC_ACTIVATEWHENVISIBLE |
OLEMISC_IGNOREACTIVATEWHENVISIBLE |
OLEMISC_SETCLIENTSITEFIRST |
OLEMISC_INSIDEOUT |
OLEMISC_CANTLINKINSIDE |
OLEMISC_RECOMPOSEONRESIZE;
IMPLEMENT_OLECTLTYPE(CTrayControlCtrl, IDS_TRAYCONTROL, _dwTrayControlOleMisc)
/////////////////////////////////////////////////////////////////////////////
// CTrayControlCtrl::CTrayControlCtrlFactory::UpdateRegistry -
// Adds or removes system registry entries for CTrayControlCtrl
BOOL CTrayControlCtrl::CTrayControlCtrlFactory::UpdateRegistry(BOOL bRegister)
{
// TODO: Verify that your control follows apartment-model threading rules.
// Refer to MFC TechNote 64 for more information.
// If your control does not conform to the apartment-model rules, then
// you must modify the code below, changing the 6th parameter from
// afxRegApartmentThreading to 0.
if (bRegister)
return AfxOleRegisterControlClass(
AfxGetInstanceHandle(),
m_clsid,
m_lpszProgID,
IDS_TRAYCONTROL,
IDB_TRAYCONTROL,
afxRegApartmentThreading,
_dwTrayControlOleMisc,
_tlid,
_wVerMajor,
_wVerMinor);
else
return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
}
/////////////////////////////////////////////////////////////////////////////
// CTrayControlCtrl::CTrayControlCtrl - Constructor
CTrayControlCtrl::CTrayControlCtrl()
{
InitializeIIDs(&IID_DTrayControl, &IID_DTrayControlEvents);
// setup properties
m_xSize = 12 ;
m_ySize = 8 ;
m_bHasFocus = false ;
m_bShowLabels = false ;
m_bXAxisAlpha = true ;
m_bYAxisAlpha = false ;
m_bTitleTipsEnabled = false ;
m_TitleTipIndex = CPoint(-1, -1) ;
m_bDoubleBuffering = false ;
m_bCherryPicking = false ;
m_bCherryDrag = false ;
m_CherryIndex = -1 ;
m_bTracking = false ;
m_bDrawTracker = false ;
m_bAutoChooseLabels = true ;
// setup sample colour infromation
m_pColourIndexes = new int[m_xSize * m_ySize] ;
memset(m_pColourIndexes, 0, sizeof(int) * m_xSize * m_ySize) ;
// setup samples selection information
m_bSelected = new bool[m_xSize * m_ySize] ;
memset(m_bSelected, 0, sizeof(bool) * m_xSize * m_ySize) ;
// setup the ocunt indexes
m_Count = new int[m_xSize * m_ySize] ;
memset(m_Count, 0, sizeof(int) * m_xSize * m_ySize) ;
// setup sample name information
m_Names = new CString[m_xSize * m_ySize] ;
// put in 3 example samples for use when placing the control in a resource editor or using the ActiveX text container
m_Names[0] = "Example 1" ;
m_Names[1] = "Example 2" ;
m_Names[2] = "Example 3" ;
// setup colour table infromation
m_NumColours = sizeof(default_colours) / sizeof(COLORREF) ;
m_pColours = new COLORREF[m_NumColours] ;
memcpy(m_pColours, default_colours, sizeof(COLORREF) * m_NumColours) ;
m_orientation = RightDown ;
// example counts for resource editor in VC etc
m_Count[0] = 3 ;
m_Count[1] = 2 ;
m_Count[2] = 1 ;
// flashing
m_Timer = 0 ;
m_bFlashing = false ;
m_FlashingIndex = -1 ;
m_bFlashOn = false ;
m_FlashRate = 500 ; // ms
m_bSelectionState = false ;
m_SampleIndex = 0 ;
m_bShowSampleIndex = false ;
}
/////////////////////////////////////////////////////////////////////////////
// CTrayControlCtrl::~CTrayControlCtrl - Destructor
CTrayControlCtrl::~CTrayControlCtrl()
{
// release any memory used
delete []m_bSelected ;
delete []m_Names ;
delete []m_pColours ;
delete []m_pColourIndexes ;
delete []m_Count ;
}
/////////////////////////////////////////////////////////////////////////////
// CTrayControlCtrl::OnDraw - Drawing function
void CTrayControlCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
CRect rect ;
// KNOWN PROBLEM : If the activeX control is in a from view and is not completely visible when being drawn,
// when it receives the focus, we get an invalid size reported to us, so the control thinks its window area is
// only the visible area of the control. THis only happens when the control gets the focus the first time. I have
// spent a long time looking for a fix for this, but no joy! Sob Sob!
GetWindowRect(&rect) ; // get size of window to know to draw in, I don;t trust the passed rcBounds!
rect -= rect.TopLeft() ;
// NOTE : I had by default to set double buffereing to false as the control would not draw in a resource editor
// it set to true. Not sure why this happens.
if (m_bDoubleBuffering) // use memDC for flicker free drawing? (Thanks to Keith Ruls)
{
CMemDC dc(pdc, rcBounds) ; // save / restoreDC build into constructor destructor
DoDraw(&dc, rcBounds, rcInvalid) ;
}
else
DoDraw(pdc, rcBounds, rcInvalid) ; // not souble buffered
}
void CTrayControlCtrl::DoDraw(CDC *pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
// stage 1 : Calculate the size the cells can be to fit in the given location
if (m_SampleIndex >= m_xSize * m_ySize)
{
// make sure the sample index is in the correct range
m_SampleIndex = m_xSize * m_ySize - 1 ;
FireInsertPointChanged() ;
}
pdc->SetMapMode(MM_TEXT) ;
pdc->SetBkMode(TRANSPARENT) ;
int x_size ;
int y_size ;
CString text ;
CSize csText ;
CFont local_font ;
// are we shown x,y labels for cell? If we are, count it as another column/row when calculating the cell size
if (m_bShowLabels)
{
// title tips if enabled also use another row
if (m_bTitleTipsEnabled)
{
x_size = rcBounds.Width() / (m_xSize + 1) ; // 1 column for labels
y_size = rcBounds.Height() / (m_ySize + 2) ; // 1 column for labels + 1 column for title tip
}
else
{
x_size = rcBounds.Width() / (m_xSize + 1) ; // 1 column for labels
y_size = rcBounds.Height() / (m_ySize + 1) ; // 1 column for labels
}
}
else
{
// just he cells to be shown, possible title tips as well
x_size = rcBounds.Width() / m_xSize ;
if (m_bTitleTipsEnabled)
y_size = rcBounds.Height() / (m_ySize + 1) ; // 1 column for labels + 1 column for title tip
else
y_size = rcBounds.Height() / m_ySize ;
}
m_cell_size = x_size ; // save the pixel size of the cells
if (y_size < m_cell_size) // us ethe samllest x,y size to keep cells square
m_cell_size = y_size ;
// make sure that the font text fits the size of the cell
// we need to set the size of the font being used
LOGFONT lf ;
memset(&lf, 0, sizeof(LOGFONT)) ;
lf.lfHeight = m_cell_size - 1 ;
lf.lfWidth = 0 ;
lf.lfWeight = FW_NORMAL ;
lf.lfCharSet = DEFAULT_CHARSET ;
lf.lfClipPrecision = CLIP_CHARACTER_PRECIS ;
lf.lfEscapement = 0 ;
lf.lfItalic = FALSE ;
lf.lfOrientation = 0L ;
lf.lfOutPrecision = OUT_TT_PRECIS ;
lf.lfPitchAndFamily = FF_ROMAN ;
lf.lfQuality = DEFAULT_QUALITY ;
strcpy(lf.lfFaceName, "Arial") ; // I use the Arial font, but you don't have to!
local_font.CreateFontIndirect(&lf) ;
pdc->SelectObject(&local_font) ;
// make sure there is space for the border around the tray
if (m_cell_size * m_xSize + 4 > rcBounds.Width())
m_cell_size-- ;
else if (m_cell_size * m_ySize + 4 > rcBounds.Height())
m_cell_size-- ;
// generate the bounding rectangle of the control
m_actual = CRect(0, 0, 0, 0) ;
CRect cell_rect ;
m_actual.right = m_cell_size * m_xSize + 4 - 1 ;
m_actual.bottom = m_cell_size * m_ySize + 4 - 1 ;
if (m_bShowLabels)
{
if (m_bTitleTipsEnabled)
m_actual += CSize((rcBounds.Width() - m_actual.Width() + m_cell_size) / 2,(rcBounds.Height() - m_actual.Height()) / 2);
else
m_actual += CSize((rcBounds.Width() - m_actual.Width() + m_cell_size) / 2,(rcBounds.Height() - m_actual.Height() + m_cell_size) / 2);
}
else
{
if (m_bTitleTipsEnabled)
m_actual += CSize((rcBounds.Width() - m_actual.Width()) / 2,(rcBounds.Height() - m_actual.Height() - m_cell_size) / 2);
else
m_actual += CSize((rcBounds.Width() - m_actual.Width()) / 2,(rcBounds.Height() - m_actual.Height()) / 2) ;
}
// stage 2 : draw the tray border as a 3D rect
// prepare the DC for drawing
CBrush background_brush ;
CBrush *old_brush ;
CBrush selected_brush ;
// if the control is in a selected state, draw everything in reverse colours
if (m_bSelectionState)
{
selected_brush.CreateSolidBrush(GetSysColor(COLOR_3DFACE)) ;
background_brush.CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT)) ;
pdc->SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT)) ;
}
else
{
selected_brush.CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT)) ;
background_brush.CreateSolidBrush(GetSysColor(COLOR_3DFACE)) ;
pdc->SetTextColor(GetSysColor(COLOR_WINDOWTEXT)) ;
}
old_brush = (CBrush*)pdc->SelectObject(&background_brush) ;
pdc->FillRect(rcBounds, &background_brush);
// draw focus rectangle if we have the focus
if (m_bHasFocus)
pdc->DrawFocusRect(&rcBounds) ;
pdc->Draw3dRect(&m_actual, GetSysColor(COLOR_3DHILIGHT), GetSysColor(COLOR_3DSHADOW)) ; // actual tray border drawn here
// draw the cells
for (int i = 0 ; i < m_xSize ; i++)
{
cell_rect.left = 2 + i * m_cell_size + m_actual.left ;
cell_rect.right = 2 + i * m_cell_size + m_cell_size - 1 + m_actual.left ;
if (m_bShowLabels)
{
// show the x (column) labels
text = GetXLabelText(i) ; // get the column text
csText = pdc->GetTextExtent(text) ;
pdc->TextOut(cell_rect.left + (m_cell_size - csText.cx) / 2, m_actual.top - m_cell_size + (m_cell_size - csText.cy) / 2, text) ;
}
for (int j = 0 ; j < m_ySize ; j++)
{
cell_rect.top = 2 + j * m_cell_size + m_actual.top ;
cell_rect.bottom = 2 + j * m_cell_size + m_cell_size - 1 + m_actual.top ;
if (m_bShowLabels && i == 0)
{
// only draw the y (row) labels on the first pass if required
text = GetYLabelText(j) ; // get the row text
csText = pdc->GetTextExtent(text) ;
pdc->TextOut(m_actual.left - m_cell_size + (m_cell_size - csText.cx) / 2, cell_rect.top + (m_cell_size - csText.cy) / 2, text) ;
}
int index = GetOrientationIndex(i + j * m_xSize) ;
if (!m_bFlashing || !m_bFlashOn || index != m_FlashingIndex)
{
if (m_bSelected[index])
{
//pdc->Draw3dRect(&cell_rect, GetSysColor(COLOR_3DSHADOW), GetSysColor(COLOR_3DHILIGHT)) ;
// fill the inside of the rect with the selected colour, as its in a selected state
pdc->FillRect(&cell_rect, &selected_brush) ;
}
else
pdc->Draw3dRect(&cell_rect, GetSysColor(COLOR_3DHILIGHT), GetSysColor(COLOR_3DSHADOW)) ;
}
else
{
// show the flash state
CBrush brush ;
brush.CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT)) ;
pdc->FillRect(&cell_rect, &brush) ;
VERIFY(brush.DeleteObject()) ;
}
if (m_TitleTipIndex == CPoint(i, j))
{
// draw a focus around the cell under the mouse if shown title tips
CRect focus(cell_rect) ;
focus.InflateRect(1, 1, 1, 1) ;
pdc->DrawFocusRect(focus) ;
}
if (m_bShowSampleIndex && m_SampleIndex == index)
{
// draw a red square around the next insert position if shown
CRect hilight(cell_rect) ;
CPen pen(PS_SOLID, 1, colRed) ;
CPen *old = pdc->SelectObject(&pen) ;
hilight.InflateRect(1, 1, 0, 0) ;
pdc->MoveTo(hilight.TopLeft()) ;
pdc->LineTo(hilight.right, hilight.top) ;
pdc->LineTo(hilight.BottomRight()) ;
pdc->LineTo(hilight.left, hilight.bottom) ;
pdc->LineTo(hilight.TopLeft()) ;
pdc->SelectObject(old) ;
}
if (m_Names[index] != "")
{
// if the name is not blank, show a sample in this position
CRect circle(cell_rect) ;
CBrush brush(m_pColours[m_pColourIndexes[index]]) ;
CBrush *pOld = pdc->SelectObject(&brush) ;
circle.DeflateRect(1, 1) ;
pdc->Ellipse(circle) ;
pdc->SelectObject(pOld) ;
if (m_Count[index] > 0)
{
// show number in cell if != 0
text.Format("%1d", m_Count[index]) ;
csText = pdc->GetTextExtent(text) ;
pdc->TextOut(cell_rect.left + cell_rect.Width() / 2 - csText.cx / 2,
cell_rect.top + cell_rect.Height() / 2 - csText.cy / 2,
text) ;
}
}
}
}
if (m_bDrawTracker)
{
// we only draw the tracker if the user is dragging a cherry pick selection
CPoint point ;
GetCursorPos(&point) ;
ScreenToClient(&point) ;
CRect rect(m_TrackerStart, point) ;
rect.NormalizeRect() ; // make sure the rect draws correctly
pdc->DrawFocusRect(&rect) ;
}
if (m_bTitleTipsEnabled && m_TitleTipIndex.x >= 0)
{
// display the title tip text
text = "" ;
if (m_bShowLabels)
text = GetCellLabel(m_TitleTipIndex) ;
text += m_Names[GetOrientationIndex(m_TitleTipIndex.x + m_TitleTipIndex.y * m_xSize)] ;
csText = pdc->GetTextExtent(text) ;
pdc->TextOut((rcBounds.Width() - csText.cx) / 2, m_actual.bottom, text) ;
}
// restore the DC
pdc->SelectObject(old_brush) ;
VERIFY(local_font.DeleteObject()) ;
VERIFY(selected_brush.DeleteObject()) ;
VERIFY(background_brush.DeleteObject()) ;
}
/////////////////////////////////////////////////////////////////////////////
// CTrayControlCtrl::DoPropExchange - Persistence support
void CTrayControlCtrl::DoPropExchange(CPropExchange* pPX)
{
ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
COleControl::DoPropExchange(pPX);
long x = m_xSize ;
long y = m_ySize ;
PX_Long(pPX, _T("XSize"), x, 12);
PX_Long(pPX, _T("YSize"), y, 8);
PX_Long(pPX, _T("ShowCellTitles"), m_bTitleTipsEnabled, TRUE);
PX_Long(pPX, _T("ShowLabels"), m_bShowLabels, TRUE);
PX_Long(pPX, _T("XLabelsAlpha"), m_bXAxisAlpha, TRUE);
PX_Long(pPX, _T("YLabelsAlpha"), m_bYAxisAlpha, FALSE);
PX_Long(pPX, _T("TrayOrieintation"), m_orientation, FALSE);
SetXSize(x) ; // done this way to keep things in sync
SetYSize(y) ;
}
/////////////////////////////////////////////////////////////////////////////
// CTrayControlCtrl::GetControlFlags -
// Flags to customize MFC's implementation of ActiveX controls.
//
// For information on using these flags, please see MFC technical note
// #nnn, "Optimizing an ActiveX Control".
DWORD CTrayControlCtrl::GetControlFlags()
{
DWORD dwFlags = COleControl::GetControlFlags();
// The control can receive mouse notifications when inactive.
// TODO: if you write handlers for WM_SETCURSOR and WM_MOUSEMOVE,
// avoid using the m_hWnd member variable without first
// checking that its value is non-NULL.
dwFlags |= pointerInactive;
return dwFlags;
}
/////////////////////////////////////////////////////////////////////////////
// CTrayControlCtrl::OnResetState - Reset control to default state
void CTrayControlCtrl::OnResetState()
{
COleControl::OnResetState(); // Resets defaults found in DoPropExchange
// TODO: Reset any other control state here.
}
/////////////////////////////////////////////////////////////////////////////
// CTrayControlCtrl::AboutBox - Display an "About" box to the user
void CTrayControlCtrl::AboutBox()
{
CDialog dlgAbout(IDD_ABOUTBOX_TRAYCONTROL);
dlgAbout.DoModal();
}
/////////////////////////////////////////////////////////////////////////////
// CTrayControlCtrl message handlers
void CTrayControlCtrl::OnSetFocus(CWnd* pOldWnd)
{
COleControl::OnSetFocus(pOldWnd);
// we have been given the focus
m_bHasFocus = true ;
Invalidate() ;
}
void CTrayControlCtrl::OnKillFocus(CWnd* pNewWnd)
{
COleControl::OnKillFocus(pNewWnd);
// we have lost the focus
m_bHasFocus = false ;
Invalidate() ;
}
BOOL CTrayControlCtrl::OnEraseBkgnd(CDC* pDC)
{
// return false so the control does not flash when being redrawn etc
return FALSE ;
//return COleControl::OnEraseBkgnd(pDC);
}
long CTrayControlCtrl::GetXSize()
{
return m_xSize ;
}
void CTrayControlCtrl::SetXSize(long nNewValue)
{
if (nNewValue == m_xSize)
return ;
if (nNewValue < 1)
nNewValue = 1 ; // stop bad programmers!
// allocate the new hilight bool buffer
bool *pBuffer = new bool[nNewValue * m_ySize] ;
memset(pBuffer, FALSE, sizeof(bool) * nNewValue * m_ySize) ;
// copy as much of the old selected data that will fit
if (m_xSize <= nNewValue)
memcpy(pBuffer, m_bSelected, m_xSize * m_ySize * sizeof(bool)) ;
else
memcpy(pBuffer, m_bSelected, nNewValue * m_ySize * sizeof(bool)) ;
delete []m_bSelected ;
m_bSelected = pBuffer ;
SetModifiedFlag();
// change the size of the m_Names array as well
CString *pNames = new CString[nNewValue * m_ySize] ;
for (int i = 0 ; i < nNewValue * m_ySize && i < m_xSize * m_ySize ; i++)
pNames[i] = m_Names[i] ; // copy across existing names
delete []m_Names ;
m_Names = pNames ;
// update colour indexes
int *pColours = new int[nNewValue * m_ySize] ;
memset(pColours, 0, sizeof(int) * nNewValue * m_ySize) ;
for (i = 0 ; i < nNewValue * m_ySize && i < m_xSize * m_ySize ; i++)
pColours[i] = m_pColourIndexes[i] ;
delete []m_pColourIndexes ;
m_pColourIndexes = pColours ;
// update count indexes
int *pCount = new int[nNewValue * m_ySize] ;
memset(pCount, 0, sizeof(int) * nNewValue * m_ySize) ;
for (i = 0 ; i < nNewValue * m_ySize && i < m_xSize * m_ySize ; i++)
pCount[i] = m_Count[i] ;
delete []m_Count ;
m_Count = pCount ;
// update the size of the tray
m_xSize = nNewValue ;
if (m_bAutoChooseLabels)
{
switch (nNewValue)
{
default : // all other types are numeric
case 12 : SetXLabelsAlpha(FALSE) ; // labels are numeric
break ;
case 8 : SetXLabelsAlpha(TRUE) ; // labels are alpha
break ;
}
}
if (m_hWnd) // in case our window does not exist!
Invalidate() ;
}
long CTrayControlCtrl::GetYSize()
{
return m_ySize ;
}
void CTrayControlCtrl::SetYSize(long nNewValue)
{
if (nNewValue == m_ySize)
return ;
if (nNewValue < 1)
nNewValue = 1 ; // stop bad programmers!
// allocate the new hilight bool buffer
bool *pBuffer = new bool[m_xSize * nNewValue] ;
memset(pBuffer, FALSE, sizeof(bool) * m_xSize * nNewValue) ;
// copy as much of the old selected data that will fit
if (m_ySize <= nNewValue)
memcpy(pBuffer, m_bSelected, m_xSize * m_ySize * sizeof(bool)) ;
else
memcpy(pBuffer, m_bSelected, m_xSize * nNewValue * sizeof(bool)) ;
delete []m_bSelected ;
m_bSelected = pBuffer ;
SetModifiedFlag();
// change the size of the m_Names array as well
CString *pNames = new CString[m_xSize * nNewValue] ;
for (int i = 0 ; i < m_xSize * nNewValue && i < m_xSize * m_ySize ; i++)
pNames[i] = m_Names[i] ; // copy across existing names
delete []m_Names ;
m_Names = pNames ;
// update colour indexes
int *pColours = new int[m_xSize * nNewValue] ;
memset(pColours, 0, sizeof(int) * m_xSize * nNewValue) ;
for (i = 0 ; i < m_xSize * nNewValue && i < m_xSize * m_ySize ; i++)
pColours[i] = m_pColourIndexes[i] ;
delete []m_pColourIndexes ;
m_pColourIndexes = pColours ;
// update the count indexes
int *pCount = new int[m_xSize * nNewValue] ;
memset(pCount, 0, sizeof(int) * m_xSize * nNewValue) ;
for (i = 0 ; i < m_xSize * nNewValue && i < m_xSize * m_ySize ; i++)
pCount[i] = m_Count[i] ;
delete []m_Count ;
m_Count = pCount ;
// update the size of the tray
m_ySize = nNewValue ;
if (m_bAutoChooseLabels)
{
switch (nNewValue)
{
default : // all other types are numeric
case 12 : SetYLabelsAlpha(FALSE) ; // labels are numeric
break ;
case 8 : SetYLabelsAlpha(TRUE) ; // labels are alpha
break ;
}
}
if (m_hWnd) // in case our window does not exist
Invalidate() ;
}
long CTrayControlCtrl::GetShowCellTitles()
{
return m_bTitleTipsEnabled ;
}
void CTrayControlCtrl::SetShowCellTitles(long nNewValue)
{
if (nNewValue == (long)m_bTitleTipsEnabled)
return ;
SetModifiedFlag();
m_bTitleTipsEnabled = nNewValue > 0 ? 1 : 0 ;
Invalidate() ;
}
long CTrayControlCtrl::GetShowLabels()
{
return m_bShowLabels ;
}
void CTrayControlCtrl::SetShowLabels(long nNewValue)
{
if (nNewValue == (long)m_bShowLabels)
return ;
SetModifiedFlag();
m_bShowLabels = nNewValue > 0 ? 1 : 0 ;
Invalidate() ;
}
long CTrayControlCtrl::GetXLabelsAlpha()
{
return m_bXAxisAlpha ;
}
void CTrayControlCtrl::SetXLabelsAlpha(long nNewValue)
{
if (nNewValue == (long)m_bXAxisAlpha)
return ;
SetModifiedFlag();
m_bXAxisAlpha = nNewValue > 0 ? 1 : 0 ;
Invalidate() ;
}
long CTrayControlCtrl::GetYLabelsAlpha()
{
return m_bYAxisAlpha ;
}
void CTrayControlCtrl::SetYLabelsAlpha(long nNewValue)
{
if (nNewValue == (long)m_bYAxisAlpha)
return ;
SetModifiedFlag();
m_bYAxisAlpha = nNewValue > 0 ? 1 : 0 ;
Invalidate() ;
}
long CTrayControlCtrl::EnableDoubleBuffering(long double_buffer)
{
long old = m_bDoubleBuffering ;
m_bDoubleBuffering = double_buffer > 0 ? true : false ;
return old ;
}
BSTR CTrayControlCtrl::GetSampleName(long sample_index)
{
CString strResult;
if (sample_index < 0 || sample_index >= m_xSize * m_ySize)
strResult = "Error, sample index out of range" ;
else
strResult = m_Names[sample_index] ;
return strResult.AllocSysString();
}
long CTrayControlCtrl::GetSampleColourIndex(long sample_index)
{
if (sample_index >= 0 && sample_index < m_xSize * m_ySize)
{
// its a valid index, return the value
return (long)m_pColourIndexes[sample_index] ;
}
return 0; // invalid index passed to us
}
long CTrayControlCtrl::GetColourRGB(long colour_index)
{
if (colour_index >= 0 && colour_index < m_NumColours)
{
// its a valid index, return the value
return (long)m_pColours[colour_index] ;
}
return (long)m_pColours[0] ; // invalid index, just return first colour
}
long CTrayControlCtrl::SetColourRGB(long colour_index, long colour_rgb)
{
COLORREF old = 0L ;
if (colour_index >= 0 && colour_index < m_NumColours)
{
old = m_pColours[colour_index] ;
m_pColours[colour_index] = (COLORREF)colour_rgb ;
// need to re-draw the control
Invalidate() ;
}
return old; // return old colour in case they need to know what it was
}
long CTrayControlCtrl::SetSampleName(long sample_index, LPCTSTR sample_name)
{
if (sample_index >= 0 && sample_index < m_xSize * m_ySize)
{
m_Names[sample_index] = sample_name ; // take a copy of the name
Invalidate() ; // re-draw the control
return TRUE ; // success
}
return FALSE ; // failure
}
long CTrayControlCtrl::SetSampleColour(long sample_index, long colour_index)
{
int old = 0 ;
// set the colour index for the given position
if (sample_index >= 0 && sample_index < m_xSize * m_ySize)
{
if (colour_index < 0 || colour_index >= m_NumColours)
colour_index = 0 ; // keep in range
old = m_pColourIndexes[sample_index] ;
m_pColourIndexes[sample_index] = colour_index ;
Invalidate() ; // re-darw to update the control
}
return old ;
}
long CTrayControlCtrl::GetTrayOrieintation()
{
return m_orientation ;
}
void CTrayControlCtrl::SetTrayOrieintation(long nNewValue)
{
SetModifiedFlag();
if (nNewValue >= 0 && nNewValue < NUM_ORIENTATIONS)
{
m_orientation = nNewValue ;
Invalidate() ;
}
}
int CTrayControlCtrl::GetOrientationIndex(int sample_index)
{
int x = sample_index % m_xSize ;
int y = sample_index / m_xSize ;
// convert the sample index supplied to support the orientation the tary is setup to use
// note : I ended up not using this feature so not sure how robust it is!
switch (m_orientation)
{
case RightDown :
return sample_index ; // no change
case DownRight :
return x * m_ySize + y ;
case RightUp :
return x + (m_ySize - y - 1) * m_xSize ;
case UpRight :
return (m_ySize - y - 1) + x * m_ySize ;
case LeftDown :
return (m_xSize - x - 1) + y * m_xSize ;
case DownLeft :
return y + (m_xSize - x - 1) * m_ySize ;
case LeftUp :
return (m_xSize - x - 1) + (m_ySize - y - 1) * m_xSize ;
case UpLeft :
return (m_ySize - y - 1) + (m_xSize - x - 1) * m_ySize ;
}
return 0 ; // error
}
void CTrayControlCtrl::SetSampleCellCount(long index, long count)
{
// if a cell has a cell count > 0, then a numeric is shown in that cells location
if (index >= 0 && index < m_xSize * m_ySize)
{
m_Count[index] = count ;
Invalidate() ;
}
else
ASSERT(FALSE) ;
}
long CTrayControlCtrl::GetSampleCellCount(long index)
{
if (index >= 0 && index < m_xSize * m_ySize)
return m_Count[index] ;
ASSERT(FALSE) ;
return 0;
}
void CTrayControlCtrl::EnableTitleTips(long enable_tips)
{
m_bTitleTipsEnabled = (enable_tips != 0) ;
Invalidate() ;
}
void CTrayControlCtrl::EnableCherryPicking(long enable_cherry)
{
// cherry picking is where a user can select locations with the mouse, or drag loactions.
m_bCherryPicking = (enable_cherry != 0) ;
}
long CTrayControlCtrl::GetCherryCount()
{
// return how many items are selected
int count = 0 ;
for (int i = 0 ; i < m_xSize * m_ySize ; i++)
{
if (m_bSelected[i])
count++ ;
}
return count;
}
long CTrayControlCtrl::GetCherryIndex(long index)
{
// return the index of the item
for (int i = 0; i < m_xSize * m_ySize ; i++)
{
if (m_bSelected[i])
index-- ;
if (index < 0)
break ;
}
if (i == m_xSize * m_ySize)
return -1 ; // error
return i ;
}
void CTrayControlCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
int fire_pos = -1 ;
if (m_bCherryPicking)
{
if (GetAsyncKeyState(VK_CONTROL) >= 0)
{
// clear all the cherry picking state
for (int i = 0 ; i < m_xSize * m_ySize ; i++)
m_bSelected[i] = false ;
}
m_CherryPoint = point ; // point start if dragging a cherry rect
m_TrackerStart = point ; // for drawing tracker rectangle
// cherry picking is enabled
point -= m_actual.TopLeft() ;
point -= CSize(1, 1) ;
if (point.x >= 0 && point.y >= 0)
{
point.x /= m_cell_size ;
point.y /= m_cell_size ;
if (point.x >= 0 && point.x < m_xSize && point.y >= 0 && point.y < m_ySize)
{
m_CherryIndex = GetOrientationIndex(point.x + point.y * m_xSize) ;
m_bSelected[m_CherryIndex] = !m_bSelected[m_CherryIndex] ;
m_CherryStart = point ;
m_CherryEnd = m_CherryStart ;
fire_pos = m_CherryIndex ;
}
}
Invalidate() ;
}
FireControlClicked(fire_pos) ;
if (fire_pos != -1)
FireCherryPicked() ; // cherry picking was performed
COleControl::OnLButtonDown(nFlags, point);
}
void CTrayControlCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
COleControl::OnMouseMove(nFlags, point);
if (!::IsWindow(m_hWnd))
return ; // you can get a mouse move for your window which is not a valid window!
bool inval = false ;
// check for cherry picking
if (m_bCherryPicking && m_CherryIndex >= 0)
{
// has the mouse moved far enough from the cherry start point to display a tracker rect?
if ((abs(point.x - m_TrackerStart.x) > 3 || abs(point.y - m_TrackerStart.y) > 3) && !m_bCherryDrag)
{
// start a cherry drag operation
m_bCherryDrag = true ;
CRect rect ;
GetWindowRect(&rect) ;
//ClientToScreen(&rect) ;
ClipCursor(rect) ; // stop the user moving outside of the control with the tracker rect
m_bDrawTracker = true ;
inval = true ;
}
if (m_bCherryDrag)
{
m_bDrawTracker = true ;
inval = true ;
CPoint pos(point) ;
pos -= m_actual.TopLeft() ;
pos -= CSize(1, 1) ;
pos.x /= m_cell_size ;
pos.y /= m_cell_size ;
// limit the drag target to the actual cells of the control
if (pos.x < 0)
pos.x = 0 ;
if (pos.x >= m_xSize)
pos.x = m_xSize - 1 ;
if (pos.y < 0)
pos.y = 0 ;
if (pos.y >= m_ySize)
pos.y = m_ySize - 1 ;
if (m_CherryEnd != pos)
{
for (int i = (m_CherryEnd.x <= m_CherryStart.x) ? m_CherryEnd.x : m_CherryStart.x ;
i <= m_CherryStart.x || i <= m_CherryEnd.x ;
i++)
{
for (int j = (m_CherryEnd.y <= m_CherryStart.y) ? m_CherryEnd.y : m_CherryStart.y ;
j <= m_CherryStart.y || j <= m_CherryEnd.y ;
j++)
{
int index = GetOrientationIndex(i + j * m_xSize) ;
m_bSelected[index] = !m_bSelected[index] ;
}
}
// need to update the selected indexes
m_CherryEnd = pos ;
for (i = (m_CherryEnd.x <= m_CherryStart.x) ? m_CherryEnd.x : m_CherryStart.x ;
i <= m_CherryStart.x || i <= m_CherryEnd.x ;
i++)
{
for (int j = (m_CherryEnd.y <= m_CherryStart.y) ? m_CherryEnd.y : m_CherryStart.y ;
j <= m_CherryStart.y || j <= m_CherryEnd.y ;
j++)
{
int index = GetOrientationIndex(i + j * m_xSize) ;
m_bSelected[index] = !m_bSelected[index] ;
}
}
FireCherryPicked() ;
inval = true ;
}
}
}
// show title of cell under assay
CString text ;
if (m_bTitleTipsEnabled)
{
CPoint pos(point) ;
ClientToScreen(&pos) ;
if (WindowFromPoint(pos) != this)
{
ReleaseCapture() ;
inval = true ;
}
else
{
point -= m_actual.TopLeft() ;
point -= CSize(1, 1) ;
if (m_cell_size == 0)
m_cell_size = 1 ;
if (point.x >= 0 && point.y >= 0)
{
point.x /= m_cell_size ;
point.y /= m_cell_size ;
if (point.x >= 0 && point.x < m_xSize && point.y >= 0 && point.y < m_ySize)
{
if (point != m_TitleTipIndex)
{
m_TitleTipIndex = point ;
inval = true ;
SetCapture() ; // so we can remove the title tip if the mouse leaves the control
}
}
else
{
if (m_TitleTipIndex.x != -1)
{
m_TitleTipIndex = CPoint(-1, -1) ;
inval = true ;
ReleaseCapture() ;
}
}
}
else
{
if (m_TitleTipIndex.x != -1)
{
m_TitleTipIndex = CPoint(-1, -1) ;
inval = true ;
}
}
if (!m_bTracking)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = m_hWnd;
tme.dwFlags = TME_LEAVE;
tme.dwHoverTime = 1;
m_bTracking = (_TrackMouseEvent(&tme) != 0) ;
}
}
}
if (inval)
Invalidate() ;
}
void CTrayControlCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if (m_bCherryDrag)
{
// finish the drag operation
ClipCursor(NULL) ; // allow mouse access to full screen again
m_bDrawTracker = false ;
m_bCherryDrag = false ;
Invalidate() ;
FireCherryPicked() ;
}
m_CherryIndex = -1 ;
COleControl::OnLButtonUp(nFlags, point);
}
LRESULT CTrayControlCtrl::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
// make any title tip dissapear
m_TitleTipIndex = -1 ;
m_bTracking = false ;
Invalidate() ;
return 0 ;
}
void CTrayControlCtrl::RemoveAll()
{
for (int i = 0 ; i < m_xSize * m_ySize ; i++)
{
m_bSelected[i] = false ;
m_Count[i] = 0 ;
m_Names[i] = "" ;
m_pColourIndexes[i] = 0 ;
}
m_SampleIndex = 0 ;
FireInsertPointChanged() ;
}
CString CTrayControlCtrl::GetXLabelText(int x)
{
CString text ;
if (m_bXAxisAlpha)
{
switch (m_orientation)
{
case RightDown :
case RightUp :
case UpRight :
case DownRight :
text.Format("%c", (char)(65 + x)) ;
break ;
case LeftDown :
case LeftUp :
case UpLeft :
case DownLeft :
text.Format("%c", (char)(65 + (m_xSize - x - 1))) ;
break ;
}
}
else
{
switch (m_orientation)
{
case RightDown :
case RightUp :
case UpRight :
case DownRight :
text.Format("%1d", x + 1) ;
break ;
case LeftDown :
case LeftUp :
case UpLeft :
case DownLeft :
text.Format("%1d", m_xSize - x) ;
break ;
}
}
return text ;
}
CString CTrayControlCtrl::GetYLabelText(int y)
{
CString text ;
if (m_bYAxisAlpha)
{
switch (m_orientation)
{
case RightDown :
case LeftDown :
case DownLeft :
case DownRight :
text.Format("%c", (char)(65 + y)) ;
break ;
case LeftUp :
case UpLeft :
case RightUp :
case UpRight :
text.Format("%c", (char)(65 + (m_ySize - y - 1))) ;
break ;
}
}
else
{
switch (m_orientation)
{
case RightDown :
case DownLeft :
case DownRight :
case LeftDown :
text.Format("%1d", y + 1) ;
break ;
case LeftUp :
case UpLeft :
case RightUp :
case UpRight :
text.Format("%1d", m_ySize - y) ;
break ;
}
}
return text ;
}
CString CTrayControlCtrl::GetCellLabel(CPoint pos)
{
CString x ;
CString y ;
if (m_xSize > 1 && m_ySize > 1)
x = GetXLabelText(pos.x) ;
if (m_xSize > 1 && m_ySize > 1)
y = GetYLabelText(pos.y) ;
switch (m_bXAxisAlpha + m_bYAxisAlpha * 2)
{
case 0 : // neither is alpha, 2 numbers
x = x + ":" + y + " " ;
return x ;
case 1 : x += y + " " ;
return x ;
case 2 : y += x + " " ;
return y ;
case 3 : x += y + " " ;
return x ;
}
return "Error" ;
}
void CTrayControlCtrl::SetFlashState(long state)
{
bool new_state = (state != 0) ;
if (new_state && !m_bFlashing)
{
// set the timer going
m_Timer = SetTimer(1, m_FlashRate, 0) ;
m_bFlashing = true ;
}
else if (!new_state && m_bFlashing)
{
KillTimer(m_Timer) ;
m_Timer = 0 ;
m_bFlashing = false ;
}
}
void CTrayControlCtrl::SetFlashIndex(long index)
{
m_FlashingIndex = index ;
}
void CTrayControlCtrl::SetFlashRate(long rate_in_ms)
{
m_FlashRate = rate_in_ms ;
if (m_bFlashing)
{
// set the new timer speed
KillTimer(m_Timer) ;
m_Timer = SetTimer(1, m_FlashRate, 0) ;
}
}
void CTrayControlCtrl::OnTimer(UINT nIDEvent)
{
m_bFlashOn = ! m_bFlashOn ;
Invalidate() ;
COleControl::OnTimer(nIDEvent);
}
void CTrayControlCtrl::SetSelectionState(long state)
{
m_bSelectionState = (state != 0) ;
Invalidate() ;
}
long CTrayControlCtrl::GetSampleIndex()
{
return m_SampleIndex ;
}
BOOL CTrayControlCtrl::AddSample(LPCTSTR sample_name, long colour_index)
{
if (m_SampleIndex >= 0 && m_SampleIndex < m_xSize * m_ySize)
{
m_Names[m_SampleIndex] = sample_name ; // take a copy of the name
m_pColourIndexes[m_SampleIndex] = colour_index ;
if (m_SampleIndex < m_xSize * m_ySize - 1)
{
m_SampleIndex++ ;
FireInsertPointChanged() ;
}
Invalidate() ; // re-draw the control
return TRUE ; // success
}
return FALSE;
}
void CTrayControlCtrl::SetSampleIndex(long sample_index)
{
m_SampleIndex = sample_index ;
if (m_bShowSampleIndex)
Invalidate() ;
FireInsertPointChanged() ;
}
void CTrayControlCtrl::SetShowNextInsertPosition(long show)
{
m_bShowSampleIndex = (show != 0) ;
Invalidate() ;
}
void CTrayControlCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
{
if (m_bShowSampleIndex)
{
point -= m_actual.TopLeft() ;
point -= CSize(1, 1) ;
if (point.x >= 0 && point.y >= 0)
{
point.x /= m_cell_size ;
point.y /= m_cell_size ;
if (point.x >= 0 && point.x < m_xSize && point.y >= 0 && point.y < m_ySize)
{
m_SampleIndex = GetOrientationIndex(point.x + point.y * m_xSize) ;
FireInsertPointChanged() ;
}
}
Invalidate() ;
}
COleControl::OnLButtonDblClk(nFlags, point);
}
BSTR CTrayControlCtrl::GetPositionLabel(long index)
{
CString strResult;
CPoint pos = GetPointFromIndex(index) ;
strResult = GetCellLabel(pos) ;
return strResult.AllocSysString();
}
CPoint CTrayControlCtrl::GetPointFromIndex(int index)
{
CPoint pos(0, 0) ;
switch (m_orientation)
{
case RightDown :
pos.x = index % m_xSize ;
pos.y = index / m_xSize ;
break ;
case DownRight :
pos.x = index / m_ySize ;
pos.y = index % m_ySize ;
break ;
case RightUp :
pos.x = index % m_xSize ;
pos.y = m_ySize - index / m_xSize - 1 ;
break ;
case UpRight :
pos.x = index / m_ySize ;
pos.y = m_ySize - index % m_ySize - 1 ;
break ;
case LeftDown :
pos.x = m_xSize - index % m_xSize - 1 ;
pos.y = index / m_xSize ;
break ;
case DownLeft :
pos.x = m_xSize - index / m_ySize - 1 ;
pos.y = index % m_ySize ;
break ;
case LeftUp :
pos.x = m_xSize - index % m_xSize - 1 ;
pos.y = m_ySize - index / m_xSize - 1 ;
break ;
case UpLeft :
pos.x = m_xSize - index / m_ySize - 1 ;
pos.y = m_ySize - index % m_ySize - 1 ;
break ;
}
return pos ;
}
BOOL CTrayControlCtrl::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_KEYDOWN)
{
// process keyboard messages if required
if (m_bShowSampleIndex)
{
// the red selection square is shown, allow the user to move it with the arrow keys
switch (pMsg->wParam)
{
case VK_LEFT :
if (m_SampleIndex >= m_ySize)
{
m_SampleIndex -= m_ySize ;
Invalidate() ;
FireInsertPointChanged() ;
}
return TRUE ; // we used the key press
case VK_RIGHT :
if (m_SampleIndex < (m_xSize - 1) * m_ySize)
{
m_SampleIndex += m_ySize ;
Invalidate() ;
FireInsertPointChanged() ;
}
return TRUE ;
case VK_UP :
if (m_SampleIndex % m_ySize < m_ySize - 1)
{
m_SampleIndex++ ;
Invalidate() ;
FireInsertPointChanged() ;
}
return TRUE ;
case VK_DOWN :
if (m_SampleIndex % m_ySize > 0)
{
m_SampleIndex-- ;
Invalidate() ;
FireInsertPointChanged() ;
}
return TRUE ;
// all other keys fall through to the default handler
}
}
}
return COleControl::PreTranslateMessage(pMsg);
}
void CTrayControlCtrl::OnRButtonDown(UINT nFlags, CPoint point)
{
int fire_pos = -1 ;
// cherry picking is enabled
point -= m_actual.TopLeft() ;
point -= CSize(1, 1) ;
if (point.x >= 0 && point.y >= 0)
{
point.x /= m_cell_size ;
point.y /= m_cell_size ;
if (point.x >= 0 && point.x < m_xSize && point.y >= 0 && point.y < m_ySize)
fire_pos = GetOrientationIndex(point.x + point.y * m_xSize) ;
}
FireControlRightClicked(fire_pos) ; // let container app know which location was right clicked, -1 if not on an actual cell
COleControl::OnRButtonDown(nFlags, point);
}