// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include "../../include/pdfwindow/PDFWindow.h"
#include "../../include/pdfwindow/PWL_Wnd.h"
#include "../../include/pdfwindow/PWL_ListCtrl.h"
#include "../../include/pdfwindow/PWL_IconList.h"
#include "../../include/pdfwindow/PWL_Utils.h"
#include "../../include/pdfwindow/PWL_ScrollBar.h"
#include "../../include/pdfwindow/PWL_Label.h"
#define PWL_IconList_ITEM_ICON_LEFTMARGIN 10.0f
#define PWL_IconList_ITEM_WIDTH 20.0f
#define PWL_IconList_ITEM_HEIGHT 20.0f
#define PWL_IconList_ITEM_SPACE 4.0f
/* ------------------ CPWL_IconList_Item ------------------- */
CPWL_IconList_Item::CPWL_IconList_Item() :
m_nIconIndex(-1),
m_pData(NULL),
m_bSelected(FALSE),
m_pText(NULL)
{
}
CPWL_IconList_Item::~CPWL_IconList_Item()
{
}
CFX_ByteString CPWL_IconList_Item::GetClassName() const
{
return "CPWL_IconList_Item";
}
FX_FLOAT CPWL_IconList_Item::GetItemHeight(FX_FLOAT fLimitWidth)
{
return PWL_IconList_ITEM_HEIGHT;
}
void CPWL_IconList_Item::DrawThisAppearance(CFX_RenderDevice* pDevice, CPDF_Matrix* pUser2Device)
{
CPDF_Rect rcClient = GetClientRect();
if (m_bSelected)
{
if (this->IsEnabled())
{
CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcClient,
CPWL_Utils::PWLColorToFXColor(PWL_DEFAULT_SELBACKCOLOR,this->GetTransparency()));
}
else
{
CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcClient,
CPWL_Utils::PWLColorToFXColor(PWL_DEFAULT_LIGHTGRAYCOLOR,this->GetTransparency()));
}
}
CPDF_Rect rcIcon = rcClient;
rcIcon.left += PWL_IconList_ITEM_ICON_LEFTMARGIN;
rcIcon.right = rcIcon.left + PWL_IconList_ITEM_WIDTH;
CPWL_Utils::DrawIconAppStream(pDevice, pUser2Device, m_nIconIndex, rcIcon,
m_crIcon, m_pText->GetTextColor(), this->GetTransparency());
}
void CPWL_IconList_Item::SetSelect(FX_BOOL bSelected)
{
m_bSelected = bSelected;
if (bSelected)
m_pText->SetTextColor(PWL_DEFAULT_WHITECOLOR);
else
m_pText->SetTextColor(PWL_DEFAULT_BLACKCOLOR);
}
FX_BOOL CPWL_IconList_Item::IsSelected() const
{
return m_bSelected;
}
void CPWL_IconList_Item::CreateChildWnd(const PWL_CREATEPARAM & cp)
{
m_pText = new CPWL_Label;
PWL_CREATEPARAM lcp = cp;
lcp.pParentWnd = this;
lcp.dwFlags = PWS_CHILD | PWS_VISIBLE | PES_LEFT | PES_CENTER;
lcp.sTextColor = PWL_DEFAULT_BLACKCOLOR;
lcp.fFontSize = 12;
m_pText->Create(lcp);
}
void CPWL_IconList_Item::SetData(void* pData)
{
m_pData = pData;
}
void CPWL_IconList_Item::SetIcon(FX_INT32 nIconIndex)
{
m_nIconIndex = nIconIndex;
}
void CPWL_IconList_Item::SetText(const CFX_WideString& str)
{
m_pText->SetText(str);
}
CFX_WideString CPWL_IconList_Item::GetText() const
{
return m_pText->GetText();
}
void CPWL_IconList_Item::RePosChildWnd()
{
CPDF_Rect rcClient = GetClientRect();
rcClient.left += (PWL_IconList_ITEM_ICON_LEFTMARGIN + PWL_IconList_ITEM_WIDTH + PWL_IconList_ITEM_ICON_LEFTMARGIN);
m_pText->Move(rcClient, TRUE, FALSE);
}
void CPWL_IconList_Item::SetIconFillColor(const CPWL_Color& color)
{
m_crIcon = color;
}
void CPWL_IconList_Item::OnEnabled()
{
if (m_bSelected)
m_pText->SetTextColor(PWL_DEFAULT_WHITECOLOR);
else
m_pText->SetTextColor(PWL_DEFAULT_BLACKCOLOR);
this->InvalidateRect();
}
void CPWL_IconList_Item::OnDisabled()
{
m_pText->SetTextColor(PWL_DEFAULT_HEAVYGRAYCOLOR);
this->InvalidateRect();
}
/* ----------------- CPWL_IconList_Content ----------------- */
CPWL_IconList_Content::CPWL_IconList_Content(FX_INT32 nListCount) :
m_nSelectIndex(-1),
m_pNotify(NULL),
m_bEnableNotify(TRUE),
m_bMouseDown(FALSE),
m_nListCount(nListCount)
{
}
CPWL_IconList_Content::~CPWL_IconList_Content()
{
}
void CPWL_IconList_Content::CreateChildWnd(const PWL_CREATEPARAM & cp)
{
for (FX_INT32 i=0; i<m_nListCount; i++)
{
CPWL_IconList_Item* pNewItem = new CPWL_IconList_Item();
PWL_CREATEPARAM icp = cp;
icp.pParentWnd = this;
icp.dwFlags = PWS_CHILD | PWS_VISIBLE | PWS_NOREFRESHCLIP;
pNewItem->Create(icp);
}
this->SetItemSpace(PWL_IconList_ITEM_SPACE);
this->ResetContent(0);
if (CPWL_Wnd * pParent = this->GetParentWindow())
{
CPDF_Rect rcScroll = this->GetScrollArea();
this->GetScrollPos();
PWL_SCROLL_INFO sInfo;
sInfo.fContentMin = rcScroll.bottom;
sInfo.fContentMax = rcScroll.top;
sInfo.fPlateWidth = GetClientRect().Height();
sInfo.fSmallStep = 13.0f;
sInfo.fBigStep = sInfo.fPlateWidth;
pParent->OnNotify(this, PNM_SETSCROLLINFO, SBT_VSCROLL, (FX_INTPTR)&sInfo);
}
}
FX_BOOL CPWL_IconList_Content::OnLButtonDown(const CPDF_Point & point)
{
SetFocus();
SetCapture();
m_bMouseDown = TRUE;
FX_INT32 nItemIndex = FindItemIndex(point);
SetSelect(nItemIndex);
ScrollToItem(nItemIndex);
return TRUE;
}
FX_BOOL CPWL_IconList_Content::OnLButtonUp(const CPDF_Point & point)
{
m_bMouseDown = FALSE;
ReleaseCapture();
return TRUE;
}
FX_BOOL CPWL_IconList_Content::OnMouseMove(const CPDF_Point & point)
{
if (m_bMouseDown)
{
FX_INT32 nItemIndex = FindItemIndex(point);
SetSelect(nItemIndex);
ScrollToItem(nItemIndex);
}
return TRUE;
}
FX_BOOL CPWL_IconList_Content::OnKeyDown(FX_WORD nChar)
{
switch (nChar)
{
case FWL_VKEY_Up:
if (m_nSelectIndex > 0)
{
FX_INT32 nItemIndex = m_nSelectIndex - 1;
SetSelect(nItemIndex);
ScrollToItem(nItemIndex);
}
return TRUE;
case FWL_VKEY_Down:
if (m_nSelectIndex < m_nListCount-1)
{
FX_INT32 nItemIndex = m_nSelectIndex + 1;
SetSelect(nItemIndex);
ScrollToItem(nItemIndex);
}
return TRUE;
}
return FALSE;
}
FX_INT32 CPWL_IconList_Content::FindItemIndex(const CPDF_Point& point)
{
FX_INT32 nIndex = 0;
for (FX_INT32 i=0,sz=m_aChildren.GetSize(); i<sz; i++)
{
if (CPWL_Wnd * pChild = m_aChildren.GetAt(i))
{
CPDF_Rect rcWnd = pChild->ChildToParent(pChild->GetWindowRect());
if (point.y < rcWnd.top)
{
nIndex = i;
}
}
}
return nIndex;
}
void CPWL_IconList_Content::ScrollToItem(FX_INT32 nItemIndex)
{
CPDF_Rect rcClient = GetClientRect();
if (CPWL_IconList_Item* pItem = GetListItem(nItemIndex))
{
CPDF_Rect rcOrigin = pItem->GetWindowRect();
CPDF_Rect rcWnd = pItem->ChildToParent(rcOrigin);
if (!(rcWnd.bottom > rcClient.bottom && rcWnd.top < rcClient.top))
{
CPDF_Point ptScroll = GetScrollPos();
if (rcWnd.top > rcClient.top)
{
ptScroll.y = rcOrigin.top;
}
else if (rcWnd.bottom < rcClient.bottom)
{
ptScroll.y = rcOrigin.bottom + rcClient.Height();
}
this->SetScrollPos(ptScroll);
this->ResetFace();
this->InvalidateRect();
if (CPWL_Wnd* pParent = this->GetParentWindow())
{
pParent->OnNotify(this, PNM_SETSCROLLPOS, SBT_VSCROLL, (FX_INTPTR)&ptScroll.y);
}
}
}
}
void CPWL_IconList_Content::SetSelect(FX_INT32 nIndex)
{
if (m_nSelectIndex != nIndex)
{
SelectItem(m_nSelectIndex, FALSE);
SelectItem(nIndex, TRUE);
m_nSelectIndex = nIndex;
if (IPWL_IconList_Notify* pNotify = GetNotify())
pNotify->OnNoteListSelChanged(nIndex);
}
}
FX_INT32 CPWL_IconList_Content::GetSelect() const
{
return m_nSelectIndex;
}
IPWL_IconList_Notify* CPWL_IconList_Content::GetNotify() const
{
if (m_bEnableNotify)
return m_pNotify;
return NULL;
}
void CPWL_IconList_Content::SetNotify(IPWL_IconList_Notify* pNotify)
{
m_pNotify = pNotify;
}
void CPWL_IconList_Content::EnableNotify(FX_BOOL bNotify)
{
m_bEnableNotify = bNotify;
}
void CPWL_IconList_Content::SelectItem(FX_INT32 nItemIndex, FX_BOOL bSelect)
{
if (CPWL_IconList_Item* pItem = GetListItem(nItemIndex))
{
pItem->SetSelect(bSelect);
pItem->InvalidateRect();
}
}
CPWL_IconList_Item* CPWL_IconList_Content::GetListItem(FX_INT32 nItemIndex) const
{
if (nItemIndex >= 0 && nItemIndex<m_aChildren.GetSize())
{
if (CPWL_Wnd * pChild = m_aChildren.GetAt(nItemIndex))
{
if (pChild->GetClassName() == "CPWL_IconList_Item")
{
return (CPWL_IconList_Item*)pChild;
}
}
}
return NULL;
}
void CPWL_IconList_Content::SetListData(FX_INT32 nItemIndex, void* pData)
{
if (CPWL_IconList_Item* pItem = GetListItem(nItemIndex))
pItem->SetData(pData);
}
void CPWL_IconList_Content::SetListIcon(FX_INT32 nItemIndex, FX_INT32 nIconIndex)
{
if (CPWL_IconList_Item* pItem = GetListItem(nItemIndex))
pItem->SetIcon(nIconIndex);
}
void CPWL_IconList_Content::SetListString(FX_INT32 nItemIndex, const CFX_WideString& str)
{
if (CPWL_IconList_Item* pItem = GetListItem(nItemIndex))
pItem->SetText(str);
}
CFX_WideString CPWL_IconList_Content::GetListString(FX_INT32 nItemIndex) const
{
if (CPWL_IconList_Item* pItem = GetListItem(nItemIndex))
return pItem->GetText();
return L"";
}
void CPWL_IconList_Content::SetIconFillColor(const CPWL_Color& color)
{
for (FX_INT32 i=0,sz=m_aChildren.GetSize(); i<sz; i++)
{
if (CPWL_Wnd * pChild = m_aChildren.GetAt(i))
{
if (pChild->GetClassName() == "CPWL_IconList_Item")
{
CPWL_IconList_Item* pItem = (CPWL_IconList_Item*)pChild;
pItem->SetIconFillColor(color);
pItem->InvalidateRect();
}
}
}
}
/* -------------------- CPWL_IconList --------------------- */
CPWL_IconList::CPWL_IconList(FX_INT32 nListCount) :
m_pListContent(NULL),
m_nListCount(nListCount)
{
}
CPWL_IconList::~CPWL_IconList()
{
}
void CPWL_IconList::RePosChildWnd()
{
CPWL_Wnd::RePosChildWnd();
if (m_pListContent)
m_pListContent->Move(GetClientRect(), TRUE, FALSE);
}
void CPWL_IconList::CreateChildWnd(const PWL_CREATEPARAM & cp)
{
m_pListContent = new CPWL_IconList_Content(m_nListCount);
PWL_CREATEPARAM ccp = cp;
ccp.pParentWnd = this;
ccp.dwFlags = PWS_CHILD | PWS_VISIBLE;
m_pListContent->Create(ccp);
}
void CPWL_IconList::OnCreated()
{
if (CPWL_ScrollBar* pScrollBar = this->GetVScrollBar())
{
pScrollBar->RemoveFlag(PWS_AUTOTRANSPARENT);
pScrollBar->SetTransparency(255);
pScrollBar->SetNotifyForever(TRUE);
}
}
void CPWL_IconList::OnNotify(CPWL_Wnd* pWnd, FX_DWORD msg, FX_INTPTR wParam, FX_INTPTR lParam)
{
CPWL_Wnd::OnNotify(pWnd, msg, wParam, lParam);
if (wParam == SBT_VSCROLL)
{
switch (msg)
{
case PNM_SETSCROLLINFO:
if (PWL_SCROLL_INFO* pInfo = (PWL_SCROLL_INFO*)lParam)
{
if (CPWL_ScrollBar* pScrollBar = this->GetVScrollBar())
{
if (pInfo->fContentMax - pInfo->fContentMin > pInfo->fPlateWidth)
{
if (!pScrollBar->IsVisible())
{
pScrollBar->SetVisible(TRUE);
RePosChildWnd();
}
else
{
}
}
else
{
if (pScrollBar->IsVisible())
{
pScrollBar->SetVisible(FALSE);
RePosChildWnd();
}
if (m_pListContent)
m_pListContent->SetScrollPos(CPDF_Point(0.0f,0.0f));
}
pScrollBar->OnNotify(pWnd,PNM_SETSCROLLINFO,wParam,lParam);
}
}
return;
case PNM_SCROLLWINDOW:
if (m_pListContent)
{
m_pListContent->SetScrollPos(CPDF_Point(0.0f, *(FX_FLOAT*)lParam));
m_pListContent->ResetFace();
m_pListContent->InvalidateRect(NULL);
}
return;
case PNM_SETSCROLLPOS:
if (CPWL_ScrollBar* pScrollBar = this->GetVScrollBar())
pScrollBar->OnNotify(pWnd,PNM_SETSCROLLPOS,wParam,lParam);
return;
}
}
}
void CPWL_IconList::SetSelect(FX_INT32 nIndex)
{
m_pListContent->SetSelect(nIndex);
}
void CPWL_IconList::SetTopItem(FX_INT32 nIndex)
{
m_pListContent->ScrollToItem(nIndex);
}
FX_INT32 CPWL_IconList::GetSelect() const
{
return m_pListContent->GetSelect();
}
void CPWL_IconList::SetNotify(IPWL_IconList_Notify* pNotify)
{
m_pListContent->SetNotify(pNotify);
}
void CPWL_IconList::EnableNotify(FX_BOOL bNotify)
{
m_pListContent->EnableNotify(bNotify);
}
void CPWL_IconList::SetListData(FX_INT32 nItemIndex, void* pData)
{
m_pListContent->SetListData(nItemIndex, pData);
}
void CPWL_IconList::SetListIcon(FX_INT32 nItemIndex, FX_INT32 nIconIndex)
{
m_pListContent->SetListIcon(nItemIndex, nIconIndex);
}
void CPWL_IconList::SetListString(FX_INT32 nItemIndex, const CFX_WideString& str)
{
m_pListContent->SetListString(nItemIndex, str);
}
CFX_WideString CPWL_IconList::GetListString(FX_INT32 nItemIndex) const
{
return m_pListContent->GetListString(nItemIndex);
}
void CPWL_IconList::SetIconFillColor(const CPWL_Color& color)
{
m_pListContent->SetIconFillColor(color);
}
FX_BOOL CPWL_IconList::OnMouseWheel(short zDelta, const CPDF_Point & point)
{
CPDF_Point ptScroll = m_pListContent->GetScrollPos();
CPDF_Rect rcScroll = m_pListContent->GetScrollArea();
CPDF_Rect rcContents = m_pListContent->GetClientRect();
if (rcScroll.top - rcScroll.bottom > rcContents.Height())
{
CPDF_Point ptNew = ptScroll;
if (zDelta > 0)
ptNew.y += 30;
else
ptNew.y -= 30;
if (ptNew.y > rcScroll.top)
ptNew.y = rcScroll.top;
if (ptNew.y < rcScroll.bottom + rcContents.Height())
ptNew.y = rcScroll.bottom + rcContents.Height();
if (ptNew.y < rcScroll.bottom)
ptNew.y = rcScroll.bottom;
if (ptNew.y != ptScroll.y)
{
m_pListContent->SetScrollPos(ptNew);
m_pListContent->ResetFace();
m_pListContent->InvalidateRect(NULL);
if (CPWL_ScrollBar* pScrollBar = this->GetVScrollBar())
pScrollBar->OnNotify(this, PNM_SETSCROLLPOS, SBT_VSCROLL, (FX_INTPTR)&ptNew.y);
return TRUE;
}
}
return FALSE;
}