home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / mfc / controls / pal / palctl.cpp < prev    next >
C/C++ Source or Header  |  1998-03-26  |  15KB  |  589 lines

  1. // palctl.cpp : Implementation of the CPalCtrl OLE control class.
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1998 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13. #include "stdafx.h"
  14. #include "pal.h"
  15. #include "palctl.h"
  16. #include "palppg.h"
  17.  
  18.  
  19. #ifdef _DEBUG
  20. #undef THIS_FILE
  21. static char BASED_CODE THIS_FILE[] = __FILE__;
  22. #endif
  23.  
  24.  
  25. /////////////////////////////////////////////////////////////////////////////
  26. // Forward declarations
  27.  
  28. HPALETTE CopyPalette(HPALETTE srcpal);
  29.  
  30.  
  31. IMPLEMENT_DYNCREATE(CPalCtrl, COleControl)
  32.  
  33.  
  34. /////////////////////////////////////////////////////////////////////////////
  35. // Message map
  36.  
  37. BEGIN_MESSAGE_MAP(CPalCtrl, COleControl)
  38.     //{{AFX_MSG_MAP(CPalCtrl)
  39.     ON_WM_ERASEBKGND()
  40.     //}}AFX_MSG_MAP
  41.     ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
  42. END_MESSAGE_MAP()
  43.  
  44.  
  45. /////////////////////////////////////////////////////////////////////////////
  46. // Dispatch map
  47.  
  48. BEGIN_DISPATCH_MAP(CPalCtrl, COleControl)
  49.     //{{AFX_DISPATCH_MAP(CPalCtrl)
  50.     DISP_PROPERTY_EX(CPalCtrl, "Length", GetLength, SetLength, VT_I2)
  51.     DISP_PROPERTY_EX(CPalCtrl, "Handle", GetHandle, SetNotSupported, VT_HANDLE)
  52.     DISP_PROPERTY_EX(CPalCtrl, "Picture", GetPicture, SetPicture, VT_PICTURE)
  53.     DISP_PROPERTY_PARAM(CPalCtrl, "Entry", GetEntry, SetEntry, VT_COLOR, VTS_I2)
  54.     DISP_DEFVALUE(CPalCtrl, "Handle")
  55.     //}}AFX_DISPATCH_MAP
  56.     DISP_FUNCTION_ID(CPalCtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
  57. END_DISPATCH_MAP()
  58.  
  59.  
  60. /////////////////////////////////////////////////////////////////////////////
  61. // Event map
  62.  
  63. BEGIN_EVENT_MAP(CPalCtrl, COleControl)
  64.     //{{AFX_EVENT_MAP(CPalCtrl)
  65.     //}}AFX_EVENT_MAP
  66. END_EVENT_MAP()
  67.  
  68.  
  69. /////////////////////////////////////////////////////////////////////////////
  70. // Property pages
  71.  
  72. // TODO: Add more property pages as needed.  Remember to increase the count!
  73. BEGIN_PROPPAGEIDS(CPalCtrl, 2)
  74.     PROPPAGEID(CPalPropPage::guid)
  75.     PROPPAGEID(CLSID_CPicturePropPage)
  76. END_PROPPAGEIDS(CPalCtrl)
  77.  
  78.  
  79. /////////////////////////////////////////////////////////////////////////////
  80. // Initialize class factory and guid
  81.  
  82. IMPLEMENT_OLECREATE_EX(CPalCtrl, "PAL.PalCtrl.1",
  83.     0x5733f76e, 0xbe58, 0x101a, 0xb5, 0x7a, 0x0, 0x0, 0xc0, 0xc3, 0xed, 0x5f)
  84.  
  85.  
  86. /////////////////////////////////////////////////////////////////////////////
  87. // Type library ID and version
  88.  
  89. IMPLEMENT_OLETYPELIB(CPalCtrl, _tlid, _wVerMajor, _wVerMinor)
  90.  
  91.  
  92. /////////////////////////////////////////////////////////////////////////////
  93. // Interface IDs
  94.  
  95. const IID BASED_CODE IID_DPal =
  96.         { 0x37446b83, 0x5870, 0x101b, { 0xb5, 0x7b, 0x0, 0x60, 0x8c, 0xc9, 0x6a, 0xfa } };
  97. const IID BASED_CODE IID_DPalEvents =
  98.         { 0x37446b84, 0x5870, 0x101b, { 0xb5, 0x7b, 0x0, 0x60, 0x8c, 0xc9, 0x6a, 0xfa } };
  99.  
  100.  
  101. /////////////////////////////////////////////////////////////////////////////
  102. // Control type information
  103.  
  104. static const DWORD BASED_CODE _dwPalOleMisc =
  105.     OLEMISC_ACTIVATEWHENVISIBLE |
  106.     OLEMISC_SETCLIENTSITEFIRST |
  107.     OLEMISC_INSIDEOUT |
  108.     OLEMISC_CANTLINKINSIDE |
  109.     OLEMISC_RECOMPOSEONRESIZE;
  110.  
  111. IMPLEMENT_OLECTLTYPE(CPalCtrl, IDS_PAL, _dwPalOleMisc)
  112.  
  113.  
  114. /////////////////////////////////////////////////////////////////////////////
  115. // CPalCtrl::CPalCtrlFactory::UpdateRegistry -
  116. // Adds or removes system registry entries for CPalCtrl
  117.  
  118. BOOL CPalCtrl::CPalCtrlFactory::UpdateRegistry(BOOL bRegister)
  119. {
  120.     if (bRegister)
  121.         return AfxOleRegisterControlClass(
  122.             AfxGetInstanceHandle(),
  123.             m_clsid,
  124.             m_lpszProgID,
  125.             IDS_PAL,
  126.             IDB_PAL,
  127.             FALSE,                      //  Not insertable
  128.             _dwPalOleMisc,
  129.             _tlid,
  130.             _wVerMajor,
  131.             _wVerMinor);
  132.     else
  133.         return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
  134. }
  135.  
  136.  
  137. /////////////////////////////////////////////////////////////////////////////
  138. // CPalCtrl::CPalCtrl - Constructor
  139.  
  140. CPalCtrl::CPalCtrl()
  141. {
  142.     InitializeIIDs(&IID_DPal, &IID_DPalEvents);
  143.  
  144.     m_iPalette = NULL;
  145. }
  146.  
  147.  
  148. /////////////////////////////////////////////////////////////////////////////
  149. // CPalCtrl::~CPalCtrl - Destructor
  150.  
  151. CPalCtrl::~CPalCtrl()
  152. {
  153.     if (m_iPalette) delete m_iPalette;
  154. }
  155.  
  156.  
  157. /////////////////////////////////////////////////////////////////////////////
  158. // CPalCtrl::OnDraw - Drawing function
  159.  
  160. void CPalCtrl::OnDraw(
  161.             CDC* pdc, const CRect& rcBounds, const CRect&)
  162. {
  163.     CPalette *oldPalette;
  164.     CPalette *pPalette;
  165.     CPalette tempPalette;
  166.     CBrush *oldBrush;
  167.     CBrush *brush;
  168.     int    i;
  169.     int    height;
  170.     int    stripeWidth;
  171.     short  palNumEntries = 0;
  172.  
  173.     if (m_iPalette)
  174.         pPalette = m_iPalette;
  175.     else
  176.     {
  177.         // Use stock palette if control palette is NULL
  178.         tempPalette.CreateStockObject(DEFAULT_PALETTE);
  179.         pPalette = &tempPalette;
  180.     }
  181.  
  182.     // Select and realize palette
  183.     oldPalette = pdc->SelectPalette(pPalette, TRUE);
  184.     pdc->RealizePalette();
  185.  
  186.     // Get number of palettes entries
  187.     pPalette->GetObject(sizeof(palNumEntries), (LPVOID)&palNumEntries);
  188.  
  189.     height = rcBounds.Height();
  190.  
  191.     // Calculate width of stripes
  192.     stripeWidth = rcBounds.Width();
  193.     stripeWidth = stripeWidth / (int)palNumEntries;
  194.     ++stripeWidth;
  195.  
  196.     pdc->IntersectClipRect(rcBounds);
  197.  
  198.     // Draw each stripe
  199.     for (i = 0; i < palNumEntries; i++)
  200.     {
  201.         brush = new CBrush;
  202.         // A palette-relative brush is used for drawing.
  203.         if (brush->CreateSolidBrush(PALETTEINDEX(i)) == TRUE)
  204.         {
  205.             // Setup brush
  206.             oldBrush = pdc->SelectObject(brush);
  207.             brush->UnrealizeObject();
  208.  
  209.             // Draw stripe
  210.             pdc->PatBlt(rcBounds.left + i*stripeWidth, rcBounds.top,
  211.                 stripeWidth, height, PATCOPY);
  212.             pdc->SelectObject(oldBrush);
  213.         }
  214.         delete brush;
  215.     }
  216.  
  217.     // Back to old palette
  218.     pdc->SelectPalette(oldPalette, TRUE);
  219.     pdc->RealizePalette();
  220. }
  221.  
  222.  
  223. /////////////////////////////////////////////////////////////////////////////
  224. // CPalCtrl::DoPropExchange - Persistence support
  225.  
  226. void CPalCtrl::DoPropExchange(CPropExchange* pPX)
  227. {
  228.     short nLength;
  229.  
  230.     ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
  231.     COleControl::DoPropExchange(pPX);
  232.  
  233.     // Get Length if not loading
  234.     if (!pPX->IsLoading())
  235.         nLength = GetLength();
  236.  
  237.     // Transfer property value to/from local variable
  238.     PX_Short(pPX, _T("Length"), nLength, 20);
  239.  
  240.     // Set Length if loading
  241.     if (pPX->IsLoading())
  242.         SetLength(nLength);
  243. }
  244.  
  245.  
  246. /////////////////////////////////////////////////////////////////////////////
  247. // CPalCtrl::Serialize - Persistence support
  248.  
  249. void CPalCtrl::Serialize(CArchive& ar)
  250. {
  251.     short nLength;
  252.     long lEntry;
  253.     short i;
  254.  
  255.     COleControl::Serialize(ar);
  256.  
  257.     nLength = GetLength();
  258.  
  259.     if (ar.IsLoading())
  260.     {
  261.         // Load each entry
  262.         for (i = 0; i < nLength; i++)
  263.         {
  264.             // Load entry
  265.             ar >> lEntry;
  266.             SetEntry(i, lEntry);
  267.         }
  268.     }
  269.     else
  270.     {
  271.         // Store each entry
  272.         for (i = 0; i < nLength; i++)
  273.         {
  274.             // Store entry
  275.             lEntry = GetEntry(i);
  276.            ar << lEntry;
  277.         }
  278.     }
  279. }
  280.  
  281.  
  282. /////////////////////////////////////////////////////////////////////////////
  283. // CPalCtrl::OnResetState - Reset control to default state
  284.  
  285. void CPalCtrl::OnResetState()
  286. {
  287.     if (m_iPalette) delete m_iPalette;
  288.     m_iPalette = NULL;
  289.  
  290.     COleControl::OnResetState();  // Resets defaults found in DoPropExchange
  291.  
  292.     SetModifiedFlag(TRUE);
  293. }
  294.  
  295.  
  296. /////////////////////////////////////////////////////////////////////////////
  297. // CPalCtrl::AboutBox - Display an "About" box to the user
  298.  
  299. void CPalCtrl::AboutBox()
  300. {
  301.     CDialog dlgAbout(IDD_ABOUTBOX_PAL);
  302.     dlgAbout.DoModal();
  303. }
  304.  
  305.  
  306. /////////////////////////////////////////////////////////////////////////////
  307. // CPalCtrl::GetLength - Return the length of the palette.
  308.  
  309. short CPalCtrl::GetLength()
  310. {
  311.     short nLength;
  312.     CPalette *pPalette;
  313.     CPalette tempPalette;
  314.  
  315.     if (m_iPalette)
  316.         pPalette = m_iPalette;
  317.     else
  318.     {
  319.         // Use stock palette if control palette is NULL
  320.         tempPalette.CreateStockObject(DEFAULT_PALETTE);
  321.         pPalette = &tempPalette;
  322.     }
  323.  
  324.     // Get number of entries
  325.     pPalette->GetObject(sizeof(nLength), LPVOID(&nLength));
  326.  
  327.     return nLength;
  328. }
  329.  
  330.  
  331. /////////////////////////////////////////////////////////////////////////////
  332. // CPalCtrl::SetLength - Set the length of the palette.  Causes the palette
  333. // to be extended (with black entries) or truncated to the specified length.
  334.  
  335. void CPalCtrl::SetLength(short nNewValue)
  336. {
  337.     HPALETTE hpal;
  338.  
  339.     if (!m_iPalette)
  340.     {
  341.         // If control palette is NULL, set it to copy of stock palette
  342.         hpal = CopyPalette((HPALETTE)GetStockObject(DEFAULT_PALETTE));
  343.         if (!hpal)
  344.             ThrowError(CTL_E_OUTOFMEMORY, AFX_IDP_E_OUTOFMEMORY);
  345.         else
  346.         {
  347.             m_iPalette = new CPalette();
  348.             m_iPalette->Attach(hpal);
  349.         }
  350.     }
  351.  
  352.     // Resize palette
  353.     if (!m_iPalette->ResizePalette(nNewValue))
  354.         ThrowError(PAL_E_CANTRESIZEPALETTE, IDS_EXCEP_CANTRESIZEPALETTE);
  355.  
  356.     SetModifiedFlag(TRUE);
  357.     InvalidateControl();
  358. }
  359.  
  360.  
  361. /////////////////////////////////////////////////////////////////////////////
  362. // CPalCtrl::GetHandle - Return the handle of the palette.
  363.  
  364. OLE_HANDLE CPalCtrl::GetHandle()
  365. {
  366.     if (m_iPalette)
  367.         return (OLE_HANDLE)m_iPalette->m_hObject;
  368.     else
  369.         // Return handle of stock palette if control palette is NULL
  370.         return (OLE_HANDLE)GetStockObject(DEFAULT_PALETTE);
  371. }
  372.  
  373.  
  374. /////////////////////////////////////////////////////////////////////////////
  375. // CPalCtrl::GetPicture - Return a picture containing the palette of the
  376. // palette control.
  377.  
  378. LPPICTUREDISP CPalCtrl::GetPicture()
  379. {
  380.     HDC       hdcScr;
  381.     HBITMAP   hbmp;
  382.     HPALETTE  hpal;
  383.     CPictureHolder picHolder;
  384.  
  385.     // Create a picture using a 1x1 bitmap and a copy of our current
  386.     // palette
  387.  
  388.     // Create 1x1 bitmap
  389.     hdcScr = ::GetDC(NULL);
  390.     hbmp = CreateBitmap(1, 1,
  391.                 (BYTE)GetDeviceCaps(hdcScr, PLANES),
  392.                 (BYTE)GetDeviceCaps(hdcScr, BITSPIXEL),
  393.                 NULL);
  394.     ::ReleaseDC(NULL, hdcScr);
  395.     if (!hbmp)
  396.         ThrowError(CTL_E_OUTOFMEMORY, AFX_IDP_E_OUTOFMEMORY);
  397.  
  398.     if (m_iPalette)
  399.     {
  400.         // Make a copy of the palette we're using
  401.         hpal = CopyPalette((HPALETTE)m_iPalette->m_hObject);
  402.         if (!hpal)
  403.             ThrowError(CTL_E_OUTOFMEMORY, AFX_IDP_E_OUTOFMEMORY);
  404.     }
  405.     else
  406.         hpal = NULL;
  407.  
  408.     // Create picture using bitmap and palette
  409.     picHolder.CreateFromBitmap(hbmp, hpal, TRUE);
  410.  
  411.     return picHolder.GetPictureDispatch();
  412. }
  413.  
  414.  
  415. /////////////////////////////////////////////////////////////////////////////
  416. // CPalCtrl::SetPicture - Set the control's palette to the palette of the
  417. // passed picture.
  418.  
  419. void CPalCtrl::SetPicture(LPPICTUREDISP newValue)
  420. {
  421.     COleDispatchDriver driver;
  422.     HPALETTE hpal1, hpal2;
  423.  
  424.     if (newValue)
  425.     {
  426.         // Obtain hPal property from picture
  427.         driver.AttachDispatch(newValue, FALSE);
  428.         driver.GetProperty(DISPID_PICT_HPAL, VT_HANDLE, (void*)&hpal1);
  429.         if (hpal1)
  430.         {
  431.             // If palette object exists, free its HPAL
  432.             if (m_iPalette)
  433.                 m_iPalette->Detach();
  434.             // Else instantiate a new palette object
  435.             else m_iPalette = new CPalette;
  436.  
  437.             // Copy the palette from the picture
  438.             hpal2 = CopyPalette(hpal1);
  439.             if (!hpal2)
  440.                 ThrowError(CTL_E_OUTOFMEMORY, AFX_IDP_E_OUTOFMEMORY);
  441.  
  442.             // Attach new HPAL
  443.             m_iPalette->Attach(hpal2);
  444.  
  445.             SetModifiedFlag(TRUE);
  446.             InvalidateControl();
  447.             return;
  448.         }
  449.     }
  450.  
  451.     // If new hPal not obtained, delete palette object so stock palette will
  452.     // be used.
  453.     if (m_iPalette)
  454.     {
  455.         delete m_iPalette;
  456.         m_iPalette = NULL;
  457.     }
  458.     SetModifiedFlag(TRUE);
  459.     InvalidateControl();
  460. }
  461.  
  462.  
  463. /////////////////////////////////////////////////////////////////////////////
  464. // CPalCtrl::GetEntry - Return a palette entry.
  465.  
  466. OLE_COLOR CPalCtrl::GetEntry(short nIndex)
  467. {
  468.     PALETTEENTRY palentry;
  469.     CPalette *pPalette;
  470.     CPalette tempPalette;
  471.  
  472.     if (m_iPalette)
  473.         pPalette = m_iPalette;
  474.     else
  475.     {
  476.         // Use stock palette if control palette is NULL
  477.         tempPalette.CreateStockObject(DEFAULT_PALETTE);
  478.         pPalette = &tempPalette;
  479.     }
  480.  
  481.     // Get palette entry
  482.     if (!pPalette->GetPaletteEntries(nIndex, 1, &palentry))
  483.         ThrowError(CTL_E_INVALIDPROPERTYARRAYINDEX, AFX_IDP_E_INVALIDPROPERTYARRAYINDEX);
  484.  
  485.     return (OLE_COLOR)RGB(palentry.peRed, palentry.peGreen, palentry.peBlue);
  486. }
  487.  
  488.  
  489. /////////////////////////////////////////////////////////////////////////////
  490. // CPalCtrl::SetEntry - Set a palette entry.
  491.  
  492. void CPalCtrl::SetEntry(short nIndex, OLE_COLOR newValue)
  493. {
  494.     COLORREF colorref;
  495.     PALETTEENTRY    palentry;
  496.     HPALETTE hpal;
  497.  
  498.     if (!m_iPalette)
  499.     {
  500.         // If control palette is NULL, set it to copy of stock palette
  501.         hpal = CopyPalette((HPALETTE)GetStockObject(DEFAULT_PALETTE));
  502.         if (!hpal)
  503.             ThrowError(CTL_E_OUTOFMEMORY, AFX_IDP_E_OUTOFMEMORY);
  504.         else
  505.         {
  506.             m_iPalette = new CPalette();
  507.             m_iPalette->Attach(hpal);
  508.         }
  509.     }
  510.  
  511.     // Build an entry and set it in the palette
  512.     colorref = TranslateColor(newValue);
  513.     palentry.peRed   = GetRValue(colorref);
  514.     palentry.peGreen = GetGValue(colorref);
  515.     palentry.peBlue  = GetBValue(colorref);
  516.     palentry.peFlags = 0;
  517.  
  518.     if (!m_iPalette->SetPaletteEntries(nIndex, 1, &palentry))
  519.         ThrowError(CTL_E_INVALIDPROPERTYARRAYINDEX, AFX_IDP_E_INVALIDPROPERTYARRAYINDEX);
  520.  
  521.     SetModifiedFlag(TRUE);
  522.     InvalidateControl();
  523. }
  524.  
  525.  
  526. /////////////////////////////////////////////////////////////////////////////
  527. // CPalCtrl::OnMapPropertyToPage - Map picture property to picture page.
  528.  
  529. BOOL CPalCtrl::OnMapPropertyToPage(DISPID dispid, LPCLSID lpclsid,
  530.     BOOL* pbPageOptional)
  531. {
  532.     switch(dispid)
  533.     {
  534.         case dispidPicture:
  535.             *lpclsid = CLSID_CPicturePropPage;
  536.             return TRUE;
  537.     }
  538.     return COleControl::OnMapPropertyToPage(dispid, lpclsid, pbPageOptional);
  539. }
  540.  
  541.  
  542. /////////////////////////////////////////////////////////////////////////////
  543. // CPalCtrl::OnEraseBkgnd - Simply return TRUE so background is not erased.
  544.  
  545. BOOL CPalCtrl::OnEraseBkgnd(CDC*)
  546. {
  547.     return TRUE;
  548. }
  549.  
  550.  
  551. /////////////////////////////////////////////////////////////////////////////
  552. // CopyPalette - Return a copy of a GDI palette object.
  553.  
  554. HPALETTE CopyPalette(HPALETTE srcpal)
  555. {
  556.     HGLOBAL hmem;
  557.     HPALETTE destpal;
  558.     PLOGPALETTE ppal;
  559.     int nNumEntries;
  560.  
  561.     if (!srcpal)
  562.         return NULL;
  563.  
  564.     GetObject(srcpal, sizeof(int), (LPSTR)&nNumEntries);
  565.  
  566.     if (nNumEntries == 0)
  567.         return NULL;
  568.  
  569.     // Allocate buffer for palette info
  570.     hmem = GlobalAlloc(LPTR, (WORD)(sizeof(LOGPALETTE) + nNumEntries * sizeof(PALETTEENTRY)));
  571.     if (!hmem)
  572.         return NULL;
  573.  
  574.     ppal = (PLOGPALETTE)GlobalLock(hmem);
  575.  
  576.     // Init palette header info
  577.     ppal->palVersion  = 0x300;
  578.     ppal->palNumEntries = (WORD)nNumEntries;
  579.  
  580.     // Copy entries
  581.     GetPaletteEntries(srcpal, 0, (WORD)nNumEntries, ppal->palPalEntry);
  582.  
  583.     // Create palette
  584.     destpal = CreatePalette(ppal);
  585.  
  586.     GlobalFree(hmem);
  587.     return destpal;
  588. }
  589.