21
21
#include <wx/docview.h>
23
#include "images/ex_aggregate.xpm"
24
#include "images/ex_append.xpm"
25
#include "images/ex_bmp_heap.xpm"
26
#include "images/ex_bmp_index.xpm"
27
#include "images/ex_cte_scan.xpm"
28
#include "images/ex_group.xpm"
29
#include "images/ex_hash.xpm"
30
#include "images/ex_hash_anti_join.xpm"
31
#include "images/ex_hash_semi_join.xpm"
32
#include "images/ex_hash_setop_except.xpm"
33
#include "images/ex_hash_setop_except_all.xpm"
34
#include "images/ex_hash_setop_intersect.xpm"
35
#include "images/ex_hash_setop_intersect_all.xpm"
36
#include "images/ex_hash_setop_unknown.xpm"
37
#include "images/ex_index_scan.xpm"
38
#include "images/ex_join.xpm"
39
#include "images/ex_limit.xpm"
40
#include "images/ex_materialize.xpm"
41
#include "images/ex_merge.xpm"
42
#include "images/ex_merge_anti_join.xpm"
43
#include "images/ex_merge_semi_join.xpm"
44
#include "images/ex_nested.xpm"
45
#include "images/ex_nested_loop_anti_join.xpm"
46
#include "images/ex_nested_loop_semi_join.xpm"
47
#include "images/ex_recursive_union.xpm"
48
#include "images/ex_result.xpm"
49
#include "images/ex_scan.xpm"
50
#include "images/ex_seek.xpm"
51
#include "images/ex_setop.xpm"
52
#include "images/ex_sort.xpm"
53
#include "images/ex_subplan.xpm"
54
#include "images/ex_tid_scan.xpm"
55
#include "images/ex_unique.xpm"
56
#include "images/ex_unknown.xpm"
57
#include "images/ex_window_aggregate.xpm"
58
#include "images/ex_worktable_scan.xpm"
23
#include "images/ex_aggregate.pngc"
24
#include "images/ex_append.pngc"
25
#include "images/ex_bmp_heap.pngc"
26
#include "images/ex_bmp_index.pngc"
27
#include "images/ex_cte_scan.pngc"
28
#include "images/ex_group.pngc"
29
#include "images/ex_hash.pngc"
30
#include "images/ex_hash_anti_join.pngc"
31
#include "images/ex_hash_semi_join.pngc"
32
#include "images/ex_hash_setop_except.pngc"
33
#include "images/ex_hash_setop_except_all.pngc"
34
#include "images/ex_hash_setop_intersect.pngc"
35
#include "images/ex_hash_setop_intersect_all.pngc"
36
#include "images/ex_hash_setop_unknown.pngc"
37
#include "images/ex_index_scan.pngc"
38
#include "images/ex_join.pngc"
39
#include "images/ex_limit.pngc"
40
#include "images/ex_materialize.pngc"
41
#include "images/ex_merge.pngc"
42
#include "images/ex_merge_anti_join.pngc"
43
#include "images/ex_merge_semi_join.pngc"
44
#include "images/ex_nested.pngc"
45
#include "images/ex_nested_loop_anti_join.pngc"
46
#include "images/ex_nested_loop_semi_join.pngc"
47
#include "images/ex_recursive_union.pngc"
48
#include "images/ex_result.pngc"
49
#include "images/ex_scan.pngc"
50
#include "images/ex_seek.pngc"
51
#include "images/ex_setop.pngc"
52
#include "images/ex_sort.pngc"
53
#include "images/ex_subplan.pngc"
54
#include "images/ex_tid_scan.pngc"
55
#include "images/ex_unique.pngc"
56
#include "images/ex_unknown.pngc"
57
#include "images/ex_window_aggregate.pngc"
58
#include "images/ex_worktable_scan.pngc"
60
60
// Greenplum images
61
#include "images/ex_broadcast_motion.xpm"
62
#include "images/ex_redistribute_motion.xpm"
63
#include "images/ex_gather_motion.xpm"
61
#include "images/ex_broadcast_motion.pngc"
62
#include "images/ex_redistribute_motion.pngc"
63
#include "images/ex_gather_motion.pngc"
65
65
#define BMP_BORDER 3
67
ExplainShape::ExplainShape(const char *bmp[], const wxString &description, long tokenNo, long detailNo)
67
ExplainShape::ExplainShape(const wxImage &bmp, const wxString &description, long tokenNo, long detailNo)
69
SetBitmap(wxBitmap(bmp));
70
SetLabel(description, tokenNo, detailNo);
69
SetBitmap(wxBitmap(bmp));
70
SetLabel(description, tokenNo, detailNo);
77
77
void ExplainShape::SetLabel(const wxString &str, int tokenNo, int detailNo)
86
wxStringTokenizer tokens(str, wxT(" "));
88
while (tokenNo-- >= 0)
90
label = tokens.GetNextToken();
94
if (!description.IsEmpty())
95
description.Append(wxT(" "));
97
description.Append(label);
102
tokens.SetString(str, wxT(" "));
106
if (!description.IsEmpty())
107
description.Append(wxT(" "));
109
description.Append(tokens.GetNextToken());
111
detail = tokens.GetString();
86
wxStringTokenizer tokens(str, wxT(" "));
88
while (tokenNo-- >= 0)
90
label = tokens.GetNextToken();
94
if (!description.IsEmpty())
95
description.Append(wxT(" "));
97
description.Append(label);
102
tokens.SetString(str, wxT(" "));
106
if (!description.IsEmpty())
107
description.Append(wxT(" "));
109
description.Append(tokens.GetNextToken());
111
detail = tokens.GetString();
116
void ExplainShape::OnDraw(wxDC& dc)
116
void ExplainShape::OnDraw(wxDC &dc)
118
wxBitmap &bmp=GetBitmap();
123
x = WXROUND(m_xpos - bmp.GetWidth() / 2.0);
124
y = WXROUND(m_ypos - GetHeight() / 2.0);
126
dc.DrawBitmap(bmp, x, y, true);
129
dc.SetFont(GetCanvas()->GetFont());
130
dc.GetTextExtent(label, &w, &h);
132
x = WXROUND(m_xpos - w / 2.0);
133
y +=bmp.GetHeight() + BMP_BORDER;
135
dc.DrawText(label, x, y);
118
wxBitmap &bmp = GetBitmap();
123
x = WXROUND(m_xpos - bmp.GetWidth() / 2.0);
124
y = WXROUND(m_ypos - GetHeight() / 2.0);
126
dc.DrawBitmap(bmp, x, y, true);
129
dc.SetFont(GetCanvas()->GetFont());
130
dc.GetTextExtent(label, &w, &h);
132
x = WXROUND(m_xpos - w / 2.0);
133
y += bmp.GetHeight() + BMP_BORDER;
135
dc.DrawText(label, x, y);
139
139
void ExplainShape::OnLeftClick(double x, double y, int keys, int attachment)
141
((ExplainCanvas*)GetCanvas())->ShowPopup(this);
141
((ExplainCanvas *)GetCanvas())->ShowPopup(this);
145
145
#define ARROWMARGIN 5
146
146
wxRealPoint ExplainShape::GetStartPoint()
148
wxRealPoint rp(GetX() + GetBitmap().GetWidth() / 2.0 + ARROWMARGIN, GetY() - (GetHeight()-GetBitmap().GetHeight()) / 2.);
148
wxRealPoint rp(GetX() + GetBitmap().GetWidth() / 2.0 + ARROWMARGIN, GetY() - (GetHeight() - GetBitmap().GetHeight()) / 2.);
153
153
wxRealPoint ExplainShape::GetEndPoint(int kidNo)
155
wxRealPoint rp(GetX() - GetBitmap().GetWidth() / 2.0 - ARROWMARGIN, GetY() - (GetHeight()-GetBitmap().GetHeight()) / 2. + (kidCount>1 ? GetBitmap().GetHeight() * 2. /3. * kidNo / (2*kidCount-2) : 0 ));
155
wxRealPoint rp(GetX() - GetBitmap().GetWidth() / 2.0 - ARROWMARGIN, GetY() - (GetHeight() - GetBitmap().GetHeight()) / 2. + (kidCount > 1 ? GetBitmap().GetHeight() * 2. / 3. * kidNo / (2 * kidCount - 2) : 0 ));
161
161
ExplainShape *ExplainShape::Create(long level, ExplainShape *last, const wxString &str)
165
int costPos=str.Find(wxT("(cost="));
166
int actPos = str.Find(wxT("(actual"));
168
wxStringTokenizer tokens(str, wxT(" "));
169
wxString token = tokens.GetNextToken();
170
wxString token2 = tokens.GetNextToken();
171
wxString token3 = tokens.GetNextToken();
173
if (tokens.HasMoreTokens())
174
token4 = tokens.GetNextToken();
177
descr = str.Left(costPos);
179
descr = str.Left(actPos);
183
// possible keywords can be found in postgresql/src/backend/commands/explain.c
185
if (token == wxT("Total")) return 0;
186
else if (token == wxT("Trigger")) return 0;
187
else if (token == wxT("Settings:")) return 0; /* Greenplum */
188
else if (token == wxT("Slice")) return 0; /* Greenplum */
189
else if (token.Mid(0,6) == wxT("(slice")) return 0; /* Greenplum */
190
else if (token == wxT("Result")) s = new ExplainShape(ex_result_xpm, descr);
191
else if (token == wxT("Append")) s = new ExplainShape(ex_append_xpm, descr);
192
else if (token == wxT("Nested"))
194
if (token2 == wxT("Loop") && token4 == wxT("Join"))
196
// Nested Loop Anti Join
197
if (token3 == wxT("Anti"))
199
s = new ExplainShape(ex_nested_loop_anti_join_xpm, descr);
201
// Nested Loop Semi Join
204
s = new ExplainShape(ex_nested_loop_semi_join_xpm, descr);
208
s = new ExplainShape(ex_nested_xpm, descr);
210
else if (token == wxT("Merge"))
212
if (token3 == wxT("Join"))
215
if (token2 == wxT("Anti"))
217
s = new ExplainShape(ex_merge_anti_join_xpm, descr);
222
s = new ExplainShape(ex_merge_semi_join_xpm, descr);
227
s = new ExplainShape(ex_merge_xpm, descr);
230
else if (token == wxT("Hash"))
232
if (token2 == wxT("Join"))
234
s = new ExplainShape(ex_join_xpm, descr);
238
if (token3 == wxT("Join"))
241
if (token2 == wxT("Anti"))
243
s = new ExplainShape(ex_hash_anti_join_xpm, descr);
246
else if (token2 == wxT("Semi"))
248
s = new ExplainShape(ex_hash_semi_join_xpm, descr);
252
s = new ExplainShape(ex_hash_xpm, descr);
257
s = new ExplainShape(ex_hash_xpm, descr);
261
else if (token == wxT("HashSetOp"))
263
if (token2 == wxT("Except"))
265
// HashSetOp Except ALL
266
if (token3 == wxT("ALL"))
268
s = new ExplainShape(ex_hash_setop_except_all_xpm, descr);
273
s = new ExplainShape(ex_hash_setop_except_xpm, descr);
276
else if (token2 == wxT("Intersect"))
278
// HashSetOp Intersect ALL
279
if (token3 == wxT("ALL"))
281
s = new ExplainShape(ex_hash_setop_intersect_all_xpm, descr);
283
// HashSetOp Intersect
286
s = new ExplainShape(ex_hash_setop_intersect_xpm, descr);
292
s = new ExplainShape(ex_hash_setop_unknown_xpm, descr);
295
else if (token == wxT("Subquery")) s = new ExplainShape(ex_subplan_xpm, descr, 0, 2);
296
else if (token == wxT("Function")) s = new ExplainShape(ex_result_xpm, descr, 0, 2);
297
else if (token == wxT("Materialize")) s = new ExplainShape(ex_materialize_xpm, descr);
298
else if (token == wxT("Sort")) s = new ExplainShape(ex_sort_xpm, descr);
299
else if (token == wxT("Group")) s = new ExplainShape(ex_group_xpm, descr);
300
else if (token == wxT("Aggregate") || token == wxT("GroupAggregate") || token == wxT("HashAggregate"))
301
s = new ExplainShape(ex_aggregate_xpm, descr);
302
else if (token == wxT("Unique")) s = new ExplainShape(ex_unique_xpm, descr);
303
else if (token == wxT("SetOp")) s = new ExplainShape(ex_setop_xpm, descr);
304
else if (token == wxT("Limit")) s = new ExplainShape(ex_limit_xpm, descr);
305
else if (token == wxT("Bitmap"))
307
if (token2 == wxT("Index")) s = new ExplainShape(ex_bmp_index_xpm, descr, 4, 3);
308
else s = new ExplainShape(ex_bmp_heap_xpm, descr, 4, 3);
310
else if (token2 == wxT("Scan"))
312
if (token == wxT("Index"))
313
// Scan Index Backword
314
if (token3 == wxT("Backward"))
315
s = new ExplainShape(ex_index_scan_xpm, descr, 4, 3);
317
s = new ExplainShape(ex_index_scan_xpm, descr, 3, 2);
319
else if (token == wxT("Tid"))
320
s = new ExplainShape(ex_tid_scan_xpm, descr, 3, 2);
322
else if (token == wxT("WorkTable"))
323
s = new ExplainShape(ex_worktable_scan_xpm, descr, 3, 2);
325
else if (token == wxT("CTE"))
326
s = new ExplainShape(ex_cte_scan_xpm, descr, 3, 2);
328
s = new ExplainShape(ex_scan_xpm, descr, 3, 2);
330
else if (token2 == wxT("Seek")) s = new ExplainShape(ex_seek_xpm, descr, 3, 2);
332
else if (token == wxT("Recursive") && token2 == wxT("Union"))
333
s = new ExplainShape(ex_recursive_union_xpm, descr);
334
else if (token == wxT("WindowAgg"))
335
s = new ExplainShape(ex_window_aggregate_xpm, descr);
337
// Greenplum additions
338
else if (token == wxT("Gather") && token2 ==wxT("Motion"))
339
s = new ExplainShape(ex_gather_motion_xpm, descr);
340
else if (token == wxT("Broadcast") && token2 ==wxT("Motion"))
341
s = new ExplainShape(ex_broadcast_motion_xpm, descr);
342
else if (token == wxT("Redistribute") && token2 ==wxT("Motion"))
343
s = new ExplainShape(ex_redistribute_motion_xpm, descr);
346
s = new ExplainShape(ex_unknown_xpm, descr);
348
s->SetDraggable(false);
356
s->actual = str.Mid(actPos);
357
s->cost = str.Mid(costPos, actPos-costPos);
360
s->cost = str.Mid(costPos);
363
s->actual = str.Mid(actPos);
367
wxBitmap &bmp=s->GetBitmap();
368
if (w < bmp.GetWidth())
371
s->SetHeight(bmp.GetHeight() + BMP_BORDER + h);
374
s->upperShape = last;
377
s->kidNo = last->kidCount;
385
wxChar *cl=(wxChar*)str.c_str() + costPos+6;
386
wxChar *ch=wxStrstr(cl, wxT(".."));
392
s->costLow = StrToDouble(cl);
395
wxChar *r=wxStrstr(ch, wxT(" rows="));
401
s->costHigh = StrToDouble(ch);
404
wxChar *w=wxStrstr(r, wxT(" width="));
410
s->rows = StrToLong(r);
412
s->width = StrToLong(w);
165
int costPos = str.Find(wxT("(cost="));
166
int actPos = str.Find(wxT("(actual"));
168
wxStringTokenizer tokens(str, wxT(" "));
169
wxString token = tokens.GetNextToken();
170
wxString token2 = tokens.GetNextToken();
171
wxString token3 = tokens.GetNextToken();
173
if (tokens.HasMoreTokens())
174
token4 = tokens.GetNextToken();
177
descr = str.Left(costPos);
179
descr = str.Left(actPos);
183
// possible keywords can be found in postgresql/src/backend/commands/explain.c
185
if (token == wxT("Total")) return 0;
186
else if (token == wxT("Trigger")) return 0;
187
else if (token == wxT("Settings:")) return 0; /* Greenplum */
188
else if (token == wxT("Slice")) return 0; /* Greenplum */
189
else if (token.Mid(0, 6) == wxT("(slice")) return 0; /* Greenplum */
190
else if (token == wxT("Result")) s = new ExplainShape(*ex_result_png_img, descr);
191
else if (token == wxT("Append")) s = new ExplainShape(*ex_append_png_img, descr);
192
else if (token == wxT("Nested"))
194
if (token2 == wxT("Loop") && token4 == wxT("Join"))
196
// Nested Loop Anti Join
197
if (token3 == wxT("Anti"))
199
s = new ExplainShape(*ex_nested_loop_anti_join_png_img, descr);
201
// Nested Loop Semi Join
204
s = new ExplainShape(*ex_nested_loop_semi_join_png_img, descr);
208
s = new ExplainShape(*ex_nested_png_img, descr);
210
else if (token == wxT("Merge"))
212
if (token3 == wxT("Join"))
215
if (token2 == wxT("Anti"))
217
s = new ExplainShape(*ex_merge_anti_join_png_img, descr);
222
s = new ExplainShape(*ex_merge_semi_join_png_img, descr);
227
s = new ExplainShape(*ex_merge_png_img, descr);
230
else if (token == wxT("Hash"))
232
if (token2 == wxT("Join"))
234
s = new ExplainShape(*ex_join_png_img, descr);
238
if (token3 == wxT("Join"))
241
if (token2 == wxT("Anti"))
243
s = new ExplainShape(*ex_hash_anti_join_png_img, descr);
246
else if (token2 == wxT("Semi"))
248
s = new ExplainShape(*ex_hash_semi_join_png_img, descr);
252
s = new ExplainShape(*ex_hash_png_img, descr);
257
s = new ExplainShape(*ex_hash_png_img, descr);
261
else if (token == wxT("HashSetOp"))
263
if (token2 == wxT("Except"))
265
// HashSetOp Except ALL
266
if (token3 == wxT("ALL"))
268
s = new ExplainShape(*ex_hash_setop_except_all_png_img, descr);
273
s = new ExplainShape(*ex_hash_setop_except_png_img, descr);
276
else if (token2 == wxT("Intersect"))
278
// HashSetOp Intersect ALL
279
if (token3 == wxT("ALL"))
281
s = new ExplainShape(*ex_hash_setop_intersect_all_png_img, descr);
283
// HashSetOp Intersect
286
s = new ExplainShape(*ex_hash_setop_intersect_png_img, descr);
292
s = new ExplainShape(*ex_hash_setop_unknown_png_img, descr);
295
else if (token == wxT("Subquery")) s = new ExplainShape(*ex_subplan_png_img, descr, 0, 2);
296
else if (token == wxT("Function")) s = new ExplainShape(*ex_result_png_img, descr, 0, 2);
297
else if (token == wxT("Materialize")) s = new ExplainShape(*ex_materialize_png_img, descr);
298
else if (token == wxT("Sort")) s = new ExplainShape(*ex_sort_png_img, descr);
299
else if (token == wxT("Group")) s = new ExplainShape(*ex_group_png_img, descr);
300
else if (token == wxT("Aggregate") || token == wxT("GroupAggregate") || token == wxT("HashAggregate"))
301
s = new ExplainShape(*ex_aggregate_png_img, descr);
302
else if (token == wxT("Unique")) s = new ExplainShape(*ex_unique_png_img, descr);
303
else if (token == wxT("SetOp")) s = new ExplainShape(*ex_setop_png_img, descr);
304
else if (token == wxT("Limit")) s = new ExplainShape(*ex_limit_png_img, descr);
305
else if (token == wxT("Bitmap"))
307
if (token2 == wxT("Index")) s = new ExplainShape(*ex_bmp_index_png_img, descr, 4, 3);
308
else s = new ExplainShape(*ex_bmp_heap_png_img, descr, 4, 3);
310
else if (token2 == wxT("Scan"))
312
if (token == wxT("Index"))
313
// Scan Index Backword
314
if (token3 == wxT("Backward"))
315
s = new ExplainShape(*ex_index_scan_png_img, descr, 4, 3);
317
s = new ExplainShape(*ex_index_scan_png_img, descr, 3, 2);
319
else if (token == wxT("Tid"))
320
s = new ExplainShape(*ex_tid_scan_png_img, descr, 3, 2);
322
else if (token == wxT("WorkTable"))
323
s = new ExplainShape(*ex_worktable_scan_png_img, descr, 3, 2);
325
else if (token == wxT("CTE"))
326
s = new ExplainShape(*ex_cte_scan_png_img, descr, 3, 2);
328
s = new ExplainShape(*ex_scan_png_img, descr, 3, 2);
330
else if (token2 == wxT("Seek")) s = new ExplainShape(*ex_seek_png_img, descr, 3, 2);
332
else if (token == wxT("Recursive") && token2 == wxT("Union"))
333
s = new ExplainShape(*ex_recursive_union_png_img, descr);
334
else if (token == wxT("WindowAgg"))
335
s = new ExplainShape(*ex_window_aggregate_png_img, descr);
337
// Greenplum additions
338
else if (token == wxT("Gather") && token2 == wxT("Motion"))
339
s = new ExplainShape(*ex_gather_motion_png_img, descr);
340
else if (token == wxT("Broadcast") && token2 == wxT("Motion"))
341
s = new ExplainShape(*ex_broadcast_motion_png_img, descr);
342
else if (token == wxT("Redistribute") && token2 == wxT("Motion"))
343
s = new ExplainShape(*ex_redistribute_motion_png_img, descr);
346
s = new ExplainShape(*ex_unknown_png_img, descr);
348
s->SetDraggable(false);
356
s->actual = str.Mid(actPos);
357
s->cost = str.Mid(costPos, actPos - costPos);
360
s->cost = str.Mid(costPos);
363
s->actual = str.Mid(actPos);
367
wxBitmap &bmp = s->GetBitmap();
368
if (w < bmp.GetWidth())
371
s->SetHeight(bmp.GetHeight() + BMP_BORDER + h);
374
s->upperShape = last;
377
s->kidNo = last->kidCount;
385
wxChar *cl = const_cast<wxChar *>((const wxChar *)str + costPos + 6);
386
wxChar *ch = wxStrstr(cl, wxT(".."));
392
s->costLow = StrToDouble(cl);
395
wxChar *r = wxStrstr(ch, wxT(" rows="));
401
s->costHigh = StrToDouble(ch);
404
wxChar *w = wxStrstr(r, wxT(" width="));
410
s->rows = StrToLong(r);
412
s->width = StrToLong(w);
420
420
ExplainLine::ExplainLine(ExplainShape *from, ExplainShape *to, double weight)
422
SetCanvas(from->GetCanvas());
423
from->AddLine(this, to);
424
MakeLineControlPoints(4);
426
width = (int) log(from->GetAverageCost());
430
// If we got an average cost of 0, width is probably negative
431
// which will look pretty darn ugly as an arrow width!
432
// This may happen on Greenplum.
436
wxNode *first = GetLineControlPoints()->GetFirst();
437
wxNode *last = GetLineControlPoints()->GetLast();
438
*(wxRealPoint *)first->GetData() = from->GetStartPoint();
439
*(wxRealPoint *)last->GetData() = to->GetEndPoint(from->GetKidno());
441
wxRealPoint *p1=(wxRealPoint *)first->GetNext()->GetData();
442
wxRealPoint *p2=(wxRealPoint *)last->GetPrevious()->GetData();
443
*p1 = from->GetStartPoint();
444
*p2 = to->GetEndPoint(from->GetKidno());
445
p1->x -= (p1->x - p2->x)/3. +8;
446
p2->x += (p1->x - p2->x)/3. -8;
422
SetCanvas(from->GetCanvas());
423
from->AddLine(this, to);
424
MakeLineControlPoints(4);
426
width = (int) log(from->GetAverageCost());
430
// If we got an average cost of 0, width is probably negative
431
// which will look pretty darn ugly as an arrow width!
432
// This may happen on Greenplum.
436
wxNode *first = GetLineControlPoints()->GetFirst();
437
wxNode *last = GetLineControlPoints()->GetLast();
438
*(wxRealPoint *)first->GetData() = from->GetStartPoint();
439
*(wxRealPoint *)last->GetData() = to->GetEndPoint(from->GetKidno());
441
wxRealPoint *p1 = (wxRealPoint *)first->GetNext()->GetData();
442
wxRealPoint *p2 = (wxRealPoint *)last->GetPrevious()->GetData();
443
*p1 = from->GetStartPoint();
444
*p2 = to->GetEndPoint(from->GetKidno());
445
p1->x -= (p1->x - p2->x) / 3. + 8;
446
p2->x += (p1->x - p2->x) / 3. - 8;
452
452
#define ARROWWIDTH 4
455
void ExplainLine::OnDraw(wxDC& dc)
455
void ExplainLine::OnDraw(wxDC &dc)
457
if (m_lineControlPoints)
459
dc.SetPen(*wxThePenList->FindOrCreatePen(*wxBLACK, 1, wxSOLID));
460
dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(*wxLIGHT_GREY, wxSOLID));
462
wxPoint *points = new wxPoint[11];
463
wxRealPoint *point0 = (wxRealPoint*) m_lineControlPoints->Item(0)->GetData();
464
wxRealPoint *point1 = (wxRealPoint*) m_lineControlPoints->Item(1)->GetData();
465
wxRealPoint *point2 = (wxRealPoint*) m_lineControlPoints->Item(2)->GetData();
466
wxRealPoint *point3 = (wxRealPoint*) m_lineControlPoints->Item(3)->GetData();
468
double phi = atan2(point2->y - point1->y, point2->x - point1->x);
469
double offs = width * tan(phi/2);
471
points[0].x = WXROUND(point0->x);
472
points[0].y = WXROUND(point0->y) - width;
473
points[10].x = WXROUND(point0->x);
474
points[10].y = WXROUND(point0->y) + width;
476
points[1].x = WXROUND(point1->x + offs);
477
points[1].y = WXROUND(point1->y) - width;
478
points[9].x = WXROUND(point1->x - offs);
479
points[9].y = WXROUND(point1->y) + width;
481
points[2].x = WXROUND(point2->x + offs);
482
points[2].y = WXROUND(point2->y) - width;
483
points[8].x = WXROUND(point2->x - offs);
484
points[8].y = WXROUND(point2->y) + width;
486
points[3].x = WXROUND(point3->x) - width - ARROWWIDTH;
487
points[3].y = WXROUND(point3->y) - width;
488
points[7].x = WXROUND(point3->x) - width - ARROWWIDTH;
489
points[7].y = WXROUND(point3->y) + width;
491
points[4].x = points[3].x;
492
points[4].y = points[3].y - ARROWWIDTH;
493
points[6].x = points[7].x;
494
points[6].y = points[7].y + ARROWWIDTH;
496
points[5].x = WXROUND(point3->x);
497
points[5].y = WXROUND(point3->y);
499
dc.DrawPolygon(11, points, 0, 0);
457
if (m_lineControlPoints)
459
dc.SetPen(*wxThePenList->FindOrCreatePen(*wxBLACK, 1, wxSOLID));
460
dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(*wxLIGHT_GREY, wxSOLID));
462
wxPoint *points = new wxPoint[11];
463
wxRealPoint *point0 = (wxRealPoint *) m_lineControlPoints->Item(0)->GetData();
464
wxRealPoint *point1 = (wxRealPoint *) m_lineControlPoints->Item(1)->GetData();
465
wxRealPoint *point2 = (wxRealPoint *) m_lineControlPoints->Item(2)->GetData();
466
wxRealPoint *point3 = (wxRealPoint *) m_lineControlPoints->Item(3)->GetData();
468
double phi = atan2(point2->y - point1->y, point2->x - point1->x);
469
double offs = width * tan(phi / 2);
471
points[0].x = WXROUND(point0->x);
472
points[0].y = WXROUND(point0->y) - width;
473
points[10].x = WXROUND(point0->x);
474
points[10].y = WXROUND(point0->y) + width;
476
points[1].x = WXROUND(point1->x + offs);
477
points[1].y = WXROUND(point1->y) - width;
478
points[9].x = WXROUND(point1->x - offs);
479
points[9].y = WXROUND(point1->y) + width;
481
points[2].x = WXROUND(point2->x + offs);
482
points[2].y = WXROUND(point2->y) - width;
483
points[8].x = WXROUND(point2->x - offs);
484
points[8].y = WXROUND(point2->y) + width;
486
points[3].x = WXROUND(point3->x) - width - ARROWWIDTH;
487
points[3].y = WXROUND(point3->y) - width;
488
points[7].x = WXROUND(point3->x) - width - ARROWWIDTH;
489
points[7].y = WXROUND(point3->y) + width;
491
points[4].x = points[3].x;
492
points[4].y = points[3].y - ARROWWIDTH;
493
points[6].x = points[7].x;
494
points[6].y = points[7].y + ARROWWIDTH;
496
points[5].x = WXROUND(point3->x);
497
points[5].y = WXROUND(point3->y);
499
dc.DrawPolygon(11, points, 0, 0);