-
-
Notifications
You must be signed in to change notification settings - Fork 32
/
VwSelection.cpp
14294 lines (13209 loc) · 492 KB
/
VwSelection.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*--------------------------------------------------------------------*//*:Ignore this sentence.
Copyright (c) 1999-2015 SIL International
This software is licensed under the LGPL, version 2.1 or later
(http://www.gnu.org/licenses/lgpl-2.1.html)
File: VwSelection.cpp
Responsibility: John Thomson
Last reviewed: Not yet.
Description:
The various kinds of selection (currently only text) that can be made in views.
-------------------------------------------------------------------------------*//*:End Ignore*/
//:>********************************************************************************************
//:> Include files
//:>********************************************************************************************
#include "Main.h"
#pragma hdrstop
// any other headers (not precompiled)
#undef THIS_FILE
DEFINE_THIS_FILE
#define EDITABLE_SELECTIONS_ONLY 1
using namespace std;
enum CharacterType { kSpace, kPunc, kAlpha };
static CharacterType GetCharacterType(ILgWritingSystem * pws, OLECHAR chw);
//:>********************************************************************************************
//:> Forward declarations
//:>********************************************************************************************
//:>********************************************************************************************
//:> Local Constants and static variables
//:>********************************************************************************************
IMPLEMENT_SIL_DISPATCH(IVwSelection, &IID_IVwSelection, &LIBID_Views)
static DummyFactory g_fact(
_T("SIL.Views.VwTextSelection"));
//:>********************************************************************************************
//:> VwSelection Constructors/Destructor
//:>********************************************************************************************
/*----------------------------------------------------------------------------------------------
Constructor.
----------------------------------------------------------------------------------------------*/
VwSelection::VwSelection()
{
m_cref = 1;
ModuleEntry::ModuleAddRef();
m_fShowing = false;
}
/*----------------------------------------------------------------------------------------------
Destructor.
----------------------------------------------------------------------------------------------*/
VwSelection::~VwSelection()
{
if (m_qrootb)
{
m_qrootb->UnregisterSelection(this);
m_qrootb.Clear();
}
ModuleEntry::ModuleRelease();
}
//:>********************************************************************************************
//:> IUnknown
//:>********************************************************************************************
/*----------------------------------------------------------------------------------------------
Standard COM function.
@param riid - reference to the desired interface ID.
@param ppv - address that receives the interface pointer.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::QueryInterface(REFIID riid, void ** ppv)
{
AssertPtr(ppv);
if (!ppv)
return WarnHr(E_POINTER);
*ppv = NULL;
if (riid == IID_IUnknown)
*ppv = static_cast<IUnknown *>(this);
else if (riid == IID_IVwSelection)
*ppv = static_cast<IVwSelection *>(this);
else if (riid == IID_ISupportErrorInfo)
{
*ppv = NewObj CSupportErrorInfo(this, IID_IVwSelection);
return S_OK;
}
else
return E_NOINTERFACE;
AddRef();
return NOERROR;
}
void GetWsFromRootAndProps(VwRootBox * prootb, ITsTextProps * pttp, ILgWritingSystem ** ppws)
{
ILgWritingSystemFactoryPtr qwsf;
CheckHr(prootb->GetDataAccess()->get_WritingSystemFactory(&qwsf));
if (pttp)
{
int ws, tmp;
CheckHr(pttp->GetIntPropValues(ktptWs, &tmp, &ws));
CheckHr(qwsf->get_EngineOrNull(ws, ppws));
}
else
{
*ppws = NULL;
}
}
/*----------------------------------------------------------------------------------------------
Override to allow CLSID_VwTextSelection trick so we can find out if an interface is our own
implementation.
@param riid - reference to the desired interface ID.
@param ppv - address that receives the interface pointer.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwTextSelection::QueryInterface(REFIID riid, void ** ppv)
{
AssertPtr(ppv);
if (!ppv)
return WarnHr(E_POINTER);
*ppv = NULL;
if (riid == IID_IUnknown)
*ppv = static_cast<IUnknown *>(this);
else if (riid == IID_IVwSelection)
*ppv = static_cast<IVwSelection *>(this);
else if (&riid == &CLSID_VwTextSelection) // ERRORJOHN
*ppv = static_cast<VwTextSelection *>(this);
else if (riid == IID_ISupportErrorInfo)
{
*ppv = NewObj CSupportErrorInfo(this, IID_IVwSelection);
return S_OK;
}
else
return E_NOINTERFACE;
AddRef();
return NOERROR;
}
/***********************************************************************************************
IVwSelection methods
***********************************************************************************************/
/*----------------------------------------------------------------------------------------------
Answer true if the selection is a range.
@param pfRet - pointer to return value through.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::get_IsRange(ComBool * pfRet)
{
BEGIN_COM_METHOD;
ChkComOutPtr(pfRet);
*pfRet = !IsInsertionPoint();
END_COM_METHOD(g_fact, IID_IVwSelection);
}
/*----------------------------------------------------------------------------------------------
Update the properties of the selected text.
An item is typically passed in for each TsTextProps previously returned by a
call to GetSelectionProps. A null in the array passed here means do not
change the properties for that range. A Ttp means change properties to that.
@param cttp - number of text properties in the array.
@param prgpttp - array of text properties.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::SetSelectionProps(int cttp, ITsTextProps ** prgpttp)
{
return S_OK; // There's no way to get one of these objects at present, so anything works.
}
/*----------------------------------------------------------------------------------------------
Get the paragraph-level properties of the selected paragraph(s).
Note that, unlike character level properties, we can only read the actual state
of the paragraphs (IVwPropertyStore), not the TsTextProps that produced them.
In fact, it is only in StText or something similar that each paragraph has an
associated TsTextProps. However, we can get the actual properties.
@param cttpMax
@param prgpvps
@param pcttp
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::GetParaProps(int cttpMax, IVwPropertyStore ** prgpvps, int * pcttp)
{
BEGIN_COM_METHOD;
ChkComArrayArg(prgpvps, cttpMax);
ChkComOutPtr(pcttp);
// By default a selection has no text props, so leave *pcttp zero.
END_COM_METHOD(g_fact, IID_IVwSelection);
}
/*----------------------------------------------------------------------------------------------
Get a sequence of TsTextProps, one for each range in the current selection.
If the current selection is an insertion point return one text props,
the one that will currently be used for an inserted character.
If the selection is not a text selection at all return 0 objects. This is the default here.
@param cttpMax
@param prgpttp
@param prgpvps
@param pcttp
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::GetSelectionProps(int cttpMax, ITsTextProps ** prgpttp,
IVwPropertyStore ** prgpvps, int * pcttp)
{
BEGIN_COM_METHOD;
ChkComArrayArg(prgpttp, cttpMax);
ChkComArrayArg(prgpvps, cttpMax);
ChkComOutPtr(pcttp);
// By default a selection has no text props, so leave 0.
END_COM_METHOD(g_fact, IID_IVwSelection);
}
/*----------------------------------------------------------------------------------------------
These methods allow getting info about the current selection.
A selection has an anchor and end point, which may be the same (insertion point) or
different(range). Each consists of a position in a string. (We may later support other
kinds of selection, in which case the interface will need extending.)
A method allows you to obtain the strings and positions.
You can also find out what properties of what objects those strings are.
Moreover, it is possible that those objects are displayed as part of the
display of some property of some higher level object. You can find out what
properties of what object, all the way up to some object that is not part of
any higher level object.
The AssocPrev argument indicates whether the selection is considered to be
before or after the indicated end point. Thus, for a range, it is false
at the start of the range and true at the end. For an insertion point,
it is the same for anchor and end point, and indicates whether the selection
is primarily considered to come after the preceding character (true) or before
the following one (false). This is important in deciding things like which
character properties apply.
@param fEndPoint - true for end point, false for anchor
@param pptss - string containing selection
@param pich - pointer to the offset into string
@param pfAssocPrev - flag whether the selection is considered to be before or after the
indicated end point
@param phvoObj - object to which the string belongs (or 0 if none)
@param ptag - tag of property to which the string belongs
@param pws - identifies which alternative, if prop is an alternation.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::TextSelInfo(ComBool fEndPoint, ITsString ** pptss, int * pich,
ComBool * pfAssocPrev, HVO * phvoObj, PropTag * ptag, int * pws)
{
// Note: I'm not worrying about doing a nice job of ones that are overridden.
Assert(false);
return E_NOTIMPL;
}
/*----------------------------------------------------------------------------------------------
The information returned by TextSelInfo indicates the level-0 object/prop
information. CLevels indicates how many levels including that exist.
@param fEndPoint - True for end point, false for anchor.
@param pclev - Pointer to an integer for returning the number of levels.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::CLevels(ComBool fEndPoint, int * pclev)
{
BEGIN_COM_METHOD;
ChkComOutPtr(pclev);
END_COM_METHOD(g_fact, IID_IVwSelection);
}
/*----------------------------------------------------------------------------------------------
Returns info about level ilev. Level 0 returns the same hvoObj and ptag as
TextSelInfo. Level 1 is the object/prop that contains hvoObj[0].
Level 2 is the object/prop that contains hvoObj[1]. And so forth.
The ihvo returned for level n is the zero-based index of hvoObj[n-1] in prop
tag[n] of hvoObj[n]. It is always 0 for level 0.
The pcpropPrevious argument is sometimes useful in the rare cases where,
within a display of a certain object, the same property is displayed more
than once. For example, within the display of a book, we might display the
sections once using a view that shows titles to produce a table of contents,
then again to produce the main body of the book. cpropPrevious indicates
how many previous occurrences of property tag there are in the display of hvoObj,
before the one which contains the indicated end point.
@param fEndPoint - true for end point, false for anchor.
@param ilev - level for which information is desired.
@param phvoObj
@param ptag
@param pihvo
@param pcpropPrevious
@param ppvps
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::PropInfo(ComBool fEndPoint, int ilev, HVO * phvoObj, PropTag * ptag,
int * pihvo, int * pcpropPrevious, IVwPropertyStore ** ppvps)
{
Assert(false);
return E_NOTIMPL;
}
/*----------------------------------------------------------------------------------------------
Return true if anchor is at the bottom/right (or left if RtoL) of the selection
@param pfRet - pointer to return value through.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::get_EndBeforeAnchor(ComBool * pfRet)
{
BEGIN_COM_METHOD;
ChkComArgPtr(pfRet);
// TODO: Someone should try to determine if any meaningful implementation can be devised.
// If not, we might want to return E_NOTIMPL. For now, let's just take a chance on lying,
// and guess that most of the time the end will be after the anchor.
*pfRet = false;
END_COM_METHOD(g_fact, IID_IVwSelection);
}
/*----------------------------------------------------------------------------------------------
Given the same first three arguments as used to draw the root, indicate where the
selection is drawn. prdPrimary will be set to a rectangle in destination coords
the bounds the selection as closely as possible; if there is a split cursor,
prdSecondary gives the place where the secondary is drawn, and pfSplit is true.
@param pvg - pointer to the IVwGraphics object for actually drawing or measuring things.
@param rcSrc
@param rcDst
@param prdPrimary
@param prdSecondary
@param pfSplit
@param pfEndBeforeAnchor
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::Location(IVwGraphics * pvg, RECT rcSrc, RECT rcDst, RECT * prdPrimary,
RECT * prdSecondary, ComBool * pfSplit, ComBool * pfEndBeforeAnchor)
{
Assert(false);
return E_NOTIMPL;
}
/*----------------------------------------------------------------------------------------------
Move the insertion point up one graphical page.
@param pvg - pointer to the IVwGraphics object for actually drawing or measuring things.
----------------------------------------------------------------------------------------------*/
void VwSelection::PageUpKey(IVwGraphics * pvg)
{
AssertPtr(pvg);
LoseSelection(true);
DoPageUpDown(pvg, true/*is page up*/, false/*is selection*/);
}
/*----------------------------------------------------------------------------------------------
Move the insertion point down one graphical page.
@param pvg - pointer to the IVwGraphics object for actually drawing or measuring things.
----------------------------------------------------------------------------------------------*/
void VwSelection::PageDownKey(IVwGraphics * pvg)
{
AssertPtr(pvg);
LoseSelection(false);
DoPageUpDown(pvg, false/*is page up*/, false/*is selection*/);
}
/*----------------------------------------------------------------------------------------------
Extend the selection up one graphical page.
@param pvg - pointer to the IVwGraphics object for actually drawing or measuring things.
----------------------------------------------------------------------------------------------*/
void VwSelection::ShiftPageUpKey(IVwGraphics * pvg)
{
AssertPtr(pvg);
DoPageUpDown(pvg, true/*is page up*/, true/*is selection*/);
}
/*----------------------------------------------------------------------------------------------
Extend the selection down one graphical page.
@param pvg - pointer to the IVwGraphics object for actually drawing or measuring things.
----------------------------------------------------------------------------------------------*/
void VwSelection::ShiftPageDownKey(IVwGraphics * pvg)
{
AssertPtr(pvg);
DoPageUpDown(pvg, false/*is page up*/, true/*is selection*/);
}
/*----------------------------------------------------------------------------------------------
Move the insertion point to the top of the graphical page.
@param pvg - pointer to the IVwGraphics object for actually drawing or measuring things.
----------------------------------------------------------------------------------------------*/
void VwSelection::ControlPageUpKey(IVwGraphics * pvg)
{
AssertPtr(pvg);
LoseSelection(true);
DoPageUpDown(pvg, true/*is page up*/, false/*is selection*/);
}
/*----------------------------------------------------------------------------------------------
Move the insertion point to the bottom of the graphical page.
@param pvg - pointer to the IVwGraphics object for actually drawing or measuring things.
@param rcDocumentCoord
@param rcClientCoord
----------------------------------------------------------------------------------------------*/
void VwSelection::ControlPageDownKey(IVwGraphics * pvg, Rect rcDocumentCoord, Rect rcClientCoord)
{
AssertPtr(pvg);
LoseSelection(false);
DoCtrlPageUpDown(pvg, rcDocumentCoord, rcClientCoord, false/*is page up*/, false/*is selection*/);
}
/*----------------------------------------------------------------------------------------------
Extend the selection to the top of the graphical page.
@param pvg - pointer to the IVwGraphics object for actually drawing or measuring things.
@param rcDocumentCoord
@param rcClientCoord
----------------------------------------------------------------------------------------------*/
void VwSelection::ControlShiftPageUpKey(IVwGraphics * pvg, Rect rcDocumentCoord, Rect rcClientCoord)
{
AssertPtr(pvg);
DoCtrlPageUpDown(pvg, rcDocumentCoord, rcClientCoord, true/*is page up*/, true/*is selection*/);
}
/*----------------------------------------------------------------------------------------------
Extend the selection to the bottom of the graphical page.
@param pvg - pointer to the IVwGraphics object for actually drawing or measuring things.
@param rcDocumentCoord
@param rcClientCoord
----------------------------------------------------------------------------------------------*/
void VwSelection::ControlShiftPageDownKey(IVwGraphics * pvg, Rect rcDocumentCoord, Rect rcClientCoord)
{
AssertPtr(pvg);
DoCtrlPageUpDown(pvg, rcDocumentCoord, rcClientCoord, false/*is page up*/, true/*is selection*/);
}
/*----------------------------------------------------------------------------------------------
Move the insertion point up (or down if not fIsPageUp) one graphical page.
@param pvg - pointer to the IVwGraphics object for actually drawing or measuring things.
@param fIsPageUp - true to handle page up, false to handle page down
@param fIsExtendSelection - true when shift key was pressed (extend selection)
----------------------------------------------------------------------------------------------*/
void VwSelection::DoPageUpDown(IVwGraphics * pvg, bool fIsPageUp, bool fIsExtendedSelection)
{
AssertPtr(pvg);
Rect rcSrc, rcDest;
IVwGraphics * pvgTmp;
m_qrootb->Site()->GetGraphics(m_qrootb, &pvgTmp, &rcSrc, &rcDest);
m_qrootb->Site()->ReleaseGraphics(m_qrootb, pvgTmp);
// The amount to move is the visible page height
// (The standard behavior of Word and other apps is to move an entire page and leave the IP
// at the same position on the screen)
COMINT32 lPageHeight = VisiblePageHeight(pvg, rcSrc, rcDest);
// going up subtract, going down add
if(fIsPageUp)
lPageHeight *= -1;
MoveIpVerticalByAmount(pvg, lPageHeight, false, fIsExtendedSelection);
}
/*----------------------------------------------------------------------------------------------
Move the selection vertically by the specified number of pixels.
If we have a range selection:
If moving up, then move from the top of the selection.
If moving down, then move from the bottom of the selection.
@param lYAdjustment The amount to move the ip
----------------------------------------------------------------------------------------------*/
void VwSelection::MoveIpVerticalByAmount(IVwGraphics * pvg, int lYAdjustment, bool fPutSelAtEdge,
bool fIsExtendedSelection)
{
AssertPtr(pvg);
IVwGraphicsWin32 * pvg32;
CheckHr(pvg->QueryInterface(IID_IVwGraphicsWin32, (void **) &pvg32));
AssertPtr(pvg32);
VwRootBox * pRootBox = RootBox();
AssertPtr(pRootBox);
if(!pRootBox)
return;
Rect rcSelection;
ComBool fSplit, fEndBeforeAnchor;
Rect rcSrc, rcDest;
IVwGraphics * pvgTmp;
m_qrootb->Site()->GetGraphics(m_qrootb, &pvgTmp, &rcSrc, &rcDest);
// convert adjustment to units for the current view
int viewUnitsPerInch;
CheckHr(pvgTmp->get_YUnitsPerInch(&viewUnitsPerInch));
int screenUnitsPerInch;
CheckHr(pvg->get_YUnitsPerInch(&screenUnitsPerInch));
lYAdjustment *= viewUnitsPerInch / screenUnitsPerInch;
m_qrootb->Site()->ReleaseGraphics(m_qrootb, pvgTmp);
int rootbHeight;
CheckHr(pRootBox->get_Height(&rootbHeight));
ComBool fRange;
CheckHr(get_IsRange(&fRange));
Point newPos;
int originalY = 0;
if (!fRange)
{
Rect rcSecondary;
CheckHr(Location(pvg, rcSrc, rcDest, &rcSelection, &rcSecondary, &fSplit, &fEndBeforeAnchor));
originalY = rcSelection.top + (rcSelection.Height() /2);
newPos.x = rcSelection.left + rcSelection.Width() / 2;
}
else
{
Rect rcSelTop, rcSelBottom, rcIgnored;
IVwSelectionPtr qVwSelAnchor;
IVwSelectionPtr qVwSelEnd;
CheckHr(EndPoint(false, &qVwSelAnchor));
CheckHr(qVwSelAnchor->Location(pvg, rcSrc, rcDest, &rcSelTop, &rcIgnored, &fSplit,
&fEndBeforeAnchor));
CheckHr(EndPoint(true, &qVwSelEnd));
CheckHr(qVwSelEnd->Location(pvg, rcSrc, rcDest, &rcSelBottom, &rcIgnored, &fSplit,
&fEndBeforeAnchor));
if (fEndBeforeAnchor)
{
Rect tmp = rcSelTop;
rcSelTop = rcSelBottom;
rcSelBottom = tmp;
}
Rect bounds = pRootBox->GetBoundsRect(pvg, rcSrc, rcDest);
rcSelection = Rect(bounds.left, rcSelTop.top, bounds.right, rcSelBottom.bottom);
// If we have a range selection, then make the proper adjustments
originalY = rcSelBottom.bottom - AdjustEndLocation(pvg, rcSrc, rcDest);
if (fPutSelAtEdge)
newPos.x = (lYAdjustment > 0 ? rcSelection.left : rcSelection.right);
else
newPos.x = rcSelBottom.left;
}
newPos.y = originalY + lYAdjustment;
if(newPos.y <= rcDest.top || newPos.y > rcDest.top + rootbHeight)
{
newPos.y = max<LONG>(newPos.y, static_cast<int>(rcDest.top));
newPos.y = min<LONG>(newPos.y, static_cast<int>(rcDest.top + rootbHeight));
newPos.x = (fEndBeforeAnchor? rcSelection.left : rcSelection.right);
}
// OK, we need to move by dy (newPos.y - originalY). But, we may have to expand a
// lazy box there in order to display a whole screen full.
// Make the same PrepareToDraw call that the rendering code will make
// so that our mouseDown event will be valid
Rect clipRect;
CheckHr(pvg->GetClipRect((int*)&clipRect.left, (int*)&clipRect.top, (int*)&clipRect.right,
(int*)&clipRect.bottom));
clipRect.Offset(0, lYAdjustment);
CheckHr(pvg32->SetClipRect(&clipRect));
VwPrepDrawResult pdr;
CheckHr(pRootBox->PrepareToDraw(pvg, rcSrc, rcDest, &pdr));
if(fIsExtendedSelection)
CheckHr(pRootBox->MouseDownExtended(newPos.x, newPos.y, rcSrc, rcDest));
else
CheckHr(pRootBox->MouseDown(newPos.x, newPos.y, rcSrc, rcDest));
pRootBox->NotifySelChange(ksctDiffPara);
}
/*----------------------------------------------------------------------------------------------
Move the insertion point to the top or bottom of the graphical page.
@param pvg - pointer to the IVwGraphics object for actually drawing or measuring things.
@param rcDocumentCoord
@param rcClientCoord
@param fIsPageUp - true to handle page up, false to handle page down
@param fIsExtendSelection - true when shift key was pressed (extend selection)
----------------------------------------------------------------------------------------------*/
void VwSelection::DoCtrlPageUpDown(IVwGraphics * pvg, Rect rcDocumentCoord, Rect rcClientCoord,
bool fIsPageUp, bool fIsExtendedSelection)
{
// Ignore the ctrl for now: see following note
return DoPageUpDown(pvg, fIsPageUp, fIsExtendedSelection);
// The following code would work if the rcClientCoord, rcDocumentCoord transformation included
// the shift information (by how much has the client scrolled the document
// this information is not available to us though from a key press at this time.
// We leave the following code in hopes that someday that information will be accessible and
// easily hooked up.
AssertPtr(pvg);
VwRootBox * pRootBox = RootBox();
AssertPtr(pRootBox);
if(!pRootBox){
return;
}
IVwRootSite * pVwRootSite = pRootBox->Site();
Assert(pVwRootSite);
if(!pVwRootSite){
return;
}
// we need the height of our window to know how much to scroll by
HWND hwndRootSite;
CheckHr(pVwRootSite->get_Hwnd(reinterpret_cast<DWORD *>(&hwndRootSite)));
Assert(hwndRootSite);
Rect rcRootSite;
#if defined(WIN32) || defined(WIN64)
if(!GetClientRect(hwndRootSite, &rcRootSite)){
Assert(false); // we better have a valid HWND at this point! That's the only reason GetClientRect should fail that we could think of.
return;
}
#else
ComSmartPtr<IVwWindow> qhwndWrapper;
qhwndWrapper.CreateInstance(CLSID_VwWindow);
CheckHr(qhwndWrapper->put_Window(reinterpret_cast<DWORD *>(hwndRootSite)));
CheckHr(qhwndWrapper->GetClientRectangle(&rcRootSite));
#endif
// rcRootSite is in client coordinates. Map rcRootSite from client coordinates to document coordinates
// rcRootSite.Map(rcClientCoord, rcDocumentCoord);
int newX, newY;
if(fIsPageUp){
newX = rcRootSite.left;
newY = rcRootSite.top;
}
else{
newX = rcRootSite.right;
newY = rcRootSite.bottom;
}
if(!fIsExtendedSelection) {
CheckHr(pRootBox->MouseDown(newX, newY, rcDocumentCoord, rcClientCoord));
}
else {
CheckHr(pRootBox->MouseDownExtended(newX, newY, rcDocumentCoord, rcClientCoord));
}
pRootBox->NotifySelChange(ksctDiffPara);
}
/*----------------------------------------------------------------------------------------------
Returns the height of a page in document coordinates or 0 if unable to determine.
@param pvg - pointer to the IVwGraphics object for actually drawing or measuring things.
@param rcDocumentCoord
@param rcClientCoord
----------------------------------------------------------------------------------------------*/
COMINT32 VwSelection::VisiblePageHeight(IVwGraphics * pvg, Rect rcDocumentCoord, Rect rcClientCoord)
{
AssertPtr(pvg);
VwRootBox * pRootBox = RootBox();
AssertPtr(pRootBox);
if(!pRootBox){
return 0;
}
IVwRootSite * pVwRootSite = pRootBox->Site();
Assert(pVwRootSite);
if(!pVwRootSite){
return 0;
}
// we need the height of our window to know how much to scroll by
HWND hwndRootSite;
CheckHr(pVwRootSite->get_Hwnd(reinterpret_cast<DWORD *>(&hwndRootSite)));
Assert(hwndRootSite);
Rect rcRootSite;
#if defined(WIN32) || defined(WIN64)
if(!GetClientRect(hwndRootSite, &rcRootSite)){
Assert(false); // we better have a valid HWND at this point! That's the only reason GetClientRect should fail that we could think of.
return 0;
}
#else
ComSmartPtr<IVwWindow> qhwndWrapper;
qhwndWrapper.CreateInstance(CLSID_VwWindow);
CheckHr(qhwndWrapper->put_Window(reinterpret_cast<DWORD *>(hwndRootSite)));
CheckHr(qhwndWrapper->GetClientRectangle(&rcRootSite));
#endif
// rcRootSite is in client coordinates. Map rcRootSite from client coordinates to document coordinates
//rcRootSite.Map(rcClientCoord, rcDocumentCoord);
return rcRootSite.Height();
}
/*----------------------------------------------------------------------------------------------
If the selection is part of one or more paragraphs, return a rectangle that
contains those paragraphs. Otherwise fail.
@param prdLoc
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::GetParaLocation(RECT * prdLoc)
{
return E_NOTIMPL;
}
/*----------------------------------------------------------------------------------------------
Replace what is selected with a TsString.
If the string contains newlines, the properties associated with the Newline become
the paragraph properties, if it is possible to make new paragraphs at the current
selection. Otherwise, newlines are stripped out.
@param ptss
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::ReplaceWithTsString(ITsString * ptss)
{
return E_NOTIMPL;
}
/*----------------------------------------------------------------------------------------------
Return what is selected as a TsString.
@param pptss
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::GetSelectionString(ITsString ** pptss, BSTR bstr)
{
return E_NOTIMPL;
}
/*----------------------------------------------------------------------------------------------
Return first para of what is selected as a TsString.
@param pptss
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::GetFirstParaString(ITsString ** pptss, BSTR bstr,
ComBool * pfGotItAll)
{
return E_NOTIMPL;
}
/*----------------------------------------------------------------------------------------------
Move the selection to the indicated location if it is an insertion point.
@param fTopLine
@param xdPos
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::SetIPLocation(ComBool fTopLine, int xdPos)
{
return E_NOTIMPL;
}
/*----------------------------------------------------------------------------------------------
Return true if we can apply paragraph formatting on the current selection.
@param pfRet - pointer to return value through.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::get_CanFormatPara(ComBool * pfRet)
{
return E_NOTIMPL;
}
/*----------------------------------------------------------------------------------------------
Return true if we can apply character formatting on the current selection. This is only
possible for text selections, so by default answer false.
@param pfRet - pointer to return value through.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::get_CanFormatChar(ComBool * pfRet)
{
BEGIN_COM_METHOD;
ChkComArgPtr(pfRet);
*pfRet = false;
END_COM_METHOD(g_fact, IID_IVwSelection);
}
/*----------------------------------------------------------------------------------------------
Return true if we can apply overlay tags on the current selection. This is only possible
for text selections, so by default answer false.
@param pfRet - pointer to return value through.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::get_CanFormatOverlay(ComBool * pfRet)
{
BEGIN_COM_METHOD;
ChkComArgPtr(pfRet);
*pfRet = false;
END_COM_METHOD(g_fact, IID_IVwSelection);
}
/*----------------------------------------------------------------------------------------------
Install *this as the active selection.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::Install()
{
return E_NOTIMPL;
}
/*----------------------------------------------------------------------------------------------
Answer true if this selection follows (comes after in the view) the argument.
False if they are exactly the same position.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::get_Follows(IVwSelection * psel, ComBool * pfFollows)
{
Assert(false);
return E_NOTIMPL;
}
/*----------------------------------------------------------------------------------------------
Like GetSelectionProps, except that the returned property stores contain the formatting
for the selection MINUS the hard-formatting that is in the TsTextProps.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::GetHardAndSoftCharProps(
int cttpMax, ITsTextProps ** prgpttpSel,
IVwPropertyStore ** prgpvpsSoft, int * pcttp)
{
return E_NOTIMPL;
}
/*----------------------------------------------------------------------------------------------
Like GetParaProps, except that the returned property stores contain the formatting
for the selection MINUS the hard-formatting that is in the TsTextProps.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwSelection::GetHardAndSoftParaProps(int cttpMax, ITsTextProps ** prgpttpPara,
ITsTextProps ** prgpttpHard, IVwPropertyStore ** prgpvpsSoft, int * pcttp)
{
return E_NOTIMPL;
}
//:>********************************************************************************************
//:> Other VwSelection methods
//:>********************************************************************************************
/*----------------------------------------------------------------------------------------------
Ensure turned on, unless disabled. This is typically used after moving the selection,
or after changing the boxes following some edit. It is currently implemented by invalidating
the area where the selection is visible. If you go back to really drawing it, make sure
that selections that span pages in print layout views keep working.
@param pvg - pointer to the IVwGraphics object for actually drawing or measuring things.
@param rcSrcRoot
@param rcDstRoot
----------------------------------------------------------------------------------------------*/
void VwSelection::Show()
{
if (m_fShowing)
return;
if (!IsEnabled())
return;
m_fShowing = true;
InvalidateSel();
}
/*----------------------------------------------------------------------------------------------
Really draw the selection, subject to current flags that control whether it is visible.
Currently used only when NOT double-buffering (which is currently never true). Untested.
----------------------------------------------------------------------------------------------*/
void VwSelection::ReallyShow(IVwGraphics * pvg, Rect rcSrcRoot, Rect rcDstRoot)
{
//StrAppBuf strb;
//strb.Format("Show:%d m_fShowing:%d SelectionState:%d\n", this, m_fShowing,
// SelectionState());
//OutputDebugString(strb.Chars());
if (m_fShowing)
return;
if (!IsEnabled())
return;
m_fShowing = true;
// we might have to pass in real values instead of -1, INT_MAX if this is really used
Draw(pvg, true, rcSrcRoot, rcDstRoot, -1, INT_MAX);
}
/*----------------------------------------------------------------------------------------------
Draw the selection if it is enabled. This is used with double buffering, when we have
drawn the underlying stuff on the off-screen bitmap. In that bitmap, the selection is
not showing, even if m_fShowing indicates that it is on the screen itself. Thus, we
draw the selection exactly if it IS showing on the screen, so that what is in the bitmap
winds up matching.
@param pvg - pointer to the IVwGraphics object for actually drawing or measuring things.
@param rcSrcRoot
@param rcDstRoot
----------------------------------------------------------------------------------------------*/
void VwSelection::DrawIfShowing(IVwGraphics * pvg, Rect rcSrcRoot, Rect rcDstRoot,
int ysTop, int dysHeight, bool fDisplayPartialLines)
{
if (!m_fShowing)
return;
if (!IsEnabled())
return;
Draw(pvg, true, rcSrcRoot, rcDstRoot, ysTop, dysHeight, fDisplayPartialLines);
}
/*----------------------------------------------------------------------------------------------
Ensure turned off
@param pvg - pointer to the IVwGraphics object for actually drawing or measuring things.
@param rcSrcRoot
@param rcDstRoot
----------------------------------------------------------------------------------------------*/
void VwSelection::Hide()
{
if (!m_fShowing)
return;
m_fShowing = false;
InvalidateSel();
}
/*----------------------------------------------------------------------------------------------
Toggle on/off, unless disabled
@param pvg - pointer to the IVwGraphics object for actually drawing or measuring things.
@param rcSrcRoot
@param rcDstRoot
----------------------------------------------------------------------------------------------*/
void VwSelection::Invert()
{
if (!IsEnabled())
return;
m_fShowing = !m_fShowing;
InvalidateSel();
}
/*----------------------------------------------------------------------------------------------
Invalidate area(s) containing the selection, forcing them to be painted. This currently
implements hide, show, and invert.
----------------------------------------------------------------------------------------------*/
void VwSelection::InvalidateSel()
{
VwRootBox * prootb = RootBox();
Point dpiSrc = prootb->DpiSrc();
// Using this rectangle as both source and destination causes no transformation at all
// from the root layout coordinates...which is exactly what we want to pass to invalidate.
HoldScreenGraphics hg(prootb);
int dpiX, dpiY;
CheckHr(hg.m_qvg->get_XUnitsPerInch(&dpiX));
CheckHr(hg.m_qvg->get_YUnitsPerInch(&dpiY));
Rect rcSrcRoot(0, 0, dpiSrc.x, dpiSrc.y);
Rect rcDstRoot(0, 0, dpiX, dpiY);
Rect rdPrimary;
Rect rdSecondary;
ComBool fSplit;
ComBool fEndBeforeAnchor;
// Get the rectangle(s) bounding the selection.
CheckHr(Location(hg.m_qvg, rcSrcRoot, rcDstRoot, &rdPrimary, &rdSecondary, &fSplit,
&fEndBeforeAnchor));
IVwRootSite * pvrs = prootb->Site();
// Invalidate them.
rdPrimary.Map(rcDstRoot, rcSrcRoot); // reverse transformation to src coords.
// Fudge a little, since PositionsOfIP is not guaranteed to give an exact result.
// Note: these fudge values cause clipping rectangle to be too large for lineheight
// causing FWNX-456, and extra width not needed for linux either
#if defined(WIN32) || defined(WIN64)
rdPrimary.left -= 3;
rdPrimary.right += 3;
rdPrimary.top -= 3;
rdPrimary.bottom += 3;
#endif
CheckHr(pvrs->InvalidateRect(prootb, rdPrimary.left, rdPrimary.top, rdPrimary.Width(),
rdPrimary.Height()));
if (fSplit && !rdSecondary.IsEmpty())
{
#if defined(WIN32) || defined(WIN64)
rdSecondary.left -= 3;
rdSecondary.right += 3;
rdSecondary.top -= 3;
rdSecondary.bottom += 3;
#endif
rdSecondary.Map(rcDstRoot, rcSrcRoot); // reverse transformation to src coords.
CheckHr(pvrs->InvalidateRect(prootb, rdSecondary.left, rdSecondary.top, rdSecondary.Width(),
rdSecondary.Height()));
}
}
/*----------------------------------------------------------------------------------------------
Check whether the given insertion point is at an editable location. This method must be
overridden by subclasses.
@param ichIP - Proposed insertion point for a new selection.
@param pvpBoxIP - Points to the paragraph of the proposed insertion point.
@param fAssocPrevIP - Flag whether the proposed insertion point associates with the
preceding character in the paragraph.
@return True if the proposed selection is editable, otherwise false.
----------------------------------------------------------------------------------------------*/
bool VwSelection::IsEditable(int ichIP, VwParagraphBox * pvpBoxIP, bool fAssocPrevIP)
{
return false;