Example 2: Multiple split views with navigation bar

This example shows how to write an application that handles two split views, each having a left and right pane, with a top level navigation pane that allows the end user to easily switch between the two split views.

main.4gl

This module implements the window creation and the parallel dialogs to control their content.

The code in the MAIN block creates four windows:
  • The main window is the navigation window/pane, defined by the TYPE=NAVIGATION attribute. Only the d_navigator() main dialog is started.
  • Two other windows are created for the customer list and details, in the customers() function. This function is called when the main dialog starts. The function checks if the w_customers window exists and if needed, opens the split-view windows and starts the dialogs handling customer records. If windows already exists, it performs a CURRENT WINDOW IS w_customers, to select the customer pane.
  • The second window showing orders and its corresponding dialog are created in the orders() function, using the same programming pattern as in the customers() function.
  • When the user selects one of the main dialog actions, it calls either the customers(), the orders(), or the params() function, to show the corresponding pane.
  • The configuration pane is handled in the params() function, with the corresponding d_params_menu dialog: When selected, the form is in read-only mode by default. The menu implements the "modify" action to edit the parameters. This action will create a modal dialog, that temporarily stops the parallel dialogs.
DEFINE c_arr DYNAMIC ARRAY OF RECORD
            id INTEGER,
            name VARCHAR(30),
            address VARCHAR(100)
  END RECORD,
  c_curr INTEGER

DEFINE o_arr DYNAMIC ARRAY OF RECORD
            id INTEGER,
            info VARCHAR(100),
            deliv DATE
  END RECORD

DEFINE params RECORD
            user_name VARCHAR(30),
            auto_sync CHAR(1)
  END RECORD
  
MAIN
  CLOSE WINDOW SCREEN
  OPEN WINDOW w_navigator WITH 10 ROWS, 80 COLUMNS
       ATTRIBUTES(TYPE=NAVIGATOR)
  START DIALOG d_navigator
  WHILE fgl_eventLoop()
  END WHILE
END MAIN

DIALOG d_navigator()
  MENU
      BEFORE MENU
         CALL customers()
      -- Note that action names must match the window names
      ON ACTION w_customers ATTRIBUTES(TEXT="Customers",IMAGE="customers")
         CALL customers()
      ON ACTION w_orders ATTRIBUTES(TEXT="Orders",IMAGE="orders")
         CALL orders()
      ON ACTION w_params ATTRIBUTES(TEXT="Params",IMAGE="sync")
         CALL params()
  END MENU
END DIALOG

FUNCTION params()
  IF ui.Window.forName("w_params") IS NULL THEN
     OPEN WINDOW w_params WITH FORM "parameters"
     LET params.user_name="Tom"
     LET params.auto_sync="Y"
     DISPLAY BY NAME params.*
     START DIALOG d_params_menu
  END IF 
  CURRENT WINDOW IS w_params
END FUNCTION

DIALOG d_params_menu()
  MENU
    ON ACTION modify ATTRIBUTES(TEXT="Modify")
       CALL edit_params()
    ON ACTION options ATTRIBUTES(TEXT="Options")
       CALL options()
  END MENU
END DIALOG

FUNCTION edit_params() -- This is a modal dialog
  LET int_flag=FALSE
  INPUT BY NAME params.* ATTRIBUTES(WITHOUT DEFAULTS)
  IF NOT int_flag THEN
     -- CALL save_params()
  END IF
END FUNCTION

FUNCTION options()
  MENU "Options" ATTRIBUTES(STYLE="dialog")
    ON ACTION sync ATTRIBUTES(TEXT="Synchronize")
       --
    ON ACTION exit ATTRIBUTES(TEXT="Exit")
       EXIT PROGRAM
    ON ACTION cancel
       EXIT MENU
  END MENU
END FUNCTION

FUNCTION customers()
    IF ui.Window.forName("w_customers") IS NULL THEN
       CALL populate_customers()
       OPEN WINDOW w_customers WITH FORM "customer_list"
            ATTRIBUTES(TYPE=LEFT)
       START DIALOG d_customer_list
       OPEN WINDOW w_customer_detail WITH FORM "customer_detail"
            ATTRIBUTES(TYPE=RIGHT)
       START DIALOG d_customer_detail
    END IF 
    CURRENT WINDOW IS w_customers
END FUNCTION

DIALOG d_customer_list()
  DISPLAY ARRAY c_arr TO c_sr.*
          ATTRIBUTES(ACCESSORYTYPE=DISCLOSUREINDICATOR)
      BEFORE ROW
        CURRENT WINDOW IS w_customer_detail
        TERMINATE DIALOG d_customer_detail
        LET c_curr = arr_curr()
        DISPLAY BY NAME c_arr[c_curr].*
        START DIALOG d_customer_detail
        CURRENT WINDOW IS w_customers
  END DISPLAY
END DIALOG

DIALOG d_customer_detail()
  MENU 
    ON ACTION details
       LET int_flag=FALSE
       INPUT BY NAME c_arr[c_curr].name,
                     c_arr[c_curr].address
             WITHOUT DEFAULTS
       IF NOT int_flag THEN
          DISPLAY BY NAME c_arr[c_curr].*
       END IF
  END MENU
END DIALOG

FUNCTION populate_customers()
  LET c_arr[1].id = 324
  LET c_arr[1].name = "Mike Treeman"
  LET c_arr[1].address = "56 Gamleed st."
  LET c_arr[2].id = 8934
  LET c_arr[2].name = "Stepfan Plombier"
  LET c_arr[2].address = "78 Pokam st."
  LET c_arr[3].id = 451
  LET c_arr[3].name = "Ted Barber"
  LET c_arr[3].address = "1243b Western st."
END FUNCTION

FUNCTION orders()
    IF ui.Window.forName("w_orders") IS NULL THEN
       CALL populate_orders()
       OPEN WINDOW w_orders WITH FORM "order_list"
       START DIALOG d_order_list
    END IF 
    CURRENT WINDOW IS w_orders
END FUNCTION

DIALOG d_order_list()
  DISPLAY ARRAY o_arr TO o_sr.*
  END DISPLAY
END DIALOG

FUNCTION populate_orders()
  LET o_arr[1].id = 43249
  LET o_arr[1].info = "Xmass gifts"
  LET o_arr[1].deliv = MDY(12,23,2011)
  LET o_arr[2].id = 33424
  LET o_arr[2].info = "Dressing items"
  LET o_arr[2].deliv = MDY(2,13,2012)
END FUNCTION

customer_list.per

This is the form defining the customer list, it is used for the left-pane of the customers split view.
LAYOUT (TEXT="Customers")
TABLE
{
[c1    |c2              ]
}
END
END
ATTRIBUTES
PHANTOM FORMONLY.id;
EDIT c1=FORMONLY.name;
EDIT c2=FORMONLY.address;
END
INSTRUCTIONS
SCREEN RECORD c_sr(FORMONLY.*);
END

customer_detail.per

This is the form defining fields to show customer details, it is used for the right-pane of the customers split view.
LAYOUT (TEXT="Customer details")
GRID
{
Id      [f01               ]
Name    [f02               ]
Address [f03               ]
        [b1_details        ]
}
END
END
ATTRIBUTES
EDIT f01=FORMONLY.id;
EDIT f02=FORMONLY.name, SCROLL;
EDIT f03=FORMONLY.address, SCROLL;
BUTTON b1_details:details,TEXT="Modify details";
END

order_list.per

This is the form defining the order list, it is a single form (not a split view)
LAYOUT (TEXT="Orders")
TABLE
{
[c1    |c2              ]
}
END
END
ATTRIBUTES
PHANTOM FORMONLY.id;
EDIT c1=FORMONLY.info;
EDIT c2=FORMONLY.date;
END
INSTRUCTIONS
SCREEN RECORD o_sr(FORMONLY.*);
END

parameters.per

LAYOUT (TEXT="Settings")
GRID
{
User       [f01               ]
Auto sync  [f02               ]
}
END
END
ATTRIBUTES
EDIT f01=FORMONLY.user_name, SCROLL;
CHECKBOX f02=FORMONLY.auto_sync, NOT NULL,
     VALUECHECKED="Y", VALUEUNCHECKED="N";
END