zhuang@linux:~/reading/programming-windows/05-basic-drawing/$ less

Programming Windows / chapter 05

Basic Drawing

$ grep tags 05-basic-drawing.md

This post extracts some knowledge from Programming Windows Chapter 5 – Basic Drawing.

The GDI Function Calls

The several hundred function calls that comprise GDI can be classified in several broad groups:

  • Functions that get (or create) and release (or destroy) a device context. (BeginPaint and EndPaint, GetDC and ReleaseDC)
  • Functions that obtain information about the device context. (GetTextMetrics)
  • Functions that draw something Obviously.
  • Functions that set and get attributes of the device context. (SetTextColor)
  • Functions that work with GDI “objects”. First an example: By default, any lines you draw using GDI are solid and of a standard width. You may wish to draw thicker lines or use lines composed of a series of dots or dashes. The line width and this line style are not attributes of the device context. Instead, they are characteristics of a “logical pen.” You can think of a pen as a collection of bundled attributes. You create a logical pen by specifying these characteristics in the CreatePen, CreatePenIndirect, or ExtCreatePen function. Although these functions are considered to be part of GDI, unlike most GDI functions they do not require a handle to a device context. The functions return a handle to a logical pen. To use this pen, you “select” the pen handle into the device context. The current pen selected in the device context is considered an attribute of the device context. From then on, whatever lines you draw use this pen. Later on, you deselect the pen object from the device context and destroy the object. Destroying the pen is necessary because the pen definition occupies allocated memory space. Besides pens, you also use GDI objects for creating brushes that fill enclosed areas, for fonts, for bitmaps, and for other aspects of GDI.

Saving Device Contexts

You might prefer that changes you make to the attributes be saved when you release the device context so that they will be in effect the next time you call GetDC or BeginPaint. You can accomplish this by including the CS_OWNDC flag as part of the window class style when you register the window class:

wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;

Now each window that you create based on this window class will have its own private device context that continues to exist when the window is destroyed.

The GDI Mapping Mode

Windows defines eight mapping modes as follows:

Mapping ModeLogical UnitPositive X DirectionPositive Y Direction
MM_TEXTPixelRightDown
MM_LOMETRIC0.1 millimeterRightUp
MM_HIMETRIC0.01 millimeterRightUp
MM_LOENGLISH0.01 inchRightUp
MM_HIENGLISH0.001 inchRightUp
MM_TWIPS1/1440 inchRightUp
MM_ISOTROPICArbitrary (x = y)User-definedUser-defined
MM_ANISOTROPICArbitrary (x ≠ y)User-definedUser-defined

Device Coordinates and Logical Coordinates

Windows continues to use device coordinates for all messages (such as WM_MOVE, WM_SIZE, and WM_MOUSEMOVE), for all non-GDI functions, and even for some GDI functions. Think of it this way: the mapping mode is an attribute of the device context, so the only time the mapping mode comes into play is when you use GDI functions that require a handle to the device context as one of the arguments.

The Device Coordinate Systems

In all device coordinate systems, units are expressed in terms of pixels. Values on the horizontal x-axis increase from left to right, and values on the vertical y-axis increase from top to bottom.

When we use the entire screen, we are working in terms of “screen coordinates.”

“Whole-window coordinates” refer to a program’s entire application window, including the title bar, menu, scroll bars, and border.

The third device coordinate system—the one we’ve been working with the most—uses “client area coordinates.”

You can convert client-area coordinates to screen coordinates and vice versa using the functions ClientToScreen and ScreenToClient. You can also obtain the position and size of the whole window in terms of screen coordinates using the GetWindowRect functions. These three functions provide enough information to translate from any one device coordinate system to the other.

The Viewport and the Window

The viewport is specified in terms of device coordinates (pixels). Most often the viewport is the same as the client area, but it can also refer to whole-window coordinates or screen coordinates if you’ve obtained a device context from GetWindowDC or CreateDC . The point (0, 0) is the upper left corner of the client area (or the whole window or the screen). Values of x increase to the right, and values of y increase going down.

The window is specified in terms of logical coordinates, which might be pixels, millimeters, inches, or any other unit you want. You specify logical window coordinates in the GDI drawing functions.

For all mapping modes, Windows translates window (logical) coordinates to viewport (device) coordinates by the use of two formulas,

$$ \begin{aligned} xViewport &= (xWindow - xWinOrg) \times \frac{xViewExt}{xWinExt} + xViewOrg \\ yViewport &= (yWindow - yWinOrg) \times \frac{yViewExt}{yWinExt} + yViewOrg \end{aligned} $$

zhuang@linux:~/reading/programming-windows/05-basic-drawing/$ comments