[ Previous | Next | Contents | Glossary | Home | Search ]
Motif 2.1 Programmer's Guide



Automatic Scrolling

In the automatic scrolling model, the ScrolledWindow creates a fixed-size viewport and handles all interaction with the ScrollBars. The application usually needs to take only the following steps:

  1. Create and manage a ScrolledWindow, supplying a value of XmAUTOMATIC for XmNscrollingPolicy in the argument list passed to the creation function

  2. Create and manage a widget child of the ScrolledWindow to serve as the scroll

  3. Adjust the size of the scroll widget, typically using XtSetValues of XmNheight and XmNwidth, as necessary to contain all the data in the scroll

    The ScrolledWindow automatically creates a widget to serve as the viewport and sets XmNclipWindow to the ID of this widget. It also creates horizontal and vertical ScrollBars and sets XmNhorizontalScrollBar and XmNverticalScrollBar to the appropriate IDs of the ScrollBars. The ScrolledWindow attaches callback procedures to the ScrollBars to handle user interaction with the ScrollBars.

    The ScrolledWindow sets the ScrollBar resource XmNincrement to a small fraction of the height or width of the viewport. It sets the ScrollBar resource XmNpageIncrement to a large fraction of the height or width of the viewport. If the ScrolledWindow resizes the viewport, it recomputes the values of these resources.

    The ScrolledWindow sets the ScrollBar resources XmNmaximum, XmNminimum, and XmNsliderSize so that the size of the slider reflects the proportion of the entire scroll that the viewport represents. If the application resizes the scroll or if the ScrolledWindow resizes the viewport, the ScrolledWindow recomputes the values of some or all of these resources.

    If the value of XmNscrollBarDisplayPolicy is XmAS_NEEDED, as it is by default in automatic scrolling, the ScrolledWindow displays a ScrollBar only if the size of the scroll exceeds the size of the viewport in the relevant dimension. If the value of XmNscrollBarDisplayPolicy is XmSTATIC, the ScrolledWindow always displays both ScrollBars.

    As the user manipulates a ScrollBar and changes its XmNvalue, the ScrolledWindow moves the scroll with respect to the viewport. For example, if the user moves the slider down in a vertical ScrollBar, the ScrolledWindow moves the scroll up with respect to the viewport.

    The ScrolledWindow may need to move the scroll (and set a ScrollBar's XmNvalue) in circumstances other than the user's interaction with the ScrollBar. For example, if the viewport is at the bottom of the scroll and the application reduces the height of the scroll, the ScrolledWindow must move the scroll down with respect to the viewport. In this case, it reduces the ScrollBar's XmNmaximum and XmNvalue.

    In automatic scrolling, the application should not try to set any of the following resources:

    1. Any geometry resources of the viewport (the XmNclipWindow)

    2. The XmNmaximum, XmNminimum, XmNvalue, XmNincrement, or XmNpageIncrement of a ScrollBar

      The application can add callbacks of its own to a ScrollBar but, because the ScrolledWindow adds its own callbacks, the application must not call XtRemoveAllCallbacks for a ScrollBar.

      The application or user can specify other resources, such as those that determine appearance, for the ScrolledWindow or its children. The names of the automatically created ScrollBars are "HorScrollBar" and "VertScrollBar".

    3. Traversing to Obscured Widgets

      By default, it is not possible to use keyboard traversal to move to a widget that is inside the ScrolledWindow but outside the viewport. For example, if the user presses osfNextField and the next field is not within the viewport, focus does not move to that field. The user must first use the ScrollBars or a scrolling command to position the viewport so that the target widget is no longer obscured.

      ScrolledWindow has a callback list, XmNtraverseObscuredCallback, that allows an application to make it possible to traverse to widgets that are in the ScrolledWindow but not in the viewport. The callback list is invoked when the user tries to traverse to such a widget in a ScrolledWindow with automatic scrolling. The callback procedure is passed a pointer to an XmTraverseObscuredCallbackStruct structure, which contains the reason (XmCR_OBSCURED_TRAVERSAL), the event, the widget that is the target of the traversal, and the traversal direction passed to XmProcessTraversal.

      Usually the callback procedure can allow traversal to the target widget simply by calling XmScrollVisible. This function takes as arguments the ScrolledWindow, the target widget, and requested margins between the target widget and the edges of the viewport. The function moves the work area with respect to the viewport to make the obscured widget visible. This function applies only to ScrolledWidgets with automatic scrolling.

      When ScrolledWindows are nested and focus is in an inner ScrolledWindow, the XmNtraverseObscuredCallback callbacks of the inner ScrolledWindow are invoked first if necessary. If the destination widget remains outside the viewport of the first ancestor ScrolledWindow, that ScrolledWindow's XmNtraverseObscuredCallback callbacks are invoked, and so on up the widget hierarchy.

      Example of Automatic Scrolling

      This section contains the scrolling-related portions of an example program that uses a ScrolledWindow with an automatic scrolling policy. The ScrolledWindow is actually a MainWindow, a subclass of ScrolledWindow that is often the containing manager for the primary window of an application. (MainWindow is discussed in Section 8.4.) The scroll widget is a DrawingArea.

      The application allows the user to create a simple map in the DrawingArea. The user can use the mouse to establish points representing cities and to draw lines between the cities. The application contains a TextField that allows the user to enter the name of a city and then to create a button child of the DrawingArea located at the city and containing the city's name as its label. The user can adjust the size of the DrawingArea by manipulating two Scales, one for the height of the DrawingArea and the other for the width. Other parts of the application save and retrieve the map data.

      This section contains only the portions of the application that relate directly to creating and maintaining the ScrolledWindow. These include:

      1. Creating the MainWindow with an automatic scrolling policy

      2. Creating the DrawingArea child of the ScrolledWindow

      3. Resizing the DrawingArea in response to the user's interaction with the Scales

      4. Establishing an XmNtraverseObscuredCallback procedure
        /*-------------------------------------------------------------
        **  Create a Main Window with a menubar, a command panel
        **  containing 2 Scales and a TextField, and a workarea.
        **  Also put in the graphic structure the workarea info and the
        **  textfield ids.
        */
        void CreateApplication (
        Widget          parent,
        Graphic *       graph)
        {
         Widget main_window, menu_bar, menu_pane, cascade,
                   button, comw, scale;
         Arg args[5];
         int n;
         
            /*  Create automatic MainWindow.
             */
            n = 0;
            XtSetArg (args[n], XmNscrollingPolicy, XmAUTOMATIC);  n++;
            main_window = XmCreateMainWindow (parent, "main_window",
                            args, n);
         
            XtAddCallback (main_window, XmNtraverseObscuredCallback,
                           TravCB, (XtPointer)graph);
         
            XtManageChild (main_window);
         
         
            /*  Create work_area in MainWindow
             */
            n = 0;
            XtSetArg (args[n], XmNresizePolicy, XmRESIZE_NONE); n++;
            XtSetArg (args[n], XmNmarginWidth, 0); n++;
            XtSetArg (args[n], XmNmarginHeight, 0); n++;
            /* hardcode this one, since its is required for the motion handling
        */
            xlations = XtParseTranslationTable(drawTranslations);
            XtSetArg (args[n], XmNtranslations, xlations); n++;
            graph->work_area = XmCreateDrawingArea(main_window, "work_area",
                                                   args, n);
            XtAddCallback (graph->work_area, XmNexposeCallback, DrawCB,
                           (XtPointer)graph);
            XtAddCallback (graph->work_area, XmNresizeCallback, DrawCB,
                           (XtPointer)graph);
            XtAddCallback (graph->work_area, XmNinputCallback, DrawCB,
                           (XtPointer)graph);
            XtManageChild (graph->work_area);
         
         
            /*  Create a commandWindow in MainWindow with text and scales
             */
            n = 0;
            comw = XmCreateRowColumn(main_window, "comw", args, n);
            XtManageChild (comw);
            n = 0;
            XtSetArg (args[n], XmNcommandWindow, comw);  n++;
            XtSetValues (main_window, args, n);
         
            /* find the initial size of the work_area and report to the scales
        */
            n = 0;
            XtSetArg (args[n], XmNwidth, &graph->old_width);  n++;
            XtSetArg (args[n], XmNheight, &graph->old_height);  n++;
            XtGetValues (graph->work_area, args, n);
         
            n = 0;
            XtSetArg (args[n], XmNorientation, XmHORIZONTAL);  n++;
            XtSetArg (args[n], XmNshowValue, True);  n++;
            XtSetArg (args[n], XmNvalue, graph->old_width);  n++;
            scale = XmCreateScale(comw, "scale_w", args, n);
               /* scale_w is the name */
            XtAddCallback (scale, XmNvalueChangedCallback, ValueCB,
                           (XtPointer)graph->work_area);
            XtManageChild (scale);
         
            n = 0;
            XtSetArg (args[n], XmNorientation, XmHORIZONTAL);  n++;
            XtSetArg (args[n], XmNshowValue, True);  n++;
            XtSetArg (args[n], XmNvalue, graph->old_height);  n++;
            scale = XmCreateScale(comw, "scale_h", args, n);
            XtAddCallback (scale, XmNvalueChangedCallback, ValueCB,
                           (XtPointer)graph->work_area);
            XtManageChild (scale);
         
            n = 0;
            graph->textf = XmCreateTextField(comw, "textf", args, n);
            XtManageChild (graph->textf);
         
         
            /*  Set MainWindow areas
             */
            XmMainWindowSetAreas (main_window, menu_bar, comw, NULL, NULL,
                                  graph->work_area);
         
        }
         
        /*-------------------------------------------------------------
        **      TravCB          - callback for traverseObscure
        */
        void TravCB (
        Widget          w,              /*  widget id           */
        XtPointer       client_data,    /*  data from application   */
        XtPointer       call_data)     /*  data from widget class  */
        {
         XmTraverseObscuredCallbackStruct * tocs =
           (XmTraverseObscuredCallbackStruct *) call_data;
         Graphic * graph = (Graphic *) client_data;
         
            if (tocs->traversal_destination != graph->work_area)
                XmScrollVisible(w, tocs->traversal_destination, 20, 20);
        }
         
        /*-------------------------------------------------------------
        **      ValueCB         - callback for scales
        */
        void ValueCB (
        Widget          w,              /*  widget id           */
        XtPointer       client_data,    /*  data from application   */
        XtPointer       call_data)     /*  data from widget class  */
        {
         Arg args[5];
         int n;
         int value;
         Widget workarea = (Widget) client_data;
         
            /* get the value out of the Scale */
            n = 0;
            XtSetArg (args[n], XmNvalue, &value);  n++;
            XtGetValues (w, args, n);
         
            n = 0;
            if (strcmp(XtName(w), "scale_w") == 0) { /* width scale */
                XtSetArg (args[n], XmNwidth, value);  n++;
            } else {
                XtSetArg (args[n], XmNheight, value);  n++;
            }
            XtSetValues (workarea, args, n);
        }

      5. [ Previous | Next | Contents | Glossary | Home | Search ]