/uppsrc/CtrlCore/DrawOpX11.cpp

https://github.com/ultimatepp/mirror · C++ · 311 lines · 289 code · 22 blank · 0 comment · 44 complexity · feb661c68ab39cde89de0798daeb150b MD5 · raw file

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