Commit hBox.[ch]; a preliminary horizontal layout container.
git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@5418 4a71c877-e1ca-e34f-864e-861f7616d084master
parent
0160a3e859
commit
8e7d4d0d09
|
@ -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;
|
||||
}
|
|
@ -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_*/
|
Loading…
Reference in New Issue