alder_lake_bios/Insyde/InsydeSetupPkg/Drivers/H2ODisplayEngineLocalMetroDxe/UiLib/UiNumberPicker.c

689 lines
19 KiB
C

/** @file
UI number picker control
;******************************************************************************
;* Copyright (c) 2014 - 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 "H2OControls.h"
#include "H2ODisplayEngineLocalMetro.h"
#include "MetroUi.h"
STATIC UI_NUMBER_PICKER_CLASS *mNumberPickerClass = NULL;
#define CURRENT_CLASS mNumberPickerClass
#define CURRENT_VALUE_TEXT_COLOR L"0xFF999999"
CHAR16 *mNumberPickerChilds = L""
L"<VerticalLayout>"
L"<Label visibility='false' name='UpArrow' height='13'>"
L"<Texture float='true' background-image='@DialogButtonUp' background-color='0xFF333333' name='UpArrowImage' background-image-style='center'/>"
L"</Label>"
L"<HorizontalLayout name='PreviousValueLayout' height='52'>"
L"<Label text-align='singleline|center' textcolor='0xFF808080' font-size='29' background-color='0xFF333333' name='PreviousValue'/>"
L"</HorizontalLayout>"
L"<Label text-align='singleline|center' font-size='29' background-color='0xFF787878' name='CurrentValue' height='39'/>"
L"<HorizontalLayout name='NextValueLayout' height='52'>"
L"<Label text-align='singleline|center' textcolor='0xFF808080' font-size='29' background-color='0xFF333333' name='NextValue'/>"
L"</HorizontalLayout>"
L"<Label visibility='true' name='DownArrow' height='13'>"
L"<Texture float='true' background-image='@DialogButtonDown' background-color='0xFF333333' name='DownArrowImage' background-image-style='center'/>"
L"</Label>"
L"</VerticalLayout>";
UI_CONTROL *
GetControlByPoint (
IN UI_NUMBER_PICKER *This,
IN CHAR16 **List,
IN UINT32 ListCount,
IN POINT *Pt
)
{
UINT32 Index;
UI_CONTROL *ChildControl;
RECT Rc;
ChildControl = NULL;
for (Index = 0; Index < ListCount; Index++) {
ChildControl = UiFindChildByName (This, List[Index]);
if (ChildControl == NULL) {
continue;
}
GetWindowRect (ChildControl->Wnd, &Rc);
if (PtInRect (&Rc, *Pt)) {
return ChildControl;
}
}
return NULL;
}
CHAR16 *
GetPreviousValueStr (
IN UI_NUMBER_PICKER *This
)
{
if (This->ListCount <= 1 || This->CurrentIndex == -1) {
return NULL;
}
if (This->ListCount == 2) {
if (This->CurrentIndex == 1) {
return This->List[0];
} else {
return NULL;
}
}
if (This->CurrentIndex == 0) {
if (This->IsLoop) {
return This->List[This->ListCount - 1];
} else {
return NULL;
}
} else {
return This->List[This->CurrentIndex - 1];
}
}
CHAR16 *
GetNextValueStr (
IN UI_NUMBER_PICKER *This
)
{
if (This->ListCount <= 1 || This->CurrentIndex == -1) {
return NULL;
}
if (This->ListCount == 2) {
if (This->CurrentIndex == 0) {
return This->List[1];
} else {
return NULL;
}
}
if (This->CurrentIndex == (INT32) (This->ListCount - 1)) {
if (This->IsLoop) {
return This->List[0];
} else {
return NULL;
}
} else {
return This->List[This->CurrentIndex + 1];
}
}
EFI_STATUS
UpdateValueStr (
IN UI_NUMBER_PICKER *This
)
{
CHAR16 *Str;
if (This->CurrentIndex == -1 || This->List == NULL || This->CurrentIndex >= (INT32) This->ListCount) {
return EFI_NOT_READY;
}
Str = This->List[This->CurrentIndex];
UiSetAttribute (This->CurrentValueControl , L"text", Str);
Str = GetPreviousValueStr (This);
UiSetAttribute (This->PreviousValueControl, L"text", ((Str == NULL) ? L"" : Str));
Str = GetNextValueStr (This);
UiSetAttribute (This->NextValueControl , L"text", ((Str == NULL) ? L"" : Str));
CONTROL_CLASS_INVALIDATE (This);
return EFI_SUCCESS;
}
VOID
ShowPreviousNextValue (
IN UI_NUMBER_PICKER *This
)
{
UiSetAttribute (This->PreviousValueControl , L"visibility", L"true");
UiSetAttribute (This->NextValueControl , L"visibility", L"true");
UiSetAttribute (This->UpArrowImageControl , L"visibility", L"true");
UiSetAttribute (This->DownArrowImageControl, L"visibility", L"true");
CONTROL_CLASS_INVALIDATE (This);
}
VOID
HidePreviousNextValue (
UI_NUMBER_PICKER *This
)
{
UiSetAttribute (This->PreviousValueControl , L"visibility", L"false");
UiSetAttribute (This->NextValueControl , L"visibility", L"false");
UiSetAttribute (This->UpArrowImageControl , L"visibility", L"false");
UiSetAttribute (This->DownArrowImageControl, L"visibility", L"false");
CONTROL_CLASS_INVALIDATE (This);
}
INT32
GetNextIndex (
IN UI_NUMBER_PICKER *This,
IN BOOLEAN Increasement
)
{
INT32 NextIndex;
NextIndex = This->CurrentIndex;
if (Increasement) {
if (This->CurrentIndex < (INT32) (This->ListCount - 1)) {
NextIndex = This->CurrentIndex + 1;
} else {
NextIndex = (This->IsLoop) ? 0 : This->CurrentIndex;
}
} else {
if (This->CurrentIndex > 0) {
NextIndex = This->CurrentIndex - 1;
} else {
NextIndex = (This->IsLoop) ? (This->ListCount - 1) : This->CurrentIndex;
}
}
return NextIndex;
}
EFI_STATUS
SetCurrentIndex (
IN UI_NUMBER_PICKER *This,
IN INT32 CurrentIndex
)
{
if (CurrentIndex == -1 || CurrentIndex >= (INT32) This->ListCount) {
return EFI_INVALID_PARAMETER;
}
if (CurrentIndex == This->CurrentIndex) {
return EFI_SUCCESS;
}
This->CurrentIndex = CurrentIndex;
UpdateValueStr (This);
return EFI_SUCCESS;
}
VOID
SetCurrentIndexByMouseClick (
IN UI_NUMBER_PICKER *This,
IN POINT *Pt
)
{
INT32 CurrentIndex;
UI_CONTROL *ChildControl;
CHAR16 *ClickControlList[] = {L"UpArrow",
L"PreviousValue",
L"NextValue",
L"DownArrow"
};
ChildControl = GetControlByPoint (
This,
ClickControlList,
sizeof (ClickControlList) / sizeof (CHAR16 *),
Pt
);
if (ChildControl == NULL) {
return;
}
if (ChildControl != This->ButtonDownControl) {
//
// Button up and button down controls are not the same
//
return;
}
if ((ChildControl == This->UpArrowControl) ||
(ChildControl == This->NextValueControl)) {
CurrentIndex = GetNextIndex (This, TRUE);
} else {
CurrentIndex = GetNextIndex (This, FALSE);
}
SetCurrentIndex (This, CurrentIndex);
}
VOID
UiNumberPickerButtonDown (
IN UI_NUMBER_PICKER *This,
IN POINT *Pt
)
{
UI_CONTROL *ChildControl;
CHAR16 *List[] = {L"UpArrow",
L"PreviousValue",
L"CurrentValue",
L"NextValue",
L"DownArrow"
};
This->ButtonDownListIndex = -1;
ChildControl = GetControlByPoint (
This,
List,
sizeof (List) / sizeof (CHAR16 *),
Pt
);
if (ChildControl == NULL) {
return;
}
if (This->DisplayMode == DISPLAY_SELECTION_WHEN_HOVER && !This->Hover && StrCmp (ChildControl->Name, L"CurrentValue") != 0) {
return;
}
if (This->DisplayMode == DISPLAY_SELECTION_WHEN_PRESS) {
if ((StrCmp (ChildControl->Name, L"CurrentValue") != 0)) {
return;
}
ShowPreviousNextValue (This);
}
CopyMem (&This->ButtonDownPoint, Pt, sizeof (POINT));
This->ButtonDownListIndex = This->CurrentIndex;
This->ButtonDownControl = ChildControl;
if (This->OnItemSelected != NULL) {
This->OnItemSelected (This);
}
}
VOID
UiNumberPickerMouseMove (
IN UI_NUMBER_PICKER *This,
IN POINT *Pt
)
{
INT32 CurrentIndex;
INT32 Difference;
INT32 DifferenceIndex;
INT32 ListCount;
BOOLEAN Increasment;
if (This->ButtonDownListIndex == -1) {
//
// Return when user button down control is not found
//
return;
}
if ((This->ButtonDownControl == This->UpArrowControl) ||
(This->ButtonDownControl == This->DownArrowControl)) {
//
// Return when user button down control is UpArrow or DownArrow
//
return;
}
Difference = Pt->y - This->ButtonDownPoint.y;
if (abs (Difference) < This->PixelPerStep) {
return;
}
CurrentIndex = This->ButtonDownListIndex;
ListCount = (INT32) This->ListCount;
Increasment = (Difference < 0) ? TRUE : FALSE;
DifferenceIndex = (abs (Difference) / This->PixelPerStep) % ListCount;
if (Increasment) {
if (CurrentIndex + DifferenceIndex >= ListCount) {
if (This->IsLoop) {
DifferenceIndex -= (ListCount - CurrentIndex);
CurrentIndex = DifferenceIndex;
} else {
CurrentIndex = (ListCount > 1) ? (ListCount - 1) : 0;
}
} else {
CurrentIndex += DifferenceIndex;
}
} else {
if (DifferenceIndex > CurrentIndex) {
if (This->IsLoop) {
DifferenceIndex -= (CurrentIndex + 1);
CurrentIndex = (ListCount > 1) ? (ListCount - 1 - DifferenceIndex) : 0;
} else {
CurrentIndex = 0;
}
} else {
CurrentIndex -= DifferenceIndex;
}
}
SetCurrentIndex (This, CurrentIndex);
}
VOID
UiNumberPickerButtonUp (
IN UI_NUMBER_PICKER *This,
IN POINT Pt
)
{
if (This->CurrentIndex == This->ButtonDownListIndex) {
SetCurrentIndexByMouseClick (This, &Pt);
}
if (This->CurrentIndex != This->ButtonDownListIndex &&
This->OnCurrentIndexChange != NULL) {
This->OnCurrentIndexChange (This, This->CurrentIndex);
}
if (This->DisplayMode == DISPLAY_SELECTION_WHEN_PRESS && This->ButtonDownListIndex != -1) {
HidePreviousNextValue (This);
}
This->ButtonDownListIndex = -1;
This->ButtonDownControl = NULL;
}
LRESULT
UiNumberPickerKeyDown (
HWND Hwnd,
UINT32 Msg,
WPARAM WParam,
LPARAM LParam
)
{
UI_NUMBER_PICKER *This;
INT32 CurrentIndex;
This = (UI_NUMBER_PICKER *) GetWindowLongPtr (Hwnd, 0);
switch (WParam) {
case VK_UP:
case VK_OEM_PLUS:
CurrentIndex = GetNextIndex (This, TRUE);
SetCurrentIndex (This, CurrentIndex);
if (This->OnCurrentIndexChange != NULL) {
This->OnCurrentIndexChange (This, CurrentIndex);
}
break;
case VK_DOWN:
case VK_OEM_MINUS:
CurrentIndex = GetNextIndex (This, FALSE);
SetCurrentIndex (This, CurrentIndex);
if (This->OnCurrentIndexChange != NULL) {
This->OnCurrentIndexChange (This, CurrentIndex);
}
break;
default:
return PARENT_CLASS_WNDPROC (CURRENT_CLASS, Hwnd, Msg, WParam, LParam);
}
return 0;
}
LRESULT
CALLBACK
UiNumberPickerCallback (
HWND Wnd,
UINT Msg,
WPARAM WParam,
LPARAM LParam
)
{
UI_NUMBER_PICKER *This;
POINT Pt;
RECT Rc;
UI_CONTROL *ChildControl;
CHAR16 *List[] = {L"UpArrow",
L"PreviousValue",
L"CurrentValue",
L"NextValue",
L"DownArrow"
};
This = (UI_NUMBER_PICKER *) GetWindowLongPtr (Wnd, 0);
if (This->ButtonDownListIndex != -1) {
//
// Return when user is dragging by mouse
//
return 0;
}
GetCursorPos (&Pt);
if (This->Hover) {
ChildControl = GetControlByPoint (
This,
List,
sizeof (List) / sizeof (CHAR16 *),
&Pt
);
if (ChildControl == NULL) {
This->Hover = FALSE;
HidePreviousNextValue (This);
}
} else {
GetWindowRect (This->CurrentValueControl->Wnd, &Rc);
if (PtInRect (&Rc, Pt)) {
This->Hover = TRUE;
ShowPreviousNextValue (This);
}
}
return 0;
}
EFI_STATUS
UiNumberPickerCreate (
IN OUT UI_NUMBER_PICKER *This
)
{
This->CurrentIndex = -1;
This->ButtonDownListIndex = -1;
This->PixelPerStep = 5;
This->IsLoop = TRUE;
This->DisplayMode = ALWAYS_DISPLAY_SELECTION;
This->UpArrowControl = UiFindChildByName (This, L"UpArrow");
This->UpArrowImageControl = UiFindChildByName (This, L"UpArrowImage");
This->PreviousValueControl = UiFindChildByName (This, L"PreviousValue");
This->CurrentValueControl = UiFindChildByName (This, L"CurrentValue");
This->NextValueControl = UiFindChildByName (This, L"NextValue");
This->DownArrowControl = UiFindChildByName (This, L"DownArrow");
This->DownArrowImageControl = UiFindChildByName (This, L"DownArrowImage");
UiSetAttribute (This->CurrentValueControl, L"textcolor", CURRENT_VALUE_TEXT_COLOR);
switch (This->DisplayMode) {
case DISPLAY_SELECTION_WHEN_HOVER:
//
// BUGBUG:
// Should use WM_MOUSEENTER and WM_MOUSELEAVE msg to implement hover.
// But this two message cannot work properly, so use timer event to implement this feature temporarily.
//
SetTimer (((UI_CONTROL *) This)->Wnd, 0, 1, UiNumberPickerCallback);
HidePreviousNextValue (This);
break;
case DISPLAY_SELECTION_WHEN_PRESS:
HidePreviousNextValue (This);
break;
default:
break;
}
return EFI_SUCCESS;
}
BOOLEAN
EFIAPI
UiNumberPickerSetAttribute (
UI_CONTROL *Control,
CHAR16 *Name,
CHAR16 *Value
)
{
UI_NUMBER_PICKER *This;
EFI_STATUS Status;
CHAR16 **List;
This = (UI_NUMBER_PICKER *) Control;
if (StrCmp (Name, L"list") == 0) {
//
// Memory address of string array. It contains the string pointer of each item of number picker
//
FreeStringArray (This->List, This->ListCount);
List = (CHAR16 **) (UINTN) StrToUInt (Value, 16, &Status);
This->ListCount = GetStringArrayCount (List);
This->List = CopyStringArray (List, This->ListCount);
UpdateValueStr (This);
} else if (StrCmp (Name, L"currentindex") == 0) {
//
// Index value of string array for current value
//
This->CurrentIndex = wcstol (Value, NULL, 10);
UpdateValueStr (This);
} else if (StrCmp (Name, L"text") == 0) {
UiSetAttribute (This->CurrentValueControl , L"text", Value);
} else {
return PARENT_CLASS_SET_ATTRIBUTE (CURRENT_CLASS, Control, Name, Value);
}
CONTROL_CLASS_INVALIDATE (This);
return TRUE;
}
VOID
EFIAPI
UiNumberPickerSetState (
UI_CONTROL *Control,
UI_STATE SetState,
UI_STATE ClearState
)
{
UI_NUMBER_PICKER *This;
This = (UI_NUMBER_PICKER *) Control;
if ((SetState & UISTATE_SELECTED) == UISTATE_SELECTED) {
UiSetAttribute (This->CurrentValueControl , L"textcolor" , L"0xFFFFFFFF");
UiSetAttribute (This->UpArrowImageControl , L"background-image-style", L"center|light");
UiSetAttribute (This->DownArrowImageControl, L"background-image-style", L"center|light");
}
if ((ClearState & UISTATE_SELECTED) == UISTATE_SELECTED) {
UiSetAttribute (This->CurrentValueControl , L"textcolor" , CURRENT_VALUE_TEXT_COLOR);
UiSetAttribute (This->UpArrowImageControl , L"background-image-style", L"center");
UiSetAttribute (This->DownArrowImageControl, L"background-image-style", L"center");
}
PARENT_CONTROL_CLASS(CURRENT_CLASS)->SetState (Control, SetState, ClearState);
}
LRESULT
EFIAPI
UiNumberPickerProc (
HWND Hwnd,
UINT32 Msg,
WPARAM WParam,
LPARAM LParam
)
{
UI_NUMBER_PICKER *This;
UI_CONTROL *Control;
POINT CurrentPoint;
This = (UI_NUMBER_PICKER *) GetWindowLongPtr (Hwnd, 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_NUMBER_PICKER *) AllocateZeroPool (sizeof (UI_NUMBER_PICKER));
if (This != NULL) {
CONTROL_CLASS (This) = (UI_CONTROL_CLASS *) GetClassLongPtr (Hwnd, 0);
SetWindowLongPtr (Hwnd, 0, (INTN)This);
SendMessage (Hwnd, UI_NOTIFY_CREATE, WParam, LParam);
}
break;
case UI_NOTIFY_CREATE:
PARENT_CLASS_WNDPROC (CURRENT_CLASS, Hwnd, UI_NOTIFY_CREATE, WParam, LParam);
XmlCreateControl (mNumberPickerChilds, Control);
SetWindowLongPtr (Control->Wnd, GWL_EXSTYLE, GetWindowLongPtr (Control->Wnd, GWL_EXSTYLE) & ~WS_EX_NOACTIVATE);
UiNumberPickerCreate (This);
break;
case WM_DESTROY:
if (This->DisplayMode == DISPLAY_SELECTION_WHEN_HOVER) {
KillTimer (Hwnd, 0);
}
return PARENT_CLASS_WNDPROC (CURRENT_CLASS, Hwnd, Msg, WParam, LParam);
case WM_NCLBUTTONDOWN:
POINTSTOPOINT (CurrentPoint, LParam);
UiNumberPickerButtonDown (This, &CurrentPoint);
return PARENT_CLASS_WNDPROC (CURRENT_CLASS, Hwnd, Msg, WParam, LParam);
case WM_NCMOUSEMOVE:
POINTSTOPOINT (CurrentPoint, LParam);
UiNumberPickerMouseMove (This, &CurrentPoint);
return PARENT_CLASS_WNDPROC (CURRENT_CLASS, Hwnd, Msg, WParam, LParam);
case WM_NCLBUTTONUP:
POINTSTOPOINT (CurrentPoint, LParam);
UiNumberPickerButtonUp (This, CurrentPoint);
return PARENT_CLASS_WNDPROC (CURRENT_CLASS, Hwnd, Msg, WParam, LParam);
case WM_KEYDOWN:
UiNumberPickerKeyDown (Hwnd, Msg, WParam, LParam);
break;
case WM_NCHITTEST:
return HTCLIENT;
default:
return PARENT_CLASS_WNDPROC (CURRENT_CLASS, Hwnd, Msg, WParam, LParam);
}
return 0;
}
UI_NUMBER_PICKER_CLASS *
EFIAPI
GetNumberPickerClass (
VOID
)
{
if (CURRENT_CLASS != NULL) {
return CURRENT_CLASS;
}
InitUiClass ((UI_CONTROL_CLASS **)&CURRENT_CLASS, sizeof (*CURRENT_CLASS), L"NumberPicker", (UI_CONTROL_CLASS *) GetControlClass());
if (CURRENT_CLASS == NULL) {
return NULL;
}
((UI_CONTROL_CLASS *)CURRENT_CLASS)->WndProc = UiNumberPickerProc;
((UI_CONTROL_CLASS *)CURRENT_CLASS)->SetState = UiNumberPickerSetState;
((UI_CONTROL_CLASS *)CURRENT_CLASS)->SetAttribute = UiNumberPickerSetAttribute;
return CURRENT_CLASS;
}