A device context is a device independent means of specifying graphics. A device context may be associated with a video display or a printer or other device. The functions that may be used for creating a new device context are shown in the table below.
begin_paint | Creates a device context suitable for painting a window. |
get_device_context | Creates a display device context. |
get_window_device_context | Creates a display device context for the entire window. |
get_device_context_extended | Creates a display device context with clipping control. |
create_device_context | Creates a device context suitable for printing. |
create_memory_device_context | Creates a memory device context. |
create_informational_device_context | Creates an information only device context. |
create_metafile | Creates a metafile device context. |
The first of these functions: begin_paint is usually called in response to the message message::paint. When the application is finished with such a device context, it should call end_paint to release the device context. This sequence creates a device context with attributes suitable for immediate drawing and validates the entire window (the invalid region of a window is the area marked as requiring painting). Drawing in a device context of this type implies that such drawing is clipped to the invalid region of the window. The rectangle found in the paint structure indicates the area to which drawing is restricted. Such a mechanism creates and destroys the device context within the body of the paint message.
The function get_device_context also creates a type of device context that is suitable for drawing in a window. Drawing is not clipped to the invalid region of the window, nor is any portion of the window validated for device contexts of this type. This type of device context is useful for drawing in a window in situations other than receiving a paint message. When finished with a device context of this type, the function release_device_context should be called.
The function get_device_context_extended creates a device context type that allows for clipping control. An application should use release_device_context to destroy device contexts of this type.
The function get_window_device_context creates a device context type that allows for drawing in the entire window - non-client areas included. Applications generally use this type of device context rarely. Such a device context may be released via the function release_device_context.
The function create_device_context is the most general function that may be used to create a device context. It allows for the creation of device contexts associated with any device type, including screens and printers. For example, this function may be used to create a screen device context as shown below.
handle device_context = create_device_context("DISPLAY",0,0,0);
Device contexts of this type are destroyed via the function delete_device_context.
The function create_informational_device_context creates a device context whose sole function is to query attributes of the associated device. Device contexts of this type should be destroyed via a call to the function delete_device_context. An information device for the display may be created via the following call.
handle device_context = create_informational_device_context("DISPLAY",0,0,0);
A device context of type created via the function create_memory_device_context is used for storing bitmaps. When an application no longer requires a device context of this type, it should call the function delete_device_context.
A device context created via the function create_metafile is a metafile device context. This type of device context is destroyed via a call to the function close_metafile. Upon closing such a device context, a handle of the newly created metafile is returned.
The program of this section displays device capabilities. The output of the program is shown below.
The program consists of a source code file. The program resembles the programs of the previous chapter (a 3 column textual display) but the information is provided to display the capabilities of a device context. The table includes the indices of the values to be queried and displayed.
The function get_device_capabilities is used to query the actual value of an index. The code sequence (that is part of the paint routine) that performs the query is shown below.
text_out(device_context, width_of_character + column1*width_of_capitals + column2*width_of_character, height_of_character * (i+1), buffer, print_string(buffer,"%5d", get_device_capabilities(device_context,capabilities[i].index)));
The remaining portions of the program are taken up with displaying the information so gained via this method.
The function that queries device capabilities yields detailed information about the color capabilities of the device associated with a device context. Color displays use more than 1 bit/pixel. In particular, the number of colors that may be displayed is 2bits/pixel. Sixteen color devices have 4 bits/pixel and are arranged in color planes. Such devices (VGA) have four color planes - a red plane, a green plane, a blue plane and an intensity plane. VGA devices are somewhat dated. Adapters with 8, 16 or 24 bits per pixel have a single color plane in which a number of adjacent bits are used to represent the color of each pixel.
The function get_device_capabilities allows for the determination of the organisation of memory in the video adapter and the number of colors that may be represented. The number of color planes may be queried using index capability::planes; whereas, the number of bits per pixel may be queried via the index capability::bits_pixel. The number of supported colors may be directly queried via the index capability::colors.
An unsigned integer is used to represent colors within a program. The data type that is used is shown below.
export struct color { color() { argb = (uint)color::black; } color(byte r, byte g, byte b) { argb = make_red_green_blue(255, r, g, b); } color(byte a, byte r, byte g, byte b) { argb = make_red_green_blue(a, r, g, b); } color(uint argb) { argb = argb; } uint get_value() const { return argb; } void set_value(uint argb) { argb = argb; } // common color constants enum { alice_blue = 0xfff0f8ff, antique_white = 0xfffaebd7, aqua = 0xff00ffff, aquamarine = 0xff7fffd4, azure = 0xfff0ffff, beige = 0xfff5f5dc, bisque = 0xffffe4c4, black = 0xff000000, blanched_almond = 0xffffebcd, blue = 0xff0000ff, blue_violet = 0xff8a2be2, brown = 0xffa52a2a, burly_wood = 0xffdeb887, cadet_blue = 0xff5f9ea0, chartreuse = 0xff7fff00, chocolate = 0xffd2691e, coral = 0xffff7f50, corn_flower_blue = 0xff6495ed, corn_silk = 0xfffff8dc, crimson = 0xffdc143c, cyan = 0xff00ffff, dark_blue = 0xff00008b, dark_cyan = 0xff008b8b, dark_golden_rod = 0xffb8860b, dark_gray = 0xffa9a9a9, dark_green = 0xff006400, dark_khaki = 0xffbdb76b, dark_magenta = 0xff8b008b, dark_olive_green = 0xff556b2f, dark_orange = 0xffff8c00, dark_orchid = 0xff9932cc, dark_red = 0xff8b0000, dark_salmon = 0xffe9967a, dark_seagreen = 0xff8fbc8b, dark_slate_blue = 0xff483d8b, dark_slate_gray = 0xff2f4f4f, dark_turquoise = 0xff00ced1, dark_violet = 0xff9400d3, deep_pink = 0xffff1493, deep_sky_blue = 0xff00bfff, dim_gray = 0xff696969, dodger_blue = 0xff1e90ff, firebrick = 0xffb22222, floral_white = 0xfffffaf0, forest_green = 0xff228b22, fuchsia = 0xffff00ff, gainsboro = 0xffdcdcdc, ghost_white = 0xfff8f8ff, gold = 0xffffd700, goldenrod = 0xffdaa520, gray = 0xff808080, green = 0xff008000, green_yellow = 0xffadff2f, honeydew = 0xfff0fff0, hot_pink = 0xffff69b4, indian_red = 0xffcd5c5c, indigo = 0xff4b0082, ivory = 0xfffffff0, khaki = 0xfff0e68c, lavender = 0xffe6e6fa, lavender_blush = 0xfffff0f5, lawn_green = 0xff7cfc00, lemon_chiffon = 0xfffffacd, light_blue = 0xffadd8e6, light_coral = 0xfff08080, light_cyan = 0xffe0ffff, light_golden_rod_yellow = 0xfffafad2, light_gray = 0xffd3d3d3, light_green = 0xff90ee90, light_pink = 0xffffb6c1, light_salmon = 0xffffa07a, light_sea_green = 0xff20b2aa, light_sky_blue = 0xff87cefa, light_slate_gray = 0xff778899, light_steel_blue = 0xffb0c4de, light_yellow = 0xffffffe0, lime = 0xff00ff00, lime_green = 0xff32cd32, linen = 0xfffaf0e6, magenta = 0xffff00ff, maroon = 0xff800000, medium_aquamarine = 0xff66cdaa, medium_blue = 0xff0000cd, medium_orchid = 0xffba55d3, medium_purple = 0xff9370db, medium_sea_green = 0xff3cb371, medium_slate_blue = 0xff7b68ee, medium_spring_green = 0xff00fa9a, medium_turquoise = 0xff48d1cc, medium_violet_red = 0xffc71585, midnight_blue = 0xff191970, mint_cream = 0xfff5fffa, misty_rose = 0xffffe4e1, moccasin = 0xffffe4b5, navajo_white = 0xffffdead, navy = 0xff000080, old_lace = 0xfffdf5e6, olive = 0xff808000, olive_drab = 0xff6b8e23, orange = 0xffffa500, orange_red = 0xffff4500, orchid = 0xffda70d6, pale_golden_rod = 0xffeee8aa, pale_green = 0xff98fb98, pale_turquoise = 0xffafeeee, pale_violet_red = 0xffdb7093, papaya_whip = 0xffffefd5, peach_puff = 0xffffdab9, peru = 0xffcd853f, pink = 0xffffc0cb, plum = 0xffdda0dd, powder_blue = 0xffb0e0e6, purple = 0xff800080, red = 0xffff0000, rosy_brown = 0xffbc8f8f, royal_blue = 0xff4169e1, saddle_brown = 0xff8b4513, salmon = 0xfffa8072, sandy_brown = 0xfff4a460, sea_green = 0xff2e8b57, sea_shell = 0xfffff5ee, sienna = 0xffa0522d, silver = 0xffc0c0c0, sky_blue = 0xff87ceeb, slate_blue = 0xff6a5acd, slate_gray = 0xff708090, snow = 0xfffffafa, spring_green = 0xff00ff7f, steel_blue = 0xff4682b4, tan = 0xffd2b48c, teal = 0xff008080, thistle = 0xffd8bfd8, tomato = 0xffff6347, transparent = 0x00ffffff, turquoise = 0xff40e0d0, violet = 0xffee82ee, wheat = 0xfff5deb3, white = 0xffffffff, white_smoke = 0xfff5f5f5, yellow = 0xffffff00, yellow_green = 0xff9acd32 }; // shift count and bit mask for a, r, g, b components enum { shift_alpha = 24, shift_red = 16, shift_green = 8, shift_blue = 0 }; enum { mask_alpha = 0xff000000, mask_red = 0x00ff0000, mask_green = 0x0000ff00, mask_blue = 0x000000ff }; // assemble a, r, g, b values into a 32-bit integer static uint make_red_green_blue(byte a, byte r, byte g, byte b) { return (((uint)(b) << shift_blue) | ((uint)(g) << shift_green) | ((uint)(r) << shift_red) | ((uint)(a) << shift_alpha)); } uint argb; };
The organisation of bits within the data type is depicted in the table below.
0 | blue | green | red | ||||||||
31 | ... | 24 | 23 | ... | 16 | 15 | ... | 8 | 7 | ... | 0 |
An inline function exists to create a color from its parts and is shown below.
inline color red_green_blue(byte r, byte g, byte b) {return ((color)(((byte)(r)|((unsigned char)((byte)(g))<<8))|(((unsigned)(byte)(b))<<16)));}
For example, the color magenta may be represented as red_green_blue(255,0,255) or more directly as 0xff00ff. The three inline functions that are available for extracting a particular color component from an unsigned integer are shown below.
inline byte red_value(unsigned red_green_blue) {return ((byte)(red_green_blue));} inline byte green_balue(unsigned red_green_blue) {return ((byte)(((unsigned char)(red_green_blue)) >> 8));} inline byte blue_value(unsigned red_green_blue) {return ((byte)((red_green_blue)>>16));}
The following table shows several individual colors.
Value | Color |
0x0000ff | red |
0x00ff00 | green |
0xff0000 | blue |
0x000000 | Black |
0xffffff | White |
Device contexts have associated attributes. When a device context is first created, default values are applied for attributes. The following table documents device context attributes.
All of the attributes of a device context may be saved using the function save_device_context. Saved attributes may be later restored using the function restore_device_context.
Apart from this, when registering a window class, the class style class_style::own_device_context may be applied. When this style is applied, each window of the class has its own device context set aside. In this case, when a device context is created, destroyed and later recreated, it retains the most recent device context attributes.