Stroika Library 3.0d18
 
Loading...
Searching...
No Matches
LedLineItView.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4
5#include "Stroika/Foundation/StroikaPreComp.h"
6
7DISABLE_COMPILER_MSC_WARNING_START (5054)
8#include <afxodlgs.h> // MFC OLE dialog classes
9DISABLE_COMPILER_MSC_WARNING_END (5054)
10
11#include <afxwin.h>
12
14#include "Stroika/Frameworks/Led/StdDialogs.h"
15
16#include "FontMenu.h"
17#include "LedLineItApplication.h"
18#include "LedLineItDocument.h"
19#include "LedLineItMainFrame.h"
20#include "Options.h"
21#include "Resource.h"
22
23#include "LedLineItView.h"
24
25using namespace Stroika::Foundation;
26using namespace Stroika::Frameworks::Led;
27
29
30class My_CMDNUM_MAPPING : public MFC_CommandNumberMapping {
31public:
32 My_CMDNUM_MAPPING ()
33 {
34 AddAssociation (ID_EDIT_UNDO, LedLineItView::kUndo_CmdID);
35 AddAssociation (ID_EDIT_REDO, LedLineItView::kRedo_CmdID);
36 AddAssociation (ID_EDIT_SELECT_ALL, LedLineItView::kSelectAll_CmdID);
37 AddAssociation (ID_EDIT_CUT, LedLineItView::kCut_CmdID);
38 AddAssociation (ID_EDIT_COPY, LedLineItView::kCopy_CmdID);
39 AddAssociation (ID_EDIT_PASTE, LedLineItView::kPaste_CmdID);
40 AddAssociation (ID_EDIT_CLEAR, LedLineItView::kClear_CmdID);
41 AddAssociation (kFindCmd, LedLineItView::kFind_CmdID);
42 AddAssociation (kFindAgainCmd, LedLineItView::kFindAgain_CmdID);
43 AddAssociation (kEnterFindStringCmd, LedLineItView::kEnterFindString_CmdID);
44 AddAssociation (kReplaceCmd, LedLineItView::kReplace_CmdID);
45 AddAssociation (kReplaceAgainCmd, LedLineItView::kReplaceAgain_CmdID);
46#if qIncludeBasicSpellcheckEngine
47 AddAssociation (kSpellCheckCmd, LedLineItView::kSpellCheck_CmdID);
48#endif
49 }
50};
51My_CMDNUM_MAPPING sMy_CMDNUM_MAPPING;
52
53struct LedLineIt_DialogSupport : TextInteractor::DialogSupport {
54public:
55 LedLineIt_DialogSupport ()
56 {
57 TextInteractor::SetDialogSupport (this);
58 }
59 ~LedLineIt_DialogSupport ()
60 {
61 TextInteractor::SetDialogSupport (NULL);
62 }
63#if qSupportStdFindDlg
64public:
65 virtual void DisplayFindDialog (Led_tString* findText, const vector<Led_tString>& recentFindSuggestions, bool* wrapSearch,
66 bool* wholeWordSearch, bool* caseSensative, bool* pressedOK) override
67 {
68 Led_StdDialogHelper_FindDialog findDialog{::AfxGetResourceHandle (), ::GetActiveWindow ()};
69
70 findDialog.fFindText = *findText;
71 findDialog.fRecentFindTextStrings = recentFindSuggestions;
72 findDialog.fWrapSearch = *wrapSearch;
73 findDialog.fWholeWordSearch = *wholeWordSearch;
74 findDialog.fCaseSensativeSearch = *caseSensative;
75
76 findDialog.DoModal ();
77
78 *findText = findDialog.fFindText;
79 *wrapSearch = findDialog.fWrapSearch;
80 *wholeWordSearch = findDialog.fWholeWordSearch;
81 *caseSensative = findDialog.fCaseSensativeSearch;
82 *pressedOK = findDialog.fPressedOK;
83 }
84#endif
85#if qSupportStdReplaceDlg
86public:
87 virtual ReplaceButtonPressed DisplayReplaceDialog (Led_tString* findText, const vector<Led_tString>& recentFindSuggestions,
88 Led_tString* replaceText, bool* wrapSearch, bool* wholeWordSearch, bool* caseSensative) override
89 {
90 Led_StdDialogHelper_ReplaceDialog replaceDialog{::AfxGetResourceHandle (), ::GetActiveWindow ()};
91
92 replaceDialog.fFindText = *findText;
93 replaceDialog.fRecentFindTextStrings = recentFindSuggestions;
94 replaceDialog.fReplaceText = *replaceText;
95 replaceDialog.fWrapSearch = *wrapSearch;
96 replaceDialog.fWholeWordSearch = *wholeWordSearch;
97 replaceDialog.fCaseSensativeSearch = *caseSensative;
98
99 replaceDialog.DoModal ();
100
101 *findText = replaceDialog.fFindText;
102 *replaceText = replaceDialog.fReplaceText;
103 *wrapSearch = replaceDialog.fWrapSearch;
104 *wholeWordSearch = replaceDialog.fWholeWordSearch;
105 *caseSensative = replaceDialog.fCaseSensativeSearch;
106
107 switch (replaceDialog.fPressed) {
108 case Led_StdDialogHelper_ReplaceDialog::eCancel:
109 return eReplaceButton_Cancel;
110 case Led_StdDialogHelper_ReplaceDialog::eFind:
111 return eReplaceButton_Find;
112 case Led_StdDialogHelper_ReplaceDialog::eReplace:
113 return eReplaceButton_Replace;
114 case Led_StdDialogHelper_ReplaceDialog::eReplaceAll:
115 return eReplaceButton_ReplaceAll;
116 case Led_StdDialogHelper_ReplaceDialog::eReplaceAllInSelection:
117 return eReplaceButton_ReplaceAllInSelection;
118 }
119 Assert (false);
120 return eReplaceButton_Cancel;
121 }
122#endif
123#if qSupportStdSpellCheckDlg
124public:
125 virtual void DisplaySpellCheckDialog (SpellCheckDialogCallback& callback) override
126 {
127 Led_StdDialogHelper_SpellCheckDialog::CallbackDelegator<SpellCheckDialogCallback> delegator (callback);
128#if qStroika_Foundation_Common_Platform_MacOS
129 Led_StdDialogHelper_SpellCheckDialog spellCheckDialog (delegator);
130#elif qStroika_Foundation_Common_Platform_Windows
131 Led_StdDialogHelper_SpellCheckDialog spellCheckDialog (delegator, ::AfxGetResourceHandle (), ::GetActiveWindow ());
132#elif qStroika_FeatureSupported_XWindows
133 Led_StdDialogHelper_SpellCheckDialog spellCheckDialog (delegator, GTK_WINDOW (LedItApplication::Get ().GetAppWindow ()));
134#endif
135
136 spellCheckDialog.DoModal ();
137 }
138#endif
139};
140static LedLineIt_DialogSupport sLedLineIt_DialogSupport;
141
142inline IncrementalFontSpecification::FontSize FontCmdToSize (UINT cmd)
143{
144 switch (cmd) {
145 case kFontSize9CmdID:
146 return 9;
147 case kFontSize10CmdID:
148 return 10;
149 case kFontSize12CmdID:
150 return 12;
151 case kFontSize14CmdID:
152 return 14;
153 case kFontSize18CmdID:
154 return 18;
155 case kFontSize24CmdID:
156 return 24;
157 case kFontSize36CmdID:
158 return 36;
159 case kFontSize48CmdID:
160 return 48;
161 case kFontSize72CmdID:
162 return 72;
163 case kFontSizeOtherCmdID:
164 return 0;
165 case kFontSizeSmallerCmdID:
166 return 0;
167 case kFontSizeLargerCmdID:
168 return 0;
169 default:
170 Assert (false);
171 return 0;
172 }
173}
174inline bool IsPredefinedFontSize (int size)
175{
176 switch (size) {
177 case 9:
178 return true;
179 case 10:
180 return true;
181 case 12:
182 return true;
183 case 14:
184 return true;
185 case 18:
186 return true;
187 case 24:
188 return true;
189 case 36:
190 return true;
191 case 48:
192 return true;
193 case 72:
194 return true;
195 default:
196 return false;
197 }
198}
199
200inline bool IsASCIISpace (int c)
201{
202 return isascii (c) and isspace (c);
203}
204
205// Perhaps replace this with a user-configuration option in the options dialog?
206const unsigned int kCharsPerTab = 4;
207
208const DistanceType kBadDistance = DistanceType (-1);
209
210class GotoLineDialog : public CDialog {
211public:
212 GotoLineDialog (size_t origLine)
213 : CDialog (kGotoLine_DialogID)
214 , fOrigLine (origLine)
215 , fResultLine (0)
216 {
217 }
218 virtual BOOL OnInitDialog () override
219 {
220 BOOL result = CDialog::OnInitDialog ();
221 SetDlgItemInt (kGotoLine_Dialog_LineNumberEditFieldID, static_cast<UINT> (fOrigLine));
222 return (result);
223 }
224 virtual void OnOK () override
225 {
226 BOOL trans = false;
227 fResultLine = GetDlgItemInt (kGotoLine_Dialog_LineNumberEditFieldID, &trans);
228 if (not trans) {
229 fResultLine = 0;
230 }
231 CDialog::OnOK ();
232 }
233
234public:
235 size_t fOrigLine;
236 size_t fResultLine;
237
238protected:
239 DECLARE_MESSAGE_MAP ()
240};
241BEGIN_MESSAGE_MAP (GotoLineDialog, CDialog)
242END_MESSAGE_MAP ()
243
244#if qSupportGenRandomCombosCommand
245namespace {
246 struct AtStartup {
247 AtStartup ()
248 {
249 ::srand ((unsigned)::time (NULL));
250 }
251 } X_AtStartup;
252}
253#endif
254
255/*
256 ********************************************************************************
257 ************************************ LedLineItView *****************************
258 ********************************************************************************
259 */
260IMPLEMENT_DYNCREATE (LedLineItView, CView)
261
262DISABLE_COMPILER_MSC_WARNING_START (4407) // Not sure this is safe to ignore but I think it is due to qMFCRequiresCWndLeftmostBaseClass
263BEGIN_MESSAGE_MAP (LedLineItView, LedLineItView::inherited)
264
265ON_WM_SETFOCUS ()
266ON_WM_CONTEXTMENU ()
267ON_COMMAND (ID_CANCEL_EDIT_CNTR, OnCancelEditCntr)
268ON_COMMAND (ID_CANCEL_EDIT_SRVR, OnCancelEditSrvr)
269ON_COMMAND (ID_FILE_PRINT, OnFilePrint)
270ON_COMMAND (ID_FILE_PRINT_DIRECT, OnFilePrint)
271ON_COMMAND (ID_FILE_PRINT_PREVIEW, OnFilePrintPreview)
272
273ON_COMMAND (kGotoLineCmdID, OnGotoLineCommand)
274#if qSupportGenRandomCombosCommand
275ON_COMMAND (kGenRandomCombosCmdID, OnGenRandomCombosCommand)
276#endif
277ON_COMMAND (kShiftLeftCmdID, OnShiftLeftCommand)
278ON_COMMAND (kShiftRightCmdID, OnShiftRightCommand)
279
280ON_COMMAND (cmdChooseFontDialog, OnChooseFontCommand)
281
282ON_UPDATE_COMMAND_UI_RANGE (cmdFontMenuFirst, cmdFontMenuLast, OnUpdateFontNameChangeCommand)
283ON_COMMAND_RANGE (cmdFontMenuFirst, cmdFontMenuLast, OnFontNameChangeCommand)
284
285ON_UPDATE_COMMAND_UI_RANGE (kBaseFontSizeCmdID, kLastFontSizeCmdID, OnUpdateFontSizeChangeCommand)
286ON_COMMAND_RANGE (kBaseFontSizeCmdID, kLastFontSizeCmdID, OnFontSizeChangeCommand)
287END_MESSAGE_MAP ()
288DISABLE_COMPILER_MSC_WARNING_END (4407)
289
290LedLineItView::LedLineItView ()
291 : inherited ()
292 , fTabStopList (TWIPS (1440 / 3))
293 , fCachedLayoutWidth (kBadDistance)
294#if qSupportSyntaxColoring
295 , fSyntaxColoringMarkerOwner (NULL)
296#endif
297{
298 SetDefaultFont (Options{}.GetDefaultNewDocFont ());
299
300 SetSmartCutAndPasteMode (Options{}.GetSmartCutAndPaste ());
301 SetControlArrowsScroll (true);
302 SetScrollBarType (h, eScrollBarAlways);
303 SetScrollBarType (v, eScrollBarAlways);
304
305 /*
306 * No logic to picking these margins (I know of). Just picked them based on what looked good.
307 * You can comment this out entirely to get the default (zero margins).
308 */
309 const TWIPS kLedItViewTopMargin = TWIPS (60);
310 const TWIPS kLedItViewBottomMargin = TWIPS (0);
311 const TWIPS kLedItViewLHSMargin = TWIPS (60);
312 const TWIPS kLedItViewRHSMargin = TWIPS (60);
313#if qStroika_Foundation_Common_Platform_Windows
314 // This SHOULD be available on other platforms, but only now done for WIN32
315 SetDefaultWindowMargins (TWIPS_Rect (kLedItViewTopMargin, kLedItViewLHSMargin, kLedItViewBottomMargin - kLedItViewTopMargin,
316 kLedItViewRHSMargin - kLedItViewLHSMargin));
317#endif
318
319#if qStroika_Foundation_Common_Platform_MacOS || qStroika_Foundation_Common_Platform_Windows
320 SetUseSecondaryHilight (true);
321#endif
322}
323
324LedLineItView::~LedLineItView ()
325{
326 SpecifyTextStore (NULL);
327 SetCommandHandler (NULL);
328#if qIncludeBasicSpellcheckEngine
329 SetSpellCheckEngine (NULL);
330#endif
331#if qSupportSyntaxColoring
332 Assert (fSyntaxColoringMarkerOwner == NULL);
333#endif
334}
335
336void LedLineItView::OnInitialUpdate ()
337{
338 inherited::OnInitialUpdate ();
339 SpecifyTextStore (&GetDocument ().GetTextStore ());
340 SetCommandHandler (&GetDocument ().GetCommandHandler ());
341#if qIncludeBasicSpellcheckEngine
342 SetSpellCheckEngine (LedLineItApplication::Get ().fSpellCheckEngine.get ());
343#endif
344}
345
346#if qSupportSyntaxColoring
347void LedLineItView::ResetSyntaxColoringTable ()
348{
349 if (PeekAtTextStore () != NULL) {
350 // static const TrivialRGBSyntaxAnalyzer kAnalyzer;
351 static const TableDrivenKeywordSyntaxAnalyzer kCPlusPlusAnalyzer (TableDrivenKeywordSyntaxAnalyzer::kCPlusPlusKeywords);
352 static const TableDrivenKeywordSyntaxAnalyzer kVisualBasicAnalyzer (TableDrivenKeywordSyntaxAnalyzer::kVisualBasicKeywords);
353
354 const SyntaxAnalyzer* analyzer = NULL;
355 switch (Options{}.GetSyntaxColoringOption ()) {
356 case Options::eSyntaxColoringNone: /* nothing - analyzer already NULL*/
357 break;
358 case Options::eSyntaxColoringCPlusPlus:
359 analyzer = &kCPlusPlusAnalyzer;
360 break;
361 case Options::eSyntaxColoringVB:
362 analyzer = &kVisualBasicAnalyzer;
363 break;
364 }
365
366 delete fSyntaxColoringMarkerOwner;
367 fSyntaxColoringMarkerOwner = NULL;
368
369 if (analyzer != NULL) {
370#if qSupportOnlyMarkersWhichOverlapVisibleRegion
371 fSyntaxColoringMarkerOwner = new WindowedSyntaxColoringMarkerOwner (*this, GetTextStore (), *analyzer);
372#else
373 fSyntaxColoringMarkerOwner = new SimpleSyntaxColoringMarkerOwner (*this, GetTextStore (), *analyzer);
374#endif
375 fSyntaxColoringMarkerOwner->RecheckAll ();
376 }
377 }
378}
379
380void LedLineItView::HookLosingTextStore ()
381{
382 delete fSyntaxColoringMarkerOwner;
383 fSyntaxColoringMarkerOwner = NULL;
384 inherited::HookLosingTextStore ();
385}
386
387void LedLineItView::HookGainedNewTextStore ()
388{
389 Assert (fSyntaxColoringMarkerOwner == NULL);
390 inherited::HookGainedNewTextStore ();
391 ResetSyntaxColoringTable ();
392}
393#endif
394
395#if qSupportSyntaxColoring
396vector<StyleRunElement> LedLineItView::SummarizeStyleMarkers (size_t from, size_t to) const
397{
398 // See SPR#1293 - may want to get rid of this eventually
399 StyleMarkerSummarySinkForSingleOwner summary (*fSyntaxColoringMarkerOwner, from, to);
400 GetTextStore ().CollectAllMarkersInRangeInto (from, to, TextStore::kAnyMarkerOwner, summary);
401 return summary.ProduceOutputSummary ();
402}
403
404vector<StyleRunElement> LedLineItView::SummarizeStyleMarkers (size_t from, size_t to, const TextLayoutBlock& text) const
405{
406 StyleMarkerSummarySinkForSingleOwner summary (*fSyntaxColoringMarkerOwner, from, to, text);
407 GetTextStore ().CollectAllMarkersInRangeInto (from, to, TextStore::kAnyMarkerOwner, summary);
408 return summary.ProduceOutputSummary ();
409}
410#endif
411
412size_t LedLineItView::GetCurUserLine () const
413{
414 // Either do caching here, or inside of GetRowContainingPosition () so this is quick.
415 // Called ALOT - even for very large documents
416 // LGP 970303
417 return GetRowContainingPosition (GetSelectionStart ()) + 1; // unclear if we should use selstart or selEnd - pick arbitrarily...
418}
419
420void LedLineItView::SetCurUserLine (size_t newCurLine)
421{
422 // Assume line chosen 1 based, regardless of how Led is built. This is the most common UI.
423 // And pin to ends if user choses too large / too small line number
424 size_t selPos = 0;
425 if (newCurLine >= 1) {
426 if (newCurLine > GetRowCount ()) {
427 newCurLine = GetRowCount ();
428 }
429 selPos = GetStartOfRow (newCurLine + (0 - 1));
430 }
431 size_t endPos = min (GetRealEndOfRowContainingPosition (selPos), GetLength ());
432 SetSelection (selPos, endPos);
433 ScrollToSelection ();
434}
435
436const TabStopList& LedLineItView::GetTabStopList (size_t /*containingPos*/) const
437{
438 return fTabStopList;
439}
440
441void LedLineItView::TabletChangedMetrics ()
442{
443 inherited::TabletChangedMetrics ();
444
445 Tablet_Acquirer tablet_ (this);
446 Tablet* tablet = tablet_;
447 fTabStopList.fTWIPSPerTabStop = tablet->CvtToTWIPSH (kCharsPerTab * GetFontMetricsAt (0).GetMaxCharacterWidth ());
448 fCachedLayoutWidth = kBadDistance;
449#if qSupportSyntaxColoring
450 if (fSyntaxColoringMarkerOwner != NULL) {
451 fSyntaxColoringMarkerOwner->RecheckAll ();
452 }
453#endif
454}
455
456void LedLineItView::DidUpdateText (const UpdateInfo& updateInfo) noexcept
457{
458 inherited::DidUpdateText (updateInfo);
459 fCachedLayoutWidth = kBadDistance;
460}
461
462void LedLineItView::UpdateScrollBars ()
463{
464 // scrolling can change the longest row in window, so update our LayoutWidth
465 fCachedLayoutWidth = kBadDistance;
466 inherited::UpdateScrollBars ();
467#if qSupportSyntaxColoring && qSupportOnlyMarkersWhichOverlapVisibleRegion
468 if (fSyntaxColoringMarkerOwner != NULL) {
469 fSyntaxColoringMarkerOwner->RecheckScrolling ();
470 }
471#endif
472}
473
474DistanceType LedLineItView::ComputeMaxHScrollPos () const
475{
476 if (fCachedLayoutWidth == kBadDistance) {
477 /*
478 * Figure the largest amount we might need to scroll given the current windows contents.
479 * But take into account where we've scrolled so far, and never invalidate that
480 * scroll amount. Always leave at least as much layout-width as needed to
481 * preserve the current scroll-to position.
482 */
483 DistanceType width = CalculateLongestRowInWindowPixelWidth ();
484 if (GetHScrollPos () != 0) {
485 width = max (width, GetHScrollPos () + GetWindowRect ().GetWidth ());
486 }
487 fCachedLayoutWidth = max (width, DistanceType (1));
488 }
489 DistanceType wWidth = GetWindowRect ().GetWidth ();
490 if (fCachedLayoutWidth > wWidth) {
491 return (fCachedLayoutWidth - wWidth);
492 }
493 else {
494 return 0;
495 }
496}
497
498void LedLineItView::OnTypedNormalCharacter (Led_tChar theChar, bool optionPressed, bool shiftPressed, bool commandPressed,
499 bool controlPressed, bool altKeyPressed)
500{
501 if (theChar == '\t' and Options{}.GetTreatTabAsIndentChar ()) {
502 // Check if the selection looks like its likely an auto-indent situation...
503 bool shiftSituation = GetSelectionStart () != GetSelectionEnd ();
504 if (shiftSituation) {
505 // If we select an entire line, or multiple lines - then the user likely intended to auto-indent. But if the selection
506 // is strictly INTRALINE - he probably intedned to replace the selected text with a tab.
507 size_t selStart = GetSelectionStart ();
508 size_t selEnd = GetSelectionEnd ();
509 size_t selStartRowStart = GetStartOfRowContainingPosition (selStart);
510 size_t selEndRowStart = GetStartOfRowContainingPosition (selEnd);
511 size_t selEndRowEnd = GetEndOfRowContainingPosition (selEnd);
512
513 // The logic is simpler to understand this way - but terser to express in the negative - I choose clarity over brevity here...
514 if (selStartRowStart != selEndRowStart) {
515 // OK - in case of multiple rows - we shift
516 }
517 else if (selStartRowStart == selEndRowStart and selStart == selStartRowStart and selEnd == selEndRowEnd) {
518 // if its a single line - but fully selected- then OK - we shift
519 }
520 else {
521 // otherwise - its an intrarow selection - and we treat that as NOT a shift - but just a replace
522 shiftSituation = false;
523 }
524 }
525
526 if (shiftSituation) {
527 if (shiftPressed) {
528 OnShiftLeftCommand ();
529 }
530 else {
531 OnShiftRightCommand ();
532 }
533 return;
534 }
535 }
536
537 inherited::OnTypedNormalCharacter (theChar, optionPressed, shiftPressed, commandPressed, controlPressed, altKeyPressed);
538 if (theChar == '\n' and GetSelectionStart () == GetSelectionEnd () and Options{}.GetAutoIndent ()) {
539 // Find the "indent level" of the previous line, and insert that much space here.
540 size_t rowStart = GetStartOfRowContainingPosition (GetSelectionEnd ());
541 size_t prevRowStart = GetStartOfPrevRowFromRowContainingPosition (GetSelectionEnd ());
542 // Check first we're not on the first line - don't want to auto-indent there..
543 if (rowStart != prevRowStart) {
544 size_t prevRowEnd = GetEndOfRowContainingPosition (prevRowStart);
545 Assert (prevRowEnd >= prevRowStart);
546 size_t prevRowLen = prevRowEnd - prevRowStart;
547 StackBuffer<Led_tChar> buf{Memory::eUninitialized, prevRowLen};
548 CopyOut (prevRowStart, prevRowLen, buf.data ());
549 size_t nTChars = 0;
550 for (size_t i = 0; i < prevRowLen; ++i) {
551 // use ANY space characters to auto-indent - should only use SPACE and TAB?
552 if (not IsASCIISpace (buf[i])) {
553 break;
554 }
555 ++nTChars;
556 }
557 InteractiveReplace (buf.data (), nTChars);
558 }
559 }
560}
561
562void LedLineItView::OnContextMenu (CWnd* /*pWnd*/, CPoint pt)
563{
564 CMenu menu;
565 if (menu.LoadMenu (kContextMenu)) {
566 CMenu* popup = menu.GetSubMenu (0);
567 AssertNotNull (popup);
568 popup->TrackPopupMenu (TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, ::AfxGetMainWnd ());
569 }
570}
571
572BOOL LedLineItView::IsSelected (const CObject* pDocItem) const
573{
574 // The implementation below is adequate if your selection consists of
575 // only LedLineItControlItem objects. To handle different selection
576 // mechanisms, the implementation here should be replaced.
577
578 // TODO: implement this function that tests for a selected OLE client item
579 //return pDocItem == GetSoleSelectedOLEEmbedding ();
580 [[maybe_unused]] BOOL test = inherited::IsSelected (pDocItem);
581 return false; // should I even need to override this? Probably NO!!!
582}
583
584void LedLineItView::OnUpdateFontNameChangeCommand (CCmdUI* pCmdUI)
585{
586 RequireNotNull (pCmdUI);
587
588 // check the item iff it is the currently selected font.
589 // But always enable them...
590 SDKString fontName = CmdNumToFontName (pCmdUI->m_nID);
591
592 pCmdUI->SetCheck (fontName == GetDefaultFont ().GetFontName ());
593 pCmdUI->Enable (true);
594}
595
596void LedLineItView::OnFontNameChangeCommand (UINT cmdNum)
597{
598 SDKString fontName = CmdNumToFontName (cmdNum);
599 IncrementalFontSpecification applyFontSpec;
600 applyFontSpec.SetFontName (fontName);
601 SetDefaultFont (applyFontSpec);
602}
603
604void LedLineItView::OnUpdateFontSizeChangeCommand (CCmdUI* pCmdUI)
605{
606 RequireNotNull (pCmdUI);
607 int chosenFontSize = FontCmdToSize (pCmdUI->m_nID);
608
609 if (chosenFontSize == 0) {
610 switch (pCmdUI->m_nID) {
611 case kFontSizeSmallerCmdID:
612 case kFontSizeLargerCmdID: {
613 pCmdUI->Enable (true);
614 } break;
615
616 case kFontSizeOtherCmdID: {
617 TCHAR nameBuf[1024];
618 Characters::CString::Copy (nameBuf, Memory::NEltsOf (nameBuf), _T ("Other"));
619 pCmdUI->SetCheck (false);
620 {
621 int pointSize = GetDefaultFont ().GetPointSize ();
622 if (not IsPredefinedFontSize (pointSize)) {
623 Characters::CString::Cat (nameBuf, Memory::NEltsOf (nameBuf), _T (" ("));
624 TCHAR nBuf[100];
625 DISABLE_COMPILER_MSC_WARNING_START (4996)
626 _stprintf (nBuf, _T ("%d"), GetDefaultFont ().GetPointSize ());
627 DISABLE_COMPILER_MSC_WARNING_END (4996)
628 Characters::CString::Cat (nameBuf, Memory::NEltsOf (nameBuf), nBuf);
629 Characters::CString::Cat (nameBuf, Memory::NEltsOf (nameBuf), _T (")"));
630 pCmdUI->SetCheck (true);
631 }
632 }
633 Characters::CString::Cat (nameBuf, Memory::NEltsOf (nameBuf), _T ("..."));
634 pCmdUI->SetText (nameBuf);
635 } break;
636 }
637 }
638 else {
639 pCmdUI->SetCheck (GetDefaultFont ().GetPointSize () == chosenFontSize);
640 pCmdUI->Enable (true);
641 }
642}
643
644void LedLineItView::OnFontSizeChangeCommand (UINT cmdNum)
645{
646 FontSpecification::FontSize chosenFontSize = FontCmdToSize (cmdNum);
647 if (chosenFontSize == 0) {
648 switch (cmdNum) {
649 case kFontSizeSmallerCmdID: {
650 IncrementalFontSpecification applyFontSpec;
651 applyFontSpec.SetPointSizeIncrement (-1);
652 SetDefaultFont (applyFontSpec);
653 return;
654 } break;
655 case kFontSizeLargerCmdID: {
656 IncrementalFontSpecification applyFontSpec;
657 applyFontSpec.SetPointSizeIncrement (1);
658 SetDefaultFont (applyFontSpec);
659 return;
660 } break;
661 case kFontSizeOtherCmdID: {
662 DistanceType oldSize = GetDefaultFont ().GetPointSize ();
663 chosenFontSize = static_cast<FontSpecification::FontSize> (PickOtherFontHeight (oldSize));
664 } break;
665 }
666 }
667 if (chosenFontSize != 0) {
668 IncrementalFontSpecification applyFontSpec;
669 applyFontSpec.SetPointSize (chosenFontSize);
670 SetDefaultFont (applyFontSpec);
671 }
672}
673
674DistanceType LedLineItView::PickOtherFontHeight (DistanceType origHeight)
675{
676#if qStroika_Foundation_Common_Platform_MacOS
677 Led_StdDialogHelper_OtherFontSizeDialog dlg;
678#elif qStroika_Foundation_Common_Platform_Windows
679 Led_StdDialogHelper_OtherFontSizeDialog dlg{::AfxGetResourceHandle (), ::GetActiveWindow ()};
680#endif
681 dlg.InitValues (origHeight);
682 if (dlg.DoModal ()) {
683 return dlg.fFontSize_Result;
684 }
685 else {
686 return 0;
687 }
688}
689
690LedLineItView::SearchParameters LedLineItView::GetSearchParameters () const
691{
692 return Options{}.GetSearchParameters ();
693}
694
695void LedLineItView::SetSearchParameters (const SearchParameters& sp)
696{
697 Options{}.SetSearchParameters (sp);
698}
699
700void LedLineItView::OnGotoLineCommand ()
701{
702 /*
703 * compute current line, and use that as the default for the dialog box. Put up the dlog box,
704 * prompting user. Then move the selection to that line (and scroll to selection).
705 */
706 size_t rowNumber = GetCurUserLine ();
707
708 /*
709 * I had coded this before to check if the stats bar was shown, and treat this
710 * as jumping the focus to the status bar. But Simone and Doug barfed violently
711 * on this idea. So lets me more traditional.
712 * -- LGP 970315
713 */
714 GotoLineDialog dlg (rowNumber);
715
716 if (dlg.DoModal () == IDOK) {
717 SetCurUserLine (dlg.fResultLine);
718 }
719}
720
721#if qSupportGenRandomCombosCommand
722void LedLineItView::OnGenRandomCombosCommand ()
723{
724 vector<Led_tString> srcFrags;
725
726 {
727 size_t lastStart = static_cast<size_t> (-1);
728 for (size_t i = GetStartOfRowContainingPosition (GetSelectionStart ()); i < GetSelectionEnd () and lastStart != i;
729 lastStart = i, i = GetStartOfNextRowFromRowContainingPosition (i)) {
730 size_t rowEnd = GetEndOfRowContainingPosition (i);
731 size_t rowLen = rowEnd - i;
732 StackBuffer<Led_tChar> buf{Memory::eUninitialized, rowLen + 1};
733 CopyOut (i, rowLen, buf);
734 buf[rowLen] = '\0';
735 srcFrags.push_back (static_cast<Led_tString> (buf));
736 }
737 }
738
739 const unsigned kGeneratedCount = 100;
740 const unsigned kMaxComboLen = 4;
741 set<Led_tString> resultFrags;
742 if (srcFrags.size () != 0) {
743 for (size_t i = 0; i < kGeneratedCount; ++i) {
744 unsigned int n = (rand () % kMaxComboLen) + 1;
745 Led_tString tmpWord;
746 for (size_t ni = 0; ni < n; ++ni) {
747 // now pick a random srcWord
748 unsigned int wi = (rand () % srcFrags.size ());
749 tmpWord += srcFrags[wi];
750 }
751 resultFrags.insert (tmpWord);
752 }
753 }
754
755 CDocManager* docMgr = AfxGetApp ()->m_pDocManager;
756 AssertNotNull (docMgr);
757 CDocTemplate* pTemplate = NULL;
758 {
759 POSITION p = docMgr->GetFirstDocTemplatePosition ();
760 pTemplate = docMgr->GetNextDocTemplate (p);
761 }
762 AssertNotNull (pTemplate);
763 CDocument* newDoc = pTemplate->OpenDocumentFile (NULL);
764 newDoc->SetTitle (newDoc->GetTitle () + Led_SDK_TCHAROF (" {generated-words}"));
765 LedLineItDocument* lNewDoc = dynamic_cast<LedLineItDocument*> (newDoc);
766 AssertNotNull (lNewDoc);
767 TextStore& ts = lNewDoc->GetTextStore ();
768 for (set<Led_tString>::const_iterator i = resultFrags.begin (); i != resultFrags.end (); ++i) {
769 ts.Replace (ts.GetEnd (), ts.GetEnd (), (*i).c_str (), (*i).length ());
770 ts.Replace (ts.GetEnd (), ts.GetEnd (), LED_TCHAR_OF ("\n"), 1);
771 }
772}
773#endif
774
775void LedLineItView::OnShiftLeftCommand ()
776{
777 OnShiftNCommand (false);
778}
779
780void LedLineItView::OnShiftRightCommand ()
781{
782 OnShiftNCommand (true);
783}
784
785void LedLineItView::OnShiftNCommand (bool shiftRight)
786{
787 BreakInGroupedCommands ();
788
789 // Find the entire set of rows which encompass the selection
790 PartitionMarker* firstPM = GetPartitionMarkerContainingPosition (GetSelectionStart ());
791 PartitionMarker* lastPM = GetPartitionMarkerContainingPosition (GetSelectionEnd ());
792 AssertNotNull (firstPM);
793 AssertNotNull (lastPM);
794 if (lastPM != firstPM and lastPM->GetStart () == GetSelectionEnd ()) {
795 lastPM = lastPM->GetPrevious ();
796 AssertNotNull (lastPM);
797 }
798
799 TextInteractor::UndoableContextHelper undoContext (*this, shiftRight ? Led_SDK_TCHAROF ("Shift Right") : Led_SDK_TCHAROF ("Shift Left"),
800 firstPM->GetStart (), min (lastPM->GetEnd (), GetTextStore ().GetEnd ()),
801 GetSelectionStart (), GetSelectionEnd (), false);
802 {
803 SetSelection (firstPM->GetStart (), min (lastPM->GetEnd (), GetTextStore ().GetEnd ()));
804
805 // Go through each PM, and either shift it right or left.
806 for (PartitionMarker* pm = firstPM; pm != lastPM->GetNext (); pm = pm->GetNext ()) {
807 if (shiftRight) {
808 InteractiveReplace_ (pm->GetStart (), pm->GetStart (), LED_TCHAR_OF ("\t"), 1, false, false, eDefaultUpdate);
809 }
810 else {
811 size_t pmLength = pm->GetLength ();
812 size_t lookAtLength = min<size_t> (pmLength - 1, kCharsPerTab);
813 StackBuffer<Led_tChar> buf{Memory::eUninitialized, lookAtLength};
814 CopyOut (pm->GetStart (), lookAtLength, buf.data ());
815 size_t deleteLength = lookAtLength; // default to deleting all if all whitespace..
816 for (size_t i = 0; i < lookAtLength; ++i) {
817 if (buf[i] == '\t') {
818 deleteLength = i + 1;
819 break;
820 }
821 if (not(IsASCIISpace (buf[i]))) {
822 deleteLength = i;
823 break;
824 }
825 }
826
827 // delete the first lookAtLength characters.
828 InteractiveReplace_ (pm->GetStart (), pm->GetStart () + deleteLength, LED_TCHAR_OF (""), 0, false, false, eDefaultUpdate);
829 }
830 }
831
832 // Select the entire set of rows updated.
833 SetSelection (firstPM->GetStart (), min (lastPM->GetEnd (), GetTextStore ().GetEnd ()));
834 }
835 undoContext.CommandComplete ();
836
837 BreakInGroupedCommands ();
838}
839
840// The following command handler provides the standard keyboard
841// user interface to cancel an in-place editing session. Here,
842// the container (not the server) causes the deactivation.
843void LedLineItView::OnCancelEditCntr ()
844{
845 // Close any in-place active item on this view.
846 COleClientItem* pActiveItem = GetDocument ().GetInPlaceActiveItem (this);
847 if (pActiveItem != NULL) {
848 pActiveItem->Close ();
849 }
850 ASSERT (GetDocument ().GetInPlaceActiveItem (this) == NULL);
851}
852
853// Special handling of OnSetFocus and OnSize are required for a container
854// when an object is being edited in-place.
855void LedLineItView::OnSetFocus (CWnd* pOldWnd)
856{
857 COleClientItem* pActiveItem = GetDocument ().GetInPlaceActiveItem (this);
858 if (pActiveItem != NULL && pActiveItem->GetItemState () == COleClientItem::activeUIState) {
859 // need to set focus to this item if it is in the same view
860 CWnd* pWnd = pActiveItem->GetInPlaceWindow ();
861 if (pWnd != NULL) {
862 pWnd->SetFocus (); // don't call the base class
863 return;
864 }
865 }
866 inherited::OnSetFocus (pOldWnd);
867}
868
869void LedLineItView::OnCancelEditSrvr ()
870{
871 GetDocument ().OnDeactivateUI (FALSE);
872}
873
874void LedLineItView::OnSelectAllCommand ()
875{
876 SetSelection (0, GetLength ());
877}
878
879void LedLineItView::OnChooseFontCommand ()
880{
881 // Copy each valid attribute into the LOGFONT to initialize the CFontDialog
882 LOGFONT lf;
883 (void)::memset (&lf, 0, sizeof (lf));
884 {
885 Characters::CString::Copy (lf.lfFaceName, Memory::NEltsOf (lf.lfFaceName), GetDefaultFont ().GetFontNameSpecifier ().fName);
886 Assert (::_tcslen (lf.lfFaceName) < sizeof (lf.lfFaceName)); // cuz our cached entry - if valid - always short enuf...
887 }
888 lf.lfWeight = (GetDefaultFont ().GetStyle_Bold ()) ? FW_BOLD : FW_NORMAL;
889 lf.lfItalic = (GetDefaultFont ().GetStyle_Italic ());
890 lf.lfUnderline = (GetDefaultFont ().GetStyle_Underline ());
891 lf.lfStrikeOut = (GetDefaultFont ().GetStyle_Strikeout ());
892
893 lf.lfHeight = GetDefaultFont ().PeekAtTMHeight ();
894
895 FontDlgWithNoColorNoStyles dlog (&lf);
896 if (dlog.DoModal () == IDOK) {
897 SetDefaultFont (FontSpecification (*dlog.m_cf.lpLogFont));
898 }
899}
900
901#ifdef _DEBUG
902void LedLineItView::AssertValid () const
903{
904 inherited::AssertValid ();
905}
906
907void LedLineItView::Dump (CDumpContext& dc) const
908{
909 inherited::Dump (dc);
910}
911
912LedLineItDocument& LedLineItView::GetDocument () const // non-debug version is inline
913{
914 ASSERT (m_pDocument->IsKindOf (RUNTIME_CLASS (LedLineItDocument)));
915 ASSERT_VALID (m_pDocument);
916 return *(LedLineItDocument*)m_pDocument;
917}
918#endif //_DEBUG
919
920/*
921 ********************************************************************************
922 ************************* FontDlgWithNoColorNoStyles ***************************
923 ********************************************************************************
924 */
925FontDlgWithNoColorNoStyles::FontDlgWithNoColorNoStyles (LOGFONT* lf)
926 : CFontDialog (lf, CF_SCREENFONTS | CF_SCALABLEONLY | CF_NOVERTFONTS)
927{
928 // SPR#1369 : Either CF_SCALABLEONLY or CF_TTONLY seems to get rid of bad fonts that don't work right with tabs
929}
930
931BOOL FontDlgWithNoColorNoStyles::OnInitDialog ()
932{
933 BOOL result = CFontDialog::OnInitDialog ();
934
935 // hide the widgets for the font-style choices
936 // Gee - I hope Microslop doesn't change these values!!! LGP 970118
937
938 // Font STYLE list LABEL
939 if (GetDlgItem (stc2) != NULL) {
940 GetDlgItem (stc2)->ShowWindow (SW_HIDE);
941 }
942 // Font STYLE list
943 if (GetDlgItem (cmb2) != NULL) {
944 GetDlgItem (cmb2)->ShowWindow (SW_HIDE);
945 }
946
947 // Script list LABEL
948 if (GetDlgItem (stc7) != NULL) {
949 GetDlgItem (stc7)->ShowWindow (SW_HIDE);
950 }
951 // Script list
952 if (GetDlgItem (cmb5) != NULL) {
953 GetDlgItem (cmb5)->ShowWindow (SW_HIDE);
954 }
955 return result;
956}
#define AssertNotNull(p)
Definition Assertions.h:333
#define RequireNotNull(p)
Definition Assertions.h:347
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
basic_string< SDKChar > SDKString
Definition SDKString.h:38