1// Copyright 2014 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "../../include/pdfwindow/PDFWindow.h"
8#include "../../include/pdfwindow/PWL_Wnd.h"
9#include "../../include/pdfwindow/PWL_ListCtrl.h"
10#include "../../include/pdfwindow/PWL_IconList.h"
11#include "../../include/pdfwindow/PWL_Utils.h"
12#include "../../include/pdfwindow/PWL_ScrollBar.h"
13#include "../../include/pdfwindow/PWL_Label.h"
14
15#define PWL_IconList_ITEM_ICON_LEFTMARGIN		10.0f
16#define PWL_IconList_ITEM_WIDTH					20.0f
17#define PWL_IconList_ITEM_HEIGHT				20.0f
18#define PWL_IconList_ITEM_SPACE					4.0f
19
20/* ------------------ CPWL_IconList_Item ------------------- */
21
22CPWL_IconList_Item::CPWL_IconList_Item() :
23	m_nIconIndex(-1),
24	m_pData(NULL),
25	m_bSelected(FALSE),
26	m_pText(NULL)
27{
28}
29
30CPWL_IconList_Item::~CPWL_IconList_Item()
31{
32}
33
34CFX_ByteString CPWL_IconList_Item::GetClassName() const
35{
36	return "CPWL_IconList_Item";
37}
38
39FX_FLOAT CPWL_IconList_Item::GetItemHeight(FX_FLOAT fLimitWidth)
40{
41	return PWL_IconList_ITEM_HEIGHT;
42}
43
44void CPWL_IconList_Item::DrawThisAppearance(CFX_RenderDevice* pDevice, CPDF_Matrix* pUser2Device)
45{
46	CPDF_Rect rcClient = GetClientRect();
47
48	if (m_bSelected)
49	{
50		if (this->IsEnabled())
51		{
52			CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcClient,
53				CPWL_Utils::PWLColorToFXColor(PWL_DEFAULT_SELBACKCOLOR,this->GetTransparency()));
54		}
55		else
56		{
57			CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcClient,
58				CPWL_Utils::PWLColorToFXColor(PWL_DEFAULT_LIGHTGRAYCOLOR,this->GetTransparency()));
59		}
60	}
61
62	CPDF_Rect rcIcon = rcClient;
63	rcIcon.left += PWL_IconList_ITEM_ICON_LEFTMARGIN;
64	rcIcon.right = rcIcon.left + PWL_IconList_ITEM_WIDTH;
65
66	CPWL_Utils::DrawIconAppStream(pDevice, pUser2Device, m_nIconIndex, rcIcon,
67		m_crIcon, m_pText->GetTextColor(), this->GetTransparency());
68}
69
70void CPWL_IconList_Item::SetSelect(FX_BOOL bSelected)
71{
72	m_bSelected = bSelected;
73
74	if (bSelected)
75		m_pText->SetTextColor(PWL_DEFAULT_WHITECOLOR);
76	else
77		m_pText->SetTextColor(PWL_DEFAULT_BLACKCOLOR);
78
79}
80
81FX_BOOL	CPWL_IconList_Item::IsSelected() const
82{
83	return m_bSelected;
84}
85
86void CPWL_IconList_Item::CreateChildWnd(const PWL_CREATEPARAM & cp)
87{
88	m_pText = new CPWL_Label;
89
90	PWL_CREATEPARAM lcp = cp;
91	lcp.pParentWnd = this;
92	lcp.dwFlags = PWS_CHILD | PWS_VISIBLE | PES_LEFT | PES_CENTER;
93	lcp.sTextColor = PWL_DEFAULT_BLACKCOLOR;
94	lcp.fFontSize = 12;
95	m_pText->Create(lcp);
96}
97
98void CPWL_IconList_Item::SetData(void* pData)
99{
100	m_pData = pData;
101}
102
103void CPWL_IconList_Item::SetIcon(FX_INT32 nIconIndex)
104{
105	m_nIconIndex = nIconIndex;
106}
107
108void CPWL_IconList_Item::SetText(const CFX_WideString& str)
109{
110	m_pText->SetText(str);
111}
112
113CFX_WideString CPWL_IconList_Item::GetText() const
114{
115	return m_pText->GetText();
116}
117
118void CPWL_IconList_Item::RePosChildWnd()
119{
120	CPDF_Rect rcClient = GetClientRect();
121
122	rcClient.left += (PWL_IconList_ITEM_ICON_LEFTMARGIN + PWL_IconList_ITEM_WIDTH + PWL_IconList_ITEM_ICON_LEFTMARGIN);
123
124	m_pText->Move(rcClient, TRUE, FALSE);
125}
126
127void CPWL_IconList_Item::SetIconFillColor(const CPWL_Color& color)
128{
129	m_crIcon = color;
130}
131
132void CPWL_IconList_Item::OnEnabled()
133{
134	if (m_bSelected)
135		m_pText->SetTextColor(PWL_DEFAULT_WHITECOLOR);
136	else
137		m_pText->SetTextColor(PWL_DEFAULT_BLACKCOLOR);
138
139	this->InvalidateRect();
140}
141
142void CPWL_IconList_Item::OnDisabled()
143{
144	m_pText->SetTextColor(PWL_DEFAULT_HEAVYGRAYCOLOR);
145
146	this->InvalidateRect();
147}
148
149/* ----------------- CPWL_IconList_Content ----------------- */
150
151CPWL_IconList_Content::CPWL_IconList_Content(FX_INT32 nListCount) :
152	m_nSelectIndex(-1),
153	m_pNotify(NULL),
154	m_bEnableNotify(TRUE),
155	m_bMouseDown(FALSE),
156	m_nListCount(nListCount)
157{
158}
159
160CPWL_IconList_Content::~CPWL_IconList_Content()
161{
162}
163
164void CPWL_IconList_Content::CreateChildWnd(const PWL_CREATEPARAM & cp)
165{
166	for (FX_INT32 i=0; i<m_nListCount; i++)
167	{
168		CPWL_IconList_Item* pNewItem = new CPWL_IconList_Item();
169
170		PWL_CREATEPARAM icp = cp;
171		icp.pParentWnd = this;
172		icp.dwFlags = PWS_CHILD | PWS_VISIBLE | PWS_NOREFRESHCLIP;
173		pNewItem->Create(icp);
174	}
175
176	this->SetItemSpace(PWL_IconList_ITEM_SPACE);
177	this->ResetContent(0);
178
179	if (CPWL_Wnd * pParent = this->GetParentWindow())
180	{
181		CPDF_Rect rcScroll = this->GetScrollArea();
182		this->GetScrollPos();
183
184		PWL_SCROLL_INFO sInfo;
185		sInfo.fContentMin = rcScroll.bottom;
186		sInfo.fContentMax = rcScroll.top;
187		sInfo.fPlateWidth = GetClientRect().Height();
188		sInfo.fSmallStep = 13.0f;
189		sInfo.fBigStep = sInfo.fPlateWidth;
190
191		pParent->OnNotify(this, PNM_SETSCROLLINFO, SBT_VSCROLL, (FX_INTPTR)&sInfo);
192	}
193}
194
195FX_BOOL	CPWL_IconList_Content::OnLButtonDown(const CPDF_Point & point)
196{
197	SetFocus();
198
199	SetCapture();
200	m_bMouseDown = TRUE;
201
202	FX_INT32 nItemIndex = FindItemIndex(point);
203	SetSelect(nItemIndex);
204	ScrollToItem(nItemIndex);
205
206	return TRUE;
207}
208
209FX_BOOL	CPWL_IconList_Content::OnLButtonUp(const CPDF_Point & point)
210{
211	m_bMouseDown = FALSE;
212	ReleaseCapture();
213
214	return TRUE;
215}
216
217FX_BOOL CPWL_IconList_Content::OnMouseMove(const CPDF_Point & point)
218{
219	if (m_bMouseDown)
220	{
221		FX_INT32 nItemIndex = FindItemIndex(point);
222		SetSelect(nItemIndex);
223		ScrollToItem(nItemIndex);
224	}
225
226	return TRUE;
227}
228
229FX_BOOL	CPWL_IconList_Content::OnKeyDown(FX_WORD nChar)
230{
231	switch (nChar)
232	{
233	case FWL_VKEY_Up:
234		if (m_nSelectIndex > 0)
235		{
236			FX_INT32 nItemIndex = m_nSelectIndex - 1;
237			SetSelect(nItemIndex);
238			ScrollToItem(nItemIndex);
239		}
240		return TRUE;
241	case FWL_VKEY_Down:
242		if (m_nSelectIndex < m_nListCount-1)
243		{
244			FX_INT32 nItemIndex = m_nSelectIndex + 1;
245			SetSelect(nItemIndex);
246			ScrollToItem(nItemIndex);
247		}
248		return TRUE;
249	}
250
251	return FALSE;
252}
253
254FX_INT32 CPWL_IconList_Content::FindItemIndex(const CPDF_Point& point)
255{
256	FX_INT32 nIndex = 0;
257	for (FX_INT32 i=0,sz=m_aChildren.GetSize(); i<sz; i++)
258	{
259		if (CPWL_Wnd * pChild = m_aChildren.GetAt(i))
260		{
261			CPDF_Rect rcWnd = pChild->ChildToParent(pChild->GetWindowRect());
262
263			if (point.y < rcWnd.top)
264			{
265				nIndex = i;
266			}
267		}
268	}
269
270	return nIndex;
271}
272
273void CPWL_IconList_Content::ScrollToItem(FX_INT32 nItemIndex)
274{
275	CPDF_Rect rcClient = GetClientRect();
276
277	if (CPWL_IconList_Item* pItem = GetListItem(nItemIndex))
278	{
279		CPDF_Rect rcOrigin = pItem->GetWindowRect();
280		CPDF_Rect rcWnd = pItem->ChildToParent(rcOrigin);
281
282		if (!(rcWnd.bottom > rcClient.bottom && rcWnd.top < rcClient.top))
283		{
284			CPDF_Point ptScroll = GetScrollPos();
285
286			if (rcWnd.top > rcClient.top)
287			{
288				ptScroll.y = rcOrigin.top;
289			}
290			else if (rcWnd.bottom < rcClient.bottom)
291			{
292				ptScroll.y = rcOrigin.bottom + rcClient.Height();
293			}
294
295			this->SetScrollPos(ptScroll);
296			this->ResetFace();
297			this->InvalidateRect();
298			if (CPWL_Wnd* pParent = this->GetParentWindow())
299			{
300				pParent->OnNotify(this, PNM_SETSCROLLPOS, SBT_VSCROLL, (FX_INTPTR)&ptScroll.y);
301			}
302		}
303	}
304}
305
306void CPWL_IconList_Content::SetSelect(FX_INT32 nIndex)
307{
308	if (m_nSelectIndex != nIndex)
309	{
310		SelectItem(m_nSelectIndex, FALSE);
311		SelectItem(nIndex, TRUE);
312		m_nSelectIndex = nIndex;
313
314		if (IPWL_IconList_Notify* pNotify = GetNotify())
315			pNotify->OnNoteListSelChanged(nIndex);
316	}
317}
318
319FX_INT32 CPWL_IconList_Content::GetSelect() const
320{
321	return m_nSelectIndex;
322}
323
324IPWL_IconList_Notify* CPWL_IconList_Content::GetNotify() const
325{
326	if (m_bEnableNotify)
327		return m_pNotify;
328	return NULL;
329}
330
331void CPWL_IconList_Content::SetNotify(IPWL_IconList_Notify* pNotify)
332{
333	m_pNotify = pNotify;
334}
335
336void CPWL_IconList_Content::EnableNotify(FX_BOOL bNotify)
337{
338	m_bEnableNotify = bNotify;
339}
340
341void CPWL_IconList_Content::SelectItem(FX_INT32 nItemIndex, FX_BOOL bSelect)
342{
343	if (CPWL_IconList_Item* pItem = GetListItem(nItemIndex))
344	{
345		pItem->SetSelect(bSelect);
346		pItem->InvalidateRect();
347	}
348}
349
350CPWL_IconList_Item* CPWL_IconList_Content::GetListItem(FX_INT32 nItemIndex) const
351{
352	if (nItemIndex >= 0 && nItemIndex<m_aChildren.GetSize())
353	{
354		if (CPWL_Wnd * pChild = m_aChildren.GetAt(nItemIndex))
355		{
356			if (pChild->GetClassName() == "CPWL_IconList_Item")
357			{
358				return (CPWL_IconList_Item*)pChild;
359			}
360		}
361	}
362
363	return NULL;
364}
365
366void CPWL_IconList_Content::SetListData(FX_INT32 nItemIndex, void* pData)
367{
368	if (CPWL_IconList_Item* pItem = GetListItem(nItemIndex))
369		pItem->SetData(pData);
370}
371
372void CPWL_IconList_Content::SetListIcon(FX_INT32 nItemIndex, FX_INT32 nIconIndex)
373{
374	if (CPWL_IconList_Item* pItem = GetListItem(nItemIndex))
375		pItem->SetIcon(nIconIndex);
376}
377
378void CPWL_IconList_Content::SetListString(FX_INT32 nItemIndex, const CFX_WideString& str)
379{
380	if (CPWL_IconList_Item* pItem = GetListItem(nItemIndex))
381		pItem->SetText(str);
382}
383
384CFX_WideString CPWL_IconList_Content::GetListString(FX_INT32 nItemIndex) const
385{
386	if (CPWL_IconList_Item* pItem = GetListItem(nItemIndex))
387		return pItem->GetText();
388
389	return L"";
390}
391
392void CPWL_IconList_Content::SetIconFillColor(const CPWL_Color& color)
393{
394	for (FX_INT32 i=0,sz=m_aChildren.GetSize(); i<sz; i++)
395	{
396		if (CPWL_Wnd * pChild = m_aChildren.GetAt(i))
397		{
398			if (pChild->GetClassName() == "CPWL_IconList_Item")
399			{
400				CPWL_IconList_Item* pItem = (CPWL_IconList_Item*)pChild;
401				pItem->SetIconFillColor(color);
402				pItem->InvalidateRect();
403			}
404		}
405	}
406
407}
408
409/* -------------------- CPWL_IconList --------------------- */
410
411CPWL_IconList::CPWL_IconList(FX_INT32 nListCount) :
412	m_pListContent(NULL),
413	m_nListCount(nListCount)
414{
415}
416
417CPWL_IconList::~CPWL_IconList()
418{
419}
420
421void CPWL_IconList::RePosChildWnd()
422{
423	CPWL_Wnd::RePosChildWnd();
424
425	if (m_pListContent)
426		m_pListContent->Move(GetClientRect(), TRUE, FALSE);
427}
428
429void CPWL_IconList::CreateChildWnd(const PWL_CREATEPARAM & cp)
430{
431	m_pListContent = new CPWL_IconList_Content(m_nListCount);
432
433	PWL_CREATEPARAM ccp = cp;
434	ccp.pParentWnd = this;
435	ccp.dwFlags = PWS_CHILD | PWS_VISIBLE;
436	m_pListContent->Create(ccp);
437}
438
439void CPWL_IconList::OnCreated()
440{
441	if (CPWL_ScrollBar* pScrollBar = this->GetVScrollBar())
442	{
443		pScrollBar->RemoveFlag(PWS_AUTOTRANSPARENT);
444		pScrollBar->SetTransparency(255);
445		pScrollBar->SetNotifyForever(TRUE);
446	}
447}
448
449void CPWL_IconList::OnNotify(CPWL_Wnd* pWnd, FX_DWORD msg, FX_INTPTR wParam, FX_INTPTR lParam)
450{
451	CPWL_Wnd::OnNotify(pWnd, msg, wParam, lParam);
452
453	if (wParam == SBT_VSCROLL)
454	{
455		switch (msg)
456		{
457		case PNM_SETSCROLLINFO:
458			if (PWL_SCROLL_INFO* pInfo = (PWL_SCROLL_INFO*)lParam)
459			{
460				if (CPWL_ScrollBar* pScrollBar = this->GetVScrollBar())
461				{
462					if (pInfo->fContentMax - pInfo->fContentMin > pInfo->fPlateWidth)
463					{
464						if (!pScrollBar->IsVisible())
465						{
466							pScrollBar->SetVisible(TRUE);
467							RePosChildWnd();
468						}
469						else
470						{
471						}
472					}
473					else
474					{
475						if (pScrollBar->IsVisible())
476						{
477							pScrollBar->SetVisible(FALSE);
478							RePosChildWnd();
479						}
480
481						if (m_pListContent)
482							m_pListContent->SetScrollPos(CPDF_Point(0.0f,0.0f));
483					}
484
485					pScrollBar->OnNotify(pWnd,PNM_SETSCROLLINFO,wParam,lParam);
486				}
487			}
488			return;
489		case PNM_SCROLLWINDOW:
490			if (m_pListContent)
491			{
492				m_pListContent->SetScrollPos(CPDF_Point(0.0f, *(FX_FLOAT*)lParam));
493				m_pListContent->ResetFace();
494				m_pListContent->InvalidateRect(NULL);
495			}
496			return;
497		case PNM_SETSCROLLPOS:
498			if (CPWL_ScrollBar* pScrollBar = this->GetVScrollBar())
499				pScrollBar->OnNotify(pWnd,PNM_SETSCROLLPOS,wParam,lParam);
500			return;
501		}
502	}
503}
504
505void CPWL_IconList::SetSelect(FX_INT32 nIndex)
506{
507	m_pListContent->SetSelect(nIndex);
508}
509
510void CPWL_IconList::SetTopItem(FX_INT32 nIndex)
511{
512	m_pListContent->ScrollToItem(nIndex);
513}
514
515FX_INT32 CPWL_IconList::GetSelect() const
516{
517	return m_pListContent->GetSelect();
518}
519
520void CPWL_IconList::SetNotify(IPWL_IconList_Notify* pNotify)
521{
522	m_pListContent->SetNotify(pNotify);
523}
524
525void CPWL_IconList::EnableNotify(FX_BOOL bNotify)
526{
527	m_pListContent->EnableNotify(bNotify);
528}
529
530void CPWL_IconList::SetListData(FX_INT32 nItemIndex, void* pData)
531{
532	m_pListContent->SetListData(nItemIndex, pData);
533}
534
535void CPWL_IconList::SetListIcon(FX_INT32 nItemIndex, FX_INT32 nIconIndex)
536{
537	m_pListContent->SetListIcon(nItemIndex, nIconIndex);
538}
539
540void CPWL_IconList::SetListString(FX_INT32 nItemIndex, const CFX_WideString& str)
541{
542	m_pListContent->SetListString(nItemIndex, str);
543}
544
545CFX_WideString CPWL_IconList::GetListString(FX_INT32 nItemIndex) const
546{
547	return m_pListContent->GetListString(nItemIndex);
548}
549
550void CPWL_IconList::SetIconFillColor(const CPWL_Color& color)
551{
552	m_pListContent->SetIconFillColor(color);
553}
554
555FX_BOOL	CPWL_IconList::OnMouseWheel(short zDelta, const CPDF_Point & point)
556{
557	CPDF_Point ptScroll = m_pListContent->GetScrollPos();
558	CPDF_Rect rcScroll = m_pListContent->GetScrollArea();
559	CPDF_Rect rcContents = m_pListContent->GetClientRect();
560
561	if (rcScroll.top - rcScroll.bottom > rcContents.Height())
562	{
563		CPDF_Point ptNew = ptScroll;
564
565		if (zDelta > 0)
566			ptNew.y += 30;
567		else
568			ptNew.y -= 30;
569
570		if (ptNew.y > rcScroll.top)
571			ptNew.y = rcScroll.top;
572		if (ptNew.y < rcScroll.bottom + rcContents.Height())
573			ptNew.y = rcScroll.bottom + rcContents.Height();
574		if (ptNew.y < rcScroll.bottom)
575			ptNew.y = rcScroll.bottom;
576
577		if (ptNew.y != ptScroll.y)
578		{
579			m_pListContent->SetScrollPos(ptNew);
580			m_pListContent->ResetFace();
581			m_pListContent->InvalidateRect(NULL);
582
583			if (CPWL_ScrollBar* pScrollBar = this->GetVScrollBar())
584				pScrollBar->OnNotify(this, PNM_SETSCROLLPOS, SBT_VSCROLL, (FX_INTPTR)&ptNew.y);
585
586			return TRUE;
587		}
588	}
589
590	return FALSE;
591}
592
593