BBMig Layout Manager Overview

 

Description

In BBj 15.0 and higher, BBMig is a powerful and flexible layout manager built upon the open source MigLayout library. By integrating the layout manager into your graphical applications you can ensure that your user interfaces conform to the available screen space in adherence to the constraints defined for the container, rows, and columns. This results in GUI controls that are automatically sized and positioned within the window, regardless of the window size or the platform upon which the program is running. BBMig uses string-based constraints, making the layout code portable, concise, human readable, and easy to implement.

In addition to controlling the layout of controls, BBMig also provides the ability to scale layouts. This makes it possible to zoom in and out of a form, similar to how browsers can zoom on a page to enlarge the text making it easier to read. Scaling the layout down in effect zooms out, decreasing the size of windows and their controls to consume less screen space.

BBMig also offers the optional handling of platform specific label justification and standard button sequencing. This simplifies the task of providing control layouts that are consistent with the target platform without having to query the target operating system or provide any extra code logic. Named tags, such as 'help', 'ok', and 'cancel' ensure that the buttons in the screenshots below will be placed in accordance with the target operating system's user interface guidelines.

The third screenshot with the dotted red and blue lines shows how BBMig's debug mode can be used to easily visualize the bounds of the layout manager's grid cells and components, respectively.

 

Sample Program Running on OS X, with Help Button on Left
 


Sample Program Running on Windows with Help Button on Right



Sample Program With Debug Mode On

 

The following links provide useful information for the MigLayout library. While the actual BBj implementation code will be slightly different, all of the information contained in the documents that refer to concepts and constraints is immediately applicable to BBMig.

MigLayout Whitepaper

MigLayout Quick Start Guide

MigLayout Cheat Sheet

Sample BBj Program

use com.basiscomponents.ui.layout.BBMigPane
use net.miginfocom.layout.PlatformDefaults

use java.util.HashMap
use java.util.Iterator

rem test code when run
rem debug = BBjAPI().TRUE
new bbmigtest(debug)
release

class public bbmigtest
    field private BBjAPI    API! = BBjAPI()
    field private BBjNumber TRUE = BBjAPI().TRUE
    field private BBjNumber FALSE = BBjAPI().FALSE
    field private BBjSysGui SysGui! = BBjAPI().openSysGui("X0")

    field private BBjNumber debug = BBjAPI().FALSE

    field private BBjTopLevelWindow Window!
    field private BBMigPane Layout!
    field private BBjChildWindow cWindow!
    field private BBMigPane cLayout!

    field private BBjStaticText lFirstName!
    field private BBjInputE iFirstName!
    field private BBjStaticText lSurname!
    field private BBjInputE iSurname!
    field private BBjStaticText lAddress!
    field private BBjInputE iAddress!

    field private BBjMenuButton bOk!
    field private BBjMenuButton bCancel!
    field private BBjMenuButton bHelp!

    field public BBjNumber ActiveResize = BBjAPI().FALSE

    method public bbmigtest()
        #bbmigtest(BBjAPI().FALSE())
    methodend

    method public bbmigtest(BBjNumber debug)
        #debug = debug
        if #debug then
            print 'show',
            rem test platforms (NOTE: setting sticks til reset or JVM re-started)
            rem PlatformDefaults.setPlatform(PlatformDefaults.WINDOWS_XP)
            rem PlatformDefaults.setPlatform(PlatformDefaults.MAC_OSX)
            rem PlatformDefaults.setPlatform(PlatformDefaults.GNOME)
            print "Platform=",
            switch PlatformDefaults.getPlatform()
                case PlatformDefaults.WINDOWS_XP
                    print "Windows",
                    break
                case PlatformDefaults.MAC_OSX
                    print "Mac OS X",
                    break
                case PlatformDefaults.GNOME
                    print "Gnome",
                    break
                case default
                    print "Unknown",
                    break
            swend
            print " (real os=",System.getProperty("os.name"),"), Default DPI=",
:               PlatformDefaults.getDefaultDPI()
        else
            print 'hide',
        endif

        #constructForm()
        #show()
    methodend

    method public void show()
        #Window!.setCallback(#Window!.ON_CLOSE, #this!, "closeWindow")
        #Window!.setCallback(#Window!.ON_RESIZE, #this!, "windowResize")
        #Window!.setCallback(#Window!.ON_SCREEN_RESIZE, #this!, "screenResize")
        #Window!.setCallback(#Window!.ON_MOUSE_SCROLL, #this!, "mouseScroll")
        #cWindow!.setCallback(#cWindow!.ON_MOUSE_SCROLL, #this!, "mouseScroll")

        #resizeTimerEvent(null())

        #Window!.setVisible(#TRUE)
        #Window!.focus()

        process_events
    methodend

    method public void closeWindow(BBjCloseEvent ev!)
        release
    methodend

    method public void windowResize(BBjResizeEvent p_event!)
        if !(#ActiveResize)
            #ActiveResize = #TRUE
            #API!.createTimer("ResizeEventTimer", .2, #this!, "resizeTimerEvent")
        endif
    methodend

    method public void screenResize(BBjScreenResizeEvent p_event!)
        if !(#ActiveResize)
            #ActiveResize = #TRUE
            #API!.createTimer("ResizeEventTimer", .2, #this!, "resizeTimerEvent")
        endif
    methodend

    method public void resizeTimerEvent(BBjTimerEvent p_event!)
        #SysGui!.setRepaintEnabled(#FALSE)
        #Layout!.layoutChildren()
        #cLayout!.layoutChildren()
        #SysGui!.setRepaintEnabled(#TRUE)
        #API!.removeTimer("ResizeEventTimer",err=*next)
        #ActiveResize = #FALSE
    methodend

    method public void mouseScroll(BBjScrollWheelEvent p_event!)
        if p_event!.isControlDown() or p_event!.isCmdDown() then
            scale = num(cast(HashMap, #Window!.getUserData()).get("scale"))
            if p_event!.getScrollDirection() then
                scale = scale + (p_event!.getWheelRotation() / 10)
            else
                scale = scale - (p_event!.getWheelRotation() / 10)
            endif
            if scale >= 0.5 and scale <= 4.0 then
                #Layout!.scaleLayout(scale, #SysGui!)
                #cLayout!.scaleLayout(scale, #SysGui!)
                cast(HashMap, #Window!.getUserData()).put("scale", scale)
            endif
        endif
    methodend

    method public void constructForm()
        WinFlags$=$00000000$
        WinFlags$=IOR(WinFlags$,$00000001$); rem Resizable
        WinFlags$=IOR(WinFlags$,$00000002$); rem Include close box
        rem WinFlags$=IOR(WinFlags$,$00000004$); rem Horizontal scroll bar
        rem WinFlags$=IOR(WinFlags$,$00000008$); rem Vertical scroll bar
        WinFlags$=IOR(WinFlags$,$00000010$); rem Initially invisible
        rem WinFlags$=IOR(WinFlags$,$00000020$); rem Initially disabled
        WinFlags$=IOR(WinFlags$,$00000080$); rem Max-/Minimizable
        rem WinFlags$=IOR(WinFlags$,$00000100$); rem Initially minimized
        rem WinFlags$=IOR(WinFlags$,$00000800$); rem Include menu bar
        rem WinFlags$=IOR(WinFlags$,$00001000$); rem Initially maximized
        rem WinFlags$=IOR(WinFlags$,$00002000$); rem No menu separator line
        WinFlags$=IOR(WinFlags$,$00010000$); rem Keyboard navigation
        rem WinFlags$=IOR(WinFlags$,$00020000$); rem Always on top
        rem WinFlags$=IOR(WinFlags$,$00040000$); rem Dialog border
        WinFlags$=IOR(WinFlags$,$00080000$); rem Behave as a dialog
        rem WinFlags$=IOR(WinFlags$,$00100000$); rem Auto-arrange controls
        WinFlags$=IOR(WinFlags$,$00400000$); rem Custom color palette
        WinFlags$=IOR(WinFlags$,$00800000$); rem <Enter> behaves as <Tab>
        rem WinFlags$=IOR(WinFlags$,$01000000$); rem No window title bar
        WinFlags$=IOR(WinFlags$,$04000000$); rem Auto-manage SYSCOLOR events
        rem WinFlags$=IOR(WinFlags$,$20000000$); rem (VPRO5) Report mouse right button
        rem WinFlags$=IOR(WinFlags$,$40000000$); rem MDI group-modal
        #Window! = #SysGui!.addWindow(
:           #SysGui!.getAvailableContext(),400,400,400,400,
:           "BBMigPane Layout Test",WinFlags$)
        #Window!.setName("window")
        #Window!.setUserData(new HashMap())
        cast(HashMap, #Window!.getUserData()).put("scale",1.0)

        declare BBjFont font!
        font_size = 12
        font! = #SysGui!.makeFont("Dialog",font_size,#SysGui!.PLAIN)
        font_height = iff(font!.getStyle()=#SysGui!.BOLD,int(font_size*1.1),font_size)

        #Window!.setFont(font!)

        if #debug then #Window!.setTrack(BBjAPI().FALSE)
        #Layout! = new BBMigPane(#Window!,
:           "insets dialog"+iff(#debug,", debug",""),
:           "[align label]rel[grow,fill]unrel[align label]rel[grow,fill]",
:           "")

        declare BBjVector tx!
        declare BBjVector tm!
        tx! = #API!.makeVector()
        tidFirstName = 0; tx!.add(tidFirstName, "First Name:")
        tidSurname = 1; tx!.add(tidSurname, "Surname:")
        tidAddress = 2; tx!.add(tidAddress, "Address:")
        tidOk = 3; tx!.add(tidOk, "OK")
        tidCancel = 4; tx!.add(tidCancel, "Cancel")
        tidHelp = 5; tx!.add(tidHelp, "Help")
        tm! = #SysGui!.getMeasures(tx!)

        declare BBjColor lbl_bkcolor!
        lbl_bkcolor! = #API!.makeColor(#SysGui!.YELLOW)
        setlblbkcolor = #debug

        rem label width/height padding, input control width/height padding
        lwpad=0,lhpad=8,iwpad=8,ihpad=8

        #lFirstName! =  #Window!.addStaticText(#Window!.getAvailableControlID(),0,0,
:           num(tm!.get(tidFirstName))+lwpad,font_height+lhpad,
:           str(tx!.get(tidFirstName)))
        #lFirstName!.setName("lFirstName")
        #lFirstName!.setOpaque(#FALSE)
        #lFirstName!.setFont(font!)
        if setlblbkcolor then #lFirstName!.setBackColor(lbl_bkcolor!)
        #Layout!.add(#lFirstName!)

        #iFirstName! = #Window!.addInputE(#Window!.getAvailableControlID(),0,0,
:           100,font_height+ihpad,"")
        #iFirstName!.setName("iFirstName")
        #iFirstName!.setFont(font!)
        #Layout!.add(#iFirstName!)

        #lSurname! = #Window!.addStaticText(#Window!.getAvailableControlID(),0,0,
:           num(tm!.get(tidSurName))+lwpad,font_height+lhpad,str(tx!.get(tidSurName)))
        #lSurname!.setName("lSurname")
        #lSurname!.setOpaque(#FALSE)
        #lSurname!.setFont(font!)
        if setlblbkcolor then #lSurname!.setBackColor(lbl_bkcolor!)
        #Layout!.add(#lSurname!)

        #iSurname! = #Window!.addInputE(#Window!.getAvailableControlID(),0,0,
:           100,font_height+ihpad,"")
        #iSurname!.setName("iSurname")
        #iSurname!.setFont(font!)
        #Layout!.add(#iSurname!, "wrap")

        #lAddress! = #Window!.addStaticText(#Window!.getAvailableControlID(),0,0,
:           num(tm!.get(tidAddress))+lwpad,font_height+lhpad,str(tx!.get(tidAddress)))
        #lAddress!.setName("lAddress")
        #lAddress!.setOpaque(#FALSE)
        #lAddress!.setFont(font!)
        if setlblbkcolor then #lAddress!.setBackColor(lbl_bkcolor!)
        #Layout!.add(#lAddress!)

        #iAddress! = #Window!.addInputE(#Window!.getAvailableControlID(),0,0,
:           200,font_height+ihpad,"")
        #iAddress!.setName("iAddress")
        #iAddress!.setFont(font!)
        #Layout!.add(#iAddress!, "spanx, wrap unrel:push")

        rem child window (pane) for the buttons to test button tags
        cWinFlags$=$00000000$
        rem cWinFlags$=IOR(cWinFlags$,$00000004$); rem Allow horizontal scroll bar
        rem cWinFlags$=IOR(cWinFlags$,$00000008$); rem Allow vertical scroll bar
        rem cWinFlags$=IOR(cWinFlags$,$00000010$); rem Initially invisible
        rem cWinFlags$=IOR(cWinFlags$,$00000020$); rem Initially disabled
        cWinFlags$=IOR(cWinFlags$,$00000800$); rem No border
        cWinFlags$=IOR(cWinFlags$,$00010000$); rem Keyboard navigation
        rem cWinFlags$=IOR(cWinFlags$,$00100000$); rem Auto-arrange controls
        rem cWinFlags$=IOR(cWinFlags$,$00200000$); rem Dock in parent frame
        cWinFlags$=IOR(cWinFlags$,$00800000$); rem <Enter> behaves as <Tab>
        rem cWinFlags$=IOR(cWinFlags$,$01000000$); rem Recessed client edge
        rem cWinFlags$=IOR(cWinFlags$,$02000000$); rem Raised edge
        #cWindow! = #Window!.addChildWindow(#Window!.getAvailableControlID(),0,0,
:           #Window!.getWidth(),25,"",cWinFlags$,#SysGui!.getAvailableContext())
        #cWindow!.setName("cWindow")
        #cWindow!.setFont(font!)

        declare BBjColor btn_bkcolor!
        btn_bkcolor! = #API!.makeColor(#SysGui!.CYAN)
        setbtnbkcolor = #debug

        if #debug then #cWindow!.setTrack(BBjAPI().FALSE)
        #cLayout! = new BBMigPane(#cWindow!, "nogrid, fill"+iff(#debug,", debug",""))

        bwpad=16,bhpad=16; rem button width/height padding

        #bHelp! = #cWindow!.addMenuButton(#cWindow!.getAvailableControlID(),0,0,
:           num(tm!.get(tidHelp))+bwpad,font_height+bhpad,str(tx!.get(tidHelp)))
        #bHelp!.setName("bHelp")
        #bHelp!.setBorderPainted(#TRUE)
        #bHelp!.setFont(font!)
        if setbtnbkcolor then #bHelp!.setBackColor(btn_bkcolor!)
        #cLayout!.add(#bHelp!,"sg,tag help");rem there is also a "tag help2"

        #bOk! = #cWindow!.addMenuButton(#cWindow!.getAvailableControlID(),0,0,
:           num(tm!.get(tidOk))+bwpad,font_height+bhpad,str(tx!.get(tidOk)))
        #bOk!.setName("bOk")
        #bOk!.setBorderPainted(#TRUE)
        #bOk!.setFont(font!)
        if setbtnbkcolor then #bOk!.setBackColor(btn_bkcolor!)
        #cLayout!.add(#bOk!,"sg,tag ok")

        #bCancel! = #cWindow!.addMenuButton(#cWindow!.getAvailableControlID(),0,0,
:           num(tm!.get(tidCancel))+bwpad,font_height+bhpad,str(tx!.get(tidCancel)))
        #bCancel!.setName("bCancel")
        #bCancel!.setBorderPainted(#TRUE)
        #bCancel!.setFont(font!)
        if setbtnbkcolor then #bCancel!.setBackColor(btn_bkcolor!)
        #cLayout!.add(#bCancel!,"sg,tag cancel")

        #cLayout!.layoutChildren()
        #Layout!.add(#cWindow!, "south")
    methodend

classend

 



______________________________________________________________________________________

Copyright BASIS International Ltd. BBj®, Visual PRO/5®, PRO/5®, and BBx® are registered trademarks.