1 
2 // ------------------------------------------------------------------
3 // Windows 2000 Graphics API Black Book
4 // Chapter 5 - Listing 5.1 (Output Primitives Demo)
5 //
6 // Created by Damon Chandler <dmc27@ee.cornell.edu>
7 // Updates can be downloaded at: <www.coriolis.com>
8 //
9 // Please do not hesistate to e-mail me at dmc27@ee.cornell.edu
10 // if you have any questions about this code.
11 // ------------------------------------------------------------------
12 
13 
14 //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
15 #include <windows.h>
16 #include <cassert>
17 
18 // for the MakeFont() function...
19 #include "mk_font.h"
20 //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
21 
22 
23 HINSTANCE hInst;
24 const char* WndClassName = "GMainWnd";
25 LRESULT CALLBACK MainWndProc(HWND HWnd, UINT Msg, WPARAM WParam,
26    LPARAM LParam);
27 
28 
WinMain(HINSTANCE hInstance,HINSTANCE,LPTSTR,int nCmdShow)29 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR,
30    int nCmdShow)
31 {
32    hInst = hInstance;
33 
34    WNDCLASS wc;
35    memset(&wc, 0, sizeof(WNDCLASS));
36 
37    wc.style = CS_VREDRAW | CS_HREDRAW;
38    wc.lpszClassName = WndClassName;
39    wc.lpfnWndProc = MainWndProc;
40    wc.hInstance = hInst;
41    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
42    wc.hbrBackground = reinterpret_cast<HBRUSH>(
43       COLOR_BTNFACE + 1
44       );
45 
46    if (RegisterClass(&wc))
47    {
48       HWND hWnd =
49          CreateWindow(
50             WndClassName, TEXT("Output Primitives Demo"),
51             WS_OVERLAPPEDWINDOW | WS_CAPTION |
52             WS_VISIBLE | WS_CLIPCHILDREN,
53             CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
54             NULL, NULL, hInst, NULL
55             );
56 
57       if (hWnd)
58       {
59          ShowWindow(hWnd, nCmdShow);
60          UpdateWindow(hWnd);
61 
62          MSG msg;
63          while (GetMessage(&msg, NULL, 0, 0))
64          {
65              TranslateMessage(&msg);
66              DispatchMessage(&msg);
67          }
68       }
69     }
70     return 0;
71 }
72 //------------------------------------------------------------------
73 
74 
75 enum OutPrimitive {
76    opLine, opBezier, opRectangle, opRoundRect,
77    opEllipse, opArc, opPie, opChord, opCustom
78    };
79 
DrawPrimitive(IN HDC hDC,IN const RECT & RPrimitive,IN OutPrimitive PrimitiveID)80 void DrawPrimitive(IN HDC hDC, IN const RECT& RPrimitive,
81    IN OutPrimitive PrimitiveID)
82 {
83    RECT R = RPrimitive;
84    InflateRect(&R, -10, -10);
85 
86    switch (PrimitiveID)
87    {
88       case opLine:
89       {
90          const POINT PLine[] = {{R.left, R.top}, {R.right, R.bottom}};
91          Polyline(hDC, PLine, 2);
92          break;
93       }
94       case opBezier:
95       {
96          const POINT PControlPoints[] = {
97             {R.left, R.top},
98             {(R.right - R.left) / 2, R.top},
99             {(R.right - R.left) / 2, R.bottom},
100             {R.right, R.bottom}
101             };
102          PolyBezier(hDC, PControlPoints, 4);
103          break;
104       }
105       case opRectangle:
106       {
107          Rectangle(hDC, R.left, R.top, R.right, R.bottom);
108          break;
109       }
110       case opRoundRect:
111       {
112          RoundRect(hDC, R.left, R.top, R.right, R.bottom, 20, 20);
113          break;
114       }
115       case opEllipse:
116       {
117          Ellipse(hDC, R.left, R.top, R.right, R.bottom);
118          break;
119       }
120       case opArc:
121       {
122          const POINT PRads[] = {
123             {(R.right - R.left) / 3 + R.left, R.top},
124             {(R.right - R.left) / 3 + R.left, R.bottom}
125             };
126          Arc(hDC, R.left, R.top, R.right, R.bottom,
127              PRads[0].x, PRads[0].y, PRads[1].x, PRads[1].y);
128          break;
129       }
130       case opPie:
131       {
132          const POINT PRads[] = {
133             {(R.right - R.left) / 3 + R.left, R.top},
134             {(R.right - R.left) / 3 + R.left, R.bottom}
135             };
136          Pie(hDC, R.left, R.top, R.right, R.bottom,
137              PRads[0].x, PRads[0].y, PRads[1].x, PRads[1].y);
138          break;
139       }
140       case opChord:
141       {
142          const POINT PRads[] = {
143             {(R.right - R.left) / 3 + R.left, R.top},
144             {(R.right - R.left) / 3 + R.left, R.bottom}
145             };
146          Chord(hDC, R.left, R.top, R.right, R.bottom,
147              PRads[0].x, PRads[0].y, PRads[1].x, PRads[1].y);
148          break;
149       }
150       case opCustom:
151       {
152          const POINT PVertices[] = {
153             {R.left, (R.bottom - R.top) / 2 + R.top},
154             {(R.right - R.left) / 2 + R.left, R.top},
155             {R.right, (R.bottom - R.top) / 2 + R.top},
156             {(R.right - R.left) / 2 + R.left, R.bottom}
157             };
158          Polygon(hDC, PVertices, 4);
159          break;
160       }
161    }
162 }
163 //------------------------------------------------------------------
164 
165 
166 HWND hListBox = NULL;      // handle to the list box
167 HBRUSH hListBrush = NULL;  // handle to the list box brush
168 HPEN hListPen = NULL;      // handle to the list box pen
169 HFONT hListFont = NULL;    // handle to the list box font
170 
MainWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)171 LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam,
172    LPARAM lParam)
173 {
174    switch (msg)
175    {
176       case WM_CREATE:
177       {
178          hListBox =
179             CreateWindowEx(
180                WS_EX_CLIENTEDGE, TEXT("LISTBOX"), TEXT(""),
181                WS_CHILD | WS_VISIBLE | WS_VSCROLL |
182                LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT |
183                LBS_OWNERDRAWFIXED,
184                0, 0, 640, 480,
185                hWnd, NULL, hInst, NULL
186                );
187          assert(hListBox != NULL);
188 
189          SetWindowLongPtr(
190             hListBox, GWL_ID, reinterpret_cast<LONG_PTR>(hListBox)
191             );
192 
193          SNDMSG(hListBox, LB_ADDSTRING, 0,
194                 reinterpret_cast<LPARAM>(TEXT("Line")));
195          SNDMSG(hListBox, LB_ADDSTRING, 0,
196                 reinterpret_cast<LPARAM>(TEXT("Bezier Curve")));
197          SNDMSG(hListBox, LB_ADDSTRING, 0,
198                 reinterpret_cast<LPARAM>(TEXT("Rectangle")));
199          SNDMSG(hListBox, LB_ADDSTRING, 0,
200                 reinterpret_cast<LPARAM>(TEXT("Rounded Rectangle")));
201          SNDMSG(hListBox, LB_ADDSTRING, 0,
202                 reinterpret_cast<LPARAM>(TEXT("Ellipse")));
203          SNDMSG(hListBox, LB_ADDSTRING, 0,
204                 reinterpret_cast<LPARAM>(TEXT("Arc")));
205          SNDMSG(hListBox, LB_ADDSTRING, 0,
206                 reinterpret_cast<LPARAM>(TEXT("Pie Slice")));
207          SNDMSG(hListBox, LB_ADDSTRING, 0,
208                 reinterpret_cast<LPARAM>(TEXT("Chord")));
209          SNDMSG(hListBox, LB_ADDSTRING, 0,
210                 reinterpret_cast<LPARAM>(TEXT("Custom")));
211 
212          hListBrush = CreateSolidBrush(PALETTERGB(64, 192, 64));
213          hListPen = CreatePen(PS_SOLID, 3, PALETTERGB(0, 0, 0));
214          HDC hScreenDC = GetDC(NULL);
215 #if 0
216          try
217 #endif
218          {
219             // MakeFont() from Chapter 4
220             hListFont = font::MakeFont(
221                hScreenDC, "Impact", 20, ANSI_CHARSET,
222                font::FS_BOLD | font::FS_UNDERLINE
223                );
224          }
225 #if 0
226          catch (...)
227 #endif
228          {
229             ReleaseDC(NULL, hScreenDC);
230          }
231          ReleaseDC(NULL, hScreenDC);
232 
233          break;
234       }
235       case WM_MEASUREITEM:
236       {
237          LPMEASUREITEMSTRUCT lpmis =
238             reinterpret_cast<LPMEASUREITEMSTRUCT>(lParam);
239          assert(lpmis != NULL);
240 
241          if (lpmis->CtlID == reinterpret_cast<UINT_PTR>(hListBox))
242          {
243             lpmis->itemHeight = 150;
244             return TRUE;
245          }
246          break;
247       }
248       case WM_DRAWITEM:
249       {
250          LPDRAWITEMSTRUCT lpdis =
251             reinterpret_cast<LPDRAWITEMSTRUCT>(lParam);
252          assert(lpdis != NULL);
253 
254          if (lpdis->CtlID == reinterpret_cast<UINT_PTR>(hListBox))
255          {
256             SaveDC(lpdis->hDC);
257 #if 0
258             try
259 #endif
260             {
261                SelectObject(lpdis->hDC, hListBrush);
262                SelectObject(lpdis->hDC, hListPen);
263                SelectObject(lpdis->hDC, hListFont);
264 
265                bool selected = (lpdis->itemState & ODS_SELECTED);
266                COLORREF clrText = GetSysColor(
267                   selected ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT
268                   );
269                HBRUSH hListBrush = GetSysColorBrush(
270                   selected ? COLOR_HIGHLIGHT : COLOR_WINDOW
271                   );
272 
273                // fill the background
274                FillRect(lpdis->hDC, &lpdis->rcItem, hListBrush);
275 
276                // render the output primitive
277                RECT RPrimitive = lpdis->rcItem;
278                InflateRect(&RPrimitive, -5, -5);
279                RPrimitive.right = static_cast<int>(
280                   0.6 * lpdis->rcItem.right + 0.5
281                   );
282                FillRect(
283                   lpdis->hDC, &RPrimitive,
284                   reinterpret_cast<HBRUSH>(COLOR_BTNFACE + 1)
285                   );
286                DrawPrimitive(
287                   lpdis->hDC, RPrimitive,
288                   static_cast<OutPrimitive>(lpdis->itemID)
289                   );
290                if (selected) InvertRect(lpdis->hDC, &RPrimitive);
291                DrawEdge(lpdis->hDC, &RPrimitive, EDGE_SUNKEN, BF_RECT);
292 
293                // render the text
294                TCHAR text[13];
295                if (SNDMSG(hListBox, LB_GETTEXT, lpdis->itemID,
296                           reinterpret_cast<LPARAM>(&text)) != LB_ERR)
297                {
298                   RECT RText = RPrimitive;
299                   RText.left =  RPrimitive.right;
300                   RText.right = lpdis->rcItem.right;
301 
302                   SelectObject(lpdis->hDC, hListFont);
303                   SetBkMode(lpdis->hDC, TRANSPARENT);
304                   SetTextColor(lpdis->hDC, clrText);
305 
306                   DrawText(lpdis->hDC, text, -1, &RText,
307                            DT_CENTER | DT_VCENTER | DT_SINGLELINE);
308                }
309 
310                // indicate keyboard focus
311                if (lpdis->itemState & ODS_FOCUS)
312                {
313                   RECT RFocus = lpdis->rcItem;
314                   InflateRect(&RFocus, -1, -1);
315                   DrawFocusRect(lpdis->hDC, &RFocus);
316                }
317             }
318 #if 0
319             catch (...)
320 #endif
321             {
322                RestoreDC(lpdis->hDC, -1);
323             }
324             RestoreDC(lpdis->hDC, -1);
325             return TRUE;
326          }
327          break;
328       }
329       case WM_SIZE:
330       {
331          MoveWindow(
332             hListBox, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE
333             );
334          return 0;
335       }
336       case WM_DESTROY:
337       {
338          if (hListBrush) DeleteObject(hListBrush);
339          if (hListPen) DeleteObject(hListPen);
340          if (hListFont) DeleteObject(hListFont);
341 
342          PostQuitMessage(0);
343          return 0;
344       }
345    }
346    return DefWindowProc(hWnd, msg, wParam, lParam);
347 }
348 //-------------------------------------------------------------------------
349 
350 
351 
352