Multi-Column Reports This set of statements, functions and routines is designed to help with the creation of font- sensitive, screen-size sensitive multi-column reports. Each line in a report has its own column structure. This allows reports to be built in sections, some lines being free form text and others in columns. Each column is defined as a pixel offset from the left of the 'page', the way the text is to be aligned against that pixel, the text and the foreground colour. Each report is built from a DLL list, using the DLL routines originally written by Dave Newton. The version of DLL included here is my own modification of these routines. This system will not work using Dave's original code. Reports come in two flavours - Standard and Special. Standard reports use the functions ReportLine{} and ReportColumn{} to build the report and three arrays - HeadString$() HeadAlign() and HeadColumn() to build an optional single-line heading. Special Reports give more freedom to build report lines on-the-fly, but require more work. You must specify a routine to format the display line, one to print the line to a printer and, if a heading is required, one to display the heading. The advantage of Special reports is that you can have an unlimited number of special reports and one Standard report available at one time. So, using special reports, you could display a list of customers, display a list of the invoices against a selected customer, display the stock items on a selected invoice, display the suppliers of a selected stock item, etc., etc. and unwind the nested reports one by one. Whichever type of report is used, the reports characteristics are specified via a variable ReportFlags. This can contain the following Bit values: #Special This is a special report if set, a standard report if not. #Heading The report has a heading. Standard reports must use the HeadString$() array to specify the heading details, Special reports must use the HeadingHook. #Message Report is to have a message area at the bottom. For a constant message, simply define the variable ReportHeading$. If the message is to change each time a line is selected, use SelectHook. #Buttons Report is to have a button area at the bottom. All reports must use ButtonHook to define the buttons. Except: #MultiSelect Reports have a predetermined set of buttons which overrides this setting. #Selectable Report is selectable if set, Read-only if not set #MultiLine Report lines are in 'groups' such that if one line of a group is selected, all are selected. The offset \Group is used to determine the group. All consecutive lines with the same \Group value are considered to be the same Group. #Small Report window does not occupy the whole screen. Set variables x & y to the top corner of the required window, BoxLeft to the x-coordinate within the window of the left side of the scrollable area and BoxWidth to the width of the scrollable area. #Wide Report has more columns than can fit on the screen width. A Horizontal scroller will be added. The screen will be divided into two parts, the left hand side is fixed horizontally and the right hand side is scrollable horizontally. Both sides scroll vertically in sync. Specify variables FixedPixels for the width of the fixed part on the left of the screen, ColWidth for the width of one scrollable column on the right of the screen TotalCols for the total number of columns on the right hand side. FixedPixels will be adjusted to make a whole number of columns fit to the right. The BitMap is then built FixedPixels + (ColWidth * TotalCols) wide. If a heading is specified, use HeadingHook to define the Fixed Heading and HeadingHook2 to define the current variable heading (on the left) #KeyPress Report is in ascending order and the keyboard can be used to position the scroller. Esc resets the list to the top of the scroller. Alphabetic keys are read in and a key is built. The list is then processed until the offset \String contains a value greater than the key. This then becomes the second line in the scroller. #NotAllLines Not all lines in the array are to be displayed. Use NotAllHook to position the array at the line to be selected and NextLineHook to position the array to the next logical line #SelectHook Report must do pre-processing before a line is shown selected. This is also used to redefine ReportMessage$ if needed. Set the variable Selection to false if the line is not to be selected. #MenuHook Report processes a non-standard menu. #SemiSelectable Only some lines in the report are selectable. The offset \Flag is set to -1 for non-selectable lines, otherwise the line is selectable. #MultiSelect More than one line can be selected at a time. Optionally set #NewBit to add a "New" button. Do not specify ButtonHook if this flag is set. #NewBit MultiSelectable report has a "New" button. To use the system, first edit MCR_Data.bb The first line is a constant #MaxReportColumns which must be set to the maximum number of columns in any one line in any report. Too big is no problem. Too small is a run-time error message. Having set that, ensure that there are enough variables ReportColumn1 etc. one for each column. (If anyone can teach me how to automate that with a macro...) Having done that, decide whether you are going to use a standard or special report. If a special report, you will need to define a list. Note the definition of *TheList and ensure that your definition matches those parts of the layout that you need. Now build your list. Then use the following skeleton code: ReportTitle$ = "Cheque Book" ; The window title ReportMessage$ = "" ; Message initially blank ReportFlags = #Special | #Selectable | #Message | #Heading | #SelectHook | #MenuHook Menu_No = 2 ; Non-standard menu *TheList = *ChequeBook ; Tell code which list to process (A special list) PrintHook = ?print_cbk_line ; print the line to a printer HeadingHook = ?print_cbk_headings ; display headings DisplayHook = ?display_cbk_line ; display a line on the scroller MenuHook = ?cbk_menu ; process the menu SelectHook = ?cbk_mode ; pre-process before scroller. Gosub process_scroller ; go do it If The_One <> -1 ; a line was selected EndIf That should be enough to get you started. If you need any more help, feel free to e-mail me edgewater@shoalhaven.net.au Cheers