1584 lines
45 KiB
C
1584 lines
45 KiB
C
/** @file
|
|
UI Common Controls
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2012 - 2021, 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"
|
|
|
|
HBITMAP mDummyBitmap = NULL; //Dummy module variable used for klocwork misjudgement
|
|
|
|
STATIC
|
|
UI_CONTROL **
|
|
GetOrderedItemsByZIndex (
|
|
IN UI_CONTROL *This
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINTN CheckIndex;
|
|
INT32 ParentZIndex;
|
|
INT32 ZIndex;
|
|
UI_CONTROL *Control;
|
|
UI_CONTROL **OrderedItems;
|
|
|
|
if (This == NULL || This->Items == NULL || This->ItemCount < 2) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// If all items are the same z-index value, no need to allocate memory to return ordered items.
|
|
//
|
|
for (Index = 1; Index < This->ItemCount; Index++) {
|
|
if (This->Items[Index]->ZIndex.Type != This->Items[0]->ZIndex.Type ||
|
|
This->Items[Index]->ZIndex.Value != This->Items[0]->ZIndex.Value) {
|
|
break;
|
|
}
|
|
}
|
|
if (Index == This->ItemCount) {
|
|
return NULL;
|
|
}
|
|
|
|
OrderedItems = AllocateCopyPool (This->ItemCount * sizeof(UI_CONTROL *), This->Items);
|
|
if (OrderedItems == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Get parent z-index value if need.
|
|
//
|
|
ParentZIndex = 0;
|
|
for (Index = 0; Index < This->ItemCount; Index++) {
|
|
if (This->Items[Index]->ZIndex.Type != UI_Z_INDEX_TYPE_AUTO) {
|
|
continue;
|
|
}
|
|
|
|
for (Control = This; Control != NULL; Control = CONTROL_CLASS_GET_PARENT(Control)) {
|
|
if (Control->ZIndex.Type == UI_Z_INDEX_TYPE_NUMBER) {
|
|
ParentZIndex = Control->ZIndex.Value;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
for (Index = 0; Index < This->ItemCount - 1; Index++) {
|
|
Control = OrderedItems[Index];
|
|
ZIndex = (Control->ZIndex.Type == UI_Z_INDEX_TYPE_AUTO) ? ParentZIndex : Control->ZIndex.Value;
|
|
|
|
for (CheckIndex = Index + 1; CheckIndex < This->ItemCount; CheckIndex++) {
|
|
if ((OrderedItems[CheckIndex]->ZIndex.Type == UI_Z_INDEX_TYPE_NUMBER && OrderedItems[CheckIndex]->ZIndex.Value < ZIndex) ||
|
|
(OrderedItems[CheckIndex]->ZIndex.Type == UI_Z_INDEX_TYPE_AUTO && ParentZIndex < ZIndex)) {
|
|
OrderedItems[Index] = OrderedItems[CheckIndex];
|
|
OrderedItems[CheckIndex] = Control;
|
|
Control = OrderedItems[Index];
|
|
ZIndex = (Control->ZIndex.Type == UI_Z_INDEX_TYPE_AUTO) ? ParentZIndex : Control->ZIndex.Value;
|
|
}
|
|
}
|
|
}
|
|
|
|
return OrderedItems;
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
StrToUiLength (
|
|
IN OUT CHAR16 **ValueStr,
|
|
OUT UI_LENGTH *UiLength
|
|
)
|
|
{
|
|
UiLength->Type = UI_LENGTH_TYPE_PIXEL;
|
|
UiLength->Value = wcstol (*ValueStr, ValueStr, 10);
|
|
|
|
if ((*ValueStr)[0] == '%') {
|
|
(*ValueStr) += 1;
|
|
UiLength->Type = UI_LENGTH_TYPE_PERCENTAGE;
|
|
} else if (StrnCmp (*ValueStr, L"px", 2) == 0) {
|
|
(*ValueStr) += 2;
|
|
UiLength->Type = UI_LENGTH_TYPE_PIXEL;
|
|
} else if (StrnCmp (*ValueStr, L"em", 2) == 0) {
|
|
(*ValueStr) += 2;
|
|
UiLength->Type = UI_LENGTH_TYPE_EM;
|
|
}
|
|
|
|
if ((*ValueStr)[0] == ',' || (*ValueStr)[0] == '|') {
|
|
(*ValueStr) += 1;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
UiControlOnUiCreate (
|
|
UI_CONTROL *Control,
|
|
HWND Wnd,
|
|
UI_MANAGER *Manager
|
|
)
|
|
{
|
|
UI_CONTROL *This;
|
|
|
|
This = (UI_CONTROL *) Control;
|
|
|
|
This->Wnd = Wnd;
|
|
if (Manager != NULL) {
|
|
This->Manager = Manager;
|
|
}
|
|
|
|
This = (UI_CONTROL *) Control;
|
|
|
|
//
|
|
// original container
|
|
//
|
|
This->ItemCount = 0;
|
|
This->Items = NULL;
|
|
This->ChildPadding = 0;
|
|
This->HScrollBar = NULL;
|
|
This->VScrollBar = NULL;
|
|
This->ScrollPos.x = 0;
|
|
This->ScrollPos.y = 0;
|
|
This->TouchSlop = 4;
|
|
This->IsBeginDraged = FALSE;
|
|
This->Dragged = FALSE;
|
|
This->BkImageStyle = 0;
|
|
This->Filter = 0;
|
|
This->TextColor = 0;
|
|
This->UserData = NULL;
|
|
This->Name = L"";
|
|
This->BkColor = 0x00000000;
|
|
This->FocusBkColor = 0x00000000;
|
|
This->BorderColor = 0;
|
|
This->Float = FALSE;
|
|
This->GradientVertial = TRUE;
|
|
This->NeedUpdateChildPos = TRUE;
|
|
This->TabOrder = (UINT32)(-2);
|
|
This->Position = UI_POSITION_RELATIVE;
|
|
This->ZIndex.Type = UI_Z_INDEX_TYPE_AUTO;
|
|
This->ZIndex.Value = 0;
|
|
This->BoxSizing = UI_BOX_SIZING_CONTENT_BOX;
|
|
SetRectEmpty (&This->Scale9Grid);
|
|
|
|
//
|
|
// no focus
|
|
//
|
|
SetWindowLongPtr (
|
|
This->Wnd,
|
|
GWL_EXSTYLE,
|
|
GetWindowLongPtr (This->Wnd, GWL_EXSTYLE) | WS_EX_NOACTIVATE
|
|
);
|
|
|
|
SetWindowLongPtr (
|
|
This->Wnd,
|
|
GWL_EXSTYLE,
|
|
GetWindowLongPtr (This->Wnd, GWL_EXSTYLE) | WS_EX_CONTROLPARENT
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
UiControlOnDestroy (
|
|
UI_CONTROL *Control
|
|
)
|
|
{
|
|
UI_CONTROL *This;
|
|
|
|
|
|
This = (UI_CONTROL *) Control;
|
|
|
|
/*
|
|
if (This->Wnd != This->Manager->MainWnd &&
|
|
This->Wnd != This->Manager->Root) {
|
|
Parent = ((UI_CONTAINER *)GetUiControl(GetParent (This->Wnd)));
|
|
Parent->Remove (Parent, This);
|
|
} */
|
|
|
|
ASSERT (This);
|
|
ASSERT (This->Name);
|
|
|
|
if (StrCmp (This->Name, L"") != 0) {
|
|
StringMapRemove (&This->Manager->NameList, This->Name);
|
|
FreePool (This->Name);
|
|
}
|
|
|
|
if (This->UserData != NULL) {
|
|
FreePool (This->UserData);
|
|
}
|
|
|
|
if (This->BkImage != NULL) {
|
|
FreePool (This->BkImage);
|
|
}
|
|
if (This->BkImageBuf.Bitmap != NULL) {
|
|
FreePool (This->BkImageBuf.Bitmap);
|
|
}
|
|
|
|
if (This->HScrollBar != NULL) {
|
|
DestroyWindow (((UI_CONTROL *)(This->HScrollBar))->Wnd);
|
|
}
|
|
|
|
if (This->VScrollBar != NULL) {
|
|
DestroyWindow (((UI_CONTROL *)(This->VScrollBar))->Wnd);
|
|
}
|
|
|
|
CONTROL_CLASS (This)->RemoveAllChild (This);
|
|
|
|
FreePool (This);
|
|
}
|
|
|
|
|
|
VOID
|
|
UiControlSetPosition (
|
|
UI_CONTROL *Control,
|
|
CONST RECT *Pos
|
|
)
|
|
{
|
|
RECT Rc;
|
|
UINTN Index;
|
|
UI_CONTROL *Item;
|
|
RECT ItemRc;
|
|
UI_CONTROL *This;
|
|
SIZE Size;
|
|
SIZE Available;
|
|
POINT LeftTop;
|
|
|
|
This = (UI_CONTROL *) Control;
|
|
|
|
ASSERT (Pos->left <= Pos->right);
|
|
ASSERT (Pos->top <= Pos->bottom);
|
|
|
|
ShowSetPositionDbgInfo (Control, Pos);
|
|
GetWindowRect(Control->Wnd, &Rc);
|
|
MapWindowPoints(HWND_DESKTOP, GetParent(Control->Wnd), (LPPOINT) &Rc, 2);
|
|
if (!EqualRect (&Rc, Pos)) {
|
|
MoveWindow (Control->Wnd, Pos->left, Pos->top, Pos->right - Pos->left, Pos->bottom - Pos->top, TRUE);
|
|
CONTROL_CLASS_INVALIDATE (This);
|
|
This->NeedUpdateChildPos = TRUE;
|
|
}
|
|
|
|
if (This->ItemCount == 0) {
|
|
return ;
|
|
}
|
|
|
|
if (!This->NeedUpdateChildPos) {
|
|
return ;
|
|
}
|
|
This->NeedUpdateChildPos = FALSE;
|
|
|
|
|
|
CopyRect (&Rc, Pos);
|
|
OffsetRect (&Rc, -Rc.left, -Rc.top);
|
|
|
|
Rc.left += (GetControlPaddingLeft (This) + GetControlBorderLeft (This) );
|
|
Rc.top += (GetControlPaddingTop (This) + GetControlBorderTop (This) );
|
|
Rc.right -= (GetControlPaddingRight (This) + GetControlBorderRight (This) );
|
|
Rc.bottom -= (GetControlPaddingBottom (This) + GetControlBorderBottom (This));
|
|
|
|
if (Rc.left > Rc.right) {
|
|
Rc.left = Rc.right;
|
|
}
|
|
if (Rc.top > Rc.bottom) {
|
|
Rc.top = Rc.bottom;
|
|
}
|
|
|
|
Available.cx = Rc.right - Rc.left;
|
|
Available.cy = Rc.bottom - Rc.top;
|
|
for (Index = 0; Index < This->ItemCount; Index++) {
|
|
Item = This->Items[Index];
|
|
|
|
if ((GetWindowLongPtr (Item->Wnd, GWL_STYLE) & WS_VISIBLE) == 0) {
|
|
continue;
|
|
}
|
|
Item->Available = Available;
|
|
Size = CONTROL_CLASS (Item)->EstimateSize (Item, Available);
|
|
|
|
if (Size.cx == 0 || Size.cx == MATCH_PARENT) {
|
|
Size.cx = Rc.right - Rc.left;
|
|
}
|
|
|
|
if (Size.cy == 0 || Size.cy == MATCH_PARENT) {
|
|
Size.cy = Rc.bottom - Rc.top;
|
|
}
|
|
|
|
LeftTop = CalculateControlDisplayXY (Item, &Size, &Available);
|
|
LeftTop.x += Rc.left;
|
|
LeftTop.y += Rc.top;
|
|
|
|
SetRect (
|
|
&ItemRc,
|
|
LeftTop.x,
|
|
LeftTop.y,
|
|
LeftTop.x + Size.cx,
|
|
LeftTop.y + Size.cy
|
|
);
|
|
mSetPositionLevel++;
|
|
CONTROL_CLASS (Item)->SetPosition (Item, &ItemRc);
|
|
mSetPositionLevel--;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
UiControlOnUiPaint (
|
|
UI_CONTROL *Control,
|
|
WPARAM WParam,
|
|
LPARAM LParam
|
|
)
|
|
{
|
|
COLORREF Color;
|
|
RECT Rc;
|
|
HDC Hdc;
|
|
UI_MANAGER *Manager;
|
|
HWND Wnd;
|
|
RECT ClipRc;
|
|
HRGN OldRgn;
|
|
HRGN NewRgn;
|
|
UINTN Index;
|
|
UI_CONTROL *This;
|
|
UI_CONTROL *Item;
|
|
RECT TmpRc;
|
|
RECT ItemRc;
|
|
UI_CONTROL **OrderedItems;
|
|
SIZE Size;
|
|
|
|
This = (UI_CONTROL *) Control;
|
|
|
|
Manager = Control->Manager;
|
|
Hdc = Control->Manager->PaintDC;
|
|
Manager->GetControlRect (Manager, Control, &Rc);
|
|
Wnd = Control->Wnd;
|
|
|
|
switch (WParam) {
|
|
|
|
case PAINT_ALL:
|
|
CONTROL_CLASS_SET_STATE(Control, 0, UISTATE_INVALIDATED);
|
|
|
|
Manager->GetControlRect (Manager, This, &Rc);
|
|
if (!IntersectRect (&TmpRc, &Rc, (RECT *)LParam)) {
|
|
return ;
|
|
}
|
|
|
|
SendMessage (Wnd, UI_NOTIFY_PAINT, PAINT_BKCOLOR, LParam);
|
|
SendMessage (Wnd, UI_NOTIFY_PAINT, PAINT_BKIMAGE, LParam);
|
|
SendMessage (Wnd, UI_NOTIFY_PAINT, PAINT_STATUSIMAGE, LParam);
|
|
SendMessage (Wnd, UI_NOTIFY_PAINT, PAINT_TEXT, LParam);
|
|
SendMessage (Wnd, UI_NOTIFY_PAINT, PAINT_BORDER, LParam);
|
|
|
|
GetClipBox (Manager->PaintDC, &ClipRc);
|
|
OldRgn = CreateRectRgnIndirect (&ClipRc);
|
|
NewRgn = CreateRectRgnIndirect (&TmpRc);
|
|
ExtSelectClipRgn (Manager->PaintDC, NewRgn, RGN_AND);
|
|
|
|
OrderedItems = GetOrderedItemsByZIndex (This);
|
|
if (OrderedItems == NULL) {
|
|
OrderedItems = This->Items;
|
|
}
|
|
for (Index = 0; Index < This->ItemCount; Index++) {
|
|
Item = OrderedItems[Index];
|
|
|
|
if (!IsWindowVisible (Item->Wnd)) {
|
|
continue;
|
|
}
|
|
|
|
|
|
Manager->GetControlRect (Manager, Item, &ItemRc);
|
|
if (IntersectRect (&TmpRc, &ItemRc, (RECT *)LParam)) {
|
|
SendMessage (Item->Wnd, UI_NOTIFY_PAINT, PAINT_ALL, (LPARAM)&TmpRc);
|
|
}
|
|
}
|
|
if (OrderedItems != NULL && OrderedItems != This->Items) {
|
|
FreePool (OrderedItems);
|
|
}
|
|
|
|
if (This->HScrollBar != NULL) {
|
|
Manager->GetControlRect (Manager, (UI_CONTROL *)This->HScrollBar, &ItemRc);
|
|
if (IntersectRect (&TmpRc, &ItemRc, (RECT *)LParam)) {
|
|
SendMessage (This->HScrollBar->Control.Wnd, UI_NOTIFY_PAINT, PAINT_ALL, (LPARAM)&TmpRc);
|
|
}
|
|
}
|
|
|
|
if (This->VScrollBar != NULL) {
|
|
Manager->GetControlRect (Manager, (UI_CONTROL *)This->VScrollBar, &ItemRc);
|
|
if (IntersectRect (&TmpRc, &ItemRc, (RECT *)LParam)) {
|
|
SendMessage (This->VScrollBar->Control.Wnd, UI_NOTIFY_PAINT, PAINT_ALL, (LPARAM)&TmpRc);
|
|
}
|
|
}
|
|
|
|
SelectClipRgn(Manager->PaintDC, OldRgn);
|
|
if (OldRgn != NULL) {
|
|
DeleteObject(OldRgn);
|
|
}
|
|
if (NewRgn != NULL) {
|
|
DeleteObject(NewRgn);
|
|
}
|
|
break;
|
|
|
|
case PAINT_BKIMAGE:
|
|
if (Control->BkImage != 0) {
|
|
ASSERT (Rc.right > Rc.left && Rc.bottom > Rc.top);
|
|
if (Control->Border.Left.Value > 0) {Rc.left += GetControlBorderLeft (This); }
|
|
if (Control->Border.Top.Value > 0) {Rc.top += GetControlBorderTop (This); }
|
|
if (Control->Border.Right.Value > 0) {Rc.right -= GetControlBorderRight (This); }
|
|
if (Control->Border.Bottom.Value > 0) {Rc.bottom -= GetControlBorderBottom (This);}
|
|
|
|
if (IS_UI_LENGTH_VALUE_ASSIGNED(This->BkImageSize.Width)) {
|
|
Size.cx = UiLengthToPixel (&This->BkImageSize.Width , Rc.right - Rc.left, GetControlFontSize (This));
|
|
|
|
if (IS_UI_LENGTH_VALUE_ASSIGNED(This->BkImageSize.Height)) {
|
|
Size.cy = UiLengthToPixel (&This->BkImageSize.Height , Rc.bottom - Rc.top, GetControlFontSize (This));
|
|
} else {
|
|
Size.cy = ((Rc.bottom - Rc.top) * Size.cx) / (Rc.right - Rc.left);
|
|
}
|
|
} else {
|
|
if (IS_UI_LENGTH_VALUE_ASSIGNED(This->BkImageSize.Height)) {
|
|
Size.cy = UiLengthToPixel (&This->BkImageSize.Height , Rc.bottom - Rc.top, GetControlFontSize (This));
|
|
Size.cx = ((Rc.right - Rc.left) * Size.cy) / (Rc.bottom - Rc.top);
|
|
} else {
|
|
Size.cy = (Rc.bottom - Rc.top);
|
|
Size.cx = (Rc.right - Rc.left);
|
|
}
|
|
}
|
|
|
|
Rc.right = Rc.left + Size.cx;
|
|
Rc.bottom = Rc.top + Size.cy;
|
|
UiShowBitmap (
|
|
Control->Wnd,
|
|
Manager->PaintDC,
|
|
&Rc,
|
|
&Control->Scale9Grid,
|
|
Control->BkImageBuf.Bitmap != NULL ? &Control->BkImageBuf : GetImageByString (Control->BkImage),
|
|
GetControlBkImageStyle (Control),
|
|
&Control->HsvDiff
|
|
);
|
|
}
|
|
break;
|
|
|
|
case PAINT_BKCOLOR:
|
|
if ((CONTROL_CLASS_GET_STATE(Control) & UISTATE_FOCUSED) != 0 && Control->FocusBkColor != 0) {
|
|
Color = Control->FocusBkColor;
|
|
} else {
|
|
Color = Control->BkColor;
|
|
}
|
|
|
|
if (Color != 0) {
|
|
if (Control->Border.Left.Value > 0) {Rc.left += GetControlBorderLeft (This); }
|
|
if (Control->Border.Top.Value > 0) {Rc.top += GetControlBorderTop (This); }
|
|
if (Control->Border.Right.Value > 0) {Rc.right -= GetControlBorderRight (This); }
|
|
if (Control->Border.Bottom.Value > 0) {Rc.bottom -= GetControlBorderBottom (This);}
|
|
|
|
if (Color >= 0xFF000000) {
|
|
UiFastFillRect (Hdc, &Rc, Color);
|
|
} else {
|
|
HDC hdcMem;
|
|
HBITMAP hbmp, hbmpOrg, hbmpDel;
|
|
RECT rc;
|
|
|
|
GetClientRect (Control->Wnd, &rc);
|
|
rc.right -= (GetControlBorderWidth (Control));
|
|
rc.bottom -= (GetControlBorderHeight (Control));
|
|
/* redirect painting to offscreen dc*/
|
|
hdcMem = CreateCompatibleDC(Hdc);
|
|
if (hdcMem != NULL) {
|
|
mDummyBitmap = CreateCompatibleBitmap(hdcMem, rc.right, rc.bottom);
|
|
hbmp = mDummyBitmap;
|
|
hbmpOrg = SelectObject(hdcMem, hbmp);
|
|
|
|
UiFastFillRect (hdcMem, &rc, Color);
|
|
|
|
/* alpha blend blit offscreen map with physical screen*/
|
|
BitBlt(Hdc, Rc.left, Rc.top, rc.right - rc.left, rc.bottom - rc.top, hdcMem, 0, 0, MWROP_SRC_OVER); /* FIXME specify constant alpha somewhere!*/
|
|
hbmpDel = SelectObject(hdcMem, hbmpOrg);
|
|
if (hbmpDel != NULL) {
|
|
DeleteObject(hbmpDel);
|
|
}
|
|
DeleteDC(hdcMem);
|
|
}
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PAINT_STATUSIMAGE:
|
|
break;
|
|
|
|
case PAINT_TEXT:
|
|
break;
|
|
|
|
case PAINT_BORDER:
|
|
if (0) {
|
|
Color = Control->BorderColor;
|
|
if (CONTROL_CLASS_GET_STATE(Control) & UISTATE_FOCUSED) {
|
|
Color = 0xFFFF0000;
|
|
}
|
|
if (Color != 0) {
|
|
SelectObject (Hdc, GetStockObject (PS_NULL));
|
|
SelectObject (Hdc, GetStockObject (DC_PEN));
|
|
SetDCPenColor (Hdc, Color);
|
|
Rectangle (Hdc, Rc.left, Rc.top, Rc.right, Rc.bottom);
|
|
}
|
|
if (CONTROL_CLASS_GET_STATE(Control) & UISTATE_FOCUSED) {
|
|
Rectangle (Hdc, Rc.left + 1, Rc.top + 1, Rc.right - 1, Rc.bottom - 1);
|
|
}
|
|
}
|
|
Color = Control->BorderColor;
|
|
if (GetControlBorderLeft (Control) > 0) {
|
|
CopyRect (&TmpRc, &Rc);
|
|
TmpRc.right = TmpRc.left + GetControlBorderLeft (Control);
|
|
UiFastFillRect (Hdc, &TmpRc, Color);
|
|
}
|
|
if (GetControlBorderRight (Control) > 0) {
|
|
CopyRect (&TmpRc, &Rc);
|
|
TmpRc.left = TmpRc.right - GetControlBorderRight (Control);
|
|
UiFastFillRect (Hdc, &TmpRc, Color);
|
|
}
|
|
if (GetControlBorderTop (Control) > 0) {
|
|
CopyRect (&TmpRc, &Rc);
|
|
TmpRc.bottom = TmpRc.top + GetControlBorderTop (Control);
|
|
UiFastFillRect (Hdc, &TmpRc, Color);
|
|
}
|
|
if (GetControlBorderBottom (Control) > 0) {
|
|
CopyRect (&TmpRc, &Rc);
|
|
TmpRc.top = TmpRc.bottom - GetControlBorderBottom (Control);
|
|
UiFastFillRect (Hdc, &TmpRc, Color);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT (FALSE);
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
UI_STATE
|
|
EFIAPI
|
|
UiControlGetState (
|
|
UI_CONTROL *Control
|
|
)
|
|
{
|
|
return Control->StateFlags;
|
|
}
|
|
|
|
VOID
|
|
EFIAPI
|
|
UiControlSetState (
|
|
UI_CONTROL *Control,
|
|
UI_STATE SetState,
|
|
UI_STATE ClearState
|
|
)
|
|
{
|
|
UI_STATE OldState;
|
|
|
|
if (Control->OnSetState) {
|
|
Control->OnSetState (Control, SetState, ClearState);
|
|
}
|
|
OldState = Control->StateFlags;
|
|
|
|
Control->StateFlags |= SetState;
|
|
Control->StateFlags &= ~(ClearState);
|
|
|
|
if ((Control->StateFlags != OldState) &&
|
|
!(ClearState & UISTATE_INVALIDATED) &&
|
|
!(Control->StateFlags & UISTATE_INVALIDATED)) {
|
|
CONTROL_CLASS_INVALIDATE (Control);
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
UiControlSetAttribute (
|
|
UI_CONTROL *Control,
|
|
CHAR16 *Name,
|
|
CHAR16 *Value
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CHAR16 *PtrValue;
|
|
UI_CONTROL *ScrollBar;
|
|
UI_CONTROL *This;
|
|
|
|
This = (UI_CONTROL *) Control;
|
|
PtrValue = Value;
|
|
|
|
if (StrCmp (Name, L"name") == 0) {
|
|
ASSERT (This->Name);
|
|
if (StrCmp(This->Name, L"") != 0) {
|
|
StringMapRemove (&This->Manager->NameList, Value);
|
|
FreePool (This->Name);
|
|
}
|
|
This->Name = AllocateCopyPool (StrSize(Value), Value);
|
|
StringMapAdd (&This->Manager->NameList, Value, This);
|
|
} else if (StrCmp (Name, L"width") == 0) {
|
|
if (isalpha (Value[0]) || StrCmp (Value, L"-1") == 0 || StrCmp (Value, L"-2") == 0) {
|
|
if (StrCmp (Value, L"match_parent") == 0 || StrCmp (Value, L"-1") == 0) {
|
|
This->Width.Type = UI_LENGTH_TYPE_MATCH_PARENT;
|
|
This->Width.Value = 0;
|
|
} else if (StrCmp (Value, L"wrap_content") == 0 || StrCmp (Value, L"-2") == 0) {
|
|
This->Width.Type = UI_LENGTH_TYPE_WRAP_CONTENT;
|
|
This->Width.Value = 0;
|
|
} else {
|
|
DEBUG ((EFI_D_ERROR, "width can only use match_parent, wrap_content or const value"));
|
|
ASSERT (FALSE);
|
|
}
|
|
} else {
|
|
StrToUiLength (&PtrValue, &This->Width);
|
|
}
|
|
UiNeedUpdatePos (Control);
|
|
} else if (StrCmp (Name, L"height") == 0) {
|
|
if (isalpha (Value[0]) || StrCmp (Value, L"-1") == 0 || StrCmp (Value, L"-2") == 0) {
|
|
if (StrCmp (Value, L"match_parent") == 0 || StrCmp (Value, L"-1") == 0) {
|
|
This->Height.Type = UI_LENGTH_TYPE_MATCH_PARENT;
|
|
This->Height.Value = 0;
|
|
} else if (StrCmp (Value, L"wrap_content") == 0 || StrCmp (Value, L"-2") == 0) {
|
|
This->Height.Type = UI_LENGTH_TYPE_WRAP_CONTENT;
|
|
This->Height.Value = 0;
|
|
} else {
|
|
DEBUG ((EFI_D_ERROR, "width can only use match_parent, wrap_content or const value"));
|
|
ASSERT (FALSE);
|
|
}
|
|
} else {
|
|
StrToUiLength (&PtrValue, &This->Height);
|
|
}
|
|
UiNeedUpdatePos (Control);
|
|
} else if (StrCmp (Name, L"background-image") == 0) {
|
|
if (This->BkImage != NULL) {
|
|
FreePool (This->BkImage);
|
|
}
|
|
if (This->BkImageBuf.Bitmap != NULL) {
|
|
FreePool (This->BkImageBuf.Bitmap);
|
|
}
|
|
|
|
This->BkImage = AllocateCopyPool (StrSize(Value), Value);
|
|
if (This->BkImage == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "Allocate This->BkImage fail."));
|
|
return TRUE;
|
|
}
|
|
|
|
if (Value[0] != '@') {
|
|
EFI_IMAGE_INPUT *Image;
|
|
|
|
Image = GetImageByString (This->BkImage);
|
|
if (Image != NULL && Image->Width != 0 && Image->Height != 0) {
|
|
CopyMem (&This->BkImageBuf, Image, sizeof(EFI_IMAGE_INPUT));
|
|
This->BkImageBuf.Bitmap = AllocateCopyPool (Image->Width * Image->Height * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL), Image->Bitmap);
|
|
}
|
|
}
|
|
} else if (StrCmp (Name, L"background-size") == 0) {
|
|
if (isalpha (PtrValue[0])) {
|
|
if (StrnCmp (PtrValue, L"auto", 4) == 0) {
|
|
This->BkImageSize.Width.Value = 0;
|
|
This->BkImageSize.Width.Type = UI_LENGTH_TYPE_UNDEFINED;
|
|
PtrValue += 4;
|
|
} else {
|
|
DEBUG ((EFI_D_ERROR, "background-size can only use auto or const value"));
|
|
ASSERT (FALSE);
|
|
}
|
|
if (*PtrValue == ',') {
|
|
PtrValue++;
|
|
}
|
|
} else {
|
|
StrToUiLength (&PtrValue, &This->BkImageSize.Width);
|
|
}
|
|
|
|
if (*PtrValue == 0 || isalpha (PtrValue[0])) {
|
|
if (*PtrValue == 0 || StrnCmp (PtrValue, L"auto", 4) == 0) {
|
|
This->BkImageSize.Height.Value = 0;
|
|
This->BkImageSize.Height.Type = UI_LENGTH_TYPE_UNDEFINED;
|
|
} else {
|
|
DEBUG ((EFI_D_ERROR, "background-size can only use auto or const value"));
|
|
ASSERT (FALSE);
|
|
}
|
|
} else {
|
|
StrToUiLength (&PtrValue, &This->BkImageSize.Height);
|
|
}
|
|
} else if (StrCmp (Name, L"background-color") == 0) {
|
|
This->BkColor = GetColorValue (Value);
|
|
} else if (StrCmp (Name, L"focusbkcolor") == 0) {
|
|
This->FocusBkColor = GetColorValue (Value);
|
|
} else if (StrCmp (Name, L"border-color") == 0) {
|
|
This->BorderColor = GetColorValue (Value);
|
|
} else if (StrCmp (Name, L"visibility") == 0) {
|
|
if (StrCmp (Value, L"true") == 0) {
|
|
ShowWindow (This->Wnd, SW_SHOW);
|
|
} else {
|
|
ShowWindow (This->Wnd, SW_HIDE);
|
|
}
|
|
UiNeedUpdatePos (Control);
|
|
} else if (StrCmp (Name, L"font-size") == 0) {
|
|
Control->FontSize = (INT32)StrToUInt (Value, 10, &Status);
|
|
} else if (StrCmp (Name, L"textcolor") == 0) {
|
|
Control->TextColor = GetColorValue (Value);
|
|
} else if (StrnCmp (Name, L"padding", 7) == 0) {
|
|
Name += 7;
|
|
if (*Name == 0) {
|
|
StrToUiLength (&PtrValue, &This->Padding.Top);
|
|
StrToUiLength (&PtrValue, &This->Padding.Right);
|
|
StrToUiLength (&PtrValue, &This->Padding.Bottom);
|
|
StrToUiLength (&PtrValue, &This->Padding.Left);
|
|
} else if (StrCmp (Name, L"-top") == 0) {
|
|
StrToUiLength (&PtrValue, &This->Padding.Top);
|
|
} else if (StrCmp (Name, L"-right") == 0) {
|
|
StrToUiLength (&PtrValue, &This->Padding.Right);
|
|
} else if (StrCmp (Name, L"-bottom") == 0) {
|
|
StrToUiLength (&PtrValue, &This->Padding.Bottom);
|
|
} else if (StrCmp (Name, L"-left") == 0) {
|
|
StrToUiLength (&PtrValue, &This->Padding.Left);
|
|
} else {
|
|
ASSERT (FALSE);
|
|
}
|
|
UiNeedUpdatePos (Control);
|
|
} else if (StrnCmp (Name, L"border", 6) == 0) {
|
|
Name += 6;
|
|
if (StrCmp (Name, L"-width") == 0) {
|
|
StrToUiLength (&PtrValue, &This->Border.Top);
|
|
StrToUiLength (&PtrValue, &This->Border.Right);
|
|
StrToUiLength (&PtrValue, &This->Border.Bottom);
|
|
StrToUiLength (&PtrValue, &This->Border.Left);
|
|
} else if (StrCmp (Name, L"-top") == 0) {
|
|
StrToUiLength (&PtrValue, &This->Border.Top);
|
|
} else if (StrCmp (Name, L"-right") == 0) {
|
|
StrToUiLength (&PtrValue, &This->Border.Right);
|
|
} else if (StrCmp (Name, L"-bottom") == 0) {
|
|
StrToUiLength (&PtrValue, &This->Border.Bottom);
|
|
} else if (StrCmp (Name, L"-left") == 0) {
|
|
StrToUiLength (&PtrValue, &This->Border.Left);
|
|
} else {
|
|
ASSERT (FALSE);
|
|
}
|
|
UiNeedUpdatePos (Control);
|
|
} else if (StrnCmp (Name, L"margin", 6) == 0) {
|
|
Name += 6;
|
|
if (*Name == 0) {
|
|
StrToUiLength (&PtrValue, &This->Margin.Top);
|
|
StrToUiLength (&PtrValue, &This->Margin.Right);
|
|
StrToUiLength (&PtrValue, &This->Margin.Bottom);
|
|
StrToUiLength (&PtrValue, &This->Margin.Left);
|
|
} else if (StrCmp (Name, L"-top") == 0) {
|
|
StrToUiLength (&PtrValue, &This->Margin.Top);
|
|
} else if (StrCmp (Name, L"-right") == 0) {
|
|
StrToUiLength (&PtrValue, &This->Margin.Right);
|
|
} else if (StrCmp (Name, L"-bottom") == 0) {
|
|
StrToUiLength (&PtrValue, &This->Margin.Bottom);
|
|
} else if (StrCmp (Name, L"-left") == 0) {
|
|
StrToUiLength (&PtrValue, &This->Margin.Left);
|
|
} else {
|
|
ASSERT (FALSE);
|
|
}
|
|
UiNeedUpdatePos (Control);
|
|
} else if (StrCmp (Name, L"left") == 0) {
|
|
StrToUiLength (&PtrValue, &Control->Left);
|
|
UiNeedUpdatePos (Control);
|
|
} else if (StrCmp (Name, L"right") == 0) {
|
|
StrToUiLength (&PtrValue, &Control->Right);
|
|
UiNeedUpdatePos (Control);
|
|
} else if (StrCmp (Name, L"top") == 0) {
|
|
StrToUiLength (&PtrValue, &Control->Top);
|
|
UiNeedUpdatePos (Control);
|
|
} else if (StrCmp (Name, L"bottom") == 0) {
|
|
StrToUiLength (&PtrValue, &Control->Bottom);
|
|
UiNeedUpdatePos (Control);
|
|
} else if (StrCmp (Name, L"scale9grid") == 0) {
|
|
This->Scale9Grid.left = wcstol (Value, &PtrValue, 10);
|
|
This->Scale9Grid.top = wcstol (PtrValue + 1, &PtrValue, 10);
|
|
This->Scale9Grid.right = wcstol (PtrValue + 1, &PtrValue, 10);
|
|
This->Scale9Grid.bottom = wcstol (PtrValue + 1, &PtrValue, 10);
|
|
} else if (StrCmp (Name, L"float") == 0) {
|
|
if (StrCmp (Value, L"true") == 0) {
|
|
This->Float = TRUE;
|
|
} else {
|
|
This->Float = FALSE;
|
|
}
|
|
UiNeedUpdatePos (Control);
|
|
} else if (StrCmp (Name, L"gradient_vertical") == 0) {
|
|
if (StrCmp (Value, L"true") == 0) {
|
|
This->GradientVertial = TRUE;
|
|
} else {
|
|
This->GradientVertial = FALSE;
|
|
}
|
|
} else if (StrCmp (Name, L"user_data") == 0) {
|
|
if (This->UserData != NULL) {
|
|
FreePool (This->UserData);
|
|
}
|
|
This->UserData = AllocateCopyPool (StrSize (Value), Value);
|
|
} else if (StrCmp (Name, L"background-image-style") == 0) {
|
|
|
|
This->BkImageStyle = 0;
|
|
if (StrStr (Value, L"center") != NULL) {
|
|
This->BkImageStyle &= ~ (DT_STRETCH);
|
|
This->BkImageStyle |= DT_CENTER | DT_VCENTER;
|
|
}
|
|
if (StrStr (Value, L"stretch") != NULL) {
|
|
SetRectEmpty (&Control->Scale9Grid);
|
|
Control->BkImageStyle &= ~ (DT_CENTER | DT_VCENTER);
|
|
Control->BkImageStyle |= DT_STRETCH;
|
|
}
|
|
if (StrStr (Value, L"gray") != NULL) {
|
|
Control->BkImageStyle |= DT_GRAY;
|
|
}
|
|
if (StrStr (Value, L"light") != NULL) {
|
|
Control->BkImageStyle |= DT_LIGHT;
|
|
}
|
|
if (StrCmp (Value, L"") == 0) {
|
|
This->BkImageStyle = 0;
|
|
}
|
|
} else if (StrCmp (Name, L"filter") == 0) {
|
|
if (StrCmp (Value, L"gray") == 0) {
|
|
Control->Filter |= DT_GRAY;
|
|
} else if (StrCmp (Value, L"none") == 0) {
|
|
Control->Filter = 0;
|
|
} else {
|
|
DEBUG ((EFI_D_ERROR, "filter can only use gray or none"));
|
|
ASSERT (FALSE);
|
|
}
|
|
} else if (StrCmp (Name, L"child-padding") == 0) {
|
|
This->ChildPadding = (UINT32)StrToUInt (Value, 10, &Status);
|
|
} else if (StrCmp (Name, L"vscrollbarpos") == 0) {
|
|
if (This->VScrollBar != NULL) {
|
|
SCROLLBAR_CLASS(This->VScrollBar)->SetScrollPos (This->VScrollBar, (INT32)StrToUInt (Value, 10, &Status));
|
|
}
|
|
} else if (StrCmp (Name, L"vscrollbar") == 0) {
|
|
|
|
if (StrCmp (Value, L"true") == 0 &&
|
|
This->VScrollBar == NULL) {
|
|
ScrollBar = CreateControl (L"SCROLLBAR", This);
|
|
ScrollBar->Class->SetAttribute (ScrollBar, L"hor", L"false");
|
|
This->VScrollBar = (UI_SCROLLBAR *) ScrollBar;
|
|
((UI_SCROLLBAR *)ScrollBar)->Owner = This;
|
|
}
|
|
UiNeedUpdatePos (Control);
|
|
} else if (StrCmp (Name, L"hscrollbar") == 0) {
|
|
|
|
if ((StrCmp (Value, L"true") == 0) && (This->HScrollBar == NULL)) {
|
|
|
|
ScrollBar = CreateControl (L"SCROLLBAR", This);
|
|
ScrollBar->Class->SetAttribute (ScrollBar, L"hor", L"true");
|
|
This->HScrollBar = (UI_SCROLLBAR *) ScrollBar;
|
|
}
|
|
UiNeedUpdatePos (Control);
|
|
} else if (StrCmp (Name, L"hsvadjust") == 0) {
|
|
This->HsvDiff.HueDiff = (INT16) wcstol (Value, &PtrValue, 10);
|
|
This->HsvDiff.SaturationDiff = (INT8) wcstol (PtrValue + 1, &PtrValue, 10);
|
|
This->HsvDiff.ValueDiff = (INT8) wcstol (PtrValue + 1, &PtrValue, 10);
|
|
} else if (StrCmp (Name, L"min-height") == 0) {
|
|
This->MinSize.cy = wcstol (Value, &PtrValue, 10);
|
|
UiNeedUpdatePos (Control);
|
|
} else if (StrCmp (Name, L"max-width") == 0) {
|
|
This->MaxSize.cx = wcstol (Value, &PtrValue, 10);
|
|
UiNeedUpdatePos (Control);
|
|
} else if (StrCmp (Name, L"taborder") == 0) {
|
|
This->TabOrder = wcstol (Value, &PtrValue, 10);
|
|
} else if (StrCmp (Name, L"tabstop") == 0) {
|
|
if (StrCmp (Value, L"true") == 0) {
|
|
SetWindowLongPtr (This->Wnd, GWL_STYLE, GetWindowLongPtr (This->Wnd, GWL_STYLE) | WS_TABSTOP);
|
|
} else {
|
|
SetWindowLongPtr (This->Wnd, GWL_STYLE, GetWindowLongPtr (This->Wnd, GWL_STYLE) & (~WS_TABSTOP));
|
|
}
|
|
} else if (StrCmp (Name, L"position") == 0) {
|
|
if (StrCmp (Value, L"relative") == 0) {
|
|
This->Position = UI_POSITION_RELATIVE;
|
|
} else if (StrCmp (Value, L"absolute") == 0) {
|
|
This->Position = UI_POSITION_ABSOLUTE;
|
|
}
|
|
} else if (StrCmp (Name, L"z-index") == 0) {
|
|
if (isalpha (Value[0])) {
|
|
if (StrCmp (Value, L"auto") == 0) {
|
|
This->ZIndex.Type = UI_Z_INDEX_TYPE_AUTO;
|
|
} else {
|
|
DEBUG ((EFI_D_ERROR, "z-index can only use auto or const value"));
|
|
ASSERT (FALSE);
|
|
}
|
|
} else {
|
|
This->ZIndex.Value = wcstol (Value, &PtrValue, 10);
|
|
This->ZIndex.Type = UI_Z_INDEX_TYPE_NUMBER;
|
|
}
|
|
} else if (StrCmp (Name, L"box-sizing") == 0) {
|
|
if (StrCmp (Value, L"border-box") == 0) {
|
|
This->BoxSizing = UI_BOX_SIZING_BORDER_BOX;
|
|
} else if (StrCmp (Value, L"content-box") == 0) {
|
|
This->BoxSizing = UI_BOX_SIZING_CONTENT_BOX;
|
|
} else {
|
|
ASSERT (FALSE);
|
|
}
|
|
} else {
|
|
DEBUG ((EFI_D_ERROR, "Unsupported attribute name/name: %s %s", Name, Value));
|
|
ASSERT (0);
|
|
return FALSE;
|
|
}
|
|
|
|
CONTROL_CLASS_INVALIDATE (This);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
EFIAPI
|
|
UiControlAddChild (
|
|
UI_CONTROL *Control,
|
|
UI_CONTROL *Child
|
|
)
|
|
{
|
|
UI_CONTROL *This;
|
|
|
|
ASSERT (Control != NULL);
|
|
|
|
This = (UI_CONTROL *) Control;
|
|
This->ItemCount++;
|
|
This->Items = ReallocatePool (
|
|
sizeof (UI_CONTROL *) * (This->ItemCount - 1),
|
|
sizeof (UI_CONTROL *) * This->ItemCount,
|
|
This->Items
|
|
);
|
|
if (This->Items == NULL) {
|
|
return FALSE;
|
|
}
|
|
This->Items[This->ItemCount - 1] = Child;
|
|
|
|
UiNeedUpdatePos (Child);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
EFIAPI
|
|
UiControlRemoveChild (
|
|
UI_CONTROL *Control,
|
|
UI_CONTROL *Child
|
|
)
|
|
{
|
|
|
|
UINTN Index;
|
|
UINTN Index2;
|
|
UI_CONTROL *This;
|
|
|
|
ASSERT (Control != NULL);
|
|
This = (UI_CONTROL *) Control;
|
|
|
|
for (Index = 0; Index < This->ItemCount; Index++) {
|
|
if (This->Items[Index] == Child) {
|
|
for (Index2 = Index; Index < This->ItemCount - 1; Index2++) {
|
|
This->Items[Index2] = This->Items[Index2 + 1];
|
|
}
|
|
This->ItemCount--;
|
|
DestroyWindow (Child->Wnd);
|
|
break;
|
|
}
|
|
}
|
|
|
|
UiNeedUpdatePos (This);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
EFIAPI
|
|
UiControlRemoveAllChild (
|
|
UI_CONTROL *Control
|
|
)
|
|
{
|
|
UINTN Index;
|
|
|
|
if (Control->ItemCount == 0) {
|
|
return TRUE;
|
|
}
|
|
|
|
for (Index = 0; Index < Control->ItemCount; Index++) {
|
|
DestroyWindow (Control->Items[Index]->Wnd);
|
|
}
|
|
|
|
FreePool (Control->Items);
|
|
Control->Items = NULL;
|
|
Control->ItemCount = 0;
|
|
|
|
UiNeedUpdatePos (Control);
|
|
return TRUE;
|
|
}
|
|
|
|
UI_CONTROL *
|
|
EFIAPI
|
|
UiControlFindChildByName (
|
|
UI_CONTROL *Control,
|
|
CHAR16 *Name,
|
|
UI_SEARCH_TYPE SearchType
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UI_CONTROL *This;
|
|
UI_CONTROL *Child;
|
|
|
|
This = (UI_CONTROL *) Control;
|
|
|
|
for (Index = 0; Index < This->ItemCount; Index++) {
|
|
if (StrCmp (This->Items[Index]->Name, Name) == 0) {
|
|
return This->Items[Index];
|
|
}
|
|
if (SearchType == UI_SEARCH_TYPE_ONLY_CHILD) {
|
|
continue;
|
|
}
|
|
|
|
Child = CONTROL_CLASS (This->Items[Index])->FindChildByName (This->Items[Index], Name, SearchType);
|
|
if (Child != NULL) {
|
|
return Child;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
BOOLEAN
|
|
UiControlActivate (
|
|
UI_CONTROL *This
|
|
)
|
|
{
|
|
|
|
UINT32 Style;
|
|
|
|
Style = (UINT32) GetWindowLongPtr (This->Wnd, GWL_STYLE);
|
|
if ((Style & WS_DISABLED) != 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ((Style & WS_VISIBLE) == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
SIZE
|
|
UiControlEstimateSize (
|
|
UI_CONTROL *Control,
|
|
SIZE AvailableSize
|
|
)
|
|
{
|
|
SIZE Size;
|
|
SIZE ItemSize;
|
|
SIZE ItemAvailableSize;
|
|
UINTN Index;
|
|
UI_CONTROL *Item;
|
|
UINTN Count;
|
|
INTN MaxWidth;
|
|
INTN MaxHeight;
|
|
|
|
if (((Control->Width.Type != UI_LENGTH_TYPE_WRAP_CONTENT) && (Control->Width.Type != UI_LENGTH_TYPE_MATCH_PARENT)) &&
|
|
((Control->Height.Type != UI_LENGTH_TYPE_WRAP_CONTENT) && (Control->Height.Type != UI_LENGTH_TYPE_MATCH_PARENT))) {
|
|
return CalculateControlDisplaySize (Control, AvailableSize);
|
|
}
|
|
|
|
Count = Control->ItemCount;
|
|
|
|
ItemAvailableSize.cx = AvailableSize.cx - GetControlPaddingWidth (Control) - GetControlBorderWidth (Control);
|
|
ItemAvailableSize.cy = AvailableSize.cy - GetControlPaddingHeight (Control) - GetControlBorderHeight (Control);
|
|
|
|
MaxWidth = 0;
|
|
MaxHeight = 0;
|
|
for (Index = 0; Index < Count; ++Index) {
|
|
|
|
Item = Control->Items[Index];
|
|
if ((GetWindowLongPtr (Item->Wnd, GWL_STYLE) & WS_VISIBLE) == 0) {
|
|
continue;
|
|
}
|
|
if (Item->Float) {
|
|
continue;
|
|
}
|
|
|
|
ItemSize = CONTROL_CLASS (Item)->EstimateSize (Item, ItemAvailableSize);
|
|
|
|
MaxWidth = MAX (MaxWidth, ItemSize.cx);
|
|
MaxHeight = MAX (MaxHeight, ItemSize.cy);
|
|
}
|
|
if (MaxWidth > 0) {
|
|
MaxWidth += (GetControlPaddingWidth (Control) + GetControlBorderWidth (Control));
|
|
}
|
|
if (MaxHeight > 0) {
|
|
MaxHeight += (GetControlPaddingHeight (Control) + GetControlBorderHeight (Control));
|
|
}
|
|
|
|
MaxWidth = MAX (MaxWidth, Control->MinSize.cx);
|
|
MaxHeight = MAX (MaxHeight, Control->MinSize.cy);
|
|
|
|
Size = CalculateControlDisplaySize (Control, AvailableSize);
|
|
if (Size.cx == WRAP_CONTENT) {
|
|
Size.cx = (GDICOORD)MaxWidth;
|
|
}
|
|
|
|
if (Size.cy == WRAP_CONTENT) {
|
|
Size.cy = (GDICOORD)MaxHeight;
|
|
}
|
|
|
|
return Size;
|
|
}
|
|
|
|
VOID
|
|
UiControlInvalidate (
|
|
UI_CONTROL *Control
|
|
)
|
|
{
|
|
RECT Rc;
|
|
RECT InvalidateRc;
|
|
RECT TmpRc;
|
|
RECT ParentRc;
|
|
HWND Parent;
|
|
|
|
if (CONTROL_CLASS_GET_STATE(Control) & UISTATE_INVALIDATED) {
|
|
//
|
|
// check update region already in invalidate region
|
|
//
|
|
if (GetUpdateRect (Control->Manager->MainWnd, &InvalidateRc, FALSE)) {
|
|
GetWindowRect (Control->Wnd, &Rc);
|
|
MapWindowPoints(NULL, Control->Manager->MainWnd, (POINT *)&Rc, 2);
|
|
if ((InvalidateRc.left <= Rc.left) && (InvalidateRc.right >= Rc.right) &&
|
|
(InvalidateRc.top <= Rc.top) && (InvalidateRc.bottom >= Rc.bottom)){
|
|
return ;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
CONTROL_CLASS_SET_STATE(Control, UISTATE_INVALIDATED, 0);
|
|
GetWindowRect (Control->Wnd, &Rc);
|
|
|
|
Parent = Control->Wnd;
|
|
CopyRect (&InvalidateRc, &Rc);
|
|
while ((Parent = Parent->parent) != NULL) {
|
|
CopyRect (&TmpRc, &InvalidateRc);
|
|
GetWindowRect (Parent, &ParentRc);
|
|
|
|
if (!IntersectRect (&InvalidateRc, &TmpRc, &ParentRc)) {
|
|
return ;
|
|
}
|
|
|
|
if (Parent == Control->Manager->Root) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
MapWindowPoints(NULL, Control->Manager->MainWnd, (POINT *)&InvalidateRc, 2);
|
|
InvalidateRect (Control->Manager->MainWnd, &InvalidateRc, FALSE);
|
|
}
|
|
|
|
|
|
UI_CONTROL*
|
|
UiControlFindNextFocus (
|
|
UI_CONTROL *Control,
|
|
UI_CONTROL *Focused,
|
|
UINTN Direction
|
|
)
|
|
{
|
|
UI_CONTROL *Root;
|
|
UINTN Index;
|
|
UI_CONTROL *Item;
|
|
RECT ItemRc;
|
|
RECT FocusRc;
|
|
UI_CONTROL *NextFocus;
|
|
UINT32 Distance;
|
|
UINT32 BestDistance;
|
|
|
|
|
|
ASSERT (Direction == VK_LEFT || Direction == VK_RIGHT || Direction == VK_UP || Direction == VK_DOWN);
|
|
|
|
if (!(GetWindowLongPtr (Control->Wnd, GWL_STYLE) & WS_CHILD)) {
|
|
return NULL;
|
|
}
|
|
|
|
Root = GetUiControl (GetParent (Control->Wnd));
|
|
if (Root == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
GetWindowRect (Focused->Wnd, &FocusRc);
|
|
|
|
//
|
|
// search next focus
|
|
//
|
|
NextFocus = NULL;
|
|
BestDistance = (UINT32)-1;
|
|
for (Index = 0; Index < Root->ItemCount; Index++) {
|
|
Item = Root->Items[Index];
|
|
if (Item == Focused) {
|
|
continue;
|
|
}
|
|
if (!IsWindowVisible (Item->Wnd)) {
|
|
continue;
|
|
}
|
|
if (GetWindowLongPtr (Item->Wnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE) {
|
|
continue;
|
|
}
|
|
GetWindowRect (Item->Wnd, &ItemRc);
|
|
|
|
if (Direction == VK_LEFT) {
|
|
if (ItemRc.left >= FocusRc.left || ((ItemRc.bottom <= FocusRc.top || ItemRc.top >= FocusRc.bottom) && ItemRc.right >= FocusRc.left)) {
|
|
continue;
|
|
}
|
|
} else if (Direction == VK_UP) {
|
|
if (ItemRc.top >= FocusRc.top || ((ItemRc.right <= FocusRc.left || ItemRc.left >= FocusRc.right) && ItemRc.bottom >= FocusRc.top)) {
|
|
continue;
|
|
}
|
|
} else if (Direction == VK_RIGHT) {
|
|
if (ItemRc.left <= FocusRc.left || ((ItemRc.bottom <= FocusRc.top || ItemRc.top >= FocusRc.bottom) && ItemRc.left <= FocusRc.right)) {
|
|
continue;
|
|
}
|
|
} else if (Direction == VK_DOWN) {
|
|
if (ItemRc.top <= FocusRc.top || ((ItemRc.right <= FocusRc.left || ItemRc.left >= FocusRc.right) && ItemRc.top <= FocusRc.bottom)) {
|
|
continue;
|
|
}
|
|
}
|
|
Distance = (FocusRc.left - ItemRc.left) * (FocusRc.left - ItemRc.left) +
|
|
(FocusRc.top - ItemRc.top) * (FocusRc.top - ItemRc.top);
|
|
if (Distance < BestDistance) {
|
|
NextFocus = Item;
|
|
BestDistance = Distance;
|
|
}
|
|
}
|
|
|
|
return NextFocus;
|
|
|
|
}
|
|
|
|
UI_CONTROL*
|
|
UiControlGetParent (
|
|
UI_CONTROL *Control
|
|
)
|
|
{
|
|
HWND Hwnd;
|
|
UI_CONTROL *Parent;
|
|
|
|
Hwnd = GetParent (Control->Wnd);
|
|
ASSERT (Hwnd != NULL);
|
|
|
|
Parent = GetUiControl (Hwnd);
|
|
ASSERT (Parent != NULL);
|
|
|
|
return Parent;
|
|
}
|
|
|
|
BOOLEAN
|
|
UiControlShouldDelayChildPressedState (
|
|
UI_CONTROL *Control
|
|
)
|
|
{
|
|
if (Control->VScrollBar != NULL || Control->HScrollBar != NULL) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
UiControlIsInScrollControl (
|
|
UI_CONTROL *This
|
|
)
|
|
{
|
|
UI_CONTROL *Parent;
|
|
|
|
Parent = CONTROL_CLASS (This)->GetParent (This);
|
|
|
|
while (Parent != NULL) {
|
|
if (CONTROL_CLASS (Parent)->ShouldDelayChildPressedState (Parent)) {
|
|
return TRUE;
|
|
}
|
|
Parent = CONTROL_CLASS (Parent)->GetParent (Parent);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
LRESULT
|
|
UiControlProc (
|
|
HWND Wnd,
|
|
UINT32 Msg,
|
|
WPARAM WParam,
|
|
LPARAM LParam
|
|
)
|
|
{
|
|
UI_CONTROL *This;
|
|
UI_CONTROL *ParentControl;
|
|
UI_CONTROL *NextFocus;
|
|
HWND ParentWnd;
|
|
|
|
RECT Rc;
|
|
UI_MANAGER *Manager;
|
|
|
|
POINT Point;
|
|
POINT LastPoint;
|
|
INT32 DeltaX;
|
|
INT32 DeltaY;
|
|
INT32 ScrollPos;
|
|
|
|
This = NULL;
|
|
Manager = NULL;
|
|
|
|
if (Msg != WM_CREATE && Msg != WM_NCCALCSIZE) {
|
|
This = (UI_CONTROL *) GetWindowLongPtr (Wnd, 0);
|
|
if (This == NULL) {
|
|
ASSERT (FALSE);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (This != NULL) {
|
|
Manager = This->Manager;
|
|
}
|
|
|
|
switch (Msg) {
|
|
|
|
case WM_CREATE:
|
|
if (This == NULL) {
|
|
This = (UI_CONTROL *) AllocateZeroPool (sizeof (UI_CONTROL));
|
|
} else {
|
|
ASSERT (FALSE);
|
|
}
|
|
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:
|
|
if (LParam == 0) {
|
|
Manager = NULL;
|
|
} else {
|
|
Manager = (UI_MANAGER *)(((CREATESTRUCT *)(LParam))->lpCreateParams);
|
|
}
|
|
UiControlOnUiCreate (This, Wnd, Manager);
|
|
break;
|
|
|
|
case UI_NOTIFY_ACTIVATE:
|
|
return UiControlActivate (This);
|
|
|
|
case WM_DESTROY:
|
|
UiControlOnDestroy (This);
|
|
break;
|
|
|
|
case WM_WINDOWPOSCHANGED:
|
|
break;
|
|
|
|
case WM_PAINT:
|
|
// ValidateRect (Wnd, NULL);
|
|
break;
|
|
|
|
case WM_NCHITTEST:
|
|
return HTTRANSPARENT;
|
|
|
|
case UI_NOTIFY_PAINT:
|
|
UiControlOnUiPaint (This, WParam, LParam);
|
|
break;
|
|
|
|
case WM_KEYDOWN:
|
|
if (WParam == VK_RETURN) {
|
|
if (!IsWindowVisible (Wnd)) {
|
|
break;
|
|
}
|
|
|
|
if (!(This->StyleFlags & UISTYLE_CLICKABLE)) {
|
|
break;
|
|
}
|
|
|
|
CONTROL_CLASS_SET_STATE (This, UISTATE_PRESSED, 0);
|
|
}
|
|
|
|
//
|
|
// we didn't send WM_KEYUP, so continue process WM_KEYUP
|
|
//
|
|
//
|
|
case WM_KEYUP:
|
|
if (WParam == VK_LEFT || WParam == VK_RIGHT
|
|
|| WParam == VK_UP || WParam == VK_DOWN) {
|
|
|
|
NextFocus = This->Class->FindNextFocus (This, This, WParam);
|
|
if (NextFocus != NULL) {
|
|
SetFocus (NextFocus->Wnd);
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
if (WParam == VK_RETURN) {
|
|
if (!IsWindowVisible (Wnd)) {
|
|
break;
|
|
}
|
|
|
|
if (!(This->StyleFlags & UISTYLE_CLICKABLE)) {
|
|
break;
|
|
}
|
|
|
|
if (!(CONTROL_CLASS_GET_STATE (This) & UISTATE_PRESSED)) {
|
|
break;
|
|
}
|
|
|
|
CONTROL_CLASS_SET_STATE(This, 0, UISTATE_PRESSED);
|
|
SendMessage (Wnd, UI_NOTIFY_ACTIVATE, 0, 0);
|
|
}
|
|
break;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
if ((This->HScrollBar != NULL) || (This->VScrollBar != NULL)) {
|
|
//
|
|
// orignal Container
|
|
//
|
|
This->IsBeginDraged = TRUE;
|
|
POINTSTOPOINT(Point, LParam);
|
|
ClientToScreen (Wnd, &Point);
|
|
This->LastMotionX = Point.x;
|
|
This->LastMotionY = Point.y;
|
|
SetCapture (Wnd);
|
|
if ((GetWindowLongPtr (Wnd, GWL_STYLE) & WS_DISABLED) == 0) {
|
|
CONTROL_CLASS_SET_STATE(This, UISTATE_PRESSED | UISTATE_CAPTURED, 0);
|
|
}
|
|
|
|
} else {
|
|
POINTSTOPOINT(Point, LParam);
|
|
ClientToScreen (Wnd, &Point);
|
|
if ((GetWindowLongPtr (Wnd, GWL_STYLE) & WS_DISABLED) == 0) {
|
|
SetCapture (Wnd);
|
|
CONTROL_CLASS_SET_STATE (This, UISTATE_PRESSED | UISTATE_CAPTURED, 0);
|
|
}
|
|
|
|
if (UiControlIsInScrollControl (This)) {
|
|
CONTROL_CLASS_SET_STATE(This, UISTATE_PREPRESSED, 0);
|
|
This->LastX = Point.x;
|
|
This->LastY = Point.y;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_LBUTTONDBLCLK:
|
|
return SendMessage (Wnd, WM_LBUTTONDOWN, WParam, LParam);
|
|
|
|
case WM_NCMOUSEMOVE:
|
|
|
|
if (This->IsBeginDraged) {
|
|
POINTSTOPOINT(Point, LParam);
|
|
DeltaX = This->LastMotionX - Point.x;
|
|
DeltaY = This->LastMotionY - Point.y;
|
|
|
|
if (abs(DeltaY) < This->TouchSlop) {
|
|
break;
|
|
}
|
|
|
|
This->LastMotionX = Point.x;
|
|
This->LastMotionY = Point.y;
|
|
//
|
|
// now only process y
|
|
//
|
|
|
|
|
|
if (DeltaY < 0) {
|
|
if (This->ScrollPos.y <= 0) {
|
|
break;
|
|
}
|
|
} else if (DeltaY > 0) {
|
|
// DeltaY =
|
|
}
|
|
|
|
if (This->VScrollBar != NULL) {
|
|
ScrollPos = (This->ScrollPos.y + DeltaY) / This->VScrollBar->LineSize;
|
|
SCROLLBAR_CLASS(This->VScrollBar)->SetScrollPos (This->VScrollBar, ScrollPos);
|
|
This->Dragged = TRUE;
|
|
//SCROLLBAR_CLASS(This->VScrollBar)->SetScrollPos (This->VScrollBar, This->ScrollPos.y + DeltaY);
|
|
}
|
|
} else if (CONTROL_CLASS_GET_STATE (This) & UISTATE_PREPRESSED) {
|
|
POINTSTOPOINT(Point, LParam);
|
|
GetWindowRect (Wnd, &Rc);
|
|
if (!PtInRect (&Rc, Point) || abs(This->LastY - Point.y) > 10) {
|
|
//
|
|
// change capture to parent
|
|
//
|
|
CONTROL_CLASS_SET_STATE (This, 0, UISTATE_PRESSED | UISTATE_CAPTURED | UISTATE_PREPRESSED);
|
|
ParentControl = This->Class->GetParent (This);
|
|
ASSERT (ParentControl != NULL);
|
|
|
|
ParentWnd = ParentControl->Wnd;
|
|
SetCapture (ParentWnd);
|
|
LastPoint.x = This->LastX;
|
|
LastPoint.y = This->LastY;
|
|
ScreenToClient (ParentWnd, &LastPoint);
|
|
SendMessage (ParentWnd, WM_LBUTTONDOWN, 0, MAKELONG(LastPoint.x, LastPoint.y));
|
|
SendMessage (ParentWnd, WM_NCMOUSEMOVE, 0, MAKELONG(Point.x, Point.y));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_NCLBUTTONUP:
|
|
break;
|
|
|
|
case WM_MOUSELEAVE:
|
|
case WM_LBUTTONUP:
|
|
This->Dragged = FALSE;
|
|
if (This->IsBeginDraged) {
|
|
ReleaseCapture ();
|
|
This->IsBeginDraged = FALSE;
|
|
} else if (GetCapture () == Wnd) {
|
|
CONTROL_CLASS_SET_STATE (This, 0, UISTATE_PRESSED | UISTATE_CAPTURED | UISTATE_PREPRESSED);
|
|
ReleaseCapture ();
|
|
}
|
|
break;
|
|
|
|
case WM_SETFOCUS:
|
|
CONTROL_CLASS_SET_STATE (This, UISTATE_FOCUSED, 0);
|
|
break;
|
|
|
|
case WM_KILLFOCUS:
|
|
CONTROL_CLASS_SET_STATE (This, 0, UISTATE_FOCUSED);
|
|
break;
|
|
|
|
case WM_ERASEBKGND:
|
|
return 1;
|
|
|
|
default:
|
|
return DefWindowProc (Wnd, Msg, WParam, LParam);
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
UI_CONTROL_CLASS *
|
|
GetControlClass (
|
|
VOID
|
|
)
|
|
{
|
|
STATIC UI_CONTROL_CLASS *Class = NULL;
|
|
|
|
if (Class != NULL) {
|
|
return Class;
|
|
}
|
|
|
|
Class = AllocateZeroPool (sizeof (UI_CONTROL_CLASS));
|
|
if (Class == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
Class->Parent = NULL;
|
|
Class->ClassSize = sizeof (*Class);
|
|
Class->ClassName = StrDuplicate (L"Control");
|
|
|
|
Class->FindChildByName = UiControlFindChildByName;
|
|
Class->AddChild = UiControlAddChild;
|
|
Class->RemoveChild = UiControlRemoveChild;
|
|
Class->RemoveAllChild = UiControlRemoveAllChild;
|
|
|
|
Class->WndProc = UiControlProc;
|
|
Class->SetState = UiControlSetState;
|
|
Class->GetState = UiControlGetState;
|
|
Class->SetAttribute = UiControlSetAttribute;
|
|
Class->SetPosition = UiControlSetPosition;
|
|
Class->EstimateSize = UiControlEstimateSize;
|
|
Class->Invalidate = UiControlInvalidate;
|
|
Class->FindNextFocus = UiControlFindNextFocus;
|
|
Class->GetParent = UiControlGetParent;
|
|
Class->ShouldDelayChildPressedState = UiControlShouldDelayChildPressedState;
|
|
|
|
|
|
return Class;
|
|
}
|
|
|
|
|