Commit hBox.[ch]; a preliminary horizontal layout container.

git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@5418 4a71c877-e1ca-e34f-864e-861f7616d084
master
Freddie Witherden 2008-07-08 11:19:29 +00:00
parent 0160a3e859
commit 8e7d4d0d09
2 changed files with 325 additions and 0 deletions

231
lib/betawidget/hBox.c Normal file
View File

@ -0,0 +1,231 @@
#include "hBox.h"
static hBoxVtbl vtbl;
const classInfo hBoxClassInfo =
{
&widgetClassInfo,
"hBox"
};
hBox *hBoxCreate(const char *id)
{
hBox *instance = malloc(sizeof(hBox));
if (instance == NULL)
{
return NULL;
}
// Call the constructor
hBoxInit(instance, id);
// Return the new object
return instance;
}
static void hBoxInitVtbl(hBox *self)
{
static bool initialised = false;
if (!initialised)
{
// Copy our parents vtable into ours
vtbl.widgetVtbl = *(WIDGET(self)->vtbl);
// Overload widget's destroy and doLayout methods
vtbl.widgetVtbl.destroy = hBoxDestroyImpl;
vtbl.widgetVtbl.doLayout = hBoxDoLayoutImpl;
// Along with the min- and max-size methods
vtbl.widgetVtbl.getMinSize = hBoxGetMinSizeImpl;
vtbl.widgetVtbl.getMaxSize = hBoxGetMinSizeImpl;
// A dummy draw method also
vtbl.widgetVtbl.doDraw = hBoxDoDrawImpl;
initialised = true;
}
// Replace our parents vtable with our own
WIDGET(self)->vtbl = &vtbl.widgetVtbl;
// Set our vtable
self->vtbl = &vtbl;
}
void hBoxInit(hBox *self, const char *id)
{
// Init our parent
widgetInit(WIDGET(self), id);
// Prepare our vtable
hBoxInitVtbl(self);
// Set our type
WIDGET(self)->classInfo = &hBoxClassInfo;
}
void hBoxDestroyImpl(widget *self)
{
// Call our parents destructor
widgetDestroyImpl(self);
}
bool hBoxDoLayoutImpl(widget *self)
{
typedef struct
{
size minSize;
size maxSize;
size currentSize;
point offset;
} sizeInfo;
int i, temp = 0;
const int numChildren = vectorSize(self->children);
const size minSize = widgetGetMinSize(self);
sizeInfo *childSizeInfo = malloc(sizeof(sizeInfo) * numChildren);
bool maxedOut = false;
// First make sure we are large enough to hold all of our children
if (self->size.x < minSize.x
|| self->size.y < minSize.y)
{
return false;
}
// Make sure malloc did not return NULL
if (childSizeInfo == NULL)
{
// We're screwed
return false;
}
// Get the min/max size of our children
for (i = 0; i < numChildren; i++)
{
widget *child = vectorAt(self->children, i);
childSizeInfo[i].currentSize.x = childSizeInfo[i].currentSize.y = 0;
childSizeInfo[i].minSize = widgetGetMinSize(child);
childSizeInfo[i].maxSize = widgetGetMaxSize(child);
}
// Next do y-axis positioning and initial x-axis sizing
for (i = 0, temp = self->size.x; i < numChildren; i++)
{
sizeInfo *child = &childSizeInfo[i];
// Make the child as heigh as possible
child->currentSize.y = MIN(self->size.y, child->maxSize.y);
// Make the child as thin as possible, noting how much x-space is left
child->currentSize.x = child->minSize.x;
temp -= child->currentSize.x;
// Pad out the remaining y-space
switch (HBOX(self)->vAlignment)
{
case TOP:
child->offset.y = 0;
break;
case MIDDLE:
child->offset.y = (self->size.y - child->currentSize.y) / 2;
break;
case BOTTOM:
child->offset.y = (self->size.y - child->currentSize.y);
break;
}
}
// Gradually increase the x-size of child widgets
while (!maxedOut)
{
maxedOut = true;
for (i = 0; temp && i < numChildren; i++)
{
sizeInfo *child = &childSizeInfo[i];
if (child->currentSize.x < child->maxSize.x)
{
child->currentSize.x++;
temp--;
maxedOut = false;
}
}
}
// All widgets are now as large as possible
for (i = temp = 0; i < numChildren; i++)
{
widget *child = vectorAt(self->children, i);
sizeInfo *childSize = &childSizeInfo[i];
// Set the size and offset
widgetResize(child, childSizeInfo->currentSize.x,
childSizeInfo->currentSize.y);
child->offset.x = temp;
child->offset.y = childSize->offset.y;
temp += child->size.x;
}
// We're done!
free(childSizeInfo);
return true;
}
void hBoxSetVAlign(hBox *self, vAlign v)
{
// Set the new alignment scheme
self->vAlignment = v;
// Re-layout outself (should *not* fail)
if (!widgetDoLayout(WIDGET(self)))
{
assert(!"widgetDoLayout failed after changing vertical alignment");
}
}
size hBoxGetMinSizeImpl(widget *self)
{
size minSize = { 0, 0 };
int i;
for (i = 0; i < vectorSize(self->children); i++)
{
const size minChildSize = widgetGetMinSize(vectorAt(self->children, i));
minSize.x += minChildSize.x;
minSize.y = MAX(minSize.y, minChildSize.y);
}
return minSize;
}
size hBoxGetMaxSizeImpl(widget *self)
{
size maxSize = { 0, 0 };
int i;
for (i = 0; i < vectorSize(self->children); i++)
{
const size maxChildSize = widgetGetMaxSize(vectorAt(self->children, i));
maxSize.x += maxChildSize.x;
maxSize.y = MAX(maxSize.y, maxChildSize.y);
}
return maxSize;
}
void hBoxDoDrawImpl(widget *self)
{
// NO-OP
(void) self;
}

94
lib/betawidget/hBox.h Normal file
View File

@ -0,0 +1,94 @@
#ifndef HBOX_H_
#define HBOX_H_
#include "widget.h"
/*
* Forward declarations
*/
typedef struct _hBox hBox;
typedef struct _hBoxVtbl hBoxVtbl;
typedef enum _vAlign vAlign;
/*
* The possible vertical sides a child can be aligned to
*/
enum _vAlign
{
TOP,
MIDDLE,
BOTTOM
};
struct _hBoxVtbl
{
widgetVtbl widgetVtbl;
// No additional virtual methods
};
/*
*
*/
struct _hBox
{
/*
* Parent
*/
widget widget;
/*
* Our vtable
*/
hBoxVtbl *vtbl;
/*
* Child alignment
*/
vAlign vAlignment;
};
/*
* Type information
*/
extern const classInfo hBoxClassInfo;
/*
* Helper macros
*/
#define HBOX(self) (assert(widgetIsA(WIDGET(self), &hBoxClassInfo)), \
(hBox *) (self))
/*
* Protected methods
*/
void hBoxInit(hBox *instance, const char *id);
void hBoxDestroyImpl(widget *instance);
bool hBoxDoLayoutImpl(widget *self);
void hBoxDoDrawImpl(widget *self);
size hBoxGetMinSizeImpl(widget *self);
size hBoxGetMaxSizeImpl(widget *self);
/*
* Public methods
*/
/**
* Constructs a new hBox object and returns it.
*
* @param id The id of the widget.
* @return A pointer to an hBox on success otherwise NULL.
*/
hBox *hBoxCreate(const char *id);
/**
* Sets the alignment of child widgets of self. This comes into effect when the
* maximum vertical size of the child widgets is less than that or self.
*
* @param self The hBox to set the alignment properties of.
* @param v The vertical alignment scheme to use.
*/
void hBoxSetVAlign(hBox *self, vAlign v);
#endif /*HBOX_H_*/