#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 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
}
};
GridClassRec gridClassRec = {
{
(WidgetClass)&xmManagerClassRec,
"Grid",
sizeof(GridRec),
grid_class_initialize,
NULL,
FALSE,
(XtInitProc)grid_initialize,
NULL,
grid_realize,
actionslist,
XtNumber(actionslist),
NULL,
0,
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,
},
{
NULL,
NULL,
0,
NULL,
0,
NULL,
NULL
},
{
0
}
};
WidgetClass gridClass = (WidgetClass)&gridClassRec;
void grid_class_initialize(Widget request, Widget new, ArgList args, Cardinal *num_args) {
}
void grid_initialize(Widget request, Widget new, ArgList args, Cardinal num_args) {
MyWidget mn = (MyWidget)new;
mn->mywidget.max_col =
0;
mn->mywidget.max_row =
0;
}
void grid_realize(MyWidget w,XtValueMask *valueMask,XSetWindowAttributes *attributes) {
XtMakeResizeRequest((Widget)w,
400,
400,
NULL,
NULL);
(coreClassRec.core_class.realize)((Widget)w, valueMask, attributes);
grid_place_children(w);
}
void grid_destroy(MyWidget widget) {
}
void grid_resize(MyWidget widget) {
grid_place_children(widget);
}
void grid_expose(MyWidget 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(MyWidget myw, XEvent *event, String *params, Cardinal *nparam) {
}
void grid_loosefocus(MyWidget 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((MyWidget)XtParent(widget));
return XtGeometryYes;
}
void GridChangeManaged(Widget widget) {
}
Boolean ConstraintSetValues(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args) {
GridConstraintRec *constraints = neww->core.constraints;
MyWidget grid = (MyWidget)XtParent(neww);
if(constraints->grid.x > grid->mywidget.max_col) {
grid->mywidget.max_col = constraints->grid.x;
}
if(constraints->grid.y > grid->mywidget.max_row) {
grid->mywidget.max_row = constraints->grid.y;
}
}
void grid_constraint_init(
Widget request,
Widget neww,
ArgList args,
Cardinal* num_args
)
{
GridConstraintRec *constraints = neww->core.constraints;
MyWidget grid = (MyWidget)XtParent(neww);
if(constraints->grid.x > grid->mywidget.max_col) {
grid->mywidget.max_col = constraints->grid.x;
}
if(constraints->grid.y > grid->mywidget.max_row) {
grid->mywidget.max_row = constraints->grid.y;
}
constraints->grid.pref_width = neww->core.width;
constraints->grid.pref_height = neww->core.height;
}
void grid_place_children(MyWidget w) {
int ncols = w->mywidget.max_col+
1;
int nrows = w->mywidget.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 =
0;
int req_height =
0;
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.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 = constraints->grid.pref_width - span_width;
if(diff >
0) {
last_col->size += diff;
}
}
else if(constraints->grid.pref_width > col->size) {
col->size = constraints->grid.pref_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 = constraints->grid.pref_height - span_height;
if(diff >
0) {
last_row->size += diff;
}
}
else if(constraints->grid.pref_height > row->size) {
row->size = constraints->grid.pref_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;
}
if(req_width >
0 && req_height >
0) {
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->mywidget.sizerequest) {
Dimension actual_width, actual_height;
w->mywidget.sizerequest =
TRUE;
XtMakeResizeRequest((Widget)w, req_width, req_height, &actual_width, &actual_height);
w->mywidget.sizerequest =
FALSE;
}
}
int hexpand =
0;
int width_diff = (
int)w->core.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 =
0;
for(
int i=
0;i<ncols;i++) {
cols[i].pos = x;
if(cols[i].expand) {
cols[i].size += hexpand + hexpand2;
}
x += cols[i].size;
hexpand2 =
0;
}
int vexpand =
0;
int height_diff = (
int)w->core.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 =
0;
for(
int i=
0;i<nrows;i++) {
rows[i].pos = y;
if(rows[i].expand) {
rows[i].size += vexpand + vexpand2;
}
y += rows[i].size;
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;
int y = r.pos;
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;
}
}
width = cwidth;
}
else {
width = c.size;
}
}
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;
}
}
height = cheight;
}
else {
height = r.size;
}
}
XtConfigureWidget(child, x, y, width, height, child->core.border_width);
}
free(cols);
free(rows);
}