Merge to XFA: Use stdint.h types throughout PDFium.
[pdfium.git] / fpdfsdk / src / pdfwindow / PWL_EditCtrl.cpp
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_EditCtrl.h"
10 #include "../../include/pdfwindow/PWL_ScrollBar.h"
11 #include "../../include/pdfwindow/PWL_Utils.h"
12 #include "../../include/pdfwindow/PWL_Caret.h"
13 #include "../../include/pdfwindow/PWL_FontMap.h"
14
15 #define IsFloatZero(f)                                          ((f) < 0.0001 && (f) > -0.0001)
16 #define IsFloatBigger(fa,fb)                            ((fa) > (fb) && !IsFloatZero((fa) - (fb)))
17 #define IsFloatSmaller(fa,fb)                           ((fa) < (fb) && !IsFloatZero((fa) - (fb)))
18 #define IsFloatEqual(fa,fb)                                     IsFloatZero((fa)-(fb))
19
20 /* ---------------------------- CPWL_EditCtrl ------------------------------ */
21
22 CPWL_EditCtrl::CPWL_EditCtrl() :
23         m_pEdit(NULL),
24         m_pEditCaret(NULL),
25         m_bMouseDown(FALSE),
26         m_pEditNotify(NULL),
27         m_nCharSet(DEFAULT_CHARSET),
28         m_nCodePage(0)
29 {
30         m_pEdit = IFX_Edit::NewEdit();
31         ASSERT(m_pEdit != NULL);
32 }
33
34 CPWL_EditCtrl::~CPWL_EditCtrl()
35 {
36         IFX_Edit::DelEdit(m_pEdit);
37 }
38
39 void CPWL_EditCtrl::OnCreate(PWL_CREATEPARAM & cp)
40 {
41         cp.eCursorType = FXCT_VBEAM;
42 }
43
44 void CPWL_EditCtrl::OnCreated()
45 {
46         SetFontSize(this->GetCreationParam().fFontSize);
47
48         m_pEdit->SetFontMap(this->GetFontMap());
49         m_pEdit->SetNotify(this);
50         m_pEdit->Initialize();
51 }
52
53 FX_BOOL CPWL_EditCtrl::IsWndHorV()
54 {
55         CPDF_Matrix mt = GetWindowMatrix();
56         CPDF_Point point1(0,1);
57         CPDF_Point point2(1,1);
58
59         mt.Transform(point1.x, point1.y);
60         mt.Transform(point2.x, point2.y);
61
62         return point2.y == point1.y;
63 }
64
65 void CPWL_EditCtrl::SetCursor()
66 {
67         if (IsValid()) 
68         {
69                 if (IFX_SystemHandler* pSH = GetSystemHandler())
70                 {
71                         if (IsWndHorV())
72                                 pSH->SetCursor(FXCT_VBEAM);
73                         else
74                                 pSH->SetCursor(FXCT_HBEAM);
75                 }
76         }
77 }
78
79 void CPWL_EditCtrl::RePosChildWnd()
80 {
81         m_pEdit->SetPlateRect(GetClientRect());
82 }
83
84 void CPWL_EditCtrl::OnNotify(CPWL_Wnd* pWnd, FX_DWORD msg, intptr_t wParam, intptr_t lParam)
85 {
86         CPWL_Wnd::OnNotify(pWnd,msg,wParam,lParam);
87
88         switch (msg)
89         {
90                 case PNM_SETSCROLLINFO:
91                         switch (wParam)
92                         {
93                                 case SBT_VSCROLL:
94                                         if (CPWL_Wnd * pChild = GetVScrollBar())
95                                         {
96                                                 pChild->OnNotify(pWnd,PNM_SETSCROLLINFO,wParam,lParam);
97                                         }
98                                         break;
99                         }
100                         break;
101                 case PNM_SETSCROLLPOS:                  
102                         switch (wParam)
103                         {
104                                 case SBT_VSCROLL:
105                                         if (CPWL_Wnd * pChild = GetVScrollBar())
106                                         {
107                                                 pChild->OnNotify(pWnd,PNM_SETSCROLLPOS,wParam,lParam);
108                                         }
109                                         break;
110                         }
111                         break;
112                 case PNM_SCROLLWINDOW:
113                         {
114                                 FX_FLOAT fPos = *(FX_FLOAT*)lParam;
115                                 switch (wParam)
116                                 {
117                                         case SBT_VSCROLL:
118                                                 m_pEdit->SetScrollPos(CPDF_Point(m_pEdit->GetScrollPos().x,fPos));
119                                                 break;
120                                 }
121                         }
122                         break;
123                 case PNM_SETCARETINFO:
124                         {
125                                 if (PWL_CARET_INFO * pCaretInfo = (PWL_CARET_INFO *)wParam)
126                                 {
127                                         this->SetCaret(pCaretInfo->bVisible,
128                                                 pCaretInfo->ptHead,
129                                                 pCaretInfo->ptFoot);                                    
130                                 }
131                         }
132                         break;
133         }
134 }
135
136 void CPWL_EditCtrl::CreateChildWnd(const PWL_CREATEPARAM & cp)
137 {
138         if (!IsReadOnly())
139                 CreateEditCaret(cp);
140 }
141
142 void CPWL_EditCtrl::CreateEditCaret(const PWL_CREATEPARAM & cp)
143 {
144         if (!m_pEditCaret)
145         {
146                 m_pEditCaret = new CPWL_Caret;  
147                 m_pEditCaret->SetInvalidRect(GetClientRect());
148
149                 PWL_CREATEPARAM ecp = cp;
150                 ecp.pParentWnd = this;
151                 ecp.dwFlags = PWS_CHILD | PWS_NOREFRESHCLIP;
152                 ecp.dwBorderWidth = 0;
153                 ecp.nBorderStyle = PBS_SOLID;
154                 ecp.rcRectWnd = CPDF_Rect(0,0,0,0);
155
156                 m_pEditCaret->Create(ecp);
157         }
158 }
159
160 void CPWL_EditCtrl::SetFontSize(FX_FLOAT fFontSize)
161 {
162         m_pEdit->SetFontSize(fFontSize);
163 }
164
165 FX_FLOAT CPWL_EditCtrl::GetFontSize() const
166 {
167         return m_pEdit->GetFontSize();
168 }
169
170 FX_BOOL CPWL_EditCtrl::OnKeyDown(FX_WORD nChar, FX_DWORD nFlag)
171 {
172         if (m_bMouseDown) return TRUE;
173
174         FX_BOOL bRet = CPWL_Wnd::OnKeyDown(nChar,nFlag);
175
176         //FILTER
177         switch (nChar)
178         {
179         default:
180                 return FALSE;
181         case FWL_VKEY_Delete:
182         case FWL_VKEY_Up:
183         case FWL_VKEY_Down:
184         case FWL_VKEY_Left:
185         case FWL_VKEY_Right:
186         case FWL_VKEY_Home:
187         case FWL_VKEY_End:
188         case FWL_VKEY_Insert:
189         case 'C':
190         case 'V':
191         case 'X':
192         case 'A':
193         case 'Z':
194         case 'c':
195         case 'v':
196         case 'x':
197         case 'a':
198         case 'z':
199                 break;
200         }
201
202         if (nChar == FWL_VKEY_Delete)
203         {
204                 if (m_pEdit->IsSelected())
205                         nChar = FWL_VKEY_Unknown;
206         }
207
208         switch (nChar)
209         {
210                 case FWL_VKEY_Delete:   
211                         Delete();
212                         return TRUE;
213                 case FWL_VKEY_Insert:
214                         if (IsSHIFTpressed(nFlag))
215                                 PasteText();
216                         return TRUE;
217                 case FWL_VKEY_Up:
218                         m_pEdit->OnVK_UP(IsSHIFTpressed(nFlag),FALSE);
219                         return TRUE;
220                 case FWL_VKEY_Down:
221                         m_pEdit->OnVK_DOWN(IsSHIFTpressed(nFlag),FALSE);
222                         return TRUE;
223                 case FWL_VKEY_Left:
224                         m_pEdit->OnVK_LEFT(IsSHIFTpressed(nFlag),FALSE);
225                         return TRUE;
226                 case FWL_VKEY_Right:
227                         m_pEdit->OnVK_RIGHT(IsSHIFTpressed(nFlag),FALSE);
228                         return TRUE;
229                 case FWL_VKEY_Home:
230                         m_pEdit->OnVK_HOME(IsSHIFTpressed(nFlag),IsCTRLpressed(nFlag));
231                         return TRUE;
232                 case FWL_VKEY_End:
233                         m_pEdit->OnVK_END(IsSHIFTpressed(nFlag),IsCTRLpressed(nFlag));
234                         return TRUE;
235                 case FWL_VKEY_Unknown:
236                         if (!IsSHIFTpressed(nFlag))
237                                 Clear();
238                         else
239                                 CutText();
240                         return TRUE;
241                 default:
242                         break;
243         }
244         
245         return bRet;
246 }
247
248 FX_BOOL CPWL_EditCtrl::OnChar(FX_WORD nChar, FX_DWORD nFlag)
249 {
250         if (m_bMouseDown) return TRUE;
251
252         CPWL_Wnd::OnChar(nChar,nFlag);
253
254         //FILTER
255         switch (nChar)
256         {
257                 case 0x0A:
258                 case 0x1B:
259                         return FALSE;           
260                 default:
261                         break;
262         }
263
264         FX_BOOL bCtrl = IsCTRLpressed(nFlag);
265         FX_BOOL bAlt = IsALTpressed(nFlag);
266         FX_BOOL bShift = IsSHIFTpressed(nFlag);
267
268         FX_WORD word = nChar;
269
270         if (bCtrl && !bAlt)
271         {
272                 switch (nChar)
273                 {
274                         case 'C' - 'A' + 1:
275                                 this->CopyText();
276                                 return TRUE;
277                         case 'V' - 'A' + 1:
278                                 this->PasteText();
279                                 return TRUE;
280                         case 'X' - 'A' + 1:
281                                 this->CutText();
282                                 return TRUE;
283                         case 'A' - 'A' + 1:
284                                 this->SelectAll();
285                                 return TRUE;
286                         case 'Z' - 'A' + 1:
287                                 if (bShift)
288                                         Redo();
289                                 else
290                                         Undo();
291                                 return TRUE;
292                         default:
293                                 if (nChar < 32)
294                                         return FALSE;
295                 }
296         }
297
298         if (IsReadOnly()) return TRUE;
299
300         if (m_pEdit->IsSelected() && word ==  FWL_VKEY_Back)
301                 word = FWL_VKEY_Unknown;
302
303         Clear();
304
305         switch (word)
306         {
307         case FWL_VKEY_Back:
308                 Backspace();
309                 break;
310         case FWL_VKEY_Return:   
311                 InsertReturn();
312                 break;
313         case FWL_VKEY_Unknown:
314                 break;
315         default:
316                 if (IsINSERTpressed(nFlag))
317                         Delete();
318                 InsertWord(word, this->GetCharSet());
319                 break;
320         }
321
322         return TRUE;
323 }
324
325 FX_BOOL CPWL_EditCtrl::OnLButtonDown(const CPDF_Point & point, FX_DWORD nFlag)
326 {
327         CPWL_Wnd::OnLButtonDown(point,nFlag);
328
329         if (ClientHitTest(point))
330         {               
331                 if (m_bMouseDown)
332                         this->InvalidateRect();
333
334                 m_bMouseDown = TRUE;            
335                 SetCapture();
336
337                 m_pEdit->OnMouseDown(point,IsSHIFTpressed(nFlag),IsCTRLpressed(nFlag));
338         }
339
340         return TRUE;
341 }
342
343 FX_BOOL CPWL_EditCtrl::OnLButtonUp(const CPDF_Point & point, FX_DWORD nFlag)
344 {
345         CPWL_Wnd::OnLButtonUp(point,nFlag);
346
347         if (m_bMouseDown)
348         {
349                 //can receive keybord message
350                 if (ClientHitTest(point) && !this->IsFocused())
351                         SetFocus();     
352
353                 ReleaseCapture();
354                 m_bMouseDown = FALSE;
355         }
356
357         return TRUE;
358 }
359
360 FX_BOOL CPWL_EditCtrl::OnMouseMove(const CPDF_Point & point, FX_DWORD nFlag)
361 {
362         CPWL_Wnd::OnMouseMove(point,nFlag);
363
364         if (m_bMouseDown)
365                 m_pEdit->OnMouseMove(point,FALSE,FALSE);
366
367         return TRUE;
368 }
369
370 CPDF_Rect CPWL_EditCtrl::GetContentRect() const
371 {
372         return m_pEdit->GetContentRect();
373 }
374
375 void CPWL_EditCtrl::SetEditCaret(FX_BOOL bVisible)
376 {
377         CPDF_Point ptHead(0,0),ptFoot(0,0);
378
379         if (bVisible)
380         {
381                 GetCaretInfo(ptHead,ptFoot);
382         }
383
384         CPVT_WordPlace wpTemp = m_pEdit->GetCaretWordPlace();
385         this->IOnSetCaret(bVisible,ptHead,ptFoot,wpTemp);
386 }
387
388 void CPWL_EditCtrl::GetCaretInfo(CPDF_Point & ptHead, CPDF_Point & ptFoot) const
389 {
390         if (IFX_Edit_Iterator * pIterator = m_pEdit->GetIterator())
391         {
392                 pIterator->SetAt(m_pEdit->GetCaret());
393                 CPVT_Word word;
394                 CPVT_Line line;
395                 if (pIterator->GetWord(word))
396                 {
397                         ptHead.x = word.ptWord.x + word.fWidth;
398                         ptHead.y = word.ptWord.y + word.fAscent;
399                         ptFoot.x = word.ptWord.x + word.fWidth;
400                         ptFoot.y = word.ptWord.y + word.fDescent;
401                 }
402                 else if (pIterator->GetLine(line))
403                 {                               
404                         ptHead.x = line.ptLine.x;
405                         ptHead.y = line.ptLine.y + line.fLineAscent;
406                         ptFoot.x = line.ptLine.x;
407                         ptFoot.y = line.ptLine.y + line.fLineDescent;
408                 }
409         }
410 }
411
412 void CPWL_EditCtrl::GetCaretPos(int32_t& x, int32_t& y) const
413 {
414         CPDF_Point ptHead(0,0), ptFoot(0,0);
415
416         GetCaretInfo(ptHead,ptFoot);
417
418         PWLtoWnd(ptHead, x, y);
419 }
420
421 void CPWL_EditCtrl::SetCaret(FX_BOOL bVisible, const CPDF_Point & ptHead, const CPDF_Point & ptFoot)
422 {
423         if (m_pEditCaret)
424         {
425                 if (!IsFocused() || m_pEdit->IsSelected())
426                         bVisible = FALSE;
427
428                 m_pEditCaret->SetCaret(bVisible, ptHead, ptFoot);
429         }
430 }
431
432 FX_BOOL CPWL_EditCtrl::IsModified() const
433 {
434         return m_pEdit->IsModified();
435 }
436
437 CFX_WideString CPWL_EditCtrl::GetText() const
438 {
439         return m_pEdit->GetText();
440 }
441
442 void CPWL_EditCtrl::SetSel(int32_t nStartChar,int32_t nEndChar)
443 {
444         m_pEdit->SetSel(nStartChar, nEndChar);
445 }
446
447 void CPWL_EditCtrl::GetSel(int32_t & nStartChar, int32_t & nEndChar ) const
448 {
449         m_pEdit->GetSel(nStartChar, nEndChar);
450 }
451
452 void CPWL_EditCtrl::Clear()
453 {
454         if (!IsReadOnly())
455                 m_pEdit->Clear();
456 }
457
458 void CPWL_EditCtrl::SelectAll()
459 {
460         m_pEdit->SelectAll();
461 }
462
463 void CPWL_EditCtrl::Paint()
464 {
465         if (m_pEdit)
466                 m_pEdit->Paint();
467 }
468
469 void CPWL_EditCtrl::EnableRefresh(FX_BOOL bRefresh)
470 {
471         if (m_pEdit)
472                 m_pEdit->EnableRefresh(bRefresh);
473 }
474
475 int32_t CPWL_EditCtrl::GetCaret() const
476 {
477         if (m_pEdit)
478                 return m_pEdit->GetCaret();
479
480         return -1;
481 }
482
483 void CPWL_EditCtrl::SetCaret(int32_t nPos)
484 {
485         if (m_pEdit)
486                 m_pEdit->SetCaret(nPos);
487 }
488
489 int32_t CPWL_EditCtrl::GetTotalWords() const
490 {
491         if (m_pEdit)
492                 return m_pEdit->GetTotalWords();
493
494         return 0;
495 }
496
497 void CPWL_EditCtrl::SetScrollPos(const CPDF_Point& point)
498 {
499         if (m_pEdit)
500                 m_pEdit->SetScrollPos(point);
501 }
502
503 CPDF_Point CPWL_EditCtrl::GetScrollPos() const
504 {
505         if (m_pEdit)
506                 return m_pEdit->GetScrollPos();
507
508         return CPDF_Point(0.0f, 0.0f);
509 }
510
511 CPDF_Font * CPWL_EditCtrl::GetCaretFont() const
512 {
513         int32_t nFontIndex = 0;
514
515         if (IFX_Edit_Iterator * pIterator = m_pEdit->GetIterator())
516         {
517                 pIterator->SetAt(m_pEdit->GetCaret());
518                 CPVT_Word word;
519                 CPVT_Section section;
520                 if (pIterator->GetWord(word))
521                 {
522                         nFontIndex = word.nFontIndex;
523                 }
524                 else if (HasFlag(PES_RICH))
525                 {
526                         if (pIterator->GetSection(section))
527                         {                               
528                                 nFontIndex = section.WordProps.nFontIndex;
529                         }
530                 }
531         }
532
533         if (IFX_Edit_FontMap * pFontMap = GetFontMap())
534                 return pFontMap->GetPDFFont(nFontIndex);
535         else
536                 return NULL;
537 }
538
539 FX_FLOAT CPWL_EditCtrl::GetCaretFontSize() const
540 {
541         FX_FLOAT fFontSize = GetFontSize();
542
543         if (IFX_Edit_Iterator * pIterator = m_pEdit->GetIterator())
544         {
545                 pIterator->SetAt(m_pEdit->GetCaret());
546                 CPVT_Word word;
547                 CPVT_Section section;
548                 if (pIterator->GetWord(word))
549                 {
550                         fFontSize = word.fFontSize;
551                 }
552                 else if (HasFlag(PES_RICH))
553                 {
554                         if (pIterator->GetSection(section))
555                         {                               
556                                 fFontSize = section.WordProps.fFontSize;
557                         }
558                 }
559         }
560
561         return fFontSize;
562 }
563
564 void CPWL_EditCtrl::SetText(FX_LPCWSTR csText)
565 {
566         m_pEdit->SetText(csText);
567 }
568
569 void CPWL_EditCtrl::CopyText()
570 {
571 }
572
573 void CPWL_EditCtrl::PasteText()
574 {
575 }
576
577 void CPWL_EditCtrl::CutText()
578 {
579 }
580
581 void CPWL_EditCtrl::ShowVScrollBar(FX_BOOL bShow)
582 {
583 }
584
585 void CPWL_EditCtrl::InsertText(FX_LPCWSTR csText)
586 {
587         if (!IsReadOnly())
588                 m_pEdit->InsertText(csText);
589 }
590
591 void CPWL_EditCtrl::InsertWord(FX_WORD word, int32_t nCharset)
592 {
593         if (!IsReadOnly())
594                 m_pEdit->InsertWord(word, nCharset);
595 }
596
597 void CPWL_EditCtrl::InsertReturn()
598 {
599         if (!IsReadOnly())
600                 m_pEdit->InsertReturn();
601 }
602
603 void CPWL_EditCtrl::Delete()
604 {
605         if (!IsReadOnly())
606                 m_pEdit->Delete();
607 }
608
609 void CPWL_EditCtrl::Backspace()
610 {
611         if (!IsReadOnly())
612                 m_pEdit->Backspace();
613 }
614
615 FX_BOOL CPWL_EditCtrl::CanUndo() const
616 {
617         return !IsReadOnly() && m_pEdit->CanUndo();
618 }
619
620 FX_BOOL CPWL_EditCtrl::CanRedo() const
621 {
622         return !IsReadOnly() && m_pEdit->CanRedo();
623 }
624
625 void CPWL_EditCtrl::Redo()
626 {
627         if (CanRedo())
628                 m_pEdit->Redo();
629 }
630
631 void CPWL_EditCtrl::Undo()
632 {
633         if (CanUndo())
634                 m_pEdit->Undo();
635 }
636
637 void CPWL_EditCtrl::IOnSetScrollInfoY(FX_FLOAT fPlateMin, FX_FLOAT fPlateMax, 
638                                                                                                 FX_FLOAT fContentMin, FX_FLOAT fContentMax, 
639                                                                                                 FX_FLOAT fSmallStep, FX_FLOAT fBigStep)
640 {
641         PWL_SCROLL_INFO Info;
642
643         Info.fPlateWidth = fPlateMax - fPlateMin;
644         Info.fContentMin = fContentMin;
645         Info.fContentMax = fContentMax;
646         Info.fSmallStep = fSmallStep;
647         Info.fBigStep = fBigStep;
648
649         this->OnNotify(this,PNM_SETSCROLLINFO,SBT_VSCROLL,(intptr_t)&Info);
650
651 //      PWL_TRACE("set scroll info:%f\n",fContentMax - fContentMin);
652
653         if (IsFloatBigger(Info.fPlateWidth,Info.fContentMax-Info.fContentMin)
654                 || IsFloatEqual(Info.fPlateWidth,Info.fContentMax-Info.fContentMin))
655         {
656                 this->ShowVScrollBar(FALSE);            
657         }
658         else
659         {
660                 this->ShowVScrollBar(TRUE);
661         }
662 }
663
664 void CPWL_EditCtrl::IOnSetScrollPosY(FX_FLOAT fy)
665 {
666 //      PWL_TRACE("set scroll position:%f\n",fy);
667         this->OnNotify(this,PNM_SETSCROLLPOS,SBT_VSCROLL,(intptr_t)&fy);
668 }
669
670 void CPWL_EditCtrl::IOnSetCaret(FX_BOOL bVisible, const CPDF_Point & ptHead, const CPDF_Point & ptFoot, const CPVT_WordPlace& place)
671 {
672         PWL_CARET_INFO cInfo;
673         cInfo.bVisible = bVisible;
674         cInfo.ptHead = ptHead;
675         cInfo.ptFoot = ptFoot;
676
677         this->OnNotify(this,PNM_SETCARETINFO,(intptr_t)&cInfo,(intptr_t)NULL);
678 }
679
680 void CPWL_EditCtrl::IOnCaretChange(const CPVT_SecProps & secProps, const CPVT_WordProps & wordProps)
681 {
682 }
683
684 void CPWL_EditCtrl::IOnContentChange(const CPDF_Rect& rcContent)
685 {
686         if (this->IsValid())
687         {
688                 if (m_pEditNotify)
689                 {
690                         m_pEditNotify->OnContentChange(rcContent);
691                 }
692         }
693 }
694
695 void CPWL_EditCtrl::IOnInvalidateRect(CPDF_Rect * pRect)
696 {
697         this->InvalidateRect(pRect);
698 }
699
700 int32_t CPWL_EditCtrl::GetCharSet() const
701 {
702         if (m_nCharSet < 0)
703                 return DEFAULT_CHARSET; 
704         else
705                 return m_nCharSet;
706 }
707
708 void CPWL_EditCtrl::GetTextRange(const CPDF_Rect& rect, int32_t & nStartChar, int32_t & nEndChar) const
709 {
710         nStartChar = m_pEdit->WordPlaceToWordIndex(m_pEdit->SearchWordPlace(CPDF_Point(rect.left, rect.top)));
711         nEndChar = m_pEdit->WordPlaceToWordIndex(m_pEdit->SearchWordPlace(CPDF_Point(rect.right, rect.bottom)));
712 }
713
714 CFX_WideString CPWL_EditCtrl::GetText(int32_t & nStartChar, int32_t & nEndChar) const
715 {
716         CPVT_WordPlace wpStart = m_pEdit->WordIndexToWordPlace(nStartChar);
717         CPVT_WordPlace wpEnd = m_pEdit->WordIndexToWordPlace(nEndChar);
718         return m_pEdit->GetRangeText(CPVT_WordRange(wpStart, wpEnd));
719 }
720
721 void    CPWL_EditCtrl::SetReadyToInput()
722 {
723         if (m_bMouseDown)
724         {
725                 ReleaseCapture();
726                 m_bMouseDown = FALSE;
727         }
728 }