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/fxedit/fxet_stub.h"
8 #include "../../include/fxedit/fxet_edit.h"
9 #include "../../include/fxedit/fxet_list.h"
10 
11 /* ------------------------------- CFX_ListItem ---------------------------------- */
12 
CFX_ListItem()13 CFX_ListItem::CFX_ListItem() : m_pEdit(NULL),
14 	m_bSelected(FALSE),
15 	m_bCaret(FALSE),
16 	m_rcListItem(0.0f,0.0f,0.0f,0.0f)
17 {
18 	m_pEdit = IFX_Edit::NewEdit();
19 	ASSERT(m_pEdit != NULL);
20 
21 	m_pEdit->SetAlignmentV(1);
22 	m_pEdit->Initialize();
23 }
24 
~CFX_ListItem()25 CFX_ListItem::~CFX_ListItem()
26 {
27 	IFX_Edit::DelEdit(m_pEdit);
28 }
29 
SetFontMap(IFX_Edit_FontMap * pFontMap)30 void CFX_ListItem::SetFontMap(IFX_Edit_FontMap * pFontMap)
31 {
32 	if (m_pEdit)
33 		m_pEdit->SetFontMap(pFontMap);
34 }
35 
GetEdit() const36 IFX_Edit* CFX_ListItem::GetEdit() const
37 {
38 	return m_pEdit;
39 }
40 
GetIterator() const41 IFX_Edit_Iterator*	CFX_ListItem::GetIterator() const
42 {
43 	if (m_pEdit)
44 		return m_pEdit->GetIterator();
45 
46 	return NULL;
47 }
48 
SetRect(const CLST_Rect & rect)49 void CFX_ListItem::SetRect(const CLST_Rect & rect)
50 {
51 	m_rcListItem = rect;
52 }
53 
GetRect() const54 CLST_Rect CFX_ListItem::GetRect() const
55 {
56 	return m_rcListItem;
57 }
58 
IsSelected() const59 FX_BOOL CFX_ListItem::IsSelected() const
60 {
61 	return m_bSelected;
62 }
63 
SetSelect(FX_BOOL bSelected)64 void CFX_ListItem::SetSelect(FX_BOOL bSelected)
65 {
66 	m_bSelected = bSelected;
67 }
68 
IsCaret() const69 FX_BOOL CFX_ListItem::IsCaret() const
70 {
71 	return m_bCaret;
72 }
73 
SetCaret(FX_BOOL bCaret)74 void CFX_ListItem::SetCaret(FX_BOOL bCaret)
75 {
76 	m_bCaret = bCaret;
77 }
78 
SetText(FX_LPCWSTR text)79 void CFX_ListItem::SetText(FX_LPCWSTR text)
80 {
81 	if (m_pEdit)
82 		m_pEdit->SetText(text);
83 }
84 
SetFontSize(FX_FLOAT fFontSize)85 void CFX_ListItem::SetFontSize(FX_FLOAT fFontSize)
86 {
87 	if (m_pEdit)
88 		m_pEdit->SetFontSize(fFontSize);
89 }
90 
GetItemHeight() const91 FX_FLOAT CFX_ListItem::GetItemHeight() const
92 {
93 	if (m_pEdit)
94 		return m_pEdit->GetContentRect().Height();
95 
96 	return 0.0f;
97 }
98 
GetFirstChar() const99 FX_WORD CFX_ListItem::GetFirstChar() const
100 {
101 	CPVT_Word word;
102 
103 	if (IFX_Edit_Iterator*	pIterator = GetIterator())
104 	{
105 		pIterator->SetAt(1);
106 		pIterator->GetWord(word);
107 	}
108 
109 	return word.Word;
110 }
111 
GetText() const112 CFX_WideString CFX_ListItem::GetText() const
113 {
114 	if (m_pEdit)
115 		return m_pEdit->GetText();
116 
117 	return L"";
118 }
119 
120 /* ------------------------------------ CFX_List --------------------------------- */
121 
CFX_List()122 CFX_List::CFX_List() : m_fFontSize(0.0f), m_pFontMap(NULL), m_bMultiple(FALSE)
123 {
124 }
125 
~CFX_List()126 CFX_List::~CFX_List()
127 {
128 	Empty();
129 }
130 
Empty()131 void CFX_List::Empty()
132 {
133 	for (FX_INT32 i=0,sz=m_aListItems.GetSize(); i<sz; i++)
134 		delete m_aListItems.GetAt(i);
135 
136 	m_aListItems.RemoveAll();
137 }
138 
SetFontMap(IFX_Edit_FontMap * pFontMap)139 void CFX_List::SetFontMap(IFX_Edit_FontMap * pFontMap)
140 {
141 	m_pFontMap = pFontMap;
142 }
143 
SetFontSize(FX_FLOAT fFontSize)144 void CFX_List::SetFontSize(FX_FLOAT fFontSize)
145 {
146 	m_fFontSize = fFontSize;
147 }
148 
AddItem(FX_LPCWSTR str)149 void CFX_List::AddItem(FX_LPCWSTR str)
150 {
151 	if (CFX_ListItem * pListItem = new CFX_ListItem())
152 	{
153 		pListItem->SetFontMap(m_pFontMap);
154 		pListItem->SetFontSize(m_fFontSize);
155 		pListItem->SetText(str);
156 		m_aListItems.Add(pListItem);
157 	}
158 }
159 
ReArrange(FX_INT32 nItemIndex)160 void CFX_List::ReArrange(FX_INT32 nItemIndex)
161 {
162 	FX_FLOAT fPosY = 0.0f;
163 
164 	if (CFX_ListItem * pPrevItem = m_aListItems.GetAt(nItemIndex - 1))
165 		fPosY = pPrevItem->GetRect().bottom;
166 
167 	for (FX_INT32 i=nItemIndex,sz=m_aListItems.GetSize(); i<sz; i++)
168 	{
169 		if (CFX_ListItem * pListItem = m_aListItems.GetAt(i))
170 		{
171 			FX_FLOAT fListItemHeight = pListItem->GetItemHeight();
172 			pListItem->SetRect(CLST_Rect(0.0f,fPosY,0.0f,fPosY + fListItemHeight));
173 			fPosY += fListItemHeight;
174 		}
175 	}
176 
177 	SetContentRect(CLST_Rect(0.0f,0.0f,0.0f,fPosY));
178 }
179 
GetItemEdit(FX_INT32 nIndex) const180 IFX_Edit * CFX_List::GetItemEdit(FX_INT32 nIndex) const
181 {
182 	if (CFX_ListItem * pListItem = m_aListItems.GetAt(nIndex))
183 	{
184 		return pListItem->GetEdit();
185 	}
186 
187 	return NULL;
188 }
189 
GetCount() const190 FX_INT32 CFX_List::GetCount() const
191 {
192 	return m_aListItems.GetSize();
193 }
194 
GetPlateRect() const195 CPDF_Rect CFX_List::GetPlateRect() const
196 {
197 	return CFX_ListContainer::GetPlateRect();
198 }
199 
GetContentRect() const200 CPDF_Rect CFX_List::GetContentRect() const
201 {
202 	return InnerToOuter(CFX_ListContainer::GetContentRect());
203 }
204 
GetFontSize() const205 FX_FLOAT CFX_List::GetFontSize() const
206 {
207 	return m_fFontSize;
208 }
209 
GetItemIndex(const CPDF_Point & point) const210 FX_INT32 CFX_List::GetItemIndex(const CPDF_Point & point) const
211 {
212 	CPDF_Point pt = OuterToInner(point);
213 
214 	FX_BOOL bFirst = TRUE;
215 	FX_BOOL bLast = TRUE;
216 
217 	for (FX_INT32 i=0,sz=m_aListItems.GetSize(); i<sz; i++)
218 	{
219 		if (CFX_ListItem * pListItem = m_aListItems.GetAt(i))
220 		{
221 			CLST_Rect rcListItem = pListItem->GetRect();
222 
223 			if (FX_EDIT_IsFloatBigger(pt.y, rcListItem.top))
224 			{
225 				bFirst = FALSE;
226 			}
227 
228 			if (FX_EDIT_IsFloatSmaller(pt.y, rcListItem.bottom))
229 			{
230 				bLast = FALSE;
231 			}
232 
233 			if (pt.y >= rcListItem.top && pt.y < rcListItem.bottom)
234 			{
235 				return i;
236 			}
237 		}
238 	}
239 
240 	if (bFirst) return 0;
241 	if (bLast) return m_aListItems.GetSize()-1;
242 
243 	return -1;
244 }
245 
GetFirstHeight() const246 FX_FLOAT CFX_List::GetFirstHeight() const
247 {
248 	if (CFX_ListItem * pListItem = m_aListItems.GetAt(0))
249 	{
250 		return pListItem->GetItemHeight();
251 	}
252 
253 	return 1.0f;
254 }
255 
GetFirstSelected() const256 FX_INT32 CFX_List::GetFirstSelected() const
257 {
258 	for (FX_INT32 i=0,sz=m_aListItems.GetSize(); i<sz; i++)
259 	{
260 		if (CFX_ListItem * pListItem = m_aListItems.GetAt(i))
261 		{
262 			if (pListItem->IsSelected())
263 				return i;
264 		}
265 	}
266 	return -1;
267 }
268 
GetLastSelected() const269 FX_INT32 CFX_List::GetLastSelected() const
270 {
271 	for (FX_INT32 i=m_aListItems.GetSize()-1; i>=0; i--)
272 	{
273 		if (CFX_ListItem * pListItem = m_aListItems.GetAt(i))
274 		{
275 			if (pListItem->IsSelected())
276 				return i;
277 		}
278 	}
279 	return -1;
280 }
281 
Toupper(FX_WCHAR c) const282 FX_WCHAR CFX_List::Toupper(FX_WCHAR c) const
283 {
284 	if ( (c >= 'a') && (c <= 'z') )
285 		c = c - ('a' - 'A');
286 	return c;
287 }
288 
FindNext(FX_INT32 nIndex,FX_WCHAR nChar) const289 FX_INT32 CFX_List::FindNext(FX_INT32 nIndex,FX_WCHAR nChar) const
290 {
291 	FX_INT32 nCircleIndex = nIndex;
292 
293 	for (FX_INT32 i=0,sz=m_aListItems.GetSize(); i<sz; i++)
294 	{
295 		nCircleIndex ++;
296 		if (nCircleIndex >= sz) nCircleIndex = 0;
297 
298 		if (CFX_ListItem * pListItem = m_aListItems.GetAt(nCircleIndex))
299 		{
300 			if (Toupper(pListItem->GetFirstChar()) == Toupper(nChar))
301 				return nCircleIndex;
302 		}
303 	}
304 
305 	return nCircleIndex;
306 }
307 
GetItemRect(FX_INT32 nIndex) const308 CPDF_Rect CFX_List::GetItemRect(FX_INT32 nIndex) const
309 {
310 	if (CFX_ListItem * pListItem = m_aListItems.GetAt(nIndex))
311 	{
312 		CPDF_Rect rcItem = pListItem->GetRect();
313 		rcItem.left = 0.0f;
314 		rcItem.right = GetPlateRect().Width();
315 		return InnerToOuter(rcItem);
316 	}
317 
318 	return CPDF_Rect();
319 }
320 
IsItemSelected(FX_INT32 nIndex) const321 FX_BOOL CFX_List::IsItemSelected(FX_INT32 nIndex) const
322 {
323 	if (CFX_ListItem * pListItem = m_aListItems.GetAt(nIndex))
324 	{
325 		return pListItem->IsSelected();
326 	}
327 
328 	return FALSE;
329 }
330 
SetItemSelect(FX_INT32 nItemIndex,FX_BOOL bSelected)331 void CFX_List::SetItemSelect(FX_INT32 nItemIndex, FX_BOOL bSelected)
332 {
333 	if (CFX_ListItem * pListItem = m_aListItems.GetAt(nItemIndex))
334 	{
335 		pListItem->SetSelect(bSelected);
336 	}
337 }
338 
SetItemCaret(FX_INT32 nItemIndex,FX_BOOL bCaret)339 void CFX_List::SetItemCaret(FX_INT32 nItemIndex, FX_BOOL bCaret)
340 {
341 	if (CFX_ListItem * pListItem = m_aListItems.GetAt(nItemIndex))
342 	{
343 		pListItem->SetCaret(bCaret);
344 	}
345 }
346 
SetMultipleSel(FX_BOOL bMultiple)347 void CFX_List::SetMultipleSel(FX_BOOL bMultiple)
348 {
349 	m_bMultiple = bMultiple;
350 }
351 
IsMultipleSel() const352 FX_BOOL CFX_List::IsMultipleSel() const
353 {
354 	return m_bMultiple;
355 }
356 
IsValid(FX_INT32 nItemIndex) const357 FX_BOOL CFX_List::IsValid(FX_INT32 nItemIndex) const
358 {
359 	return nItemIndex >= 0 && nItemIndex < m_aListItems.GetSize();
360 }
361 
GetItemText(FX_INT32 nIndex) const362 CFX_WideString CFX_List::GetItemText(FX_INT32 nIndex) const
363 {
364 	if (CFX_ListItem * pListItem = m_aListItems.GetAt(nIndex))
365 	{
366 		return pListItem->GetText();
367 	}
368 
369 	return L"";
370 }
371 
372 /* ------------------------------------ CPLST_Select ---------------------------------- */
373 
CPLST_Select()374 CPLST_Select::CPLST_Select()
375 {
376 }
377 
~CPLST_Select()378 CPLST_Select::~CPLST_Select()
379 {
380 	for (FX_INT32 i=0,sz=m_aItems.GetSize(); i<sz; i++)
381 		delete m_aItems.GetAt(i);
382 
383 	m_aItems.RemoveAll();
384 }
385 
Add(FX_INT32 nItemIndex)386 void CPLST_Select::Add(FX_INT32 nItemIndex)
387 {
388 	FX_INT32 nIndex = Find(nItemIndex);
389 
390 	if (nIndex < 0)
391 		m_aItems.Add(new CPLST_Select_Item(nItemIndex,1));
392 	else
393 	{
394 		if (CPLST_Select_Item * pItem = m_aItems.GetAt(nIndex))
395 		{
396 			pItem->nState = 1;
397 		}
398 	}
399 }
400 
Add(FX_INT32 nBeginIndex,FX_INT32 nEndIndex)401 void CPLST_Select::Add(FX_INT32 nBeginIndex, FX_INT32 nEndIndex)
402 {
403 	if (nBeginIndex > nEndIndex)
404 	{
405 		FX_INT32 nTemp = nEndIndex;
406 		nEndIndex = nBeginIndex;
407 		nBeginIndex = nTemp;
408 	}
409 
410 	for (FX_INT32 i=nBeginIndex; i<=nEndIndex; i++)	Add(i);
411 }
412 
Sub(FX_INT32 nItemIndex)413 void CPLST_Select::Sub(FX_INT32 nItemIndex)
414 {
415 	for (FX_INT32 i=m_aItems.GetSize()-1; i>=0; i--)
416 	{
417 		if (CPLST_Select_Item * pItem = m_aItems.GetAt(i))
418 			if (pItem->nItemIndex == nItemIndex)
419 				pItem->nState = -1;
420 	}
421 }
422 
Sub(FX_INT32 nBeginIndex,FX_INT32 nEndIndex)423 void CPLST_Select::Sub(FX_INT32 nBeginIndex, FX_INT32 nEndIndex)
424 {
425 	if (nBeginIndex > nEndIndex)
426 	{
427 		FX_INT32 nTemp = nEndIndex;
428 		nEndIndex = nBeginIndex;
429 		nBeginIndex = nTemp;
430 	}
431 
432 	for (FX_INT32 i=nBeginIndex; i<=nEndIndex; i++)	Sub(i);
433 }
434 
Find(FX_INT32 nItemIndex) const435 FX_INT32 CPLST_Select::Find(FX_INT32 nItemIndex) const
436 {
437 	for (FX_INT32 i=0,sz=m_aItems.GetSize(); i<sz; i++)
438 	{
439 		if (CPLST_Select_Item * pItem = m_aItems.GetAt(i))
440 		{
441 			if (pItem->nItemIndex == nItemIndex)
442 				return i;
443 		}
444 	}
445 
446 	return -1;
447 }
448 
IsExist(FX_INT32 nItemIndex) const449 FX_BOOL CPLST_Select::IsExist(FX_INT32 nItemIndex) const
450 {
451 	return Find(nItemIndex) >= 0;
452 }
453 
GetCount() const454 FX_INT32 CPLST_Select::GetCount() const
455 {
456 	return m_aItems.GetSize();
457 }
458 
GetItemIndex(FX_INT32 nIndex) const459 FX_INT32 CPLST_Select::GetItemIndex(FX_INT32 nIndex) const
460 {
461 	if (nIndex >= 0 && nIndex < m_aItems.GetSize())
462 		if (CPLST_Select_Item * pItem = m_aItems.GetAt(nIndex))
463 			return pItem->nItemIndex;
464 
465 	return -1;
466 }
467 
GetState(FX_INT32 nIndex) const468 FX_INT32 CPLST_Select::GetState(FX_INT32 nIndex) const
469 {
470 	if (nIndex >= 0 && nIndex < m_aItems.GetSize())
471 		if (CPLST_Select_Item * pItem = m_aItems.GetAt(nIndex))
472 			return pItem->nState;
473 
474 	return 0;
475 }
476 
DeselectAll()477 void CPLST_Select::DeselectAll()
478 {
479 	for (FX_INT32 i=0,sz=m_aItems.GetSize(); i<sz; i++)
480 	{
481 		if (CPLST_Select_Item * pItem = m_aItems.GetAt(i))
482 		{
483 			pItem->nState = -1;
484 		}
485 	}
486 }
487 
Done()488 void CPLST_Select::Done()
489 {
490 	for (FX_INT32 i=m_aItems.GetSize()-1; i>=0; i--)
491 	{
492 		if (CPLST_Select_Item * pItem = m_aItems.GetAt(i))
493 		{
494 			if (pItem->nState == -1)
495 			{
496 				delete pItem;
497 				m_aItems.RemoveAt(i);
498 			}
499 			else
500 			{
501 				pItem->nState = 0;
502 			}
503 		}
504 	}
505 }
506 
507 /* ------------------------------------ CFX_ListCtrl --------------------------------- */
508 
CFX_ListCtrl()509 CFX_ListCtrl::CFX_ListCtrl() : m_pNotify(NULL),
510 	m_bNotifyFlag(FALSE),
511 	m_ptScrollPos(0.0f,0.0f),
512 	m_nSelItem(-1),
513 	m_nFootIndex(-1),
514 	m_bCtrlSel(FALSE),
515 	m_nCaretIndex(-1)
516 {
517 }
518 
~CFX_ListCtrl()519 CFX_ListCtrl::~CFX_ListCtrl()
520 {
521 }
522 
SetNotify(IFX_List_Notify * pNotify)523 void CFX_ListCtrl::SetNotify(IFX_List_Notify * pNotify)
524 {
525 	m_pNotify = pNotify;
526 }
527 
InToOut(const CPDF_Point & point) const528 CPDF_Point CFX_ListCtrl::InToOut(const CPDF_Point & point) const
529 {
530 	CPDF_Rect rcPlate = GetPlateRect();
531 
532 	return CPDF_Point(point.x - (m_ptScrollPos.x - rcPlate.left),
533 		point.y - (m_ptScrollPos.y - rcPlate.top));
534 }
535 
OutToIn(const CPDF_Point & point) const536 CPDF_Point CFX_ListCtrl::OutToIn(const CPDF_Point & point) const
537 {
538 	CPDF_Rect rcPlate = GetPlateRect();
539 
540 	return CPDF_Point(point.x + (m_ptScrollPos.x - rcPlate.left),
541 		point.y + (m_ptScrollPos.y - rcPlate.top));
542 }
543 
InToOut(const CPDF_Rect & rect) const544 CPDF_Rect CFX_ListCtrl::InToOut(const CPDF_Rect & rect) const
545 {
546 	CPDF_Point ptLeftBottom = InToOut(CPDF_Point(rect.left,rect.bottom));
547 	CPDF_Point ptRightTop = InToOut(CPDF_Point(rect.right,rect.top));
548 
549 	return CPDF_Rect(ptLeftBottom.x,ptLeftBottom.y,ptRightTop.x,ptRightTop.y);
550 }
551 
OutToIn(const CPDF_Rect & rect) const552 CPDF_Rect CFX_ListCtrl::OutToIn(const CPDF_Rect & rect) const
553 {
554 	CPDF_Point ptLeftBottom = OutToIn(CPDF_Point(rect.left,rect.bottom));
555 	CPDF_Point ptRightTop = OutToIn(CPDF_Point(rect.right,rect.top));
556 
557 	return CPDF_Rect(ptLeftBottom.x,ptLeftBottom.y,ptRightTop.x,ptRightTop.y);
558 }
559 
OnMouseDown(const CPDF_Point & point,FX_BOOL bShift,FX_BOOL bCtrl)560 void CFX_ListCtrl::OnMouseDown(const CPDF_Point & point,FX_BOOL bShift,FX_BOOL bCtrl)
561 {
562 	FX_INT32 nHitIndex = this->GetItemIndex(point);
563 
564 	if (IsMultipleSel())
565 	{
566 		if (bCtrl)
567 		{
568 			if (IsItemSelected(nHitIndex))
569 			{
570 				m_aSelItems.Sub(nHitIndex);
571 				SelectItems();
572 				m_bCtrlSel = FALSE;
573 			}
574 			else
575 			{
576 				m_aSelItems.Add(nHitIndex);
577 				SelectItems();
578 				m_bCtrlSel = TRUE;
579 			}
580 
581 			m_nFootIndex = nHitIndex;
582 		}
583 		else if (bShift)
584 		{
585 			m_aSelItems.DeselectAll();
586 			m_aSelItems.Add(m_nFootIndex,nHitIndex);
587 			SelectItems();
588 		}
589 		else
590 		{
591 			m_aSelItems.DeselectAll();
592 			m_aSelItems.Add(nHitIndex);
593 			SelectItems();
594 
595 			m_nFootIndex = nHitIndex;
596 		}
597 
598 		SetCaret(nHitIndex);
599 	}
600 	else
601 	{
602 		SetSingleSelect(nHitIndex);
603 	}
604 
605 	if (!this->IsItemVisible(nHitIndex))
606 		this->ScrollToListItem(nHitIndex);
607 }
608 
OnMouseMove(const CPDF_Point & point,FX_BOOL bShift,FX_BOOL bCtrl)609 void CFX_ListCtrl::OnMouseMove(const CPDF_Point & point,FX_BOOL bShift,FX_BOOL bCtrl)
610 {
611 	FX_INT32 nHitIndex = this->GetItemIndex(point);
612 
613 	if (IsMultipleSel())
614 	{
615 		if (bCtrl)
616 		{
617 			if (m_bCtrlSel)
618 				m_aSelItems.Add(m_nFootIndex,nHitIndex);
619 			else
620 				m_aSelItems.Sub(m_nFootIndex,nHitIndex);
621 
622 			SelectItems();
623 		}
624 		else
625 		{
626 			m_aSelItems.DeselectAll();
627 			m_aSelItems.Add(m_nFootIndex,nHitIndex);
628 			SelectItems();
629 		}
630 
631 		SetCaret(nHitIndex);
632 	}
633 	else
634 	{
635 		SetSingleSelect(nHitIndex);
636 	}
637 
638 	if (!this->IsItemVisible(nHitIndex))
639 		this->ScrollToListItem(nHitIndex);
640 }
641 
OnVK(FX_INT32 nItemIndex,FX_BOOL bShift,FX_BOOL bCtrl)642 void CFX_ListCtrl::OnVK(FX_INT32 nItemIndex,FX_BOOL bShift,FX_BOOL bCtrl)
643 {
644 	if (IsMultipleSel())
645 	{
646 		if (nItemIndex >= 0 && nItemIndex < GetCount())
647 		{
648 			if (bCtrl)
649 			{
650 			}
651 			else if (bShift)
652 			{
653 				m_aSelItems.DeselectAll();
654 				m_aSelItems.Add(m_nFootIndex,nItemIndex);
655 				SelectItems();
656 			}
657 			else
658 			{
659 				m_aSelItems.DeselectAll();
660 				m_aSelItems.Add(nItemIndex);
661 				SelectItems();
662 				m_nFootIndex = nItemIndex;
663 			}
664 
665 			SetCaret(nItemIndex);
666 		}
667 	}
668 	else
669 	{
670 		SetSingleSelect(nItemIndex);
671 	}
672 
673 	if (!this->IsItemVisible(nItemIndex))
674 		this->ScrollToListItem(nItemIndex);
675 }
676 
OnVK_UP(FX_BOOL bShift,FX_BOOL bCtrl)677 void CFX_ListCtrl::OnVK_UP(FX_BOOL bShift,FX_BOOL bCtrl)
678 {
679 	OnVK(IsMultipleSel() ? GetCaret()-1 : GetSelect()-1, bShift, bCtrl);
680 }
681 
OnVK_DOWN(FX_BOOL bShift,FX_BOOL bCtrl)682 void CFX_ListCtrl::OnVK_DOWN(FX_BOOL bShift,FX_BOOL bCtrl)
683 {
684 	OnVK(IsMultipleSel() ? GetCaret()+1 : GetSelect()+1, bShift, bCtrl);
685 }
686 
OnVK_LEFT(FX_BOOL bShift,FX_BOOL bCtrl)687 void CFX_ListCtrl::OnVK_LEFT(FX_BOOL bShift,FX_BOOL bCtrl)
688 {
689 	OnVK(0, bShift, bCtrl);
690 }
691 
OnVK_RIGHT(FX_BOOL bShift,FX_BOOL bCtrl)692 void CFX_ListCtrl::OnVK_RIGHT(FX_BOOL bShift,FX_BOOL bCtrl)
693 {
694 	OnVK(GetCount()-1, bShift, bCtrl);
695 }
696 
OnVK_HOME(FX_BOOL bShift,FX_BOOL bCtrl)697 void CFX_ListCtrl::OnVK_HOME(FX_BOOL bShift,FX_BOOL bCtrl)
698 {
699 	OnVK(0, bShift, bCtrl);
700 }
701 
OnVK_END(FX_BOOL bShift,FX_BOOL bCtrl)702 void CFX_ListCtrl::OnVK_END(FX_BOOL bShift,FX_BOOL bCtrl)
703 {
704 	OnVK(GetCount()-1, bShift, bCtrl);
705 }
706 
OnChar(FX_WORD nChar,FX_BOOL bShift,FX_BOOL bCtrl)707 FX_BOOL	CFX_ListCtrl::OnChar(FX_WORD nChar,FX_BOOL bShift,FX_BOOL bCtrl)
708 {
709 	FX_INT32 nIndex = GetLastSelected();
710 	FX_INT32 nFindIndex = FindNext(nIndex,nChar);
711 
712 	if (nFindIndex != nIndex)
713 	{
714 		OnVK(nFindIndex, bShift, bCtrl);
715 		return TRUE;
716 	}
717 	return FALSE;
718 }
719 
720 /* -------- inner methods ------- */
721 
SetPlateRect(const CPDF_Rect & rect)722 void CFX_ListCtrl::SetPlateRect(const CPDF_Rect & rect)
723 {
724 	CFX_ListContainer::SetPlateRect(rect);
725 	m_ptScrollPos.x = rect.left;
726 	SetScrollPos(CPDF_Point(rect.left,rect.top));
727 	ReArrange(0);
728 	InvalidateItem(-1);
729 }
730 
GetItemRect(FX_INT32 nIndex) const731 CPDF_Rect CFX_ListCtrl::GetItemRect(FX_INT32 nIndex) const
732 {
733 	return InToOut(CFX_List::GetItemRect(nIndex));
734 }
735 
AddString(FX_LPCWSTR string)736 void CFX_ListCtrl::AddString(FX_LPCWSTR string)
737 {
738 	AddItem(string);
739 	ReArrange(GetCount() - 1);
740 }
741 
SetMultipleSelect(FX_INT32 nItemIndex,FX_BOOL bSelected)742 void CFX_ListCtrl::SetMultipleSelect(FX_INT32 nItemIndex, FX_BOOL bSelected)
743 {
744 	if (!IsValid(nItemIndex)) return;
745 
746 	if (bSelected != this->IsItemSelected(nItemIndex))
747 	{
748 		if (bSelected)
749 		{
750 			SetItemSelect(nItemIndex,TRUE);
751 			InvalidateItem(nItemIndex);
752 		}
753 		else
754 		{
755 			SetItemSelect(nItemIndex,FALSE);
756 			InvalidateItem(nItemIndex);
757 		}
758 	}
759 }
760 
SetSingleSelect(FX_INT32 nItemIndex)761 void CFX_ListCtrl::SetSingleSelect(FX_INT32 nItemIndex)
762 {
763 	if (!IsValid(nItemIndex)) return;
764 
765 	if (m_nSelItem != nItemIndex)
766 	{
767 		if (m_nSelItem >= 0)
768 		{
769 			SetItemSelect(m_nSelItem,FALSE);
770 			InvalidateItem(m_nSelItem);
771 		}
772 
773 		SetItemSelect(nItemIndex,TRUE);
774 		InvalidateItem(nItemIndex);
775 		m_nSelItem = nItemIndex;
776 	}
777 }
778 
SetCaret(FX_INT32 nItemIndex)779 void CFX_ListCtrl::SetCaret(FX_INT32 nItemIndex)
780 {
781 	if (!IsValid(nItemIndex)) return;
782 
783 	if (this->IsMultipleSel())
784 	{
785 		FX_INT32 nOldIndex = m_nCaretIndex;
786 
787 		if (nOldIndex != nItemIndex)
788 		{
789 			m_nCaretIndex = nItemIndex;
790 
791 			SetItemCaret(nOldIndex, FALSE);
792 			SetItemCaret(nItemIndex,TRUE);
793 
794 			InvalidateItem(nOldIndex);
795 			InvalidateItem(nItemIndex);
796 		}
797 	}
798 }
799 
InvalidateItem(FX_INT32 nItemIndex)800 void CFX_ListCtrl::InvalidateItem(FX_INT32 nItemIndex)
801 {
802 	if (m_pNotify)
803 	{
804 		if (nItemIndex == -1)
805 		{
806 			if (!m_bNotifyFlag)
807 			{
808 				m_bNotifyFlag = TRUE;
809 				CPDF_Rect rcRefresh = GetPlateRect();
810 				m_pNotify->IOnInvalidateRect(&rcRefresh);
811 				m_bNotifyFlag = FALSE;
812 			}
813 		}
814 		else
815 		{
816 			if (!m_bNotifyFlag)
817 			{
818 				m_bNotifyFlag = TRUE;
819 				CPDF_Rect rcRefresh = GetItemRect(nItemIndex);
820 				rcRefresh.left -= 1.0f;
821 				rcRefresh.right += 1.0f;
822 				rcRefresh.bottom -= 1.0f;
823 				rcRefresh.top += 1.0f;
824 
825 				m_pNotify->IOnInvalidateRect(&rcRefresh);
826 				m_bNotifyFlag = FALSE;
827 			}
828 		}
829 	}
830 }
831 
SelectItems()832 void CFX_ListCtrl::SelectItems()
833 {
834 	for (FX_INT32 i=0,sz=m_aSelItems.GetCount(); i<sz; i++)
835 	{
836 		FX_INT32 nItemIndex = m_aSelItems.GetItemIndex(i);
837 		FX_INT32 nState = m_aSelItems.GetState(i);
838 
839 		switch(nState)
840 		{
841 		case 1:
842 			SetMultipleSelect(nItemIndex, TRUE);
843 			break;
844 		case -1:
845 			SetMultipleSelect(nItemIndex, FALSE);
846 			break;
847 		}
848 	}
849 
850 	m_aSelItems.Done();
851 }
852 
Select(FX_INT32 nItemIndex)853 void CFX_ListCtrl::Select(FX_INT32 nItemIndex)
854 {
855 	if (!IsValid(nItemIndex)) return;
856 
857 	if (this->IsMultipleSel())
858 	{
859 		m_aSelItems.Add(nItemIndex);
860 		SelectItems();
861 	}
862 	else
863 		SetSingleSelect(nItemIndex);
864 }
865 
IsItemVisible(FX_INT32 nItemIndex) const866 FX_BOOL	CFX_ListCtrl::IsItemVisible(FX_INT32 nItemIndex) const
867 {
868 	CPDF_Rect rcPlate = this->GetPlateRect();
869 	CPDF_Rect rcItem = this->GetItemRect(nItemIndex);
870 
871 	return rcItem.bottom >= rcPlate.bottom && rcItem.top <= rcPlate.top;
872 }
873 
ScrollToListItem(FX_INT32 nItemIndex)874 void CFX_ListCtrl::ScrollToListItem(FX_INT32 nItemIndex)
875 {
876 	if (!IsValid(nItemIndex)) return;
877 
878 	CPDF_Rect rcPlate = this->GetPlateRect();
879 	CPDF_Rect rcItem = CFX_List::GetItemRect(nItemIndex);
880 	CPDF_Rect rcItemCtrl = GetItemRect(nItemIndex);
881 
882 	if (FX_EDIT_IsFloatSmaller(rcItemCtrl.bottom, rcPlate.bottom))
883 	{
884 		if (FX_EDIT_IsFloatSmaller(rcItemCtrl.top, rcPlate.top))
885 		{
886 			SetScrollPosY(rcItem.bottom + rcPlate.Height());
887 		}
888 	}
889 	else if (FX_EDIT_IsFloatBigger(rcItemCtrl.top, rcPlate.top))
890 	{
891 		if (FX_EDIT_IsFloatBigger(rcItemCtrl.bottom, rcPlate.bottom))
892 		{
893 			SetScrollPosY(rcItem.top);
894 		}
895 	}
896 }
897 
SetScrollInfo()898 void CFX_ListCtrl::SetScrollInfo()
899 {
900 	if (m_pNotify)
901 	{
902 		CPDF_Rect rcPlate = GetPlateRect();
903 		CPDF_Rect rcContent = CFX_List::GetContentRect();
904 
905 		if (!m_bNotifyFlag)
906 		{
907 			m_bNotifyFlag = TRUE;
908 			m_pNotify->IOnSetScrollInfoY(rcPlate.bottom, rcPlate.top,
909 					rcContent.bottom, rcContent.top, GetFirstHeight(), rcPlate.Height());
910 			m_bNotifyFlag = FALSE;
911 		}
912 	}
913 }
914 
SetScrollPos(const CPDF_Point & point)915 void CFX_ListCtrl::SetScrollPos(const CPDF_Point & point)
916 {
917 	SetScrollPosY(point.y);
918 }
919 
SetScrollPosY(FX_FLOAT fy)920 void CFX_ListCtrl::SetScrollPosY(FX_FLOAT fy)
921 {
922 	if (!FX_EDIT_IsFloatEqual(m_ptScrollPos.y,fy))
923 	{
924 		CPDF_Rect rcPlate = this->GetPlateRect();
925 		CPDF_Rect rcContent = CFX_List::GetContentRect();
926 
927 		if (rcPlate.Height() > rcContent.Height())
928 		{
929 			fy = rcPlate.top;
930 		}
931 		else
932 		{
933 			if (FX_EDIT_IsFloatSmaller(fy - rcPlate.Height(), rcContent.bottom))
934 			{
935 				fy = rcContent.bottom + rcPlate.Height();
936 			}
937 			else if (FX_EDIT_IsFloatBigger(fy, rcContent.top))
938 			{
939 				fy = rcContent.top;
940 			}
941 		}
942 
943 		m_ptScrollPos.y = fy;
944 		InvalidateItem(-1);
945 
946 		if (m_pNotify)
947 		{
948 			if (!m_bNotifyFlag)
949 			{
950 				m_bNotifyFlag = TRUE;
951 				m_pNotify->IOnSetScrollPosY(fy);
952 				m_bNotifyFlag = FALSE;
953 			}
954 		}
955 	}
956 }
957 
GetContentRect() const958 CPDF_Rect CFX_ListCtrl::GetContentRect() const
959 {
960 	return InToOut(CFX_List::GetContentRect());
961 }
962 
ReArrange(FX_INT32 nItemIndex)963 void CFX_ListCtrl::ReArrange(FX_INT32 nItemIndex)
964 {
965 	CFX_List::ReArrange(nItemIndex);
966 	SetScrollInfo();
967 }
968 
SetTopItem(FX_INT32 nIndex)969 void CFX_ListCtrl::SetTopItem(FX_INT32 nIndex)
970 {
971 	if (IsValid(nIndex))
972 	{
973 		this->GetPlateRect();
974 		CPDF_Rect rcItem = CFX_List::GetItemRect(nIndex);
975 		SetScrollPosY(rcItem.top);
976 	}
977 }
978 
GetTopItem() const979 FX_INT32 CFX_ListCtrl::GetTopItem() const
980 {
981 	FX_INT32 nItemIndex = this->GetItemIndex(this->GetBTPoint());
982 
983 	if (!IsItemVisible(nItemIndex) && IsItemVisible(nItemIndex + 1))
984 			nItemIndex += 1;
985 
986 	return nItemIndex;
987 }
988 
Empty()989 void CFX_ListCtrl::Empty()
990 {
991 	CFX_List::Empty();
992 	InvalidateItem(-1);
993 }
994 
Cancel()995 void CFX_ListCtrl::Cancel()
996 {
997 	m_aSelItems.DeselectAll();
998 }
999 
GetItemIndex(const CPDF_Point & point) const1000 FX_INT32 CFX_ListCtrl::GetItemIndex(const CPDF_Point & point) const
1001 {
1002 	return CFX_List::GetItemIndex(OutToIn(point));
1003 }
1004 
GetText() const1005 CFX_WideString CFX_ListCtrl::GetText() const
1006 {
1007 	if (this->IsMultipleSel())
1008 		return this->GetItemText(this->m_nCaretIndex);
1009 	else
1010 		return this->GetItemText(this->m_nSelItem);
1011 }
1012 
1013