#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Grid.h"
#include <X11/Xlib.h>
static XtActionsRec actionslist[] = {
{
"getfocus",grid_getfocus},
{
"loosefocus",grid_loosefocus},
{
"NULL",
NULL}
};
static char defaultTranslations[] =
"\
<EnterWindow>: getfocus()\n\
<LeaveWindow>: loosefocus()\n";
static XtResource resources[] =
{
{
gridColumnSpacing,
gridColumnSpacing,
XmRDimension,
sizeof (Dimension),
XtOffsetOf( GridRec,
grid.columnspacing),
XmRImmediate,
(XtPointer)
0
},
{
gridRowSpacing,
gridRowSpacing,
XmRDimension,
sizeof (Dimension),
XtOffsetOf( GridRec,
grid.rowspacing),
XmRImmediate,
(XtPointer)
0
},
{
gridPaddingLeft,
gridPaddingLeft,
XmRDimension,
sizeof (Dimension),
XtOffsetOf( GridRec,
grid.padding_left),
XmRImmediate,
(XtPointer)
0
},
{
gridPaddingRight,
gridPaddingRight,
XmRDimension,
sizeof (Dimension),
XtOffsetOf( GridRec,
grid.padding_right),
XmRImmediate,
(XtPointer)
0
},
{
gridPaddingTop,
gridPaddingTop,
XmRDimension,
sizeof (Dimension),
XtOffsetOf( GridRec,
grid.padding_top),
XmRImmediate,
(XtPointer)
0
},
{
gridPaddingBottom,
gridPaddingBottom,
XmRDimension,
sizeof (Dimension),
XtOffsetOf( GridRec,
grid.padding_bottom),
XmRImmediate,
(XtPointer)
0
}
};
static XtResource constraints[] =
{
{
gridColumn,
gridColumn,
XmRDimension,
sizeof (Dimension),
XtOffsetOf( GridConstraintRec,
grid.x),
XmRImmediate,
(XtPointer)
0
},
{
gridRow,
gridRow,
XmRDimension,
sizeof (Dimension),
XtOffsetOf( GridConstraintRec,
grid.y),
XmRImmediate,
(XtPointer)
0
},
{
gridColspan,
gridColspan,
XmRDimension,
sizeof (Dimension),
XtOffsetOf( GridConstraintRec,
grid.colspan),
XmRImmediate,
(XtPointer)
0
},
{
gridRowspan,
gridRowspan,
XmRDimension,
sizeof (Dimension),
XtOffsetOf( GridConstraintRec,
grid.rowspan),
XmRImmediate,
(XtPointer)
0
},
{
gridMarginLeft,
gridMarginLeft,
XmRDimension,
sizeof (Dimension),
XtOffsetOf( GridConstraintRec,
grid.margin_left),
XmRImmediate,
(XtPointer)
0
},
{
gridMarginRight,
gridMarginRight,
XmRDimension,
sizeof (Dimension),
XtOffsetOf( GridConstraintRec,
grid.margin_right),
XmRImmediate,
(XtPointer)
0
},
{
gridMarginTop,
gridMarginTop,
XmRDimension,
sizeof (Dimension),
XtOffsetOf( GridConstraintRec,
grid.margin_top),
XmRImmediate,
(XtPointer)
0
},
{
gridMarginBottom,
gridMarginBottom,
XmRDimension,
sizeof (Dimension),
XtOffsetOf( GridConstraintRec,
grid.margin_bottom),
XmRImmediate,
(XtPointer)
0
},
{
gridHExpand,
gridHExpand,
XmRBoolean,
sizeof (Boolean),
XtOffsetOf( GridConstraintRec,
grid.hexpand),
XmRImmediate,
(XtPointer)
0
},
{
gridVExpand,
gridVExpand,
XmRBoolean,
sizeof (Boolean),
XtOffsetOf( GridConstraintRec,
grid.vexpand),
XmRImmediate,
(XtPointer)
0
},
{
gridHFill,
gridHFill,
XmRBoolean,
sizeof (Boolean),
XtOffsetOf( GridConstraintRec,
grid.hfill),
XmRImmediate,
(XtPointer)
0
},
{
gridVFill,
gridVFill,
XmRBoolean,
sizeof (Boolean),
XtOffsetOf( GridConstraintRec,
grid.vfill),
XmRImmediate,
(XtPointer)
0
},
{
gridMinWidth,
gridMinWidth,
XmRDimension,
sizeof (Dimension),
XtOffsetOf( GridConstraintRec,
grid.min_width),
XmRImmediate,
(XtPointer)
0
}
};
GridClassRec gridClassRec = {
{
(WidgetClass)&xmManagerClassRec,
"Grid",
sizeof(GridRec),
grid_class_initialize,
NULL,
FALSE,
(XtInitProc)grid_initialize,
NULL,
grid_realize,
actionslist,
XtNumber(actionslist),
resources,
XtNumber(resources),
NULLQUARK,
True,
True,
True,
False,
(XtWidgetProc)grid_destroy,
(XtWidgetProc)grid_resize,
(XtExposeProc)grid_expose,
grid_set_values,
NULL,
XtInheritSetValuesAlmost,
NULL,
(XtAcceptFocusProc)grid_acceptfocus,
XtVersion,
NULL,
defaultTranslations,
XtInheritQueryGeometry,
NULL,
NULL,
},
{
GridGeometryManager,
GridChangeManaged,
XtInheritInsertChild,
XtInheritDeleteChild,
NULL,
},
{
constraints,
XtNumber(constraints),
sizeof(GridConstraintRec),
grid_constraint_init,
NULL,
ConstraintSetValues,
NULL,
},
{
XtInheritTranslations,
NULL,
0,
NULL,
0,
XmInheritParentProcess,
NULL
},
{
0
}
};
WidgetClass gridClass = (WidgetClass)&gridClassRec;
void grid_class_initialize(
void) {
}
void grid_initialize(Widget request, Widget new, ArgList args, Cardinal num_args) {
Grid mn = (Grid)new;
mn->grid.max_col =
0;
mn->grid.max_row =
0;
}
void grid_realize(Widget w,XtValueMask *valueMask,XSetWindowAttributes *attributes) {
Grid grid = (Grid)w;
XtMakeResizeRequest(w,
400,
400,
NULL,
NULL);
(coreClassRec.core_class.realize)((Widget)w, valueMask, attributes);
grid_place_children(grid);
}
void grid_destroy(Grid widget) {
}
void grid_resize(Grid widget) {
grid_place_children(widget);
}
void grid_expose(Grid widget, XEvent *event, Region region) {
}
Boolean grid_set_values(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args) {
return False;
}
Boolean grid_acceptfocus(Widget w, Time *t) {
}
void grid_getfocus(Widget myw, XEvent *event, String *params, Cardinal *nparam) {
}
void grid_loosefocus(Widget myw, XEvent *event, String *params, Cardinal *nparam) {
}
XtGeometryResult GridGeometryManager(Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *reply) {
GridRec *grid = (GridRec*)XtParent(widget);
GridConstraintRec *constraints = widget->core.constraints;
if((request->request_mode & CWWidth) == CWWidth) {
widget->core.width = request->width;
constraints->grid.pref_width = request->width;
}
if((request->request_mode & CWHeight) == CWHeight) {
widget->core.height = request->height;
constraints->grid.pref_height = request->height;
}
grid_place_children((Grid)XtParent(widget));
return XtGeometryYes;
}
void GridChangeManaged(Widget widget) {
grid_place_children((Grid)widget);
}
Boolean ConstraintSetValues(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args) {
GridConstraintRec *constraints = neww->core.constraints;
Grid grid = (Grid)XtParent(neww);
if(constraints->grid.x > grid->grid.max_col) {
grid->grid.max_col = constraints->grid.x;
}
if(constraints->grid.y > grid->grid.max_row) {
grid->grid.max_row = constraints->grid.y;
}
}
void grid_constraint_init(
Widget request,
Widget neww,
ArgList args,
Cardinal* num_args
)
{
GridConstraintRec *constraints = neww->core.constraints;
Grid grid = (Grid)XtParent(neww);
if(constraints->grid.x > grid->grid.max_col) {
grid->grid.max_col = constraints->grid.x;
}
if(constraints->grid.y > grid->grid.max_row) {
grid->grid.max_row = constraints->grid.y;
}
constraints->grid.pref_width = neww->core.width;
constraints->grid.pref_height = neww->core.height;
}
void grid_place_children(Grid w) {
if(!XtIsRealized((Widget)w)) {
return;
}
int ncols = w->grid.max_col
+1;
int nrows = w->grid.max_row
+1;
GridDef *cols = calloc(ncols,
sizeof(GridDef));
GridDef *rows = calloc(nrows,
sizeof(GridDef));
int num_cols_expanding =
0;
int num_rows_expanding =
0;
int req_width = w->grid.padding_left + w->grid.padding_right;
int req_height = w->grid.padding_top + w->grid.padding_bottom;
int width = w->core.width;
int height = w->core.height;
int span_max =
1;
for(
int r=
0;r<
2;r++) {
for(
int i=
0;i<w->composite.num_children;i++) {
Widget child = w->composite.children[i];
GridConstraintRec *constraints = child->core.constraints;
if(constraints->grid.pref_width ==
0) {
constraints->grid.pref_width = child->core.width;
}
if(constraints->grid.pref_height ==
0) {
constraints->grid.pref_height = child->core.height;
}
if(constraints->grid.pref_width < constraints->grid.min_width) {
constraints->grid.pref_width = constraints->grid.min_width;
}
int elm_width = constraints->grid.pref_width + constraints->grid.margin_left + constraints->grid.margin_right;
int elm_height = constraints->grid.pref_height + constraints->grid.margin_top + constraints->grid.margin_bottom;
if(!XtIsManaged(child)) {
elm_width =
0;
elm_height =
0;
}
if(constraints->grid.colspan > span_max || constraints->grid.rowspan > span_max) {
continue;
}
int x = constraints->grid.x;
int y = constraints->grid.y;
if(x >= ncols) {
fprintf(stderr,
"Error: widget x out of bounds\n");
continue;
}
if(y >= nrows) {
fprintf(stderr,
"Error: widget y out of bounds\n");
continue;
}
GridDef *col = &cols[x];
GridDef *row = &rows[y];
if(constraints->grid.hexpand) {
if(constraints->grid.colspan >
1) {
GridDef *last_col = col;
for(
int c=x;c<ncols;c++) {
last_col = &cols[c];
if(last_col->expand) {
break;
}
}
last_col->expand =
TRUE;
}
else {
col->expand =
TRUE;
}
}
if(constraints->grid.vexpand) {
if(constraints->grid.rowspan >
1) {
GridDef *last_row = row;
for(
int c=x;c<nrows;c++) {
last_row = &rows[c];
if(last_row->expand) {
break;
}
}
last_row->expand =
TRUE;
}
else {
row->expand =
TRUE;
}
}
if(constraints->grid.colspan >
1) {
Dimension span_width = col->size;
GridDef *last_col = col;
for(
int s=x
+1;s<ncols;s++) {
last_col = &cols[s];
span_width = last_col->size;
}
int diff = elm_width - span_width;
if(diff >
0) {
last_col->size += diff;
}
}
else if(elm_width > col->size) {
col->size = elm_width;
}
if(constraints->grid.rowspan >
1) {
Dimension span_height = row->size;
GridDef *last_row = row;
for(
int s=x
+1;s<nrows;s++) {
last_row = &rows[s];
span_height = last_row->size;
}
int diff = elm_height - span_height;
if(diff >
0) {
last_row->size += diff;
}
}
else if(elm_height > row->size) {
row->size = elm_height;
}
}
span_max =
50000;
}
for(
int i=
0;i<ncols;i++) {
if(cols[i].expand) {
num_cols_expanding++;
}
req_width += cols[i].size;
}
for(
int i=
0;i<nrows;i++) {
if(rows[i].expand) {
num_rows_expanding++;
}
req_height += rows[i].size;
}
int total_colspacing =
0;
int total_rowspacing =
0;
for(
int i=
0;i
+1<ncols;i++) {
if(cols[i].size >
0) {
total_colspacing += w->grid.columnspacing;
}
}
for(
int i=
0;i
+1<nrows;i++) {
if(rows[i].size >
0) {
total_rowspacing += w->grid.rowspacing;
}
}
if(req_width >
0 && req_height >
0) {
req_width += total_colspacing;
req_height += total_rowspacing;
Widget parent = w->core.parent;
Dimension rwidth = req_width;
Dimension rheight = req_height;
if(rwidth < w->core.width) {
}
if(rheight < w->core.height) {
}
if(!w->grid.sizerequest) {
Dimension actual_width, actual_height;
w->grid.sizerequest =
TRUE;
XtMakeResizeRequest((Widget)w, req_width, req_height, &actual_width, &actual_height);
w->grid.sizerequest =
FALSE;
}
}
int hexpand =
0;
int width_diff = width - req_width;
int hexpand2 =
0;
if(width_diff >
0 && num_cols_expanding >
0) {
hexpand = width_diff / num_cols_expanding;
hexpand2 = width_diff-hexpand*num_cols_expanding;
}
int x = w->grid.padding_left;
for(
int i=
0;i<ncols;i++) {
cols[i].pos = x;
if(cols[i].expand) {
cols[i].size += hexpand + hexpand2;
}
if(cols[i].size >
0) {
x += cols[i].size + w->grid.columnspacing;
}
hexpand2 =
0;
}
int vexpand =
0;
int height_diff = height - req_height;
int vexpand2 =
0;
if(height_diff >
0 && num_rows_expanding >
0) {
vexpand = height_diff / num_rows_expanding;
vexpand2 = height_diff-vexpand*num_rows_expanding;
}
int y = w->grid.padding_bottom;
for(
int i=
0;i<nrows;i++) {
rows[i].pos = y;
if(rows[i].expand) {
rows[i].size += vexpand + vexpand2;
}
if(rows[i].size >
0) {
y += rows[i].size += w->grid.rowspacing;
}
vexpand2 =
0;
}
for(
int i=
0;i<w->composite.num_children;i++) {
Widget child = w->composite.children[i];
GridConstraintRec *constraints = child->core.constraints;
GridDef c = cols[constraints->grid.x];
GridDef r = rows[constraints->grid.y];
int x = c.pos + constraints->grid.margin_left;
int y = r.pos + constraints->grid.margin_top;
int width = constraints->grid.pref_width;
int height = constraints->grid.pref_height;
if(constraints->grid.hfill) {
if(constraints->grid.colspan >
1) {
Dimension cwidth =
0;
for(
int j=
0;j<constraints->grid.colspan;j++) {
if(constraints->grid.x+j < ncols) {
cwidth += cols[constraints->grid.x+j].size + (j >
0 ? w->grid.columnspacing :
0);
}
}
width = cwidth;
}
else {
width = c.size - w->grid.columnspacing - constraints->grid.margin_left - constraints->grid.margin_right;
}
}
if(constraints->grid.vfill) {
if(constraints->grid.rowspan >
1) {
Dimension cheight =
0;
for(
int j=
0;j<constraints->grid.rowspan;j++) {
if(constraints->grid.y+j < nrows) {
cheight += rows[constraints->grid.y+j].size + (j >
0 ? w->grid.rowspacing :
0);
}
}
height = cheight;
}
else {
height = r.size - w->grid.rowspacing - constraints->grid.margin_top - constraints->grid.margin_bottom;
}
}
if(width >
0 && height >
0) {
XtConfigureWidget(child, x, y, width, height, child->core.border_width);
}
}
free(cols);
free(rows);
}