1
|
#include "CtrlLib.h"
|
2
|
|
3
|
NAMESPACE_UPP
|
4
|
|
5
|
#define LLOG(x)
|
6
|
|
7
|
Rect RichTextView::GetPage() const
|
8
|
{
|
9
|
return Rect(0, 0, GetPageCx(), INT_MAX);
|
10
|
}
|
11
|
|
12
|
void RichTextView::Paint(Draw& w)
|
13
|
{
|
14
|
Size sz = GetSize();
|
15
|
w.DrawRect(sz, background);
|
16
|
sz.cx -= margin.left + margin.right;
|
17
|
sz.cy -= margin.top + margin.bottom;
|
18
|
w.Clipoff(margin.left, margin.top, sz.cx, sz.cy);
|
19
|
PaintInfo pi;
|
20
|
if(!hldec)
|
21
|
pi.hyperlink = Null;
|
22
|
if(sell < selh) {
|
23
|
pi.sell = sell;
|
24
|
pi.selh = selh;
|
25
|
}
|
26
|
pi.indexentry = Null;
|
27
|
pi.highlightpara = highlight;
|
28
|
pi.zoom = GetZoom();
|
29
|
int q = sb * pi.zoom;
|
30
|
scroller.Set(q);
|
31
|
w.Offset(0, -q);
|
32
|
SimplePageDraw pw(w);
|
33
|
pi.top = PageY(0, sb);
|
34
|
pi.bottom = PageY(0, sb + sz.cy / pi.zoom);
|
35
|
pi.usecache = true;
|
36
|
pi.sizetracking = sizetracking;
|
37
|
pi.shrink_oversized_objects = shrink_oversized_objects;
|
38
|
Color c = SColorPaper();
|
39
|
if(Grayscale(c) < 100)
|
40
|
pi.coloroverride = true;
|
41
|
text.Paint(pw, GetPage(), pi);
|
42
|
w.End();
|
43
|
w.End();
|
44
|
}
|
45
|
|
46
|
Zoom RichTextView::GetZoom() const
|
47
|
{
|
48
|
int szcx = GetSize().cx;
|
49
|
if(!sb.IsShown() && sb.IsAutoHide())
|
50
|
szcx -= ScrollBarSize();
|
51
|
return IsNull(zoom) ? Zoom(szcx - margin.left - margin.right, cx) : zoom;
|
52
|
}
|
53
|
|
54
|
int RichTextView::GetPageCx(bool reduced) const
|
55
|
{
|
56
|
int szcx = GetSize().cx;
|
57
|
if(reduced && !sb.IsShown() && sb.IsAutoHide())
|
58
|
szcx -= ScrollBarSize();
|
59
|
return IsNull(zoom) ? cx : (szcx - margin.left - margin.right) / zoom;
|
60
|
}
|
61
|
|
62
|
void RichTextView::SetSb()
|
63
|
{
|
64
|
Rect page(0, 0, GetPageCx(true), INT_MAX);
|
65
|
PageY py = text.GetHeight(page);
|
66
|
sb.SetTotal(py.y);
|
67
|
sb.SetPage((GetSize().cy - margin.top - margin.bottom) / GetZoom());
|
68
|
}
|
69
|
|
70
|
bool RichTextView::Key(dword key, int count)
|
71
|
{
|
72
|
if(key == K_CTRL_C || key == K_SHIFT_INSERT) {
|
73
|
Copy();
|
74
|
return true;
|
75
|
}
|
76
|
return sb.VertKey(key);
|
77
|
}
|
78
|
|
79
|
void RichTextView::MouseWheel(Point p, int zdelta, dword keyflags)
|
80
|
{
|
81
|
sb.Wheel(zdelta);
|
82
|
}
|
83
|
|
84
|
Image RichTextView::CursorImage(Point p, dword keyflags)
|
85
|
{
|
86
|
int pos = GetPointPos(p);
|
87
|
if(WhenLink && pos >= 0 && !IsNull(GetLink(pos, p)))
|
88
|
return Image::Hand();
|
89
|
if(HasCapture())
|
90
|
return Image::IBeam();
|
91
|
return Image::Arrow();
|
92
|
}
|
93
|
|
94
|
void RichTextView::Copy()
|
95
|
{
|
96
|
if(anchor == cursor)
|
97
|
WriteClipboardUnicodeText(text.GetPlainText());
|
98
|
else {
|
99
|
RefreshSel();
|
100
|
WString h = text.GetPlainText(false).Mid(sell, selh - sell);
|
101
|
WString r;
|
102
|
for(const wchar *s = ~h; s < h.End(); s++) {
|
103
|
if(*s == '\n')
|
104
|
r.Cat('\r');
|
105
|
r.Cat(*s);
|
106
|
}
|
107
|
WriteClipboardUnicodeText(r);
|
108
|
}
|
109
|
}
|
110
|
|
111
|
void RichTextView::RightDown(Point p, dword keyflags)
|
112
|
{
|
113
|
MenuBar b;
|
114
|
b.Add(t_("Copy"), CtrlImg::copy(), THISBACK(Copy)).Key(K_CTRL_C).Enable(cursor != anchor);
|
115
|
b.Execute();
|
116
|
}
|
117
|
|
118
|
int RichTextView::GetPointPos(Point p) const
|
119
|
{
|
120
|
Size sz = GetSize();
|
121
|
sz.cx -= margin.left + margin.right;
|
122
|
sz.cy -= margin.top + margin.bottom;
|
123
|
p -= margin.TopLeft();
|
124
|
Zoom zoom = GetZoom();
|
125
|
p.y += sb * zoom;
|
126
|
return text.GetPos(p.x / zoom, PageY(0, p.y / zoom), GetPage());
|
127
|
}
|
128
|
|
129
|
String RichTextView::GetLink(int pos, Point p) const
|
130
|
{
|
131
|
String link;
|
132
|
RichObject object = text.GetRichPos(pos).object;
|
133
|
if(object) {
|
134
|
Rect rc = text.GetCaret(pos, GetPage());
|
135
|
link = object.GetLink(p - rc.TopLeft(), rc.Size());
|
136
|
}
|
137
|
|
138
|
if(IsNull(link)) {
|
139
|
RichPos richpos = text.GetRichPos(pos);
|
140
|
if(richpos.chr != '\n')
|
141
|
link = Nvl(richpos.fieldformat.link, richpos.format.link);
|
142
|
}
|
143
|
return link;
|
144
|
}
|
145
|
|
146
|
void RichTextView::RefreshRange(int a, int b)
|
147
|
{
|
148
|
int l = min(a, b);
|
149
|
int h = max(a, b);
|
150
|
if(l == h)
|
151
|
return;
|
152
|
Rect r1 = text.GetCaret(l, GetPage());
|
153
|
Rect r2 = text.GetCaret(h, GetPage());
|
154
|
Zoom zoom = GetZoom();
|
155
|
Refresh(0, zoom * (r1.top - sb), GetSize().cx, zoom * (r2.bottom - sb + zoom.d - 1));
|
156
|
}
|
157
|
|
158
|
void RichTextView::RefreshSel()
|
159
|
{
|
160
|
int l = minmax(min(cursor, anchor), 0, text.GetLength());
|
161
|
int h = minmax(max(cursor, anchor), 0, text.GetLength());
|
162
|
if(sell == l && selh == h || sell == selh && l == h)
|
163
|
return;
|
164
|
RichPos pl = text.GetRichPos(l);
|
165
|
RichPos ph = text.GetRichPos(h);
|
166
|
RichPos psell = text.GetRichPos(sell);
|
167
|
RichPos pselh = text.GetRichPos(selh);
|
168
|
if(psell.parai != pl.parai || pselh.parai != ph.parai ||
|
169
|
psell.table != pl.table || pselh.table != ph.table ||
|
170
|
psell.cell != pl.cell || pselh.cell != ph.cell)
|
171
|
Refresh();
|
172
|
else {
|
173
|
RefreshRange(l, sell);
|
174
|
RefreshRange(h, selh);
|
175
|
}
|
176
|
sell = l;
|
177
|
selh = h;
|
178
|
}
|
179
|
|
180
|
void RichTextView::LeftDown(Point p, dword keyflags)
|
181
|
{
|
182
|
int pos = GetPointPos(p);
|
183
|
if(pos < 0) {
|
184
|
cursor = anchor = 0;
|
185
|
return;
|
186
|
}
|
187
|
String link = GetLink(pos, p);
|
188
|
if(!IsNull(link))
|
189
|
WhenLink(link);
|
190
|
else {
|
191
|
cursor = pos;
|
192
|
if(!(keyflags & K_SHIFT))
|
193
|
anchor = pos;
|
194
|
RefreshSel();
|
195
|
SetFocus();
|
196
|
SetCapture();
|
197
|
}
|
198
|
}
|
199
|
|
200
|
void RichTextView::LeftDouble(Point p, dword keyflags)
|
201
|
{
|
202
|
int pos = GetPointPos(p);
|
203
|
if(IsLeNum(text[pos])) {
|
204
|
anchor = pos;
|
205
|
while(anchor > 0 && IsLeNum(text[anchor - 1]))
|
206
|
anchor--;
|
207
|
cursor = pos;
|
208
|
while(cursor + 1 < text.GetLength() && IsLeNum(text[cursor]))
|
209
|
cursor++;
|
210
|
while(cursor + 1 < text.GetLength() && text[cursor] == ' ')
|
211
|
cursor++;
|
212
|
RefreshSel();
|
213
|
SetFocus();
|
214
|
}
|
215
|
}
|
216
|
|
217
|
void RichTextView::LeftTriple(Point p, dword keyflags)
|
218
|
{
|
219
|
int pos = GetPointPos(p);
|
220
|
RichPos rp = text.GetRichPos(pos);
|
221
|
anchor = pos - rp.posinpara;
|
222
|
cursor = anchor + rp.paralen + 1;
|
223
|
RefreshSel();
|
224
|
SetFocus();
|
225
|
}
|
226
|
|
227
|
void RichTextView::MouseMove(Point p, dword keyflags)
|
228
|
{
|
229
|
int pos = GetPointPos(p);
|
230
|
WhenMouseMove(pos);
|
231
|
if(HasCapture()) {
|
232
|
if(pos < 0)
|
233
|
return;
|
234
|
cursor = pos;
|
235
|
Rect r1 = text.GetCaret(cursor, GetPage());
|
236
|
sb.ScrollInto(r1.top, r1.Height());
|
237
|
RefreshSel();
|
238
|
}
|
239
|
}
|
240
|
|
241
|
void RichTextView::LeftRepeat(Point p, dword keyflags)
|
242
|
{
|
243
|
MouseMove(p, keyflags);
|
244
|
}
|
245
|
|
246
|
void RichTextView::EndSizeTracking()
|
247
|
{
|
248
|
sizetracking = false;
|
249
|
Refresh();
|
250
|
}
|
251
|
|
252
|
void RichTextView::Layout()
|
253
|
{
|
254
|
sizetracking = false;
|
255
|
if(IsOpen() && lazy) {
|
256
|
sizetracking = true;
|
257
|
KillTimeCallback(TIMEID_ENDSIZETRACKING);
|
258
|
SetTimeCallback(250, THISBACK(EndSizeTracking), TIMEID_ENDSIZETRACKING);
|
259
|
}
|
260
|
SetSb();
|
261
|
Refresh();
|
262
|
}
|
263
|
|
264
|
Value RichTextView::GetData() const
|
265
|
{
|
266
|
if(text.IsEmpty()) return Value();
|
267
|
return GetQTF();
|
268
|
}
|
269
|
|
270
|
void RichTextView::SetData(const Value& v)
|
271
|
{
|
272
|
SetQTF(String(v));
|
273
|
}
|
274
|
|
275
|
void RichTextView::Scroll()
|
276
|
{
|
277
|
scroller.Scroll(*this, Rect(GetSize()).Deflated(margin), sb * GetZoom());
|
278
|
}
|
279
|
|
280
|
void RichTextView::GotoLabel(const String& lbl, bool dohighlight)
|
281
|
{
|
282
|
Vector<RichValPos> f = text.GetValPos(GetPage(), RichText::LABELS);
|
283
|
highlight = Null;
|
284
|
for(int i = 0; i < f.GetCount(); i++) {
|
285
|
if(f[i].data == WString(lbl)) {
|
286
|
sb = f[i].py.y;
|
287
|
if(dohighlight)
|
288
|
highlight = f[i].pos;
|
289
|
Refresh();
|
290
|
break;
|
291
|
}
|
292
|
}
|
293
|
}
|
294
|
|
295
|
void RichTextView::Clear()
|
296
|
{
|
297
|
sb = 0;
|
298
|
text.Clear();
|
299
|
SetSb();
|
300
|
Refresh();
|
301
|
anchor = cursor = sell = selh = 0;
|
302
|
}
|
303
|
|
304
|
void RichTextView::Pick(pick_ RichText& rt)
|
305
|
{
|
306
|
sb = 0;
|
307
|
anchor = cursor = sell = selh = 0;
|
308
|
text = rt;
|
309
|
SetSb();
|
310
|
UpdateRefresh();
|
311
|
highlight = -1;
|
312
|
}
|
313
|
|
314
|
void RichTextView::Pick(pick_ RichText& txt, Zoom z) {
|
315
|
if(z.m != z.d)
|
316
|
const_cast<RichText&>(txt).ApplyZoom(z);
|
317
|
Pick(txt);
|
318
|
sb.SetLine(z * 100);
|
319
|
}
|
320
|
|
321
|
void RichTextView::SetQTF(const char *qtf, Zoom z)
|
322
|
{
|
323
|
Pick(ParseQTF(qtf), z);
|
324
|
}
|
325
|
|
326
|
RichTextView& RichTextView::PageWidth(int _cx)
|
327
|
{
|
328
|
cx = _cx;
|
329
|
sb = 0;
|
330
|
SetSb();
|
331
|
Refresh();
|
332
|
return *this;
|
333
|
}
|
334
|
|
335
|
RichTextView& RichTextView::SetZoom(Zoom z)
|
336
|
{
|
337
|
zoom = z;
|
338
|
sb = 0;
|
339
|
SetSb();
|
340
|
Refresh();
|
341
|
return *this;
|
342
|
}
|
343
|
|
344
|
RichTextView& RichTextView::Background(Color c)
|
345
|
{
|
346
|
background = c;
|
347
|
Transparent(IsNull(c));
|
348
|
Refresh();
|
349
|
return *this;
|
350
|
}
|
351
|
|
352
|
RichTextView& RichTextView::VCenter(bool b)
|
353
|
{
|
354
|
vcenter = b;
|
355
|
return *this;
|
356
|
}
|
357
|
|
358
|
RichTextView& RichTextView::Margins(const Rect& m)
|
359
|
{
|
360
|
margin = m;
|
361
|
Refresh();
|
362
|
return *this;
|
363
|
}
|
364
|
|
365
|
RichTextView& RichTextView::HMargins(int a)
|
366
|
{
|
367
|
margin.left = margin.right = a;
|
368
|
Refresh();
|
369
|
return *this;
|
370
|
}
|
371
|
|
372
|
RichTextView& RichTextView::VMargins(int a)
|
373
|
{
|
374
|
margin.top = margin.bottom = a;
|
375
|
Refresh();
|
376
|
return *this;
|
377
|
}
|
378
|
|
379
|
RichTextView& RichTextView::Margins(int a)
|
380
|
{
|
381
|
margin.Set(a, a, a, a);
|
382
|
Refresh();
|
383
|
return *this;
|
384
|
}
|
385
|
|
386
|
void LinkInRichTextClipboard__();
|
387
|
|
388
|
RichTextView::RichTextView()
|
389
|
{
|
390
|
cx = 3968;
|
391
|
sizetracking = false;
|
392
|
sb.SetLine(100);
|
393
|
sb.WhenScroll = THISBACK(Scroll);
|
394
|
zoom = Null;
|
395
|
background = SColorPaper;
|
396
|
vcenter = false;
|
397
|
margin = Rect(0, 0, 0, 0);
|
398
|
highlight = -1;
|
399
|
hldec = true;
|
400
|
WhenLink = callback(LaunchWebBrowser);
|
401
|
anchor = cursor = sell = selh = 0;
|
402
|
SetFrame(ViewFrame());
|
403
|
AddFrame(sb);
|
404
|
NoWantFocus();
|
405
|
lazy = true;
|
406
|
shrink_oversized_objects = true;
|
407
|
}
|
408
|
|
409
|
RichTextView::~RichTextView() {}
|
410
|
|
411
|
void RichTextCtrl::SetData(const Value& v)
|
412
|
{
|
413
|
SetQTF(String(v));
|
414
|
}
|
415
|
|
416
|
RichTextCtrl::RichTextCtrl()
|
417
|
{
|
418
|
SetZoom(Zoom(1, 1));
|
419
|
Transparent();
|
420
|
Background(Null);
|
421
|
SetFrame(NullFrame());
|
422
|
AutoHideSb();
|
423
|
}
|
424
|
|
425
|
#ifndef PLATFORM_PDA
|
426
|
|
427
|
void Print(Draw& w, const RichText& text, const Rect& page, const Vector<int>& pg)
|
428
|
{
|
429
|
LLOG("Print");
|
430
|
int lpage = text.GetHeight(page).page;
|
431
|
PrintPageDraw pw(w);
|
432
|
Size sz = w.GetPageMMs();
|
433
|
Size pgsz = page.Size();
|
434
|
int x = (6000 * sz.cx / 254 - pgsz.cx) / 2;
|
435
|
int y = (6000 * sz.cy / 254 - pgsz.cy) / 2;
|
436
|
for(int pi = 0; pi < pg.GetCount(); pi++) {
|
437
|
int i = pg[pi];
|
438
|
w.StartPage();
|
439
|
w.Offset(x, y);
|
440
|
pw.SetPage(i);
|
441
|
PaintInfo paintinfo;
|
442
|
paintinfo.top = PageY(i, 0);
|
443
|
paintinfo.bottom = PageY(i + 1, 0);
|
444
|
paintinfo.indexentry = Null;
|
445
|
if(text.IsPrintNoLinks())
|
446
|
paintinfo.hyperlink = Null;
|
447
|
text.Paint(pw, page, paintinfo);
|
448
|
w.End();
|
449
|
String footer = text.GetFooter();
|
450
|
if(!IsNull(footer) && lpage) {
|
451
|
String n = Format(footer, i + 1, lpage + 1);
|
452
|
Size nsz = GetTextSize(n, Arial(90).Italic());
|
453
|
pw.Page(i).DrawText(
|
454
|
x + pgsz.cx - nsz.cx, y + pgsz.cy + 100,
|
455
|
n, Arial(90).Italic());
|
456
|
}
|
457
|
w.EndPage();
|
458
|
}
|
459
|
}
|
460
|
|
461
|
void Print(Draw& w, const RichText& text, const Rect& page)
|
462
|
{
|
463
|
int n = text.GetHeight(page).page;
|
464
|
Vector<int> pg;
|
465
|
for(int i = 0; i <= n; i++)
|
466
|
pg.Add(i);
|
467
|
Print(w, text, page, pg);
|
468
|
}
|
469
|
|
470
|
bool Print(const RichText& text, const Rect& page, int currentpage, const char *name)
|
471
|
{
|
472
|
PrinterJob pj(name);
|
473
|
pj.CurrentPage(currentpage);
|
474
|
pj.PageCount(text.GetHeight(page).page + 1);
|
475
|
pj.Landscape(page.GetWidth() > page.GetHeight());
|
476
|
if(pj.Execute()) {
|
477
|
Print(pj, text, page, pj.GetPages());
|
478
|
return true;
|
479
|
}
|
480
|
return false;
|
481
|
}
|
482
|
|
483
|
#endif
|
484
|
|
485
|
END_UPP_NAMESPACE
|