Search code examples
openoffice.orglibreofficelibreoffice-basicopenoffice-basic

Scroll bar in LibreOffice dialog


I am trying to make an image picker component in LibreOffice. I have a dialog that is dynamically filled with images. When the user clicks on one images, it should be selected and the dialog should be closed. The problem is that the number of images is variable. So I need to enable scrolling in the dialog (so that the user can navigate through all images).

There seems to be some properties on the dialog object (Scrollbars, Scroll width, Scroll height, etc) However, I cannot find a way to use them anywhere.

Any ideas?


Solution

  • The scrollbar is one of the Controls available through the dialog box editor. That is the easier way to put a ScrollBar on a dialog box. Just insert it like any other control. There is a harder way via DialogModel.addControl but that seems non-essential to answering this question.

    If you add a scrollbar to the dialog box and run the dialog box, you will find it does nothing by default. The functionality (apparently) must be written into a macro. The appropriate triggering event is the While Adjusting event on the ScrollBar object, although it does not trigger the macro simply with the "Test Mode" function in the dialog editor. Running the dialog box through a macro triggers the While Adjusting event when the scroll arrows are triggered, when the slider area is clicked to move the slider, and when the slider itself is dragged. The Object variable returned by the scrollbar event contains a property .Value which is an absolute value between 0 and the EventObject.Model.ScrollValueMax, which allows you to manipulate the other objects on the page manually based on the position of the slider.

    Yes, that's right, manipulate objects manually. The sole example I found, from the LibreOffice 4.5 SDK, does precisely this. Of course, it is not as bad as it sounds, because one can iterate through all of the objects on the page by reading the array Dialog.getControls(). In any event, the secret sauce of the example provided in the SDK is to define Static variables to save the initial positions of all of the objects you manipulate with the scrollbar and then simply index those initial positions based on a ratio derived from the scrollbar Value divided by the ScrollValueMax.

    Here is a very simple working example of how to scroll. This requires a saved Dialog1 in the Standard library of your document, which contains an object ScrollBar1 (a vertical scrollbar) and Label1 anywhere in the dialog. The ScrollBar1 must be configured to execute the macro ScrBar subroutine (below) on the While Adjusting event. Open the dialog by executing the OpenDialog macro and the scrollbar will move the Label1 control up and down in proportion to the page.

    Sub OpenDialog
    
       DialogLibraries.LoadLibrary("Standard")
       oVariable = DialogLibraries.Standard.Dialog1
       oDialog1 = CreateUnoDialog( oVariable )
       oDialog1.Execute()
    
    End Sub
    
    Sub ScrBar (oEventObj As Object)
      Static bInit As Boolean
      Static PositionLbl1Y0 As Long
    
      oSrc = oEventObj.Source
      oSrcModel = oSrc.Model
    
      scrollRatio = oEventObj.Value / oSrcModel.ScrollValueMax
    
      oContx = oSrc.Context
      oContxModl = oContx.Model
    
      oLbl1 = oContx.getControl("Label1")
      oLbl1Model = oLbl1.Model
    
      REM on initialization remember the position of the label
      If bInit = False Then
         bInit = True
         PositionLbl1Y0 = oLbl1Model.PositionY
      End If    
    
      oLbl1Model.PositionY  = PositionLbl1Y0 - (scrollRatio * oContx.Size.Height)
    
    End Sub
    

    The example provided by the SDK does not run on my setup, but the principles are sound.

    There appears to be a second improvised method closer to the functionality one might expect. This method uses the DialogModel.scrollTop property. The property appears to iterate the entire box up or down as a scroll based on the user input. There are two problems using this methodology, however. First, unless you put the scrollbar somewhere else, the scroll bar will scroll away along with the rest of the page. You will need to adjust the location of the scrollbar precisely to compensate for/negate the scrolling of the entire page. In the example below I tried but did not perfect this. Second, the property seems to miss inputs with frequency and easily goes out of alignment/ enters a maladjusted state. Perhaps you can overcome these limitations. Here is the example, relying on the same setup described above.

    Sub ScrBar (oEventObj As Object)
      Static scrollPos
      oSrc = oEventObj.Source
      oSrcModel = oSrc.Model
    
      scrollRatio = oEventObj.Value / oSrcModel.ScrollValueMax
      If IsEmpty(scrollPos) = False Then 
        scrollDiff = oEventObj.Value - scrollPos
      Else
        scrollDiff = oEventObj.Value
      End If
      scrollPos = oEventObj.Value
    
      oContx = oSrc.Context
      oContxModl = oContx.Model
    
      oContxModl.scrollTop = scrollDiff * -1
      oSrcModel.PositionY=(scrollRatio * oContx.Size.Height/5) * -1 
    End Sub
    

    This (sort of) will scroll the contents of the entire dialog box, within limits and with the caveats noted above.