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