void CComboBoxUI::PaintStatusImage(HDC hDC)
	{
		if (m_sArrowImage.IsEmpty())
			CComboUI::PaintStatusImage(hDC);
		else
		{
			// get index
			if( IsFocused() ) m_uButtonState |= UISTATE_FOCUSED;
			else m_uButtonState &= ~ UISTATE_FOCUSED;
			if( !IsEnabled() ) m_uButtonState |= UISTATE_DISABLED;
			else m_uButtonState &= ~ UISTATE_DISABLED;

			int nIndex = 0;
			if ((m_uButtonState & UISTATE_DISABLED) != 0)
				nIndex = 4;
			else if ((m_uButtonState & UISTATE_PUSHED) != 0)
				nIndex = 2;
			else if ((m_uButtonState & UISTATE_HOT) != 0)
				nIndex = 1;
			else if ((m_uButtonState & UISTATE_FOCUSED) != 0)
				nIndex = 3;

			// make modify string
			CDuiString sModify = m_sArrowImage;

			int nPos1 = sModify.Find(_T("source"));
			int nPos2 = sModify.Find(_T("'"), nPos1 + 7);
			if (nPos2 == -1) return; //first
			int nPos3 = sModify.Find(_T("'"), nPos2 + 1);
			if (nPos3 == -1) return; //second

			CDuiRect rcBmpPart;
			LPTSTR lpszValue = NULL;
			rcBmpPart.left = _tcstol(sModify.GetData() + nPos2 + 1, &lpszValue, 10);  ASSERT(lpszValue);    
			rcBmpPart.top = _tcstol(lpszValue + 1, &lpszValue, 10);    ASSERT(lpszValue);    
			rcBmpPart.right = _tcstol(lpszValue + 1, &lpszValue, 10);  ASSERT(lpszValue);    
			rcBmpPart.bottom = _tcstol(lpszValue + 1, &lpszValue, 10); ASSERT(lpszValue); 

			m_nArrowWidth = rcBmpPart.GetWidth() / 5;
			rcBmpPart.left += nIndex * m_nArrowWidth;
			rcBmpPart.right = rcBmpPart.left + m_nArrowWidth;

			CDuiRect rcDest(0, 0, m_rcItem.right - m_rcItem.left, m_rcItem.bottom - m_rcItem.top);
			rcDest.Deflate(GetBorderSize(), GetBorderSize());
			rcDest.left = rcDest.right - m_nArrowWidth;

			CDuiString sSource = sModify.Mid(nPos1, nPos3 + 1 - nPos1);
			CDuiString sReplace;
			sReplace.SmallFormat(_T("source='%d,%d,%d,%d' dest='%d,%d,%d,%d'"),
				rcBmpPart.left, rcBmpPart.top, rcBmpPart.right, rcBmpPart.bottom,
				rcDest.left, rcDest.top, rcDest.right, rcDest.bottom);

			sModify.Replace(sSource, sReplace);

			// draw image
			if (!DrawImage(hDC, m_sArrowImage, sModify))
				m_sNormalImage.Empty();
		}
	}
Exemple #2
0
void CImgStatic::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
  // Check if image data is loaded
  if (m_bImageLoaded) {
    RECT rc;
    GetClientRect(&rc);

    if (m_bUseScrollBars) {
      UINT uiHHeight = GetSystemMetrics(SM_CYHSCROLL);
      UINT uiVWidth = GetSystemMetrics(SM_CXVSCROLL);
      CRect rectH, rectV;
      rectH = rc;
      rectH.top = rectH.bottom - uiHHeight;
      rectH.right -= uiVWidth;

      rectV = rc;
      rectV.left = rectV.right - uiVWidth;
      rectV.bottom -= uiHHeight;

      m_HScroll.MoveWindow(rectH);
      m_VScroll.MoveWindow(rectV);
    }

    // Get Gdiplus graphics object
    Gdiplus::Graphics grp(lpDrawItemStruct->hDC);

    // Get image
    Gdiplus::Image image(m_pStream);

    // Adjust for aspect ratio
    SetAspectRatio(image, rc);

    if (m_iZoomFactor == 10) {
      // Draw it
      grp.DrawImage(&image, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
    } else {
      Gdiplus::Rect rcDest(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
      int srcx, srcy, srcwidth, srcheight;

      srcx = (int)(image.GetWidth() * ((float)m_iHPos / 100.0));
      srcy = (int)(image.GetHeight() * ((float)m_iVPos / 100.0));
      srcwidth = (int)(image.GetWidth() / ((float)m_iZoomFactor / 10.0));
      srcheight = (int)(image.GetHeight() / ((float)m_iZoomFactor / 10.0));

      grp.DrawImage(&image, rcDest, srcx, srcy, srcwidth, srcheight, Gdiplus::UnitPixel);
    }
  }
}
Exemple #3
0
int KQtTester::testDrawPixmapScale2()
{
    QPixmap pixmap (IMAGE_FILE);

    QRect rcSource = pixmap.rect();
    QRect rcDest(10, 10, pixmap.width() * 2, pixmap.height() * 2);
    m_TimerPtr->Restart();

    for (int i = 0; i < m_nNumber; ++i)
    {
        m_painter->drawPixmap(rcDest, pixmap, rcSource);
    }

    m_TimerPtr->Stop();

    return m_TimerPtr->ElapsedMsec();
}
Exemple #4
0
int KQtTester::testDrawImageArgb32PreScale2()
{
    QImage img = QImage(IMAGE_FILE).convertToFormat(QImage::Format_ARGB32_Premultiplied);

    QRect rcSource = img.rect();
    QRect rcDest(10, 10, img.width() * 2, img.height() * 2);
    m_TimerPtr->Restart();

    for (int i = 0; i < m_nNumber; ++i)
    {
        m_painter->drawImage(rcDest, img, rcSource);
    }

    m_TimerPtr->Stop();

    return m_TimerPtr->ElapsedMsec();
}
Exemple #5
0
int KQtTester::testDrawImageArgb32Scale2()
{
    QImage img (IMAGE_FILE);

    QRect rcSource = img.rect();
    QRect rcDest(10, 10, img.width() * 2, img.height() * 2);
    m_TimerPtr->Restart();

    for (int i = 0; i < m_nNumber; ++i)
    {
        m_painter->drawImage(rcDest, img, rcSource);
    }

    m_TimerPtr->Stop();

    return m_TimerPtr->ElapsedMsec();
}
	void CComboBoxUI::PaintStatusImage(HDC hDC)
	{
		if (m_sArrowImage.IsEmpty())
			CComboUI::PaintStatusImage(hDC);
		else
		{
			// get index
			if( IsFocused() ) m_uButtonState |= UISTATE_FOCUSED;
			else m_uButtonState &= ~ UISTATE_FOCUSED;
			if( !IsEnabled() ) m_uButtonState |= UISTATE_DISABLED;
			else m_uButtonState &= ~ UISTATE_DISABLED;

			int nIndex = 0;
			if ((m_uButtonState & UISTATE_DISABLED) != 0)
				nIndex = 4;
			else if ((m_uButtonState & UISTATE_PUSHED) != 0)
				nIndex = 2;
			else if ((m_uButtonState & UISTATE_HOT) != 0)
				nIndex = 1;
			else if ((m_uButtonState & UISTATE_FOCUSED) != 0)
				nIndex = 3;

			CDuiRect rcBmpPart(m_sArrowImage.GetSource());

			m_nArrowWidth = rcBmpPart.GetWidth() / 5;
			rcBmpPart.left += nIndex * m_nArrowWidth;
			rcBmpPart.right = rcBmpPart.left + m_nArrowWidth;

			CDuiRect rcDest(0, 0, m_rcItem.right - m_rcItem.left, m_rcItem.bottom - m_rcItem.top);
			rcDest.Deflate(GetBorderSize(), GetBorderSize());
			rcDest.left = rcDest.right - m_nArrowWidth;

			// draw image
			if (!DrawImage(hDC, m_sArrowImage))
				m_sNormalImage.Empty();
			else 
			{
				DrawImage(hDC, m_sArrowImage,rcBmpPart);
				DrawImage(hDC, m_sArrowImage,rcDest);
			}
		}
	}
Exemple #7
0
	bool CImage::Draw(HDC hDC, CPaintManagerUI* pManager, const RECT& rc, const RECT& rcPaint) const
	{
		if (m_rcItem.right == m_rcItem.left && m_rcItem.top == m_rcItem.bottom)
		{
			CDuiRect rcDest = rc;

			return CRenderEngine::DrawImage(hDC, pManager, rc, rcPaint, m_sImageName,
				rcDest, m_rcBmpPart, m_rcCorner, m_dwMask, m_bFade, m_bHole, m_bTiledX, m_bTiledY);
		}
		else
		{
			CDuiRect rcDest(
				rc.left + m_rcItem.left, 
				rc.top + m_rcItem.top, 
				(rc.left + m_rcItem.right > rc.right)? rc.right: rc.left + m_rcItem.right,
				(rc.top + m_rcItem.bottom > rc.bottom)? rc.bottom: rc.top + m_rcItem.bottom
				);

			return CRenderEngine::DrawImage(hDC, pManager, rc, rcPaint, m_sImageName,
				rcDest, m_rcBmpPart, m_rcCorner, m_dwMask, m_bFade, m_bHole, m_bTiledX, m_bTiledY);
		}
	}
Exemple #8
0
////////////////
// Draw min, max/restore, close buttons.
// Returns total width of buttons drawn.
//
int CCaptionPainter::DrawCustomButtons(CDC* dc, CRect& capRect)
{
	ASSERT(m_pParentDlg);
	CWnd& wnd = (CWnd&)*m_pParentDlg;
	
	DWORD dwStyle = wnd.GetStyle();
	if (!(dwStyle & WS_CAPTION))
		return 0;

	if (!(dwStyle & WS_SYSMENU)) // does it contain controls in the title bar?
		return 0;

	RDcDrawingSurface destDS;
	destDS.Initialize(dc->m_hDC, dc->m_hAttribDC);

	// do the close box
	int btnDim = capRect.Height() - (2 * kCtrlInset);
	CRect rcSrc(0, 0, btnDim, btnDim);
	
	CRect rcDest(rcSrc);
	rcDest.OffsetRect(capRect.left + capRect.Width() - (btnDim + kCtrlInset) , capRect.top + kCtrlInset);	// move right
	
	m_rcCloseBtn = rcDest;
	
	m_pCloseBxImgCtrl->SetControlSize(rcSrc, m_pTitleBkImgCtrl);
	m_pCloseBxImgCtrl->Draw(CPImageControl::UP, destDS, rcSrc, rcDest);

	// Max/restore button is like close box; just shift rectangle left
	// Also does help button, if any.
	BOOL bMaxBox = dwStyle & WS_MAXIMIZEBOX;
	if (bMaxBox || (wnd.GetExStyle() & WS_EX_CONTEXTHELP)) 
	{
		rcDest.OffsetRect(-(btnDim + kCtrlInset), 0);
		CPImageControl* pImgCtrl;
		if ( bMaxBox != FALSE )
			pImgCtrl = (wnd.IsZoomed() ? m_pRestoreBxImgCtrl : m_pMaxBxImgCtrl);
		else
			ASSERT(0);//pImgCtrl = m_pHelpBxImgCtrl;

		if (pImgCtrl)
		{
			pImgCtrl->SetControlSize(rcSrc, m_pTitleBkImgCtrl);
			pImgCtrl->Draw(CPImageControl::UP, destDS, rcSrc, rcDest);
		}
		m_rcMaxBtn = rcDest;
	}

	// Minimize button has 2 pixel border on all sides but right.
	if (dwStyle & WS_MINIMIZEBOX) 
	{
		rcDest -= CPoint(btnDim, 0);
		m_pMinBxImgCtrl->SetControlSize(rcSrc, m_pTitleBkImgCtrl);
		m_pMinBxImgCtrl->Draw(CPImageControl::UP, destDS, rcSrc, rcDest);
		m_rcMinBtn = rcDest;
	}

	destDS.RestoreDefaults( );
	
	return capRect.Width() - rcDest.left - 2;

}
Exemple #9
0
BOOL CImageEx::DrawNinePartImage(int pleft, int ptop, int pright, int pbottom,
					   HDC hDC, int height, int width, int left, int top, int right, int bottom)
{
	// 左上
	{
		CRect rcDest(pleft, ptop, pleft+left, ptop+top);
		CRect rcSrc(0, 0, left, top);
		if (!rcDest.IsRectEmpty() && !rcSrc.IsRectEmpty())
			Draw(hDC, rcDest, rcSrc);
	}

	// 左边
	{
		CRect rcDest(pleft, top+ptop, pleft+left, top+(height-top-bottom-ptop-pbottom));
		CRect rcSrc(0, top, left, top+(GetHeight()-top-bottom));
		if (!rcDest.IsRectEmpty() && !rcSrc.IsRectEmpty())
			Draw(hDC, rcDest, rcSrc);
	}

	// 上边
	{
		CRect rcDest(left+pleft, ptop, (left+pleft)+(width-left-right-pleft-pright), ptop+top);
		CRect rcSrc(left, 0, left+(GetWidth()-left-right), top);
		if (!rcDest.IsRectEmpty() && !rcSrc.IsRectEmpty())
			Draw(hDC, rcDest, rcSrc);
	}

	// 右上
	{
		CRect rcDest(width- right-pright, ptop, (width- right-pright)+right, ptop+top);
		CRect rcSrc(GetWidth()-right, 0, (GetWidth()-right)+right, top);
		if (!rcDest.IsRectEmpty() && !rcSrc.IsRectEmpty())
			Draw(hDC, rcDest, rcSrc);
	}

	// 右边
	{
		CRect rcDest(width-right-pright, top+ptop, (width-right-pright)+right, (top+ptop)+(height-top-bottom-ptop-pbottom));
		CRect rcSrc(GetWidth()-right, top, (GetWidth()-right)+right, top+(GetHeight()-top-bottom));
		if (!rcDest.IsRectEmpty() && !rcSrc.IsRectEmpty())
			Draw(hDC, rcDest, rcSrc);
	}

	// 下边
	{
		CRect rcDest(left+pleft, height-bottom-pbottom, (left+pleft)+(width-left-right-pleft-pright), (height-bottom-pbottom)+bottom);
		CRect rcSrc(left, GetHeight()-bottom, left+(GetWidth()-left-right), (GetHeight()-bottom)+bottom);
		if (!rcDest.IsRectEmpty() && !rcSrc.IsRectEmpty())
			Draw(hDC, rcDest, rcSrc);
	}

	// 右下
	{
		CRect rcDest(width-right-pright, height-bottom-pbottom, (width-right-pright)+right, (height-bottom-pbottom)+bottom);
		CRect rcSrc(GetWidth()-right, GetHeight()-bottom, (GetWidth()-right)+right, (GetHeight()-bottom)+bottom);
		if (!rcDest.IsRectEmpty() && !rcSrc.IsRectEmpty())
			Draw(hDC, rcDest, rcSrc);
	}

	// 左下
	{
		CRect rcDest(pleft, height-bottom-pbottom, pleft+left, (height-bottom-pbottom)+bottom);
		CRect rcSrc(0, GetHeight()-bottom, left, (GetHeight()-bottom)+bottom);
		if (!rcDest.IsRectEmpty() && !rcSrc.IsRectEmpty())
			Draw(hDC, rcDest, rcSrc);
	}

	// 中间
	{
		CRect rcDest(left+pleft, top+ptop, (left+pleft)+(width-left-right-pleft-pright), (top+ptop)+(height-top-bottom-ptop-pbottom));
		CRect rcSrc(left, top, left+(GetWidth()-left-right), top+(GetHeight()-top-bottom));
		if (!rcDest.IsRectEmpty() && !rcSrc.IsRectEmpty())
			Draw(hDC, rcDest, rcSrc);
	}

	return TRUE;
}
void VFSNodeUnit::run() {
    // Note that we also do testing of streams and file i/o here.

    this->logStatus(VSTRING_FORMAT("getExecutable: '%s'", VFSNode::getExecutable().getPath().chars()));
    this->logStatus(VSTRING_FORMAT("getExecutableDirectory: '%s'", VFSNode::getExecutableDirectory().getPath().chars()));
    this->logStatus(VSTRING_FORMAT("USER_HOME_DIRECTORY: '%s'", VFSNode::getKnownDirectoryNode(VFSNode::USER_HOME_DIRECTORY, "com", "app").getPath().chars()));
    this->logStatus(VSTRING_FORMAT("LOG_FILES_DIRECTORY: '%s'", VFSNode::getKnownDirectoryNode(VFSNode::LOG_FILES_DIRECTORY, "com", "app").getPath().chars()));
    this->logStatus(VSTRING_FORMAT("USER_PREFERENCES_DIRECTORY: '%s'", VFSNode::getKnownDirectoryNode(VFSNode::USER_PREFERENCES_DIRECTORY, "com", "app").getPath().chars()));
    this->logStatus(VSTRING_FORMAT("CACHED_DATA_DIRECTORY: '%s'", VFSNode::getKnownDirectoryNode(VFSNode::CACHED_DATA_DIRECTORY, "com", "app").getPath().chars()));
    this->logStatus(VSTRING_FORMAT("APPLICATION_DATA_DIRECTORY: '%s'", VFSNode::getKnownDirectoryNode(VFSNode::APPLICATION_DATA_DIRECTORY, "com", "app").getPath().chars()));
    this->logStatus(VSTRING_FORMAT("CURRENT_WORKING_DIRECTORY: '%s'", VFSNode::getKnownDirectoryNode(VFSNode::CURRENT_WORKING_DIRECTORY, "com", "app").getPath().chars()));
    this->logStatus(VSTRING_FORMAT("EXECUTABLE_DIRECTORY: '%s'", VFSNode::getKnownDirectoryNode(VFSNode::EXECUTABLE_DIRECTORY, "com", "app").getPath().chars()));

    VFSNode tempDir = VFSNode::getKnownDirectoryNode(VFSNode::CACHED_DATA_DIRECTORY, "vault", "unittest");
    VString tempDirPath = tempDir.getPath();

    VFSNode testDirRoot(tempDir, "vfsnodetest_temp");
    (void) testDirRoot.rm();

    VFSNode testDirDeep(tempDir, "vfsnodetest_temp/one/two/three");
    VUNIT_ASSERT_FALSE_LABELED(testDirDeep.exists(), "initial state 1");
    testDirDeep.mkdirs();
    VUNIT_ASSERT_TRUE_LABELED(testDirDeep.exists(), "deep mkdirs");

    VFSNode testDirDeeper(testDirDeep, "four");
    VUNIT_ASSERT_FALSE_LABELED(testDirDeeper.exists(), "initial state 2");
    testDirDeeper.mkdirs();
    VUNIT_ASSERT_TRUE_LABELED(testDirDeeper.exists(), "one-deep mkdirs");

    // Now that we have created a deep directory structure, let's do some
    // file i/o streams stuff here.

    VFSNode testTextFileNode(testDirDeeper, "test_text_file.txt");

    VBufferedFileStream btfs(testTextFileNode);
    this->_testTextFileIO("starting Buffered Text IO tests", testTextFileNode, btfs);
    (void) testTextFileNode.rm();
    VUNIT_ASSERT_FALSE_LABELED(testTextFileNode.exists(), "buffered text file removed");

    VDirectIOFileStream dtfs(testTextFileNode);
    this->_testTextFileIO("starting Unbuffered Text IO tests", testTextFileNode, dtfs);
    this->_testTextFileReadAll(testTextFileNode);
    (void) testTextFileNode.rm();
    VUNIT_ASSERT_FALSE_LABELED(testTextFileNode.exists(), "unbuffered text file removed");

    VFSNode testBinaryFileNode(testDirDeeper, "test_binary_file");

    VBufferedFileStream bbfs(testBinaryFileNode);
    this->_testBinaryFileIO("starting Buffered Binary IO tests", testBinaryFileNode, bbfs);
    (void) testBinaryFileNode.rm();
    VUNIT_ASSERT_FALSE_LABELED(testBinaryFileNode.exists(), "buffered binary file removed");

    VDirectIOFileStream dbfs(testBinaryFileNode);
    this->_testBinaryFileIO("starting Unbuffered Binary IO tests", testBinaryFileNode, dbfs);
    (void) testBinaryFileNode.rm();
    VUNIT_ASSERT_FALSE_LABELED(testBinaryFileNode.exists(), "unbuffered binary file removed");

    this->_testDirectoryIteration(testDirDeeper);

    // Next, test all flavors of renaming operations.
    VFSNode copyTest1(tempDir, "vfsnodetest_temp/one/two/test1.txt");
    VBufferedFileStream sourceFileStream(copyTest1);
    sourceFileStream.openWrite();
    VTextIOStream sourceOut(sourceFileStream);
    sourceOut.writeLine("line 1");
    sourceOut.writeLine("line 2");
    sourceOut.flush();
    sourceFileStream.close();
    VUNIT_ASSERT_TRUE_LABELED(copyTest1.exists(), "test1 exists");

    VFSNode copyTest2(tempDir, "vfsnodetest_temp/one/two/test2.txt");
    copyTest1.renameToName("test2.txt");
    VUNIT_ASSERT_FALSE_LABELED(copyTest1.exists(), "test1 was renamed");
    VUNIT_ASSERT_TRUE_LABELED(copyTest2.exists(), "test2 exists");

    VFSNode copyTest3;
    copyTest2.renameToName("test3.txt", copyTest3);
    VUNIT_ASSERT_FALSE_LABELED(copyTest2.exists(), "test2 was renamed");
    VUNIT_ASSERT_TRUE_LABELED(copyTest3.getPath() == tempDirPath + "/vfsnodetest_temp/one/two/test3.txt" && copyTest3.exists(), "test3 exists");

    VFSNode copyTest4(tempDir, "vfsnodetest_temp/one/two/three/test4.txt");
    copyTest3.renameToNode(copyTest4);
    VUNIT_ASSERT_FALSE_LABELED(copyTest3.exists(), "test3 was moved and renamed");
    VUNIT_ASSERT_TRUE_LABELED(copyTest4.exists(), "test4 exists");

    copyTest4.renameToPath(tempDirPath + "/vfsnodetest_temp/one/two/test5.txt");
    VFSNode copyTest5(tempDir, "vfsnodetest_temp/one/two/test5.txt");
    VUNIT_ASSERT_FALSE_LABELED(copyTest4.exists(), "test4 was moved and renamed");
    VUNIT_ASSERT_TRUE_LABELED(copyTest5.exists(), "test5 exists");

    copyTest5.renameToName("test5.txt"); // should throw
    
    VFSNode dirCopyTarget(tempDir, "vfsnodetest_temp_copy");
    VFSNode::copyDirectory(testDirRoot, dirCopyTarget, true);
    // Verify that expected files now exist. Very dependent on file operations performed in tests above.
    VUNIT_ASSERT_TRUE_LABELED(VFSNode(tempDirPath + "/vfsnodetest_temp_copy/one/two/test5.txt").isFile(), "copied directory, spot check test5.txt");
    VUNIT_ASSERT_TRUE_LABELED(VFSNode(tempDirPath + "/vfsnodetest_temp_copy/one/two/three/four/iter_test_0.txt").isFile(), "copied directory, spot check iter_test_0.txt");
    VUNIT_ASSERT_TRUE_LABELED(VFSNode(tempDirPath + "/vfsnodetest_temp_copy/one/two/three/four/iter_test_1.txt").isFile(), "copied directory, spot check iter_test_1.txt");
    VUNIT_ASSERT_TRUE_LABELED(VFSNode(tempDirPath + "/vfsnodetest_temp_copy/one/two/three/four/iter_test_2.txt").isFile(), "copied directory, spot check iter_test_2.txt");
    VUNIT_ASSERT_TRUE_LABELED(VFSNode(tempDirPath + "/vfsnodetest_temp_copy/one/two/three/four/iter_test_3.txt").isFile(), "copied directory, spot check iter_test_3.txt");
    
    // Verify that a non-recursive copy of source into a subdirectory of itself is allowed.
    VFSNode nrcSource(tempDirPath + "/vfsnodetest_temp/one/two");
    VFSNode nrcDest(tempDirPath + "/vfsnodetest_temp/one/two/non-recursive-copy-of-two");
    VFSNode::copyDirectory(nrcSource, nrcDest, false);
    VUNIT_ASSERT_TRUE_LABELED(VFSNode(tempDirPath + "/vfsnodetest_temp/one/two/non-recursive-copy-of-two/test5.txt").isFile(), "non-recursive nested copy succeeds on child file");
    
    // Verify that a recursive copy of source into a subdirectory of itself yields an
    // exception (rather than an infinite loop copying until disk is full!).
    try {
        VFSNode rcSource(tempDirPath + "/vfsnodetest_temp/one/two");
        VFSNode rcDest(tempDirPath + "/vfsnodetest_temp/one/two/recursive-copy-of-two");
        VFSNode::copyDirectory(nrcSource, nrcDest, true);
        VUNIT_ASSERT_FAILURE("Recursive nested copy was improperly allowed");
    } catch (const VException& ex) {
        VUNIT_ASSERT_SUCCESS("Recursive nested copy threw an exception as expected");
    }

    // Clean up our litter.
    (void) copyTest5.rm();
    (void) dirCopyTarget.rm();
    (void) nrcDest.rm();

    // Done with exercising file i/o and streams and directory stuff. Clean up our litter.

    VString deepPath;
    testDirDeeper.getParentPath(deepPath);
    VUNIT_ASSERT_EQUAL_LABELED(deepPath, tempDirPath + "/vfsnodetest_temp/one/two/three", "get parent path");

    VString nodeName;
    testDirDeeper.getName(nodeName);
    VUNIT_ASSERT_EQUAL_LABELED(nodeName, "four", "get deep node name");

    VFSNode shallowNode("shallow");
    shallowNode.getName(nodeName);
    VUNIT_ASSERT_EQUAL_LABELED(nodeName, "shallow", "get shallow node name");

    (void) testDirRoot.rm();
    VUNIT_ASSERT_FALSE_LABELED(testDirRoot.exists(), "rm tree");

    // Test some of the path string manipulation.

    VString testPath3("one/two/three");
    VFSNode testPath3Node(testPath3);

    VString testPath2;
    testPath3Node.getParentPath(testPath2);
    VFSNode testPath2Node(testPath2);
    VUNIT_ASSERT_EQUAL_LABELED(testPath2, "one/two", "parent of level 3 path");

    VString testPath1;
    testPath2Node.getParentPath(testPath1);
    VFSNode testPath1Node(testPath1);
    VUNIT_ASSERT_EQUAL_LABELED(testPath1, "one", "parent of level 2 path");

    VString testPath0;
    testPath1Node.getParentPath(testPath0);
    VFSNode testPath0Node(testPath0);
    VUNIT_ASSERT_EQUAL_LABELED(testPath0, "", "parent of level 1 path");

    // Test oddities with DOS driver letters and mapped drives. Trailing slash on drive letter may or may be present.
#ifdef VPLATFORM_WIN
    // These tests assume that C: and C:Windows exist; some installations may use a different drive letter, in which case skip the test.
    const VString DRIVE_LETTER("C");
    const VString CHILD_NODE_NAME("Windows");
    if (VFSNode(VSTRING_FORMAT("%s:/%s", DRIVE_LETTER.chars(), CHILD_NODE_NAME.chars())).exists()) {
        this->_testWindowsDrivePaths(DRIVE_LETTER, CHILD_NODE_NAME, false, true);
        this->_testWindowsDrivePaths(DRIVE_LETTER, CHILD_NODE_NAME, true, true);
    }
#endif

    // Test assignment operator.
    VFSNode someNode("a/b/c/d");
    VFSNode copiedNode;
    copiedNode = someNode;
    VUNIT_ASSERT_EQUAL_LABELED(copiedNode.getPath(), "a/b/c/d", "assignment operator");

    /*
        Uncomment if you want to exercise this code. It's commented out for now because by its nature it
        will litter several directories with its output. (It tests the APIs that locate the various
        platform-dependent directories where log files, preference files, etc. should be written.
        So for now I've chosen not to exercise this code in this unit test.

        // Test known directory location lookup. Just write a file to each directory;
        // user will have to visually check that it was put in the right place.
        this->_writeKnownDirectoryTestFile(VFSNode::USER_HOME_DIRECTORY, "unittest-user");
        this->_writeKnownDirectoryTestFile(VFSNode::LOG_FILES_DIRECTORY, "unittest-logs");
        this->_writeKnownDirectoryTestFile(VFSNode::USER_PREFERENCES_DIRECTORY, "unittest-prefs");
        this->_writeKnownDirectoryTestFile(VFSNode::CACHED_DATA_DIRECTORY, "unittest-cache");
        this->_writeKnownDirectoryTestFile(VFSNode::APPLICATION_DATA_DIRECTORY, "unittest-appdata");
        this->_writeKnownDirectoryTestFile(VFSNode::CURRENT_WORKING_DIRECTORY, "unittest-cwd");
    */
}
void CCategoryItem::DoPaint(CDCHandle dc, ButtonStatus eTabStatus, CategoryPosition btnPos, ButtonStatus eBtn, bool bDrawCloseBtn, int iDeltaHeight)
{
	// m_iXPos: x-value
	// iDeltaHeight: y-value
	// CATEGORY_ITEM_OVERLAP 重叠宽度

	RECT rcItem = { m_iXPos, iDeltaHeight, m_iXPos + m_iWidth + CATEGORY_ITEM_OVERLAP, iDeltaHeight + s()->Category()->GetCategoryHeight() };

	// 画背景
	s()->Category()->DrawCategory(dc, rcItem, eTabStatus);

	int iXTitlePos;

	// if this item is selected, draw Close btn
	// 画关闭图标
	if (bDrawCloseBtn && !GetWebData()->IsNoClose())
	{
		// 关闭图标的y坐标
		int iYCloseBtn = (s()->Category()->GetCategoryHeight() - s()->Category()->GetCategoryCloseButtonHeight()) / 2 + iDeltaHeight;

		RECT rcCloseBtn = { rcItem.right - s()->Category()->GetCategoryCloseButtonWidth() - s()->Category()->GetCategoryMargin(), iYCloseBtn,
			rcItem.right - s()->Category()->GetCategoryMargin(), iYCloseBtn + s()->Category()->GetCategoryCloseButtonHeight() };

		OffsetRect(&rcCloseBtn, -CATEGORY_ITEM_OVERLAP, 0);

		s()->Category()->DrawCategoryCloseButton(dc, rcCloseBtn, btnPos == CatePos_TabItemClose ? eBtn : Btn_MouseOut);
		iXTitlePos = rcCloseBtn.left;
	}
	else // 不画关闭图标
		iXTitlePos = rcItem.right - s()->Category()->GetCategoryMargin();


	bool bSelectedItem = false;
	if (m_pCateCtrl && m_pCateCtrl->GetCurrentSelection() == this)
		bSelectedItem = true;

	// 画logo图和Title
	// Draw the image.
	if (GetWebData() != NULL)
	{
		// 		int iIconWidth = GetWebData()->GetLogo().GetWidth();
		// 		int iIconHeight = GetWebData()->GetLogo().GetHeight();
		// 		POINT pt = { rcItem.left + s()->Category()->GetCategoryMargin(), (s()->Category()->GetCategoryHeight() - iIconHeight) / 2 + iDeltaHeight };
		// 		GetWebData()->GetLogo().Draw(dc, pt.x, pt.y + 3);

		// png icon
		int iIconWidth = GetWebData()->GetLogoPng(bSelectedItem).GetWidth();
		int iIconHeight = GetWebData()->GetLogoPng(bSelectedItem).GetHeight();
		POINT pt = { rcItem.left + s()->Tab()->GetTabMargin(), (s()->Tab()->GetTabHeight() - iIconHeight) / 2 + iDeltaHeight };
		CRect rcDest(pt.x, pt.y, pt.x + iIconWidth, pt.y + iIconHeight);
		rcDest.OffsetRect(0, 1);
		CRect rcSrc(0, 0, iIconWidth, iIconHeight);
		GetWebData()->GetLogoPng(bSelectedItem).ResetCacheDC(); // CacheDC没有正确设置,这里重新设置一下
		GetWebData()->GetLogoPng(bSelectedItem).Draw(dc, rcDest, rcSrc);

		if (ShowSecureLock())
		{
			int iIconHeight = 0;
			//POINT pt = { rcItem.left + s()->Tab()->GetTabMargin(), (s()->Tab()->GetTabHeight() - iIconHeight) / 2 + iDeltaHeight };
			POINT pt = { rcItem.left, rcItem.top };
			CRect rcMiniLock(pt.x, pt.y, pt.x + 15, pt.y + 16);
			OffsetRect(&rcMiniLock, 12, 10);
			s()->Tab()->DrawTabMiniLockButton(dc, rcMiniLock, (ButtonStatus)0);
		}

		dc.SetTextColor(eTabStatus == Btn_MouseDown ? RGB(16, 93, 145) : RGB(29, 126, 191));
		RECT rcText = { rcItem.left + s()->Category()->GetCategoryMargin() + 20 + CATEGORY_IMAGE_TEXT_MARGIN, 6, iXTitlePos - CATEGORY_TEXT_CLOSE_MARGIN, s()->Category()->GetCategoryHeight() };
		OffsetRect(&rcText, -1, -2);
		dc.DrawText(GetWebData()->GetName(), -1, &rcText, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_WORD_ELLIPSIS | DT_NOPREFIX);
	}
}