Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
MFC.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Foundation/Characters/LineEndings.h"
7
8namespace Stroika::Frameworks::Led::Platform {
9
10 /*
11 @METHOD: AsCPoint
12 @DESCRIPTION: Convert a @'Led_Point' to an MFC CPoint.
13 <p>See also @'AsLedPoint', @'AsCRect', @'AsLedRect'.
14 */
15 inline CPoint AsCPoint (Led_Point p)
16 {
17 return CPoint (p.h, p.v);
18 }
19 /*
20 @METHOD: AsLedPoint
21 @DESCRIPTION: Convert an MFC CPoint to a @'Led_Point'.
22 <p>See also @'AsCPoint', @'AsCRect', @'AsLedRect'.
23 */
24 inline Led_Point AsLedPoint (CPoint p)
25 {
26 return Led_Point (p.y, p.x);
27 }
28 /*
29 @METHOD: AsCRect
30 @DESCRIPTION: Convert a Led_Rect to an MFC CRect.
31 <p>See also @'AsCPoint', @'AsLedPoint', @'AsLedRect'.
32 */
33 inline CRect AsCRect (Led_Rect r)
34 {
35 return CRect (r.left, r.top, r.right, r.bottom);
36 }
37 /*
38 @METHOD: AsLedRect
39 @DESCRIPTION: Convert an MFC CRect to a Led_Rect.
40 <p>See also @'AsCPoint', @'AsLedPoint', @'AsCRect'.
41 */
42 inline Led_Rect AsLedRect (CRect r)
43 {
44 return Led_Rect (r.top, r.left, r.Height (), r.Width ());
45 }
46 /*
47 @METHOD: AsCSize
48 @DESCRIPTION: Convert a Led_Size to an MFC CSize.
49 */
50 inline CSize AsCSize (Led_Size s)
51 {
52 return CSize (s.h, s.v);
53 }
54
55 // class Led_MFC_CDCFromTablet
56 inline Led_MFC_CDCFromTablet::Led_MFC_CDCFromTablet (Tablet* t)
57 : fCDC ()
58 {
60 fCDC.m_hDC = t->m_hDC;
61 fCDC.m_hAttribDC = t->m_hAttribDC;
62 fCDC.m_bPrinting = t->m_bPrinting;
63 }
64 inline Led_MFC_CDCFromTablet::~Led_MFC_CDCFromTablet ()
65 {
66 fCDC.Detach ();
67 }
68 inline Led_MFC_CDCFromTablet::operator CDC* ()
69 {
70 return &fCDC;
71 }
72
73 // class Led_MFC_TabletFromCDC
74 inline Led_MFC_TabletFromCDC::Led_MFC_TabletFromCDC (CDC* pDC)
75 : fTablet ()
76 {
77 RequireNotNull (pDC);
78 fTablet.m_hDC = pDC->m_hDC;
79 fTablet.m_hAttribDC = pDC->m_hAttribDC;
80 fTablet.m_bPrinting = pDC->m_bPrinting;
81 }
82 inline Led_MFC_TabletFromCDC::~Led_MFC_TabletFromCDC ()
83 {
84 fTablet.Detach ();
85 }
86 inline Led_MFC_TabletFromCDC::operator Tablet* ()
87 {
88 return &fTablet;
89 }
90 inline Tablet* Led_MFC_TabletFromCDC::operator->()
91 {
92 return &fTablet;
93 }
94
95 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
96 inline Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::Led_MFC_Helper ()
97 : LED_WIN32_HELPER ()
98 , MFC_BASE_CLASS ()
99 {
100 }
101 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
102 inline Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::~Led_MFC_Helper ()
103 {
104 }
105 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
106 HWND Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::GetHWND () const
107 {
108 return this->m_hWnd;
109 }
110 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
111 int Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnCreate (LPCREATESTRUCT lpCreateStruct)
112 {
113 RequireNotNull (lpCreateStruct);
114 if (MFC_BASE_CLASS::OnCreate (lpCreateStruct) != 0) {
115 return -1; // failed to create
116 }
117 this->TabletChangedMetrics (); // maybe should catch failures here, and return -1?
118 if ((lpCreateStruct->style & WS_VSCROLL) and this->GetScrollBarType (TextInteractor::v) == TextInteractor::eScrollBarNever) {
119 this->SetScrollBarType (TextInteractor::v, TextInteractor::eScrollBarAlways);
120 }
121 if ((lpCreateStruct->style & WS_HSCROLL) and this->GetScrollBarType (TextInteractor::h) == TextInteractor::eScrollBarNever) {
122 this->SetScrollBarType (TextInteractor::h, TextInteractor::eScrollBarAlways);
123 }
124 return 0; // sucess
125 }
126 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
127 void Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnPaint ()
128 {
129 CPaintDC dc (this);
130 CRect boundsRect = CRect (0, 0, 0, 0);
131 Verify (dc.GetClipBox (&boundsRect) != ERROR);
132 this->WindowDrawHelper (Led_MFC_TabletFromCDC (&dc), AsLedRect (boundsRect), false);
133 }
134 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
135 /*
136 @METHOD: Led_MFC_Helper<MFC_BASE_CLASS,BASE_INTERACTOR>::OnSetCursor
137 @DESCRIPTION: Hook the Win32 SDK WM_SETCURSOR message to handle set the cursor to an I-Beam, as appropriate. When over
138 draggable text, instead use a standard arrow cursor.
139 */
140 BOOL Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnSetCursor (CWnd* pWnd, UINT nHitTest, UINT message)
141 {
142 return this->OnSetCursor_Msg (pWnd->GetSafeHwnd (), nHitTest, message);
143 }
144 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
145 UINT Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnGetDlgCode ()
146 {
147 return this->OnGetDlgCode_Msg ();
148 }
149 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
150 void Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnChar (UINT nChar, UINT nRepCnt, UINT nFlags)
151 {
152 this->OnChar_Msg (nChar, nRepCnt + (nFlags << 16));
153 }
154 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
155 void Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnKeyDown (UINT nChar, UINT nRepCnt, UINT nFlags)
156 {
157 this->OnKeyDown_Msg (nChar, nRepCnt + (nFlags << 16));
158 }
159 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
160 void Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnMouseMove (UINT nFlags, CPoint oPoint)
161 {
162 this->OnMouseMove_Msg (nFlags, oPoint.x, oPoint.y);
163 }
164 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
165 /*
166 @METHOD: Led_MFC_Helper<MFC_BASE_CLASS,BASE_INTERACTOR>::ReplaceWindow
167 @DESCRIPTION: <p>Similar to @'Led_Win32_SimpleWndProc_Helper<BASE_INTERACTOR>::ReplaceWindow'
168 except that it works with MFC windows and MFC's CWnd message maps etc.
169 </p>
170 */
171 BOOL Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::ReplaceWindow (HWND hWnd)
172 {
173 CWnd* parent = MFC_BASE_CLASS::FromHandle (hWnd)->GetParent ();
174 HWND hwndParent = parent->GetSafeHwnd ();
175 if (hwndParent == NULL) {
176 return false;
177 }
178
179 int id = ::GetWindowLong (hWnd, GWL_ID);
180
181 HWND hwndEdit = ::GetDlgItem (hwndParent, id);
182 AssertNotNull (hwndEdit);
183
184 DWORD dwStyle = ::GetWindowLong (hwndEdit, GWL_STYLE);
185 DWORD exStyle = ::GetWindowLong (hwndEdit, GWL_EXSTYLE);
186
187 // Assume edit widget's position.
188 WINDOWPLACEMENT wp;
189 memset (&wp, 0, sizeof (wp));
190 wp.length = sizeof (wp);
191 Verify (::GetWindowPlacement (hwndEdit, &wp));
192
193 // Delete the edit widget window.
194 ::DestroyWindow (hwndEdit);
195
196 return MFC_BASE_CLASS::CreateEx (exStyle, NULL, NULL, dwStyle | WS_CHILD, wp.rcNormalPosition.left, wp.rcNormalPosition.top,
197 wp.rcNormalPosition.right - wp.rcNormalPosition.left,
198 wp.rcNormalPosition.bottom - wp.rcNormalPosition.top, parent->GetSafeHwnd (), (HMENU)id, NULL);
199 }
200 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
201 /*
202 @METHOD: Led_MFC_Helper<MFC_BASE_CLASS,BASE_INTERACTOR>::GetWindowRect
203 @DESCRIPTION: Return the Led WindowRect. This name is a somewhat unfortunate choice for Windows, because WindowRect means something
204 vaguely similar, but substantially different in the Win32 SDK.
205 <p>In the future, I may need to consider changing this name. But for now, I can think of none better.
206 <p>I provide two overloads of this routine. The one that returns a Led_Rect returns the Led WindowRect. And the one
207 that takes an LPRECT parameter returns the Win32 SDK WindowRect.
208 */
209 inline Led_Rect Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::GetWindowRect () const
210 {
211 return TextImager::GetWindowRect ();
212 }
213 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
214 inline void Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::GetWindowRect (LPRECT lpRect) const
215 {
216 // The CWnd version of GetWindowRect ()
217 const CWnd* cwnd = this;
218 CWnd* wnd = const_cast<CWnd*> (cwnd);
219 wnd->GetWindowRect (lpRect);
220 }
221 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
222 inline DWORD Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::GetStyle () const
223 {
224 return MFC_BASE_CLASS::GetStyle ();
225 }
226 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
227 void Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnLButtonDown (UINT nFlags, CPoint oPoint)
228 {
229 this->OnLButtonDown_Msg (nFlags, oPoint.x, oPoint.y);
230 }
231 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
232 void Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnLButtonUp (UINT nFlags, CPoint oPoint)
233 {
234 this->OnLButtonUp_Msg (nFlags, oPoint.x, oPoint.y);
235 }
236 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
237 void Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnLButtonDblClk (UINT nFlags, CPoint oPoint)
238 {
239 this->OnLButtonDblClk_Msg (nFlags, oPoint.x, oPoint.y);
240 }
241 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
242 void Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnSetFocus (CWnd* pOldWnd)
243 {
244 MFC_BASE_CLASS::OnSetFocus (pOldWnd);
245 this->OnSetFocus_Msg (pOldWnd->GetSafeHwnd ());
246 }
247 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
248 void Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnKillFocus (CWnd* pNewWnd)
249 {
250 this->OnKillFocus_Msg (pNewWnd->GetSafeHwnd ());
251 MFC_BASE_CLASS::OnKillFocus (pNewWnd);
252 }
253 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
254 void Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnSize (UINT nType, int cx, int cy)
255 {
256 MFC_BASE_CLASS::OnSize (nType, cx, cy);
257 this->OnSize_Msg ();
258 }
259 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
260 BOOL Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnEraseBkgnd (CDC* pDC)
261 {
262 return this->OnEraseBkgnd_Msg (pDC->GetSafeHdc ());
263 }
264 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
265 void Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnVScroll (UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
266 {
267 this->OnVScroll_Msg (nSBCode, nPos, pScrollBar->GetSafeHwnd ());
268 }
269 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
270 void Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnHScroll (UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
271 {
272 this->OnHScroll_Msg (nSBCode, nPos, pScrollBar->GetSafeHwnd ());
273 }
274 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
275 BOOL Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnMouseWheel (UINT fFlags, short zDelta, CPoint point)
276 {
277 return this->OnMouseWheel_Msg (MAKEWPARAM (fFlags, zDelta), MAKELPARAM (point.x, point.y));
278 }
279 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
280 void Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnEnable (BOOL bEnable)
281 {
282 this->OnEnable_Msg (!!bEnable);
283 }
284 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
285 void Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnTimer (UINT_PTR nEventID)
286 {
287 this->OnTimer_Msg (nEventID, NULL);
288 }
289 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
290 inline LRESULT Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnUniChar ([[maybe_unused]] WPARAM wParam, [[maybe_unused]] LPARAM lParam)
291 {
292 return LED_WIN32_HELPER::OnUniChar_Msg (wParam, lParam);
293 }
294 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
295 inline LRESULT Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnIMEChar ([[maybe_unused]] WPARAM wParam, [[maybe_unused]] LPARAM lParam)
296 {
297#if qHookIMEEndCompositionMessageToWorkAroundWin2KIMEForNonUNICODEBug
298 return LED_WIN32_HELPER::OnIMEChar_Msg (wParam, lParam);
299#else
300 return MFC_BASE_CLASS::Default ();
301#endif
302 }
303 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
304 inline LRESULT Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnIME_COMPOSITION ([[maybe_unused]] WPARAM wParam, [[maybe_unused]] LPARAM lParam)
305 {
306#if qHookIMEEndCompositionMessageToWorkAroundWin2KIMEForNonUNICODEBug
307 return LED_WIN32_HELPER::OnIME_COMPOSITION_Msg (wParam, lParam);
308#else
309 return MFC_BASE_CLASS::Default ();
310#endif
311 }
312 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
313 inline LRESULT Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnIME_ENDCOMPOSITION ([[maybe_unused]] WPARAM wParam, [[maybe_unused]] LPARAM lParam)
314 {
315#if qHookIMEEndCompositionMessageToWorkAroundWin2KIMEForNonUNICODEBug
316 return LED_WIN32_HELPER::OnIME_ENDCOMPOSITION_Msg (wParam, lParam);
317#else
318 return MFC_BASE_CLASS::Default ();
319#endif
320 }
321 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
322 void Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnUpdateCommand_MSG (CCmdUI* pCmdUI)
323 {
324 RequireNotNull (pCmdUI);
325 if (not this->OnUpdateCommand (Led_MFC_TmpCmdUpdater (pCmdUI))) {
326 pCmdUI->Enable (false); // disable commands by default (SPR#1462)
327 }
328 }
329 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
330 void Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::OnPerformCommand_MSG (UINT commandNumber)
331 {
332 using namespace Stroika::Foundation;
334 IdleManager::NonIdleContext nonIdleContext;
335 try {
336 (void)this->OnPerformCommand (MFC_CommandNumberMapping::Get ().Lookup (commandNumber));
337 }
338 catch (...) {
339 DbgTrace ("Ignoring / suppressing uncaught exception in PerformCommand: {}"_f, current_exception ());
340 }
341 }
342 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
343 const AFX_MSGMAP* Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::GetMessageMap () const
344 {
345 return this->GetThisMessageMap ();
346 }
347 template <typename MFC_BASE_CLASS, typename BASE_INTERACTOR>
348 const AFX_MSGMAP* PASCAL Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>::GetThisMessageMap ()
349 {
350 using ThisClass = Led_MFC_Helper<MFC_BASE_CLASS, BASE_INTERACTOR>;
351 using TheBaseClass = MFC_BASE_CLASS;
352 DISABLE_COMPILER_MSC_WARNING_START (4407) // Not sure this is safe to ignore but I think it is due to qMFCRequiresCWndLeftmostBaseClass
353 static const AFX_MSGMAP_ENTRY _messageEntries[] = {
354 ON_WM_CREATE () ON_WM_CHAR () ON_WM_TIMER () ON_WM_KEYDOWN () ON_WM_PAINT () ON_WM_MOUSEMOVE () ON_WM_LBUTTONDOWN ()
355 ON_WM_SETCURSOR () ON_WM_GETDLGCODE () ON_WM_LBUTTONUP () ON_WM_LBUTTONDBLCLK () ON_WM_SETFOCUS () ON_WM_KILLFOCUS ()
356 ON_WM_SIZE () ON_WM_ERASEBKGND () ON_WM_VSCROLL () ON_WM_HSCROLL () ON_WM_MOUSEWHEEL () ON_WM_ENABLE () ON_MESSAGE (
357 WM_UNICHAR, &OnUniChar) ON_MESSAGE (WM_IME_CHAR, &OnIMEChar) ON_MESSAGE (WM_IME_COMPOSITION, &OnIME_COMPOSITION)
358 ON_MESSAGE (WM_IME_ENDCOMPOSITION, &OnIME_ENDCOMPOSITION) LED_MFC_HANDLE_COMMAND_M (BASE_INTERACTOR::kUndo_CmdID)
359 LED_MFC_HANDLE_COMMAND_M (BASE_INTERACTOR::kRedo_CmdID) LED_MFC_HANDLE_COMMAND_M (BASE_INTERACTOR::kSelectAll_CmdID)
360 LED_MFC_HANDLE_COMMAND_M (BASE_INTERACTOR::kSelectWord_CmdID) LED_MFC_HANDLE_COMMAND_M (
361 BASE_INTERACTOR::kSelectTextRow_CmdID) LED_MFC_HANDLE_COMMAND_M (BASE_INTERACTOR::kSelectParagraph_CmdID)
362 LED_MFC_HANDLE_COMMAND_M (BASE_INTERACTOR::kCut_CmdID) LED_MFC_HANDLE_COMMAND_M (BASE_INTERACTOR::kCopy_CmdID)
363 LED_MFC_HANDLE_COMMAND_M (BASE_INTERACTOR::kPaste_CmdID) LED_MFC_HANDLE_COMMAND_M (BASE_INTERACTOR::kClear_CmdID)
364 LED_MFC_HANDLE_COMMAND_M (BASE_INTERACTOR::kFind_CmdID) LED_MFC_HANDLE_COMMAND_M (BASE_INTERACTOR::kFindAgain_CmdID)
365 LED_MFC_HANDLE_COMMAND_M (BASE_INTERACTOR::kEnterFindString_CmdID)
366 LED_MFC_HANDLE_COMMAND_M (BASE_INTERACTOR::kReplace_CmdID)
367 LED_MFC_HANDLE_COMMAND_M (BASE_INTERACTOR::kReplaceAgain_CmdID) LED_MFC_HANDLE_COMMAND_M (
368 BASE_INTERACTOR::kSpellCheck_CmdID){0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0}};
369 DISABLE_COMPILER_MSC_WARNING_END (4407)
370 static const AFX_MSGMAP messageMap = {&TheBaseClass::GetThisMessageMap, &_messageEntries[0]};
371 return &messageMap;
372 }
373
374 // class Led_MFC_MimicMFCAPIHelper<BASECLASS>
375 template <typename BASECLASS>
376 inline BOOL Led_MFC_MimicMFCAPIHelper<BASECLASS>::Create (DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
377 {
378 return BASECLASS::Create (NULL, NULL, dwStyle, rect, pParentWnd, nID);
379 }
380 template <typename BASECLASS>
381 inline BOOL Led_MFC_MimicMFCAPIHelper<BASECLASS>::CanUndo () const
382 {
383 Assert (::IsWindow (this->m_hWnd));
384 return (BOOL)::SendMessage (this->m_hWnd, EM_CANUNDO, 0, 0);
385 }
386 template <typename BASECLASS>
387 inline int Led_MFC_MimicMFCAPIHelper<BASECLASS>::GetLineCount_CEdit () const
388 {
389 Assert (::IsWindow (this->m_hWnd));
390 return (int)::SendMessage (this->m_hWnd, EM_GETLINECOUNT, 0, 0);
391 }
392 template <typename BASECLASS>
393 inline BOOL Led_MFC_MimicMFCAPIHelper<BASECLASS>::GetModify () const
394 {
395 Assert (false); // though THIS code is fine - we haven't yet hooked the callback, so this call will
396 // produce poor results... LGP 941129
397 Assert (::IsWindow (this->m_hWnd));
398 return (BOOL)::SendMessage (this->m_hWnd, EM_GETMODIFY, 0, 0);
399 }
400 template <typename BASECLASS>
401 inline void Led_MFC_MimicMFCAPIHelper<BASECLASS>::SetModify (BOOL bModified)
402 {
403 Assert (false); // though THIS code is fine - we haven't yet hooked the callback, so this call will
404 // produce poor results... LGP 941129
405 Assert (::IsWindow (this->m_hWnd));
406 ::SendMessage (this->m_hWnd, EM_SETMODIFY, bModified, 0);
407 }
408 template <typename BASECLASS>
409 inline void Led_MFC_MimicMFCAPIHelper<BASECLASS>::GetRect (LPRECT lpRect) const
410 {
411 Assert (false); // though THIS code is fine - we haven't yet hooked the callback, so this call will
412 // produce poor results... LGP 941129
413 Assert (::IsWindow (this->m_hWnd));
414 ::SendMessage (this->m_hWnd, EM_GETRECT, 0, (LPARAM)lpRect);
415 }
416 template <typename BASECLASS>
417 inline void Led_MFC_MimicMFCAPIHelper<BASECLASS>::GetSel (int& nStartChar, int& nEndChar) const
418 {
419 Assert (::IsWindow (this->m_hWnd));
420 ::SendMessage (this->m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar);
421 }
422 template <typename BASECLASS>
423 inline DWORD Led_MFC_MimicMFCAPIHelper<BASECLASS>::GetSel () const
424 {
425 Assert (::IsWindow (this->m_hWnd));
426 return ::SendMessage (this->m_hWnd, EM_GETSEL, 0, 0);
427 }
428 template <typename BASECLASS>
429 inline int Led_MFC_MimicMFCAPIHelper<BASECLASS>::GetLine (int nIndex, LPTSTR lpszBuffer) const
430 {
431 Assert (false); // though THIS code is fine - we haven't yet hooked the callback, so this call will
432 // produce poor results... LGP 941129
433 Assert (::IsWindow (this->m_hWnd));
434 return (int)::SendMessage (this->m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer);
435 }
436 template <typename BASECLASS>
437 inline int Led_MFC_MimicMFCAPIHelper<BASECLASS>::GetLine (int nIndex, LPTSTR lpszBuffer, int nMaxLength) const
438 {
439 Assert (false); // though THIS code is fine - we haven't yet hooked the callback, so this call will
440 // produce poor results... LGP 941129
441 Assert (::IsWindow (this->m_hWnd));
442 *(LPWORD)lpszBuffer = (WORD)nMaxLength;
443 return (int)::SendMessage (this->m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer);
444 }
445 template <typename BASECLASS>
446 inline void Led_MFC_MimicMFCAPIHelper<BASECLASS>::EmptyUndoBuffer ()
447 {
448 Assert (::IsWindow (this->m_hWnd));
449 ::SendMessage (this->m_hWnd, EM_EMPTYUNDOBUFFER, 0, 0);
450 }
451 template <typename BASECLASS>
452 inline BOOL Led_MFC_MimicMFCAPIHelper<BASECLASS>::FmtLines (BOOL bAddEOL)
453 {
454 Assert (false); // though THIS code is fine - we haven't yet hooked the callback, so this call will
455 // produce poor results... LGP 941129
456 Assert (::IsWindow (this->m_hWnd));
457 return (BOOL)::SendMessage (this->m_hWnd, EM_FMTLINES, bAddEOL, 0);
458 }
459 template <typename BASECLASS>
460 inline void Led_MFC_MimicMFCAPIHelper<BASECLASS>::LimitText (int nChars)
461 {
462 Assert (false); // though THIS code is fine - we haven't yet hooked the callback, so this call will
463 // produce poor results... LGP 941129
464 Assert (::IsWindow (this->m_hWnd));
465 ::SendMessage (this->m_hWnd, EM_LIMITTEXT, nChars, 0);
466 }
467 template <typename BASECLASS>
468 inline int Led_MFC_MimicMFCAPIHelper<BASECLASS>::LineFromChar (int nIndex) const
469 {
470 Assert (::IsWindow (this->m_hWnd));
471 return (int)::SendMessage (this->m_hWnd, EM_LINEFROMCHAR, nIndex, 0);
472 }
473 template <typename BASECLASS>
474 inline int Led_MFC_MimicMFCAPIHelper<BASECLASS>::LineIndex (int nLine) const
475 {
476 Assert (::IsWindow (this->m_hWnd));
477 return (int)::SendMessage (this->m_hWnd, EM_LINEINDEX, nLine, 0);
478 }
479 template <typename BASECLASS>
480 inline int Led_MFC_MimicMFCAPIHelper<BASECLASS>::LineLength (int nLine) const
481 {
482 Assert (::IsWindow (this->m_hWnd));
483 return (int)::SendMessage (this->m_hWnd, EM_LINELENGTH, nLine, 0);
484 }
485 template <typename BASECLASS>
486 inline void Led_MFC_MimicMFCAPIHelper<BASECLASS>::LineScroll (int nLines, int nChars)
487 {
488 Assert (::IsWindow (this->m_hWnd));
489 ::SendMessage (this->m_hWnd, EM_LINESCROLL, nChars, nLines);
490 }
491 template <typename BASECLASS>
492 inline void Led_MFC_MimicMFCAPIHelper<BASECLASS>::ReplaceSel (LPCTSTR lpszNewText)
493 {
494 AssertNotNull (lpszNewText);
495 Assert (::IsWindow (this->m_hWnd));
496 ::SendMessage (this->m_hWnd, EM_REPLACESEL, 0, (LPARAM)lpszNewText);
497 }
498 template <typename BASECLASS>
499 inline void Led_MFC_MimicMFCAPIHelper<BASECLASS>::SetPasswordChar (TCHAR ch)
500 {
501 Assert (false); // though THIS code is fine - we haven't yet hooked the callback, so this call will
502 // produce poor results... LGP 941129
503 Assert (::IsWindow (this->m_hWnd));
504 ::SendMessage (this->m_hWnd, EM_SETPASSWORDCHAR, ch, 0);
505 }
506 template <typename BASECLASS>
507 inline void Led_MFC_MimicMFCAPIHelper<BASECLASS>::SetRect (LPCRECT lpRect)
508 {
509 Assert (false); // though THIS code is fine - we haven't yet hooked the callback, so this call will
510 // produce poor results... LGP 941129
511 Assert (::IsWindow (this->m_hWnd));
512 ::SendMessage (this->m_hWnd, EM_SETRECT, 0, (LPARAM)lpRect);
513 }
514 template <typename BASECLASS>
515 inline void Led_MFC_MimicMFCAPIHelper<BASECLASS>::SetRectNP (LPCRECT lpRect)
516 {
517 Assert (false); // though THIS code is fine - we haven't yet hooked the callback, so this call will
518 // produce poor results... LGP 941129
519 Assert (::IsWindow (this->m_hWnd));
520 ::SendMessage (this->m_hWnd, EM_SETRECTNP, 0, (LPARAM)lpRect);
521 }
522 template <typename BASECLASS>
523 inline void Led_MFC_MimicMFCAPIHelper<BASECLASS>::SetSel (DWORD dwSelection, BOOL bNoScroll)
524 {
525 Assert (::IsWindow (this->m_hWnd));
526 ::SendMessage (this->m_hWnd, EM_SETSEL, LOWORD (dwSelection), HIWORD (dwSelection));
527 if (not bNoScroll) {
528 ::SendMessage (this->m_hWnd, EM_SCROLLCARET, 0, 0);
529 }
530 }
531 template <typename BASECLASS>
532 inline void Led_MFC_MimicMFCAPIHelper<BASECLASS>::SetSel (int nStartChar, int nEndChar, BOOL bNoScroll)
533 {
534 Assert (::IsWindow (this->m_hWnd));
535 ::SendMessage (this->m_hWnd, EM_SETSEL, nStartChar, nEndChar);
536 if (not bNoScroll) {
537 ::SendMessage (this->m_hWnd, EM_SCROLLCARET, 0, 0);
538 }
539 }
540 template <typename BASECLASS>
541 inline BOOL Led_MFC_MimicMFCAPIHelper<BASECLASS>::SetTabStops (int nTabStops, LPINT rgTabStops)
542 {
543 Assert (false); // though THIS code is fine - we haven't yet hooked the callback, so this call will
544 // produce poor results... LGP 941129
545 Assert (::IsWindow (this->m_hWnd));
546 return (BOOL)::SendMessage (this->m_hWnd, EM_SETTABSTOPS, nTabStops, (LPARAM)rgTabStops);
547 }
548 template <typename BASECLASS>
549 inline void Led_MFC_MimicMFCAPIHelper<BASECLASS>::SetTabStops ()
550 {
551 Assert (false); // though THIS code is fine - we haven't yet hooked the callback, so this call will
552 // produce poor results... LGP 941129
553 Assert (::IsWindow (this->m_hWnd));
554 Verify (::SendMessage (this->m_hWnd, EM_SETTABSTOPS, 0, 0));
555 }
556 template <typename BASECLASS>
557 inline BOOL Led_MFC_MimicMFCAPIHelper<BASECLASS>::SetTabStops (const int& cxEachStop)
558 {
559 Assert (false); // though THIS code is fine - we haven't yet hooked the callback, so this call will
560 // produce poor results... LGP 941129
561 Assert (::IsWindow (this->m_hWnd));
562 return (BOOL)::SendMessage (this->m_hWnd, EM_SETTABSTOPS, 1, (LPARAM)(LPINT)&cxEachStop);
563 }
564 template <typename BASECLASS>
565 inline BOOL Led_MFC_MimicMFCAPIHelper<BASECLASS>::Undo ()
566 {
567 Assert (::IsWindow (this->m_hWnd));
568 return (BOOL)::SendMessage (this->m_hWnd, EM_UNDO, 0, 0);
569 }
570 template <typename BASECLASS>
571 inline void Led_MFC_MimicMFCAPIHelper<BASECLASS>::Clear ()
572 {
573 Assert (::IsWindow (this->m_hWnd));
574 ::SendMessage (this->m_hWnd, WM_CLEAR, 0, 0);
575 }
576 template <typename BASECLASS>
577 inline void Led_MFC_MimicMFCAPIHelper<BASECLASS>::Copy ()
578 {
579 Assert (::IsWindow (this->m_hWnd));
580 ::SendMessage (this->m_hWnd, WM_COPY, 0, 0);
581 }
582 template <typename BASECLASS>
583 inline void Led_MFC_MimicMFCAPIHelper<BASECLASS>::Cut ()
584 {
585 Assert (::IsWindow (this->m_hWnd));
586 ::SendMessage (this->m_hWnd, WM_CUT, 0, 0);
587 }
588 template <typename BASECLASS>
589 inline void Led_MFC_MimicMFCAPIHelper<BASECLASS>::Paste ()
590 {
591 Assert (::IsWindow (this->m_hWnd));
592 ::SendMessage (this->m_hWnd, WM_PASTE, 0, 0);
593 }
594 template <typename BASECLASS>
595 inline BOOL Led_MFC_MimicMFCAPIHelper<BASECLASS>::SetReadOnly (BOOL bReadOnly)
596 {
597 Assert (::IsWindow (this->m_hWnd));
598 return (BOOL)::SendMessage (this->m_hWnd, EM_SETREADONLY, bReadOnly, 0L);
599 }
600 template <typename BASECLASS>
601 inline int Led_MFC_MimicMFCAPIHelper<BASECLASS>::GetFirstVisibleLine () const
602 {
603 Assert (::IsWindow (this->m_hWnd));
604 return (int)::SendMessage (this->m_hWnd, EM_GETFIRSTVISIBLELINE, 0, 0L);
605 }
606 template <typename BASECLASS>
607 inline TCHAR Led_MFC_MimicMFCAPIHelper<BASECLASS>::GetPasswordChar () const
608 {
609 Assert (false); // though THIS code is fine - we haven't yet hooked the callback, so this call will
610 // produce poor results... LGP 941129
611 Assert (::IsWindow (this->m_hWnd));
612 return (TCHAR)::SendMessage (this->m_hWnd, EM_GETPASSWORDCHAR, 0, 0L);
613 }
614
615 // class Led_MFC_OptionalWin32SDKMessageMimicHelper<BASECLASS>
616 template <typename BASECLASS>
617 const AFX_MSGMAP* Led_MFC_OptionalWin32SDKMessageMimicHelper<BASECLASS>::GetMessageMap () const
618 {
619 return GetThisMessageMap ();
620 }
621 template <typename BASECLASS>
622 const AFX_MSGMAP* PASCAL Led_MFC_OptionalWin32SDKMessageMimicHelper<BASECLASS>::GetThisMessageMap ()
623 {
624 using ThisClass = Led_MFC_OptionalWin32SDKMessageMimicHelper<BASECLASS>;
625 using TheBaseClass = BASECLASS;
626 DISABLE_COMPILER_MSC_WARNING_START (4407) // Not sure this is safe to ignore but I think it is due to qMFCRequiresCWndLeftmostBaseClass
627 static const AFX_MSGMAP_ENTRY _messageEntries[] = {
628 ON_MESSAGE (WM_SETTEXT, &OnMFCSDKMessageDispatcher<WM_SETTEXT>) ON_MESSAGE (WM_GETTEXT, &OnMFCSDKMessageDispatcher<WM_GETTEXT>)
629 ON_MESSAGE (WM_GETTEXTLENGTH, &OnMFCSDKMessageDispatcher<WM_GETTEXTLENGTH>) ON_MESSAGE (
630 EM_GETSEL, &OnMFCSDKMessageDispatcher<EM_GETSEL>) ON_MESSAGE (EM_SETREADONLY, &OnMFCSDKMessageDispatcher<EM_SETREADONLY>)
631 ON_MESSAGE (EM_GETFIRSTVISIBLELINE, &OnMFCSDKMessageDispatcher<EM_GETFIRSTVISIBLELINE>) ON_MESSAGE (
632 EM_LINEINDEX, &OnMFCSDKMessageDispatcher<EM_LINEINDEX>) ON_MESSAGE (EM_GETLINECOUNT, &OnMFCSDKMessageDispatcher<EM_GETLINECOUNT>)
633 ON_MESSAGE (EM_CANUNDO, &OnMFCSDKMessageDispatcher<EM_CANUNDO>) ON_MESSAGE (EM_UNDO, &OnMFCSDKMessageDispatcher<EM_UNDO>)
634 ON_MESSAGE (EM_EMPTYUNDOBUFFER, &OnMFCSDKMessageDispatcher<EM_EMPTYUNDOBUFFER>)
635 ON_MESSAGE (WM_CLEAR, &OnMFCSDKMessageDispatcher<WM_CLEAR>) ON_MESSAGE (WM_CUT, &OnMFCSDKMessageDispatcher<WM_CUT>)
636 ON_MESSAGE (WM_COPY, &OnMFCSDKMessageDispatcher<WM_COPY>) ON_MESSAGE (WM_PASTE, &OnMFCSDKMessageDispatcher<WM_PASTE>)
637 ON_MESSAGE (EM_LINEFROMCHAR, &OnMFCSDKMessageDispatcher<EM_LINEFROMCHAR>)
638 ON_MESSAGE (EM_LINELENGTH, &OnMFCSDKMessageDispatcher<EM_LINELENGTH>)
639 ON_MESSAGE (EM_LINESCROLL, &OnMFCSDKMessageDispatcher<EM_LINESCROLL>)
640 ON_MESSAGE (EM_REPLACESEL, &OnMFCSDKMessageDispatcher<EM_REPLACESEL>)
641 ON_MESSAGE (EM_SETSEL, &OnMFCSDKMessageDispatcher<EM_SETSEL>)
642 ON_MESSAGE (EM_SCROLLCARET, &OnMFCSDKMessageDispatcher<EM_SCROLLCARET>)
643 ON_MESSAGE (WM_GETFONT, &OnMFCSDKMessageDispatcher<WM_GETFONT>)
644 ON_MESSAGE (WM_SETFONT, &OnMFCSDKMessageDispatcher<WM_SETFONT>){
645 0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0}};
646 DISABLE_COMPILER_MSC_WARNING_END (4407)
647 static const AFX_MSGMAP messageMap = {&TheBaseClass::GetThisMessageMap, &_messageEntries[0]};
648 return &messageMap;
649 }
650
651 // class Led_MFC_DragAndDropWindow<BASECLASS>
652 template <typename BASECLASS>
653 typename Led_MFC_DragAndDropWindow<BASECLASS>::LedStartDragAndDropContext* Led_MFC_DragAndDropWindow<BASECLASS>::sCurrentDragInfo = NULL;
654 template <typename BASECLASS>
655 Led_MFC_DragAndDropWindow<BASECLASS>::Led_MFC_DragAndDropWindow ()
656 : inherited ()
657 , fDropTarget ()
658 , fDragPoint ()
659 , fDragSize ()
660 , fDragOffset ()
661 , fPrevDropEffect (DROPEFFECT_NONE)
662 , fDragAutoScrollTimerID (0)
663 {
664 }
665 template <typename BASECLASS>
666 Led_MFC_DragAndDropWindow<BASECLASS>::~Led_MFC_DragAndDropWindow ()
667 {
668 Assert (fDragAutoScrollTimerID == 0);
669 }
670 template <typename BASECLASS>
671 /*
672 @METHOD: Led_MFC_DragAndDropWindow<BASECLASS>::GetCommandNames
673 @DESCRIPTION: Returns command name for each of the user-visible commands produced by this module.
674 This name is used used in the constructed Undo command name, as
675 in, "Undo Drag and Drop". You can replace this name with whatever you like.You change this value with
676 WordProcessor::SetCommandNames.
677 <p> The point of this is to allow for different UI-language localizations,
678 without having to change Led itself.
679 <p>See also @'Led_MFC_DragAndDropWindow<BASECLASS>::CommandNames'.
680 */
681 inline const Led_MFC_DragAndDropWindow<BASECLASS>::CommandNames& Led_MFC_DragAndDropWindow<BASECLASS>::GetCommandNames ()
682 {
683 return sCommandNames;
684 }
685 template <typename BASECLASS>
686 /*
687 @METHOD: Led_MFC_DragAndDropWindow<BASECLASS>::SetCommandNames
688 @DESCRIPTION: See @'Led_MFC_DragAndDropWindow<BASECLASS>::GetCommandNames'.
689 */
690 inline void Led_MFC_DragAndDropWindow<BASECLASS>::SetCommandNames (const typename Led_MFC_DragAndDropWindow<BASECLASS>::CommandNames& cmdNames)
691 {
692 sCommandNames = cmdNames;
693 }
694 template <typename BASECLASS>
695 typename Led_MFC_DragAndDropWindow<BASECLASS>::CommandNames Led_MFC_DragAndDropWindow<BASECLASS>::sCommandNames;
696 template <typename BASECLASS>
697 int Led_MFC_DragAndDropWindow<BASECLASS>::OnCreate (LPCREATESTRUCT lpCreateStruct)
698 {
699 if (inherited::OnCreate (lpCreateStruct) != 0) {
700 return -1; // failed to create
701 }
702 if (not fDropTarget.Register (this)) {
703 /*
704 * This can happen if the document associated with the view is not a COleDocument, for
705 * example. Shouldn't prevent Led view from being used. D&D just won't work...
706 */
707 TRACE (_T ("Warning: failed to register window as drop target\n"));
708 return 0; // treat this as OK - but warn above...
709 }
710 return 0; // success
711 }
712 template <typename BASECLASS>
713 bool Led_MFC_DragAndDropWindow<BASECLASS>::IsADragSelect (Led_Point clickedWhere) const
714 {
715 /*
716 * This seems to be what most people do. But I think this algorithm should
717 * be embellished, so we detect that the mouse is down for a while (a half second?)
718 * and then melt the drag into a regular selection. Also, pay attention to keys
719 * pressed etc as a hint of intent. But immediately return yes if we are moving
720 * what we've selected.
721 *
722 * For now though, just do it the simple way...
723 */
724 Region r;
725 this->GetSelectionWindowRegion (&r, this->GetSelectionStart (), this->GetSelectionEnd ());
726 return !!r.PtInRegion (AsCPoint (clickedWhere));
727 }
728 template <typename BASECLASS>
729 void Led_MFC_DragAndDropWindow<BASECLASS>::HandleDragSelect (UINT /*nFlags*/, CPoint oPoint)
730 {
731 const Foundation::Time::DurationSeconds kTimeEnoughToRestoreSelection = 0.3s;
732
733 using TextInteractor::eDefaultUpdate;
734
735 if (this->GetStyle () & WS_DISABLED) {
736 return;
737 }
738 if (this->GetFocus () != this) {
739 this->SetFocus ();
740 }
741
742 /*
743 * Be sure to reset these so on a double click after what looked like a single
744 * click we don't grab the old anchor (see spr#0438).
745 */
746 this->fMouseTrackingLastPoint = AsLedPoint (oPoint);
747 this->fDragAnchor = this->GetCharAtClickLocation (this->fMouseTrackingLastPoint);
748
749 Assert (sCurrentDragInfo == NULL);
750 sCurrentDragInfo = new LedStartDragAndDropContext{this};
751
752 sCurrentDragInfo->fOurDragStart = this->GetSelectionStart ();
753 sCurrentDragInfo->fOurDragEnd = this->GetSelectionEnd ();
754
755 try {
756 COleDataSource dataSrc;
757 Led_MFCWriterDAndDFlavorPackage flavorPackage (&dataSrc);
758 this->ExternalizeFlavors (flavorPackage);
759
760 Region selectionRegion;
761 this->GetSelectionWindowRegion (&selectionRegion, this->GetSelectionStart (), this->GetSelectionEnd ());
762
763 Foundation::Time::TimePointSeconds startDragSelectAt = Foundation::Time::GetTickCount (); // Grab it after the ExternalizeFlavors call in case thats slow (SPR#1498).
764 ::DROPEFFECT dropResult = DROPEFFECT_COPY;
765 if (not(this->GetStyle () & ES_READONLY)) {
766 // Assure we don't change read-only text.
767 dropResult |= DROPEFFECT_MOVE;
768 }
769 dropResult = dataSrc.DoDragDrop (dropResult);
771 if (this->GetStyle () & ES_READONLY) {
772 Assert (not(dropResult & DROPEFFECT_MOVE));
773 }
774 }
775 switch (dropResult) {
776 case DROPEFFECT_NONE: {
777 AssertNotNull (sCurrentDragInfo);
778 if (Foundation::Time::GetTickCount () - startDragSelectAt > kTimeEnoughToRestoreSelection) {
779 /*
780 * SPR#1374 - on aborted drag - restore the selection to its original value, rather
781 * than setting it to an empty selection where the user had clicked.
782 */
783 this->SetSelection (sCurrentDragInfo->fOurDragStart, sCurrentDragInfo->fOurDragEnd);
784 }
785 else {
786 // for a very short click - just treat it as a regular click - changing the
787 // selection to an insertion point where the user clicked.
788 size_t ignored = 0;
789 (void)this->ProcessSimpleClick (this->fMouseTrackingLastPoint, 1, false, &ignored);
790 }
791 } break;
792 case DROPEFFECT_MOVE: {
793 /*
794 * delete the original text on a MOVE
795 */
796 TextInteractor::InteractiveModeUpdater iuMode{*this};
797 AssertNotNull (sCurrentDragInfo);
798 TextInteractor::UndoableContextHelper undoContext (
799 *this, sCurrentDragInfo->fWeRecievedDrop ? SDKString{} : GetCommandNames ().fDragCommandName,
800 sCurrentDragInfo->fOrigSelection.GetStart (), sCurrentDragInfo->fOrigSelection.GetEnd (), true);
801 {
802 TextInteractor::InteractiveReplace_ (undoContext.GetUndoRegionStart (), undoContext.GetUndoRegionEnd (),
803 LED_TCHAR_OF (""), 0, false, false, eDefaultUpdate);
804 }
805 undoContext.CommandComplete (sCurrentDragInfo->fOrigSelection.GetEnd ());
806 } break;
807 default: {
808 // we do nothing then - I think....
809 }
810 }
811
812 // must do here, even if NOT a MOVE - cuz we skipped this in the OnDrop code...
813 this->BreakInGroupedCommands ();
814 }
815 catch (...) {
816 delete sCurrentDragInfo;
817 sCurrentDragInfo = NULL;
818 throw;
819 }
820
821 delete sCurrentDragInfo;
822 sCurrentDragInfo = NULL;
823 }
824 template <typename BASECLASS>
825 void Led_MFC_DragAndDropWindow<BASECLASS>::HandleSharedDragOverUpdateSelCode ()
826 {
827 using TextInteractor::eImmediateUpdate;
828 CClientDC dc (this);
829 if (fPrevDropEffect != DROPEFFECT_NONE) {
830 // erase previous focus rect
831 dc.DrawFocusRect (CRect (fDragPoint, fDragSize));
832 }
833
834 size_t newPos = this->GetCharAtClickLocation (AsLedPoint (fDragPoint));
835
836 // Auto-scroll if necessary...
837 if (newPos < this->GetMarkerPositionOfStartOfWindow ()) {
838 this->ScrollByIfRoom (-1, eImmediateUpdate);
839 }
840 else if (newPos > this->GetMarkerPositionOfEndOfWindow ()) {
841 this->ScrollByIfRoom (1, eImmediateUpdate);
842 }
843
844 if (fPrevDropEffect != DROPEFFECT_NONE) {
845 // draw new focus rect
846 dc.DrawFocusRect (CRect (fDragPoint, fDragSize));
847 }
848 }
849 template <typename BASECLASS>
850 DROPEFFECT Led_MFC_DragAndDropWindow<BASECLASS>::HelperDragEnter (COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
851 {
852 // We allow dropping any time - I think... - See page 444 of MSVC4.0 Visual C++ Tutorial for hints on how to check if we accept...
853 this->StartDragAutoscrollTimer ();
854 if (not GetObjectInfo (pDataObject, &fDragSize, &fDragOffset)) {
855 return DROPEFFECT_NONE;
856 }
857 CClientDC dc (NULL);
858 dc.HIMETRICtoDP (&fDragSize);
859 dc.HIMETRICtoDP (&fDragOffset);
860 DROPEFFECT result = this->HelperDragOver (pDataObject, dwKeyState, point);
861 return result;
862 }
863 template <typename BASECLASS>
864 DROPEFFECT Led_MFC_DragAndDropWindow<BASECLASS>::HelperDragOver (COleDataObject* /*pDataObject*/, DWORD dwKeyState, CPoint point)
865 {
866 using TextInteractor::eImmediateUpdate;
867 point -= fDragOffset; // adjust target rect by cursor offset
868
869 // See See page 444 of MSVC4.0 Visual C++ Tutorial for hints on how to check if we accept...
870
871 // now do draw of hilite...
872 DROPEFFECT de = DROPEFFECT_NONE;
873
874 if ((dwKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT)) {
875 de = DROPEFFECT_NONE; // we don't support linking...
876 }
877 else if ((dwKeyState & MK_CONTROL) == MK_CONTROL) {
878 de = DROPEFFECT_COPY;
879 }
880 else if ((dwKeyState & MK_ALT) == MK_ALT) {
881 de = DROPEFFECT_MOVE;
882 }
883 else {
884 de = DROPEFFECT_MOVE; // an unfortunate choice, but windows defaults to this apparently...
885 }
886
887 if (point != fDragPoint) {
888 // cursor has moved
889 CClientDC dc (this);
890 if (fPrevDropEffect != DROPEFFECT_NONE) {
891 // erase previous focus rect
892 dc.DrawFocusRect (CRect (fDragPoint, fDragSize));
893 }
894
895 size_t newPos = this->GetCharAtClickLocation (AsLedPoint (point));
896
897 // Disalow dragging selection ontop of itself...
898 if (sCurrentDragInfo != NULL and sCurrentDragInfo->fLedMFCView == this and
899 (newPos >= sCurrentDragInfo->fOurDragStart and newPos <= sCurrentDragInfo->fOurDragEnd)) {
900 this->SetSelection (sCurrentDragInfo->fOurDragStart, sCurrentDragInfo->fOurDragEnd);
901 this->Update ();
902 fPrevDropEffect = DROPEFFECT_NONE;
903 return DROPEFFECT_NONE;
904 }
905
906 // either scroll, or adjust the selection...
907 if (newPos < this->GetMarkerPositionOfStartOfWindow ()) {
908 this->ScrollByIfRoom (-1, eImmediateUpdate);
909 }
910 else if (newPos > this->GetMarkerPositionOfEndOfWindow ()) {
911 this->ScrollByIfRoom (1, eImmediateUpdate);
912 }
913
914 if (newPos >= this->GetMarkerPositionOfStartOfWindow () and newPos <= this->GetMarkerPositionOfEndOfWindow ()) {
915 this->SetSelection (newPos, newPos);
916 this->Update ();
917 }
918
919 fPrevDropEffect = de;
920 if (fPrevDropEffect != DROPEFFECT_NONE) {
921 // draw new focus rect
922 fDragPoint = point;
923 dc.DrawFocusRect (CRect (fDragPoint, fDragSize));
924 }
925 }
926
927 return de;
928 }
929 template <typename BASECLASS>
930 BOOL Led_MFC_DragAndDropWindow<BASECLASS>::HelperDrop (COleDataObject* pDataObject, DROPEFFECT /*dropEffect*/, CPoint /*point*/)
931 {
932 using namespace Stroika::Foundation;
933 RequireNotNull (pDataObject);
934
935 // Cleanup focus rect...
936 HelperDragLeave ();
937
938 if (sCurrentDragInfo != NULL and sCurrentDragInfo->fLedMFCView == this) {
939 sCurrentDragInfo->fWeRecievedDrop = true;
940 }
941
942#if 0
943 // debugging hack- leave in for now in case helpful to see whats in drop package...
944 // LGP 960502
945 {
946 pDataObject->BeginEnumFormats ();
947 FORMATETC formatC;
948 while (pDataObject->GetNextFormat (&formatC)) {
949 char buf[1024];
950 int nChars = ::GetClipboardFormatName (formatC.cfFormat, buf, sizeof buf);
951 int barf = 1; // set breakpoint here
952 }
953 }
954#endif
955
956 CWaitCursor busy;
957
958 Led_MFCReaderDAndDFlavorPackage flavors (pDataObject);
959
960 bool doSmartCNP = this->GetSmartCutAndPasteMode () and flavors.GetFlavorAvailable_TEXT ();
961 TextInteractor::SmartCNPInfo smartCNPInfo;
962 if (doSmartCNP) {
963 size_t length = flavors.GetFlavorSize (kTEXTClipFormat);
964 Led_ClipFormat textFormat = kTEXTClipFormat;
965 Memory::StackBuffer<Led_tChar> buf{Memory::eUninitialized, length}; // really could use smaller buffer
966 length = flavors.ReadFlavorData (textFormat, length, buf.data ());
967 if (doSmartCNP) {
968 size_t nTChars = length / sizeof (Led_tChar);
969 if (nTChars > 0) {
970 --nTChars; // on windows, the text buffer contains a trailing NUL-byte
971 }
972 doSmartCNP = this->LooksLikeSmartPastableText (buf.data (), nTChars, &smartCNPInfo);
973 }
974 }
975
976 this->BreakInGroupedCommands ();
977
978 TextInteractor::InteractiveModeUpdater iuMode (*this);
979 size_t ucSelStart = (sCurrentDragInfo != nullptr and sCurrentDragInfo->fLedMFCView == this) ? sCurrentDragInfo->fOrigSelection.GetStart ()
980 : this->GetSelectionStart ();
981 size_t ucSelEnd = (sCurrentDragInfo != nullptr and sCurrentDragInfo->fLedMFCView == this) ? sCurrentDragInfo->fOrigSelection.GetEnd ()
982 : this->GetSelectionEnd ();
983 TextInteractor::UndoableContextHelper undoContext (*this,
984 (sCurrentDragInfo != nullptr and sCurrentDragInfo->fLedMFCView == this)
985 ? GetCommandNames ().fDragNDropCommandName
986 : GetCommandNames ().fDropCommandName,
987 this->GetSelectionStart (), this->GetSelectionEnd (), ucSelStart, ucSelEnd, false);
988 {
989 try {
990 this->InternalizeBestFlavor (flavors);
991 }
992 catch (...) {
993#if _MFC_VER > 0x0E00
994// Known broken in 0x0421 and 0x0600 anx 0x700 (MSVC.Net), and 0x710 (MSVC.NET 2003), and 0x0A00 (MSVC.net 2010),
995// and 0x0B00 = Microsoft Foundation Classes version 11.00
996// and 0x0C00 = Microsoft Foundation Classes version 12.00
997// and 0x0E00 = MFC included with Visual Studio.net 2017
998#pragma message("See if MFC has fixed this bug yet")
999#endif
1000 // Cannot re-throw here, due to MFC bug in COleDropTarget::XDropTarget::Drop (), where
1001 // it fails to do a RELEASE() call in case we throw here. Returning FALSE still signifies the drop fialed, but
1002 // then the calling APP may not see a good message about what failed. Too bad.
1003 return false;
1004 throw;
1005 }
1006 if (doSmartCNP) {
1007 this->OptionallyAddExtraSpaceForSmartCutAndPasteModeAdds (undoContext.GetUndoRegionStart (), smartCNPInfo);
1008 }
1009 }
1010 undoContext.CommandComplete ();
1011
1012 // If WE INITED DRAG - don't do break here, do it in HandleDragSelect () so it can incorporate a DELETE TEXT on MOVE...
1013 if (sCurrentDragInfo == nullptr or sCurrentDragInfo->fLedMFCView != this) {
1014 this->BreakInGroupedCommands ();
1015 }
1016
1017 return true;
1018 }
1019 template <typename BASECLASS>
1020 void Led_MFC_DragAndDropWindow<BASECLASS>::HelperDragLeave ()
1021 {
1022 StopDragAutoscrollTimer ();
1023 if (fPrevDropEffect != DROPEFFECT_NONE) {
1024 CClientDC dc (this);
1025 // erase previous focus rect
1026 dc.DrawFocusRect (CRect (fDragPoint, fDragSize));
1027 fPrevDropEffect = DROPEFFECT_NONE;
1028 }
1029 }
1030 template <typename BASECLASS>
1031 bool Led_MFC_DragAndDropWindow<BASECLASS>::GetObjectInfo (COleDataObject* pDataObject, CSize* pSize, CSize* pOffset)
1032 {
1033 RequireNotNull (pDataObject);
1034 RequireNotNull (pSize);
1035 RequireNotNull (pOffset);
1036
1037 static CLIPFORMAT kObjectDescriptorFormatTag = (CLIPFORMAT)::RegisterClipboardFormat (_T("Object Descriptor"));
1038
1039 HGLOBAL hObjDesc = pDataObject->GetGlobalData (kObjectDescriptorFormatTag);
1040 if (hObjDesc == nullptr) {
1041 *pSize = CSize{0, 0};
1042 *pOffset = CSize{0, 0};
1043 return false;
1044 }
1045 else {
1046 LPOBJECTDESCRIPTOR pObjDesc = (LPOBJECTDESCRIPTOR)::GlobalLock (hObjDesc);
1047 if (pObjDesc == nullptr) {
1048 memset (pSize, 0, sizeof (*pSize));
1049 memset (pOffset, 0, sizeof (*pOffset));
1050 }
1051 else {
1052 pSize->cx = (int)pObjDesc->sizel.cx;
1053 pSize->cy = (int)pObjDesc->sizel.cy;
1054 pOffset->cx = (int)pObjDesc->pointl.x;
1055 pOffset->cy = (int)pObjDesc->pointl.y;
1056 }
1057 ::GlobalUnlock (hObjDesc);
1058 ::GlobalFree (hObjDesc);
1059 return true;
1060 }
1061 }
1062 template <typename BASECLASS>
1063 void Led_MFC_DragAndDropWindow<BASECLASS>::StartDragAutoscrollTimer ()
1064 {
1065 Assert (fDragAutoScrollTimerID == 0); // not sure about this - just for debug sake??? - LGP 960530
1066 if (fDragAutoScrollTimerID == 0) {
1067 //const int kTimeout = 25; // 25 milliseconds - update autoscroll every 1/40
1068 const int kTimeout = 20; // 20 milliseconds - update autoscroll every 1/50
1069 // second.
1070 Verify ((fDragAutoScrollTimerID = this->SetTimer (eAutoscrolling4DragTimerEventID, kTimeout, NULL)) != 0);
1071 }
1072 }
1073 template <typename BASECLASS>
1074 void Led_MFC_DragAndDropWindow<BASECLASS>::StopDragAutoscrollTimer ()
1075 {
1076 if (fDragAutoScrollTimerID != 0) {
1077 Verify (this->KillTimer (eAutoscrolling4DragTimerEventID));
1078 fDragAutoScrollTimerID = 0;
1079 }
1080 }
1081 template <typename BASECLASS>
1082 void Led_MFC_DragAndDropWindow<BASECLASS>::OnTimer (UINT_PTR nEventID)
1083 {
1084 if (nEventID == eAutoscrolling4DragTimerEventID) {
1085 this->HandleSharedDragOverUpdateSelCode ();
1086 }
1087 else {
1088 inherited::OnTimer (nEventID);
1089 }
1090 }
1091 template <typename BASECLASS>
1092 const AFX_MSGMAP* Led_MFC_DragAndDropWindow<BASECLASS>::GetMessageMap () const
1093 {
1094 return GetThisMessageMap ();
1095 }
1096 template <typename BASECLASS>
1097 const AFX_MSGMAP* PASCAL Led_MFC_DragAndDropWindow<BASECLASS>::GetThisMessageMap ()
1098 {
1099 using ThisClass = Led_MFC_DragAndDropWindow<BASECLASS>;
1100 using TheBaseClass = BASECLASS;
1101 DISABLE_COMPILER_MSC_WARNING_START (4407) // Not sure this is safe to ignore but I think it is due to qMFCRequiresCWndLeftmostBaseClass
1102 static const AFX_MSGMAP_ENTRY _messageEntries[] = {ON_WM_CREATE () ON_WM_TIMER (){0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0}};
1103 DISABLE_COMPILER_MSC_WARNING_END (4407)
1104 static const AFX_MSGMAP messageMap = {&TheBaseClass::GetThisMessageMap, &_messageEntries[0]};
1105 return &messageMap;
1106 }
1107
1108 // class Led_MFC_CViewHelper<BASECLASS>
1109 template <typename BASECLASS>
1110 Led_MFC_CViewHelper<BASECLASS>::Led_MFC_CViewHelper ()
1111 : inherited ()
1112 ,
1113 // NB: CTOR for TWIPS_Rect is TOP/LEFT/HEIGHT/WIDTH, so we set height/width to zero to get same TLBR.
1114 fPrintMargins (TWIPS_Rect (TWIPS{1440}, TWIPS{1440}, TWIPS{0}, TWIPS{0}))
1115 , fPrintInfo{nullptr}
1116 {
1117 }
1118 template <typename BASECLASS>
1119 Led_MFC_CViewHelper<BASECLASS>::~Led_MFC_CViewHelper ()
1120 {
1121 Assert (fPrintInfo == nullptr);
1122 }
1123 template <typename BASECLASS>
1124 /*
1125 @METHOD: Led_MFC_CViewHelper<BASECLASS>::GetPrintMargins
1126 @DESCRIPTION: <p>Return the print margins. These are used by @'Led_MFC_CViewHelper<BASECLASS>::CalculatePrintingRect'.
1127 See also @'Led_MFC_CViewHelper<BASECLASS>::SetPrintMargins'.
1128 */
1129 TWIPS_Rect Led_MFC_CViewHelper<BASECLASS>::GetPrintMargins () const
1130 {
1131 return fPrintMargins;
1132 }
1133 template <typename BASECLASS>
1134 /*
1135 @METHOD: Led_MFC_CViewHelper<BASECLASS>::SetPrintMargins
1136 @DESCRIPTION: <p>See also @'Led_MFC_CViewHelper<BASECLASS>::GetPrintMargins'.
1137 */
1138 void Led_MFC_CViewHelper<BASECLASS>::SetPrintMargins (const TWIPS_Rect& printMargins)
1139 {
1140 fPrintMargins = printMargins;
1141 }
1142 template <typename BASECLASS>
1143 /*
1144 @METHOD: Led_MFC_CViewHelper<BASECLASS>::OnPreparePrinting
1145 @DESCRIPTION: Hook the MFC OnPreparePrinting () method to handle printing in the standard MFC fasion.
1146 Don't call this directly.
1147 */
1148 BOOL Led_MFC_CViewHelper<BASECLASS>::OnPreparePrinting (CPrintInfo* pInfo)
1149 {
1150 // default preparation
1151 return this->DoPreparePrinting (pInfo);
1152 }
1153 template <typename BASECLASS>
1154 /*
1155 @METHOD: Led_MFC_CViewHelper<BASECLASS>::OnBeginPrinting
1156 @DESCRIPTION: Hook the MFC OnBeginPrinting () method to handle printing in the standard MFC fasion.
1157 Also, keep track of some internals we will use later in printing, and setup SetForceAllRowsShowing
1158 so when we print the last page, we can see lots of nice whatspace at the end. Don't call this directly.
1159 */
1160 void Led_MFC_CViewHelper<BASECLASS>::OnBeginPrinting (CDC* pDC, CPrintInfo* pInfo)
1161 {
1162 // THIS CODE IS KINDOF HACKISH - SHOULD HAVE A PAGENATE STAGE/FUNCTION!!! TO FILL THIS ARRAY!!!
1163 Assert (fPrintInfo == nullptr);
1164 BASECLASS::OnBeginPrinting (pDC, pInfo);
1165 fPrintInfo = new PrintInfo (*this, pDC, this->GetWindowRect (), this->GetMarkerPositionOfStartOfWindow (), this->GetForceAllRowsShowing ());
1166 this->SetForceAllRowsShowing (false);
1167 }
1168 template <typename BASECLASS>
1169 void Led_MFC_CViewHelper<BASECLASS>::OnPrint (CDC* pDC, CPrintInfo* /*pInfo*/)
1170 {
1171 AssertNotNull (fPrintInfo);
1172 // Consider different print loop - maybe different print-oriented entry in TextImager?
1173 // That doesn't have todo with scrolling? Just DrawFromSize_tOffset? Maybe - into rect.
1174 // Make the MRTI::Draw() vector to that?
1175 ASSERT_VALID (pDC);
1176 Led_MFC_TabletFromCDC tablet (pDC);
1177 typename BASECLASS::TemporarilyUseTablet tmpUseTablet{*this, tablet, BASECLASS::TemporarilyUseTablet::eDontDoTextMetricsChangedCall};
1178 CRect boundsRect = CRect (0, 0, 0, 0);
1179 Verify (pDC->GetClipBox (&boundsRect) != ERROR);
1180 this->Draw (AsLedRect (boundsRect), true);
1181 }
1182 template <typename BASECLASS>
1183 void Led_MFC_CViewHelper<BASECLASS>::OnEndPrinting (CDC* pDC, CPrintInfo* pInfo)
1184 {
1185 if (fPrintInfo == nullptr) {
1186 // Can be NULL if print fails, cuz no printer installed
1187 BASECLASS::OnEndPrinting (pDC, pInfo);
1188 }
1189 else {
1190 this->SetForceAllRowsShowing (fPrintInfo->fSavedForceAllRowsFlag);
1191 this->SetWindowRect (fPrintInfo->fOldWindowRect);
1192 this->SetTopRowInWindowByMarkerPosition (fPrintInfo->fSavedScrollPos);
1193 delete fPrintInfo;
1194 fPrintInfo = nullptr;
1195 BASECLASS::OnEndPrinting (pDC, pInfo);
1196 }
1197 }
1198 template <typename BASECLASS>
1199 void Led_MFC_CViewHelper<BASECLASS>::OnPrepareDC (CDC* pDC, CPrintInfo* pInfo)
1200 {
1201 if (pInfo != NULL and pDC->IsPrinting ()) { // For some STUPID reason, MFC calls this even if we aren't printing...
1202 {
1203 WindowDC screenDC (NULL);
1204 (void)pDC->SetMapMode (MM_ANISOTROPIC);
1205 (void)pDC->SetWindowExt (screenDC.GetDeviceCaps (LOGPIXELSX), screenDC.GetDeviceCaps (LOGPIXELSY));
1206 (void)pDC->SetViewportExt (pDC->GetDeviceCaps (LOGPIXELSX), pDC->GetDeviceCaps (LOGPIXELSY));
1207 // I REMOVED calls to SetWindowRect/TabletChangedMetrics for WYSYWIG (SPR#0869),
1208 // This created a new problem - SPR#1079 - which is now fixed (or largely worked around here).
1209 // Probably there is still a real latent problem inside TabletChangedMetrics - but I don't
1210 // need to debug that now, and this whole thing will go away if I rewrite the printing code
1211 // after 3.0 - as is anticipated.
1212 // I changed the args to CalculateWindowRect() to accomodate this bugfix.
1213 //
1214 Led_Rect oldWR = this->GetWindowRect ();
1215 Led_Rect newWR = this->CalculatePrintingRect (pDC);
1216 this->SetWindowRect (newWR);
1217 }
1218 CView::OnPrepareDC (pDC, pInfo);
1219 if (fPrintInfo->fWindowStarts.size () == 0) {
1220 fPrintInfo->fWindowStarts.push_back (0);
1221 this->SetTopRowInWindowByMarkerPosition (0, TextInteractor::eNoUpdate);
1222 }
1223 pInfo->m_bContinuePrinting = true; // Assume scroll forward succeeded
1224 // First page into our fWindowStarts cache enuf pages to satisfy this 'goto page' request. NB:
1225 // In Print (page n..m) requests - this can be starting well past fWindowStarts.size () - contrary
1226 // to earlier - incorrect - Led comments - LGP 981007
1227 while (fPrintInfo->fWindowStarts.size () < pInfo->m_nCurPage) {
1228 // advanced one page...
1229 if (this->GetMarkerPositionOfEndOfWindow () == this->GetTextStore ().GetEnd ()) {
1230 pInfo->m_bContinuePrinting = false; // scroll forward failed
1231 return;
1232 }
1233 this->SetTopRowInWindowByMarkerPosition (this->FindNextCharacter (this->GetMarkerPositionOfEndOfWindow ()), TextInteractor::eNoUpdate);
1234 size_t newStart = this->GetMarkerPositionOfStartOfWindow ();
1235 if (newStart == fPrintInfo->fWindowStarts.back ()) {
1236 pInfo->m_bContinuePrinting = false; // scroll forward failed
1237 return;
1238 }
1239 else {
1240 fPrintInfo->fWindowStarts.push_back (newStart);
1241 }
1242 }
1243 // scroll forward/back to some page in our (now filled in cache) page list
1244 this->SetTopRowInWindowByMarkerPosition (fPrintInfo->fWindowStarts[pInfo->m_nCurPage - 1]);
1245 if (this->GetMarkerPositionOfEndOfWindow () == this->GetTextStore ().GetEnd ()) {
1246 pInfo->SetMaxPage (pInfo->m_nCurPage);
1247 return;
1248 }
1249 }
1250 }
1251 template <typename BASECLASS>
1252 /*
1253 @METHOD: Led_MFC_CViewHelper<BASECLASS>::CalculatePrintingRect
1254 @DESCRIPTION: Hook function to change the default size Led will use for printing. Defautlts to
1255 FULL page. Override to inset for margins, and/or headers/footers, or call @'Led_MFC_CViewHelper<BASECLASS>::SetPrintMargins'.
1256 <p>Don't call directly. Just called after DC setup from @'Led_MFC_CViewHelper<BASECLASS>::OnPrepareDC'.</p>
1257 <p>See also @'Led_MFC_CViewHelper<BASECLASS>::GetPrintMargins' to specify the margins that are used by this
1258 routine by default.</p>
1259 */
1260 Led_Rect Led_MFC_CViewHelper<BASECLASS>::CalculatePrintingRect (CDC* pDC) const
1261 {
1262 RequireNotNull (pDC);
1263 /*
1264 * See SPR#1079, and SPR#1153 about whats going on here.
1265 */
1266 CRect winRect = CRect (0, 0, pDC->GetDeviceCaps (HORZRES), pDC->GetDeviceCaps (VERTRES));
1267 pDC->DPtoLP (&winRect);
1268 Led_Rect useRect = AsLedRect (winRect);
1269 Led_Rect marginRect = Led_MFC_TabletFromCDC (pDC)->CvtFromTWIPS (fPrintMargins);
1270 useRect = Led_Rect (useRect.GetTop () + marginRect.GetTop (), useRect.GetLeft () + marginRect.GetLeft (),
1271 useRect.GetHeight () - (marginRect.GetTop () + marginRect.GetBottom ()),
1272 useRect.GetWidth () - (marginRect.GetLeft () + marginRect.GetRight ()));
1273 return useRect;
1274 }
1275 template <typename BASECLASS>
1276 void Led_MFC_CViewHelper<BASECLASS>::InvalidateScrollBarParameters ()
1277 {
1278 if (fPrintInfo == nullptr) {
1279 inherited::InvalidateScrollBarParameters ();
1280 }
1281 }
1282 template <typename BASECLASS>
1283 /*
1284 @METHOD: Led_MFC_CViewHelper<BASECLASS>::UpdateScrollBars
1285 @DESCRIPTION: Avoid errors updating sbars while printing.
1286 */
1287 void Led_MFC_CViewHelper<BASECLASS>::UpdateScrollBars ()
1288 {
1289 if (fPrintInfo != nullptr) {
1290 return; // ignore while in print mode...
1291 }
1292 inherited::UpdateScrollBars ();
1293 }
1294 template <typename BASECLASS>
1295 /*
1296 @METHOD: Led_MFC_CViewHelper<BASECLASS>::DeleteContents
1297 @DESCRIPTION: Hook the MFC DeleteContents () routine, and simulate the user having deleted all the text in the
1298 buffer.
1299 */
1300 void Led_MFC_CViewHelper<BASECLASS>::DeleteContents ()
1301 {
1302 ASSERT_VALID (this);
1303 AssertNotNull (this->m_hWnd);
1304 this->SetWindowText (nullptr);
1305 ASSERT_VALID (this);
1306 }
1307 template <typename BASECLASS>
1308 void Led_MFC_CViewHelper<BASECLASS>::Serialize (CArchive& ar)
1309 {
1310 // Probably not the right thing todo, but a simple enuf hack for now - LGP 950511
1311 this->SerializeRaw (ar);
1312 }
1313 template <typename BASECLASS>
1314 void Led_MFC_CViewHelper<BASECLASS>::SerializeRaw (CArchive& ar)
1315 {
1316 ASSERT_VALID (this);
1317 AssertNotNull (this->m_hWnd);
1318 if (ar.IsStoring ()) {
1319 this->WriteToArchive (ar);
1320 }
1321 else {
1322 CFile* file = ar.GetFile ();
1323 ASSERT_VALID (file);
1324 DWORD dwLen = static_cast<DWORD> (file->GetLength ()); // maybe should subtract current offset?
1325 this->ReadFromArchive (ar, (UINT)dwLen);
1326 }
1327 ASSERT_VALID (this);
1328 }
1329 template <typename BASECLASS>
1330 void Led_MFC_CViewHelper<BASECLASS>::ReadFromArchive (CArchive& ar, UINT nLen)
1331 {
1332 using namespace Stroika::Foundation;
1333 ASSERT_VALID (this);
1334
1335 Memory::StackBuffer<Led_tChar> buf{Memory::eUninitialized, nLen};
1336 if (ar.Read (buf.data (), nLen * sizeof (Led_tChar)) != nLen * sizeof (Led_tChar)) {
1337 AfxThrowArchiveException (CArchiveException::endOfFile);
1338 }
1339 // Replace the editing edit buffer with the newly loaded data
1340 nLen = static_cast<UINT> (Characters::NormalizeTextToNL<Led_tChar> (buf.data (), nLen, buf.data (), nLen));
1341 if (ValidateTextForCharsetConformance (buf.data (), nLen)) {
1342 this->Replace (0, 0, buf.data (), nLen);
1343 }
1344 else {
1345 this->OnBadUserInput ();
1346 }
1347
1348 this->Invalidate ();
1349
1350 ASSERT_VALID (this);
1351 }
1352 template <typename BASECLASS>
1353 void Led_MFC_CViewHelper<BASECLASS>::WriteToArchive (CArchive& ar)
1354 {
1355 using namespace Foundation;
1356 ASSERT_VALID (this);
1357
1358 size_t nLen = this->GetLength ();
1359 Memory::StackBuffer<Led_tChar> buf{Memory::eUninitialized, nLen};
1360 this->CopyOut (0, nLen, buf.data ());
1361 Memory::StackBuffer<Led_tChar> buf2{Memory::eUninitialized, 2 * nLen};
1362 nLen = Characters::NLToNative<Led_tChar> (buf.data (), nLen, buf2.data (), 2 * nLen);
1363 ar.Write (buf2.data (), static_cast<UINT> (nLen * sizeof (Led_tChar)));
1364
1365 ASSERT_VALID (this);
1366 }
1367 template <typename BASECLASS>
1368 void Led_MFC_CViewHelper<BASECLASS>::OnLButtonDown (UINT nFlags, CPoint oPoint)
1369 {
1370 this->UpdateClickCount (Foundation::Time::GetTickCount (), AsLedPoint (oPoint));
1371
1372 if (this->m_pDocument != NULL and dynamic_cast<COleDocument*> (this->m_pDocument) != NULL) {
1373 // Any time we get a click, make sure there are no active in-place activations.
1374 // Any click anyplace outside the active item is ignored, except for deactivating
1375 // that item.
1376 AssertMember (this->m_pDocument, COleDocument); //
1377 COleDocument& doc = *(COleDocument*)this->m_pDocument;
1378 COleClientItem* pItem = doc.GetInPlaceActiveItem (this);
1379 if (pItem != NULL) {
1380 pItem->Close ();
1381 return;
1382 }
1383 }
1384
1385 if (this->GetCurClickCount () == 1 and this->IsADragSelect (AsLedPoint (oPoint))) {
1386 this->HandleDragSelect (nFlags, oPoint);
1387 }
1388 else {
1389 this->OnNormalLButtonDown (nFlags, AsLedPoint (oPoint));
1390 }
1391 }
1392 template <typename BASECLASS>
1393 DROPEFFECT Led_MFC_CViewHelper<BASECLASS>::OnDragEnter (COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
1394 {
1395 return this->HelperDragEnter (pDataObject, dwKeyState, point);
1396 }
1397 template <typename BASECLASS>
1398 DROPEFFECT Led_MFC_CViewHelper<BASECLASS>::OnDragOver (COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
1399 {
1400 return this->HelperDragOver (pDataObject, dwKeyState, point);
1401 }
1402 template <typename BASECLASS>
1403 BOOL Led_MFC_CViewHelper<BASECLASS>::OnDrop (COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)
1404 {
1405 return this->HelperDrop (pDataObject, dropEffect, point);
1406 }
1407 template <typename BASECLASS>
1408 void Led_MFC_CViewHelper<BASECLASS>::OnDragLeave ()
1409 {
1410 this->HelperDragLeave ();
1411 }
1412 template <typename BASECLASS>
1413 void Led_MFC_CViewHelper<BASECLASS>::OnPaint ()
1414 {
1415 CView::OnPaint (); // don't use inherited/Led_MFC_CViewHelper<BASECLASS>_Helper<T> version - cuz misses some MFC hooks
1416 }
1417 template <typename BASECLASS>
1418 /*
1419 @METHOD: Led_MFC_CViewHelper<BASECLASS>::OnDraw
1420 @DESCRIPTION: Hook the MFC OnDraw () method to invoke the Led drawing mechanism, and redisplay the window.
1421 */
1422 void Led_MFC_CViewHelper<BASECLASS>::OnDraw (CDC* pDC)
1423 {
1424 ASSERT_VALID (pDC);
1425
1426 /*
1427 * Since we currently use the same textimager for printing as for display, we will screw
1428 * up all our cached info for line breaks etc if we display while we are printing.
1429 * If it is desired to make this work then we must use a NEW imager (as with LedIt! PowerPlant)
1430 * to print to.
1431 */
1432 if (fPrintInfo != nullptr) {
1433 return;
1434 }
1435
1436 CRect boundsRect = CRect (0, 0, 0, 0);
1437 Verify (pDC->GetClipBox (&boundsRect) != ERROR);
1438 this->WindowDrawHelper (Led_MFC_TabletFromCDC (pDC), AsLedRect (boundsRect), false);
1439 }
1440 template <typename BASECLASS>
1441 int Led_MFC_CViewHelper<BASECLASS>::OnCreate (::LPCREATESTRUCT lpCreateStruct)
1442 {
1443 if (inherited::OnCreate (lpCreateStruct) != 0) {
1444 return -1; // failed to create
1445 }
1446 this->TabletChangedMetrics (); // maybe should catch failures here, and return -1?
1447 return 0; // sucess
1448 }
1449 template <typename BASECLASS>
1450 void Led_MFC_CViewHelper<BASECLASS>::OnVScroll (UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
1451 {
1452 if (this->m_pDocument != NULL and dynamic_cast<COleDocument*> (this->m_pDocument) != NULL) {
1453 // Don't allow scrolling while there is an in-place active item.
1454 // Wish we had a better interface for this... Maybe we should be deactivating
1455 // SBARS when we activate item??? For now, interpret scroll attempt as a request
1456 // to deactivate...
1457 // LGP 960530
1458 AssertMember (this->m_pDocument, COleDocument);
1459 COleDocument& doc = *(COleDocument*)this->m_pDocument;
1460 COleClientItem* pItem = doc.GetInPlaceActiveItem (this);
1461 if (pItem != NULL) {
1462 pItem->Close ();
1463 return;
1464 }
1465 }
1466 inherited::OnVScroll (nSBCode, nPos, pScrollBar);
1467 }
1468 template <typename BASECLASS>
1469 void Led_MFC_CViewHelper<BASECLASS>::OnHScroll (UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
1470 {
1471 if (this->m_pDocument != NULL and dynamic_cast<COleDocument*> (this->m_pDocument) != NULL) {
1472 // Don't allow scrolling while there is an in-place active item.
1473 // Wish we had a better interface for this... Maybe we should be deactivating
1474 // SBARS when we activate item??? For now, interpret scroll attempt as a request
1475 // to deactivate...
1476 // LGP 960530
1477 AssertMember (this->m_pDocument, COleDocument); //
1478 COleDocument& doc = *(COleDocument*)this->m_pDocument;
1479 COleClientItem* pItem = doc.GetInPlaceActiveItem (this);
1480 if (pItem != NULL) {
1481 pItem->Close ();
1482 return;
1483 }
1484 }
1485 inherited::OnHScroll (nSBCode, nPos, pScrollBar);
1486 }
1487 template <typename BASECLASS>
1488 const AFX_MSGMAP* Led_MFC_CViewHelper<BASECLASS>::GetMessageMap () const
1489 {
1490 return GetThisMessageMap ();
1491 }
1492 template <typename BASECLASS>
1493 const AFX_MSGMAP* PASCAL Led_MFC_CViewHelper<BASECLASS>::GetThisMessageMap ()
1494 {
1495 using ThisClass = Led_MFC_CViewHelper<BASECLASS>;
1496 using TheBaseClass = BASECLASS;
1497 DISABLE_COMPILER_MSC_WARNING_START (4407) // Not sure this is safe to ignore but I think it is due to qMFCRequiresCWndLeftmostBaseClass
1498 static const AFX_MSGMAP_ENTRY _messageEntries[] = {ON_WM_PAINT () ON_WM_LBUTTONDOWN () ON_WM_CREATE () ON_WM_VSCROLL ()
1499 ON_WM_HSCROLL (){0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0}};
1500 DISABLE_COMPILER_MSC_WARNING_END (4407)
1501 static const AFX_MSGMAP messageMap = {&TheBaseClass::GetThisMessageMap, &_messageEntries[0]};
1502 return &messageMap;
1503 }
1504
1505 // class Led_MFC_ExceptionHandlerHelper<BASECLASS>
1506 template <typename BASECLASS>
1507 /*
1508 @METHOD: Led_MFC_ExceptionHandlerHelper<BASECLASS>::HandleException
1509 @DESCRIPTION: Override this to provide different exception handling. By default, this calls @'Led_BeepNotify'.
1510 */
1511 void Led_MFC_ExceptionHandlerHelper<BASECLASS>::HandleException () const
1512 {
1513 Led_BeepNotify ();
1514 }
1515 template <typename BASECLASS>
1516 void Led_MFC_ExceptionHandlerHelper<BASECLASS>::OnChar (UINT nChar, UINT nRepCnt, UINT nFlags)
1517 {
1518 try {
1519 inherited::OnChar (nChar, nRepCnt, nFlags);
1520 }
1521 catch (...) {
1522 this->HandleException ();
1523 }
1524 }
1525 template <typename BASECLASS>
1526 LRESULT Led_MFC_ExceptionHandlerHelper<BASECLASS>::OnIMEChar (WPARAM wParam, LPARAM lParam)
1527 {
1528 try {
1529 return inherited::OnIMEChar (wParam, lParam);
1530 }
1531 catch (...) {
1532 this->HandleException ();
1533 return 0;
1534 }
1535 }
1536 template <typename BASECLASS>
1537 void Led_MFC_ExceptionHandlerHelper<BASECLASS>::OnKeyDown (UINT nChar, UINT nRepCnt, UINT nFlags)
1538 {
1539 try {
1540 inherited::OnKeyDown (nChar, nRepCnt, nFlags);
1541 }
1542 catch (...) {
1543 this->HandleException ();
1544 }
1545 }
1546 template <typename BASECLASS>
1547 LRESULT Led_MFC_ExceptionHandlerHelper<BASECLASS>::OnMsgPaste (WPARAM wParam, LPARAM lParam)
1548 {
1549 try {
1550 return inherited::OnMsgPaste (wParam, lParam);
1551 }
1552 catch (...) {
1553 this->HandleException ();
1554 return 0;
1555 }
1556 }
1557 template <typename BASECLASS>
1558 void Led_MFC_ExceptionHandlerHelper<BASECLASS>::OnLButtonDown (UINT nFlags, CPoint oPoint)
1559 {
1560 try {
1561 inherited::OnLButtonDown (nFlags, oPoint);
1562 }
1563 catch (...) {
1564 this->HandleException ();
1565 }
1566 }
1567 template <typename BASECLASS>
1568 void Led_MFC_ExceptionHandlerHelper<BASECLASS>::OnLButtonUp (UINT nFlags, CPoint oPoint)
1569 {
1570 try {
1571 inherited::OnLButtonUp (nFlags, oPoint);
1572 }
1573 catch (...) {
1574 this->HandleException ();
1575 }
1576 }
1577 template <typename BASECLASS>
1578 void Led_MFC_ExceptionHandlerHelper<BASECLASS>::OnLButtonDblClk (UINT nFlags, CPoint oPoint)
1579 {
1580 try {
1581 inherited::OnLButtonDblClk (nFlags, oPoint);
1582 }
1583 catch (...) {
1584 this->HandleException ();
1585 }
1586 }
1587 template <typename BASECLASS>
1588 BOOL Led_MFC_ExceptionHandlerHelper<BASECLASS>::OnCmdMsg (UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
1589 {
1590 try {
1591 return inherited::OnCmdMsg (nID, nCode, pExtra, pHandlerInfo);
1592 }
1593 catch (...) {
1594 this->HandleException ();
1595 return 1;
1596 }
1597 }
1598 template <typename BASECLASS>
1599 const AFX_MSGMAP* Led_MFC_ExceptionHandlerHelper<BASECLASS>::GetMessageMap () const
1600 {
1601 return GetThisMessageMap ();
1602 }
1603 template <typename BASECLASS>
1604 const AFX_MSGMAP* PASCAL Led_MFC_ExceptionHandlerHelper<BASECLASS>::GetThisMessageMap ()
1605 {
1606 using ThisClass = Led_MFC_ExceptionHandlerHelper<BASECLASS>;
1607 using TheBaseClass = BASECLASS;
1608 DISABLE_COMPILER_MSC_WARNING_START (4407) // Not sure this is safe to ignore but I think it is due to qMFCRequiresCWndLeftmostBaseClass
1609 static const AFX_MSGMAP_ENTRY _messageEntries[] = {ON_WM_CHAR () ON_MESSAGE (WM_IME_CHAR, &OnIMEChar) ON_WM_KEYDOWN () ON_MESSAGE (
1610 WM_PASTE, &OnMsgPaste) ON_WM_LBUTTONDOWN () ON_WM_LBUTTONUP () ON_WM_LBUTTONDBLCLK (){0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0}};
1611 DISABLE_COMPILER_MSC_WARNING_END (4407)
1612 static const AFX_MSGMAP messageMap = {&TheBaseClass::GetThisMessageMap, &_messageEntries[0]};
1613 return &messageMap;
1614 }
1615
1616 // class Led_MFC_X<ChosenInteractor,LEDMFC>
1617 template <typename ChosenInteractor, typename LEDMFC>
1618 inline Led_MFC_X<ChosenInteractor, LEDMFC>::Led_MFC_X ()
1619 : ChosenInteractor ()
1620 , LEDMFC ()
1621 {
1622 }
1623 /*
1624 @METHOD: Led_MFC_X<ChosenInteractor,LEDMFC>::AboutToUpdateText
1625 @DESCRIPTION: Override to handle mixin ambiguity.
1626 */
1627 template <typename ChosenInteractor, typename LEDMFC>
1628 void Led_MFC_X<ChosenInteractor, LEDMFC>::AboutToUpdateText (const MarkerOwner::UpdateInfo& updateInfo)
1629 {
1630 LEDMFC::AboutToUpdateText (updateInfo);
1631 ChosenInteractor::AboutToUpdateText (updateInfo);
1632 }
1633 /*
1634 @METHOD: Led_MFC_X<ChosenInteractor,LEDMFC>::DidUpdateText
1635 @DESCRIPTION: Override to handle mixin ambiguity.
1636 */
1637 template <typename ChosenInteractor, typename LEDMFC>
1638 void Led_MFC_X<ChosenInteractor, LEDMFC>::DidUpdateText (const MarkerOwner::UpdateInfo& updateInfo) noexcept
1639 {
1640 LEDMFC::DidUpdateText_ (updateInfo);
1641 ChosenInteractor::DidUpdateText (updateInfo);
1642 }
1643
1644 // FUNCTION Led_GetTextExtent ()
1645 /*
1646 @METHOD: Led_GetTextExtent<TRIVIALWORDWRAPPEDTEXTIMAGER,SIMPLETEXTIMAGER,TEXTSTORE>
1647 @DESCRIPTION: Trivial wrapper on TrivialImager<TEXTSTORE,IMAGER> etc, except it handles
1648 case of word wrapping as a parameter. So this is roughly a replacement for the Win32 SDK
1649 routine GetTextExtent() - except its implemented by Led (and so UNICODE friendly, for example).
1650 <p>Note - this is done as a template - rather than directly as a function - so as to avoid forcing
1651 people who include Led_MFC from also including all these other modules required for this. There is
1652 a global function version of this function (@'Led_GetTextExtent') which will be enabled/included in
1653 your program if you define @'qSupportDrawTextGetTextExtent'.
1654 <p>See also Led_DrawText<TRIVIALWORDWRAPPEDTEXTIMAGER,SIMPLETEXTIMAGER,TEXTSTORE>
1655 */
1656 template <typename TRIVIALWORDWRAPPEDTEXTIMAGER, typename SIMPLETEXTIMAGER, typename TEXTSTORE>
1657 CSize Led_GetTextExtent (CDC* cdc, const Led_tString& text, CRect r, bool wordWrap)
1658 {
1659 RequireNotNull (cdc);
1660 Led_MFC_TabletFromCDC tmpTablet (cdc);
1661 return AsCSize (GetTextExtent<TRIVIALWORDWRAPPEDTEXTIMAGER, SIMPLETEXTIMAGER, TEXTSTORE> (tmpTablet, text, AsLedRect (r), wordWrap));
1662 }
1663
1664 // FUNCTION Led_DrawText ()
1665 /*
1666 @METHOD: Led_DrawText<TRIVIALWORDWRAPPEDTEXTIMAGER,SIMPLETEXTIMAGER,TEXTSTORE>
1667 @DESCRIPTION: Trivial wrapper on TrivialImager<TEXTSTORE,IMAGER> etc, except it handles
1668 case of word wrapping as a parameter. So this is roughly a replacement for the Win32 SDK
1669 routine DrawText () - except its implemented by Led (and so UNICODE friendly, for example).
1670 <p>Note - this is done as a template - rather than directly as a function - so as to avoid forcing
1671 people who include Led_MFC from also including all these other modules required for this. There is
1672 a global function version of this function (@'Led_DrawText') which will be enabled/included in
1673 your program if you define @'qSupportDrawTextGetTextExtent'.
1674 <p>See also Led_GetTextExtent<TRIVIALWORDWRAPPEDTEXTIMAGER,SIMPLETEXTIMAGER,TEXTSTORE>
1675 */
1676 template <typename TRIVIALWORDWRAPPEDTEXTIMAGER, typename SIMPLETEXTIMAGER, typename TEXTSTORE>
1677 void Led_DrawText (CDC* cdc, const Led_tString& text, CRect r, bool wordWrap)
1678 {
1679 RequireNotNull (cdc);
1680 Led_MFC_TabletFromCDC tmpTablet (cdc);
1681 DrawTextBox<TRIVIALWORDWRAPPEDTEXTIMAGER, SIMPLETEXTIMAGER, TEXTSTORE> (tmpTablet, text, AsLedRect (r), wordWrap);
1682 }
1683
1684 // class Led_MFC_TmpCmdUpdater
1685 inline Led_MFC_TmpCmdUpdater::Led_MFC_TmpCmdUpdater (CCmdUI* pCmdUI)
1686 : fCmdUI (pCmdUI)
1687 , fCmdNum (MFC_CommandNumberMapping::Get ().Lookup (pCmdUI->m_nID))
1688 , fEnabled (false)
1689 {
1690 RequireNotNull (fCmdUI);
1691 }
1692 inline Led_MFC_TmpCmdUpdater::operator Led_MFC_TmpCmdUpdater* ()
1693 {
1694 return this;
1695 }
1696 inline Led_MFC_TmpCmdUpdater::operator CCmdUI* ()
1697 {
1698 EnsureNotNull (fCmdUI);
1699 return fCmdUI;
1700 }
1701}
1702
1703CompileTimeFlagChecker_HEADER (Stroika::Frameworks::Led::Platform, qMFCRequiresCWndLeftmostBaseClass, qMFCRequiresCWndLeftmostBaseClass)
#define AssertNotNull(p)
Definition Assertions.h:333
#define EnsureNotNull(p)
Definition Assertions.h:340
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
Definition Assertions.h:48
#define RequireNotNull(p)
Definition Assertions.h:347
#define AssertMember(p, c)
Definition Assertions.h:312
#define Verify(c)
Definition Assertions.h:419
#define CompileTimeFlagChecker_HEADER(NS_PREFIX, NAME, VALUE)
CompileTimeFlagChecker_HEADER () will generate a LINK ERROR if you ever compile a header with one val...
time_point< RealtimeClock, DurationSeconds > TimePointSeconds
TimePointSeconds is a simpler approach to chrono::time_point, which doesn't require using templates e...
Definition Realtime.h:82
chrono::duration< double > DurationSeconds
chrono::duration<double> - a time span (length of time) measured in seconds, but high precision.
Definition Realtime.h:57
#define DbgTrace
Definition Trace.h:309
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
Create a format-string (see std::wformat_string or Stroika FormatString, or python 'f' strings.
basic_string< SDKChar > SDKString
Definition SDKString.h:38