1044 lines
33 KiB
C
1044 lines
33 KiB
C
/** @file
|
|
UI Common Controls
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2020, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
#include "UiControls.h"
|
|
|
|
STATIC UI_FLEX_LAYOUT_CLASS *mFlexLayoutClass = NULL;
|
|
#define CURRENT_CLASS mFlexLayoutClass
|
|
|
|
typedef struct {
|
|
INT32 Width;
|
|
INT32 Height;
|
|
|
|
SIZE *ItemsSize;
|
|
UINTN ItemCount;
|
|
UINTN FlexItemCount;
|
|
} UI_FLEX_LAYOUT_ROW_INFO, UI_FLEX_LAYOUT_COLUMN_INFO;
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
UiFlexLayoutGetRowInfo (
|
|
IN UI_CONTROL *Control,
|
|
IN SIZE ChildAvailable,
|
|
OUT UINT32 *RowInfoCount,
|
|
OUT UI_FLEX_LAYOUT_ROW_INFO **RowInfoList
|
|
)
|
|
{
|
|
UI_FLEX_LAYOUT *This;
|
|
SIZE *SizeList;
|
|
SIZE *ItemSize;
|
|
UINTN Index;
|
|
UINTN ItemCount;
|
|
UINTN FlexItemCount;
|
|
INT32 RowWidth;
|
|
INT32 RowHeight;
|
|
UI_FLEX_LAYOUT_ROW_INFO *RowInfo;
|
|
UI_FLEX_LAYOUT_ROW_INFO *InfoList;
|
|
UINT32 InfoCount;
|
|
UI_CONTROL *Item;
|
|
INT32 ItemMarginWidth;
|
|
INT32 ItemMarginHeight;
|
|
SIZE ItemAvailable;
|
|
|
|
if (Control->ItemCount == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
SizeList = AllocateZeroPool (Control->ItemCount * sizeof(SIZE));
|
|
if (SizeList == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
This = (UI_FLEX_LAYOUT *) Control;
|
|
InfoList = NULL;
|
|
InfoCount = 0;
|
|
RowWidth = 0;
|
|
RowHeight = 0;
|
|
ItemCount = 0;
|
|
FlexItemCount = 0;
|
|
|
|
for (Index = 0; Index < Control->ItemCount; Index++) {
|
|
Item = Control->Items[Index];
|
|
ItemCount++;
|
|
|
|
if ((GetWindowLongPtr (Item->Wnd, GWL_STYLE) & WS_VISIBLE) == 0) {
|
|
continue;
|
|
}
|
|
|
|
ItemSize = &SizeList[Index];
|
|
CopyMem (&Item->Available, &ChildAvailable, sizeof (SIZE));
|
|
CopyMem (&ItemAvailable , &ChildAvailable, sizeof (SIZE));
|
|
ItemMarginWidth = GetControlMarginWidth (Item);
|
|
ItemMarginHeight = GetControlMarginHeight (Item);
|
|
ItemAvailable.cx -= ItemMarginWidth;
|
|
ItemAvailable.cy -= ItemMarginHeight;
|
|
SizeList[Index] = CONTROL_CLASS (Item)->EstimateSize (Item, ItemAvailable);
|
|
if (ItemSize->cx <= 0) {
|
|
continue;
|
|
}
|
|
ItemSize->cx += ItemMarginWidth;
|
|
ItemSize->cy += ItemMarginHeight;
|
|
|
|
if (Item->Float || Item->Position == UI_POSITION_ABSOLUTE) {
|
|
continue;
|
|
}
|
|
FlexItemCount++;
|
|
|
|
if (This->FlexWrap == UI_FLEX_LAYOUT_FLEX_WRAP_TYPE_NO_WRAP || RowWidth + ItemSize->cx <= ChildAvailable.cx) {
|
|
RowWidth += ItemSize->cx;
|
|
RowHeight = MAX(RowHeight, ItemSize->cy);
|
|
} else {
|
|
InfoList = ReallocatePool (sizeof(UI_FLEX_LAYOUT_ROW_INFO) * InfoCount, sizeof(UI_FLEX_LAYOUT_ROW_INFO) * (InfoCount + 1), InfoList);
|
|
if (InfoList == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
RowInfo = &InfoList[InfoCount++];
|
|
|
|
if (RowWidth > 0) {
|
|
RowInfo->Width = RowWidth;
|
|
RowInfo->Height = RowHeight;
|
|
RowInfo->ItemCount = ItemCount - 1;
|
|
RowInfo->FlexItemCount = FlexItemCount - 1;
|
|
RowInfo->ItemsSize = &SizeList[Index - RowInfo->ItemCount];
|
|
|
|
ItemCount = 1;
|
|
FlexItemCount = 1;
|
|
RowWidth = ItemSize->cx;
|
|
RowHeight = ItemSize->cy;
|
|
} else {
|
|
RowInfo->Width = ItemSize->cx;
|
|
RowInfo->Height = ItemSize->cy;
|
|
RowInfo->ItemCount = ItemCount;
|
|
RowInfo->FlexItemCount = FlexItemCount;
|
|
RowInfo->ItemsSize = &SizeList[Index + 1 - RowInfo->ItemCount];
|
|
|
|
ItemCount = 0;
|
|
FlexItemCount = 0;
|
|
RowWidth = 0;
|
|
RowHeight = 0;
|
|
}
|
|
}
|
|
}
|
|
if (RowWidth > 0) {
|
|
InfoList = ReallocatePool (sizeof(UI_FLEX_LAYOUT_ROW_INFO) * InfoCount, sizeof(UI_FLEX_LAYOUT_ROW_INFO) * (InfoCount + 1), InfoList);
|
|
if (InfoList == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
RowInfo = &InfoList[InfoCount++];
|
|
|
|
RowInfo->Width = RowWidth;
|
|
RowInfo->Height = RowHeight;
|
|
RowInfo->ItemCount = ItemCount;
|
|
RowInfo->FlexItemCount = FlexItemCount;
|
|
RowInfo->ItemsSize = &SizeList[Index - RowInfo->ItemCount];
|
|
}
|
|
|
|
if (InfoCount == 0) {
|
|
FreePool (SizeList);
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
*RowInfoList = InfoList;
|
|
*RowInfoCount = InfoCount;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
UiFlexLayoutGetColumnInfo (
|
|
IN UI_CONTROL *Control,
|
|
IN SIZE ChildAvailable,
|
|
OUT UINT32 *ColumnInfoCount,
|
|
OUT UI_FLEX_LAYOUT_COLUMN_INFO **ColumnInfoList
|
|
)
|
|
{
|
|
UI_FLEX_LAYOUT *This;
|
|
SIZE *SizeList;
|
|
SIZE *ItemSize;
|
|
UINTN Index;
|
|
UINTN ItemCount;
|
|
UINTN FlexItemCount;
|
|
INT32 ColumnWidth;
|
|
INT32 ColumnHeight;
|
|
UI_FLEX_LAYOUT_COLUMN_INFO *ColumnInfo;
|
|
UI_FLEX_LAYOUT_COLUMN_INFO *InfoList;
|
|
UINT32 InfoCount;
|
|
UI_CONTROL *Item;
|
|
INT32 ItemMarginWidth;
|
|
INT32 ItemMarginHeight;
|
|
SIZE ItemAvailable;
|
|
|
|
if (Control->ItemCount == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
SizeList = AllocateZeroPool (Control->ItemCount * sizeof(SIZE));
|
|
if (SizeList == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
This = (UI_FLEX_LAYOUT *) Control;
|
|
InfoList = NULL;
|
|
InfoCount = 0;
|
|
ColumnWidth = 0;
|
|
ColumnHeight = 0;
|
|
ItemCount = 0;
|
|
FlexItemCount = 0;
|
|
|
|
for (Index = 0; Index < Control->ItemCount; Index++) {
|
|
Item = Control->Items[Index];
|
|
ItemCount++;
|
|
|
|
if ((GetWindowLongPtr (Item->Wnd, GWL_STYLE) & WS_VISIBLE) == 0) {
|
|
continue;
|
|
}
|
|
|
|
ItemSize = &SizeList[Index];
|
|
CopyMem (&Item->Available, &ChildAvailable, sizeof (SIZE));
|
|
CopyMem (&ItemAvailable, &ChildAvailable, sizeof (SIZE));
|
|
ItemMarginWidth = GetControlMarginWidth (Item);
|
|
ItemMarginHeight = GetControlMarginHeight (Item);
|
|
ItemAvailable.cx -= ItemMarginWidth;
|
|
ItemAvailable.cy -= ItemMarginHeight;
|
|
SizeList[Index] = CONTROL_CLASS (Item)->EstimateSize (Item, ItemAvailable);
|
|
if (ItemSize->cy <= 0) {
|
|
continue;
|
|
}
|
|
ItemSize->cx += ItemMarginWidth;
|
|
ItemSize->cy += ItemMarginHeight;
|
|
|
|
if (Item->Float || Item->Position == UI_POSITION_ABSOLUTE) {
|
|
continue;
|
|
}
|
|
FlexItemCount++;
|
|
|
|
if (This->FlexWrap == UI_FLEX_LAYOUT_FLEX_WRAP_TYPE_NO_WRAP || ColumnHeight + ItemSize->cy <= ChildAvailable.cy) {
|
|
ColumnHeight += ItemSize->cy;
|
|
ColumnWidth = MAX(ColumnWidth, ItemSize->cx);
|
|
} else {
|
|
InfoList = ReallocatePool (sizeof(UI_FLEX_LAYOUT_COLUMN_INFO) * InfoCount, sizeof(UI_FLEX_LAYOUT_COLUMN_INFO) * (InfoCount + 1), InfoList);
|
|
if (InfoList == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
ColumnInfo = &InfoList[InfoCount++];
|
|
|
|
if (ColumnHeight > 0) {
|
|
ColumnInfo->Width = ColumnWidth;
|
|
ColumnInfo->Height = ColumnHeight;
|
|
ColumnInfo->ItemCount = ItemCount - 1;
|
|
ColumnInfo->FlexItemCount = FlexItemCount - 1;
|
|
ColumnInfo->ItemsSize = &SizeList[Index - ColumnInfo->ItemCount];
|
|
|
|
ItemCount = 1;
|
|
FlexItemCount = 1;
|
|
ColumnWidth = ItemSize->cx;
|
|
ColumnHeight = ItemSize->cy;
|
|
} else {
|
|
ColumnInfo->Width = ItemSize->cx;
|
|
ColumnInfo->Height = ItemSize->cy;
|
|
ColumnInfo->ItemCount = ItemCount;
|
|
ColumnInfo->FlexItemCount = FlexItemCount;
|
|
ColumnInfo->ItemsSize = &SizeList[Index + 1 - ColumnInfo->ItemCount];
|
|
|
|
ItemCount = 0;
|
|
FlexItemCount = 0;
|
|
ColumnWidth = 0;
|
|
ColumnHeight = 0;
|
|
}
|
|
}
|
|
}
|
|
if (ColumnHeight > 0) {
|
|
InfoList = ReallocatePool (sizeof(UI_FLEX_LAYOUT_COLUMN_INFO) * InfoCount, sizeof(UI_FLEX_LAYOUT_COLUMN_INFO) * (InfoCount + 1), InfoList);
|
|
if (InfoList == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
ColumnInfo = &InfoList[InfoCount++];
|
|
|
|
ColumnInfo->Width = ColumnWidth;
|
|
ColumnInfo->Height = ColumnHeight;
|
|
ColumnInfo->ItemCount = ItemCount;
|
|
ColumnInfo->FlexItemCount = FlexItemCount;
|
|
ColumnInfo->ItemsSize = &SizeList[Index - ColumnInfo->ItemCount];
|
|
}
|
|
|
|
if (InfoCount == 0) {
|
|
FreePool (SizeList);
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
*ColumnInfoList = InfoList;
|
|
*ColumnInfoCount = InfoCount;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
UiFlexLayoutEstimateChildSizeByRow (
|
|
IN UI_CONTROL *Control,
|
|
IN SIZE ChildAvailable,
|
|
OUT INTN *ChildWidth,
|
|
OUT INTN *ChildHeight
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UI_FLEX_LAYOUT_ROW_INFO *RowInfoList;
|
|
UINT32 Count;
|
|
UINT32 Index;
|
|
INTN Height;
|
|
INTN Width;
|
|
|
|
Status = UiFlexLayoutGetRowInfo (Control, ChildAvailable, &Count, &RowInfoList);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Width = 0;
|
|
Height = 0;
|
|
for (Index = 0; Index < Count; Index++) {
|
|
Width = MAX(Width, RowInfoList[Index].Width);
|
|
Height += RowInfoList[Index].Height;
|
|
}
|
|
*ChildWidth = Width;
|
|
*ChildHeight = Height;
|
|
|
|
FreePool (RowInfoList->ItemsSize);
|
|
FreePool (RowInfoList);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
UiFlexLayoutEstimateChildSizeByColumn (
|
|
IN UI_CONTROL *Control,
|
|
IN SIZE ChildAvailable,
|
|
OUT INTN *ChildWidth,
|
|
OUT INTN *ChildHeight
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UI_FLEX_LAYOUT_COLUMN_INFO *ColumnInfoList;
|
|
UINT32 Count;
|
|
UINT32 Index;
|
|
INTN Height;
|
|
INTN Width;
|
|
|
|
Status = UiFlexLayoutGetColumnInfo (Control, ChildAvailable, &Count, &ColumnInfoList);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Width = 0;
|
|
Height = 0;
|
|
for (Index = 0; Index < Count; Index++) {
|
|
Height = MAX(Height, ColumnInfoList[Index].Height);
|
|
Width += ColumnInfoList[Index].Width;
|
|
}
|
|
*ChildWidth = Width;
|
|
*ChildHeight = Height;
|
|
|
|
FreePool (ColumnInfoList->ItemsSize);
|
|
FreePool (ColumnInfoList);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
SIZE
|
|
UiFlexLayoutEstimateSize (
|
|
UI_CONTROL *Control,
|
|
SIZE AvailableSize
|
|
)
|
|
{
|
|
UI_FLEX_LAYOUT *This;
|
|
SIZE Size;
|
|
SIZE Available;
|
|
INTN Height;
|
|
INTN Width;
|
|
|
|
if (Control->Width.Type != UI_LENGTH_TYPE_WRAP_CONTENT &&
|
|
Control->Height.Type != UI_LENGTH_TYPE_WRAP_CONTENT) {
|
|
return CalculateControlDisplaySize (Control, AvailableSize);
|
|
}
|
|
|
|
Available.cx = AvailableSize.cx - GetControlPaddingWidth (Control) - GetControlBorderWidth (Control);
|
|
Available.cy = AvailableSize.cy - GetControlPaddingHeight (Control) - GetControlBorderHeight (Control);
|
|
|
|
if (IS_CONTROL_HEIGHT_VALUE_ASSIGNED (Control)) {
|
|
Available.cy = CalculateControlDisplayHeight (Control, AvailableSize) - GetControlPaddingHeight (Control) - GetControlBorderHeight (Control);
|
|
}
|
|
if (IS_CONTROL_WIDTH_VALUE_ASSIGNED (Control)) {
|
|
Available.cx = CalculateControlDisplayWidth (Control, AvailableSize) - GetControlPaddingWidth (Control) - GetControlBorderWidth (Control);
|
|
}
|
|
|
|
This = (UI_FLEX_LAYOUT *) Control;
|
|
Width = 0;
|
|
Height = 0;
|
|
if (This->FlexDirection == UI_FLEX_LAYOUT_FLEX_DIRECTION_TYPE_ROW) {
|
|
UiFlexLayoutEstimateChildSizeByRow (Control, Available, &Width, &Height);
|
|
} else {
|
|
UiFlexLayoutEstimateChildSizeByColumn (Control, Available, &Width, &Height);
|
|
}
|
|
|
|
if (Width > 0) {
|
|
Width += (GetControlPaddingWidth (Control) + GetControlBorderWidth (Control));
|
|
}
|
|
if (Height > 0) {
|
|
Height += (GetControlPaddingHeight (Control) + GetControlBorderHeight (Control));
|
|
}
|
|
|
|
Width = MAX (Width , Control->MinSize.cx);
|
|
Height = MAX (Height, Control->MinSize.cy);
|
|
|
|
Size = CalculateControlDisplaySize (Control, AvailableSize);
|
|
if (Size.cy == WRAP_CONTENT) {
|
|
Size.cy = (GDICOORD)Height;
|
|
}
|
|
|
|
if (Size.cx == WRAP_CONTENT) {
|
|
Size.cx = (GDICOORD)Width;
|
|
}
|
|
|
|
return Size;
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
UiFlexLayoutSetChildPositionByRow (
|
|
UI_CONTROL *Control,
|
|
CONST RECT *Pos
|
|
)
|
|
{
|
|
UI_FLEX_LAYOUT *This;
|
|
UI_CONTROL *Item;
|
|
UINTN Index;
|
|
UINTN ItemIndex;
|
|
UINTN Count;
|
|
RECT ItemRc;
|
|
UINT32 Left;
|
|
UINT32 Top;
|
|
UINT32 JustifyContentPadding;
|
|
UINT32 AlignContentPadding;
|
|
UINT32 AlignItemsPadding;
|
|
SIZE Available;
|
|
SIZE *ItemSize;
|
|
POINT Point;
|
|
UINT32 RowInfoCount;
|
|
UI_FLEX_LAYOUT_ROW_INFO *RowInfoList;
|
|
UI_FLEX_LAYOUT_ROW_INFO *RowInfo;
|
|
EFI_STATUS Status;
|
|
INT32 Height;
|
|
|
|
This = (UI_FLEX_LAYOUT *) Control;
|
|
|
|
Available.cx = Pos->right - Pos->left;
|
|
Available.cy = Pos->bottom - Pos->top;
|
|
|
|
Status = UiFlexLayoutGetRowInfo (Control, Available, &RowInfoCount, &RowInfoList);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
Top = Pos->top;
|
|
Left = Pos->left;
|
|
AlignItemsPadding = 0;
|
|
AlignContentPadding = 0;
|
|
JustifyContentPadding = 0;
|
|
|
|
switch (This->AlignContent) {
|
|
|
|
case UI_FLEX_LAYOUT_ALIGN_CONTENT_TYPE_STRETCH:
|
|
Top = Pos->top;
|
|
for (Index = 0, Height = 0; Index < RowInfoCount; Index++) {
|
|
Height += RowInfoList[Index].Height;
|
|
}
|
|
if (Available.cy > Height) {
|
|
for (Index = 0; Index < RowInfoCount; Index++) {
|
|
RowInfoList[Index].Height += (Available.cy - Height) / RowInfoCount;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_ALIGN_CONTENT_TYPE_FLEX_START:
|
|
Top = Pos->top;
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_ALIGN_CONTENT_TYPE_FLEX_END:
|
|
Top = Pos->bottom;
|
|
for (Index = 0; Index < RowInfoCount; Index++) {
|
|
Top -= RowInfoList[Index].Height;
|
|
}
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_ALIGN_CONTENT_TYPE_CENTER:
|
|
for (Index = 0, Height = 0; Index < RowInfoCount; Index++) {
|
|
Height += RowInfoList[Index].Height;
|
|
}
|
|
Top = Pos->top + (Available.cy - Height) / 2;
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_ALIGN_CONTENT_TYPE_SPACE_BETWEEN:
|
|
Top = Pos->top;
|
|
if (RowInfoCount > 1) {
|
|
for (Index = 0, Height = 0; Index < RowInfoCount; Index++) {
|
|
Height += RowInfoList[Index].Height;
|
|
}
|
|
if (Available.cy > Height) {
|
|
AlignContentPadding = (Available.cy - Height) / (RowInfoCount - 1);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_ALIGN_CONTENT_TYPE_SPACE_AROUND:
|
|
for (Index = 0, Height = 0; Index < RowInfoCount; Index++) {
|
|
Height += RowInfoList[Index].Height;
|
|
}
|
|
if (Available.cy > Height) {
|
|
AlignContentPadding = (Available.cy - Height) / (RowInfoCount * 2);
|
|
}
|
|
|
|
Top = Pos->top + AlignContentPadding;
|
|
AlignContentPadding = AlignContentPadding * 2;
|
|
break;
|
|
}
|
|
|
|
for (Index = 0, Count = 0; Index < RowInfoCount; Index++) {
|
|
RowInfo = &RowInfoList[Index];
|
|
|
|
switch (This->JustifyContent) {
|
|
|
|
case UI_FLEX_LAYOUT_JUSTIFY_CONTENT_TYPE_FLEX_START:
|
|
Left = Pos->left;
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_JUSTIFY_CONTENT_TYPE_FLEX_END:
|
|
Left = Pos->right - RowInfo->Width;
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_JUSTIFY_CONTENT_TYPE_CENTER:
|
|
Left = Pos->left + (Available.cx - RowInfo->Width) / 2;
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_JUSTIFY_CONTENT_TYPE_SPACE_BETWEEN:
|
|
Left = Pos->left;
|
|
if (Available.cx > RowInfo->Width && RowInfo->FlexItemCount > 1) {
|
|
JustifyContentPadding = (UINT32) ((Available.cx - RowInfo->Width) / (RowInfo->FlexItemCount - 1));
|
|
} else {
|
|
JustifyContentPadding = 0;
|
|
}
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_JUSTIFY_CONTENT_TYPE_SPACE_AROUND:
|
|
if (Available.cx > RowInfo->Width) {
|
|
JustifyContentPadding = (UINT32) ((Available.cx - RowInfo->Width) / (RowInfo->FlexItemCount * 2));
|
|
} else {
|
|
JustifyContentPadding = 0;
|
|
}
|
|
Left = Pos->left + JustifyContentPadding;
|
|
JustifyContentPadding = JustifyContentPadding * 2;
|
|
break;
|
|
}
|
|
|
|
for (ItemIndex = 0; ItemIndex < RowInfo->ItemCount; ItemIndex++) {
|
|
Item = Control->Items[Count++];
|
|
ItemSize = &RowInfo->ItemsSize[ItemIndex];
|
|
|
|
if ((GetWindowLongPtr (Item->Wnd, GWL_STYLE) & WS_VISIBLE) == 0) {
|
|
continue;
|
|
}
|
|
if (Item->Float || Item->Position == UI_POSITION_ABSOLUTE) {
|
|
if (ItemSize->cx == 0 || ItemSize->cx == MATCH_PARENT) {
|
|
ItemSize->cx = Available.cx;
|
|
}
|
|
if (ItemSize->cy == 0 || ItemSize->cy == MATCH_PARENT) {
|
|
ItemSize->cy = Available.cy;
|
|
}
|
|
|
|
Point = CalculateControlDisplayXY (Item, ItemSize, &Item->Available);
|
|
SetRect (
|
|
&ItemRc,
|
|
Point.x + GetControlMarginLeft (Item),
|
|
Point.y + GetControlMarginTop (Item),
|
|
Point.x + GetControlMarginLeft (Item) + ItemSize->cx,
|
|
Point.y + GetControlMarginTop (Item) + ItemSize->cy
|
|
);
|
|
mSetPositionLevel++;
|
|
CONTROL_CLASS (Item)->SetPosition (Item, &ItemRc);
|
|
mSetPositionLevel--;
|
|
continue;
|
|
}
|
|
|
|
switch (This->AlignItems) {
|
|
|
|
case UI_FLEX_LAYOUT_ALIGN_ITEMS_TYPE_FLEX_END:
|
|
if (RowInfo->Height > ItemSize->cy) {
|
|
AlignItemsPadding = RowInfo->Height - ItemSize->cy;
|
|
} else {
|
|
AlignItemsPadding = 0;
|
|
}
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_ALIGN_ITEMS_TYPE_CENTER:
|
|
if (RowInfo->Height > ItemSize->cy) {
|
|
AlignItemsPadding = (RowInfo->Height - ItemSize->cy) / 2;
|
|
} else {
|
|
AlignItemsPadding = 0;
|
|
}
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_ALIGN_ITEMS_TYPE_STRETCH:
|
|
if (!IS_UI_LENGTH_VALUE_ASSIGNED (Item->Height) && RowInfo->Height > ItemSize->cy) {
|
|
ItemSize->cy = RowInfo->Height;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if ((ItemSize->cy == 0) || (ItemSize->cy == MATCH_PARENT)) {
|
|
ItemSize->cy = RowInfo->Height;
|
|
}
|
|
|
|
Left += GetControlMarginLeft (Item);
|
|
|
|
ItemRc.left = Left;
|
|
ItemRc.top = Top + GetControlMarginTop (Item) + AlignItemsPadding;
|
|
ItemRc.right = ItemRc.left + ItemSize->cx - GetControlMarginWidth (Item);
|
|
ItemRc.bottom = ItemRc.top + ItemSize->cy - GetControlMarginHeight (Item);
|
|
|
|
mSetPositionLevel++;
|
|
CONTROL_CLASS (Item)->SetPosition (Item, &ItemRc);
|
|
mSetPositionLevel--;
|
|
|
|
Left = ItemRc.right + GetControlMarginRight (Item) + JustifyContentPadding;
|
|
}
|
|
|
|
Top += RowInfo->Height + AlignContentPadding;
|
|
}
|
|
|
|
FreePool (RowInfoList->ItemsSize);
|
|
FreePool (RowInfoList);
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
UiFlexLayoutSetChildPositionByColumn (
|
|
UI_CONTROL *Control,
|
|
CONST RECT *Pos
|
|
)
|
|
{
|
|
UI_FLEX_LAYOUT *This;
|
|
UI_CONTROL *Item;
|
|
UINTN Index;
|
|
UINTN ItemIndex;
|
|
UINTN Count;
|
|
RECT ItemRc;
|
|
UINT32 Left;
|
|
UINT32 Top;
|
|
UINT32 JustifyContentPadding;
|
|
UINT32 AlignContentPadding;
|
|
UINT32 AlignItemsPadding;
|
|
SIZE Available;
|
|
SIZE *ItemSize;
|
|
POINT Point;
|
|
UINT32 ColumnInfoCount;
|
|
UI_FLEX_LAYOUT_COLUMN_INFO *ColumnInfoList;
|
|
UI_FLEX_LAYOUT_COLUMN_INFO *ColumnInfo;
|
|
EFI_STATUS Status;
|
|
INT32 Width;
|
|
|
|
This = (UI_FLEX_LAYOUT *) Control;
|
|
|
|
Available.cx = Pos->right - Pos->left;
|
|
Available.cy = Pos->bottom - Pos->top;
|
|
|
|
Status = UiFlexLayoutGetColumnInfo (Control, Available, &ColumnInfoCount, &ColumnInfoList);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
Top = Pos->top;
|
|
Left = Pos->left;
|
|
AlignItemsPadding = 0;
|
|
AlignContentPadding = 0;
|
|
JustifyContentPadding = 0;
|
|
|
|
switch (This->AlignContent) {
|
|
|
|
case UI_FLEX_LAYOUT_ALIGN_CONTENT_TYPE_STRETCH:
|
|
Left = Pos->left;
|
|
for (Index = 0, Width = 0; Index < ColumnInfoCount; Index++) {
|
|
Width += ColumnInfoList[Index].Width;
|
|
}
|
|
if (Available.cx > Width) {
|
|
for (Index = 0; Index < ColumnInfoCount; Index++) {
|
|
ColumnInfoList[Index].Width += (Available.cx - Width) / ColumnInfoCount;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_ALIGN_CONTENT_TYPE_FLEX_START:
|
|
Left = Pos->left;
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_ALIGN_CONTENT_TYPE_FLEX_END:
|
|
Left = Pos->right;
|
|
for (Index = 0; Index < ColumnInfoCount; Index++) {
|
|
Left -= ColumnInfoList[Index].Width;
|
|
}
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_ALIGN_CONTENT_TYPE_CENTER:
|
|
for (Index = 0, Width = 0; Index < ColumnInfoCount; Index++) {
|
|
Width += ColumnInfoList[Index].Width;
|
|
}
|
|
Left = Pos->left + (Available.cx - Width) / 2;
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_ALIGN_CONTENT_TYPE_SPACE_BETWEEN:
|
|
Left = Pos->left;
|
|
if (ColumnInfoCount > 1) {
|
|
for (Index = 0, Width = 0; Index < ColumnInfoCount; Index++) {
|
|
Width += ColumnInfoList[Index].Width;
|
|
}
|
|
if (Available.cx > Width) {
|
|
AlignContentPadding = (Available.cx - Width) / (ColumnInfoCount - 1);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_ALIGN_CONTENT_TYPE_SPACE_AROUND:
|
|
for (Index = 0, Width = 0; Index < ColumnInfoCount; Index++) {
|
|
Width += ColumnInfoList[Index].Width;
|
|
}
|
|
if (Available.cx > Width) {
|
|
AlignContentPadding = (Available.cx - Width) / (ColumnInfoCount * 2);
|
|
}
|
|
|
|
Left = Pos->left + AlignContentPadding;
|
|
AlignContentPadding = AlignContentPadding * 2;
|
|
break;
|
|
}
|
|
|
|
for (Index = 0, Count = 0; Index < ColumnInfoCount; Index++) {
|
|
ColumnInfo = &ColumnInfoList[Index];
|
|
|
|
switch (This->JustifyContent) {
|
|
|
|
case UI_FLEX_LAYOUT_JUSTIFY_CONTENT_TYPE_FLEX_START:
|
|
Top = Pos->top;
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_JUSTIFY_CONTENT_TYPE_FLEX_END:
|
|
Top = Pos->bottom - ColumnInfo->Height;
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_JUSTIFY_CONTENT_TYPE_CENTER:
|
|
Top = Pos->top + (Available.cy - ColumnInfo->Height) / 2;
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_JUSTIFY_CONTENT_TYPE_SPACE_BETWEEN:
|
|
Top = Pos->top;
|
|
if (Available.cy > ColumnInfo->Height && ColumnInfo->FlexItemCount > 1) {
|
|
JustifyContentPadding = (UINT32) ((Available.cy - ColumnInfo->Height) / (ColumnInfo->FlexItemCount - 1));
|
|
} else {
|
|
JustifyContentPadding = 0;
|
|
}
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_JUSTIFY_CONTENT_TYPE_SPACE_AROUND:
|
|
if (Available.cy > ColumnInfo->Height) {
|
|
JustifyContentPadding = (UINT32) ((Available.cy - ColumnInfo->Height) / (ColumnInfo->FlexItemCount * 2));
|
|
} else {
|
|
JustifyContentPadding = 0;
|
|
}
|
|
Top = Pos->top + JustifyContentPadding;
|
|
JustifyContentPadding = JustifyContentPadding * 2;
|
|
break;
|
|
}
|
|
|
|
for (ItemIndex = 0; ItemIndex < ColumnInfo->ItemCount; ItemIndex++) {
|
|
Item = Control->Items[Count++];
|
|
ItemSize = &ColumnInfo->ItemsSize[ItemIndex];
|
|
|
|
if ((GetWindowLongPtr (Item->Wnd, GWL_STYLE) & WS_VISIBLE) == 0) {
|
|
continue;
|
|
}
|
|
if (Item->Float || Item->Position == UI_POSITION_ABSOLUTE) {
|
|
if (ItemSize->cx == 0 || ItemSize->cx == MATCH_PARENT) {
|
|
ItemSize->cx = Available.cx;
|
|
}
|
|
if (ItemSize->cy == 0 || ItemSize->cy == MATCH_PARENT) {
|
|
ItemSize->cy = Available.cy;
|
|
}
|
|
|
|
Point = CalculateControlDisplayXY (Item, ItemSize, &Item->Available);
|
|
SetRect (
|
|
&ItemRc,
|
|
Point.x + GetControlMarginLeft (Item),
|
|
Point.y + GetControlMarginTop (Item),
|
|
Point.x + GetControlMarginLeft (Item) + ItemSize->cx,
|
|
Point.y + GetControlMarginTop (Item) + ItemSize->cy
|
|
);
|
|
mSetPositionLevel++;
|
|
CONTROL_CLASS (Item)->SetPosition (Item, &ItemRc);
|
|
mSetPositionLevel--;
|
|
continue;
|
|
}
|
|
|
|
switch (This->AlignItems) {
|
|
|
|
case UI_FLEX_LAYOUT_ALIGN_ITEMS_TYPE_FLEX_END:
|
|
if (ColumnInfo->Width > ItemSize->cx) {
|
|
AlignItemsPadding = ColumnInfo->Width - ItemSize->cx;
|
|
} else {
|
|
AlignItemsPadding = 0;
|
|
}
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_ALIGN_ITEMS_TYPE_CENTER:
|
|
if (ColumnInfo->Width > ItemSize->cx) {
|
|
AlignItemsPadding = (ColumnInfo->Width - ItemSize->cx) / 2;
|
|
} else {
|
|
AlignItemsPadding = 0;
|
|
}
|
|
break;
|
|
|
|
case UI_FLEX_LAYOUT_ALIGN_ITEMS_TYPE_STRETCH:
|
|
if (!IS_UI_LENGTH_VALUE_ASSIGNED (Item->Width) && ColumnInfo->Width > ItemSize->cx) {
|
|
ItemSize->cx = ColumnInfo->Width;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if ((ItemSize->cx == 0) || (ItemSize->cx == MATCH_PARENT)) {
|
|
ItemSize->cx = ColumnInfo->Width;
|
|
}
|
|
|
|
Top += GetControlMarginTop (Item);
|
|
|
|
ItemRc.left = Left + GetControlMarginLeft (Item)+ AlignItemsPadding;
|
|
ItemRc.top = Top;
|
|
ItemRc.right = ItemRc.left + ItemSize->cx - GetControlMarginWidth (Item);
|
|
ItemRc.bottom = ItemRc.top + ItemSize->cy - GetControlMarginHeight (Item);
|
|
|
|
mSetPositionLevel++;
|
|
CONTROL_CLASS (Item)->SetPosition (Item, &ItemRc);
|
|
mSetPositionLevel--;
|
|
|
|
Top = ItemRc.bottom + GetControlMarginBottom (Item) + JustifyContentPadding;
|
|
}
|
|
|
|
Left += ColumnInfo->Width + AlignContentPadding;
|
|
}
|
|
|
|
FreePool (ColumnInfoList->ItemsSize);
|
|
FreePool (ColumnInfoList);
|
|
}
|
|
|
|
VOID
|
|
UiFlexLayoutSetPosition (
|
|
UI_CONTROL *Control,
|
|
CONST RECT *Pos
|
|
)
|
|
{
|
|
UI_FLEX_LAYOUT *This;
|
|
RECT Rc;
|
|
|
|
This = (UI_FLEX_LAYOUT *) Control;
|
|
|
|
ShowSetPositionDbgInfo (Control, Pos);
|
|
GetWindowRect(Control->Wnd, &Rc);
|
|
MapWindowPoints(HWND_DESKTOP, GetParent(Control->Wnd), (LPPOINT) &Rc, 2);
|
|
if (!EqualRect (&Rc, Pos)) {
|
|
ShowSetPositionDbgInfo (Control, Pos);
|
|
MoveWindow (Control->Wnd, Pos->left, Pos->top, Pos->right - Pos->left, Pos->bottom - Pos->top, TRUE);
|
|
CONTROL_CLASS_INVALIDATE (This);
|
|
Control->NeedUpdateChildPos = TRUE;
|
|
}
|
|
if (Control->ItemCount == 0) {
|
|
return ;
|
|
}
|
|
|
|
if (!Control->NeedUpdateChildPos) {
|
|
return ;
|
|
}
|
|
Control->NeedUpdateChildPos = FALSE;
|
|
|
|
CopyRect (&Rc, Pos);
|
|
OffsetRect (&Rc, -Rc.left, -Rc.top);
|
|
|
|
Rc.left += (GetControlPaddingLeft (Control) + GetControlBorderLeft (Control) );
|
|
Rc.top += (GetControlPaddingTop (Control) + GetControlBorderTop (Control) );
|
|
Rc.right -= (GetControlPaddingRight (Control) + GetControlBorderRight (Control) );
|
|
Rc.bottom -= (GetControlPaddingBottom (Control) + GetControlBorderBottom (Control));
|
|
|
|
if (Rc.left > Rc.right) {
|
|
Rc.left = Rc.right;
|
|
}
|
|
if (Rc.top > Rc.bottom) {
|
|
Rc.top = Rc.bottom;
|
|
}
|
|
|
|
if (This->FlexDirection == UI_FLEX_LAYOUT_FLEX_DIRECTION_TYPE_ROW) {
|
|
UiFlexLayoutSetChildPositionByRow (Control, &Rc);
|
|
} else {
|
|
UiFlexLayoutSetChildPositionByColumn (Control, &Rc);
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
EFIAPI
|
|
UiFlexLayoutSetAttribute (
|
|
UI_CONTROL *Control,
|
|
CHAR16 *Name,
|
|
CHAR16 *Value
|
|
)
|
|
{
|
|
UI_FLEX_LAYOUT *This;
|
|
|
|
This = (UI_FLEX_LAYOUT *) Control;
|
|
|
|
if (StrCmp (Name, L"flex-direction") == 0) {
|
|
if (StrCmp (Value, L"row") == 0 || StrCmp (Value, L"none") == 0) {
|
|
This->FlexDirection = UI_FLEX_LAYOUT_FLEX_DIRECTION_TYPE_ROW;
|
|
} else if (StrCmp (Value, L"column") == 0) {
|
|
This->FlexDirection = UI_FLEX_LAYOUT_FLEX_DIRECTION_TYPE_COLUMN;
|
|
} else {
|
|
DEBUG ((EFI_D_ERROR, "flex-direction can only use { none, row, column }"));
|
|
ASSERT (FALSE);
|
|
}
|
|
} else if (StrCmp (Name, L"flex-wrap") == 0) {
|
|
if (StrCmp (Value, L"nowrap") == 0) {
|
|
This->FlexWrap = UI_FLEX_LAYOUT_FLEX_WRAP_TYPE_NO_WRAP;
|
|
} else if (StrCmp (Value, L"wrap") == 0) {
|
|
This->FlexWrap = UI_FLEX_LAYOUT_FLEX_WRAP_TYPE_WRAP;
|
|
} else {
|
|
DEBUG ((EFI_D_ERROR, "flex-wrap can only use { nowrap, wrap}"));
|
|
ASSERT (FALSE);
|
|
}
|
|
} else if (StrCmp (Name, L"justify-content") == 0) {
|
|
if (StrCmp (Value, L"flex-start") == 0) {
|
|
This->JustifyContent = UI_FLEX_LAYOUT_JUSTIFY_CONTENT_TYPE_FLEX_START;
|
|
} else if (StrCmp (Value, L"flex-end") == 0) {
|
|
This->JustifyContent = UI_FLEX_LAYOUT_JUSTIFY_CONTENT_TYPE_FLEX_END;
|
|
} else if (StrCmp (Value, L"center") == 0) {
|
|
This->JustifyContent = UI_FLEX_LAYOUT_JUSTIFY_CONTENT_TYPE_CENTER;
|
|
} else if (StrCmp (Value, L"space-between") == 0) {
|
|
This->JustifyContent = UI_FLEX_LAYOUT_JUSTIFY_CONTENT_TYPE_SPACE_BETWEEN;
|
|
} else if (StrCmp (Value, L"space-around") == 0) {
|
|
This->JustifyContent = UI_FLEX_LAYOUT_JUSTIFY_CONTENT_TYPE_SPACE_AROUND;
|
|
} else {
|
|
DEBUG ((EFI_D_ERROR, "justify-content can only use { flex-start, flex-end, center, space-between, space-around }"));
|
|
ASSERT (FALSE);
|
|
}
|
|
} else if (StrCmp (Name, L"align-content") == 0) {
|
|
if (StrCmp (Value, L"stretch") == 0) {
|
|
This->AlignContent = UI_FLEX_LAYOUT_ALIGN_CONTENT_TYPE_STRETCH;
|
|
} else if (StrCmp (Value, L"flex-start") == 0) {
|
|
This->AlignContent = UI_FLEX_LAYOUT_ALIGN_CONTENT_TYPE_FLEX_START;
|
|
} else if (StrCmp (Value, L"flex-end") == 0) {
|
|
This->AlignContent = UI_FLEX_LAYOUT_ALIGN_CONTENT_TYPE_FLEX_END;
|
|
} else if (StrCmp (Value, L"center") == 0) {
|
|
This->AlignContent = UI_FLEX_LAYOUT_ALIGN_CONTENT_TYPE_CENTER;
|
|
} else if (StrCmp (Value, L"space-between") == 0) {
|
|
This->AlignContent = UI_FLEX_LAYOUT_ALIGN_CONTENT_TYPE_SPACE_BETWEEN;
|
|
} else if (StrCmp (Value, L"space-around") == 0) {
|
|
This->AlignContent = UI_FLEX_LAYOUT_ALIGN_CONTENT_TYPE_SPACE_AROUND;
|
|
} else {
|
|
DEBUG ((EFI_D_ERROR, "align-content can only use { flex-start, flex-end, center, space-between, space-around, stretch }"));
|
|
ASSERT (FALSE);
|
|
}
|
|
} else if (StrCmp (Name, L"align-items") == 0) {
|
|
if (StrCmp (Value, L"flex-start") == 0) {
|
|
This->AlignItems = UI_FLEX_LAYOUT_ALIGN_ITEMS_TYPE_FLEX_START;
|
|
} else if (StrCmp (Value, L"flex-end") == 0) {
|
|
This->AlignItems = UI_FLEX_LAYOUT_ALIGN_ITEMS_TYPE_FLEX_END;
|
|
} else if (StrCmp (Value, L"center") == 0) {
|
|
This->AlignItems = UI_FLEX_LAYOUT_ALIGN_ITEMS_TYPE_CENTER;
|
|
} else if (StrCmp (Value, L"stretch") == 0) {
|
|
This->AlignItems = UI_FLEX_LAYOUT_ALIGN_ITEMS_TYPE_STRETCH;
|
|
} else {
|
|
DEBUG ((EFI_D_ERROR, "align-items can only use { flex-start, flex-end, center, stretch }"));
|
|
ASSERT (FALSE);
|
|
}
|
|
} else {
|
|
return PARENT_CLASS_SET_ATTRIBUTE (CURRENT_CLASS, Control, Name, Value);
|
|
}
|
|
|
|
CONTROL_CLASS_INVALIDATE (This);
|
|
return TRUE;
|
|
}
|
|
|
|
LRESULT
|
|
EFIAPI
|
|
UiFlexLayoutProc (
|
|
HWND Wnd,
|
|
UINT32 Msg,
|
|
WPARAM WParam,
|
|
LPARAM LParam
|
|
)
|
|
{
|
|
UI_FLEX_LAYOUT *This;
|
|
UI_CONTROL *Control;
|
|
|
|
This = (UI_FLEX_LAYOUT *) GetWindowLongPtr (Wnd, 0);
|
|
if (This == NULL && Msg != WM_CREATE && Msg != WM_NCCALCSIZE) {
|
|
ASSERT (FALSE);
|
|
return 0;
|
|
}
|
|
Control = (UI_CONTROL *)This;
|
|
|
|
switch (Msg) {
|
|
|
|
case WM_CREATE:
|
|
This = (UI_FLEX_LAYOUT *) AllocateZeroPool (sizeof (UI_FLEX_LAYOUT));
|
|
if (This != NULL) {
|
|
CONTROL_CLASS (This) = (UI_CONTROL_CLASS *) GetClassLongPtr (Wnd, 0);
|
|
SetWindowLongPtr (Wnd, 0, (INTN)This);
|
|
SendMessage (Wnd, UI_NOTIFY_CREATE, WParam, LParam);
|
|
}
|
|
break;
|
|
|
|
case UI_NOTIFY_CREATE:
|
|
PARENT_CLASS_WNDPROC (CURRENT_CLASS, Wnd, Msg, WParam, LParam);
|
|
break;
|
|
|
|
case WM_NCHITTEST:
|
|
return HTTRANSPARENT;
|
|
|
|
default:
|
|
return PARENT_CLASS_WNDPROC (CURRENT_CLASS, Wnd, Msg, WParam, LParam);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
UI_FLEX_LAYOUT_CLASS *
|
|
EFIAPI
|
|
GetFlexLayoutClass (
|
|
VOID
|
|
)
|
|
{
|
|
if (CURRENT_CLASS != NULL) {
|
|
return CURRENT_CLASS;
|
|
}
|
|
|
|
InitUiClass ((UI_CONTROL_CLASS **)&CURRENT_CLASS, sizeof (*CURRENT_CLASS), L"FlexLayout", (UI_CONTROL_CLASS *)GetControlClass());
|
|
if (CURRENT_CLASS == NULL) {
|
|
return NULL;
|
|
}
|
|
((UI_CONTROL_CLASS *)CURRENT_CLASS)->WndProc = UiFlexLayoutProc;
|
|
((UI_CONTROL_CLASS *)CURRENT_CLASS)->SetPosition = UiFlexLayoutSetPosition;
|
|
((UI_CONTROL_CLASS *)CURRENT_CLASS)->EstimateSize = UiFlexLayoutEstimateSize;
|
|
((UI_CONTROL_CLASS *)CURRENT_CLASS)->SetAttribute = UiFlexLayoutSetAttribute;
|
|
return CURRENT_CLASS;
|
|
}
|
|
|