Elements of graphics. Graphics Tools (TGraphicTool) and Drawing Canvas (TCanvas)
When creating projects on Windows, there is at least one task that is extremely difficult to program using a pure API. This is drawing on a DC (DC - Device Context) window or on a temporary image in memory (bitmap, i.e. a bitmap, a common name for a bitmap) using drawing tools - fonts, pencils and brushes ... Without object programming, this task becomes very difficult, the code is confusing and cumbersome, it is extremely easy to make mistakes in it, or simply "forget" to destroy any GDI tool (GDI - Graphic Device Interface). As a result, a so-called "resource leak" can appear in the program (which can lead to the fact that all resources in the system, the number of which is limited, run out,
To do this, both VCL and KOL create a TCanvas object (only in KOL this is an object type, and in VCL - a class), and a set of tools encapsulating a font (font), a brush (brush) and a pencil (pen). The VCL uses a standard approach for these three graphics tools: there is a base class TGraphicsObject, which inherits the TFont, TBrush and TPen classes. In the KOL library, heirs are saved, and all three types of graphic tools are represented by the same object type TGraphicTool. Of course, they have different constructors, and the functionality of the object and the set of supported properties are different. For this reason, you should not try, for example, to change the FontName property for a brush - it still does nothing.
Constructors:
NewCanvas(DC) - creates a canvas object (if DC is specified, then this canvas is bound to an existing device context, usually for an in-memory image). In real programming, it is almost never necessary to create a canvas on your own, instead, you should use the Canvas property of the corresponding object to draw on a bitmap or in a window, the same applies to the following graphic tool constructors: usually you should use the Font, Brush and Pen properties of the canvas itself or a visual object;
NewFont - creates a font (returns a PGraphicTool);
NewBrush - creates a brush (returns PGraphicTool);
NewPen - creates a pencil (returns a PGraphicTool).
Now about the properties and methods of the canvas. They are basically the same as in the VCL. But there are also differences. The most important difference is how the GDI resources used by the application are prevented from growing too much. Dealing with the subtle and complex mechanism that implements this task in the VCL, I once spent more than one evening trying to figure out how it works there. This is somewhat similar to automatic garbage collection, which is sometimes used by memory managers. I decided to use a simpler algorithm for KOL. These are all internal implementation details, and I cannot dwell on them in more detail now, but I note that as a result, the canvas in the KOL library has a little more restrictions on its use.
For example, you should not take the canvas of a window object at an arbitrary point in time and start drawing something on it. You should draw exactly when processing of the OnPaint message begins (that is, when the system allows you to do it). What should you do if you need to render some animation and update the image in the window at certain intervals? The correct solution is to "tell" the system that the window is "damaged" and needs to be redrawn after the next time interval (for example, by the OnTimer event in the "clock" object) (for example, call the Invalidate method of the corresponding window object). After that, the system itself will send the message WM_ERASEBKGND (erase the background) and WM_PAINT (draw the content) to the window, and the OnPaint event handler will be called,
Graphical tool objects have several properties in common:
Handle - graphic object descriptor;
HandleAllocated - checks that the descriptor has been created (if you just refer to the Handle property, the descriptor will be created, so it makes no sense to check if it is equal to zero for this purpose);
OnChange - an event that is triggered when any properties of a graphic instrument change;
ReleaseHandle - takes ownership of the handle from the tool, returning the previous handle (Handle);
Assign(GT) - assigns all the properties of the specified tool to this one (the type of tool must be the same, i.e. a brush can be assigned to a brush, etc.);
Color - color.
All other properties are different, including by name.
Brush properties:
BrushBitmap - a bitmap (i.e. a picture) that is used for filling when a brush is used to fill;
BrushStyle - brush style (especially interesting are the bsSolid style - the main style for filling, and bsClear - when the brush does not work, this style of the "transparent" brush allows you to keep the matte intact in all drawing operations on the canvas);
BrushLineColor - line color for brush with styles (BrushStyle) of hatching with lines.
Pencil properties:
PenWidth - the width of the pencil in pixels;
PenStyle - pencil style (the degree of hatching of the line, there is also psClear, which allows you to ignore the pencil when drawing);
PenMode - pencil drawing mode (black, white, color, inverse, etc.);
GeometricPen - sets the so-called "geometric" pencil (in contrast to the non-geometric pencil, it allows you to set the type of outline of the line ends, see PenJoin and PenEndCap);
PenBrushStyle - brush style for a geometric pencil with shading;
PenBrushBitmap - bitmap for filling when drawing with a geometric pencil;
PenEndCap - the shape of the end of the line for a geometric pencil (round, square, flat);
PenJoin - way of connecting lines (round, boundary, middle).
Properties for the font (Font):
FontHeight - font height in pixels (an exception for a rich edit object: for it, the font height is set in special units called twips (literally: twentieth), and equal to 1/20 of the height of a point on the printer, or 1/1440 inch, or 1 / 10 pixels - approximate, depending on display resolution);
FontWidth - font width in pixels, if 0, then the standard font width for the current height is used, in KOL this can be changed by narrowing or thickening the fonts to your liking;
FontPitch - font style (monospaced, proportional or default);
FontStyle - a set of font styles (bold - see also FontWeight, oblique, underlined, strikethrough);
FontCharset - character set (forced selection of one or another national character set);
FontQuality - the quality of the font drawing;
FontOrientation - the angle of rotation of the font in grades, i.e. in 1/10 degree. A value of 900 corresponds to the rotation of the font 90 degrees counterclockwise. This property works only for TrueType fonts (for example, Arial or Times);
FontWeight - sets the exact value for font thickening. If set to a nonzero value, then the fsBold indication, i.e. bold is ignored in font styles. The value 700 corresponds to the fsBold style, the value 400 - to the fsNormal style, the others are in accordance with the obtained calibration scale;
FontName - font name;
IsFontTrueType - checks if the font is a TrueType font (ie "truly scalable").
In addition, a little more detailed information on the use of fonts in visual objects. In a KOL application (including MCK projects) it is possible not to specify a font at all, in this case the system font (extremely large, FixedSys) will be used. In general, MCK projects use the "default" font as the default font, the characteristics of which are recorded in the global DefFont structure. Initially, this is MS Sans Serif with a height of 0, i.e. the height depends on the default settings for the desktop (and the default font color is taken from the global variable DefFontColor, originally clWindowText). If you change these variables before creating the first visual, then all fonts (assigned by default) in the application will change.
As for KOL applications (i.e., those written without using MCK, if you don't change them at all and don't refer to the Font property, then the FixedSys system font will be used, and if you refer to at least one font property of the visual object, then both this visual object and all its child objects will have their DefFont applied first, and then the specified property will be modified (if it is modified).
And finally, I will give a list of canvas properties and methods that you may need when programming drawing:
Handle - handle to the device context (the same DC with which the canvas object is associated). It is provided so that it remains possible to perform any low-level operations using API functions if there is no equivalent for them in the TCanvas object. Also, the canvas descriptor can always be passed as a parameter to functions that are focused on working with the DC device context, and may not know anything about the canvas, and not use its methods;
PenPos - the position of the pencil, remembers the last coordinate used in the MoveTo and LineTo methods;
Pen - a property that provides a "pencil" object;
Brush - a property that provides a brush object;
Font - a property that provides a "font" object;
Arc(X1, Y1, X2, Y2, X3, Y3, X4, Y4) - draws an elliptical arc - along the curve of the ellipse, limiting the ellipse to points (X1, Y1) and (X2, Y2) and drawing the curve counterclockwise starting with point ( X3, Y3) and up to point (X4, Y4), use a pencil (Pen) for drawing;
Chord(X1, Y1, X2, Y2, X3, Y3, X4, Y4) - Draws a shape bounded by an arch and a chord connecting the ends of the arch. The bounding line is drawn using a pencil (Pen), the interior of the resulting shape is filled with a brush (Brush);
DrawFocusRect(R) - draws a focus frame along the specified rectangle (Pen is used in XOR mode, i.e. repeated call of the same method returns the image to its original state);
Ellipse(X1, Y1, X2, Y2) - draws an ellipse bounded by a rectangle specified by two vertices at points (X1, Y1) and (X2, Y2). To draw the border, use a pencil (Pen), fill the inside of the ellipse with a brush (Brush);
FillRect(R) - fills rectangle R using a brush (Brush);
FillRgn(rgn) - fills the specified region using a brush (Brush);
Floodfill(X, Y, Color, FillStyle) - filling the area either filled with Color, or vice versa, up to the border of Color, depending on the FillStyle, with a brush (Brush);
FrameRect(R) - draws the border of the specified rectangle using a brush (Brush);
MoveTo(X, Y) - moves the pencil to point (X, Y);
LineTo(X, Y) - draws a straight line from the current position of the pencil to point (X, Y) with the pencil tool (Pen);
Pie(X1, Y1, X2, Y2, X3, Y3, X4, Y4) - draws a sector based on an elliptical arc and centered in the center of an ellipse inscribed in a rectangle (X1, Y1), (X2, Y2), the arc is is drawn counterclockwise from point (X3, Y3) to point (X4, Y4), the border of the resulting shape is drawn with a pencil (Pen), and the inner part of the sector is painted over with a brush (Brush);
Polygon(pts) - draws a polygon based on an array of specified points (the last point in the array is connected to the first one), the border is drawn with a pencil, and the inner part is filled with a brush;
Polyline(pts) - draws a polyline along a given array of points using a pencil;
Rectangle(X1, Y1, X2, Y2) - draws a rectangle with vertices at points (X1, Y1), (X2, Y2), the border is drawn with a pencil, the interior is filled with a brush;
RoundRect(X1, Y1, X2, Y2, X3, Y3) - draws a rectangle with rounded corners, using an ellipse of height Y3 and width X3 for rounding;
TextOut(X, Y, s) - draws text s from point (X, Y) with the current font (Font) and filling the background with a brush (Brush);
ExtTextOut(X, Y, options, s, spacing) - draws text in a given rectangle using additional options and an array of letter spacing (spacing), for more details, see the description of the ExtTextOut API function, which this method calls;
DrawText(s, R, flags) - draws text in a rectangle using the DrawText API function and allows you to format the text in accordance with the specified flags;
TextRect(R, X, Y, s) - draws text, limiting the drawing area to rectangle R;
TextExtent(s) - calculates the size of the text in pixels;
TextArea(s, sz, pt) - calculates the size of the rectangle and the starting point for the given text and the current font (taking into account its orientation, i.e. rotation angle, and other properties) and the starting point for setting in text rendering methods;
TextWidth(s) - calculates the width of the text;
TextHeight(s) - calculates the height of the text;
ClipRect - returns the current bounding rectangle of the output area;
ModeCopy - the current copy mode (for the CopyRect method);
CopyRect(Rdst, srcDC, Rsrc) - copies a rectangle from another (or the same) canvas, possibly performing stretching / compressing or even flipping horizontally or vertically along the way, depending on the specified coordinates of the source and destination rectangles;
OnChange - an event that fires as soon as the content of the canvas changes;
Assign(srcCanvas) - assigns the content and parameters of the specified canvas to this canvas, including copying graphic tools;
RequiredState(i) - the method is mainly for internal use, ensures that the descriptors of the required graphic tools are ready for drawing, the input parameter can be a combination (OR combination) of the HandleValid, FontValid, BrushValid, PenValid and ChangingCanvas flags;
DeselectHandles - detaches all instruments from the canvas. It makes sense to use this method if you made direct changes to the font, brush or pencil parameters through API functions, and you need to ensure that the descriptors for these tools are recreated and attached to the canvas with the corrected descriptors before further drawing. This function is also mainly intended for internal use;
Pixels[X, Y] - slow access to canvas pixels (for fast pixel-by-pixel drawing on a bitmap in memory, it is recommended to use the Scanline [] property of the TBitmap object).
As you can see, the main set of canvas properties and methods is just as rich as in the VCL. In addition, there are a number of additions that allow you to work with Unicode text from a non-UNICODE application (in a UNICODE application, all the usual functions for working with text are automatically translated into their UNICODE compatible counterparts):
WTextOut(X, Y, s) - displays a Unicode string at the specified coordinates (analogous to TextOut);
WExtTextOut(X, Y, options, s, spacing) - similar to ExtTextOut, but for Unicode text;
WDrawText(s, R, flags) - analogue of DrawText for Unicode;
WTextRect(R, X, Y, s) - analogue of TextRec for Unicode;
WTextExtent(s) - similar to TextExtent, calculates the size of text in pixels;
WTextWidth(s) - the width of the Unicode text in pixels;
WTextHeight(s) - the height of the Unicode text in pixels.
And to wrap up my discussion of canvas and the tools for painting on canvas, here are the KOL functions for working with color. The color, just like in the VCL, is stored in a 32-bit integer variable (of the TColor type), in which a sign (less than zero) means that this is a system color constant corresponding to one of the system elements in the desktop setting, and the lower three bytes - in all other cases, the values of the red, green and blue color channels are stored in the usual color coding system R, G, B (R is the least significant byte, B is the most significant byte in the triplet).
There are a number of color conversion functions:
Color2RGB(C) - converts the system color to RGB-encoding (if the color is already specified by the RGB-code, then it is also returned as a result);
ColorsMix(C1, C2) - mixes two colors (arithmetic mean for each of the R, G, B channels), both colors are preliminarily converted to RGB;
Color2RGBQuad(C) - for a given color, returns a TRGBQuad structure (used in 32-bit bitmaps to store individual pixels, for example);
Color2Color16(C) - Returns the color as represented for a 16-bit color palette with 64K colors;
Color2Color15(C) - similar, but for a palette of 32K colors.