196 lines
4.3 KiB
C++
196 lines
4.3 KiB
C++
|
// 26 november 2015
|
||
|
#include "uipriv_winforms.hpp"
|
||
|
|
||
|
using namespace System::Collections::Generic;
|
||
|
|
||
|
// TODO
|
||
|
// - save Alignment of children?
|
||
|
// - SnapsToDevicePixels? http://stackoverflow.com/questions/10718985/grid-border-gap-between-cells
|
||
|
|
||
|
ref class boxChild {
|
||
|
public:
|
||
|
uiControl *c;
|
||
|
Border ^border;
|
||
|
int stretchy;
|
||
|
};
|
||
|
|
||
|
struct uiBox {
|
||
|
uiWindowsControl c;
|
||
|
// we could've used StackPanel but that doesn't care about available size
|
||
|
gcroot<Grid ^> *grid;
|
||
|
gcroot<List<boxChild ^> ^> *children;
|
||
|
int vertical;
|
||
|
int padded;
|
||
|
};
|
||
|
|
||
|
static void onDestroy(uiBox *b);
|
||
|
|
||
|
uiWindowsDefineControlWithOnDestroy(
|
||
|
uiBox, // type name
|
||
|
uiBoxType, // type function
|
||
|
grid, // handle
|
||
|
onDestroy(hthis); // on destroy
|
||
|
)
|
||
|
|
||
|
static void onDestroy(uiBox *b)
|
||
|
{
|
||
|
List<boxChild ^> ^children;
|
||
|
|
||
|
children = *(b->children);
|
||
|
while (children->Count != 0) {
|
||
|
children[0]->border->Child = nullptr;
|
||
|
uiControlSetParent(children[0]->c, NULL);
|
||
|
uiControlDestroy(children[0]->c);
|
||
|
children->RemoveAt(0);
|
||
|
}
|
||
|
delete b->children;
|
||
|
}
|
||
|
|
||
|
static void boxContainerUpdateState(uiControl *c)
|
||
|
{
|
||
|
uiBox *b = uiBox(c);
|
||
|
List<boxChild ^> ^children;
|
||
|
int i;
|
||
|
|
||
|
children = *(b->children);
|
||
|
for (i = 0; i < children->Count; i++)
|
||
|
controlUpdateState(children[i]->c);
|
||
|
}
|
||
|
|
||
|
// Grid unfortunately does not have a way to set the spacing between rows and columns.
|
||
|
// This means we have to do padding ourselves.
|
||
|
// TODO this doesn't work right for visibility purposes
|
||
|
static void resetMargins(uiBox *b)
|
||
|
{
|
||
|
double paddingUnit;
|
||
|
Thickness first;
|
||
|
Thickness after;
|
||
|
List<boxChild ^> ^children;
|
||
|
int i;
|
||
|
|
||
|
children = *(b->children);
|
||
|
if (children->Count == 0)
|
||
|
return;
|
||
|
|
||
|
paddingUnit = 0;
|
||
|
if (b->padded)
|
||
|
paddingUnit = 5;
|
||
|
first = Thickness(0, 0, 0, 0);
|
||
|
after = Thickness(paddingUnit, 0, 0, 0);
|
||
|
if (b->vertical)
|
||
|
after = Thickness(0, paddingUnit, 0, 0);
|
||
|
|
||
|
// TODO padding?
|
||
|
children[0]->border->Margin = first;
|
||
|
for (i = 1; i < children->Count; i++)
|
||
|
children[i]->border->Margin = after;
|
||
|
}
|
||
|
|
||
|
void uiBoxAppend(uiBox *b, uiControl *c, int stretchy)
|
||
|
{
|
||
|
Grid ^g;
|
||
|
boxChild ^bc;
|
||
|
int pos;
|
||
|
|
||
|
bc = gcnew boxChild();
|
||
|
bc->c = c;
|
||
|
bc->border = gcnew Border();
|
||
|
bc->stretchy = stretchy;
|
||
|
|
||
|
bc->border->Child = genericHandle(bc->c);
|
||
|
|
||
|
g = *(b->grid);
|
||
|
|
||
|
// get position before adding the child so that we get the right count value
|
||
|
pos = g->ColumnDefinitions->Count;
|
||
|
if (b->vertical)
|
||
|
pos = g->RowDefinitions->Count;
|
||
|
|
||
|
g->Children->Add(bc->border);
|
||
|
|
||
|
if (b->vertical) {
|
||
|
g->SetRow(bc->border, pos);
|
||
|
g->SetColumn(bc->border, 0);
|
||
|
// apparently we have to do this ourselves...
|
||
|
g->RowDefinitions->Add(gcnew RowDefinition());
|
||
|
if (bc->stretchy)
|
||
|
g->RowDefinitions[pos]->Height = GridLength(1, GridUnitType::Star);
|
||
|
else
|
||
|
g->RowDefinitions[pos]->Height = GridLength(1, GridUnitType::Auto);
|
||
|
} else {
|
||
|
g->SetRow(bc->border, 0);
|
||
|
g->SetColumn(bc->border, pos);
|
||
|
g->ColumnDefinitions->Add(gcnew ColumnDefinition());
|
||
|
if (bc->stretchy)
|
||
|
g->ColumnDefinitions[pos]->Width = GridLength(1, GridUnitType::Star);
|
||
|
else
|
||
|
g->ColumnDefinitions[pos]->Width = GridLength(1, GridUnitType::Auto);
|
||
|
}
|
||
|
|
||
|
uiControlSetParent(bc->c, uiControl(b));
|
||
|
(*(b->children))->Add(bc);
|
||
|
resetMargins(b);
|
||
|
}
|
||
|
|
||
|
void uiBoxDelete(uiBox *b, uintmax_t index)
|
||
|
{
|
||
|
boxChild ^bc;
|
||
|
List<boxChild ^> ^children;
|
||
|
|
||
|
children = *(b->children);
|
||
|
bc = children[index];
|
||
|
children->RemoveAt(index);
|
||
|
uiControlSetParent(bc->c, NULL);
|
||
|
bc->border->Child = nullptr;
|
||
|
(*(b->grid))->Children->RemoveAt(index);
|
||
|
resetMargins(b);
|
||
|
}
|
||
|
|
||
|
int uiBoxPadded(uiBox *b)
|
||
|
{
|
||
|
return b->padded;
|
||
|
}
|
||
|
|
||
|
void uiBoxSetPadded(uiBox *b, int padded)
|
||
|
{
|
||
|
b->padded = padded;
|
||
|
resetMargins(b);
|
||
|
}
|
||
|
|
||
|
static uiBox *finishNewBox(int vertical)
|
||
|
{
|
||
|
uiBox *b;
|
||
|
|
||
|
b = (uiBox *) uiNewControl(uiBoxType());
|
||
|
|
||
|
b->grid = new gcroot<Grid ^>();
|
||
|
*(b->grid) = gcnew Grid();
|
||
|
|
||
|
b->vertical = vertical;
|
||
|
if (b->vertical) {
|
||
|
(*(b->grid))->ColumnDefinitions->Add(gcnew ColumnDefinition());
|
||
|
(*(b->grid))->ColumnDefinitions[0]->Width = GridLength(1, GridUnitType::Star);
|
||
|
} else {
|
||
|
(*(b->grid))->RowDefinitions->Add(gcnew RowDefinition());
|
||
|
(*(b->grid))->RowDefinitions[0]->Height = GridLength(1, GridUnitType::Star);
|
||
|
}
|
||
|
|
||
|
b->children = new gcroot<List<boxChild ^> ^>();
|
||
|
*(b->children) = gcnew List<boxChild ^>();
|
||
|
|
||
|
uiWindowsFinishNewControl(b, uiBox, grid);
|
||
|
uiControl(b)->ContainerUpdateState = boxContainerUpdateState;
|
||
|
|
||
|
return b;
|
||
|
}
|
||
|
|
||
|
uiBox *uiNewHorizontalBox(void)
|
||
|
{
|
||
|
return finishNewBox(0);
|
||
|
}
|
||
|
|
||
|
uiBox *uiNewVerticalBox(void)
|
||
|
{
|
||
|
return finishNewBox(1);
|
||
|
}
|