%%
%% $Id$
%%
\authorrunning{Hold, Reichel}
\titlerunning{A web based GridBagLayout}
\title{A web based GridBagLayout}
\subtitle{Seminar Web-based Development Environments}
\author{Alexander~Hold \and Stefan~Reichel}
\institute{%
  Hasso-Plattner-Institut, Potsdam\\
  \email{alexander.hold@student.hpi.uni-potsdam.de}
 \email{stefan.reichel@student.hpi.uni-potsdam.de}
}
\maketitle

\bibliographystyle{splncs03}
\begin{abstract}
\blindtext
Lively Kernel is one of the first web based development environments, which makes the creation of powerful interactive web applications possible. One key challenge is the layouting of graphical elements, which can now be freely dragged, moved and scaled. Our layout manager solves this issue and allows it in effect to create complex arrangements with windows, labels and editor boxes. In this paper a GridBagLayout algorithm is described and the special challenges of a web based development are discussed.
\end{abstract}

\section{Motivation}
Modern web based development environments like Lively Kernel provide several tools to create complex graphical elements. These elements are called Morphs in Lively and can be arranged to form complex structures like editor windows, system class browsers etc. Of course you are able to resize and move such windows and their contents, but this creates a new challenge. When the user resizes an editor window for example, he expects, that its text box will also be resized automatically. At the same time the position of the buttons should be altered but the size should still be the same. This complex behavior is normally realized by a layout manager.

Lively Kernel already contains two simple layout managers for horizontal and vertical layouting. Those two layouts can be combined by putting a container morph with the horizontal layout into another one with the vertical layout and the other way arround. Nevertheless it would be difficult to align items inside the main container in both directions.
For example if the horizontal layout would be used for the inner container it would be necessary to align the items vertically manually.
A layout manager is usefull, which can perform vertical and horizontal layouting at the same time and allows the definition of fixed areas, which will not be resized. In addition to that the manager should be configured in a lively way, which means just by clicking and not by editing large portions of source code. These challenges are covered by the developed GridBagLayout manager.

The remainder of the paper is structured as follows. First of all the layout manager concept is presented, which is followed by the related work. In the second part special concepts and challenges of the layout implementation are discussed. Afterwards the usage of the new layout is shown and finally a conclusion is drawn.

\section{The concept}
\subsection{The layout manager concept}
Currently there exist various concepts for layouting, one of the most famous is the GridLayout. The basic idea behind the concept is the division of the container element into equal cells. Every cell gets its own row and column number assigned. To add an element to the container it has to be put into one of those cells. The element will cover the whole space of the cell, which means it has to be extended or shrinked to fit. Often the resulting size is too small for the element e.g. for a text box, therefore it can be spanned over several cells. When the container is resized every cell will be altered, which in result will also effect the elements in the cells. One major disadvantage of this approach is the equal size of every cell because this makes it very inflexible.

This behavior is changed in the GridBagLayout concept, which allows variable heights (for rows) and widths (for columns).
Columns and rows can be set to a specific size which will not change when resizing the container.
They can also be set to be resizable, which means that its size may change when the container is scaled.
By default all resizable rows or columns have the same size, which can be zero if the containers size equals the size of all fixed rows/colums.
If all rows or columns have a fixed size, a new resizing row or column will be added to fill the remaining space (which may be zero).

\subsection{Related work}
The GridBag layout was not invented by computer scientists and despite the several user interaction challenges it is quiet easy to understand in principle. In effect there exist not much related theoretic work in the software industry. The background of the grid layout idea is much older than computers itself. The problem of arranging huge amount of information in form of text and images raised in the printing industry. That is why most of the theoretical work such as the book Making and Breaking the Grid \cite{Samara:2003} has such a background. Nevertheless those ideas were also adopted in the computer industry and resulted in various different implementations such as Ext JS\cite{EXTJS}, Nokia QT\cite{QT} \cite{QTLayout} and JAVA\cite{Java}.

Almost every bigger framework that contains graphics has some kind of grid layout.
For example in Ext JS\cite{EXTJS}, a large graphic framework for JavaScript, you can add the table to almost every panel.
This table layout works much like the GridLayout.
In this layout you do not specify where a panel should be placed to.
The position is calculated by the column and row spanning of the panels and their order in which they are added to the layout's panel.
This layout is pretty useful, but one thing is missing: you cannot edit your layout by using a graphical UI.

In the QT framework\cite{QT} \cite{QTLayout} , the most used graphics framework for C++, many designers use the "QGridLayout" for layouting their windows and dialogs.
The QT designer tool often uses the grid as default layout when you add Widgets into another Widget.
This tool was used as blueprint for many of the usability questions in the Lively GridBagLayout.
It always tries to resize dropped Widgets to fit into the layout.
That is useful for filling windows completely instead of having empty parts.
The new layout for Lively tries to avoid resizing the morphs after dropping, because the user may not like to have his predesigned morphs to be resized automatically.
Other parts like the way to handle dropping onto an occupied cell works more like in the QT designer.
\begin{figure}[ht] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[width=\textwidth]{images/qt.png}
   \caption{Dropping a Widget between two others in the QT designer.}
   \label{fig:qt}
\end{figure}

In the QT designer the user can drag items from the menu or already existing items into the layout.
He can see a graphical effect when dragging, which shows where the Widget will be placed to.
When marking the layout object or its parent, the user can set preferences for it in a separate part of the UI.
Margins to the borders can be set, spacings between the cell and minimum sizes for the rows and columns.
In addition to that a stretching factor can be added for single rows and columns, to modify how their size changes if the layout's size is changed.
The Widgets itself can have a minimum and maximum size, too.
Size constraint values can be set to define how the layout should react if it is resized.

The designer creates a XML file from the settings you make.
The User Interface Compiler uses this file to create corresponding C++ header or source files.
You do not need to use the QT designer to create windows or dialogs.
The designer is just a tool to simplify the UI creation.
Once the header or source files are created, they can be used in the C++ project.

Every setting which could be changed in the designer can also be changed at runtime.
For example Widgets can be added, margins, spacings or the Geometry of the layout can be set.
The layout provides information about the current settings like the position of a specific cell, the count of rows or the minimum width of a column.

The GridBagLayout concept is also implemented in Java \ref{Java} and provides similar methods. The key of the this approach is the so called “GridConstaint”, which must be supplied whenever a new item is added. This constraint object contains information about the current cell position, spanning, padding and also its margins. It also determines the behavior if the added element is smaller than the corresponding cell e.g. after resizing of its container. In that case it can be specified whether the element should be stretched horizontally, vertically or both. If the element is not resized in both directions the developer can align the element for example to the bottom or top. Those “GridConstraints” can be altered at runtime to provide maximal flexibility.

\begin{lstlisting}%
[caption=Adding a new button to a container with GridBagLayout ,label=lst:JavaGridBagLayoutExample]
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;

JButton button = new JButton("Button 1");
container.add(button, c);
\end{lstlisting}

Listing \ref{lst:JavaGridBagLayoutExample} shows how a button is added to a container element which uses the GridBagLayout. The button will be added to the first column(“gridx”) and first row(“gridy”). If the container is resized the button will only be scaled horizontally.


\section{The layout manager implementation}
\subsection{The dropping concept}
\label{sec:dropping}
A main purpose was to implement a grid layout that can be build easily by using drag and drop.
For this we used the functionality of lively which already detects where the dragged morph was dropped.
All inserted morphs start with a column and row spanning of one.
If a morph is inserted at an empty row or column, this one is set to the morphs size and set to fixed.
The size of a row or column is increased to the size of a new morph, if it is larger than the row's or column's size before the drop.

\begin{figure}[h] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[width=\textwidth]{images/DroppingOnEmpty.png}
   \caption{If the row and column are empty they use the morphs size after dropping.}
   \label{fig:droppingEmpty}
\end{figure}

If a morph was dropped onto the container morph, a function is called which determines to which cell the morph should be added to.
As dropping point the center of the dropped morph is used.
The algorithm begins by retrieving the cell to which the point belongs to.
If this cell is empty, the morph can be added here.
Otherwise the morph will be added to a new row or column.

\begin{figure}[h] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[width=\textwidth]{images/Dropping.png}
   \caption{Dropping a Morph onto an occupied cell creates new cells.}
   \label{fig:dropping}
\end{figure}
\begin{figure}[h] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[width=\textwidth]{images/DroppingWithSpanning.png}
   \caption{The morph is inserted into the column where it was dropped in.}
   \label{fig:droppingWithSpanning}
\end{figure}
The dropping point's distance to the four borders of the occupied cell's morph (target morph) are compared.
The distanced are normalized by height/width of the target morph which is necessary if it has a big difference between its height and width.
Next to the nearest border a new row/column is inserted, in which the morph will be placed.
A dropped morph will always be placed in the same row (column) as dropped, if the nearest border is the left or right (top or bottom) one.



\subsection{User interaction for grid resizing}
\label{sec:interaction}
The user can toggle to show or hide the borders of all rows and columns (GridLines).
These GridLines protrude from the container.
This part of the line can be used to resize a row or column by dragging.
Dragging a line between two resizable rows will not change anything.
Changing the position of an outer line may change the containers size, but not to a width (height) less than the total size of all fixed columns (rows).

When displaying the GridLines, additional buttons are shown at the sides for every row and column.
Red buttons mean that this row or column has a fixed size and green buttons are next to resizing rows and columns.
Pushing one of these buttons toggles the corresponding row or column resizing policy (fixed / flexible).

At the top or left of a GridLine a plus sign is shown.
Clicking that sign adds a resizing row or column at this position.

\subsection{Spanning of Morphs}
A morph can span multiple rows and columns at once.
The user can drag the GridLine to the right or bottom of a morph to change this spanning.
The morph will use the complete area of all rows and columns it lays in.
Increasing the spanning is prohibited, if the new spanning includes an already occupied cell.
If a new row or column is inserted in the middle of a morph, the morph's spanning will increase.

\begin{figure}[ht] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[width=\textwidth]{images/Spanning.png}
   \caption{Changing the spanning of a morph.}
   \label{fig:spanning}
\end{figure}

The implementation of spanning allows the user more flexible designs.
A morph can now be in a flexible and a fixed row at once, which guarantees a minimum height.
The design in figure \ref{fig:spanningExample} would not be possible without spanning.

\begin{figure}[ht] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[width=\textwidth]{images/SpanningExample.png}
   \caption{This would not be possible without spanning.}
   \label{fig:spanningExample}
\end{figure}

\subsection{Context based menus}
\label{sec:menu}
The user interaction is mainly done via GridLines, but also other interaction mechanism were needed.  A well known concept is the usage of context menus. This makes it possible to perform a right click on a morph and to select an option to hide the grid or to remove the selected column. Every morph has already a predefined context menu, which is inherited from the world morph. Nevertheless for our purpose it has to be altered. The easiest way to do this, is to overwrite the “morphMenu” method, which is used to create the menu . This idea has a major disadvantage, the inherited world morph context menu and its items are lost, so they wont be shown when right clicking on the altered morph. A real solution should combine the new items, for example “Remove column”, and the old items inherited from the world morph.

This is done by context based programming in Javascript, in Lively it is called ContextJS.  At first a so called “layer” has to be created. In this layer the class of the object, which should be altered is specified. In the above mentioned use case this is the Morph class itself. In a second step the methods of the class can be overwritten. In comparison to the first approach, this time ContextJS provides a reference to the original implementation. In effect the old implementation can be called and afterwards user defined additional code. To alter the context menu the old morphMenu method is called, this will create a menu with all world morph items. Afterwards additional items like “Remove column” are added to the resulting menu, as shown in listing \ref{lst:layerCreation}.

\begin{lstlisting}%
[caption=Altering morph menus with ContextJS,label=lst:layerCreation]
layerClass(GridBagLayer, Morph, {
			
			morphMenu: function ($proceed, evt) {
				var menu = $proceed(evt);
				menu.addItem(["Remove column", this.removeCol]);

				return menu;
			},
};
\end{lstlisting}

The layer and its effects are by default turned off. To activate it for example after the Morph was added to a container with a GridBagLayout manager, the Morph has to be just informed, that the layer is active by calling its  “setWithLayers” method. This new context is not only active for the Morph itself but also for any of its children. An extract of the code which was used to perform this task can be found in listing \ref{lst:layerActivation}.

\begin{lstlisting}%
[caption=Activating the ContextJS layer,label=lst:layerActivation]
beforeAddMorph: function (supermorph, morph, isFront) {
         ....
	morph.setWithLayers([GridBagLayer]);
}

\end{lstlisting}

\subsection{Saving a layout}
In comparison to normal interactive web sites, the Lively development environment has special challenges to master. One of them is saving of content. Interactive web sites also tend to save information like data entered in a web form. Nevertheless within the scope of web based IDEs this challenge gets  a new quality. It is not only necessary to save simple text, but also complex data structures, in Lively a lot of those structures exist.

Saving itself is not the easiest task to perform. Nevertheless the perhaps most complex task is the loading and recovering of the saved data back to working JavaScript code.

For the first part of the saving challenge, Lively Kernel uses the JavaScript Object Notation\footnote{http://www.json.org/} technology. JSON is a very lightweight data interchange format, which was developed with the goal to create an easy to save and machine readable format. This data representation is itself valid JavaScript code, which can be executed by calling the JavaScript method "eval". Today various implementations for common used programming languages exist, one of them is JavaScript. By using JSON and its ability to save data structures like lists and dictionaries.

In that way Lively is able to save for example parts of the ContextJS layers and later on to unserialize and in effect to recover them. Every Object can implement a method called “toLiteral” which controls the serialization and method “fromLiteral” for the unserialization. This works for Layers out of the box, nevertheless for the developed layout manager, those methods had to be overwritten.

One of the main concepts of the layout implementation is to store adminstration data mainly in the manager and not in its controlled Morphs. Therefore saving and recovering of the layout manager is essential, this is done in two steps. At first the general column and row data are stored, these are mainly sizes and constrains. The saving and recovering are done with the above mentioned "toLiteral" and "fromLiteral" methods.

\begin{lstlisting}%
[caption=JSON representation of the saved row information of the GridBagLayout,label=lst:JSON example]
"rows":"[{\"size\":30,\"fixed\":true,\"baseSize\":0,\"notEmpty\":true},{\"width\":0,\"fixed\":false,\"baseSize\":0,\"size\":120}]"
\end{lstlisting}

The second step is performed after the basic layout manager and its Morphs have been restored. At this time the manager knows the size and some additional information of the cells, but not which (container-) Morph is assigned to it. This relation is recreated by asking the container Morph for its children, which will be assigned to a column and row. The crucial point of the method is the container itself, which is not available after the first step. Normally a layout manager in Lively does  by design not know its container, this information is later supplied by special user triggered events, for example when a new child morph was added. Those events are also used by the developed GridBagLayout so in effect the user will have a working layout at every time.


\section{Using the layout}
For using the GridBagLayoutManager it is need to include the module \emph{GridBagLayout}.
To add the layout to a morph use the following line (\emph{aMorph} is the the morph you want apply the layout to):
\begin{lstlisting}
aMorph.layoutManager = new GridBagLayoutManager(aMorph);
\end{lstlisting}
By default the helping morphs and lines described in section \ref{sec:interaction} are visible, but can be hidden by using the point ``Hide grid'' of the morph's menu.

The GridBagLayoutManager is designed for creating and editing a layout in the UI of Lively.
How to use the UI functionality is described in the sections \ref{sec:dropping} to \ref{sec:menu}.
Nevertheless it is possible to create a design automatically by using JavaScript.
Every needed method is directly invoked in the layout manager, a list of all methods for creating and editing a grid is shown in the tables \ref{tab:morphEditing} to \ref{tab:gridEditing}.

The layout manager API can be divided into three main parts. First of all there are methods to assign a morph to a cell and to change its spanning.


\begin{table}[H] %  table placement: here, top, bottom, or page
  \centering
\begin{tabular}{|p{6cm}|p{5cm}|} % two columns: 4 cm and 6 cm
    \hline
    \texttt{moveMorphToCell (aMorph, x, y)} & Moves a Morph to the specified cell if it exists and is not empty. \\
    \hline
    \texttt{setRowSpanForMorph (aMorph, span)} & Sets a Morph's row spanning. \\
    \hline
    \texttt{setColSpanForMorph (aMorph, span)} & Sets a Morph's column spanning. \\
    \hline
\end{tabular}
\caption{Methods for a morph of the grid layout manager}
\label{tab:morphEditing}
\end{table}

The second part of the API is represented by several getters, which help the developer to get a morph based on its position in the grid. If no morph is present at the supplied position the undefined value will be returned.

\begin{table}[H] %  table placement: here, top, bottom, or page
  \centering
\begin{tabular}{|p{6cm}|p{5cm}|}%
    \hline
    \texttt{getMorphAt (x, y)} & Return the Morph contained in this cell.\\
    \hline
    \texttt{getMorphsInColumn (index)} & Returns the Morphs of this column. \\
    \hline
    \texttt{getMorphsInRow (index)} & Returns the Morphs of this row.  \\
    \hline
\end{tabular}
\caption{Methods to obtain a Morph}
\end{table}

The last part of the programming interface is used to control the size and resizing mode of cells. If a row or column is set to a fixed mode it won't be resized, instead it will keep its size. The following API can also be used to add new rows and columns. By adding rows and columns with a small width or height and a fixed size policy it is possible to create padding between cells.

\begin{table}[H] %  table placement: here, top, bottom, or page
  \centering
  \sffamily
  \footnotesize
\begin{tabular}{|p{6cm}|p{5cm}|} % two columns: 4 cm and 6 cm
    \hline
    \texttt{addRowAt (index)} & Adds a row at the specified index. \\
    \hline
    \texttt{addColAt (index)} & Adds a column at the specified index. \\
    \hline
    \texttt{removeRow (index)} & Removes a row if it is empty. \\
    \hline
    \texttt{removeCol (index)} & Removes a column if it is empty. \\
    \hline
    \texttt{setRowFixed (index, value)} & Sets a row to fixed as default or to resizing if value is false.\\
    \hline
    \texttt{setColFixed (index, value)} & Sets a column to fixed as default or to resizing if value is false. \\
    \hline
    \texttt{toggleRowFixed  (index)} & Toggles a row between resizable and fixed.\\
    \hline
    \texttt{toggleColFixed (index)} & Toggles a row between resizable and fixed.\\
    \hline
    \texttt{setRowSize (index, size)} & Sets a row to a fixed size. \\
    \hline
    \texttt{setColSize (index, size)} & Sets a column to a fixed size. \\
    \hline
\end{tabular}
\caption{Methods for row and column access}
\label{tab:gridEditing}
\end{table}


\section{Conclusion}
Developing for and in a web based environment creates a lot of challenges. One of them is now solved. The GridBagLayout of Lively Kernel provides the user the ability to create complex arrangements of morphs, which can together act as one. Whether they are scaled or moved, whether they are put in horizontal or vertical order, the layout will always guarantee a proper position and size. At the same time the administration of such a complex piece of software is kept simple and can be controlled by a few lines of code. In addition to that a user interface was created lively, which means to change cell size, mode and control morphs with just a click.

Although the developed layout manager is for most of the users an invisible component in the background, it enriches their Lively Kernel experience every day.



\blindtext
\nocite{*}
\blindtext
\blindtext
\bibliography{references}

%%% Local Variables:
%%% mode: latex
%%% TeX-master: "Pape_2010_WDE_TeXParagraphLayout"
%%% End:
