1 #include "RichEdit.h"
2 #include <Painter/Painter.h>
3 
4 namespace Upp {
5 
InsertImage()6 void RichEdit::InsertImage()
7 {
8 	if(!imagefs.ExecuteOpen(t_("Open image from file")))
9 		return;
10 	String fn = ~imagefs;
11 	if(GetFileLength(fn) > 17000000) {
12 		Exclamation("Image is too large!");
13 		return;
14 	}
15 	String data = LoadFile(fn);
16 	StringStream ss(data);
17 	if(!StreamRaster::OpenAny(ss) && !IsSVG(data)) {
18 		Exclamation(Format(t_("Unsupported image format in file [* \1%s\1]."), ~imagefs));
19 		return;
20 	}
21 	RichText clip;
22 	RichPara p;
23 	p.Cat(CreateRawImageObject(data), formatinfo);
24 	clip.Cat(p);
25 	ClipPaste(clip, "image/raw");
26 }
27 
Accept(PasteClip & d,RichText & clip,String & fmt)28 bool RichEdit::Accept(PasteClip& d, RichText& clip, String& fmt)
29 {
30 	if(IsReadOnly())
31 		return false;
32 	if(AcceptFiles(d)) {
33 		Vector<String> s = GetFiles(d);
34 		if(s.GetCount()) {
35 			String fn = s[0];
36 			String ext = ToLower(GetFileExt(fn));
37 			if(findarg(ext, ".png", ".jpg", ".jpeg", ".gif", ".tif", ".tiff", ".svg") >= 0) {
38 				if(d.Accept() && GetFileLength(fn) < 17000000) {
39 					String data = LoadFile(fn);
40 					StringStream ss(data);
41 					if(StreamRaster::OpenAny(ss) || ext == ".svg" && IsSVG(LoadFile(fn))) {
42 						RichPara p;
43 						p.Cat(CreateRawImageObject(data), formatinfo);
44 						clip.Cat(p);
45 						fmt = "files";
46 					}
47 					return true;
48 				}
49 				return false;
50 			}
51 		}
52 		d.Reject();
53 	}
54 	if(d.Accept("image/x-inkscape-svg")) {
55 		RichPara p;
56 		p.Cat(CreateRawImageObject(~d), formatinfo);
57 		clip.Cat(p);
58 		fmt = "files";
59 	}
60 	if(d.Accept("text/QTF")) {
61 		fmt = "text/QTF";
62 		clip = ParseQTF(~d, 0, context);
63 		return true;
64 	}
65 	if(d.Accept(ClipFmtsRTF())) {
66 		fmt = ClipFmtsRTF();
67 		clip = ParseRTF(~d);
68 		return true;
69 	}
70 	for(int i = 0; i < RichObject::GetTypeCount(); i++) {
71 		RichObjectType& rt = RichObject::GetType(i);
72 		if(rt.Accept(d)) {
73 			Value data = rt.Read(d);
74 			if(!IsNull(data)) {
75 				RichPara p;
76 				RichObject o = RichObject(&rt, data, pagesz);
77 				p.Cat(o, formatinfo);
78 				clip.Cat(p);
79 				fmt = o.GetTypeName();
80 			}
81 			return true;
82 		}
83 	}
84 	if(AcceptText(d)) {
85 		fmt = "text/plain";
86 		clip = AsRichText(GetWString(d), formatinfo);
87 		return true;
88 	}
89 	return false;
90 }
91 
ClipPaste(RichText & clip,const String & fmt)92 void RichEdit::ClipPaste(RichText& clip, const String& fmt)
93 {
94 	clip.ApplyZoom(clipzoom.Reciprocal());
95 	PasteFilter(clip, fmt);
96 	NextUndo();
97 	if(clip.GetPartCount() == 1 && clip.IsTable(0)) {
98 		CancelSelection();
99 		if(cursorp.table) {
100 			NextUndo();
101 			SaveTable(cursorp.table);
102 			text.PasteTable(cursorp.table, cursorp.cell, clip.GetTable(0));
103 			Finish();
104 			return;
105 		}
106 	}
107 	clip.Normalize();
108 	PasteText(clip);
109 }
110 
DragAndDrop(Point p,PasteClip & d)111 void RichEdit::DragAndDrop(Point p, PasteClip& d)
112 {
113 	int dropcursor = GetMousePos(p);
114 	if(dropcursor >= 0) {
115 		RichText clip;
116 		String fmt;
117 		if(Accept(d, clip, fmt)) {
118 			NextUndo();
119 			int a = sb;
120 			int c = dropcursor;
121 			if(InSelection(c)) {
122 				if(!IsReadOnly())
123 					RemoveSelection();
124 				if(IsDragAndDropSource())
125 					d.SetAction(DND_COPY);
126 			}
127 			int sell, selh;
128 			if(GetSelection(sell, selh) && d.GetAction() == DND_MOVE && IsDragAndDropSource()) {
129 				if(c > sell)
130 					c -= selh - sell;
131 				if(!IsReadOnly())
132 					RemoveSelection();
133 				d.SetAction(DND_COPY);
134 			}
135 			Move(c);
136 			clip.Normalize();
137 			ClipPaste(clip, fmt);
138 			sb = a;
139 			Select(c, clip.GetLength());
140 			SetFocus();
141 			Action();
142 			return;
143 		}
144 	}
145 	if(!d.IsAccepted())
146 		dropcursor = -1;
147 	Rect r = Null;
148 	if(dropcursor >= 0 && dropcursor < text.GetLength()) {
149 		RichCaret pr = text.GetCaret(dropcursor, pagesz);
150 		Zoom zoom = GetZoom();
151 		Rect tr = GetTextRect();
152 		r = RectC(pr.left * zoom + tr.left - 1,
153 		          GetPosY(pr) + (pr.lineascent - pr.caretascent) * zoom,
154 		          2, (pr.caretascent + pr.caretdescent) * zoom);
155 	}
156 	if(r != dropcaret) {
157 		RefreshDropCaret();
158 		dropcaret = r;
159 		RefreshDropCaret();
160 	}
161 }
162 
DragRepeat(Point p)163 void RichEdit::DragRepeat(Point p)
164 {
165 	sb = (int)sb + GetDragScroll(this, p, 16).y;
166 }
167 
RefreshDropCaret()168 void RichEdit::RefreshDropCaret()
169 {
170 	Refresh(dropcaret.OffsetedVert(-sb));
171 }
172 
Paste()173 void RichEdit::Paste()
174 {
175 	if(IsReadOnly())
176 		return;
177 	RichText clip;
178 	PasteClip d = Clipboard();
179 	String fmt;
180 	if(!Accept(d, clip, fmt))
181 		return;
182 	ClipPaste(clip, fmt);
183 }
184 
DragLeave()185 void RichEdit::DragLeave()
186 {
187 	RefreshDropCaret();
188 	dropcaret.Clear();
189 }
190 
sRTF(const Value & data)191 static String sRTF(const Value& data)
192 {
193 	const RichText& txt = ValueTo<RichText>(data);
194 	return EncodeRTF(txt);
195 }
196 
sQTF(const Value & data)197 static String sQTF(const Value& data)
198 {
199 	const RichText& txt = ValueTo<RichText>(data);
200 	return AsQTF(txt);
201 }
202 
ZoomClip(RichText & text) const203 void RichEdit::ZoomClip(RichText& text) const
204 {
205 	text.ApplyZoom(clipzoom);
206 }
207 
AppendClipboard(RichText && txt)208 void AppendClipboard(RichText&& txt)
209 {
210 	AppendClipboardUnicodeText(txt.GetPlainText());
211 	Value clip = RawPickToValue(pick(txt));
212 	AppendClipboard("text/QTF", clip, sQTF);
213 	AppendClipboard(ClipFmtsRTF(), clip, sRTF);
214 }
215 
Copy()216 void RichEdit::Copy()
217 {
218 	RichText txt;
219 	if(IsSelection())
220 		txt = GetSelection();
221 	else if(objectpos >= 0)
222 		txt = text.Copy(cursor, 1);
223 	else {
224 		BeepExclamation();
225 		return;
226 	}
227 	ZoomClip(txt);
228 	ClearClipboard();
229 	AppendClipboard(pick(txt));
230 	if(objectpos >= 0) {
231 		RichObject o = GetObject();
232 		Vector<String> v = Split(o.GetType().GetClipFmts(), ';');
233 		for(int i = 0; i < v.GetCount(); i++)
234 			AppendClipboard(v[i], o.GetType().GetClip(o.GetData(), v[i]));
235 	}
236 }
237 
GetSelectionData(const String & fmt) const238 String RichEdit::GetSelectionData(const String& fmt) const
239 {
240 	String f = fmt;
241 	if(IsSelection()) {
242 		RichText clip = GetSelection();
243 		ZoomClip(clip);
244 		if(f == "text/QTF")
245 			return AsQTF(clip);
246 		if(InScList(f, ClipFmtsRTF()))
247 			return EncodeRTF(clip);
248 		return GetTextClip(clip.GetPlainText(), fmt);
249 	}
250 /*	else
251 	if(objectpos >= 0) {
252 		RichObject o = GetObject();
253 		if(InScList(fmt, o.GetType().GetClipFmts()))
254 			return o.GetType().GetClip(o.GetData(), fmt);
255 	}*/
256 	return Null;
257 }
258 
LeftDrag(Point p,dword flags)259 void RichEdit::LeftDrag(Point p, dword flags)
260 {
261 	int c = GetMousePos(p);
262 	Size ssz = StdSampleSize();
263 	if(!HasCapture() && InSelection(c)) {
264 		RichText sample = GetSelection(5000);
265 		sample.ApplyZoom(Zoom(1, 8));
266 		ImageDraw iw(ssz);
267 		iw.DrawRect(0, 0, ssz.cx, ssz.cy, White);
268 		sample.Paint(iw, 0, 0, 128);
269 		NextUndo();
270 		if(DoDragAndDrop(String().Cat() << "text/QTF;" << ClipFmtsRTF() << ";" << ClipFmtsText(),
271 		                 ColorMask(iw, White)) == DND_MOVE && !IsReadOnly()) {
272 			RemoveSelection();
273 			Action();
274 		}
275 	}
276 /*	else
277 	if(objectpos >= 0 && c == objectpos) {
278 		ReleaseCapture();
279 		RichObject o = GetObject();
280 		Size sz = o.GetPhysicalSize();
281 		NextUndo();
282 		if(DoDragAndDrop(o.GetType().GetClipFmts(),
283 		                 o.ToImage(Size(ssz.cx, sz.cy * ssz.cx / sz.cx))) == DND_MOVE
284 		   && objectpos >= 0) {
285 			if(droppos > objectpos)
286 				droppos--;
287 			Remove(objectpos, 1);
288 		}
289 		Move(droppos);
290 		SetObjectPos(droppos);
291 	}*/
292 }
293 
MiddleDown(Point p,dword flags)294 void  RichEdit::MiddleDown(Point p, dword flags)
295 {
296 	RichText clip;
297 	if(IsReadOnly())
298 		return;
299 	String fmt;
300 	if(Accept(Selection(), clip, fmt)) {
301 		selclick = false;
302 		LeftDown(p, flags);
303 		ClipPaste(clip, fmt);
304 	}
305 }
306 
307 }
308