1 #include "CtrlCore.h"
2 
3 #ifdef GUI_X11
4 
5 namespace Upp {
6 
7 #define LLOG(x)     // LOG(x)
8 #define LTIMING(x)  // TIMING(x)
9 
BeginOp()10 void SystemDraw::BeginOp()
11 {
12 	Cloff f = cloff.Top();
13 	Vector<Rect> newclip;
14 	newclip <<= clip.Top();
15 	f.clipi = clip.GetCount();
16 	clip.Add() = pick(newclip);
17 	cloff.Add(f);
18 }
19 
OffsetOp(Point p)20 void SystemDraw::OffsetOp(Point p)
21 {
22 	Cloff f = cloff.Top();
23 	f.offseti = offset.GetCount();
24 	actual_offset += p;
25 	drawingclip -= p;
26 	offset.Add(actual_offset);
27 	cloff.Add(f);
28 }
29 
ClipOp(const Rect & r)30 bool SystemDraw::ClipOp(const Rect& r)
31 {
32 	LLOG("SystemDraw::ClipOp(" << r << ")");
33 	Cloff f = cloff.Top();
34 	bool ch = false;
35 	Vector<Rect> newclip = Intersect(clip.Top(), r + actual_offset, ch);
36 	if(ch) {
37 		f.clipi = clip.GetCount();
38 		clip.Add() = pick(newclip);
39 	}
40 	cloff.Add(f);
41 	if(ch)
42 		SetClip();
43 	return clip.Top().GetCount();
44 }
45 
ClipoffOp(const Rect & r)46 bool SystemDraw::ClipoffOp(const Rect& r)
47 {
48 	LLOG("SystemDraw::ClipOffOp(" << r << ")");
49 	Cloff f = cloff.Top();
50 	bool ch = false;
51 	Vector<Rect> newclip = Intersect(clip.Top(), r + actual_offset, ch);
52 	if(ch) {
53 		f.clipi = clip.GetCount();
54 		clip.Add() = pick(newclip);
55 	}
56 	f.offseti = offset.GetCount();
57 	actual_offset += r.TopLeft();
58 	drawingclip -= r.TopLeft();
59 	offset.Add(actual_offset);
60 	cloff.Add(f);
61 	if(ch)
62 		SetClip();
63 	return clip.Top().GetCount();
64 }
65 
EndOp()66 void SystemDraw::EndOp()
67 {
68 	ASSERT(cloff.GetCount());
69 	cloff.Drop();
70 	actual_offset = offset[cloff.Top().offseti];
71 	clip.SetCount(cloff.Top().clipi + 1);
72 	SetClip();
73 }
74 
ExcludeClipOp(const Rect & r)75 bool SystemDraw::ExcludeClipOp(const Rect& r)
76 {
77 	LLOG("SystemDraw::ExcludeClipOp(" << r << ")");
78 	CloneClip();
79 	Vector<Rect>& cl = clip.Top();
80 	bool ch = false;
81 	Vector<Rect> ncl = Subtract(cl, r + actual_offset, ch);
82 	if(ch) {
83 		cl = pick(ncl);
84 		SetClip();
85 	}
86 	return clip.Top().GetCount();
87 }
88 
IntersectClipOp(const Rect & r)89 bool SystemDraw::IntersectClipOp(const Rect& r)
90 {
91 	CloneClip();
92 	Vector<Rect>& cl = clip.Top();
93 	bool ch = false;
94 	Vector<Rect> ncl = Intersect(cl, r + actual_offset, ch);
95 	if(ch) {
96 		cl = pick(ncl);
97 		SetClip();
98 	}
99 	return clip.Top().GetCount();
100 }
101 
IsPaintingOp(const Rect & r) const102 bool SystemDraw::IsPaintingOp(const Rect& r) const
103 {
104 	LTIMING("IsPaintingOp");
105 	Rect rr = r + actual_offset;
106 	const Vector<Rect>& cl = clip[cloff.Top().clipi];
107 	for(int i = 0; i < cl.GetCount(); i++)
108 		if(cl[i].Intersects(rr))
109 			return true;
110 	return false;
111 }
112 
GetPaintRect() const113 Rect SystemDraw::GetPaintRect() const
114 {
115 	return drawingclip;
116 }
117 
DrawRectOp(int x,int y,int cx,int cy,Color color)118 void SystemDraw::DrawRectOp(int x, int y, int cx, int cy, Color color)
119 {
120 	LTIMING("DrawRect");
121 	GuiLock __;
122 	LLOG("DrawRect " << RectC(x, y, cx, cy) << ": " << color);
123 	if(IsNull(color)) return;
124 	if(cx <= 0 || cy <= 0) return;
125 	if(color == InvertColor) {
126 		XSetFunction(Xdisplay, gc, GXinvert);
127 		XFillRectangle(Xdisplay, dw, gc, x + actual_offset.x, y + actual_offset.y, cx, cy);
128 		XSetFunction(Xdisplay, gc, GXcopy);
129 	}
130 	else {
131 		SetForeground(color);
132 		XFillRectangle(Xdisplay, dw, gc, x + actual_offset.x, y + actual_offset.y, cx, cy);
133 	}
134 }
135 
DrawLineOp(int x1,int y1,int x2,int y2,int width,Color color)136 void SystemDraw::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color)
137 {
138 	GuiLock __;
139 	if(IsNull(width) || IsNull(color)) return;
140 	SetLineStyle(width);
141 	SetForeground(color);
142 	XDrawLine(Xdisplay, dw, gc,
143 	          x1 + actual_offset.x, y1 + actual_offset.y,
144 	          x2 + actual_offset.x, y2 + actual_offset.y);
145 }
146 
DrawPolyPolylineOp(const Point * vertices,int vertex_count,const int * counts,int count_count,int width,Color color,Color doxor)147 void SystemDraw::DrawPolyPolylineOp(const Point *vertices, int vertex_count,
148 	                          const int *counts, int count_count,
149 	                          int width, Color color, Color doxor)
150 {
151 	GuiLock __;
152 	ASSERT(count_count > 0 && vertex_count > 0);
153 	if(vertex_count < 2 || IsNull(color))
154 		return;
155 	SetLineStyle(width);
156 	XGCValues gcv_old, gcv_new;
157 	XGetGCValues(Xdisplay, GetGC(), GCForeground | GCFunction, &gcv_old);
158 	gcv_new.function = IsNull(doxor) ? X11_ROP2_COPY : X11_ROP2_XOR;
159 	gcv_new.foreground = GetXPixel(color) ^ (IsNull(doxor) ? 0 : GetXPixel(doxor));
160 	XChangeGC(Xdisplay, GetGC(), GCForeground | GCFunction, &gcv_new);
161 	enum { REQUEST_LENGTH = 256 }; // X server XDrawLines request length (heuristic)
162 	Point offset = GetOffset();
163 	if(vertex_count == 2)
164 		XDrawLine(Xdisplay, GetDrawable(), GetGC(),
165 			vertices[0].x + offset.x, vertices[0].y + offset.y,
166 			vertices[1].x + offset.x, vertices[1].y + offset.y);
167 	else if(count_count == 1 || vertex_count > count_count * (REQUEST_LENGTH + 2)) {
168 		for(; --count_count >= 0; counts++)
169 		{
170 			Buffer<XPoint> part(*counts);
171 			for(XPoint *vo = part, *ve = vo + *counts; vo < ve; vo++, vertices++)
172 			{
173 				vo -> x = (short)(vertices -> x + offset.x);
174 				vo -> y = (short)(vertices -> y + offset.y);
175 			}
176 			XDrawLines(Xdisplay, GetDrawable(), GetGC(), part, *counts, CoordModeOrigin);
177 		}
178 	}
179 	else {
180 		int segment_count = vertex_count - count_count;
181 		Buffer<XSegment> segments(segment_count);
182 		XSegment *so = segments;
183 		while(--count_count >= 0)
184 		{
185 			const Point *end = vertices + *counts++;
186 			so -> x1 = (short)(vertices -> x + offset.x);
187 			so -> y1 = (short)(vertices -> y + offset.y);
188 			vertices++;
189 			so -> x2 = (short)(vertices -> x + offset.x);
190 			so -> y2 = (short)(vertices -> y + offset.y);
191 			so++;
192 			while(++vertices < end) {
193 				so -> x1 = so[-1].x2;
194 				so -> y1 = so[-1].y2;
195 				so -> x2 = (short)(vertices -> x + offset.x);
196 				so -> y2 = (short)(vertices -> y + offset.y);
197 				so++;
198 			}
199 		}
200 		ASSERT(so == segments + segment_count);
201 		XDrawSegments(Xdisplay, GetDrawable(), GetGC(), segments, segment_count);
202 	}
203 	XChangeGC(Xdisplay, GetGC(), GCForeground | GCFunction, &gcv_old);
204 }
205 
DrawPolyPolyPolygonRaw(SystemDraw & draw,const Point * vertices,int vertex_count,const int * subpolygon_counts,int subpolygon_count_count,const int *,int)206 static void DrawPolyPolyPolygonRaw(SystemDraw& draw, const Point *vertices, int vertex_count,
207 	const int *subpolygon_counts, int subpolygon_count_count, const int *, int)
208 {
209 	GuiLock __;
210 	Point offset = draw.GetOffset();
211 	const Point *in = vertices;
212 	for(int i = 0; i < subpolygon_count_count; i++) {
213 		int n = subpolygon_counts[i];
214 		Buffer<XPoint> out_points(n);
215 		XPoint *t = out_points;
216 		XPoint *e = t + n;
217 		while(t < e) {
218 			t->x = (short)(in->x + offset.x);
219 			t->y = (short)(in->y + offset.y);
220 			t++;
221 			in++;
222 		}
223 		XFillPolygon(Xdisplay, draw.GetDrawable(), draw.GetGC(), out_points, n, Nonconvex, CoordModeOrigin);
224 	}
225 }
226 
DrawPolyPolyPolygonOp(const Point * vertices,int vertex_count,const int * subpolygon_counts,int subpolygon_count_count,const int * disjunct_polygon_counts,int disjunct_polygon_count_count,Color color,int width,Color outline,uint64 pattern,Color doxor)227 void SystemDraw::DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count,
228 	 const int *subpolygon_counts, int subpolygon_count_count,
229 	const int *disjunct_polygon_counts, int disjunct_polygon_count_count,
230 	Color color, int width, Color outline, uint64 pattern, Color doxor)
231 {
232 	GuiLock __;
233 	if(vertex_count == 0)
234 		return;
235 
236 	if(!IsNull(outline)) SetLineStyle(width); // Added
237 	bool is_xor = !IsNull(doxor);
238 	XGCValues gcv_old, gcv_new;
239 	XGetGCValues(Xdisplay, GetGC(), GCForeground | GCFunction, &gcv_old);
240 	unsigned xor_pixel = (is_xor ? GetXPixel(doxor) : 0);
241 	if(!IsNull(color))
242 	{
243 		gcv_new.foreground = GetXPixel(color) ^ xor_pixel;
244 		gcv_new.function = is_xor ? X11_ROP2_XOR : X11_ROP2_COPY;
245 		XChangeGC(Xdisplay, GetGC(), GCForeground | GCFunction, &gcv_new);
246 		DrawPolyPolyPolygonRaw(*this, vertices, vertex_count,
247 			subpolygon_counts, subpolygon_count_count,
248 			disjunct_polygon_counts, disjunct_polygon_count_count);
249 	}
250 	if(!IsNull(outline))
251 	{
252 		gcv_new.foreground = GetXPixel(outline) ^ xor_pixel;
253 		XChangeGC(Xdisplay, GetGC(), GCForeground, &gcv_new);
254 		Point offset = GetOffset();
255 		for(const int *sp = subpolygon_counts, *se = sp + subpolygon_count_count; sp < se; sp++)
256 		{
257 			Buffer<XPoint> segment(*sp + 1);
258 			XPoint *out = segment;
259 			for(const Point *end = vertices + *sp; vertices < end; vertices++, out++)
260 			{
261 				out -> x = (short)(vertices -> x + offset.x);
262 				out -> y = (short)(vertices -> y + offset.y);
263 			}
264 			*out = segment[0];
265 			XDrawLines(Xdisplay, GetDrawable(), GetGC(), segment, *sp + 1, CoordModeOrigin);
266 		}
267 	}
268 	XChangeGC(Xdisplay, GetGC(), GCForeground | GCFunction, &gcv_old);
269 }
270 
DrawEllipseOp(const Rect & r,Color color,int pen,Color pencolor)271 void SystemDraw::DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor)
272 {
273 	GuiLock __;
274 	SetLineStyle(pen);
275 	if(!IsNull(color)) {
276 		SetForeground(color);
277 		XFillArc(Xdisplay, dw, gc, r.left + actual_offset.x, r.top + actual_offset.y,
278 			r.Width() - 1, r.Height() - 1, 0, 360 * 64);
279 	}
280 	if(!IsNull(pencolor) && !IsNull(pen)) {
281 		SetForeground(pencolor);
282 		XDrawArc(Xdisplay, dw, gc, r.left + actual_offset.x, r.top + actual_offset.y,
283 			r.Width() - 1, r.Height() - 1, 0, 360 * 64);
284 	}
285 }
286 
DrawArcOp(const Rect & rc,Point start,Point end,int width,Color color)287 void SystemDraw::DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color)
288 {
289 	GuiLock __;
290 	SetLineStyle(width);
291 	XGCValues gcv, gcv_old;
292 	XGetGCValues(Xdisplay, GetGC(), GCForeground, &gcv_old);
293 	Point offset = GetOffset();
294 	gcv.foreground = GetXPixel(color);
295 	XChangeGC(Xdisplay, GetGC(), GCForeground, &gcv);
296 	Point centre = rc.CenterPoint();
297 	int angle1 = fround(360 * 64 / (2 * M_PI) *
298 	                    atan2(centre.y - start.y, start.x - centre.x));
299 	int angle2 = fround(360 * 64 / (2 * M_PI) *
300 	                    atan2(centre.y - end.y, end.x - centre.x));
301 	if(angle2 <= angle1)
302 		angle2 += 360 * 64;
303 	angle2 -= angle1;
304 	XDrawArc(Xdisplay, GetDrawable(), GetGC(), rc.left + offset.x, rc.top + offset.y,
305 		rc.Width(), rc.Height(), angle1, angle2);
306 	XChangeGC(Xdisplay, GetGC(), GCForeground, &gcv_old);
307 }
308 
309 }
310 
311 #endif
312