//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "LineEdit.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//

static inline void ValidCtrCheck(TLineEdit *)
{
	new TLineEdit(NULL);
}
//---------------------------------------------------------------------------
__fastcall TLineEdit::TLineEdit(TComponent* Owner)
	: TWinControl(Owner)
{
    m_Canvas = new TControlCanvas();
    m_Canvas->Control = this;

    m_HintLabel = new TLabel(this);
    m_HintLabel->Font->Color = TColor(0x594D43);
    m_HintLabel->OnMouseDown = DoHintLabelMouseDown;

    Height			= 24;
    Width			= 124;
    FBorderColor 	= TColor(0x5F5954);
    FShadowColor 	= TColor(0x4C463F);
    Color 			= TColor(0xC4B4A8);
    FHintColor		= TColor(0x594D43);
    FMaxLength 		= 500;
    FOnChange 		= NULL;
	TabStop 		= true;

	FNumberMax		= -1;
	FNumberMin		= -1;

    m_IsCreated = false;
}
//---------------------------------------------------------------------------
namespace Lineedit
{
	void __fastcall PACKAGE Register()
	{
		TComponentClass classes[1] = {__classid(TLineEdit)};
		RegisterComponents(L"Samples", classes, 0);
	}
}
//---------------------------------------------------------------------------

__fastcall TLineEdit::~TLineEdit()
{
    if(m_Canvas)
    {
    	delete m_Canvas;
        m_Canvas = NULL;
    }

    if(m_HintLabel)
    {
        delete m_HintLabel;
        m_HintLabel = NULL;
    }
}
//---------------------------------------------------------------------------

void __fastcall TLineEdit::SetTextFont(String name, int size)
{
	Font->Name = name;
	Font->Size = size;

	m_HintLabel->Font->Name = Font->Name;
	m_HintLabel->Font->Size = Font->Size;
}
//---------------------------------------------------------------------------

void __fastcall TLineEdit::AdjustThisSize()
{
    // 设置创建圆角窗口
    HRGN var_Hrgn;
	var_Hrgn = CreateRoundRectRgn(0, 0, Width + 1, Height + 1, 3, 3);
	SetWindowRgn(Handle, var_Hrgn, true);
    DeleteObject(var_Hrgn);

    // 获取字体高度
    m_FontHeight = CalcFontHeight();

    int var_EditTop = (Height - m_FontHeight) / 2;

    // 计算编辑区位置
    m_TextRect = GetClientRect();
    m_TextRect.Left += 4;
    m_TextRect.Right -= 4;
    m_TextRect.Top = var_EditTop;

    // 设置HintText位置
    m_HintLabel->Top = m_TextRect.Top;
    m_HintLabel->Left = m_TextRect.Left;
    m_HintLabel->Width = m_TextRect.Width();

    // 设置编辑区左右边距
    SendMessage(Handle, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, 0);

    // 设置编辑区域(多行编辑有效)
    SendMessage(Handle, EM_SETRECT, 0, (LPARAM)(&m_TextRect));
}

int __fastcall TLineEdit::CalcColorValue(TColor Bg, TColor Fr, int Level, int Alpha)
{
    return ((Bg * (Level - Alpha) + Fr * Alpha) / Level);
}

int __fastcall TLineEdit::CalcFontHeight()
{
	// 计算字体高度
    TTextMetric var_Metric;
    HDC var_DC = GetDC(0);

    SelectObject(var_DC, Font->Handle);
    GetTextMetricsW(var_DC, &var_Metric);

    ReleaseDC(0, var_DC);

    return var_Metric.tmHeight;
}

void __fastcall TLineEdit::CreateShadowColor()
{
    int var_R, var_G, var_B, var_Alpha;
    int Level = (int)(atan(3.14 / 2) * 500);

    // 计算阴影颜色
    for(int var_Index = 0; var_Index < 4; var_Index++)
    {
    	var_Alpha = (int)(atan(3.14 / (2 * 3) * var_Index) * 500);

    	var_R = CalcColorValue(GetRValue(FShadowColor), GetRValue(Color), Level, var_Alpha);
    	var_G = CalcColorValue(GetGValue(FShadowColor), GetGValue(Color), Level, var_Alpha);
        var_B = CalcColorValue(GetBValue(FShadowColor), GetBValue(Color), Level, var_Alpha);

		m_ShadowColorArray[var_Index] = RGB(var_R, var_G, var_B);
    }

    m_ShadowColorArray[4] = Color;
}

void __fastcall TLineEdit::CreateParams(TCreateParams &Params)
{
    TWinControl::CreateParams(Params);
    CreateSubClass(Params, L"EDIT");

    DWORD var_Alignments[] 		= {ES_LEFT, ES_RIGHT, ES_CENTER};
    DWORD var_CharCase[] 		= {0, ES_UPPERCASE, ES_LOWERCASE};
    DWORD var_HideSelection[] 	= {ES_NOHIDESEL, 0};
    DWORD var_NumbersOnly[] 	= {0, ES_NUMBER};
    DWORD var_OEMConvert[] 		= {0, ES_OEMCONVERT};
    DWORD var_PasswordChar[] 	= {0, ES_PASSWORD};
    DWORD var_ReadOnly[] 		= {0, ES_READONLY};

    Params.Style |= var_Alignments[FAlignment];
    Params.Style |= var_CharCase[FCharCase];
    Params.Style |= var_HideSelection[FHideSelection];
    Params.Style |= var_NumbersOnly[FNumbersOnly];
    Params.Style |= var_OEMConvert[FOEMConvert];
    Params.Style |= var_PasswordChar[FPasswordChar != 0];
    Params.Style |= var_ReadOnly[FReadOnly];

    Params.Style |= ES_AUTOHSCROLL;
    Params.Style |= ES_MULTILINE;

    //Params.Style |= WS_TABSTOP;

    //Params.ExStyle |= WS_EX_CONTROLPARENT;
}

void __fastcall TLineEdit::CreateWindowHandle(const TCreateParams &Params)
{
    TWinControl::CreateWindowHandle(Params);
}

void __fastcall TLineEdit::CreateWnd()
{
	TWinControl::CreateWnd();
	m_HintLabel->Parent = this;

    if(FPasswordChar != 0)
    {
    	if(FPasswordChar == '*')
        {
            SendMessageW(Handle, EM_SETPASSWORDCHAR, L'●', 0);
        }
        else
        {
        	SendMessageW(Handle, EM_SETPASSWORDCHAR, FPasswordChar, 0);
        }
    }

    if(FReadOnly)
    {
        SendMessage(WindowHandle, EM_SETREADONLY, 1, 0);
    }

    if(!m_IsCreated)
    {
    	SetText(FText);
        m_IsCreated = true;
    }

    SetMaxLength(FMaxLength);

    AdjustThisSize();
}

void __fastcall TLineEdit::CMColorChanged(TMessage &Message)
{
    CreateShadowColor();
    Invalidate();
}

void __fastcall TLineEdit::CMFontChanged(TWMFontChange &Message)
{
    TColor var_FontColor = Font->Color;

	if(var_FontColor != m_FontColor) {
		m_FontColor = var_FontColor;		// 保存字体颜色
		Invalidate();
	}
	else {
		m_HintLabel->Font->Name = Font->Name;
		m_HintLabel->Font->Size = Font->Size;

        RecreateWnd();
    }
}

void __fastcall TLineEdit::SetBorderColor(TColor Color)
{
	if(FBorderColor != Color)
    {
    	FBorderColor = Color;
        SendMessage(Handle, CM_COLORCHANGED, 0, 0);
    }
}

void __fastcall TLineEdit::SetCursorPos(int Pos)
{
    //SendMessage(Handle, EM_SETSEL, Pos, Pos);

    SendMessage(Handle, EM_SCROLL, SB_PAGEUP, 0);
}

void __fastcall TLineEdit::SetFocus()
{
	m_HintLabel->Visible = false;
    TWinControl::SetFocus();
}

void __fastcall TLineEdit::SetOnChange(TNotifyEvent OnChange)
{
    FOnChange = OnChange;
}

void __fastcall TLineEdit::SetShadowColor(TColor Color)
{
    if(FShadowColor != Color)
    {
        FShadowColor = Color;
        SendMessage(Handle, CM_COLORCHANGED, 0, 0);
    }
}

void __fastcall TLineEdit::ShowHintText()
{
	if(Text.IsEmpty() && !Focused())
    	m_HintLabel->Visible = true;
    else
    	m_HintLabel->Visible = false;
	//if(Text.Length() == 0) m_HintLabel->Visible = true;
    //else m_HintLabel->Visible = false;
}

void __fastcall TLineEdit::WMChar(TWMChar &Message)
{
	if(Message.CharCode < 32)
    {
    	switch(Message.CharCode)
        {
        case 1:		// Ctrl + A
        case 3:		// 双击鼠标左键
            SelectAll();
            break;

        default:
            TWinControl::Dispatch(&Message);
        }
    }
    else if(Message.CharCode == 32)
    {
        if(!FNumbersOnly)
        	TWinControl::Dispatch(&Message);
    }
    else
    {
		// 限制长度
		String text = GetText();
		int selStart = GetSelStart();
		int selLen = GetSelLength();
		text.Delete(selStart + 1, selLen);

    	if(text.Length() <  FMaxLength)
		{
			if(FNumbersOnly)
            {
				if(Message.CharCode >= 0x30 && Message.CharCode <= 0x39)
				{
					if(FNumberMax != -1) {
						wchar_t c = Message.CharCode;

						if(!text.IsEmpty()) {
							if(selStart == 0 && Message.CharCode == '0')
								return;

							if(StrToInt(text) == 0 && Message.CharCode == '0')
								return;
						}

						text.Insert(String(c), selStart);
						int num = StrToInt(text);
						if(num <= FNumberMax) {
							TWinControl::Dispatch(&Message);
                        }
					}
					else
						TWinControl::Dispatch(&Message);
                }
            }
            else
            {
				TWinControl::Dispatch(&Message);
            }
        }
        else
        {
            //MessageBeep(MB_OK);
        }
    }
}

void __fastcall TLineEdit::WMCommand(TWMCommand &Message)
{
    if(Message.NotifyCode == EN_CHANGE)
    {
    	//ShowHintText();
        Invalidate();
        if(FOnChange) FOnChange(this);
    }
}

void __fastcall TLineEdit::WMCtlColorEdit(TWMCtlColorEdit &Message)
{
	if(GetTextColor(Message.ChildDC)  != ColorToRGB(Font->Color))
    	SetTextColor(Message.ChildDC, ColorToRGB(Font->Color));	// 设置编辑文字颜色

    //if(GetBkColor(Message.ChildDC) != ColorToRGB(Color))
    //{
    //	SetBkColor(Message.ChildDC, ColorToRGB(Color));			// 设置编辑背景颜色
    //}

    if(GetBkMode(Message.ChildDC) != TRANSPARENT)
    	SetBkMode(Message.ChildDC, TRANSPARENT);

    //ExcludeUpdateRgn(Message.ChildDC, Message.ChildWnd); */
}

void __fastcall TLineEdit::WMCtlColorStatic(TWMCtlColorStatic &Message)
{
	SetTextColor(Message.ChildDC, ColorToRGB(Font->Color));	// 设置编辑文字颜色

    if(GetBkMode(Message.ChildDC) != TRANSPARENT)
    	SetBkMode(Message.ChildDC, TRANSPARENT);

    //SetBkColor(Message.ChildDC, ColorToRGB(Color));			// 设置编辑背景颜色
}

void __fastcall TLineEdit::WMEraseBkgnd(TWMEraseBkgnd &Message)
{
    m_Canvas->Lock();
    m_Canvas->Handle = Message.DC;

    TRect var_Rect = GetClientRect();

    // 绘制背景
    m_Canvas->Brush->Color = Color;
    m_Canvas->FillRect(var_Rect);

    // 绘制边框
    m_Canvas->Brush->Color = FBorderColor;
    m_Canvas->FrameRect(var_Rect);

    var_Rect.Top++;
    var_Rect.Left++;
    var_Rect.Right--;
    var_Rect.Bottom--;

    // 绘制阴影
    m_Canvas->Brush->Color = TColor(m_ShadowColorArray[0]);
    //m_Canvas->Brush->Color = FShadowColor;
    m_Canvas->FrameRect(var_Rect);

    for(int var_Layer = 1; var_Layer < 4; var_Layer++)
    {
    	// 设置画笔颜色
    	m_Canvas->Pen->Color = TColor(m_ShadowColorArray[var_Layer]);

    	m_Canvas->MoveTo(var_Rect.Left + var_Layer, var_Rect.Bottom - 2);
    	m_Canvas->LineTo(var_Rect.Left + var_Layer, var_Rect.Top + var_Layer);

    	m_Canvas->MoveTo(var_Rect.Left + var_Layer, var_Rect.Top + var_Layer);
    	m_Canvas->LineTo(var_Rect.Right - 1, var_Rect.Top + var_Layer);
    }

    m_Canvas->UpdateTextFlags();
    m_Canvas->Unlock();
}

void __fastcall TLineEdit::WMKeyDown(TWMKeyDown &Message)
{
    if(Message.CharCode == VK_RETURN && !FReadOnly && Enabled)
    {
        MessageBeep(MB_OK);
    }

    TWinControl::Dispatch(&Message);
}

void __fastcall TLineEdit::WMKillFocus(TWMKillFocus &Message)
{
    ShowHintText();

	TWinControl::Dispatch(&Message);

	if(Text.Length() <  FMaxLength && !Text.IsEmpty())
	{
		if(FNumbersOnly && FNumberMin != -1)
		{
			int Value = StrToInt(Text);
			if(Value < FNumberMin) {
				Text = IntToStr(FNumberMin);
            }
		}
	}

    Invalidate();
}

void __fastcall TLineEdit::WMPaint(TWMPaint &Message)
{
    PaintHandler(Message);
}

void __fastcall TLineEdit::WMSetFocus(TWMSetFocus &Message)
{
    //ShowHintText();
    m_HintLabel->Visible = false;
    TWinControl::Dispatch(&Message);
}

void __fastcall TLineEdit::WMSize(TWMSize &Message)
{
    // 获取当前字体高度
    m_FontHeight = CalcFontHeight();

    // 计算编辑框的最小高度
    int var_MinHeight = m_FontHeight + 4;
    int var_MinWidth = 20;

    // 检查宽高的合法性
    if(Height < var_MinHeight)
    {
        Height = var_MinHeight;
        return;
    }

    if(Width < var_MinWidth)
    {
        Width = var_MinWidth;
        return;
    }

    AdjustThisSize();
}

/******************************************************************************/
// 编辑框操作
/******************************************************************************/
void __fastcall TLineEdit::DoHintLabelMouseDown(TObject *Sender,
    								TMouseButton Button,
    								TShiftState Shift, int X, int Y)
{
	SetFocus();
}

void __fastcall TLineEdit::Clear()
{
    FText = "";
    SetText(FText);
}

void __fastcall TLineEdit::ClearSelection()
{
    SendMessage(Handle, WM_CLEAR, 0, 0);
}

void __fastcall TLineEdit::CopyToClipboard()
{
    SendMessage(Handle, WM_COPY, 0, 0);
}

void __fastcall TLineEdit::CutToClipboard()
{
    SendMessage(Handle, WM_CUT, 0, 0);
}

void __fastcall TLineEdit::PasteFromClipboard()
{
    SendMessage(Handle, WM_PASTE, 0, 0);
}

void __fastcall TLineEdit::Undo()
{
    SendMessage(Handle, WM_UNDO, 0, 0);
}

void __fastcall TLineEdit::ClearUndo()
{
    SendMessage(Handle, EM_EMPTYUNDOBUFFER, 0, 0);
}

void __fastcall TLineEdit::SelectAll()
{
    SendMessage(Handle, EM_SETSEL, 0, -1);
}

String __fastcall TLineEdit::GetText()
{
    if(HandleAllocated())
    {
    	SendMessageW(Handle, WM_GETTEXT, 1024, (LPARAM)m_TextBuf);
	}
	else
	{
        wcscpy( m_TextBuf, FText.c_str() );
    }

    return String(m_TextBuf);
}

bool __fastcall TLineEdit::GetCanUndo()
{
	if(HandleAllocated())
    {
    	return (SendMessage(Handle, EM_CANUNDO, 0, 0) != 0);
    }
    else
    {
    	return false;
    }
}

int __fastcall TLineEdit::GetSelLength()
{
    TSelection Selection;
    SendMessage(Handle, EM_GETSEL, (WPARAM)&Selection.StartPos, (LPARAM)&Selection.EndPos);

    return Selection.EndPos - Selection.StartPos;
}

int __fastcall TLineEdit::GetSelStart()
{
	int var_Result;
	SendMessage(Handle, EM_GETSEL, (WPARAM)&var_Result, 0);

	return var_Result;
}

String __fastcall TLineEdit::GetSelText()
{
    int var_Start, var_Length;

    var_Start = GetSelStart();
    var_Length = GetSelLength();

    return Text.SubString(var_Start + 1, var_Length);
}

void __fastcall TLineEdit::SetMaxLength(int Value)
{
	if(Value > 500 || Value <= 0)
    {
        Value = 500;
    }

    if(FMaxLength != Value)
    {
        FMaxLength = Value;
    }
}

void __fastcall TLineEdit::SetSelLength(int Value)
{
	TSelection Selection;
    SendMessage(Handle, EM_GETSEL, (WPARAM)&Selection.StartPos, (LPARAM)&Selection.EndPos);

    Selection.EndPos = Selection.StartPos + Value;
    SendMessage(Handle, EM_SETSEL, Selection.StartPos, Selection.EndPos);
    SendMessage(Handle, EM_SCROLLCARET, 0, 0);
}

void __fastcall TLineEdit::SetSelStart(int Value)
{
    SendMessage(Handle, EM_SETSEL, Value, Value);
}

void __fastcall TLineEdit::SetAlignment(TAlignment Value)
{
    if(FAlignment != Value)
    {
    	FAlignment = Value;
        m_HintLabel->Alignment = Value;

        if(HandleAllocated())
        {
        	RecreateWnd();
        }
    }
}

void __fastcall TLineEdit::SetCharCase(TEditCharCase Value)
{
    if(FCharCase != Value)
    {
    	FCharCase = Value;

        if(HandleAllocated())
        {
        	RecreateWnd();
        }
    }
}

void __fastcall TLineEdit::SetHideSelection(bool Value)
{
    if(FHideSelection != Value)
    {
    	FHideSelection = Value;

        if(HandleAllocated())
        {
        	RecreateWnd();
        }
    }
}

void __fastcall TLineEdit::SetHintText(String Value)
{
    if(FHintText != Value)
    {
    	FHintText = Value;
    	m_HintLabel->Caption = Value;
    }
}

void __fastcall TLineEdit::SetHintColor(TColor Value)
{
    if(FHintColor != Value)
    {
    	FHintColor = Value;
    	m_HintLabel->Font->Color = Value;
    }
}

void __fastcall TLineEdit::SetNumbersOnly(bool Value)
{
    if(FNumbersOnly != Value)
    {
    	FNumbersOnly = Value;

        if(HandleAllocated())
        {
        	RecreateWnd();
        }
    }
}

void __fastcall TLineEdit::SetOEMConvert(bool Value)
{
    if(FOEMConvert != Value)
    {
    	FOEMConvert = Value;

        if(HandleAllocated())
        {
        	RecreateWnd();
        }
    }
}

void __fastcall TLineEdit::SetPasswordChar(WideChar Value)
{
	if(FPasswordChar != Value)
    {
    	FPasswordChar = Value;

        if(HandleAllocated())
        {
        	RecreateWnd();
        }
    }
}

void __fastcall TLineEdit::SetReadOnly(bool Value)
{
    if(FReadOnly != Value)
    {
    	FReadOnly = Value;

        if(HandleAllocated())
        {
        	RecreateWnd();
        }
    }
}

void __fastcall TLineEdit::SetText(String Value)
{
    FText = Value;

    if(HandleAllocated())
    {
        //SetWindowText(Handle, Value.c_str());

        //SetWindowText(Handle, FText.c_str());
        if(Value.IsEmpty())
        {
            m_HintLabel->SetDesignVisible(true);
            m_HintLabel->Visible = true;
        }
        else
        {
        	m_HintLabel->SetDesignVisible(false);
        	m_HintLabel->Visible = false;
        }

    	SendMessageW(Handle, WM_SETTEXT, 0, (LPARAM)Value.c_str());

        if(FOnChange) FOnChange(this);
    }
}

void __fastcall TLineEdit::SetNumberMax(int Value)
{
	if(FNumberMax != Value) {

		FNumberMax = Value;
    }
}

void __fastcall TLineEdit::SetNumberMin(int Value)
{
	if(FNumberMin != Value) {

		if(Value > FNumberMax) {
			Value = FNumberMax;
		}

		FNumberMin = Value;
    }
}

/******************************************************************************/
