-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathrvscroll.pas
366 lines (355 loc) · 10.6 KB
/
rvscroll.pas
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
unit RVScroll;
interface
uses
{$IFDEF FPC}
RVLazIntf, LCLType, LCLIntf,
{$ELSE}
Windows, Messages,
{$ENDIF}
SysUtils, Classes, Forms, Controls, Graphics;
type
{ TRVScroller }
TRVScroller = class(TCustomControl)
private
FTracking: Boolean;
FFullRedraw: Boolean;
FVScrollVisible: Boolean;
FOnVScrolled: TNotifyEvent;
function GetVScrollPos(): Integer;
procedure SetVScrollPos(Pos: Integer);
function GetVScrollMax(): Integer;
procedure SetVScrollVisible(vis: Boolean);
protected
SmallStep: Integer;
HPos: Integer;
VPos: Integer;
XSize: Integer;
YSize: Integer;
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd(); override;
procedure UpdateScrollBars(XS, YS: Integer);
procedure WMHScroll(var Message: TWMHScroll); message WM_HSCROLL;
procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
procedure SetVPos(p: Integer);
procedure SetHPos(p: Integer);
procedure Paint(); override;
procedure ScrollChildren(dx, dy: Integer);
procedure UpdateChildren();
property FullRedraw: Boolean read FFullRedraw write FFullRedraw;
protected // to be publised properties
property Visible;
property TabStop;
property TabOrder;
property Align;
property HelpContext;
{ Determines whether the control will scroll when the scroll bar thumb tab
is being dragged or will wait for the tab to be dropped. Default value = True. }
property Tracking: Boolean read FTracking write FTracking;
{ Hides or shows vertical scrollbar.
If False then vertical scrollbar never appears.
If True then vertical scrollbar appears when it needed.
Horizontal scrollbar appears only if you insert pictures or components wider
than width of TRichView component, or if you set large MinTextWidth property. }
property VScrollVisible: Boolean read FVScrollVisible write SetVScrollVisible;
property OnVScrolled: TNotifyEvent read FOnVScrolled write FOnVScrolled;
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
{$ifdef FPC}procedure EraseBackground(DC: HDC); override;{$endif}
{ Scrolls TRichView control to vertical coordinate = y pixels from the top of scrolled area.
So RichView1.ScrollTo(0) scrolls to the top of document.
You can use this method with methods GetCheckPointY and GetJumpPointY.
Note: method ScrollTo does not scroll exactly to specified coordinate,
but can scroll slightly highter }
procedure ScrollTo(y: Integer);
{ Vertical scrolling position, from 0 to VScrollMax inclusively.
Measured in 'my scrolling units' (MSU). By default 1 MSU = 10 pixels. }
property VScrollPos: Integer read GetVScrollPos write SetVScrollPos;
{ Maximum value of VScrollPos property }
property VScrollMax: Integer read GetVScrollMax;
end;
procedure Tag2Y(AControl: TControl);
implementation
{------------------------------------------------------}
procedure Tag2Y(AControl: TControl);
begin
if AControl.Tag > 10000 then
AControl.Top := 10000
else
begin
if AControl.Tag < -10000 then
AControl.Top := -10000
else
AControl.Top := AControl.Tag;
end;
end;
{------------------------------------------------------}
constructor TRVScroller.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
TabStop := True;
FTracking := True;
FFullRedraw := False;
FVScrollVisible := False;
end;
{$ifdef FPC}
procedure TRVScroller.EraseBackground(DC: HDC);
begin
end;
{$endif}
{------------------------------------------------------}
procedure TRVScroller.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params); //CreateWindow
Params.Style := Params.Style or WS_CLIPCHILDREN or WS_HSCROLL or WS_VSCROLL;
end;
{------------------------------------------------------}
procedure TRVScroller.CreateWnd;
begin
inherited CreateWnd;
SmallStep := 10;
VPos := 0;
HPos := 0;
UpdateScrollBars(ClientWidth, (ClientHeight div SmallStep));
end;
{------------------------------------------------------}
procedure TRVScroller.UpdateScrollBars(XS, YS: Integer);
var
ScrollInfo: TScrollInfo;
begin
XSize := XS;
YSize := YS;
ScrollInfo.cbSize := SizeOf(ScrollInfo);
ScrollInfo.fMask := SIF_ALL;
ScrollInfo.nMin := 0;
if SmallStep = 0 then SmallStep := 1;
ScrollInfo.nPage := ClientHeight div SmallStep;
ScrollInfo.nMax := YSize;
ScrollInfo.nPos := VPos;
ScrollInfo.nTrackPos := 0;
SetScrollInfo(Handle, SB_VERT, ScrollInfo, True);
if not FVScrollVisible then
ShowScrollBar(Handle, SB_VERT, FVScrollVisible);
ScrollInfo.fMask := SIF_ALL;
ScrollInfo.nMin := 0;
ScrollInfo.nMax := XSize-1;
ScrollInfo.nPage := ClientWidth;
ScrollInfo.nPos := VPos;
ScrollInfo.nTrackPos := 0;
SetScrollInfo(Handle, SB_HORZ, ScrollInfo, True);
//UpdateChildren;
end;
{------------------------------------------------------}
procedure TRVScroller.UpdateChildren();
var
i: Integer;
begin
for i := 0 to ControlCount-1 do
Tag2Y(Controls[i]);
end;
{------------------------------------------------------}
procedure TRVScroller.ScrollChildren(dx, dy: Integer);
var
i: Integer;
begin
if (dx = 0) and (dy = 0) then
Exit;
for i := 0 to ControlCount-1 do
begin
if dy <> 0 then
begin
Controls[i].Tag := Controls[i].Tag + dy;
Tag2Y(Controls[i]);
end;
if dx <> 0 then
Controls[i].Left := Controls[i].Left + dx;
end
end;
{------------------------------------------------------}
procedure TRVScroller.WMHScroll(var Message: TWMHScroll);
begin
case Message.ScrollCode of
SB_LINEUP: SetHPos(HPos - SmallStep);
SB_LINEDOWN: SetHPos(HPos + SmallStep);
SB_PAGEUP: SetHPos(HPos-10 * SmallStep);
SB_PAGEDOWN: SetHPos(HPos + 10 * SmallStep);
SB_THUMBPOSITION: SetHPos(Message.Pos);
SB_THUMBTRACK: if FTracking then SetHPos(Message.Pos);
SB_TOP: SetHPos(0);
SB_BOTTOM: SetHPos(XSize);
end;
end;
{------------------------------------------------------}
procedure TRVScroller.WMVScroll(var Message: TWMVScroll);
begin
case Message.ScrollCode of
SB_LINEUP: SetVPos(VPos - 1);
SB_LINEDOWN: SetVPos(VPos + 1);
SB_PAGEUP: SetVPos(VPos-10);
SB_PAGEDOWN: SetVPos(VPos+10);
SB_THUMBPOSITION: SetVPos(Message.Pos);
SB_THUMBTRACK: if FTracking then SetVPos(Message.Pos);
SB_TOP: SetVPos(0);
SB_BOTTOM: SetVPos(YSize);
end;
end;
{------------------------------------------------------}
procedure TRVScroller.WMKeyDown(var Message: TWMKeyDown);
var
vScrollNotify, hScrollNotify: Integer;
begin
vScrollNotify := -1;
hScrollNotify := -1;
case Message.CharCode of
VK_UP:
vScrollNotify := SB_LINEUP;
VK_PRIOR:
vScrollNotify := SB_PAGEUP;
VK_NEXT:
vScrollNotify := SB_PAGEDOWN;
VK_DOWN:
vScrollNotify := SB_LINEDOWN;
VK_HOME:
vScrollNotify := SB_TOP;
VK_END:
vScrollNotify := SB_BOTTOM;
VK_LEFT:
hScrollNotify := SB_LINELEFT;
VK_RIGHT:
hScrollNotify := SB_LINERIGHT;
end;
if (vScrollNotify <> -1) then
Perform(WM_VSCROLL, vScrollNotify, 0);
if (hScrollNotify <> -1) then
Perform(WM_HSCROLL, hScrollNotify, 0);
{$IFDEF FPC}
inherited WMKeyDown(Message);
{$ELSE}
inherited;
{$ENDIF}
end;
{------------------------------------------------------}
procedure TRVScroller.SetVPos(p: Integer);
var
ScrollInfo: TScrollInfo;
oldPos: Integer;
r: TRect;
begin
OldPos := VPos;
VPos := p;
ScrollInfo.cbSize := SizeOf(ScrollInfo);
ScrollInfo.nPos := VPos;
ScrollInfo.fMask := SIF_POS;
SetScrollInfo(Handle, SB_VERT, ScrollInfo, True);
GetScrollInfo(Handle, SB_VERT, ScrollInfo);
VPos := ScrollInfo.nPos;
r := ClientRect;
if OldPos - VPos <> 0 then
begin
if FFullRedraw then
begin
ScrollChildren(0, (OldPos - VPos) * SmallStep);
Refresh();
end
else
begin
{$IFDEF MSWINDOWS}
ScrollWindowEx(Handle, 0, (OldPos - VPos) * SmallStep, nil, @r, 0, nil, SW_INVALIDATE {or
SW_SCROLLCHILDREN});
{$ELSE}
Invalidate;
{$ENDIF}
ScrollChildren(0, (OldPos - VPos) * SmallStep);
end;
if Assigned(FOnVScrolled) then FOnVScrolled(Self);
end;
end;
{------------------------------------------------------}
procedure TRVScroller.SetHPos(p: Integer);
var
ScrollInfo: TScrollInfo;
oldPos: Integer;
r: TRect;
begin
OldPos := HPos;
HPos := p;
ScrollInfo.cbSize := SizeOf(ScrollInfo);
ScrollInfo.nPos := HPos;
ScrollInfo.fMask := SIF_POS;
SetScrollInfo(Handle, SB_HORZ, ScrollInfo, True);
GetScrollInfo(Handle, SB_HORZ, ScrollInfo);
HPos := ScrollInfo.nPos;
r := ClientRect;
if OldPos - HPos <> 0 then
begin
if FFullRedraw then
begin
ScrollChildren((OldPos - HPos), 0);
Refresh;
end
else
begin
ScrollWindowEx(Handle, (OldPos - HPos), 0, nil, @r, 0, nil, SW_INVALIDATE{or
SW_SCROLLCHILDREN});
ScrollChildren((OldPos - HPos), 0);
end;
end;
end;
{------------------------------------------------------}
procedure TRVScroller.Paint();
var
i: Integer;
begin
Canvas.Font.Color := clRed;
Canvas.Font.Size := 2;
Canvas.FillRect(Canvas.ClipRect);
if SmallStep = 0 then
SmallStep := 1;
for i := (Canvas.ClipRect.Top div SmallStep) - 1 to (Canvas.ClipRect.Bottom div SmallStep) + 1 do
Canvas.TextOut(-HPos, i * SmallStep, IntToStr(i + VPos));
end;
{------------------------------------------------------}
procedure TRVScroller.ScrollTo(y: Integer);
begin
if SmallStep = 0 then
SmallStep := 1;
SetVPos(y div SmallStep);
end;
{-------------------------------------------------------}
function TRVScroller.GetVScrollPos: Integer;
begin
GetVScrollPos := VPos;
end;
{-------------------------------------------------------}
procedure TRVScroller.SetVScrollPos(Pos: Integer);
begin
SetVPos(Pos);
end;
{-------------------------------------------------------}
function TRVScroller.GetVScrollMax(): Integer;
var
ScrollInfo: TScrollInfo;
begin
ScrollInfo.cbSize := SizeOf(ScrollInfo);
ScrollInfo.nPos := HPos;
ScrollInfo.fMask := SIF_RANGE or SIF_PAGE;
GetScrollInfo(Handle, SB_VERT, ScrollInfo);
GetVScrollMax := ScrollInfo.nMax - Integer(ScrollInfo.nPage-1);
end;
{-------------------------------------------------------}
procedure TRVScroller.SetVScrollVisible(vis: Boolean);
begin
FVScrollVisible := vis;
if HandleAllocated() then
begin;
ShowScrollBar(Handle, SB_VERT, vis);
end;
end;
{-------------------------------------------------------}
procedure TRVScroller.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
Message.Result := DLGC_WANTARROWS;
end;
end.