diff --git a/src/lib/aqdiagram/placement/0BUILD b/src/lib/aqdiagram/placement/0BUILD
index 73f0952..f769747 100644
--- a/src/lib/aqdiagram/placement/0BUILD
+++ b/src/lib/aqdiagram/placement/0BUILD
@@ -61,6 +61,8 @@
+ o_hlayout.h
+ o_hlayout-t.h
@@ -70,6 +72,9 @@
$(local/typefiles)
+
+ o_hlayout.c
+ o_hlayout-t.c
diff --git a/src/lib/aqdiagram/placement/o_hlayout-t.c b/src/lib/aqdiagram/placement/o_hlayout-t.c
new file mode 100644
index 0000000..f5f4d7c
--- /dev/null
+++ b/src/lib/aqdiagram/placement/o_hlayout-t.c
@@ -0,0 +1,201 @@
+/****************************************************************************
+ * 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
+#endif
+
+#include "o_hlayout-t.h"
+#include "o_hlayout.h"
+
+#include
+
+#include
+
+
+
+#ifdef AQDIAGRAM_ENABLE_TESTCODE
+
+
+
+/* ------------------------------------------------------------------------------------------------
+ * forward declarations
+ * ------------------------------------------------------------------------------------------------
+ */
+
+static int GWENHYWFAR_CB test1(GWEN_TEST_MODULE *mod);
+
+static AQDG_OBJECT *_createBox10x10(uint32_t opts);
+static int _boxGetDefaultWidth10(AQDG_OBJECT *object);
+static int _boxGetDefaultHeight10(AQDG_OBJECT *object);
+
+
+
+/* ------------------------------------------------------------------------------------------------
+ * implementations
+ * ------------------------------------------------------------------------------------------------
+ */
+
+int AQDG_HLayoutObject_AddTests(GWEN_TEST_MODULE *mod)
+{
+ GWEN_TEST_MODULE *newMod;
+
+ newMod=GWEN_Test_Module_AddModule(mod, "AQDG_HLayoutObject", NULL);
+
+ GWEN_Test_Module_AddTest(newMod, "test1", test1, NULL);
+
+ return 0;
+}
+
+
+
+int test1(GWEN_UNUSED GWEN_TEST_MODULE *mod)
+{
+ AQDG_OBJECT *hlayout;
+ AQDG_OBJECT *box1;
+ AQDG_OBJECT *box2;
+ AQDG_OBJECT *box3;
+ int x;
+ int y;
+ int w;
+ int h;
+ int errors=0;
+
+ hlayout=AQDG_HLayoutObject_new(NULL, 0);
+ AQDG_Object_SetWidth(hlayout, 100);
+ AQDG_Object_SetHeight(hlayout, 50);
+ AQDG_Object_SetBorderLeft(hlayout, 2);
+ AQDG_Object_SetBorderRight(hlayout, 4);
+ AQDG_Object_SetBorderTop(hlayout, 3);
+ AQDG_Object_SetBorderBottom(hlayout, 5);
+ AQDG_Object_SetHSpacing(hlayout, 2);
+ AQDG_Object_SetVSpacing(hlayout, 3);
+
+ box1=_createBox10x10(AQDG_OBJECT_OPTIONS_STRETCHY);
+ AQDG_Object_Tree2_AddChild(hlayout, box1);
+
+ box2=_createBox10x10(AQDG_OBJECT_OPTIONS_STRETCHX | AQDG_OBJECT_OPTIONS_VALIGNCENTER);
+ AQDG_Object_Tree2_AddChild(hlayout, box2);
+
+ box3=_createBox10x10(AQDG_OBJECT_OPTIONS_VALIGNBOTTOM);
+ AQDG_Object_Tree2_AddChild(hlayout, box3);
+
+ AQDG_Object_Layout(hlayout);
+
+ x=AQDG_Object_GetRelativeX(box1);
+ y=AQDG_Object_GetRelativeY(box1);
+ w=AQDG_Object_GetWidth(box1);
+ h=AQDG_Object_GetHeight(box1);
+ DBG_INFO(AQDG_LOGDOMAIN, "x=%d, y=%d, w=%d, h=%d", x, y, w, h);
+ if (x!=2) {
+ DBG_ERROR(AQDG_LOGDOMAIN, "X of box 1 is not 2 (%d)", x);
+ errors++;
+ }
+ if (w!=10) {
+ DBG_ERROR(AQDG_LOGDOMAIN, "WIDTH of box 1 is not 10 (%d)", w);
+ errors++;
+ }
+ if (y!=3) {
+ DBG_ERROR(AQDG_LOGDOMAIN, "Y of box 1 is not 3 (%d)", y);
+ errors++;
+ }
+ if (h!=42) {
+ DBG_ERROR(AQDG_LOGDOMAIN, "HEIGHT of box 1 is not 42 (%d)", y);
+ errors++;
+ }
+
+ x=AQDG_Object_GetRelativeX(box2);
+ y=AQDG_Object_GetRelativeY(box2);
+ w=AQDG_Object_GetWidth(box2);
+ h=AQDG_Object_GetHeight(box2);
+ DBG_INFO(AQDG_LOGDOMAIN, "x=%d, y=%d, w=%d, h=%d", x, y, w, h);
+
+ if (x!=14) {
+ DBG_ERROR(AQDG_LOGDOMAIN, "X of box 2 is not 14 (%d)", x);
+ errors++;
+ }
+ if (w!=70) {
+ DBG_ERROR(AQDG_LOGDOMAIN, "WIDTH of box 2 is not 70 (%d)", w);
+ errors++;
+ }
+ if (y!=16) {
+ DBG_ERROR(AQDG_LOGDOMAIN, "Y of box 2 is not 16 (%d)", y);
+ errors++;
+ }
+ if (h!=10) {
+ DBG_ERROR(AQDG_LOGDOMAIN, "HEIGHT of box 2 is not 10 (%d)", y);
+ errors++;
+ }
+
+ x=AQDG_Object_GetRelativeX(box3);
+ y=AQDG_Object_GetRelativeY(box3);
+ w=AQDG_Object_GetWidth(box3);
+ h=AQDG_Object_GetHeight(box3);
+ DBG_INFO(AQDG_LOGDOMAIN, "x=%d, y=%d, w=%d, h=%d", x, y, w, h);
+ if (x!=86) {
+ DBG_ERROR(AQDG_LOGDOMAIN, "X of box 3 is not 86 (%d)", x);
+ errors++;
+ }
+ if (w!=10) {
+ DBG_ERROR(AQDG_LOGDOMAIN, "WIDTH of box 3 is not 10 (%d)", w);
+ errors++;
+ }
+ if (y!=35) {
+ DBG_ERROR(AQDG_LOGDOMAIN, "Y of box 3 is not 35 (%d)", y);
+ errors++;
+ }
+ if (h!=10) {
+ DBG_ERROR(AQDG_LOGDOMAIN, "HEIGHT of box 3 is not 10 (%d)", y);
+ errors++;
+ }
+
+
+ return errors?GWEN_ERROR_GENERIC:0;
+}
+
+
+
+AQDG_OBJECT *_createBox10x10(uint32_t opts)
+{
+ AQDG_OBJECT *box;
+
+ box=AQDG_Object_new();
+ AQDG_Object_SetOptions(box, opts);
+ AQDG_Object_SetGetDefaultWidthFn(box, _boxGetDefaultWidth10);
+ AQDG_Object_SetGetDefaultHeightFn(box, _boxGetDefaultHeight10);
+ return box;
+}
+
+
+
+int _boxGetDefaultWidth10(AQDG_OBJECT *object)
+{
+ return 10;
+}
+
+
+
+int _boxGetDefaultHeight10(AQDG_OBJECT *object)
+{
+ return 10;
+}
+
+
+
+
+
+#else
+
+int AQDG_HLayoutObject_AddTests(GWEN_TEST_MODULE *mod)
+{
+ DBG_ERROR(GWEN_LOGDOMAIN, "AqDiagram was compiled without test code enabled.");
+ return GWEN_ERROR_GENERIC;
+}
+
+
+#endif
diff --git a/src/lib/aqdiagram/placement/o_hlayout-t.h b/src/lib/aqdiagram/placement/o_hlayout-t.h
new file mode 100644
index 0000000..a4c18e8
--- /dev/null
+++ b/src/lib/aqdiagram/placement/o_hlayout-t.h
@@ -0,0 +1,25 @@
+/****************************************************************************
+ * 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_T_H
+#define AQDG_PLACEMENT_O_LAYOUT_T_H
+
+#include
+
+#include
+#include
+
+
+
+AQDG_API int AQDG_HLayoutObject_AddTests(GWEN_TEST_MODULE *mod);
+
+
+
+
+#endif
+
diff --git a/src/lib/aqdiagram/placement/o_hlayout.c b/src/lib/aqdiagram/placement/o_hlayout.c
new file mode 100644
index 0000000..7441b97
--- /dev/null
+++ b/src/lib/aqdiagram/placement/o_hlayout.c
@@ -0,0 +1,154 @@
+/****************************************************************************
+ * 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
+#endif
+
+#include "o_hlayout.h"
+
+
+/* ------------------------------------------------------------------------------------------------
+ * forward declarations
+ * ------------------------------------------------------------------------------------------------
+ */
+
+static int _layout(AQDG_OBJECT *object);
+static void _vAlignChild(AQDG_OBJECT *child, uint32_t childOpts, int parentHeight, int borderTop, int borderBottom);
+
+
+
+/* ------------------------------------------------------------------------------------------------
+ * implementations
+ * ------------------------------------------------------------------------------------------------
+ */
+
+AQDG_OBJECT *AQDG_HLayoutObject_new(AQDG_OBJECT *parent, uint32_t options)
+{
+ AQDG_OBJECT *object;
+
+ object=AQDG_Object_new();
+ AQDG_Object_SetOptions(object, options);
+
+ AQDG_Object_SetLayoutFn(object, _layout);
+
+ if (parent)
+ AQDG_Object_Tree2_AddChild(parent, object);
+ return object;
+}
+
+
+
+
+int _layout(AQDG_OBJECT *object)
+{
+ AQDG_OBJECT *child;
+ int stretchables=0;
+ int minWidth;
+ int selfWidth;
+ int selfHeight;
+ int hSpacing;
+ int borderTop;
+ int borderBottom;
+
+ selfWidth=AQDG_Object_GetWidth(object);
+ selfHeight=AQDG_Object_GetHeight(object);
+ borderTop=AQDG_Object_GetBorderTop(object);
+ borderBottom=AQDG_Object_GetBorderBottom(object);
+ hSpacing=AQDG_Object_GetHSpacing(object);
+
+ minWidth=AQDG_Object_GetBorderLeft(object);
+ child=AQDG_Object_Tree2_GetFirstChild(object);
+ while(child) {
+ int childDefWidth;
+ uint32_t childOpts;
+
+ childOpts=AQDG_Object_GetOptions(child);
+ AQDG_Object_SetRelativeX(child, minWidth);
+
+ if (childOpts & AQDG_OBJECT_OPTIONS_FIXEDWIDTH)
+ childDefWidth=AQDG_Object_GetWidth(child);
+ else {
+ childDefWidth=AQDG_Object_GetDefaultWidth(child);
+ AQDG_Object_SetWidth(child, childDefWidth);
+ }
+ minWidth+=childDefWidth;
+
+ _vAlignChild(child, childOpts, selfHeight, borderTop, borderBottom);
+
+ if (childOpts & AQDG_OBJECT_OPTIONS_STRETCHX)
+ stretchables++;
+
+ child=AQDG_Object_Tree2_GetNext(child);
+ if (child)
+ minWidth+=hSpacing;
+ }
+ minWidth+=AQDG_Object_GetBorderRight(object);
+
+ if (stretchables && (selfWidth>minWidth)) {
+ int diffWidth;
+ int toAdd;
+ int pos;
+
+ diffWidth=selfWidth-minWidth;
+ toAdd=diffWidth/stretchables;
+
+ pos=AQDG_Object_GetBorderLeft(object);
+ child=AQDG_Object_Tree2_GetFirstChild(object);
+ while(child) {
+ int w;
+
+ AQDG_Object_SetRelativeX(child, pos);
+ w=AQDG_Object_GetWidth(child);
+ if (AQDG_Object_GetOptions(child) & AQDG_OBJECT_OPTIONS_STRETCHX) {
+ w+=toAdd;
+ AQDG_Object_SetWidth(child, w);
+ }
+ pos+=w;
+ child=AQDG_Object_Tree2_GetNext(child);
+ if (child)
+ pos+=hSpacing;
+ } /* while */
+ }
+ return 0;
+}
+
+
+
+void _vAlignChild(AQDG_OBJECT *child, uint32_t childOpts, int parentHeight, int borderTop, int borderBottom)
+{
+ int childHeight;
+ int y;
+ int rawParentHeight;
+
+ rawParentHeight=parentHeight-borderTop-borderBottom;
+ if (childOpts & AQDG_OBJECT_OPTIONS_FIXEDHEIGHT)
+ childHeight=AQDG_Object_GetHeight(child);
+ else {
+ if (childOpts & AQDG_OBJECT_OPTIONS_STRETCHY)
+ childHeight=rawParentHeight;
+ else
+ childHeight=AQDG_Object_GetDefaultHeight(child);
+ AQDG_Object_SetHeight(child, childHeight);
+ }
+
+ if (childOpts & AQDG_OBJECT_OPTIONS_VALIGNBOTTOM)
+ y=parentHeight-borderBottom-childHeight;
+ else if (childOpts & AQDG_OBJECT_OPTIONS_VALIGNCENTER)
+ y=(rawParentHeight-childHeight)/2;
+ else
+ y=borderTop;
+ AQDG_Object_SetRelativeY(child, y);
+}
+
+
+
+
+
+
+
diff --git a/src/lib/aqdiagram/placement/o_hlayout.h b/src/lib/aqdiagram/placement/o_hlayout.h
new file mode 100644
index 0000000..a23ff71
--- /dev/null
+++ b/src/lib/aqdiagram/placement/o_hlayout.h
@@ -0,0 +1,24 @@
+/****************************************************************************
+ * 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
+
+#include
+
+
+
+AQDG_API AQDG_OBJECT *AQDG_HLayoutObject_new(AQDG_OBJECT *parent, uint32_t options);
+
+
+
+
+#endif
+