Added common code for layouting.

This commit is contained in:
Martin Preuss
2023-11-18 17:02:30 +01:00
parent 697548e093
commit 0638a58e16
6 changed files with 471 additions and 2 deletions

View File

@@ -61,6 +61,8 @@
<headers dist="true" install="$(pkgincludedir)">
layout.h
o_layout.h
o_hlayout.h
o_hlayout-t.h
</headers>
@@ -73,6 +75,8 @@
<sources>
$(local/typefiles)
layout.c
o_layout.c
o_hlayout.c
o_hlayout-t.c
</sources>

View File

@@ -0,0 +1,196 @@
/****************************************************************************
* This file is part of the project AqDiagram.
* AqDiagram (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./layout.h"
static int _getSumOfElementWidths(const AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements);
static int _getStretchableElements(const AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements);
static int _getMaxElementWidth(const AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements);
static void _placeAndStretch(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements, int borderBegin, int spacing, int stretch);
static void _placeAndStretchWithEqualLength(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements,
int borderBegin, int spacing, int itemLength, int stretch);
static void _place(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements, int borderBegin, int spacing);
void AQDG_Placement_LayoutAndStretch(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements,
int destLength, int borderBegin, int borderEnd, int spacing)
{
if (numElements) {
int w;
int stretchables;
w=borderBegin+_getSumOfElementWidths(ptrElements, numElements)+borderEnd+(numElements-1)*spacing;
stretchables=_getStretchableElements(ptrElements, numElements);
if (stretchables && w<destLength) {
int d;
d=(destLength-w)/stretchables;
if (d)
_placeAndStretch(ptrElements, numElements, borderBegin, spacing, d);
else
_place(ptrElements, numElements, borderBegin, spacing);
}
else
_place(ptrElements, numElements, borderBegin, spacing);
}
}
void AQDG_Placement_LayoutWithEqualLength(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements,
int destLength, int borderBegin, int borderEnd, int spacing)
{
if (numElements) {
int maxElementWidth;
int w;
int stretch=0;
maxElementWidth=_getMaxElementWidth(ptrElements, numElements);
w=borderBegin+maxElementWidth+borderEnd+(numElements-1)*spacing;
if (w<destLength)
stretch=(destLength-w)/numElements;
_placeAndStretchWithEqualLength(ptrElements, numElements, borderBegin, spacing, maxElementWidth, (stretch>0)?stretch:0);
}
}
void AQDG_Placement_LayoutSecondaryAxis(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements,
int destLength, int borderBegin, int borderEnd)
{
if (numElements) {
int i;
int rawLength;
AQDG_PLACEMENT_LAYOUT_ELEMENT *ptr;
rawLength=destLength-borderBegin-borderEnd;
ptr=ptrElements;
for (i=0; i<numElements; i++) {
int pos;
if (ptr->opts & AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_RIGHT) {
pos=destLength-borderEnd-ptr->length;
}
else if (ptr->opts & AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_CENTER) {
pos=borderBegin+(rawLength-ptr->length)/2;
}
else
pos=borderBegin;
ptr->pos=(pos>borderBegin)?pos:borderBegin;
ptr++;
}
}
}
int _getSumOfElementWidths(const AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements)
{
int i;
int w=0;
for (i=0; i<numElements; i++)
w+=(ptrElements++)->length;
return w;
}
int _getStretchableElements(const AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements)
{
int i;
int n=0;
for (i=0; i<numElements; i++)
if (((ptrElements++)->opts) & AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_STRETCH)
n++;
return n;
}
int _getMaxElementWidth(const AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements)
{
int i;
int w=-1;
for (i=0; i<numElements; i++) {
w=(ptrElements->length>w)?(ptrElements->length):w;
ptrElements++;
}
return w;
}
void _placeAndStretch(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements, int borderBegin, int spacing, int stretch)
{
int i;
int pos=0;
AQDG_PLACEMENT_LAYOUT_ELEMENT *ptr;
pos=borderBegin;
ptr=ptrElements;
for (i=0; i<numElements; i++) {
ptr->pos=pos;
if (ptr->opts & AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_STRETCH)
ptr->length+=stretch;
pos+=ptr->length+spacing;
ptr++;
}
}
void _placeAndStretchWithEqualLength(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements,
int borderBegin, int spacing, int itemLength, int stretch)
{
int i;
int pos=0;
AQDG_PLACEMENT_LAYOUT_ELEMENT *ptr;
pos=borderBegin;
ptr=ptrElements;
for (i=0; i<numElements; i++) {
ptr->pos=pos;
ptr->length=itemLength;
pos+=itemLength+spacing+stretch;
ptr++;
}
}
void _place(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements, int borderBegin, int spacing)
{
int i;
int pos=0;
AQDG_PLACEMENT_LAYOUT_ELEMENT *ptr;
pos=borderBegin;
ptr=ptrElements;
for (i=0; i<numElements; i++) {
ptr->pos=pos;
pos+=ptr->length+spacing;
ptr++;
}
}

View File

@@ -0,0 +1,48 @@
/****************************************************************************
* This file is part of the project AqDiagram.
* AqDiagram (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQDG_PLACEMENT_LAYOUT_H
#define AQDG_PLACEMENT_LAYOUT_H
#include <aqdiagram/aqdg_api.h>
#include <inttypes.h>
#define AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_STRETCH 0x0001
#define AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_CENTER 0x0002
#define AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_RIGHT 0x0004
typedef struct AQDG_PLACEMENT_LAYOUT_ELEMENT AQDG_PLACEMENT_LAYOUT_ELEMENT;
struct AQDG_PLACEMENT_LAYOUT_ELEMENT {
int pos;
int length;
uint32_t opts;
};
AQDG_API void AQDG_Placement_LayoutAndStretch(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements,
int destLength, int borderBegin, int borderEnd, int spacing);
AQDG_API void AQDG_Placement_LayoutWithEqualLength(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements,
int destLength, int borderBegin, int borderEnd, int spacing);
AQDG_API void AQDG_Placement_LayoutSecondaryAxis(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements,
int destLength, int borderBegin, int borderEnd);
#endif

View File

@@ -6,8 +6,8 @@
* should have received along with this file.
****************************************************************************/
#ifndef AQDG_PLACEMENT_O_LAYOUT_H
#define AQDG_PLACEMENT_O_LAYOUT_H
#ifndef AQDG_PLACEMENT_O_HLAYOUT_H
#define AQDG_PLACEMENT_O_HLAYOUT_H
#include <aqdiagram/aqdg_api.h>

View File

@@ -0,0 +1,189 @@
/****************************************************************************
* This file is part of the project AqDiagram.
* AqDiagram (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "o_layout.h"
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _setElementFromObjectX(AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr, const AQDG_OBJECT *object);
static void _setElementFromObjectY(AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr, const AQDG_OBJECT *object);
static void _setObjectFromElementX(AQDG_OBJECT *object, const AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr);
static void _setObjectFromElementY(AQDG_OBJECT *object, const AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
int AQDG_LayoutObject_CountDirectChildren(const AQDG_OBJECT *object)
{
int c=0;
const AQDG_OBJECT *child;
child=AQDG_Object_Tree2_GetFirstChild(object);
while(child) {
c++;
child=AQDG_Object_Tree2_GetNext(child);
}
return c;
}
AQDG_PLACEMENT_LAYOUT_ELEMENT *AQDG_LayoutObject_Children2ElementsX(const AQDG_OBJECT *object, int num)
{
if (num) {
AQDG_PLACEMENT_LAYOUT_ELEMENT *elements;
elements=(AQDG_PLACEMENT_LAYOUT_ELEMENT*) malloc(num*sizeof(AQDG_PLACEMENT_LAYOUT_ELEMENT));
if (elements) {
const AQDG_OBJECT *child;
AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr;
eptr=elements;
child=AQDG_Object_Tree2_GetFirstChild(object);
while(child && num) {
_setElementFromObjectX(eptr, object);
child=AQDG_Object_Tree2_GetNext(child);
eptr++;
num--;
}
return elements;
}
}
return NULL;
}
AQDG_PLACEMENT_LAYOUT_ELEMENT *AQDG_LayoutObject_Children2ElementsY(const AQDG_OBJECT *object, int num)
{
if (num) {
AQDG_PLACEMENT_LAYOUT_ELEMENT *elements;
elements=(AQDG_PLACEMENT_LAYOUT_ELEMENT*) malloc(num*sizeof(AQDG_PLACEMENT_LAYOUT_ELEMENT));
if (elements) {
const AQDG_OBJECT *child;
AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr;
eptr=elements;
child=AQDG_Object_Tree2_GetFirstChild(object);
while(child && num) {
_setElementFromObjectY(eptr, object);
child=AQDG_Object_Tree2_GetNext(child);
eptr++;
num--;
}
return elements;
}
}
return NULL;
}
void AQDG_LayoutObject_ChildrenFromElementsX(AQDG_OBJECT *object, const AQDG_PLACEMENT_LAYOUT_ELEMENT *elements, int num)
{
if (num && elements) {
AQDG_OBJECT *child;
const AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr;
eptr=elements;
child=AQDG_Object_Tree2_GetFirstChild(object);
while(child && num) {
_setObjectFromElementX(child, eptr);
eptr++;
num--;
child=AQDG_Object_Tree2_GetNext(child);
}
}
}
void AQDG_LayoutObject_ChildrenFromElementsY(AQDG_OBJECT *object, const AQDG_PLACEMENT_LAYOUT_ELEMENT *elements, int num)
{
if (num && elements) {
AQDG_OBJECT *child;
const AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr;
eptr=elements;
child=AQDG_Object_Tree2_GetFirstChild(object);
while(child && num) {
_setObjectFromElementY(child, eptr);
eptr++;
num--;
child=AQDG_Object_Tree2_GetNext(child);
}
}
}
void _setElementFromObjectX(AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr, const AQDG_OBJECT *object)
{
uint32_t opts;
opts=AQDG_Object_GetOptions(object);
eptr->pos=0;
eptr->length=AQDG_Object_GetWidth(object);
eptr->opts=(opts & AQDG_OBJECT_OPTIONS_STRETCHX)?AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_STRETCH:0;
eptr->opts|=(opts & AQDG_OBJECT_OPTIONS_HALIGNCENTER)?AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_CENTER:0;
eptr->opts|=(opts & AQDG_OBJECT_OPTIONS_HALIGNRIGHT)?AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_RIGHT:0;
}
void _setElementFromObjectY(AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr, const AQDG_OBJECT *object)
{
uint32_t opts;
opts=AQDG_Object_GetOptions(object);
eptr->pos=0;
eptr->length=AQDG_Object_GetHeight(object);
eptr->opts=(opts & AQDG_OBJECT_OPTIONS_STRETCHY)?AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_STRETCH:0;
eptr->opts|=(opts & AQDG_OBJECT_OPTIONS_VALIGNCENTER)?AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_CENTER:0;
eptr->opts|=(opts & AQDG_OBJECT_OPTIONS_VALIGNBOTTOM)?AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_RIGHT:0;
}
void _setObjectFromElementX(AQDG_OBJECT *object, const AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr)
{
AQDG_Object_SetRelativeX(object, eptr->pos);
AQDG_Object_SetWidth(object, eptr->length);
}
void _setObjectFromElementY(AQDG_OBJECT *object, const AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr)
{
AQDG_Object_SetRelativeY(object, eptr->pos);
AQDG_Object_SetHeight(object, eptr->length);
}

View File

@@ -0,0 +1,32 @@
/****************************************************************************
* This file is part of the project AqDiagram.
* AqDiagram (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQDG_PLACEMENT_O_LAYOUT_H
#define AQDG_PLACEMENT_O_LAYOUT_H
#include <aqdiagram/aqdg_api.h>
#include <aqdiagram/placement/object.h>
#include <aqdiagram/placement/layout.h>
AQDG_API int AQDG_LayoutObject_CountDirectChildren(const AQDG_OBJECT *object);
AQDG_API AQDG_PLACEMENT_LAYOUT_ELEMENT *AQDG_LayoutObject_Children2ElementsX(const AQDG_OBJECT *object, int num);
AQDG_API AQDG_PLACEMENT_LAYOUT_ELEMENT *AQDG_LayoutObject_Children2ElementsY(const AQDG_OBJECT *object, int num);
AQDG_API void AQDG_LayoutObject_ChildrenFromElementsX(AQDG_OBJECT *object, const AQDG_PLACEMENT_LAYOUT_ELEMENT *elements, int num);
AQDG_API void AQDG_LayoutObject_ChildrenFromElementsY(AQDG_OBJECT *object, const AQDG_PLACEMENT_LAYOUT_ELEMENT *elements, int num);
#endif