Jump to content

GPIGuide - Editing Retained Graphics and Graphics Segments

From EDM2
Revision as of 17:59, 10 May 2025 by Martini (talk | contribs)

Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation

GPI Guide and Reference
  1. How to Use the GPI Guide and Reference
  2. Graphics Functions
  3. Data Types
  4. Graphics Orders
  5. Graphics Orders Data Types
  6. Errors
  7. Area and Polygon Primitives
  8. Bit Maps
  9. Creating and Drawing Retained Graphics
  10. Character String Primitives
  11. Clipping and Boundary Determination
  12. Color and Mix Attributes
  13. Correlation
  14. Coordinate Spaces and Transformations
  15. Editing Retained Graphics and Graphics Segments
  16. Fonts
  17. Graphics Attributes
  18. Line and Arc Primitives
  19. Marker Primitives
  20. Matrix Multiplication
  21. Metafiles
  22. Print Job Submission and Manipulation
  23. Presentation Spaces and Device Contexts
  24. Paths
  25. Regions
  26. Notices
  27. Glossary

This chapter describes editing retained graphics and graphics segments. The following topics are related to the information in this chapter:

  • Presentation spaces and device contexts
  • Coordinate spaces and transformations
  • Creating and drawing retained graphics

About Editing Retained Graphics and Graphics Segments

In the OS/2 operating system, applications store retained graphics in segments. One of the advantages of using graphics segments is that segments can be edited, which allows the retained image to be modified without having to re-create the unmodified portion with multiple GPI functions.

Creating and Drawing Retained Graphics described how to create a segment and store GPI functions within the segment bracket (the GPI functions bracketed by GpiOpenSegment and GpiCloseSegment). To understand how to edit a segment, the underlying structure of a segment is described here in greater detail.

The GPI functions are not inserted directly into a segment bracket. Instead, the operating system converts the GPI functions into graphics orders. A graphics order, also known as a drawing order, is the smallest complete portion of a segment. Once the GPI functions are converted into graphics orders, these orders are stored in the GpiOpenSegment-GpiCloseSegment bracket.

Generally, each of the GPI functions within the segment bracket generates one element of the segment. An element is the smallest portion of a segment that can be edited and is made up of one or more orders. The following figure illustrates the levels of graphic segment construction.

Structure of a Graphics Segment
GpiOpenSegment (...);    Graphic Segment
                        ┌───────────────────────┐              element
GpiLine (...);          │ line order            │ element 0  � pointer
                        │                       │
GpiBeginElement (...);  │ begin element order   │ element 1
                        │                       │
   GpiBox (...);        │       box order       │
   GpiPolyline (...);   │       polyline order  │
                        │                       │
GpiEndElement (...);    │ end element order     │
                        │                       │
GpiLabel (...);         │ label order           │ element 2
                        │                       │
GpiSetColor (...);      │ set-color order       │ element 3
                        └───────────────────────┘
GpiCloseSegment (...);

Elements 0, 2, and 3 are each composed of a single order. Element 1 is composed of two orders bracketed by GpiBeginElement and GpiEndElement.

Graphics Orders

A graphics order is a low-level graphics command that corresponds to a primitive function or attribute. In addition to code and data requirements, each graphics order uses approximately 11 bytes of storage. An application that uses 2000 graphics drawing orders will use around 22KB of memory to store them. The following table describes the four sizes of graphics orders.

Graphics Orders

Graphics Order Size Content
1 byte A hexadecimal identifier corresponding to a drawing function or attribute function. This identifier is also known as the order code.
2 byte The order code is in the first byte, and data is in the second byte.
Long The order code is in the first byte. The length value of the actual data, in bytes, is in the second byte. The actual data (up to 255 bytes).
Very long (maximum length of 64KB) A hexadecimal identifier specifically for extended orders, is in the first byte. The order code is in the second byte. A length value that specifies how many bytes are used by the graphics-order arguments, (high order) is in the third byte. A length value that specifies how many bytes are used by the graphics-order arguments, (low order) is in the fourth byte. The actual data.

The following example shows a long graphics order that corresponds to GpiLine: ``` 81 8 100 0 0 0 100 0 0 0 ```

The first number, 81, is the hexadecimal identifier that corresponds to GpiLine. The second number, 8, is the length value that specifies how many bytes are used by the graphics-order arguments. The next eight bytes contain the arguments for GpiLine. In this case, the arguments specify the line's end point at (100,100).

Graphics Orders
                               Graphics
                               Segment
                                      │
┌──────────────────────┐  ┌──   0x21  ┼────────── order # ──┐
│                      │  │     0x08  ┼────────── length    │
│ ptl.x = 100L;        │  │     0x00  │ ────┐               │
│ ptl.y = 100L;        │  │     0x00  │     ├──      x      │
│ GpiMove (hps, &ptl); ┼──┘     0x10  │     │               ├──  element
│ ptl.x = 200L;        │        0x00  │ ────┘               │
│ ptl.y = 400L;        │        0x00  │ ────┐               │
│ GpiMove (hps, &ptl); ┼──┐     0x00  │     ├──      y      │
│                      │  │     0x20  │     │               │
└──────────────────────┘  │     0x00  │ ────┘             ──┘
                          └──   0x81  ┼────────── order # ──┐
                                0x08  ┼────────── length    │
                                0x00  │ ────┐               │
                                0x00  │     ├──      x      │
                                0x30  │     │               ├──  element
                                0x00  │ ────┘               │
                                0x00  │ ────┐               │
                                0x00  │     ├──      y      │
                                0x40  │     │               │
                                0x00  │ ────┘             ──┘
                                      │

The encoding that appears in the Graphics Segments column is a hexadecimal version of the order, length, and parameter information.

In most cases, graphics orders in a segment correspond to a subpicture, which is part of a complete, more complex picture. Your application would combine the individual segments to form the complete picture.

Three drawing modes affect how the operating system stores graphics orders in segments. These modes are described in the following table. The default drawing mode is draw (DM_DRAW). To specify another as the current drawing mode, use GpiSetDrawingMode.

The actual drawing mode is a combination of the drawing mode as set using GpiSetDrawingMode, and the segment status—chained, unchained, or outside of the segment. The actual drawing mode does not affect the storing of orders in segments.

Segment Graphics Drawing Modes

Drawing Mode GpiSetDrawingMode Value When this mode is set...
Draw DM_DRAW it is not possible to store graphics orders in a chained segment.
Retain DM_RETAIN your application can store graphics orders in chained and unchained segments.
Draw-and-retain DM_DRAWANDRETAIN your application can store graphics orders in chained and unchained segments. In this mode, output intended for a chained segment is both drawn on the device and stored in a segment.

Graphics Elements

Graphics elements are composed of either a single graphics order, or a series of graphic orders that are bracketed by an opening and closing element function.

The purpose of this element bracket is to allow the addition of a single element, that comprises more than one graphics order, to a segment. This is most useful when you know that you will want to retrieve those orders at a later time, and manipulate them as a group rather than as individual functions.

Note: There is no reason for enclosing a single GPI function within a GpiBeginElement-GpiEndElement bracket, although it is a valid construction.

Element brackets also are valid when drawing graphics directly to the output device, but again, they serve no purpose unless converted to a retained segment at a later time. Elements cannot be nested, so two elements cannot begin in succession without an intervening GpiEndElement request. Certain GPI functions cannot be called between GpiBeginElement and GpiEndElement. For example, GpiLabel cannot be used between GpiBeginElement and GpiEndElement.

Element construction is valid only within segments.

Adding Elements to a New Segment

There are four ways of adding elements to a newly created segment:

  • Call one or more GPI functions. Each function generates one element of the segment. This is the simplest way of supplying graphics data to a segment.
  • Call GpiBeginElement, and follow it with one or more GPI functions. Close the element using GpiEndElement. All the GPI functions enclosed within the bracket and GpiBeginElement and GpiEndElement generate a single element of the segment, and therefore occupy a single-element-pointer position. Subsequently, the graphics orders cannot be accessed individually with the element pointer, although the orders can be accessed directly, for example, using GpiGetData.
  • Call GpiElement. As input, you supply the graphics orders themselves, rather than the GPI functions that generate them. No matter how much data you supply on this request, it is considered a single element of the segment. Multiple orders added to a segment in this way cannot be accessed individually using the element pointer, but they can be accessed directly, for example, using GpiGetData. GpiElement cannot be included within a GpiBeginElement-GpiEndElement bracket. The data passed by GpiElement must not include GpiBeginElement and GpiEndElement.
  • Call GpiPutData. As with GpiElement, supply graphics orders as input. You can even include GpiBeginElement and GpiEndElement orders in this data, and thus add more than one element to the segment. GpiPutData is useful when there is a large amount of data to add to a segment. GpiPutData cannot be used if the segment editing mode is set to SEGEM_REPLACE. When the segment editing mode is SEGEM_INSERT, the element pointer must point to the last element in the current segment. The segment editing mode can be set by using GpiSetEditMode. GpiPutData is most often used in conjunction with GpiGetData, which copies data as a list of drawing orders from a segment to application storage.

Element Types

Each element that results from a single GPI function has an associated element type.

The element type is generally the graphics-order code associated with the graphics order generated by the GPI function, and is supplied by the system. For example, GpiLine has the element type, OCODE_GCLINE, which identifies it as a line-drawing request. Your application can determine the current classification of an element using GpiQueryElementType.

When using GpiElement or GpiBeginElement, you can simultaneously add several graphics orders to a segment. Those orders become one element of the segment. You can supply your own classification for these compound elements by supplying a value for the type parameter of GpiElement or GpiBeginElement in the range of 0x81000000 through 0xFFFFFFFF.

For example, the orders passed by a single GpiElement function could change the line type to dotted, set the current color to blue, and draw a line. You could classify this element with a type value that identifies it as a blue dotted line.

Note: Element types are used only for classification. They are not used as location markers or correlation tags.

Element Pointer

Use the element pointer to change the contents of an existing segment. When calling GpiOpenSegment, the element pointer is set to 0. The first element that you add to a newly created segment causes the pointer to be set to 1, and each subsequent element causes the pointer to be incremented by 1. When a segment is closed, the element pointer is always reset to 0.

Your application can move the element pointer to a specified value using GpiSetElementPointer. For example, to address the sixth element in a segment, set the element pointer to 6.

Your application also can move the element pointer by a specific number, rather than to a specific number, using GpiOffsetElementPointer. For example, if the element pointer currently addresses element 3, to move it to element 8, code an offset of 5 in GpiOffsetElementPointer. The pointer moves backward rather than forward through the segment. The offset value can be a positive or negative number.

If the sum of the offset and the current pointer position is less than 0, the operating system sets the pointer so that it points to position 0. Position 0 precedes the first element in the segment. If the sum of the offset and the current pointer position is greater than the number of elements in the segment, the operating system sets the pointer so that it points to the last element in the segment.

You can determine the current location of the element pointer using GpiQueryElementPointer. To request the contents of a part of or all of the elements at the current pointer position, use GpiQueryElement.

Labels

You can include labels in a segment to make locating particular elements of the segment easier. If you label an element that is likely to be edited, you can access that element when necessary, regardless of whether the actual position of the label-element pair within the segment has changed.

Warning: When editing segments, do not inadvertently insert elements between a label and the element that follows. Your application will no longer be able to use certain GPIs correctly because their default locations and offsets will be invalid.

A label is only a place-holder or reference point, and is itself an element of the segment. Labels are long integer values. To include a label in a segment, use GpiLabel. The following example includes the label 5 in the current segment, whose segment id is 4.

``` GpiOpenSegment(hps, 4L); GpiLabel(hps, 5L); ... ```

Your application can set the element pointer to the label position using GpiSetElementPointerAtLabel, then increment the pointer position to the element itself using GpiOffsetElementPointer with an offset of 1.

Note: This example of GPI cannot work properly if your application has allowed the insertion of elements between a label and the element that follows it.

Labels do not have to be unique. If you do not use unique labels, GpiSetElementPointerAtLabel positions the element pointer at the first occurrence of the label, starting from the current pointer position. If the label is not found between the current pointer position and the end of the segment, an error condition is raised. Using labels as a navigation aid might be quicker than scanning the segment for a particular element.

If you do not use labels, you must locate an element before you can change it. To locate a specific element in a segment, you must repeatedly move the element pointer using GpiSetElementPointer then read the contents of the element using GpiQueryElement. This can be quite a lengthy procedure depending upon the number of elements in the segment.

Graphics Segments

Segments are made up of elements, which are in turn made up of one or more graphic orders. The previous sections have discussed the properties and functions for orders and elements. The following sections discuss the attributes and functions that apply to segments as a whole.

The segment attributes are encoded in a segment prior to the graphics orders that correspond to GPIs and attributes.

Segment Attributes

Each segment has a number of characteristics, called attributes that you can set in accordance with your application's requirements. The attributes of a segment are quite different from those of a graphics primitive, in that segment attributes have ON and OFF settings. There are seven segment attributes, each described in the following table.

Graphic Segment Attributes and Initial Settings

Attribute Value If set... Default
Chained ATTR_CHAINED the operating system adds each new segment in your application's presentation space to the segment chain. ON
Fast chain ATTR_FASTCHAIN the operating system prevents the resetting of primitive attributes to their default values before drawing the segment chain. ON
Dynamic ATTR_DYNAMIC the operating system draws segment output by using the XOR raster operation. OFF
Detectable ATTR_DETECTABLE your application can perform correlation operations on segments created in this presentation space. OFF
Propagate detectable ATTR_PROP_DETECTABLE the detectable attribute will be set in each segment called by a chained segment. ON
Visible ATTR_VISIBLE GpiDrawChain, GpiDrawFrom, and GpiDrawSegment will generate output on a device. ON
Propagate visible ATTR_PROP_VISIBLE The visible attribute will be set in each segment called by a chained segment. ON

When an application creates a segment in a presentation space, the operating system assigns initial attributes to it. By default, five of the attributes will be set ON and two will be set OFF. Your application can override the defaults for all subsequently created segments within the presentation space using GpiSetInitialSegmentAttrs.

Use GpiQueryInitialSegmentAttrs, to retrieve the values of the current initial attributes.

The Dynamic Attribute

Dynamic segments are graphics segments that can be moved from where they were drawn on the screen to a different coordinate position, or altered in some other way, without affecting the remaining part of the picture. The new position of a dynamic segment can be provided with an input device, such as a mouse, or it can be application-generated.

The dynamic attribute is set to OFF by default. The setting is always inherited by called segments from the setting of their callers. If a calling segment is nondynamic, any segments called by it are also nondynamic, regardless of how they have been defined. If the calling segment is dynamic, all segments called by it are also dynamic. Any segment explicitly defined as dynamic must have a unique name, and it cannot be created when the current drawing-mode parameter is DM_DRAW or DM_DRAWANDRETAIN. Although no error condition is raised if you define an unchained segment as dynamic, it is not treated as dynamic unless the segment is called from a dynamic root segment.

Graphics objects to be moved without disturbing the remaining contents of the display are drawn in exclusive-OR mode. Segments that you define as dynamic always are drawn in exclusive-OR mode, regardless of the current mix attribute settings and any GpiSetMix functions the segment itself might contain.

For performance reasons, dynamic segments are to be grouped at the start of the picture chain. There are GPI functions that handle dynamic segments as a group, so it is more efficient if the entire segment chain does not have to be scanned to locate them.

When the entire picture chain is drawn, however, dynamic segments are to be drawn after all other segments in the chain to ensure that the effects of drawing in exclusive-OR mode are not adversely affected by drawings in other mix modes. Also, you must ensure that no nondynamic drawing overlays the dynamic segments after they have been drawn. The PM ensures that dynamic segments are always drawn on top of other graphics.

The Detectability Attribute

The detectability attribute of a segment determines if that segment can be selected with an input device, such as a mouse. A segment with this attribute is said to be selectable. Selectable segments can be selected for correlation operations. The detectability attribute is set OFF by default. All detectable segments must have unique names. If you define a zero segment as detectable, it is created as nondetectable.

The Propagate-Detectability Attribute

This attribute controls whether the detectability attribute of a calling segment is inherited by any segments called from it. The propagate-detectability attribute is set ON by default. This value overrides the detectability setting of the called segment. For example, if you set the detectability attribute of a calling segment to OFF, all segments called from it are nondetectable, regardless of how they have been defined.

The Visibility Attribute

The visibility attribute controls whether a segment is to be visible on an output device. The contents of a segment that is not defined with the visibility attribute set ON are still executed whenever the segment is drawn. This can cause changes to the current position and to current attribute values, even though the primitives themselves are not visible on the output device. The visibility attribute is set ON by default.

The Propagate-Visibility Attribute

This attribute controls whether the visibility attribute of a calling segment is inherited by any segments called from it. The propagate-visibility attribute is set ON by default. This value overrides the visibility setting of the called segment. For example, if the visibility attribute of a calling segment is set to OFF, all segments called from it are invisible, regardless of how they have been defined.

Changing the Attributes of a Segment

After you create a segment, you might need to alter its attributes. For example, if you created a segment using the default attributes and you want to perform a correlation operation on the subpicture in that segment, you will need to set the detectable attribute using GpiSetSegmentAttrs. You can retrieve the values of the attributes for any segment using GpiQuerySegmentAttrs.

You can change the default segment-attribute settings globally for a single presentation space using GpiSetInitialSegmentAttrs. The attribute setting that you specify in this function applies to all segments created subsequently in that presentation space, except that a nonretained segment can never have the dynamic attribute. For example, if you want all segments to be detectable, you can call this function to change the setting for all of them before you create them. GpiSetInitialSegmentAttrs cannot be used to change the attributes of existing segments.

You also can change the attributes of any single retained segment, but not those created subsequently, using GpiSetSegmentAttrs. This is useful if, for example, you want most of the segments in a picture chain to be detectable. You can change the attribute setting to detectable for the entire chain, before creating it, using GpiSetInitialSegmentAttrs; then, change the attribute to nondetectable for each of the segment exceptions using GpiSetSegmentAttrs. You can also use GpiSetSegmentAttrs, for example, to make a visible segment invisible when an erase request is received from the operator, or to take a segment out of the chain by redefining it as unchained. If you change an unchained segment to chained, it is added to the end of the segment chain. If you want the newly chained segment to be positioned elsewhere in the chain, use GpiSetSegmentPriority rather than GpiSetSegmentAttrs.

Some of these segment attributes apply equally to primitives that are outside of segments, although their default settings cannot be changed. Primitives outside of segments are always detectable and visible. They cannot be dynamic, because the dynamic attribute applies only to retained graphics. The chained and fast-chaining attributes do not apply to primitives outside of segments.

Editing a Segment

The operating system provides segment editing functions for writing applications that allow users to edit segments or elements in a segment. For example, after performing a correlation operation using your application, a user might need to alter the elements that intersected the pick aperture. Correlation and the pick aperture are explained in Correlation.

You can edit the contents of any retained segment that has a unique name. You also can edit the contents of a retained zero segment that has not yet been closed. Zero segments cannot be edited after they have been closed, because you cannot refer to a zero segment when it is no longer the current open segment.

Before you can begin editing, you must set the current drawing-mode parameter to DM_RETAIN. You cannot edit a segment if the current drawing-mode parameter is DM_DRAWANDRETAIN or DM_DRAW. To begin editing, call GpiOpenSegment and specify the name of the segment you want to edit. When you are finished editing a segment, close it using GpiCloseSegment.

The operating system has two edit modes: insert mode and replace mode. You can set the edit modes using GpiSetEditMode. You can determine which mode is currently set using GpiQueryEditMode.

The current edit mode applies to all segments in the presentation space until you change it. The edit mode is not an attribute of a particular segment and can be changed at any time. The default edit mode, which is set when you create a presentation space, is insert mode. When you create a graphics segment, you are actually editing it in insert mode.

If the edit mode is set to insert (SEGEM_INSERT) you can insert an element at the current location of the element pointer. The operating system shifts the element that was previously at that location into the next slot, and so on, until the last element is shifted into a new, final slot. The following figure shows a segment before and after a new element is inserted at position 0, the beginning of the segment.

Inserting a New Element in a Segment
            Original Segment                         New Segment
                                Element Pointer
            ┌─────────────┐     │             │      ┌─────────────┐
Position 0  │             │ ────┘             └───── │             │
            │             │                          │             │
            ├─────────────┤                          ├─────────────┤
Position 1  │  Element 1  │─ ─ ─ ─ ─ ─ ─ ─ ─ ─┐      │ New element │
            │             │                   │      │             │
            ├─────────────┤                   │      ├─────────────┤
Position 2  │  Element 2  │─ ─ ─ ─ ─ ─ ─ ─ ─┐ └─ ─ ─ │  Element 1  │
            │             │                 │        │             │
            ├─────────────┤                 │        ├─────────────┤
Position 3  │  Element 3  │─ ─ ─ ─ ─ ─ ─ ─┐ └─ ─ ─ ─ │  Element 2  │
            │             │               │          │             │
            ├─────────────┤               │          ├─────────────┤
Position 4  │  Element 4  │─ ─ ─ ─ ─ ─ ─┐ └─ ─ ─ ─ ─ │  Element 3  │
            │             │             │            │             │
            ├─────────────┤             │            ├─────────────┤
Position 5  │  Element 5  │─ ─ ─ ─ ─ ─┐ └─ ─ ─ ─ ─ ─ │  Element 4  │
            │             │           │              │             │
            ├─────────────┤           │              ├─────────────┤
Position 6  │  Element 6  │─ ─ ─ ─ ─┐ └─ ─ ─ ─ ─ ─ ─ │  Element 5  │
            │             │         │                │             │
            ├─────────────┤         │                ├─────────────┤
Position 7  │  Element 7  │─ ─ ─ ─┐ └─ ─ ─ ─ ─ ─ ─ ─ │  Element 6  │
            │             │       │                  │             │
            └─────────────┘       │                  ├─────────────┤
                                  └─ ─ ─ ─ ─ ─ ─ ─ ─ │  Element 7  │
                                                     │             │
                                                     └─────────────┘

The new element is inserted after the current element; then, the element pointer is set to the new element.

If replace mode is set (SEGEM_REPLACE) you can replace the element at the current pointer location with a new element. The following figure shows a segment before and after the third element was replaced.

Replacing an Element with a New Element
           Original Segment                         New Segment
           ┌─────────────┐                          ┌─────────────┐
Position 0 │             │                          │             │
           │             │                          │             │
           ├─────────────┤                          ├─────────────┤
Position 1 │  Element 1  │                          │  Element 1  │
           │             │                          │             │
           ├─────────────┤                          ├─────────────┤
Position 2 │  Element 2  │                          │  Element 2  │
           │             │     Element pointer      │             │
           ├─────────────┤     │             │      ├─────────────┤
Position 3 │  Element 3  │ ────┘             └───── │  Element 3  │
           │             │                          │             │
           ├─────────────┤                          ├─────────────┤
Position 4 │  Element 4  │                          │  Element 4  │
           │             │                          │             │
           ├─────────────┤                          ├─────────────┤
Position 5 │  Element 5  │                          │  Element 5  │
           │             │                          │             │
           ├─────────────┤                          ├─────────────┤
Position 6 │  Element 6  │                          │  Element 6  │
           │             │                          │             │
           ├─────────────┤                          ├─────────────┤
Position 7 │  Element 7  │                          │  Element 7  │
           │             │                          │             │
           └─────────────┘                          └─────────────┘

The new element overwrites the previous element; the element pointer does not change.

Replacing elements is the recommended technique for redrawing identical primitives with different attributes—for example, color.

You can insert or replace data in an existing segment using any of the functions described in Adding Elements to a New Segment. As mentioned previously, GpiPutData is valid only in insert mode and only when the element pointer is addressing the final element in the segment. That is, when you are editing, you can use GpiPutData only to add data to the end of a segment.

A replace request is not valid when the element pointer is set to 0. If you call GpiOpenSegment to create a new segment without first ensuring that the current edit mode is insert, your first attempt to add an element to the segment might cause an error condition to be raised.

Deleting a Graphics Element

The PM has three different functions that allow you to delete elements within the currently opened segment.

Function Description:

When you remove an element from a segment, the element pointer addresses the element immediately before the one you deleted. As with other editing functions, the current drawing mode parameter must be DM_RETAIN when you are deleting elements. The current editing mode (insert or replace) has no effect on the delete functions.

Deleting Graphics Segments

When you have finished drawing the subpicture associated with a segment, you should delete the segment. The PM has two different functions that allow you to delete segments.

Function Description:

Your application can only delete segments that have unique names because you use the segment identifiers to identify the segment or range of segments for deletion. Retained zero segments cannot be deleted. They disappear only when their associated presentation space is deleted or reset. The presentation space can be reset either by GpiResetPS with the GRES_SEGMENTS flag or the GRES_ALL flag set, or by GpiSetPS. Resetting the presentation space is described in Reusing the Presentation Space.

If GpiDeleteSegment occurs within a segment bracket and the segment identified is the currently open segment, the operating system deletes the segment and ignores the remainder of the functions up to, and including, GpiCloseSegment. If GpiDeleteSegment occurs within a segment bracket and the identifier for a segment other than the currently open segment, the operating system deletes the segment, then continues processing the remaining functions in the segment bracket. If GpiDeleteSegment occurs outside of a segment and references a segment in the segment chain, the operating system removes the segment from the chain and links the two adjacent segments, if such segments exist.

If the range of segments deleted by GpiDeleteSegments were in the segment chain, the operating system "repairs" the chain by linking the segments immediately preceding and following the deleted segments, if such segments exist.

Copying a Single Graphics Element

Your application can copy the graphics orders from a single element using the GpiQueryElement and GpiElement functions. GpiQueryElement copies the graphics orders (or part of the orders, depending on allocated size) from an element into an array of bytes. GpiQueryElement is not valid within an element bracket, nor if the drawing mode is other than DM_RETAIN.

GpiElement copies the data from the array back into the current segment. The data may not contain any begin or end element orders. GpiElement is not valid within an element bracket. The element is retained if the drawing mode is DM_RETAIN and drawn if the mode is either DM_DRAW, or DM_DRAWANDRETAIN.

Copying Multiple Graphics Elements

Your application can use GpiGetData and GpiPutData to:

  • Copy elements from one segment to another.
  • Copy elements from one position in a segment to another position in the same segment.

GpiGetData copies a buffer of graphics orders from a named segment, into an area of application storage, whose byte size you specify on input. Only the named segment must not be open when you call this function. The named segment is also known as the source segment.

The first time GpiGetData is called, data retrieval has to start at the beginning of the segment. This is done by declaring an element offset of 0.

Output from GpiGetData depends on whether the area of application storage is large enough to hold the entire buffer of graphics orders. If so, the buffer is returned along with a count of the number of bytes of data returned to you from the segment. If not, the application storage is filled, and the count is set to the size of the application storage. The offset of the element where GpiGetData stopped copying, and the count are returned. Your application can then determine if a subsequent GpiGetData needs to be called, by checking that the count is less than the size (length) of the application storage.

On subsequent GpiGetData functions, the element offset can be 0, or it can be the offset value that was returned from the previous function. In this manner, if your application calls GpiGetData more than once to copy an entire segment, it can "pick up where it left off", rather than recopying the segment from the beginning each time.

You can copy the data from the application storage to a new location in a segment using GpiPutData. This receiving segment is also known as the destination segment. The segment into which you are copying the data can be open when you call GpiPutData.

If GpiGetData does not retrieve a complete segment, the data it does retrieve can be written out to the second segment using GpiPutData, even if the last order copied is incomplete.

The current drawing mode determines whether the graphics orders are executed, stored in the segment, or both. When you call GpiPutData, the current edit mode must be SEGEM_INSERT and, if there is already data in the destination segment, the element pointer must address the last element of the segment.

Because the PM does not support explicit renaming of segments, GpiGetData-GpiPutData is the method you use to rename a segment. That is, create a second segment with the desired name, copy the contents of the first segment to it, then delete the original segment.

Drawing Retained Graphics

Nonretained graphics segments and primitives outside of graphics segment are always drawn immediately to the current output device. Segments that have been retained in segment store, however, can be drawn any number of times to any number of device contexts. The PM has three different functions that allow you to draw segments:

Function Description:

GpiDrawSegment draws a single, named segment, which can be chained or unchained. You supply the segment name as input to this function. GpiDrawSegment can draw a dynamic segment in some circumstances. These are described in Drawing Dynamic Segments.

GpiDrawFrom draws one or more root segments from the segment chain. You supply the names of two root segments as input. The drawing process starts at the first named segment and draws all chained and called segments, excluding dynamic segments, up to and including the second named segment.

The order in which you specify the segment names is to reflect their relative positions in the segment chain. If the second-named segment appears in the segment chain before the first-named segment, no error is raised, but drawing starts from the first named segment and continues to the end of the chain. This also happens if the second segment is an unchained segment rather than a root segment. If the drawing control, DCTL_DYNAMIC is set, any dynamic segments already drawn on the display are removed before GpiDrawFrom begins to draw nondynamic segments. Then they are redrawn after GpiDrawFrom ends.

GpiDrawChain draws all nondynamic chained segments in a named presentation space, as well as any unchained segments called by those chained segments. It does not draw dynamic segments. You supply only the presentation space handle as input to this function. If the drawing control, DCTL_DYNAMIC is set, any dynamic segments already drawn on the display are removed before GpiDrawFrom begins to draw nondynamic segments. Then they are redrawn after GpiDrawFrom completes.

You can call any of these functions while a segment is open. The open segment is not modified by these functions, although any of them can result in the current attribute values and current position being modified. For more information about the attribute-resetting process, see Graphics Attributes.

The current drawing mode determines whether the segments identified in the drawing functions are executed, stored in the segment, or both. The current drawing mode does not affect which segments are drawn, or the priority in which they are drawn for any of these three GPI drawing functions.

If an error occurs during the drawing process, you can determine where the error occurred using GpiErrorSegmentData. This function returns information about the last error that occurred during a segment-drawing operation. It returns a pointer to the segment identifier and a pointer to one of three constants that indicate when the error occurred.

Constant Error occurred:

  • GPIE_SEGMENT: While drawing the segment.
  • GPIE_ELEMENT: While calling GpiElement.
  • GPIE_DATA: While calling GpiPutData.

Drawing Dynamic Segments

A dynamic segment is a chained segment that possesses special properties. Dynamic segments are those that can be moved or changed in some other way without disturbing the remaining parts of the picture. To draw dynamic segments on the display screen for the first time, use GpiDrawDynamics. GpiDrawDynamics draws every dynamic segment in the segment chain.

When they have been drawn on the display, dynamic segments can be updated. For example, to move one or more dynamic segments to another part of the display screen, remove them from their current position using GpiRemoveDynamics. You can restrict the scope of this function by supplying the names of a start segment and a finish segment. The start segment and finish segment can be the same. Dynamic segments outside of this range are not removed from the display screen.

If you intend to re-associate the presentation space, call GpiRemoveDynamics first; otherwise, GpiRemoveDynamics cannot remove the dynamic segments after the presentation space has been re-associated. The dynamic segments effectively cease to be dynamic.

After removing the appropriate dynamic segments from the display screen, you can redraw them elsewhere, again using GpiDrawDynamics. If you specify a range of dynamic segments in GpiRemoveDynamics, the redrawing is restricted to that range. Note that, when dynamic segments have been drawn on the display screen, you must not edit their definitions in segment store.

Dynamic segments are treated like nondynamic segments when you are directing output to a hardcopy device. GpiRemoveDynamics and GpiDrawDynamics raise an error condition if the current output device is not a display window.

The Drawing Controls

GpiErase clears the output display of the currently associated device to CLR_BACKGROUND, which is the normal background color for the device. If you are using the default color table, this value clears the window background to white. This is a once-only request and must be issued each time you want the display screen cleared before drawing a new picture. You can use this function for either a micro presentation space or a normal presentation space.

To get this effect for more than one drawing request, you can use GpiSetDrawControl. This function establishes current values for five drawing controls, which remain in effect until they are reset. The following table describes the five drawing controls.

Drawing Controls

Control Value If set, the operating system...
Boundary data accumulation DCTL_BOUNDARY computes the dimensions of the smallest rectangle that would completely surround the retained-drawing output. This control is described in Clipping and Boundary Determination.
Correlation DCTL_CORRELATE performs correlation operations on any primitives or any output associated with GpiPutData or GpiElement. This control is described in Correlation.
Display control DCTL_DISPLAY draws retained output on the device identified by the current device context. If this control is not set, no retained output will appear on the device.
Draw-dynamic-segments DCTL_DYNAMIC calls GpiRemoveDynamics before drawing any retained output and then, after drawing the retained output, it calls GpiDrawDynamics to draw output stored in dynamic segments. This automatically removes all dynamic segments from the display screen before a GpiDraw... request is issued, then later redraws the segments. This ensures that dynamic segments are always drawn on top of nondynamic segments and primitives.
Erase-before-draw DCTL_ERASE calls GpiErase before drawing any retained output.

GpiSetDrawControl can be called in either a micro or a normal presentation space, although not all of the controls are valid in a micro presentation space. GpiDrawSegment can be used to draw a dynamic segment in some circumstances. Its effects are as follows:

  • If the named segment is both chained and dynamic, and the DCTL_DYNAMIC drawing control is set, all dynamic segments in the chain, including the named segment, are drawn as dynamic.
  • If the named segment is both chained and dynamic, and the DCTL_DYNAMIC control is not set, the named segment is not drawn.
  • If the named segment is unchained and dynamic, it is drawn as a nondynamic segment, regardless of the setting of the DCTL_DYNAMIC control.

If you called GpiRemoveDynamics prior to calling GpiDrawDynamics and you specified a range of dynamic segments, the operating system draws only that range. If you set the DCTL_DYNAMIC control using GpiSetDrawControl, the operating system calls GpiRemoveDynamics before drawing the subpictures from the dynamic segments.

The DCTL_DISPLAY control is the only control set to DCTL_ON by default. All other controls are set to DCTL_OFF when you create a presentation space.

Using Segment Editing Functions

You can use editing functions to:

  • Create a chained-dynamic segment.
  • Delete a segment.
  • Edit the contents of a segment.

The following figure shows an example of how to edit the contents of a segment. In the example, three elements are inserted. The steps required for this task are as follows: 1. Set the segment edit mode to insert or replace using GpiSetEditMode. 2. Set the drawing mode to retain. 3. Open the segment using GpiOpenSegment, passing it the segment identifier from a previous correlation operation. 4. Set the element pointer so that it points to the position at which you will replace or insert an element using GpiSetElementPointer, GpiSetElementPointerAtLabel, or GpiOffsetElementPointer. 5. Insert the new primitives using any of the Gpi primitive functions. 6. Delete any unnecessary primitives using GpiDeleteElement or GpiDeleteElementRange. 7. Close the segment using GpiCloseSegment.

#define INCL_GPISEGEDITING
#define INCL_GPICONTROL
#include <os2.h>
void fncESEG01(void){
    HPS hps;
    LONG idNonChained;
    POINTL ptl;

    GpiSetEditMode(hps, SEGEM_INSERT);

    GpiSetDrawingMode(hps, DM_RETAIN);

    GpiOpenSegment(hps, idNonChained);

    GpiSetElementPointer(hps, 0L);

    GpiSetColor(hps, CLR_YELLOW);

    ptl.x = 100; ptl.y = 100;

    GpiMove(hps, &ptl);

    ptl.x = 150; ptl.y = 150;

    GpiBox(hps, DRO_OUTLINE, &ptl, 40L, 40L);

    ptl.x = 30; ptl.y = 30;

    GpiMove(hps, &ptl);

    GpiSetElementPointer(hps, 5L);

    GpiDeleteElement(hps);

    GpiCloseSegment(hps);

} /* fncESEG01 */

The first element inserted contains the graphics order that sets the color to yellow; the second element moves the current position; and the third element draws an outlined box with rounded corners. After the three elements are inserted, the code deletes the element at position 5 in the segment (this element was previously at positions 1 and 2).