wxRectTracker
|
00001 /* **************************************************************************** 00002 * LineTracker.cpp * 00003 * * 00004 * (c) 2004-2012 - Rémi Peyronnet <remi+rphoto@via.ecp.fr> * 00005 * LineTracker was originally designed for RPhoto, but can be used separately * 00006 * * 00007 * Licence : wxWindows (based on L-GPL) * 00008 * * 00009 * ************************************************************************** */ 00010 00011 00012 #include "LineTracker.h" 00013 #include <wx/dcbuffer.h> 00014 00015 /// Helpers 00016 00017 static wxRect NormalizeRect(wxRect rect) 00018 { 00019 if (rect.width < 0) { rect.x += rect.width ; rect.width = -rect.width; } 00020 if (rect.height < 0) { rect.y += rect.height ; rect.height = -rect.height; } 00021 return rect; 00022 } 00023 00024 /// wxLineTracker 00025 00026 IMPLEMENT_CLASS(wxLineTracker, wxRectTracker) 00027 00028 wxLineTracker::wxLineTracker(wxWindow * parent, wxFrame * frame) 00029 : wxRectTracker(parent, frame) 00030 { 00031 } 00032 00033 wxLineTracker::~wxLineTracker() 00034 { 00035 } 00036 00037 00038 void wxLineTracker::OnPaint(wxPaintEvent & event) 00039 { 00040 if ((m_state & RT_STATE_DISABLED) != 0) return; 00041 if ((m_state & RT_STATE_DRAGGING) != 0) return; 00042 this->GetNextHandler()->ProcessEvent(event); 00043 wxClientDC dc(m_wnd); 00044 if (wxDynamicCast(m_wnd,wxScrolledWindow)) 00045 { 00046 wxDynamicCast(m_wnd,wxScrolledWindow)->DoPrepareDC(dc); 00047 } 00048 DrawLine(dc, GetPosBegin(), GetPosEnd()); 00049 } 00050 00051 // DrawLine operates with a wxPaintDC => Window coordinates 00052 void wxLineTracker::DrawLine(wxDC & dc, wxPoint begin, wxPoint end) 00053 { 00054 // Rect 00055 dc.SetBrush(*wxTRANSPARENT_BRUSH); 00056 dc.SetPen(*wxBLACK_PEN); 00057 dc.DrawLine(begin.x, begin.y, end.x, end.y); 00058 dc.SetPen(wxPen(*wxWHITE,1,wxDOT)); 00059 dc.DrawLine(begin.x, begin.y, end.x, end.y); 00060 00061 // Handlers 00062 int z = m_iHandlerWidth; 00063 if (m_iHandlerMask != RT_MASK_NONE) 00064 { 00065 dc.SetBrush(*wxBLACK_BRUSH); 00066 dc.SetPen(*wxBLACK_PEN); 00067 00068 if (m_iHandlerMask & RT_LINE_MASK_BEGIN) dc.DrawRectangle(begin.x-(z/2), begin.y-(z/2), z, z); 00069 if (m_iHandlerMask & RT_LINE_MASK_END ) dc.DrawRectangle(end.x-(z/2), end.y-(z/2), z, z); 00070 } 00071 } 00072 00073 // DrawTracker operates with the parent's wxWindowDC => Parent coordinates 00074 void wxLineTracker::DrawTracker(wxDC & dc, wxPoint begin, wxPoint end) 00075 { 00076 00077 int x1, y1, x2, y2; 00078 x1 = begin.x; y1 = begin.y; 00079 x2 = end.x; y2 = end.y; 00080 // Convert coordinates if scrolled 00081 if (wxDynamicCast(m_wnd,wxScrolledWindow) != NULL) 00082 { 00083 wxDynamicCast(m_wnd,wxScrolledWindow)->CalcScrolledPosition(x1, y1, &x1, &y1); 00084 wxDynamicCast(m_wnd,wxScrolledWindow)->CalcScrolledPosition(x2, y2, &x2, &y2); 00085 } 00086 00087 // Inverted Line 00088 dc.SetLogicalFunction(wxINVERT); 00089 dc.SetBrush(*wxTRANSPARENT_BRUSH); 00090 dc.SetPen(*wxGREY_PEN); 00091 dc.DrawLine(begin.x,begin.y,end.x,end.y); 00092 dc.SetLogicalFunction(wxCOPY); 00093 } 00094 00095 00096 void wxLineTracker::OnKey(wxKeyEvent & event) 00097 { 00098 00099 if ((m_state & RT_STATE_DISABLED) != 0) return; 00100 00101 int incr = 0, dx = 0, dy = 0; 00102 int handler; 00103 wxRect tmpRect; 00104 tmpRect = GetUnscrolledRect(); 00105 00106 if (event.ControlDown()) incr = 10; else incr = 1; 00107 00108 switch(event.GetKeyCode()) 00109 { 00110 case WXK_ESCAPE : 00111 if ((m_state & RT_STATE_MOUSE_CAPTURED) != 0) 00112 { 00113 m_wnd->ReleaseMouse(); 00114 m_state ^= RT_STATE_MOUSE_CAPTURED; 00115 Update(); 00116 } 00117 else 00118 { 00119 Hide(); 00120 } 00121 break; 00122 case WXK_LEFT : dx -= incr; break; 00123 case WXK_UP : dy -= incr; break; 00124 case WXK_RIGHT : dx += incr; break; 00125 case WXK_DOWN : dy += incr; break; 00126 default: 00127 event.Skip(); 00128 } 00129 00130 if ((dx != 0) || (dy != 0)) 00131 { 00132 if (event.ShiftDown()) 00133 { 00134 m_pCurEnd.x += dx; 00135 m_pCurEnd.y += dy; 00136 handler = RT_LINE_HANDLER_END; 00137 } 00138 else 00139 { 00140 m_pCurBegin.x += dx; m_pCurEnd.x += dx; 00141 m_pCurBegin.y += dy; m_pCurEnd.y += dy; 00142 handler = 0; 00143 } 00144 AdjustLineTracker(m_pCurBegin, m_pCurEnd, handler); 00145 SetTrackerPosition(m_pCurBegin, m_pCurEnd); 00146 Update(); 00147 } 00148 00149 } 00150 00151 void wxLineTracker::OnMouseMotion(wxMouseEvent & event) 00152 { 00153 int hit; 00154 int dx, dy; 00155 00156 if ((m_state & RT_STATE_DISABLED) != 0) return; 00157 00158 // Just moving ? 00159 if (!event.Dragging()) 00160 { 00161 hit = HitTest(event.m_x, event.m_y); 00162 switch (hit) 00163 { 00164 case RT_LINE_HANDLER_END: 00165 case RT_LINE_HANDLER_BEGIN: 00166 case RT_LINE_HANDLER_ON_LINE: 00167 m_wnd->SetCursor(*m_cursorMove); 00168 break; 00169 default: 00170 m_wnd->SetCursor(wxCursor(wxCURSOR_ARROW)); 00171 break; 00172 } 00173 } 00174 else if (event.LeftIsDown()) 00175 { 00176 // Dragging 00177 00178 wxASSERT(m_wnd!=NULL); 00179 00180 // Drawing Tracker Rect 00181 wxClientDC dc(m_wnd); 00182 00183 if ((m_state & RT_STATE_DRAGGING) == 0) 00184 { 00185 m_state |= RT_STATE_DRAGGING; 00186 m_pCurBegin = GetPosBegin(); 00187 m_pCurEnd = GetPosEnd(); 00188 } 00189 else 00190 { 00191 // Erase previous Tracker 00192 DrawTracker(dc, m_pCurBegin, m_pCurEnd); 00193 } 00194 00195 // Update the new position 00196 // - Which Tracker ? 00197 hit = HitTest(m_leftClick.x, m_leftClick.y); 00198 // - Default Rect values 00199 00200 dx = (event.m_x - m_leftClick.x); 00201 dy = (event.m_y - m_leftClick.y); 00202 00203 if ( (hit & RT_LINE_HANDLER_BEGIN) != 0) 00204 { 00205 m_pCurBegin.x = GetPosBegin().x + dx; 00206 m_pCurBegin.y = GetPosBegin().y + dy; 00207 } 00208 if ( (hit & RT_LINE_HANDLER_END) != 0) 00209 { 00210 m_pCurEnd.x = GetPosEnd().x + dx; 00211 m_pCurEnd.y = GetPosEnd().y + dy; 00212 } 00213 00214 // Adjust current Tracker size 00215 AdjustLineTracker(m_pCurBegin, m_pCurEnd, hit); 00216 00217 // Draw current Tracker 00218 DrawTracker(dc, m_pCurBegin, m_pCurEnd); 00219 00220 // Update Parent's Status Bar 00221 wxCommandEvent evt(wxEVT_TRACKER_CHANGING, m_wnd->GetId()); 00222 m_wnd->GetEventHandler()->ProcessEvent(evt); 00223 00224 //dc.EndDrawingOnTop(); 00225 } 00226 00227 // Check there is no abuse mouse capture 00228 if (!(event.LeftIsDown()) && ((m_state & RT_STATE_MOUSE_CAPTURED) != 0)) 00229 { 00230 m_wnd->ReleaseMouse(); 00231 m_state ^= RT_STATE_MOUSE_CAPTURED; 00232 } 00233 00234 // Update prev_move 00235 m_prevMove = event.GetPosition(); 00236 } 00237 00238 void wxLineTracker::OnMouseLeftDown(wxMouseEvent & event) 00239 { 00240 if (HitTest(event.m_x, event.m_y) == RT_LINE_HANDLER_NONE) 00241 { 00242 m_pCurBegin = wxPoint(event.m_x, event.m_y); 00243 m_pCurEnd = m_pCurBegin; 00244 SetTrackerPosition(m_pCurBegin, m_pCurEnd); 00245 } 00246 wxRectTracker::OnMouseLeftDown(event); 00247 } 00248 00249 void wxLineTracker::OnMouseLeftUp(wxMouseEvent & event) 00250 { 00251 if ((m_state & RT_STATE_MOUSE_CAPTURED) != 0) 00252 { 00253 m_wnd->ReleaseMouse(); 00254 m_state ^= RT_STATE_MOUSE_CAPTURED; 00255 } 00256 if ((m_state & RT_STATE_DRAGGING) != 0) 00257 { 00258 SetTrackerPosition(m_pCurBegin, m_pCurEnd); 00259 m_state ^= RT_STATE_DRAGGING; 00260 Update(); 00261 } 00262 } 00263 00264 int wxLineTracker::HitTest(int x, int y) const 00265 { 00266 wxRect curRect; 00267 int z = m_iHandlerWidth; 00268 int hit; 00269 00270 hit = wxRectTracker::HitTest(x, y); 00271 00272 // if ( (y < 0) || (y > h) || (x < 0) || (x > w) ) return RT_HANDLER_OUTSIDE; 00273 00274 if ( hit == m_iEndHandler) return RT_LINE_HANDLER_END; 00275 if ( hit == m_iBeginHandler) return RT_LINE_HANDLER_BEGIN; 00276 00277 // Distance entre le point et le segment (a = begin ; b = end ; c = x,y ) 00278 int xac = x - GetPosBegin().x; // + m_Rect.GetPosition().x; 00279 int yac = y - GetPosBegin().y; // + m_Rect.GetPosition().y; 00280 int xab = GetPosEnd().x - GetPosBegin().x; 00281 int yab = GetPosEnd().y - GetPosBegin().y; 00282 00283 if ( (xab != 0) || (yab != 0) ) 00284 if ( ( (((double) - xac * yab + yac * xab ) * ((double) - xac * yab + yac * xab )) 00285 / ((double) (xab * xab) + (yab * yab)) 00286 ) < ((double) z * z) ) 00287 return RT_LINE_HANDLER_ON_LINE; 00288 00289 return RT_HANDLER_NONE; 00290 } 00291 00292 void wxLineTracker::AdjustLineTracker(wxPoint & begin, wxPoint & end, int handler) 00293 { 00294 AdjustLineTrackerMax(begin, end, handler); 00295 } 00296 00297 void wxLineTracker::AdjustLineTrackerMax(wxPoint & begin, wxPoint & end, int handler) 00298 { 00299 00300 // Adjust m_maxRect 00301 if ((m_maxRect.width < 0) || (m_maxRect.height < 0)) return; 00302 00303 if (begin.x < m_maxRect.x) begin.x = m_maxRect.x; 00304 if (begin.x > m_maxRect.x + m_maxRect.width) begin.x = m_maxRect.x + m_maxRect.width; 00305 if (begin.y < m_maxRect.y) begin.y = m_maxRect.y; 00306 if (begin.y > m_maxRect.y + m_maxRect.height) begin.y = m_maxRect.x + m_maxRect.height; 00307 00308 if (end.x < m_maxRect.x) end.x = m_maxRect.x; 00309 if (end.x > m_maxRect.x + m_maxRect.width) end.x = m_maxRect.x + m_maxRect.width; 00310 if (end.y < m_maxRect.y) end.y = m_maxRect.y; 00311 if (end.y > m_maxRect.y + m_maxRect.height) end.y = m_maxRect.x + m_maxRect.height; 00312 00313 } 00314 00315 void wxLineTracker::SetTrackerPosition(wxPoint begin, wxPoint end) 00316 { 00317 if (begin.x <= end.x) 00318 { 00319 if (begin.y <= end.y) 00320 { 00321 m_iBeginHandler = RT_HANDLER_TOP_LEFT; 00322 m_iEndHandler = RT_HANDLER_BOTTOM_RIGHT; 00323 } 00324 else 00325 { 00326 m_iBeginHandler = RT_HANDLER_BOTTOM_LEFT; 00327 m_iEndHandler = RT_HANDLER_TOP_RIGHT; 00328 } 00329 } 00330 else 00331 { 00332 if (begin.y <= end.y) 00333 { 00334 m_iBeginHandler = RT_HANDLER_TOP_RIGHT; 00335 m_iEndHandler = RT_HANDLER_BOTTOM_LEFT; 00336 } 00337 else 00338 { 00339 m_iBeginHandler = RT_HANDLER_BOTTOM_RIGHT; 00340 m_iEndHandler = RT_HANDLER_TOP_LEFT; 00341 } 00342 } 00343 SetUnscrolledRect(NormalizeRect(wxRect(begin, end))); 00344 } 00345 00346 00347 void wxLineTracker::Update() 00348 { 00349 m_wnd->Refresh(); 00350 wxCommandEvent evt(wxEVT_TRACKER_CHANGED, m_wnd->GetId()); 00351 m_wnd->GetEventHandler()->ProcessEvent(evt); 00352 } 00353 00354 wxPoint wxLineTracker::GetPosBegin() const 00355 { 00356 return GetPosHandler(m_iBeginHandler); 00357 } 00358 00359 wxPoint wxLineTracker::GetPosEnd() const 00360 { 00361 return GetPosHandler(m_iEndHandler); 00362 } 00363 00364 wxPoint wxLineTracker::GetPosHandler(enum RT_HANDLER handler) const 00365 { 00366 wxPoint pos; 00367 switch(handler) 00368 { 00369 case RT_HANDLER_TOP_MID: pos = wxPoint(m_Rect.GetWidth() / 2, 0); break; 00370 case RT_HANDLER_MID_RIGHT: pos = wxPoint(m_Rect.GetWidth() - 1, m_Rect.GetHeight() / 2); break; 00371 case RT_HANDLER_BOTTOM_MID: pos = wxPoint(m_Rect.GetWidth() / 2, m_Rect.GetHeight() - 1); break; 00372 case RT_HANDLER_MID_LEFT: pos = wxPoint(0, m_Rect.GetHeight() / 2); break; 00373 case RT_HANDLER_TOP_LEFT: pos = wxPoint(0, 0); break; 00374 case RT_HANDLER_TOP_RIGHT: pos = wxPoint(m_Rect.GetWidth() - 1, 0); break; 00375 case RT_HANDLER_BOTTOM_RIGHT: pos = wxPoint(m_Rect.GetWidth() - 1, m_Rect.GetHeight() - 1); break; 00376 case RT_HANDLER_BOTTOM_LEFT: pos = wxPoint(0, m_Rect.GetHeight() - 1); break; 00377 case RT_HANDLER_OUTSIDE: 00378 case RT_HANDLER_NONE: 00379 default: 00380 return wxPoint(-1,-1); 00381 } 00382 return pos + m_Rect.GetPosition(); 00383 } 00384