FunLayout.java Source code

Java tutorial

Introduction

Here is the source code for FunLayout.java

Source

import java.awt.*;
import java.util.*;

/*
 * @(#)FunLayout.java   1.0  96/10/12  Eric Swildens  Copyright (c) 1996
 *
 * Permission to use, copy, modify, and distribute this software
 * for any purpose is hereby granted provided that this copyright
 * notice appears in all copies.
 *
 * NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 * THE SOFTWARE ARE GIVEN, EITHER EXPRESS OR IMPLIED, INCLUDING BUT
 * NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
 */

public class FunLayout implements LayoutManager {
    // Using this layout manager, you can place components at exact
    // locations (x, y, width, height) and then determine how they
    // behave when the window containing them (their parent) is resized.
    //
    // sample use:
    //
    // fun1.html:
    //
    //  <title>fun1 example</title>
    //  <applet code="fun1.class" width=400 height=300> </applet>
    //
    // fun1.java:
    //
    //  import java.applet.Applet;
    //  import java.awt.*;
    //
    //  public class fun1 extends Applet
    //  {
    //  public void init()
    //    {
    //    FunLayout layout = new FunLayout();
    //    setLayout(layout);
    //
    //    setBackground(Color.lightGray);
    //
    //    Button rightButton1 = new Button("Button1");
    //    rightButton1.reshape(300, 5, 90, 20);
    //    add(rightButton1);
    //    layout.movesRight(rightButton1);
    //
    //    Button rightButton2 = new Button("Button 2");
    //    rightButton2.reshape(200, 5, 90, 20);
    //    add(rightButton2);
    //    layout.movesRight(rightButton2);
    //
    //    Panel midPanel = new Panel();
    //    midPanel.reshape(5, 40, 390, 200);
    //    midPanel.setBackground(Color.blue);
    //    layout.widthChanges(midPanel);
    //    layout.heightChanges(midPanel);
    //    add(midPanel);
    //
    //    Panel statusBar = new Panel();
    //    statusBar.reshape(5, 245, 390, 20);
    //    statusBar.setBackground(Color.black);
    //    layout.movesDown(statusBar);
    //    layout.widthChanges(statusBar);
    //    add(statusBar);
    //    }
    //  }
    //
    // The above code creates an applet containing 2 buttons, a center panel
    // and a status panel.  The two buttons are placed next to each other
    // in the upper right.  When the window is sized wider, the buttons
    // will move to the right to stick near the edge of the window.
    //
    // The midPanel is placed in the center and when the window is sized
    // larger (in both dimensions), the panel will grow wider and taller.
    //
    // The statusBar is placed on the bottom and sticks to the bottom of
    // the panel when it is sized larger or smaller in height (it moves
    // down if the window it is contained in is sized to a larger height).
    // It will grow wider if the window it is contained in is sized wider.
    //
    // The advantage of the FunLayout is that you place components where you
    // want them to appear (best when using an interface builder) and still
    // have control over what happens during sizing.
    //
    // This is the default layout mechanism many interface systems use, such
    // as Netscape's IFC.  In fact, if you use this layout manager, you will
    // find porting your code to Netscape's IFC much easier, as the layout
    // container here is very similar to Netscape's IFC layout mechanism.
    //
    // There are only 4 methods which determine how components are resized
    //
    //   layout.movesRight(comp);
    //   layout.movesDown(comp);
    //   layout.widthChanges(comp);
    //   layout.heightChanges(comp);
    //
    // When you determine which to choose, you should ask "What should the
    // component do when the window is sized larger?"
    //
    // If you don't call any of the above methods for a component, it will
    // simply stay at its current location.
    //
    // It's more Fun than a Bag of layouts :-)
    //

    private Hashtable _moves;
    private Hashtable _negSized;
    private Dimension _prevContainerSize;

    private final static int MOVES_RIGHT = 2;
    private final static int MOVES_DOWN = 4;
    private final static int HEIGHT_CHANGES = 8;
    private final static int WIDTH_CHANGES = 16;

    public FunLayout() {
        _moves = new Hashtable();
        _negSized = new Hashtable();
    }

    private int _getMove(Component comp) {
        if (!_moves.containsKey(comp))
            return 0;
        return ((Integer) _moves.get(comp)).intValue();
    }
    //
    // private methods
    //

    private void _setMove(Component comp, int move) {
        if (_moves.containsKey(comp)) {
            move |= ((Integer) _moves.get(comp)).intValue();
            _moves.remove(comp);
        }
        _moves.put(comp, new Integer(move));
    }
    //
    // LayoutManager implementation
    //

    public void addLayoutComponent(String name, Component c) {
    }

    /**
      * When the window containing the given component is stretched to a
      * larger height, the given component will grow taller (and shorter
      * when the window is shortened).
      * @param comp the target Component
      */
    public void heightChanges(Component comp) {
        if ((_getMove(comp) & MOVES_DOWN) > 0)
            System.out.println(getClass() + ":layout conflict for " + comp);
        _setMove(comp, HEIGHT_CHANGES);
    }

    public void layoutContainer(Container con) {
        int i, count, deltax, deltay, move;
        Dimension conSize;
        Rectangle rect;
        Component comp;

        conSize = con.getSize();
        if (_prevContainerSize == null) {
            _prevContainerSize = conSize;
            return;
        }
        deltax = conSize.width - _prevContainerSize.width;
        deltay = conSize.height - _prevContainerSize.height;
        _prevContainerSize = conSize;
        count = con.countComponents();
        for (i = 0; i < count; i++) {
            comp = con.getComponent(i);
            if (!comp.isVisible())
                continue;
            move = _getMove(comp);
            if (move == 0)
                continue;
            rect = comp.getBounds();
            if (_negSized.containsKey(comp)) {
                // the component is really at a negative size
                rect = (Rectangle) _negSized.get(comp);
                _negSized.remove(comp);
            }
            if ((move & MOVES_RIGHT) > 0)
                rect.x += deltax;
            else if ((move & WIDTH_CHANGES) > 0)
                rect.width += deltax;
            if ((move & MOVES_DOWN) > 0)
                rect.y += deltay;
            else if ((move & HEIGHT_CHANGES) > 0)
                rect.height += deltay;
            // if a components size becomes negative, we track it since the AWT
            // does not allow components to have a size < (0, 0)
            if (rect.width < 0 || rect.height < 0)
                _negSized.put(comp, rect);
            comp.setBounds(rect.x, rect.y, rect.width, rect.height);
        }
    }

    public Dimension minimumLayoutSize(Container target) {
        return new Dimension(10, 10);
    }

    /**
      * When the window containing the given component is stretched to a
      * larger height, the given component will move down (and up
      * when the window is shortened).
      * @param comp the target Component
      */
    public void movesDown(Component comp) {
        if ((_getMove(comp) & HEIGHT_CHANGES) > 0)
            System.out.println(getClass() + ":layout conflict for " + comp);
        _setMove(comp, MOVES_DOWN);
    }
    //
    // public methods
    //

    /**
      * When the window containing the given component is widened, the
      * component will move right (and left when the window is shrunk).
      * @param comp the target Component
      */
    public void movesRight(Component comp) {
        if ((_getMove(comp) & WIDTH_CHANGES) > 0)
            System.out.println(getClass() + ":layout conflict for " + comp);
        _setMove(comp, MOVES_RIGHT);
    }

    public Dimension preferredLayoutSize(Container con) {
        Component comp;
        Rectangle rect;
        int i, count;
        Dimension d;

        d = new Dimension(0, 0);
        count = con.countComponents();
        for (i = 0; i < count; i++) {
            comp = con.getComponent(i);
            if (!comp.isVisible())
                continue;
            rect = comp.getBounds();
            if (d.width < rect.x + rect.width)
                d.width = rect.x + rect.width;
            if (d.height < rect.y + rect.height)
                d.height = rect.y + rect.height;
        }
        return d;
    }

    public void removeLayoutComponent(Component c) {
        if (_negSized.containsKey(c))
            _negSized.remove(c);
    }

    /**
      * When the window containing the given component is widened, the
      * component will grow wider (and smaller when the window is shrunk).
      * @param comp the target Component
      */
    public void widthChanges(Component comp) {
        if ((_getMove(comp) & MOVES_RIGHT) > 0)
            System.out.println(getClass() + ":layout conflict for " + comp);
        _setMove(comp, WIDTH_CHANGES);
    }
}