home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / contrib / src / ogl / canvas.cpp < prev    next >
C/C++ Source or Header  |  2002-07-07  |  16KB  |  526 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        canvas.cpp
  3. // Purpose:     Shape canvas class
  4. // Author:      Julian Smart
  5. // Modified by:
  6. // Created:     12/07/98
  7. // RCS-ID:      $Id: canvas.cpp,v 1.6 2002/07/06 04:14:27 RD Exp $
  8. // Copyright:   (c) Julian Smart
  9. // Licence:       wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13. #pragma implementation "canvas.h"
  14. #endif
  15.  
  16. // For compilers that support precompilation, includes "wx.h".
  17. #include "wx/wxprec.h"
  18.  
  19. #ifdef __BORLANDC__
  20. #pragma hdrstop
  21. #endif
  22.  
  23. #ifndef WX_PRECOMP
  24. #include <wx/wx.h>
  25. #endif
  26.  
  27. #include <wx/wxexpr.h>
  28.  
  29. #ifdef new
  30. #undef new
  31. #endif
  32.  
  33. #if wxUSE_IOSTREAMH
  34. #include <iostream.h>
  35. #else
  36. #include <iostream>
  37. #endif
  38.  
  39. #include <ctype.h>
  40. #include <math.h>
  41. #include <stdlib.h>
  42.  
  43. #include <wx/ogl/basic.h>
  44. #include <wx/ogl/basicp.h>
  45. #include <wx/ogl/canvas.h>
  46. #include <wx/ogl/ogldiag.h>
  47. #include <wx/ogl/misc.h>
  48. #include <wx/ogl/lines.h>
  49. #include <wx/ogl/composit.h>
  50.  
  51. #define CONTROL_POINT_SIZE       6
  52.  
  53. // Control point types
  54. // Rectangle and most other shapes
  55. #define CONTROL_POINT_VERTICAL   1
  56. #define CONTROL_POINT_HORIZONTAL 2
  57. #define CONTROL_POINT_DIAGONAL   3
  58.  
  59. // Line
  60. #define CONTROL_POINT_ENDPOINT_TO 4
  61. #define CONTROL_POINT_ENDPOINT_FROM 5
  62. #define CONTROL_POINT_LINE       6
  63.  
  64. IMPLEMENT_DYNAMIC_CLASS(wxShapeCanvas, wxScrolledWindow)
  65.  
  66. BEGIN_EVENT_TABLE(wxShapeCanvas, wxScrolledWindow)
  67.     EVT_PAINT(wxShapeCanvas::OnPaint)
  68.     EVT_MOUSE_EVENTS(wxShapeCanvas::OnMouseEvent)
  69. END_EVENT_TABLE()
  70.  
  71. wxChar* wxShapeCanvasNameStr = wxT("shapeCanvas");
  72.  
  73. // Object canvas
  74. wxShapeCanvas::wxShapeCanvas(wxWindow *parent, wxWindowID id,
  75.                              const wxPoint& pos,
  76.                              const wxSize& size,
  77.                              long style,
  78.                              const wxString& name):
  79.   wxScrolledWindow(parent, id, pos, size, style, name)
  80. {
  81.   m_shapeDiagram = NULL;
  82.   m_dragState = NoDragging;
  83.   m_draggedShape = NULL;
  84.   m_oldDragX = 0;
  85.   m_oldDragY = 0;
  86.   m_firstDragX = 0;
  87.   m_firstDragY = 0;
  88.   m_checkTolerance = TRUE;
  89. }
  90.  
  91. wxShapeCanvas::~wxShapeCanvas()
  92. {
  93. }
  94.  
  95. void wxShapeCanvas::OnPaint(wxPaintEvent& event)
  96. {
  97.     wxPaintDC dc(this);
  98.  
  99.     PrepareDC(dc);
  100.  
  101.     dc.SetBackground(wxBrush(GetBackgroundColour(), wxSOLID));
  102.     dc.Clear();
  103.  
  104.     if (GetDiagram())
  105.         GetDiagram()->Redraw(dc);
  106. }
  107.  
  108. void wxShapeCanvas::OnMouseEvent(wxMouseEvent& event)
  109. {
  110.   wxClientDC dc(this);
  111.   PrepareDC(dc);
  112.  
  113.   wxPoint logPos(event.GetLogicalPosition(dc));
  114.  
  115.   double x, y;
  116.   x = (double) logPos.x;
  117.   y = (double) logPos.y;
  118.  
  119.   int keys = 0;
  120.   if (event.ShiftDown())
  121.     keys = keys | KEY_SHIFT;
  122.   if (event.ControlDown())
  123.     keys = keys | KEY_CTRL;
  124.  
  125.   bool dragging = event.Dragging();
  126.  
  127.   // Check if we're within the tolerance for mouse movements.
  128.   // If we're very close to the position we started dragging
  129.   // from, this may not be an intentional drag at all.
  130.   if (dragging)
  131.   {
  132.     int dx = abs(dc.LogicalToDeviceX((long) (x - m_firstDragX)));
  133.     int dy = abs(dc.LogicalToDeviceY((long) (y - m_firstDragY)));
  134.     if (m_checkTolerance && (dx <= GetDiagram()->GetMouseTolerance()) && (dy <= GetDiagram()->GetMouseTolerance()))
  135.     {
  136.       return;
  137.     }
  138.     else
  139.       // If we've ignored the tolerance once, then ALWAYS ignore
  140.       // tolerance in this drag, even if we come back within
  141.       // the tolerance range.
  142.       m_checkTolerance = FALSE;
  143.   }
  144.  
  145.   // Dragging - note that the effect of dragging is left entirely up
  146.   // to the object, so no movement is done unless explicitly done by
  147.   // object.
  148.   if (dragging && m_draggedShape && m_dragState == StartDraggingLeft)
  149.   {
  150.     m_dragState = ContinueDraggingLeft;
  151.  
  152.     // If the object isn't m_draggable, transfer message to canvas
  153.     if (m_draggedShape->Draggable())
  154.       m_draggedShape->GetEventHandler()->OnBeginDragLeft((double)x, (double)y, keys, m_draggedAttachment);
  155.     else
  156.     {
  157.       m_draggedShape = NULL;
  158.       OnBeginDragLeft((double)x, (double)y, keys);
  159.     }
  160.  
  161.     m_oldDragX = x; m_oldDragY = y;
  162.   }
  163.   else if (dragging && m_draggedShape && m_dragState == ContinueDraggingLeft)
  164.   {
  165.     // Continue dragging
  166.     m_draggedShape->GetEventHandler()->OnDragLeft(FALSE, m_oldDragX, m_oldDragY, keys, m_draggedAttachment);
  167.     m_draggedShape->GetEventHandler()->OnDragLeft(TRUE, (double)x, (double)y, keys, m_draggedAttachment);
  168.     m_oldDragX = x; m_oldDragY = y;
  169.   }
  170.   else if (event.LeftUp() && m_draggedShape && m_dragState == ContinueDraggingLeft)
  171.   {
  172.     m_dragState = NoDragging;
  173.     m_checkTolerance = TRUE;
  174.  
  175.     m_draggedShape->GetEventHandler()->OnDragLeft(FALSE, m_oldDragX, m_oldDragY, keys, m_draggedAttachment);
  176.  
  177.     m_draggedShape->GetEventHandler()->OnEndDragLeft((double)x, (double)y, keys, m_draggedAttachment);
  178.     m_draggedShape = NULL;
  179.   }
  180.   else if (dragging && m_draggedShape && m_dragState == StartDraggingRight)
  181.   {
  182.     m_dragState = ContinueDraggingRight;
  183.  
  184.     if (m_draggedShape->Draggable())
  185.       m_draggedShape->GetEventHandler()->OnBeginDragRight((double)x, (double)y, keys, m_draggedAttachment);
  186.     else
  187.     {
  188.       m_draggedShape = NULL;
  189.       OnBeginDragRight((double)x, (double)y, keys);
  190.     }
  191.     m_oldDragX = x; m_oldDragY = y;
  192.   }
  193.   else if (dragging && m_draggedShape && m_dragState == ContinueDraggingRight)
  194.   {
  195.     // Continue dragging
  196.     m_draggedShape->GetEventHandler()->OnDragRight(FALSE, m_oldDragX, m_oldDragY, keys, m_draggedAttachment);
  197.     m_draggedShape->GetEventHandler()->OnDragRight(TRUE, (double)x, (double)y, keys, m_draggedAttachment);
  198.     m_oldDragX = x; m_oldDragY = y;
  199.   }
  200.   else if (event.RightUp() && m_draggedShape && m_dragState == ContinueDraggingRight)
  201.   {
  202.     m_dragState = NoDragging;
  203.     m_checkTolerance = TRUE;
  204.  
  205.     m_draggedShape->GetEventHandler()->OnDragRight(FALSE, m_oldDragX, m_oldDragY, keys, m_draggedAttachment);
  206.  
  207.     m_draggedShape->GetEventHandler()->OnEndDragRight((double)x, (double)y, keys, m_draggedAttachment);
  208.     m_draggedShape = NULL;
  209.   }
  210.  
  211.   // All following events sent to canvas, not object
  212.   else if (dragging && !m_draggedShape && m_dragState == StartDraggingLeft)
  213.   {
  214.     m_dragState = ContinueDraggingLeft;
  215.     OnBeginDragLeft((double)x, (double)y, keys);
  216.     m_oldDragX = x; m_oldDragY = y;
  217.   }
  218.   else if (dragging && !m_draggedShape && m_dragState == ContinueDraggingLeft)
  219.   {
  220.     // Continue dragging
  221.     OnDragLeft(FALSE, m_oldDragX, m_oldDragY, keys);
  222.     OnDragLeft(TRUE, (double)x, (double)y, keys);
  223.     m_oldDragX = x; m_oldDragY = y;
  224.   }
  225.   else if (event.LeftUp() && !m_draggedShape && m_dragState == ContinueDraggingLeft)
  226.   {
  227.     m_dragState = NoDragging;
  228.     m_checkTolerance = TRUE;
  229.  
  230.     OnDragLeft(FALSE, m_oldDragX, m_oldDragY, keys);
  231.     OnEndDragLeft((double)x, (double)y, keys);
  232.     m_draggedShape = NULL;
  233.   }
  234.   else if (dragging && !m_draggedShape && m_dragState == StartDraggingRight)
  235.   {
  236.     m_dragState = ContinueDraggingRight;
  237.     OnBeginDragRight((double)x, (double)y, keys);
  238.     m_oldDragX = x; m_oldDragY = y;
  239.   }
  240.   else if (dragging && !m_draggedShape && m_dragState == ContinueDraggingRight)
  241.   {
  242.     // Continue dragging
  243.     OnDragRight(FALSE, m_oldDragX, m_oldDragY, keys);
  244.     OnDragRight(TRUE, (double)x, (double)y, keys);
  245.     m_oldDragX = x; m_oldDragY = y;
  246.   }
  247.   else if (event.RightUp() && !m_draggedShape && m_dragState == ContinueDraggingRight)
  248.   {
  249.     m_dragState = NoDragging;
  250.     m_checkTolerance = TRUE;
  251.  
  252.     OnDragRight(FALSE, m_oldDragX, m_oldDragY, keys);
  253.     OnEndDragRight((double)x, (double)y, keys);
  254.     m_draggedShape = NULL;
  255.   }
  256.  
  257.   // Non-dragging events
  258.   else if (event.IsButton())
  259.   {
  260.     m_checkTolerance = TRUE;
  261.  
  262.     // Find the nearest object
  263.     int attachment = 0;
  264.     wxShape *nearest_object = FindShape(x, y, &attachment);
  265.     if (nearest_object) // Object event
  266.     {
  267.       if (event.LeftDown())
  268.       {
  269.         m_draggedShape = nearest_object;
  270.         m_draggedAttachment = attachment;
  271.         m_dragState = StartDraggingLeft;
  272.         m_firstDragX = x;
  273.         m_firstDragY = y;
  274.       }
  275.       else if (event.LeftUp())
  276.       {
  277.         // N.B. Only register a click if the same object was
  278.         // identified for down *and* up.
  279.         if (nearest_object == m_draggedShape)
  280.           nearest_object->GetEventHandler()->OnLeftClick((double)x, (double)y, keys, attachment);
  281.  
  282.         m_draggedShape = NULL;
  283.         m_dragState = NoDragging;
  284.       }
  285.       else if (event.LeftDClick())
  286.       {
  287.         nearest_object->GetEventHandler()->OnLeftDoubleClick((double)x, (double)y, keys, attachment);
  288.  
  289.         m_draggedShape = NULL;
  290.         m_dragState = NoDragging;
  291.       }
  292.       else if (event.RightDown())
  293.       {
  294.         m_draggedShape = nearest_object;
  295.         m_draggedAttachment = attachment;
  296.         m_dragState = StartDraggingRight;
  297.         m_firstDragX = x;
  298.         m_firstDragY = y;
  299.       }
  300.       else if (event.RightUp())
  301.       {
  302.         if (nearest_object == m_draggedShape)
  303.           nearest_object->GetEventHandler()->OnRightClick((double)x, (double)y, keys, attachment);
  304.  
  305.         m_draggedShape = NULL;
  306.         m_dragState = NoDragging;
  307.       }
  308.     }
  309.     else // Canvas event (no nearest object)
  310.     {
  311.       if (event.LeftDown())
  312.       {
  313.         m_draggedShape = NULL;
  314.         m_dragState = StartDraggingLeft;
  315.         m_firstDragX = x;
  316.         m_firstDragY = y;
  317.       }
  318.       else if (event.LeftUp())
  319.       {
  320.         OnLeftClick((double)x, (double)y, keys);
  321.  
  322.         m_draggedShape = NULL;
  323.         m_dragState = NoDragging;
  324.       }
  325.       else if (event.RightDown())
  326.       {
  327.         m_draggedShape = NULL;
  328.         m_dragState = StartDraggingRight;
  329.         m_firstDragX = x;
  330.         m_firstDragY = y;
  331.       }
  332.       else if (event.RightUp())
  333.       {
  334.         OnRightClick((double)x, (double)y, keys);
  335.  
  336.         m_draggedShape = NULL;
  337.         m_dragState = NoDragging;
  338.       }
  339.     }
  340.   }
  341. }
  342.  
  343. /*
  344.  * Try to find a sensitive object, working up the hierarchy of composites.
  345.  *
  346.  */
  347. wxShape *wxShapeCanvas::FindFirstSensitiveShape(double x, double y, int *new_attachment, int op)
  348. {
  349.   wxShape *image = FindShape(x, y, new_attachment);
  350.   if (!image) return NULL;
  351.  
  352.   wxShape *actualImage = FindFirstSensitiveShape1(image, op);
  353.   if (actualImage)
  354.   {
  355.     double dist;
  356.     // Find actual attachment
  357.     actualImage->HitTest(x, y, new_attachment, &dist);
  358.   }
  359.   return actualImage;
  360. }
  361.  
  362. wxShape *wxShapeCanvas::FindFirstSensitiveShape1(wxShape *image, int op)
  363. {
  364.   if (image->GetSensitivityFilter() & op)
  365.     return image;
  366.   if (image->GetParent())
  367.     return FindFirstSensitiveShape1(image->GetParent(), op);
  368.   return NULL;
  369. }
  370.  
  371. // Helper function: TRUE if 'contains' wholly contains 'contained'.
  372. static bool WhollyContains(wxShape *contains, wxShape *contained)
  373. {
  374.   double xp1, yp1, xp2, yp2;
  375.   double w1, h1, w2, h2;
  376.   double left1, top1, right1, bottom1, left2, top2, right2, bottom2;
  377.  
  378.   xp1 = contains->GetX(); yp1 = contains->GetY(); xp2 = contained->GetX(); yp2 = contained->GetY();
  379.   contains->GetBoundingBoxMax(&w1, &h1);
  380.   contained->GetBoundingBoxMax(&w2, &h2);
  381.  
  382.   left1 = (double)(xp1 - (w1 / 2.0));
  383.   top1 = (double)(yp1 - (h1 / 2.0));
  384.   right1 = (double)(xp1 + (w1 / 2.0));
  385.   bottom1 = (double)(yp1 + (h1 / 2.0));
  386.  
  387.   left2 = (double)(xp2 - (w2 / 2.0));
  388.   top2 = (double)(yp2 - (h2 / 2.0));
  389.   right2 = (double)(xp2 + (w2 / 2.0));
  390.   bottom2 = (double)(yp2 + (h2 / 2.0));
  391.  
  392.   return ((left1 <= left2) && (top1 <= top2) && (right1 >= right2) && (bottom1 >= bottom2));
  393. }
  394.  
  395. wxShape *wxShapeCanvas::FindShape(double x, double y, int *attachment, wxClassInfo *info, wxShape *notObject)
  396. {
  397.   double nearest = 100000.0;
  398.   int nearest_attachment = 0;
  399.   wxShape *nearest_object = NULL;
  400.  
  401.   // Go backward through the object list, since we want:
  402.   // (a) to have the control points drawn LAST to overlay
  403.   //     the other objects
  404.   // (b) to find the control points FIRST if they exist
  405.  
  406.   wxNode *current = GetDiagram()->GetShapeList()->Last();
  407.   while (current)
  408.   {
  409.     wxShape *object = (wxShape *)current->Data();
  410.  
  411.     double dist;
  412.     int temp_attachment;
  413.  
  414.     // First pass for lines, which might be inside a container, so we
  415.     // want lines to take priority over containers. This first loop
  416.     // could fail if we clickout side a line, so then we'll
  417.     // try other shapes.
  418.     if (object->IsShown() &&
  419.         object->IsKindOf(CLASSINFO(wxLineShape)) &&
  420.         object->HitTest(x, y, &temp_attachment, &dist) &&
  421.         ((info == NULL) || object->IsKindOf(info)) &&
  422.         (!notObject || !notObject->HasDescendant(object)))
  423.     {
  424.       // A line is trickier to spot than a normal object.
  425.       // For a line, since it's the diagonal of the box
  426.       // we use for the hit test, we may have several
  427.       // lines in the box and therefore we need to be able
  428.       // to specify the nearest point to the centre of the line
  429.       // as our hit criterion, to give the user some room for
  430.       // manouevre.
  431.       if (dist < nearest)
  432.       {
  433.         nearest = dist;
  434.         nearest_object = object;
  435.         nearest_attachment = temp_attachment;
  436.       }
  437.     }
  438.     if (current)
  439.       current = current->Previous();
  440.   }
  441.  
  442.   current = GetDiagram()->GetShapeList()->Last();
  443.   while (current)
  444.   {
  445.     wxShape *object = (wxShape *)current->Data();
  446.     double dist;
  447.     int temp_attachment;
  448.  
  449.     // On second pass, only ever consider non-composites or divisions. If children want to pass
  450.     // up control to the composite, that's up to them.
  451.     if (object->IsShown() && (object->IsKindOf(CLASSINFO(wxDivisionShape)) || !object->IsKindOf(CLASSINFO(wxCompositeShape)))
  452.         && object->HitTest(x, y, &temp_attachment, &dist) && ((info == NULL) || object->IsKindOf(info)) &&
  453.         (!notObject || !notObject->HasDescendant(object)))
  454.     {
  455.       if (!object->IsKindOf(CLASSINFO(wxLineShape)))
  456.       {
  457.         // If we've hit a container, and we have already found a line in the
  458.         // first pass, then ignore the container in case the line is in the container.
  459.         // Check for division in case line straddles divisions (i.e. is not wholly contained).
  460.         if (!nearest_object || !(object->IsKindOf(CLASSINFO(wxDivisionShape)) || WhollyContains(object, nearest_object)))
  461.         {
  462.           nearest = dist;
  463.           nearest_object = object;
  464.           nearest_attachment = temp_attachment;
  465.           current = NULL;
  466.         }
  467.       }
  468.     }
  469.     if (current)
  470.       current = current->Previous();
  471.   }
  472.  
  473.   *attachment = nearest_attachment;
  474.   return nearest_object;
  475. }
  476.  
  477. /*
  478.  * Higher-level events called by OnEvent
  479.  *
  480.  */
  481.  
  482. void wxShapeCanvas::OnLeftClick(double x, double y, int keys)
  483. {
  484. }
  485.  
  486. void wxShapeCanvas::OnRightClick(double x, double y, int keys)
  487. {
  488. }
  489.  
  490. void wxShapeCanvas::OnDragLeft(bool draw, double x, double y, int keys)
  491. {
  492. }
  493.  
  494. void wxShapeCanvas::OnBeginDragLeft(double x, double y, int keys)
  495. {
  496. }
  497.  
  498. void wxShapeCanvas::OnEndDragLeft(double x, double y, int keys)
  499. {
  500. }
  501.  
  502. void wxShapeCanvas::OnDragRight(bool draw, double x, double y, int keys)
  503. {
  504. }
  505.  
  506. void wxShapeCanvas::OnBeginDragRight(double x, double y, int keys)
  507. {
  508. }
  509.  
  510. void wxShapeCanvas::OnEndDragRight(double x, double y, int keys)
  511. {
  512. }
  513.  
  514. void wxShapeCanvas::AddShape(wxShape *object, wxShape *addAfter)
  515.  { GetDiagram()->AddShape(object, addAfter); }
  516. void wxShapeCanvas::InsertShape(wxShape *object)
  517.  { GetDiagram()->InsertShape(object); }
  518. void wxShapeCanvas::RemoveShape(wxShape *object)
  519.  { GetDiagram()->RemoveShape(object); }
  520. bool wxShapeCanvas::GetQuickEditMode()
  521.  { return GetDiagram()->GetQuickEditMode(); }
  522. void wxShapeCanvas::Redraw(wxDC& dc)
  523.  { GetDiagram()->Redraw(dc); }
  524. void wxShapeCanvas::Snap(double *x, double *y)
  525.  { GetDiagram()->Snap(x, y); }
  526.