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.


 

 For complete BBMig documentation click here.


Capabilities

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

 

Helpful Links

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