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_Button.h"
10#include "../../include/pdfwindow/PWL_EditCtrl.h"
11#include "../../include/pdfwindow/PWL_Edit.h"
12#include "../../include/pdfwindow/PWL_ListCtrl.h"
13#include "../../include/pdfwindow/PWL_ScrollBar.h"
14#include "../../include/pdfwindow/PWL_Note.h"
15#include "../../include/pdfwindow/PWL_Label.h"
16#include "../../include/pdfwindow/PWL_Edit.h"
17#include "../../include/pdfwindow/PWL_ScrollBar.h"
18#include "../../include/pdfwindow/PWL_Utils.h"
19#include "../../include/pdfwindow/PWL_Caret.h"
20
21#define POPUP_ITEM_HEAD_BOTTOM					3.0f
22#define POPUP_ITEM_BOTTOMWIDTH					1.0f
23#define POPUP_ITEM_SIDEMARGIN					3.0f
24#define POPUP_ITEM_SPACE						4.0f
25#define POPUP_ITEM_TEXT_INDENT					2.0f
26#define POPUP_ITEM_BORDERCOLOR					CPWL_Color(COLORTYPE_RGB, 80/255.0f, 80/255.0f, 80/255.0f)
27
28#define IsFloatZero(f)						((f) < 0.0001 && (f) > -0.0001)
29#define IsFloatBigger(fa,fb)				((fa) > (fb) && !IsFloatZero((fa) - (fb)))
30#define IsFloatSmaller(fa,fb)				((fa) < (fb) && !IsFloatZero((fa) - (fb)))
31#define IsFloatEqual(fa,fb)					IsFloatZero((fa)-(fb))
32
33
34/* ------------------------------- CPWL_Note_Options ------------------------------- */
35
36CPWL_Note_Options::CPWL_Note_Options() : m_pText(NULL)
37{
38}
39
40CPWL_Note_Options::~CPWL_Note_Options()
41{
42}
43
44void CPWL_Note_Options::SetTextColor(const CPWL_Color & color)
45{
46	CPWL_Wnd::SetTextColor(color);
47
48	if (m_pText)
49		m_pText->SetTextColor(color);
50}
51
52void CPWL_Note_Options::RePosChildWnd()
53{
54	if (this->IsValid())
55	{
56		ASSERT(m_pText != NULL);
57
58		CPDF_Rect rcClient = GetClientRect();
59
60		if (rcClient.Width() > 15.0f)
61		{
62			rcClient.right -= 15.0f;
63			m_pText->Move(rcClient, TRUE, FALSE);
64			m_pText->SetVisible(TRUE);
65		}
66		else
67		{
68			m_pText->Move(CPDF_Rect(0,0,0,0), TRUE, FALSE);
69			m_pText->SetVisible(FALSE);
70		}
71	}
72}
73
74void CPWL_Note_Options::CreateChildWnd(const PWL_CREATEPARAM & cp)
75{
76	m_pText = new CPWL_Label;
77	PWL_CREATEPARAM tcp = cp;
78	tcp.pParentWnd = this;
79	tcp.dwFlags = PWS_CHILD | PWS_VISIBLE;
80	m_pText->Create(tcp);
81}
82
83void CPWL_Note_Options::SetText(const CFX_WideString& sText)
84{
85	m_pText->SetText(sText);
86}
87
88void CPWL_Note_Options::DrawThisAppearance(CFX_RenderDevice* pDevice, CPDF_Matrix* pUser2Device)
89{
90	CPWL_Wnd::DrawThisAppearance(pDevice, pUser2Device);
91
92	CPDF_Rect rcClient = GetClientRect();
93	rcClient.left = rcClient.right - 15.0f;
94
95	CPDF_Point ptCenter = CPDF_Point((rcClient.left + rcClient.right) * 0.5f, (rcClient.top + rcClient.bottom) * 0.5f);
96
97	CPDF_Point pt1(ptCenter.x - 2.0f, ptCenter.y + 2.0f * 0.5f);
98	CPDF_Point pt2(ptCenter.x + 2.0f, ptCenter.y + 2.0f * 0.5f);
99	CPDF_Point pt3(ptCenter.x, ptCenter.y - 3.0f * 0.5f);
100
101	CFX_PathData path;
102
103	path.SetPointCount(4);
104	path.SetPoint(0, pt1.x, pt1.y, FXPT_MOVETO);
105	path.SetPoint(1, pt2.x, pt2.y, FXPT_LINETO);
106	path.SetPoint(2, pt3.x, pt3.y, FXPT_LINETO);
107	path.SetPoint(3, pt1.x, pt1.y, FXPT_LINETO);
108
109	pDevice->DrawPath(&path, pUser2Device, NULL,
110		CPWL_Utils::PWLColorToFXColor(GetTextColor(),GetTransparency()),
111		0, FXFILL_ALTERNATE);
112}
113
114CPDF_Rect CPWL_Note_Options::GetContentRect() const
115{
116	ASSERT(m_pText != NULL);
117
118	CPDF_Rect rcText = m_pText->GetContentRect();
119	rcText.right += 15.0f;
120	return rcText;
121}
122
123/* ------------------------------- CPWL_Note_Edit ------------------------------ */
124
125CPWL_Note_Edit::CPWL_Note_Edit() : m_bEnableNotify(TRUE),
126	m_fOldItemHeight(0.0f),
127	m_bSizeChanged(FALSE),
128	m_fOldMin(0.0f),
129	m_fOldMax(0.0f)
130{
131}
132
133CPWL_Note_Edit::~CPWL_Note_Edit()
134{
135}
136
137void CPWL_Note_Edit::RePosChildWnd()
138{
139	m_bEnableNotify = FALSE;
140	CPWL_Edit::RePosChildWnd();
141	m_bEnableNotify = TRUE;
142
143	m_fOldItemHeight = this->GetContentRect().Height();
144}
145
146void CPWL_Note_Edit::SetText(FX_LPCWSTR csText)
147{
148	m_bEnableNotify = FALSE;
149	CPWL_Edit::SetText(csText);
150	m_bEnableNotify = TRUE;
151	m_fOldItemHeight = this->GetContentRect().Height();
152}
153
154void CPWL_Note_Edit::OnSetFocus()
155{
156	m_bEnableNotify = FALSE;
157	CPWL_Edit::OnSetFocus();
158	m_bEnableNotify = TRUE;
159
160	this->EnableSpellCheck(TRUE);
161}
162
163void CPWL_Note_Edit::OnKillFocus()
164{
165	this->EnableSpellCheck(FALSE);
166
167	if (CPWL_Wnd* pParent = this->GetParentWindow())
168	{
169		if (CPWL_Wnd* pGrand = pParent->GetParentWindow())
170		{
171			ASSERT(pGrand->GetClassName() == "CPWL_NoteItem");
172
173			CPWL_NoteItem* pNoteItem = (CPWL_NoteItem*)pGrand;
174
175			pNoteItem->OnContentsValidate();
176		}
177	}
178
179	CPWL_Edit::OnKillFocus();
180}
181
182void CPWL_Note_Edit::OnNotify(CPWL_Wnd* pWnd, FX_DWORD msg, FX_INTPTR wParam, FX_INTPTR lParam)
183{
184	if (m_bEnableNotify)
185	{
186		if (wParam == SBT_VSCROLL)
187		{
188			switch (msg)
189			{
190			case PNM_SETSCROLLINFO:
191				if (PWL_SCROLL_INFO* pInfo = (PWL_SCROLL_INFO*)lParam)
192				{
193					if (!IsFloatEqual(pInfo->fContentMax, m_fOldMax) ||
194						!IsFloatEqual(pInfo->fContentMin, m_fOldMin))
195					{
196						m_bSizeChanged = TRUE;
197						if (CPWL_Wnd * pParent = this->GetParentWindow())
198						{
199							pParent->OnNotify(this, PNM_NOTEEDITCHANGED, 0, 0);
200						}
201
202						m_fOldMax = pInfo->fContentMax;
203						m_fOldMin = pInfo->fContentMin;
204						return;
205					}
206				}
207			}
208		}
209	}
210
211	CPWL_Edit::OnNotify(pWnd, msg, wParam, lParam);
212
213	if (m_bEnableNotify)
214	{
215		switch (msg)
216		{
217		case PNM_SETCARETINFO:
218			if (PWL_CARET_INFO * pInfo = (PWL_CARET_INFO*)wParam)
219			{
220				PWL_CARET_INFO newInfo = *pInfo;
221				newInfo.bVisible = TRUE;
222				newInfo.ptHead = this->ChildToParent(pInfo->ptHead);
223				newInfo.ptFoot = this->ChildToParent(pInfo->ptFoot);
224
225				if (CPWL_Wnd * pParent = this->GetParentWindow())
226				{
227					pParent->OnNotify(this, PNM_SETCARETINFO, (FX_INTPTR)&newInfo, 0);
228				}
229			}
230			break;
231		}
232	}
233}
234
235FX_FLOAT CPWL_Note_Edit::GetItemHeight(FX_FLOAT fLimitWidth)
236{
237	if (fLimitWidth > 0)
238	{
239		if (!m_bSizeChanged)
240			return m_fOldItemHeight;
241
242		m_bSizeChanged = FALSE;
243
244		this->EnableNotify(FALSE);
245		this->EnableRefresh(FALSE);
246		m_pEdit->EnableNotify(FALSE);
247
248		//CPDF_Rect rcOld = this->GetWindowRect();
249
250		this->Move(CPDF_Rect(0,0,fLimitWidth,0), TRUE, FALSE);
251		FX_FLOAT fRet = this->GetContentRect().Height();
252
253		//this->Move(rcOld, TRUE, FALSE);
254
255		m_pEdit->EnableNotify(TRUE);
256		this->EnableNotify(TRUE);
257		this->EnableRefresh(TRUE);
258
259		return fRet;
260	}
261
262	return 0;
263}
264
265FX_FLOAT CPWL_Note_Edit::GetItemLeftMargin()
266{
267	return POPUP_ITEM_TEXT_INDENT;
268}
269
270FX_FLOAT CPWL_Note_Edit::GetItemRightMargin()
271{
272	return POPUP_ITEM_TEXT_INDENT;
273}
274
275/* -------------------------------- CPWL_Note_LBBox --------------------------------*/
276
277CPWL_Note_LBBox::CPWL_Note_LBBox()
278{
279}
280
281CPWL_Note_LBBox::~CPWL_Note_LBBox()
282{
283}
284
285void CPWL_Note_LBBox::DrawThisAppearance(CFX_RenderDevice* pDevice, CPDF_Matrix* pUser2Device)
286{
287	CPDF_Rect rcClient = this->GetClientRect();
288
289	CFX_GraphStateData gsd;
290	gsd.m_LineWidth = 1.0f;
291
292	CFX_PathData pathCross;
293
294	pathCross.SetPointCount(4);
295	pathCross.SetPoint(0, rcClient.left, rcClient.top, FXPT_MOVETO);
296	pathCross.SetPoint(1, rcClient.right, rcClient.bottom, FXPT_LINETO);
297	pathCross.SetPoint(2, rcClient.left, rcClient.bottom + rcClient.Height() * 0.5f, FXPT_MOVETO);
298	pathCross.SetPoint(3, rcClient.left + rcClient.Width() * 0.5f, rcClient.bottom, FXPT_LINETO);
299
300	pDevice->DrawPath(&pathCross, pUser2Device, &gsd,
301		0, CPWL_Utils::PWLColorToFXColor(GetTextColor(),this->GetTransparency()), FXFILL_ALTERNATE);
302}
303
304/* -------------------------------- CPWL_Note_RBBox --------------------------------*/
305
306CPWL_Note_RBBox::CPWL_Note_RBBox()
307{
308}
309
310CPWL_Note_RBBox::~CPWL_Note_RBBox()
311{
312}
313
314void CPWL_Note_RBBox::DrawThisAppearance(CFX_RenderDevice* pDevice, CPDF_Matrix* pUser2Device)
315{
316	CPDF_Rect rcClient = this->GetClientRect();
317
318	CFX_GraphStateData gsd;
319	gsd.m_LineWidth = 1.0f;
320
321	CFX_PathData pathCross;
322
323	pathCross.SetPointCount(4);
324	pathCross.SetPoint(0, rcClient.right, rcClient.top, FXPT_MOVETO);
325	pathCross.SetPoint(1, rcClient.left, rcClient.bottom, FXPT_LINETO);
326	pathCross.SetPoint(2, rcClient.right, rcClient.bottom + rcClient.Height() * 0.5f, FXPT_MOVETO);
327	pathCross.SetPoint(3, rcClient.left + rcClient.Width() * 0.5f, rcClient.bottom, FXPT_LINETO);
328
329	pDevice->DrawPath(&pathCross, pUser2Device, &gsd,
330		0, CPWL_Utils::PWLColorToFXColor(GetTextColor(),this->GetTransparency()), FXFILL_ALTERNATE);
331}
332
333/* --------------------------------- CPWL_Note_Icon ---------------------------------- */
334
335CPWL_Note_Icon::CPWL_Note_Icon() : m_nType(0)
336{
337}
338
339CPWL_Note_Icon::~CPWL_Note_Icon()
340{
341}
342
343void CPWL_Note_Icon::SetIconType(FX_INT32 nType)
344{
345	m_nType = nType;
346}
347
348void CPWL_Note_Icon::DrawThisAppearance(CFX_RenderDevice* pDevice, CPDF_Matrix* pUser2Device)
349{
350	CPWL_Utils::DrawIconAppStream(pDevice, pUser2Device, m_nType, GetClientRect(),
351		this->GetBackgroundColor(), PWL_DEFAULT_BLACKCOLOR, this->GetTransparency());
352}
353
354/* --------------------------------- CPWL_Note_CloseBox ---------------------------------- */
355
356CPWL_Note_CloseBox::CPWL_Note_CloseBox() : m_bMouseDown(FALSE)
357{
358}
359
360CPWL_Note_CloseBox::~CPWL_Note_CloseBox()
361{
362}
363
364void CPWL_Note_CloseBox::DrawThisAppearance(CFX_RenderDevice* pDevice, CPDF_Matrix* pUser2Device)
365{
366	CPWL_Button::DrawThisAppearance(pDevice, pUser2Device);
367
368	CPDF_Rect rcClient = this->GetClientRect();
369	rcClient = CPWL_Utils::DeflateRect(rcClient, 2.0f);
370
371	CFX_GraphStateData gsd;
372	gsd.m_LineWidth = 1.0f;
373
374	CFX_PathData pathCross;
375
376	if (m_bMouseDown)
377	{
378		rcClient.left += 0.5f;
379		rcClient.right += 0.5f;
380		rcClient.top -= 0.5f;
381		rcClient.bottom -= 0.5f;
382	}
383
384	pathCross.SetPointCount(4);
385	pathCross.SetPoint(0, rcClient.left, rcClient.bottom, FXPT_MOVETO);
386	pathCross.SetPoint(1, rcClient.right, rcClient.top, FXPT_LINETO);
387	pathCross.SetPoint(2, rcClient.left, rcClient.top, FXPT_MOVETO);
388	pathCross.SetPoint(3, rcClient.right, rcClient.bottom, FXPT_LINETO);
389
390	pDevice->DrawPath(&pathCross, pUser2Device, &gsd,
391		0, CPWL_Utils::PWLColorToFXColor(GetTextColor(),this->GetTransparency()), FXFILL_ALTERNATE);
392}
393
394FX_BOOL CPWL_Note_CloseBox::OnLButtonDown(const CPDF_Point & point, FX_DWORD nFlag)
395{
396	SetBorderStyle(PBS_INSET);
397	InvalidateRect(NULL);
398
399	m_bMouseDown = TRUE;
400
401	return CPWL_Button::OnLButtonDown(point,nFlag);
402}
403
404FX_BOOL	CPWL_Note_CloseBox::OnLButtonUp(const CPDF_Point & point, FX_DWORD nFlag)
405{
406	m_bMouseDown = FALSE;
407
408	SetBorderStyle(PBS_BEVELED);
409	InvalidateRect(NULL);
410
411	return CPWL_Button::OnLButtonUp(point,nFlag);
412}
413
414/* ------------------------------ CPWL_Note_Contents ------------------------------- */
415
416CPWL_Note_Contents::CPWL_Note_Contents() : m_pEdit(NULL)
417{
418}
419
420CPWL_Note_Contents::~CPWL_Note_Contents()
421{
422}
423
424CFX_ByteString CPWL_Note_Contents::GetClassName() const
425{
426	return "CPWL_Note_Contents";
427}
428
429void CPWL_Note_Contents::CreateChildWnd(const PWL_CREATEPARAM & cp)
430{
431	m_pEdit = new CPWL_Note_Edit;
432	PWL_CREATEPARAM ecp = cp;
433	ecp.pParentWnd = this;
434	ecp.dwFlags = PWS_VISIBLE | PWS_CHILD | PES_MULTILINE | PES_AUTORETURN | PES_TEXTOVERFLOW | PES_UNDO | PES_SPELLCHECK;
435
436	m_pEdit->EnableNotify(FALSE);
437	m_pEdit->Create(ecp);
438	m_pEdit->EnableNotify(TRUE);
439}
440
441void CPWL_Note_Contents::SetText(const CFX_WideString& sText)
442{
443	if (m_pEdit)
444	{
445		m_pEdit->EnableNotify(FALSE);
446		m_pEdit->SetText(sText);
447		m_pEdit->EnableNotify(TRUE);
448		OnNotify(m_pEdit, PNM_NOTEEDITCHANGED, 0, 0);
449	}
450}
451
452CFX_WideString CPWL_Note_Contents::GetText() const
453{
454	if (m_pEdit)
455		return m_pEdit->GetText();
456
457	return L"";
458}
459
460CPWL_NoteItem* CPWL_Note_Contents::CreateSubItem()
461{
462	CPWL_NoteItem* pNoteItem = new CPWL_NoteItem;
463	PWL_CREATEPARAM icp = this->GetCreationParam();
464	icp.pParentWnd = this;
465	icp.dwFlags =  PWS_CHILD | PWS_VISIBLE | PWS_BACKGROUND;
466	pNoteItem->Create(icp);
467
468	pNoteItem->OnCreateNoteItem();
469
470	pNoteItem->ResetSubjectName(m_aChildren.GetSize() - 1);
471
472	FX_SYSTEMTIME st;
473	if (IFX_SystemHandler* pSH = this->GetSystemHandler())
474		st = pSH->GetLocalTime();
475	pNoteItem->SetDateTime(st);
476
477	pNoteItem->SetContents(L"");
478
479	this->OnNotify(pNoteItem, PNM_NOTEEDITCHANGED, 0, 0);
480
481	return pNoteItem;
482}
483
484FX_INT32 CPWL_Note_Contents::CountSubItems() const
485{
486	return m_aChildren.GetSize() - 1;
487}
488
489IPWL_NoteItem* CPWL_Note_Contents::GetSubItems(FX_INT32 index) const
490{
491	FX_INT32 nIndex = index + 1;
492
493	if (nIndex > 0 && nIndex < m_aChildren.GetSize())
494		if (CPWL_Wnd* pChild = m_aChildren.GetAt(nIndex))
495		{
496			ASSERT(pChild->GetClassName() == "CPWL_NoteItem");
497			CPWL_NoteItem* pItem = (CPWL_NoteItem*)pChild;
498			return pItem;
499		}
500	return NULL;
501}
502
503void CPWL_Note_Contents::DeleteSubItem(IPWL_NoteItem* pNoteItem)
504{
505	FX_INT32 nIndex = this->GetItemIndex((CPWL_NoteItem*)pNoteItem);
506
507	if (nIndex > 0)
508	{
509		if (CPWL_NoteItem* pPWLNoteItem = (CPWL_NoteItem*)pNoteItem)
510		{
511			pPWLNoteItem->KillFocus();
512			pPWLNoteItem->Destroy();
513			delete pPWLNoteItem;
514		}
515
516		for (FX_INT32 i=nIndex,sz=m_aChildren.GetSize(); i<sz; i++)
517		{
518			if (CPWL_Wnd* pChild = m_aChildren.GetAt(i))
519			{
520				ASSERT(pChild->GetClassName() == "CPWL_NoteItem");
521				CPWL_NoteItem* pItem = (CPWL_NoteItem*)pChild;
522				pItem->ResetSubjectName(i);
523			}
524		}
525
526		this->OnNotify(this, PNM_NOTEEDITCHANGED, 0, 0);
527	}
528}
529
530IPWL_NoteItem* CPWL_Note_Contents::GetHitNoteItem(const CPDF_Point& point)
531{
532	CPDF_Point pt = this->ParentToChild(point);
533
534	for (FX_INT32 i=0,sz=m_aChildren.GetSize(); i<sz; i++)
535	{
536		if (CPWL_Wnd* pChild = m_aChildren.GetAt(i))
537		{
538			if (pChild->GetClassName() == "CPWL_NoteItem")
539			{
540				CPWL_NoteItem* pNoteItem = (CPWL_NoteItem*)pChild;
541				if (IPWL_NoteItem* pRet = pNoteItem->GetHitNoteItem(pt))
542					return pRet;
543			}
544		}
545	}
546	return NULL;
547}
548
549void CPWL_Note_Contents::OnNotify(CPWL_Wnd* pWnd, FX_DWORD msg, FX_INTPTR wParam, FX_INTPTR lParam)
550{
551	switch (msg)
552	{
553	case PNM_NOTEEDITCHANGED:
554		{
555			FX_INT32 nIndex = this->GetItemIndex(pWnd);
556			if (nIndex < 0) nIndex = 0;
557
558			m_pEdit->EnableNotify(FALSE);
559			this->ResetContent(nIndex);
560			m_pEdit->EnableNotify(TRUE);
561
562			for (FX_INT32 i=nIndex+1, sz=m_aChildren.GetSize(); i<sz; i++)
563			{
564				if (CPWL_Wnd* pChild = m_aChildren.GetAt(i))
565					pChild->OnNotify(this, PNM_NOTERESET, 0, 0);
566			}
567
568			if (CPWL_Wnd * pParent = this->GetParentWindow())
569			{
570				pParent->OnNotify(this, PNM_NOTEEDITCHANGED, 0, 0);
571			}
572		}
573		return;
574	case PNM_SCROLLWINDOW:
575		this->SetScrollPos(CPDF_Point(0.0f, *(FX_FLOAT*)lParam));
576		this->ResetFace();
577		InvalidateRect(NULL);
578		return;
579	case PNM_SETCARETINFO:
580		if (PWL_CARET_INFO * pInfo = (PWL_CARET_INFO*)wParam)
581		{
582			PWL_CARET_INFO newInfo = *pInfo;
583			newInfo.bVisible = TRUE;
584			newInfo.ptHead = this->ChildToParent(pInfo->ptHead);
585			newInfo.ptFoot = this->ChildToParent(pInfo->ptFoot);
586
587			if (CPWL_Wnd * pParent = this->GetParentWindow())
588			{
589				pParent->OnNotify(this, PNM_SETCARETINFO, (FX_INTPTR)&newInfo, 0);
590			}
591		}
592		return;
593	case PNM_NOTERESET:
594		{
595			m_pEdit->EnableNotify(FALSE);
596			this->ResetContent(0);
597			m_pEdit->EnableNotify(TRUE);
598
599			for (FX_INT32 i=1, sz=m_aChildren.GetSize(); i<sz; i++)
600			{
601				if (CPWL_Wnd* pChild = m_aChildren.GetAt(i))
602					pChild->OnNotify(this, PNM_NOTERESET, 0, 0);
603			}
604
605			m_pEdit->EnableNotify(FALSE);
606			this->ResetContent(0);
607			m_pEdit->EnableNotify(TRUE);
608		}
609		return;
610	}
611
612	CPWL_Wnd::OnNotify(pWnd, msg, wParam, lParam);
613}
614
615FX_BOOL	CPWL_Note_Contents::OnLButtonDown(const CPDF_Point & point, FX_DWORD nFlag)
616{
617	if (CPWL_Wnd::OnLButtonDown(point,nFlag)) return TRUE;
618
619	if (!m_pEdit->IsFocused())
620	{
621		m_pEdit->SetFocus();
622	}
623
624	return TRUE;
625}
626
627void CPWL_Note_Contents::SetEditFocus(FX_BOOL bLast)
628{
629	if (!m_pEdit->IsFocused())
630	{
631		m_pEdit->SetFocus();
632		m_pEdit->SetCaret(bLast ? m_pEdit->GetTotalWords() : 0);
633	}
634}
635
636CPWL_Edit* CPWL_Note_Contents::GetEdit() const
637{
638	return m_pEdit;
639}
640
641void CPWL_Note_Contents::EnableModify(FX_BOOL bEnabled)
642{
643	if (!bEnabled)
644		m_pEdit->AddFlag(PWS_READONLY);
645	else
646		m_pEdit->RemoveFlag(PWS_READONLY);
647
648	for (FX_INT32 i=0,sz=m_aChildren.GetSize(); i<sz; i++)
649	{
650		if (CPWL_Wnd* pChild = m_aChildren.GetAt(i))
651		{
652			if (pChild->GetClassName() == "CPWL_NoteItem")
653			{
654				CPWL_NoteItem* pNoteItem = (CPWL_NoteItem*)pChild;
655				pNoteItem->EnableModify(bEnabled);
656			}
657		}
658	}
659}
660
661void CPWL_Note_Contents::EnableRead(FX_BOOL bEnabled)
662{
663	if (!bEnabled)
664		m_pEdit->AddFlag(PES_NOREAD);
665	else
666		m_pEdit->RemoveFlag(PES_NOREAD);
667
668	for (FX_INT32 i=0,sz=m_aChildren.GetSize(); i<sz; i++)
669	{
670		if (CPWL_Wnd* pChild = m_aChildren.GetAt(i))
671		{
672			if (pChild->GetClassName() == "CPWL_NoteItem")
673			{
674				CPWL_NoteItem* pNoteItem = (CPWL_NoteItem*)pChild;
675				pNoteItem->EnableRead(bEnabled);
676			}
677		}
678	}
679}
680
681/* ---------------------------------- CPWL_NoteItem ---------------------------------- */
682
683CPWL_NoteItem::CPWL_NoteItem() :
684	m_pPrivateData(NULL),
685	m_pSubject(NULL),
686	m_pDateTime(NULL),
687	m_pContents(NULL),
688	m_sAuthor(L""),
689	m_fOldItemHeight(0.0f),
690	m_bSizeChanged(FALSE),
691	m_bAllowModify(TRUE)
692{
693}
694
695CPWL_NoteItem::~CPWL_NoteItem()
696{
697}
698
699CFX_ByteString CPWL_NoteItem::GetClassName() const
700{
701	return "CPWL_NoteItem";
702}
703
704void CPWL_NoteItem::CreateChildWnd(const PWL_CREATEPARAM & cp)
705{
706	CPWL_Color sTextColor;
707
708	if (CPWL_Utils::IsBlackOrWhite(this->GetBackgroundColor()))
709		sTextColor = PWL_DEFAULT_WHITECOLOR;
710	else
711		sTextColor = PWL_DEFAULT_BLACKCOLOR;
712
713	m_pSubject = new CPWL_Label;
714	PWL_CREATEPARAM scp = cp;
715	scp.pParentWnd = this;
716	scp.dwFlags = PWS_VISIBLE | PWS_CHILD | PES_LEFT | PES_TOP;
717	scp.sTextColor = sTextColor;
718	m_pSubject->Create(scp);
719
720	m_pDateTime = new CPWL_Label;
721	PWL_CREATEPARAM dcp = cp;
722	dcp.pParentWnd = this;
723	dcp.dwFlags = PWS_VISIBLE | PWS_CHILD | PES_RIGHT | PES_TOP;
724	dcp.sTextColor = sTextColor;
725	m_pDateTime->Create(dcp);
726
727	m_pContents = new CPWL_Note_Contents;
728	PWL_CREATEPARAM ccp = cp;
729	ccp.pParentWnd = this;
730	//ccp.sBackgroundColor = PWL_DEFAULT_WHITECOLOR;
731	ccp.sBackgroundColor = CPWL_Color(COLORTYPE_RGB, 240/255.0f, 240/255.0f, 240/255.0f);
732	ccp.dwFlags = PWS_VISIBLE | PWS_CHILD | PWS_BACKGROUND;
733	m_pContents->Create(ccp);
734	m_pContents->SetItemSpace(POPUP_ITEM_SPACE);
735	m_pContents->SetTopSpace(POPUP_ITEM_SPACE);
736	m_pContents->SetBottomSpace(POPUP_ITEM_SPACE);
737}
738
739void CPWL_NoteItem::RePosChildWnd()
740{
741	if (this->IsValid())
742	{
743		ASSERT(m_pSubject != NULL);
744		ASSERT(m_pDateTime != NULL);
745		ASSERT(m_pContents != NULL);
746
747		CPDF_Rect rcClient = GetClientRect();
748
749		CPDF_Rect rcSubject = rcClient;
750		rcSubject.left += POPUP_ITEM_TEXT_INDENT;
751		rcSubject.top = rcClient.top;
752		rcSubject.right = PWL_MIN(rcSubject.left + m_pSubject->GetContentRect().Width() + 1.0f, rcClient.right);
753		rcSubject.bottom = rcSubject.top - m_pSubject->GetContentRect().Height();
754		rcSubject.Normalize();
755		m_pSubject->Move(rcSubject, TRUE, FALSE);
756		m_pSubject->SetVisible(CPWL_Utils::ContainsRect(rcClient, rcSubject));
757
758		CPDF_Rect rcDate = rcClient;
759		rcDate.right -= POPUP_ITEM_TEXT_INDENT;
760		rcDate.left = PWL_MAX(rcDate.right - m_pDateTime->GetContentRect().Width() - 1.0f, rcSubject.right);
761		rcDate.bottom = rcDate.top - m_pDateTime->GetContentRect().Height();
762		rcDate.Normalize();
763		m_pDateTime->Move(rcDate, TRUE, FALSE);
764		m_pDateTime->SetVisible(CPWL_Utils::ContainsRect(rcClient, rcDate));
765
766		CPDF_Rect rcContents = rcClient;
767		rcContents.left += 1.0f;
768		rcContents.right -= 1.0f;
769		rcContents.top = rcDate.bottom - POPUP_ITEM_HEAD_BOTTOM;
770		rcContents.bottom += POPUP_ITEM_BOTTOMWIDTH;
771		rcContents.Normalize();
772		m_pContents->Move(rcContents, TRUE, FALSE);
773		m_pContents->SetVisible(CPWL_Utils::ContainsRect(rcClient, rcContents));
774	}
775
776	SetClipRect(CPWL_Utils::InflateRect(GetWindowRect(),1.0f));
777}
778
779void CPWL_NoteItem::SetPrivateData(void* pData)
780{
781	m_pPrivateData = pData;
782}
783
784void CPWL_NoteItem::SetBkColor(const CPWL_Color& color)
785{
786	CPWL_Color sBK = color;
787	this->SetBackgroundColor(sBK);
788
789	CPWL_Color sTextColor;
790
791	if (CPWL_Utils::IsBlackOrWhite(sBK))
792		sTextColor = PWL_DEFAULT_WHITECOLOR;
793	else
794		sTextColor = PWL_DEFAULT_BLACKCOLOR;
795
796	this->SetTextColor(sTextColor);
797	if (m_pSubject)
798		m_pSubject->SetTextColor(sTextColor);
799	if (m_pDateTime)
800		m_pDateTime->SetTextColor(sTextColor);
801
802	this->InvalidateRect(NULL);
803
804	if (IPWL_NoteNotify* pNotify = GetNoteNotify())
805	{
806		pNotify->OnSetBkColor(this);
807	}
808}
809
810void CPWL_NoteItem::SetSubjectName(const CFX_WideString& sName)
811{
812	if (m_pSubject)
813	{
814		m_pSubject->SetText(sName);
815	}
816
817	if (IPWL_NoteNotify* pNotify = GetNoteNotify())
818	{
819		pNotify->OnSetSubjectName(this);
820	}
821}
822
823void CPWL_NoteItem::SetAuthorName(const CFX_WideString& sName)
824{
825	m_sAuthor = sName;
826	ResetSubjectName(-1);
827
828	if (IPWL_NoteNotify* pNotify = GetNoteNotify())
829	{
830		pNotify->OnSetAuthorName(this);
831	}
832}
833
834void CPWL_NoteItem::ResetSubjectName(FX_INT32 nItemIndex)
835{
836	if (nItemIndex < 0)
837	{
838		if (CPWL_Wnd* pParent = this->GetParentWindow())
839		{
840			ASSERT(pParent->GetClassName() == "CPWL_Note_Contents");
841
842			CPWL_Note_Contents* pContents = (CPWL_Note_Contents*)pParent;
843			nItemIndex = pContents->GetItemIndex(this);
844		}
845	}
846
847	const CPWL_Note* pNote = GetNote();
848	ASSERT(pNote != NULL);
849
850	CFX_WideString sSubject;
851	sSubject.Format(pNote->GetReplyString(), nItemIndex);
852
853	if (!m_sAuthor.IsEmpty())
854	{
855
856		sSubject += L" - ";
857		sSubject += m_sAuthor;
858	}
859	this->SetSubjectName(sSubject);
860	this->RePosChildWnd();
861}
862
863void CPWL_NoteItem::SetDateTime(FX_SYSTEMTIME time)
864{
865	m_dtNote = time;
866
867	CFX_WideString swTime;
868	swTime.Format((FX_LPCWSTR)L"%04d-%02d-%02d %02d:%02d:%02d", time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond);
869	if (m_pDateTime)
870	{
871		m_pDateTime->SetText(swTime);
872	}
873
874	this->RePosChildWnd();
875
876	if (IPWL_NoteNotify* pNotify = GetNoteNotify())
877	{
878		pNotify->OnSetDateTime(this);
879	}
880}
881
882void CPWL_NoteItem::SetContents(const CFX_WideString& sContents)
883{
884	if (m_pContents)
885	{
886		m_pContents->SetText(sContents);
887	}
888
889	if (IPWL_NoteNotify* pNotify = GetNoteNotify())
890	{
891		pNotify->OnSetContents(this);
892	}
893}
894
895CPWL_NoteItem* CPWL_NoteItem::GetParentNoteItem() const
896{
897	if (CPWL_Wnd* pParent = this->GetParentWindow())
898	{
899		if (CPWL_Wnd* pGrand = pParent->GetParentWindow())
900		{
901			ASSERT(pGrand->GetClassName() == "CPWL_NoteItem");
902			return (CPWL_NoteItem*)pGrand;
903		}
904	}
905
906	return NULL;
907}
908
909IPWL_NoteItem* CPWL_NoteItem::GetParentItem() const
910{
911	return GetParentNoteItem();
912}
913
914CPWL_Edit* CPWL_NoteItem::GetEdit() const
915{
916	if (m_pContents)
917		return m_pContents->GetEdit();
918	return NULL;
919}
920
921void* CPWL_NoteItem::GetPrivateData() const
922{
923	return m_pPrivateData;
924}
925
926CFX_WideString CPWL_NoteItem::GetAuthorName() const
927{
928	return m_sAuthor;
929}
930
931CPWL_Color CPWL_NoteItem::GetBkColor() const
932{
933	return this->GetBackgroundColor();
934}
935
936CFX_WideString CPWL_NoteItem::GetContents() const
937{
938	if (m_pContents)
939		return m_pContents->GetText();
940
941	return L"";
942}
943
944FX_SYSTEMTIME CPWL_NoteItem::GetDateTime() const
945{
946	return m_dtNote;
947}
948
949CFX_WideString CPWL_NoteItem::GetSubjectName() const
950{
951	if (m_pSubject)
952		return m_pSubject->GetText();
953
954	return L"";
955}
956
957CPWL_NoteItem* CPWL_NoteItem::CreateNoteItem()
958{
959	if (m_pContents)
960		return m_pContents->CreateSubItem();
961
962	return NULL;
963}
964
965IPWL_NoteItem* CPWL_NoteItem::CreateSubItem()
966{
967	return CreateNoteItem();
968}
969
970FX_INT32 CPWL_NoteItem::CountSubItems() const
971{
972	if (m_pContents)
973		return m_pContents->CountSubItems();
974
975	return 0;
976}
977
978IPWL_NoteItem* CPWL_NoteItem::GetSubItems(FX_INT32 index) const
979{
980	if (m_pContents)
981		return m_pContents->GetSubItems(index);
982
983	return NULL;
984}
985
986void CPWL_NoteItem::DeleteSubItem(IPWL_NoteItem* pNoteItem)
987{
988	this->KillFocus();
989
990	if (IPWL_NoteNotify* pNotify = GetNoteNotify())
991	{
992		pNotify->OnItemDelete(pNoteItem);
993	}
994
995	if (m_pContents)
996		m_pContents->DeleteSubItem(pNoteItem);
997}
998
999IPWL_NoteItem* CPWL_NoteItem::GetHitNoteItem(const CPDF_Point& point)
1000{
1001	CPDF_Point pt = this->ParentToChild(point);
1002
1003	if (this->WndHitTest(pt))
1004	{
1005		if (m_pContents)
1006		{
1007			if (IPWL_NoteItem* pNoteItem = m_pContents->GetHitNoteItem(pt))
1008				return pNoteItem;
1009		}
1010
1011		return this;
1012	}
1013
1014	return NULL;
1015}
1016
1017IPWL_NoteItem* CPWL_NoteItem::GetFocusedNoteItem() const
1018{
1019	if (const CPWL_Wnd* pWnd = this->GetFocused())
1020	{
1021		if (pWnd->GetClassName() == "CPWL_Edit")
1022		{
1023			if (CPWL_Wnd* pParent = pWnd->GetParentWindow())
1024			{
1025				ASSERT(pParent->GetClassName() == "CPWL_Note_Contents");
1026
1027				if (CPWL_Wnd* pGrand = pParent->GetParentWindow())
1028				{
1029					ASSERT(pGrand->GetClassName() == "CPWL_NoteItem");
1030					return (CPWL_NoteItem*)pGrand;
1031				}
1032			}
1033		}
1034	}
1035
1036	return NULL;
1037}
1038
1039FX_FLOAT CPWL_NoteItem::GetItemHeight(FX_FLOAT fLimitWidth)
1040{
1041	if (fLimitWidth > 0)
1042	{
1043		if (!m_bSizeChanged)
1044			return m_fOldItemHeight;
1045
1046		m_bSizeChanged = FALSE;
1047
1048		ASSERT(m_pSubject != NULL);
1049		ASSERT(m_pDateTime != NULL);
1050		ASSERT(m_pContents != NULL);
1051
1052		FX_FLOAT fRet = m_pDateTime->GetContentRect().Height();
1053		FX_FLOAT fBorderWidth = (FX_FLOAT)this->GetBorderWidth();
1054		if (fLimitWidth > fBorderWidth * 2)
1055			fRet += m_pContents->GetContentsHeight(fLimitWidth - fBorderWidth * 2);
1056		fRet += POPUP_ITEM_HEAD_BOTTOM + POPUP_ITEM_BOTTOMWIDTH + fBorderWidth * 2;
1057
1058		return m_fOldItemHeight = fRet;
1059	}
1060
1061	return 0;
1062}
1063
1064FX_FLOAT CPWL_NoteItem::GetItemLeftMargin()
1065{
1066	return POPUP_ITEM_SIDEMARGIN;
1067}
1068
1069FX_FLOAT CPWL_NoteItem::GetItemRightMargin()
1070{
1071	return POPUP_ITEM_SIDEMARGIN;
1072}
1073
1074FX_BOOL	CPWL_NoteItem::OnLButtonDown(const CPDF_Point& point, FX_DWORD nFlag)
1075{
1076	if (!m_pContents->WndHitTest(m_pContents->ParentToChild(point)))
1077	{
1078		SetNoteFocus(FALSE);
1079	}
1080
1081	CPWL_Wnd::OnLButtonDown(point,nFlag);
1082
1083	return TRUE;
1084}
1085
1086FX_BOOL	CPWL_NoteItem::OnRButtonUp(const CPDF_Point & point, FX_DWORD nFlag)
1087{
1088	if (!m_pContents->WndHitTest(m_pContents->ParentToChild(point)))
1089	{
1090		SetNoteFocus(FALSE);
1091		PopupNoteItemMenu(point);
1092
1093		return TRUE;
1094	}
1095
1096	return CPWL_Wnd::OnRButtonUp(point,nFlag);
1097}
1098
1099void CPWL_NoteItem::OnNotify(CPWL_Wnd* pWnd, FX_DWORD msg, FX_INTPTR wParam, FX_INTPTR lParam)
1100{
1101	switch (msg)
1102	{
1103	case PNM_NOTEEDITCHANGED:
1104		m_bSizeChanged = TRUE;
1105
1106		if (CPWL_Wnd* pParent = this->GetParentWindow())
1107		{
1108			pParent->OnNotify(this, PNM_NOTEEDITCHANGED, 0, 0);
1109		}
1110		return;
1111	case PNM_SETCARETINFO:
1112		if (PWL_CARET_INFO * pInfo = (PWL_CARET_INFO*)wParam)
1113		{
1114			PWL_CARET_INFO newInfo = *pInfo;
1115			newInfo.bVisible = TRUE;
1116			newInfo.ptHead = this->ChildToParent(pInfo->ptHead);
1117			newInfo.ptFoot = this->ChildToParent(pInfo->ptFoot);
1118
1119			if (CPWL_Wnd * pParent = this->GetParentWindow())
1120			{
1121				pParent->OnNotify(this, PNM_SETCARETINFO, (FX_INTPTR)&newInfo, 0);
1122			}
1123		}
1124		return;
1125	case PNM_NOTERESET:
1126		m_bSizeChanged = TRUE;
1127		m_pContents->OnNotify(this, PNM_NOTERESET, 0, 0);
1128
1129		return;
1130	}
1131
1132	CPWL_Wnd::OnNotify(pWnd, msg, wParam, lParam);
1133}
1134
1135void CPWL_NoteItem::PopupNoteItemMenu(const CPDF_Point& point)
1136{
1137	if (IPWL_NoteNotify* pNotify = GetNoteNotify())
1138	{
1139		FX_INT32 x,y;
1140		PWLtoWnd(point, x, y);
1141		if (IFX_SystemHandler* pSH = GetSystemHandler())
1142			pSH->ClientToScreen(GetAttachedHWnd(), x, y);
1143		pNotify->OnPopupMenu(this, x, y);
1144	}
1145}
1146
1147const CPWL_Note* CPWL_NoteItem::GetNote() const
1148{
1149	if (const CPWL_Wnd* pRoot = this->GetRootWnd())
1150	{
1151		ASSERT(pRoot->GetClassName() == "CPWL_NoteItem");
1152		CPWL_NoteItem* pNoteItem = (CPWL_NoteItem*)pRoot;
1153		if (pNoteItem->IsTopItem())
1154		{
1155			return (CPWL_Note*)pNoteItem;
1156		}
1157	}
1158
1159	return NULL;
1160}
1161
1162IPWL_NoteNotify* CPWL_NoteItem::GetNoteNotify() const
1163{
1164	if (const CPWL_Note* pNote = GetNote())
1165		return pNote->GetNoteNotify();
1166
1167	return NULL;
1168}
1169
1170void CPWL_NoteItem::OnCreateNoteItem()
1171{
1172	if (IPWL_NoteNotify* pNotify = GetNoteNotify())
1173	{
1174		pNotify->OnItemCreate(this);
1175	}
1176}
1177
1178void CPWL_NoteItem::OnContentsValidate()
1179{
1180	if (IPWL_NoteNotify* pNotify = GetNoteNotify())
1181	{
1182		pNotify->OnSetContents(this);
1183	}
1184}
1185
1186void CPWL_NoteItem::SetNoteFocus(FX_BOOL bLast)
1187{
1188	m_pContents->SetEditFocus(bLast);
1189}
1190
1191void CPWL_NoteItem::EnableModify(FX_BOOL bEnabled)
1192{
1193	m_pContents->EnableModify(bEnabled);
1194	m_bAllowModify = bEnabled;
1195}
1196
1197void CPWL_NoteItem::EnableRead(FX_BOOL bEnabled)
1198{
1199	m_pContents->EnableRead(bEnabled);
1200}
1201
1202/* ---------------------------------- CPWL_Note ---------------------------------- */
1203
1204CPWL_Note::CPWL_Note(IPopup_Note* pPopupNote, IPWL_NoteNotify* pNoteNotify, IPWL_NoteHandler* pNoteHandler) :
1205	m_pAuthor(NULL),
1206	m_pIcon(NULL),
1207	m_pCloseBox(NULL),
1208	m_pContentsBar(NULL),
1209	m_pLBBox(NULL),
1210	m_pRBBox(NULL),
1211	m_pOptions(NULL),
1212	m_bResizing(FALSE),
1213	m_rcCaption(0,0,0,0),
1214	m_pNoteNotify(pNoteNotify),
1215	m_bEnalbleNotify(TRUE),
1216	m_pPopupNote(pPopupNote),
1217	m_pNoteHandler(pNoteHandler)
1218{
1219}
1220
1221CPWL_Note::~CPWL_Note()
1222{
1223}
1224
1225IPWL_NoteItem* CPWL_Note::Reply()
1226{
1227	return CreateNoteItem();
1228}
1229
1230void CPWL_Note::EnableNotify(FX_BOOL bEnabled)
1231{
1232	m_bEnalbleNotify = bEnabled;
1233}
1234
1235void CPWL_Note::RePosChildWnd()
1236{
1237	RePosNoteChildren();
1238	m_pContents->OnNotify(this, PNM_NOTERESET, 0, 0);
1239	ResetScrollBar();
1240	m_pContents->OnNotify(this, PNM_NOTERESET, 0, 0);
1241	this->OnNotify(this, PNM_NOTEEDITCHANGED, 0, 0);
1242	//ͬ��
1243	if (const CPWL_Wnd* pWnd = this->GetFocused())
1244	{
1245		if (pWnd->GetClassName() == "CPWL_Edit")
1246		{
1247			CPWL_Edit* pEdit = (CPWL_Edit*)pWnd;
1248			pEdit->SetCaret(pEdit->GetCaret());
1249		}
1250	}
1251	//CPDF_Point ptNew = m_pContents->GetScrollPos();
1252	//m_pContentsBar->OnNotify(this, PNM_SETSCROLLPOS, SBT_VSCROLL, (FX_INTPTR)&ptNew.y);
1253}
1254
1255FX_BOOL CPWL_Note::ResetScrollBar()
1256{
1257	FX_BOOL bScrollChanged = FALSE;
1258
1259	if (ScrollBarShouldVisible())
1260	{
1261		if (!m_pContentsBar->IsVisible())
1262		{
1263			m_pContentsBar->SetVisible(TRUE);
1264			if (m_pContentsBar->IsVisible())
1265			{
1266				m_pContentsBar->InvalidateRect(NULL);
1267				bScrollChanged = TRUE;
1268			}
1269		}
1270	}
1271	else
1272	{
1273		if (m_pContentsBar->IsVisible())
1274		{
1275			m_pContentsBar->SetVisible(FALSE);
1276			m_pContentsBar->InvalidateRect(NULL);
1277
1278			bScrollChanged = TRUE;
1279		}
1280	}
1281
1282	if (bScrollChanged)
1283	{
1284		CPDF_Rect rcNote = this->GetClientRect();
1285		CPDF_Rect rcContents = m_pContents->GetWindowRect();
1286		rcContents.right = rcNote.right - 3.0f;
1287		if (m_pContentsBar->IsVisible())
1288			rcContents.right -= PWL_SCROLLBAR_WIDTH;
1289		m_pContents->Move(rcContents, TRUE, TRUE);
1290		m_pContents->SetScrollPos(CPDF_Point(0.0f,0.0f));
1291		m_pContents->InvalidateRect(NULL);
1292	}
1293
1294	return bScrollChanged;
1295}
1296
1297FX_BOOL CPWL_Note::ScrollBarShouldVisible()
1298{
1299	CPDF_Rect rcContentsFact = m_pContents->GetScrollArea();
1300	CPDF_Rect rcContentsClient = m_pContents->GetClientRect();
1301
1302	return rcContentsFact.Height() > rcContentsClient.Height();
1303}
1304
1305void CPWL_Note::SetOptionsText(const CFX_WideString& sText)
1306{
1307	if (m_pOptions)
1308		m_pOptions->SetText(sText);
1309
1310	RePosNoteChildren();
1311}
1312
1313void CPWL_Note::RePosNoteChildren()
1314{
1315	if (m_bResizing) return;
1316
1317	m_bResizing = TRUE;
1318
1319	if (this->IsValid())
1320	{
1321		ASSERT(m_pSubject != NULL);
1322		ASSERT(m_pDateTime != NULL);
1323		ASSERT(m_pContents != NULL);
1324		ASSERT(m_pAuthor != NULL);
1325		ASSERT(m_pCloseBox != NULL);
1326		ASSERT(m_pIcon != NULL);
1327		ASSERT(m_pLBBox != NULL);
1328		ASSERT(m_pRBBox != NULL);
1329		ASSERT(m_pContentsBar != NULL);
1330		ASSERT(m_pOptions != NULL);
1331
1332		CPDF_Rect rcClient = GetClientRect();
1333
1334		CPDF_Rect rcIcon = rcClient;
1335		rcIcon.top -= 2.0f;
1336		rcIcon.right = rcIcon.left + 14.0f;
1337		rcIcon.bottom = rcIcon.top - 14.0f;
1338		rcIcon.Normalize();
1339		m_pIcon->Move(rcIcon, TRUE, FALSE);
1340		m_pIcon->SetVisible(CPWL_Utils::ContainsRect(rcClient, rcIcon));
1341
1342		CPDF_Rect rcCloseBox = rcClient;
1343		rcCloseBox.right -= 1.0f;
1344		rcCloseBox.top -= 1.0f;
1345		rcCloseBox.left = rcCloseBox.right - 14.0f;
1346		rcCloseBox.bottom = rcCloseBox.top - 14.0f;
1347		rcCloseBox.Normalize();
1348		m_pCloseBox->Move(rcCloseBox, TRUE, FALSE);
1349		m_pCloseBox->SetVisible(CPWL_Utils::ContainsRect(rcClient, rcCloseBox));
1350
1351		CPDF_Rect rcDate = rcClient;
1352		rcDate.right = rcCloseBox.left - POPUP_ITEM_TEXT_INDENT;
1353		rcDate.left = PWL_MAX(rcDate.right - m_pDateTime->GetContentRect().Width() - 1.0f, rcIcon.right + 1.0f);
1354		rcDate.top = rcClient.top - 2.0f;
1355		rcDate.bottom = rcDate.top - m_pDateTime->GetContentRect().Height();
1356		rcDate.Normalize();
1357		m_pDateTime->Move(rcDate, TRUE, FALSE);
1358		m_pDateTime->SetVisible(CPWL_Utils::ContainsRect(rcClient, rcDate));
1359
1360		CPDF_Rect rcSubject = rcClient;
1361		rcSubject.top = rcClient.top - 2.0f;
1362		rcSubject.left = rcIcon.right + POPUP_ITEM_TEXT_INDENT;
1363		rcSubject.right = PWL_MIN(rcSubject.left + m_pSubject->GetContentRect().Width() + 1.0f, rcDate.left - 1.0f);
1364		rcSubject.bottom = rcSubject.top - m_pSubject->GetContentRect().Height();
1365		rcSubject.Normalize();
1366		m_pSubject->Move(rcSubject, TRUE, FALSE);
1367		m_pSubject->SetVisible(CPWL_Utils::ContainsRect(rcClient, rcSubject));
1368
1369		CPDF_Rect rcOptions = rcClient;
1370		rcOptions.left = PWL_MAX(rcOptions.right - m_pOptions->GetContentRect().Width(), rcIcon.right + 1.0f);
1371		rcOptions.top = rcSubject.bottom - 4.0f;
1372		rcOptions.bottom = rcOptions.top - m_pOptions->GetContentRect().Height();
1373		rcOptions.Normalize();
1374		m_pOptions->Move(rcOptions, TRUE, FALSE);
1375		m_pOptions->SetVisible(CPWL_Utils::ContainsRect(rcClient, rcOptions));
1376
1377		CPDF_Rect rcAuthor = rcClient;
1378		rcAuthor.top = rcSubject.bottom - 4.0f;
1379		rcAuthor.left = rcSubject.left;
1380		rcAuthor.right = PWL_MIN(rcSubject.left + m_pAuthor->GetContentRect().Width() + 1.0f, rcOptions.left - 1.0f);
1381		rcAuthor.bottom = rcAuthor.top - m_pAuthor->GetContentRect().Height();
1382		rcAuthor.Normalize();
1383		m_pAuthor->Move(rcAuthor, TRUE, FALSE);
1384		m_pAuthor->SetVisible(CPWL_Utils::ContainsRect(rcClient, rcAuthor));
1385
1386		CPDF_Rect rcLBBox = rcClient;
1387		rcLBBox.top = rcLBBox.bottom + 7.0f;
1388		rcLBBox.right = rcLBBox.left + 7.0f;
1389		rcLBBox.Normalize();
1390		m_pLBBox->Move(rcLBBox, TRUE, FALSE);
1391		m_pLBBox->SetVisible(CPWL_Utils::ContainsRect(rcClient, rcLBBox));
1392
1393		CPDF_Rect rcRBBox = rcClient;
1394		rcRBBox.top = rcRBBox.bottom + 7.0f;
1395		rcRBBox.left = rcRBBox.right - 7.0f;
1396		rcRBBox.Normalize();
1397		m_pRBBox->Move(rcRBBox, TRUE, FALSE);
1398		m_pRBBox->SetVisible(CPWL_Utils::ContainsRect(rcClient, rcRBBox));
1399
1400		CPDF_Rect rcContents = rcClient;
1401		rcContents.top = rcAuthor.bottom - POPUP_ITEM_HEAD_BOTTOM;
1402		rcContents.left += 3.0f;
1403		rcContents.right -= 3.0f;
1404		if (m_pContentsBar->IsVisible())
1405			rcContents.right -= PWL_SCROLLBAR_WIDTH;
1406		rcContents.bottom += 14.0f;
1407		rcContents.Normalize();
1408		m_pContents->Move(rcContents, FALSE, FALSE);
1409		m_pContents->SetVisible(CPWL_Utils::ContainsRect(rcClient, rcContents));
1410
1411		CPDF_Rect rcContentsBar = rcContents;
1412		rcContentsBar.right = rcClient.right - 3.0f;
1413		rcContentsBar.left = rcContentsBar.right - PWL_SCROLLBAR_WIDTH;
1414		rcContentsBar.Normalize();
1415		m_pContentsBar->Move(rcContentsBar, TRUE, FALSE);
1416
1417		m_rcCaption = rcClient;
1418		m_rcCaption.bottom = rcContents.top;
1419	}
1420
1421	m_bResizing = FALSE;
1422}
1423
1424//0-normal / 1-caption / 2-leftbottom corner / 3-rightbottom corner / 4-close / 5-options
1425FX_INT32 CPWL_Note::NoteHitTest(const CPDF_Point& point) const
1426{
1427	ASSERT(m_pSubject != NULL);
1428	ASSERT(m_pDateTime != NULL);
1429	ASSERT(m_pContents != NULL);
1430	ASSERT(m_pAuthor != NULL);
1431	ASSERT(m_pIcon != NULL);
1432	ASSERT(m_pContentsBar != NULL);
1433
1434	ASSERT(m_pCloseBox != NULL);
1435	ASSERT(m_pLBBox != NULL);
1436	ASSERT(m_pRBBox != NULL);
1437	ASSERT(m_pOptions != NULL);
1438
1439	GetClientRect();
1440
1441	if (m_pSubject->WndHitTest(m_pSubject->ParentToChild(point))) return 1;
1442	if (m_pDateTime->WndHitTest(m_pDateTime->ParentToChild(point))) return 1;
1443	if (m_pAuthor->WndHitTest(m_pAuthor->ParentToChild(point))) return 1;
1444	if (m_pIcon->WndHitTest(m_pIcon->ParentToChild(point))) return 1;
1445
1446	if (m_pContents->WndHitTest(m_pContents->ParentToChild(point))) return 0;
1447	if (m_pContentsBar->WndHitTest(m_pContentsBar->ParentToChild(point))) return 0;
1448
1449	if (m_pCloseBox->WndHitTest(m_pCloseBox->ParentToChild(point))) return 4;
1450	if (m_pLBBox->WndHitTest(m_pLBBox->ParentToChild(point))) return 2;
1451	if (m_pRBBox->WndHitTest(m_pRBBox->ParentToChild(point))) return 3;
1452	if (m_pOptions->WndHitTest(m_pOptions->ParentToChild(point))) return 5;
1453
1454	return 1;
1455}
1456
1457void CPWL_Note::CreateChildWnd(const PWL_CREATEPARAM & cp)
1458{
1459	CPWL_NoteItem::CreateChildWnd(cp);
1460
1461	CPWL_Color sTextColor;
1462
1463	if (CPWL_Utils::IsBlackOrWhite(this->GetBackgroundColor()))
1464		sTextColor = PWL_DEFAULT_WHITECOLOR;
1465	else
1466		sTextColor = PWL_DEFAULT_BLACKCOLOR;
1467
1468	m_pAuthor = new CPWL_Label;
1469	PWL_CREATEPARAM acp = cp;
1470	acp.pParentWnd = this;
1471	acp.dwFlags = PWS_VISIBLE | PWS_CHILD | PES_LEFT | PES_TOP;
1472	acp.sTextColor = sTextColor;
1473	m_pAuthor->Create(acp);
1474
1475	m_pCloseBox = new CPWL_Note_CloseBox;
1476	PWL_CREATEPARAM ccp = cp;
1477	ccp.pParentWnd = this;
1478	ccp.dwBorderWidth = 2;
1479	ccp.nBorderStyle = PBS_BEVELED;
1480	ccp.dwFlags = PWS_VISIBLE | PWS_CHILD | PWS_BORDER;
1481	ccp.sTextColor = sTextColor;
1482	m_pCloseBox->Create(ccp);
1483
1484	m_pIcon = new CPWL_Note_Icon;
1485	PWL_CREATEPARAM icp = cp;
1486	icp.pParentWnd = this;
1487	icp.dwFlags = PWS_VISIBLE | PWS_CHILD;
1488	m_pIcon->Create(icp);
1489
1490	m_pOptions = new CPWL_Note_Options;
1491	PWL_CREATEPARAM ocp = cp;
1492	ocp.pParentWnd = this;
1493	ocp.dwFlags = PWS_CHILD | PWS_VISIBLE;
1494	ocp.sTextColor = sTextColor;
1495	m_pOptions->Create(ocp);
1496
1497	m_pLBBox = new CPWL_Note_LBBox;
1498	PWL_CREATEPARAM lcp = cp;
1499	lcp.pParentWnd = this;
1500	lcp.dwFlags = PWS_VISIBLE | PWS_CHILD;
1501	lcp.eCursorType = FXCT_NESW;
1502	lcp.sTextColor = sTextColor;
1503	m_pLBBox->Create(lcp);
1504
1505	m_pRBBox = new CPWL_Note_RBBox;
1506	PWL_CREATEPARAM rcp = cp;
1507	rcp.pParentWnd = this;
1508	rcp.dwFlags = PWS_VISIBLE | PWS_CHILD;
1509	rcp.eCursorType = FXCT_NWSE;
1510	rcp.sTextColor = sTextColor;
1511	m_pRBBox->Create(rcp);
1512
1513	m_pContentsBar = new CPWL_ScrollBar(SBT_VSCROLL);
1514	PWL_CREATEPARAM scp = cp;
1515	scp.pParentWnd = this;
1516	scp.sBackgroundColor = CPWL_Color(COLORTYPE_RGB, 240/255.0f, 240/255.0f, 240/255.0f);
1517	scp.dwFlags = PWS_CHILD | PWS_VISIBLE | PWS_BACKGROUND;
1518	m_pContentsBar->Create(scp);
1519	m_pContentsBar->SetNotifyForever(TRUE);
1520}
1521
1522void CPWL_Note::SetSubjectName(const CFX_WideString& sName)
1523{
1524	CPWL_NoteItem::SetSubjectName(sName);
1525	RePosChildWnd();
1526}
1527
1528void CPWL_Note::SetAuthorName(const CFX_WideString& sName)
1529{
1530	if (m_pAuthor)
1531	{
1532		m_pAuthor->SetText(sName);
1533		RePosChildWnd();
1534	}
1535
1536	if (IPWL_NoteNotify* pNotify = GetNoteNotify())
1537	{
1538		pNotify->OnSetAuthorName(this);
1539	}
1540}
1541
1542CFX_WideString CPWL_Note::GetAuthorName() const
1543{
1544	if (m_pAuthor)
1545		return m_pAuthor->GetText();
1546
1547	return L"";
1548}
1549
1550FX_BOOL CPWL_Note::OnMouseWheel(short zDelta, const CPDF_Point & point, FX_DWORD nFlag)
1551{
1552	CPDF_Point ptScroll = m_pContents->GetScrollPos();
1553	CPDF_Rect rcScroll = m_pContents->GetScrollArea();
1554	CPDF_Rect rcContents = m_pContents->GetClientRect();
1555
1556	if (rcScroll.top - rcScroll.bottom > rcContents.Height())
1557	{
1558		CPDF_Point ptNew = ptScroll;
1559
1560		if (zDelta > 0)
1561			ptNew.y += 30;
1562		else
1563			ptNew.y -= 30;
1564
1565		if (ptNew.y > rcScroll.top)
1566			ptNew.y = rcScroll.top;
1567		if (ptNew.y < rcScroll.bottom + rcContents.Height())
1568			ptNew.y = rcScroll.bottom + rcContents.Height();
1569		if (ptNew.y < rcScroll.bottom)
1570			ptNew.y = rcScroll.bottom;
1571
1572		if (ptNew.y != ptScroll.y)
1573		{
1574			m_pContents->OnNotify(this, PNM_NOTERESET, 0, 0);
1575			m_pContents->OnNotify(this, PNM_SCROLLWINDOW, SBT_VSCROLL, (FX_INTPTR)&ptNew.y);
1576			m_pContentsBar->OnNotify(this, PNM_SETSCROLLPOS, SBT_VSCROLL, (FX_INTPTR)&ptNew.y);
1577
1578			return TRUE;
1579		}
1580	}
1581
1582	return FALSE;
1583}
1584
1585void CPWL_Note::OnNotify(CPWL_Wnd* pWnd, FX_DWORD msg, FX_INTPTR wParam, FX_INTPTR lParam)
1586{
1587	switch (msg)
1588	{
1589	case PNM_NOTEEDITCHANGED:
1590		{
1591			CPDF_Rect rcScroll = m_pContents->GetScrollArea();
1592
1593
1594			PWL_SCROLL_INFO sInfo;
1595			sInfo.fContentMin = rcScroll.bottom;
1596			sInfo.fContentMax = rcScroll.top;
1597			sInfo.fPlateWidth = m_pContents->GetClientRect().Height();
1598			sInfo.fSmallStep = 13.0f;
1599			sInfo.fBigStep = sInfo.fPlateWidth;
1600
1601			if (FXSYS_memcmp(&m_OldScrollInfo, &sInfo, sizeof(PWL_SCROLL_INFO)) != 0)
1602			{
1603				FX_BOOL bScrollChanged = FALSE;
1604
1605				if (lParam < 3) //��ֹ��ѭ�� mantis:15759
1606				{
1607					bScrollChanged = ResetScrollBar();
1608					if (bScrollChanged)
1609					{
1610						lParam++;
1611						m_pContents->OnNotify(this, PNM_NOTERESET, 0, 0);
1612						this->OnNotify(this, PNM_NOTEEDITCHANGED, 0, lParam);
1613					}
1614				}
1615
1616				if (!bScrollChanged)
1617				{
1618					if (m_pContentsBar->IsVisible())
1619					{
1620						m_pContentsBar->OnNotify(pWnd, PNM_SETSCROLLINFO, SBT_VSCROLL, (FX_INTPTR)&sInfo);
1621						m_OldScrollInfo = sInfo;
1622
1623						CPDF_Point ptScroll = m_pContents->GetScrollPos();
1624						CPDF_Point ptOld = ptScroll;
1625
1626						if (ptScroll.y > sInfo.fContentMax)
1627							ptScroll.y = sInfo.fContentMax;
1628						if (ptScroll.y < sInfo.fContentMin + sInfo.fPlateWidth)
1629							ptScroll.y = sInfo.fContentMin + sInfo.fPlateWidth;
1630						if (ptScroll.y < sInfo.fContentMin)
1631							ptScroll.y = sInfo.fContentMin;
1632
1633						if (ptOld.y != ptScroll.y)
1634						{
1635							m_pContentsBar->OnNotify(this, PNM_SETSCROLLPOS, SBT_VSCROLL, (FX_INTPTR)&ptScroll.y);
1636							m_pContentsBar->InvalidateRect(NULL);
1637							m_pContents->OnNotify(this, PNM_SCROLLWINDOW, SBT_VSCROLL, (FX_INTPTR)&ptScroll.y);
1638						}
1639					}
1640				}
1641			}
1642		}
1643
1644		m_pContents->InvalidateRect(NULL);
1645
1646		return;
1647	case PNM_SCROLLWINDOW:
1648		if (m_pContents)
1649			m_pContents->OnNotify(pWnd, msg, wParam, lParam);
1650		return;
1651	case PNM_SETSCROLLPOS:
1652		if (m_pContentsBar)
1653			m_pContentsBar->OnNotify(pWnd,PNM_SETSCROLLPOS,wParam,lParam);
1654		return;
1655	}
1656
1657	if (msg == PNM_SETCARETINFO && IsValid())
1658	{
1659		if (PWL_CARET_INFO * pInfo = (PWL_CARET_INFO*)wParam)
1660		{
1661			if (m_pContents)
1662			{
1663				CPDF_Rect rcClient = m_pContents->GetClientRect();
1664				if (pInfo->ptHead.y > rcClient.top)
1665				{
1666					CPDF_Point pt = m_pContents->OutToIn(pInfo->ptHead);
1667					m_pContents->OnNotify(this, PNM_SCROLLWINDOW, SBT_VSCROLL, (FX_INTPTR)&pt.y);
1668
1669					CPDF_Point ptScroll = m_pContents->GetScrollPos();
1670					m_pContentsBar->OnNotify(this, PNM_SETSCROLLPOS, SBT_VSCROLL, (FX_INTPTR)&ptScroll.y);
1671
1672					return;
1673				}
1674
1675				if (pInfo->ptFoot.y < rcClient.bottom)
1676				{
1677					CPDF_Point pt = m_pContents->OutToIn(pInfo->ptFoot);
1678					pt.y += rcClient.Height();
1679					m_pContents->OnNotify(this, PNM_SCROLLWINDOW, SBT_VSCROLL, (FX_INTPTR)&pt.y);
1680
1681					CPDF_Point ptScroll = m_pContents->GetScrollPos();
1682					m_pContentsBar->OnNotify(this, PNM_SETSCROLLPOS, SBT_VSCROLL, (FX_INTPTR)&ptScroll.y);
1683
1684					return;
1685				}
1686			}
1687		}
1688	}
1689
1690	CPWL_NoteItem::OnNotify(pWnd, msg, wParam, lParam);
1691}
1692
1693void CPWL_Note::SetBkColor(const CPWL_Color& color)
1694{
1695	CPWL_NoteItem::SetBkColor(color);
1696
1697	CPWL_Color sBK = color;
1698	CPWL_Color sTextColor;
1699	if (CPWL_Utils::IsBlackOrWhite(sBK))
1700		sTextColor = PWL_DEFAULT_WHITECOLOR;
1701	else
1702		sTextColor = PWL_DEFAULT_BLACKCOLOR;
1703
1704	if (m_pCloseBox)
1705		m_pCloseBox->SetTextColor(sTextColor);
1706	if (m_pAuthor)
1707		m_pAuthor->SetTextColor(sTextColor);
1708	if (m_pOptions)
1709		m_pOptions->SetTextColor(sTextColor);
1710	if (m_pLBBox)
1711		m_pLBBox->SetTextColor(sTextColor);
1712	if (m_pRBBox)
1713		m_pRBBox->SetTextColor(sTextColor);
1714}
1715
1716FX_BOOL	CPWL_Note::OnLButtonDown(const CPDF_Point& point, FX_DWORD nFlag)
1717{
1718	if (m_pOptions->WndHitTest(m_pOptions->ParentToChild(point)))
1719	{
1720		if (IPWL_NoteNotify* pNotify = this->GetNoteNotify())
1721		{
1722			FX_INT32 x, y;
1723			PWLtoWnd(point, x, y);
1724			if (IFX_SystemHandler* pSH = GetSystemHandler())
1725				pSH->ClientToScreen(GetAttachedHWnd(), x, y);
1726			this->KillFocus();
1727			pNotify->OnPopupMenu(x, y);
1728
1729			return TRUE;
1730		}
1731	}
1732
1733	return CPWL_Wnd::OnLButtonDown(point,nFlag);
1734}
1735
1736FX_BOOL	CPWL_Note::OnRButtonUp(const CPDF_Point & point, FX_DWORD nFlag)
1737{
1738	return CPWL_Wnd::OnRButtonUp(point,nFlag);
1739}
1740
1741const CPWL_Note* CPWL_Note::GetNote() const
1742{
1743	return this;
1744}
1745
1746IPWL_NoteNotify* CPWL_Note::GetNoteNotify() const
1747{
1748	if (m_bEnalbleNotify)
1749		return m_pNoteNotify;
1750
1751	return NULL;
1752}
1753
1754void CPWL_Note::SetIconType(FX_INT32 nType)
1755{
1756	if (m_pIcon)
1757		m_pIcon->SetIconType(nType);
1758}
1759
1760void CPWL_Note::EnableModify(FX_BOOL bEnabled)
1761{
1762	m_pContents->EnableModify(bEnabled);
1763}
1764
1765void CPWL_Note::EnableRead(FX_BOOL bEnabled)
1766{
1767	m_pContents->EnableRead(bEnabled);
1768}
1769
1770CFX_WideString CPWL_Note::GetReplyString() const
1771{
1772	return m_sReplyString;
1773}
1774
1775void CPWL_Note::SetReplyString(const CFX_WideString& string)
1776{
1777	m_sReplyString = string;
1778}
1779
1780