Wednesday, October 2, 2013

Condition display fields without indicators

I received a message after publishing the No More Number Indicators story about an alternate method of conditioning fields in a Display file without using indicators. As the person who sent me this did so as Anonymous I cannot thank them by name, but you know who you are.

I did use this method once, many years ago. I had create a program and display file for the editing of UB82 and UB92, universal billing forms used by hospital and doctors to submit to Medicare and other insurance companies. To put all of the fields on screens made it look too confusing and complicated. Therefore, I tried to make it easier to understand by only displaying the field relevant to the type of claim, highlighted the fields in error, etc. Before long I found I was using just about all of the indicators, *IN01 - 99, on the first couple of record formats. What was I going to do for the rest?

A look in the IBM manual for programming with displays introduced me to Program to Systems fields. By passing a hexadecimal value to a field in the display file I could eliminate most of the indicators I had been using.

In this example PFLD001 is defined as a Program to System field, see line 3 below. This is defined as a single byte alphanumeric field, with 'P' for the field Use. The DSPATR on line 2 indicates that the field FLD001 is conditioned by the field PFLD001.

01 A          R SCREEN1
02 A            FLD001         3A  B  2  2DSPATR(&PFLD001)
03 A            PFLD001        1A  P

All I have to do is move the appropriate hexadecimal value to PFLD001, see below, and that will change the way FLD001 is displayed. Below is how I could do it in RPGLE/RPG IV using the hexadecimal code for red and reverse image:

01 FDISPLAYF  CF   E             WORKSTN
02  /free
03     PFLD001 = x'29' ;
04     exfmt SCREEN1 ;

One of the display attributes I used in this program was the Position Cursor, DSPATR(PC), which is not handled with Program to System fields. Therefore, if the user wanted to move to the next field in error they would press F2, the key I designated for this purpose, and I had to use indicators to position the cursor to the next field.

So what are all of the hexadecimal values that can be used for Program to System fields, and what are they the equivalent of:

Hex Color
COLOR()
Display
attribute
DSPATR()
Displayed as
20 GRN Green
21 GRN RI Green, reverse image
22 WHT White
23 WHT RI White, reverse image
24 GRN UL Green, underline
25 GRN UL RI Green, underline, reverse image
26 WHT UL White, underline
27 ND Nondisplay
28 RED Red
29 RED RI Red, reverse image
2A RED HI Red, high intensity
2B RED HI RI Red, reverse image, high intensity
2C RED UL Red, underline
2D RED UL RI Red, unline, reverse image
2E RED UL BL Red, underline, blink
2F ND Nondisplay
30 TRQ CS Turquoise, column separator
31 TRQ CS RI Turquoise, column separator, reverse image
32 YLW CS Yellow, column separator
33 WHT RI CS White, reverse image, column separator
34 TRQ UL CS Turquoise, underline, column separator
35 TRQ UL RI CS Turquoise, underline, reverse image, column separator
36 YLW UL CS Yellow, underline, column separator
37 ND Nondisplay
38 PNK Pink
39 PNK RI Pink, reverse image
3A BLU Blue
3B BLU RI Blue, reverse image
3C PNK UL Pink, underline
3D PNK UL RI Pink, underline, reverse image
3E BLU UL Blue, underline
3F ND Nondisplay

Hex Color
COLOR()
Display
attribute
DSPATR()
Displayed as
A0 GRN PR Green, protected
A1 GRN PR RI Green, protected, reverse image
A2 WHT PR White, protected
A3 WHT PR RI White, protected, reverse image
A4 GRN PR UL Green, protected, underline
A5 GRN PR UL RI Green, protected, underline, reverse image
A6 WHT PR UL White, protected, underline
A7 ND PR Nondisplay, protected
A8 RED PR Red, protected
A9 RED PR RI Red, protected, reverse image
AA RED PR HI Red, protected, high intensity
AB RED PR HI RI Red, protected, reverse image, high intensity
AC RED PR UL Red, protected, underline
AD RED PR UL RI Red, protected, unline, reverse image
AE RED PR UL BL Red, protected, underline, blink
AF ND PR Nondisplay, protected
B0 TRQ PR CS Turquoise, protected, column separator
B1 TRQ PR CS RI Turquoise, protected, column separator, reverse image
B2 YLW PR CS Yellow, protected, column separator
B3 WHT PR RI CS White, protected, reverse image, column separator
B4 TRQ PR UL CS Turquoise, protected, underline, column separator
B5 TRQ PR UL RI CS Turquoise, protected, underline, reverse image, column separator
B6 YLW PR UL CS Yellow, protected, underline, column separator
B7 ND PR Nondisplay, protected
B8 PNK PR Pink, protected
B9 PNK PR RI Pink, protected, reverse image
BA BLU PR Blue, protected
BB BLU PR RI Blue, protected, reverse image
BC PNK PR UL Pink, protected, underline
BD PNK PR UL RI Pink, protected, underline, reverse image
BE BLU PR UL Blue, protected, underline
BF ND PR Nondisplay, protected

Rather than use the hexadecimal codes it would make it easier to understand if they are given meaningful names. If I was to use them again I would create a datastructure that would look like this:

 * Program To System Fields
D PgmToSys        DS                  qualified
 * Fields will be unprotected
D  GRN                           1A   inz(x'20')
D  GRN_RI                        1A   inz(x'21')
D  WHT                           1A   inz(x'22')
D  WHT_RI                        1A   inz(x'23')
D  GRN_UL                        1A   inz(x'24')
D  GRN_UL_RI                     1A   inz(x'25')
D  WHT_UL                        1A   inz(x'26')
D  ND                            1A   inz(x'27')
D  RED                           1A   inz(x'28')
D  RED_RI                        1A   inz(x'29')
D  RED_HI                        1A   inz(x'2A')
D  RED_HI_RI                     1A   inz(x'2B')
D  RED_UL                        1A   inz(x'2C')
D  RED_UL_RI                     1A   inz(x'2D')
D  RED_UL_BL                     1A   inz(x'2E')
D  TRQ_CS                        1A   inz(x'30')
D  TRQ_CS_RI                     1A   inz(x'31')
D  YLW_CS                        1A   inz(x'32')
D  WHT_RI_CS                     1A   inz(x'33')
D  TRQ_UL_CS                     1A   inz(x'34')
D  TRQ_UL_RI_CS                  1A   inz(x'35')
D  YLW_UL_CS                     1A   inz(x'36')
D  PNK                           1A   inz(x'38')
D  PNK_RI                        1A   inz(x'39')
D  BLU                           1A   inz(x'3A')
D  BLU_RI                        1A   inz(x'3B')
D  PNK_UL                        1A   inz(x'3C')
D  PNK_UL_RI                     1A   inz(x'3D')
D  BLU_UL                        1A   inz(x'3E')
 * Fields will be protected
D  PR_GRN                        1A   inz(x'A0')
D  PR_GRN_RI                     1A   inz(x'A1')
D  PR_WHT                        1A   inz(x'A2')
D  PR_WHT_RI                     1A   inz(x'A3')
D  PR_GRN_UL                     1A   inz(x'A4')
D  PR_GRN_UL_RI                  1A   inz(x'A5')
D  PR_WHT_UL                     1A   inz(x'A6')
D  PR_ND                         1A   inz(x'A7')
D  PR_RED                        1A   inz(x'A8')
D  PR_RED_RI                     1A   inz(x'A9')
D  PR_RED_HI                     1A   inz(x'AA')
D  PR_RED_HI_RI                  1A   inz(x'AB')
D  PR_RED_UL                     1A   inz(x'AC')
D  PR_RED_UL_RI                  1A   inz(x'AD')
D  PR_RED_UL_BL                  1A   inz(x'AE')
D  PR_TRQ_CS                     1A   inz(x'B0')
D  PR_TRQ_CS_RI                  1A   inz(x'B1')
D  PR_YLW_CS                     1A   inz(x'B2')
D  PR_WHT_RI_CS                  1A   inz(x'B3')
D  PR_TRQ_UL_CS                  1A   inz(x'B4')
D  PR_TRQ_UL_RI_CS               1A   inz(x'B5')
D  PR_YLW_UL_CS                  1A   inz(x'B6')
D  PR_PNK                        1A   inz(x'B8')
D  PR_PNK_RI                     1A   inz(x'B9')
D  PR_BLU                        1A   inz(x'BA')
D  PR_BLU_RI                     1A   inz(x'BB')
D  PR_PNK_UL                     1A   inz(x'BC')
D  PR_PNK_UL_RI                  1A   inz(x'BD')
D  PR_BLU_UL                     1A   inz(x'BE')

I know the subfield names are not great, but I think they are descriptive once you work out that they are the color codes followed by the display attribute codes.

I would keep this data structure in its own member, that way it can be copied into the source code of another.

I have also qualified the data structure, therefore, when using any of the subfields I have to qualify it with the data structure's name. For example to change the attribute to red and reverse image I would code the subfield as: PgmToSys.RED_RI

This means I can do the same as my previous example of RPGLE/RPG IV code as:

01 FDISPLAYF  CF   E             WORKSTN
02  /include mylib/mysrc,pgm2sysfld
03  /free
04     PFLD001 = PgmToSys.RED_RI ;
05     exfmt SCREEN1 ;

On line 2 I have used /INCLUDE, which is the same as /COPY. PGM2SYSFLD is the name of the member that contains the data structure.

You can learn more this on the IBM website:

 

This article was written for IBM i 7.1, and it should work with earlier releases too.

14 comments:

  1. Excellent, thanks for posting this.

    ReplyDelete
  2. Thanks for sharing this. Wish I had known about this 15 or 20 years ago.

    ReplyDelete
  3. I remember doing this on 34/36 with biton bitof and placing the single byte characters either end of the data to do the same - much easier these days - nice article.

    ReplyDelete
  4. This is good. I've been using this technique since 2006.

    ReplyDelete
  5. Nice article.
    Thanks,
    Simon

    ReplyDelete
  6. Sergio Luis Puentes-ValladaresOctober 3, 2013 at 2:49 PM

    Excellent Simon

    ReplyDelete
  7. By using the %bitor BIF the set of constants can be must shorter:

    -- Constants

    d cDspBlue c Const(x'3A')
    d cDspGreen c Const(x'20')
    d cDspPink c Const(x'38')
    d cDspRed c Const(x'28')
    d cDspTurquoise c Const(x'30')
    d cDspWhite c Const(x'22')
    d cDspYellow c Const(x'32')

    d cDspNormal c Const(x'20')
    d cDspProtect c Const(x'80')
    d cDspColSep c Const(x'10')
    d cDspBlink c Const(x'08')
    d cDspUnderline c Const(x'04')
    d cDspHilite c Const(x'02')
    d cDspReverse c Const(x'01')
    d cDspNonDisplay c Const(x'07')

    -- Function

    //--------------------------------------------------------------------
    p SetDdsProperties...
    p b
    d pi 1a
    d @color 1a
    d @protect n
    d @error n
    // Workfields
    d @ddsProperty s 1a
    /free
    @ddsProperty = cDspGreen;
    if @protect;
    @ddsProperty = %bitOr(@ddsProperty:cDspProtect);
    else;
    @ddsProperty = %bitOr(@ddsProperty:cDspUnderline);
    endif;
    if @error;
    @ddsProperty = %bitOr(@ddsProperty:cDspReverse);
    endif;

    return @ddsProperty;
    /end-free
    p e

    -- Usage
    -- Protect/Read only/Output
    PFLD001 = SetDdsProperties(cDspGreen:*On:*Off);

    -- Error
    PFLD001 = SetDdsProperties(cDspGreen:*Off:*On);

    ReplyDelete
  8. and de Position Cursor? I already knew this trick, but still had to use dspatr(pc).
    btw: %bitxx i don't like.... It reminds me of old pgms. I try avoid it

    ReplyDelete
  9. Write a function around API QDFRTVFD (DSPFFD) to retrieve the position of the field and set it via DDS keyword CSRLOC.

    I made a SRVPGM to do all of this, works like a charm. No more counting indicators, reorganizing datastructures....

    As a hint I will give the function names I have used, take your time to build your own and test it, but it will pay itself back:
    SCREEN_Init (Register the given screen/format for all fields and field attributes via QDFRTVFD)
    SCREEN_Finale (UnRegister the given screen/format)
    SCREEN_ErrorFlags (Set all error flags on or off)
    SCREEN_ProtectFlags (Set all protect flags on or off)
    SCREEN_HiddenFlags (Set all hidden flags on or off)
    SCREEN_Field (Set current field)
    SCREEN_Error (Set the error flag on for current field)
    SCREEN_Protect (Set the protect flag on for current field)
    SCREEN_Hidden (Set the error flag on for current field)
    SCREEN_Color (Set the color for the current field
    SCREEN_GetDdsProp (Get the value for the Program To Display Field for the given fieldname)
    SCREEN_CursorTo (Get the position of the given field)
    SCREEN_CursorToFirstError (Get the position of the first field in error)
    SCREEN_FormatToFirstError (Get the formatname where the first field in error is on)
    SCREEN_IsError (Is the given field in error or, when no parameter, is there any field in error)
    (As I use a SRVPGM all functions work with a handle (return of SCREEN_Init) to support multiple screen and formats)

    ReplyDelete
  10. One small caveat with using DSPATR with a program-to-system field: In the unlikely event that you still have black-and-white (or black-and-green) 5250 workstations, your program will need to test the display model and set the attribute field appropriately for both monochrome and color displays. DDS normally does this for you, with the COLOR keyword overriding the DSPATR(HI BL CS) attributes, but only on color displays.

    Probably 99% of System i shops are color-only, so this caveat only applies to the remaining 1% or so that still have some monochrome displays around.

    ReplyDelete
  11. J. Michael G. JonesOctober 14, 2013 at 5:15 AM

    Not also having a value that initially and then conditionally positions the display's cursor may be a real drawback that holds folk back from using the technique.

    Plus the above remark about OVERLAY makes a valid point.

    Instead of having massive conditioned 'dirty' display formats, a set of clean formats containing only relevant data items ultimately easier and safer. Also makes sense for print formats too.

    ReplyDelete
  12. Definitely something to keep for future use and reference -

    Thanks for your effort.

    ReplyDelete
  13. Thanks for the sharing. It clears my question at great deal.

    ReplyDelete

To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.