home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / contrib / samples / ogl / studio / doc.cpp < prev    next >
C/C++ Source or Header  |  2001-10-30  |  18KB  |  599 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        doc.cpp
  3. // Purpose:     Implements document functionality
  4. // Author:      Julian Smart
  5. // Modified by:
  6. // Created:     12/07/98
  7. // RCS-ID:      $Id: doc.cpp,v 1.2 2001/10/30 13:28:45 GT Exp $
  8. // Copyright:   (c) Julian Smart
  9. // Licence:       wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13. // #pragma implementation
  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. #include "studio.h"
  30. #include "doc.h"
  31. #include "view.h"
  32. #include <wx/ogl/basicp.h>
  33.  
  34. IMPLEMENT_DYNAMIC_CLASS(csDiagramDocument, wxDocument)
  35.  
  36. #ifdef _MSC_VER
  37. #pragma warning(disable:4355)
  38. #endif
  39.  
  40. csDiagramDocument::csDiagramDocument():m_diagram(this)
  41. {
  42. }
  43.  
  44. #ifdef _MSC_VER
  45. #pragma warning(default:4355)
  46. #endif
  47.  
  48. csDiagramDocument::~csDiagramDocument()
  49. {
  50. }
  51.  
  52. bool csDiagramDocument::OnCloseDocument()
  53. {
  54.   m_diagram.DeleteAllShapes();
  55.   return TRUE;
  56. }
  57.  
  58. bool csDiagramDocument::OnSaveDocument(const wxString& file)
  59. {
  60.   if (file == "")
  61.     return FALSE;
  62.  
  63.   if (!m_diagram.SaveFile(file))
  64.   {
  65.     wxString msgTitle;
  66.     if (wxTheApp->GetAppName() != "")
  67.         msgTitle = wxTheApp->GetAppName();
  68.     else
  69.         msgTitle = wxString("File error");
  70.  
  71.     (void)wxMessageBox("Sorry, could not open this file for saving.", msgTitle, wxOK | wxICON_EXCLAMATION,
  72.       GetDocumentWindow());
  73.     return FALSE;
  74.   }
  75.  
  76.   Modify(FALSE);
  77.   SetFilename(file);
  78.   return TRUE;
  79. }
  80.     
  81. bool csDiagramDocument::OnOpenDocument(const wxString& file)
  82. {
  83.   if (!OnSaveModified())
  84.     return FALSE;
  85.  
  86.   wxString msgTitle;
  87.   if (wxTheApp->GetAppName() != "")
  88.     msgTitle = wxTheApp->GetAppName();
  89.   else
  90.     msgTitle = wxString("File error");
  91.  
  92.   m_diagram.DeleteAllShapes();
  93.   if (!m_diagram.LoadFile(file))
  94.   {
  95.     (void)wxMessageBox("Sorry, could not open this file.", msgTitle, wxOK|wxICON_EXCLAMATION,
  96.      GetDocumentWindow());
  97.     return FALSE;
  98.   }
  99.   SetFilename(file, TRUE);
  100.   Modify(FALSE);
  101.   UpdateAllViews();
  102.   
  103.   return TRUE;
  104. }
  105.     
  106.  
  107. /*
  108.  * Implementation of drawing command
  109.  */
  110.  
  111. csDiagramCommand::csDiagramCommand(const wxString& name, csDiagramDocument *doc,
  112.     csCommandState* onlyState):
  113.   wxCommand(TRUE, name)
  114. {
  115.   m_doc = doc;
  116.  
  117.   if (onlyState)
  118.   {
  119.     AddState(onlyState);
  120.   }
  121. }
  122.  
  123. csDiagramCommand::~csDiagramCommand()
  124. {
  125.     wxNode* node = m_states.First();
  126.     while (node)
  127.     {
  128.         csCommandState* state = (csCommandState*) node->Data();
  129.         delete state;
  130.         node = node->Next();
  131.     }
  132. }
  133.  
  134. void csDiagramCommand::AddState(csCommandState* state)
  135. {
  136.     state->m_doc = m_doc;
  137. //    state->m_cmd = m_cmd;
  138.     m_states.Append(state);
  139. }
  140.  
  141. // Insert a state at the beginning of the list
  142. void csDiagramCommand::InsertState(csCommandState* state)
  143. {
  144.     state->m_doc = m_doc;
  145. //    state->m_cmd = m_cmd;
  146.     m_states.Insert(state);
  147. }
  148.  
  149. // Schedule all lines connected to the states to be cut.
  150. void csDiagramCommand::RemoveLines()
  151. {
  152.     wxNode* node = m_states.First();
  153.     while (node)
  154.     {
  155.         csCommandState* state = (csCommandState*) node->Data();
  156.         wxShape* shape = state->GetShapeOnCanvas();
  157.         wxASSERT( (shape != NULL) );
  158.  
  159.         wxNode *node1 = shape->GetLines().First();
  160.         while (node1)
  161.         {
  162.             wxLineShape *line = (wxLineShape *)node1->Data();
  163.             if (!FindStateByShape(line))
  164.             {
  165.                 csCommandState* newState = new csCommandState(ID_CS_CUT, NULL, line);
  166.                 InsertState(newState);
  167.             }
  168.  
  169.             node1 = node1->Next();
  170.         }
  171.         node = node->Next();
  172.     }
  173. }
  174.  
  175. csCommandState* csDiagramCommand::FindStateByShape(wxShape* shape)
  176. {
  177.     wxNode* node = m_states.First();
  178.     while (node)
  179.     {
  180.         csCommandState* state = (csCommandState*) node->Data();
  181.         if (shape == state->GetShapeOnCanvas() || shape == state->GetSavedState())
  182.             return state;
  183.         node = node->Next();
  184.     }
  185.     return NULL;
  186. }
  187.  
  188. bool csDiagramCommand::Do()
  189. {
  190.     wxNode* node = m_states.First();
  191.     while (node)
  192.     {
  193.         csCommandState* state = (csCommandState*) node->Data();
  194.         if (!state->Do())
  195.             return FALSE;
  196.         node = node->Next();
  197.     }
  198.     return TRUE;
  199. }
  200.  
  201. bool csDiagramCommand::Undo()
  202. {
  203.     // Undo in reverse order, so e.g. shapes get added
  204.     // back before the lines do.
  205.     wxNode* node = m_states.Last();
  206.     while (node)
  207.     {
  208.         csCommandState* state = (csCommandState*) node->Data();
  209.         if (!state->Undo())
  210.             return FALSE;
  211.         node = node->Previous();
  212.     }
  213.     return TRUE;
  214. }
  215.  
  216. csCommandState::csCommandState(int cmd, wxShape* savedState, wxShape* shapeOnCanvas)
  217. {
  218.     m_cmd = cmd;
  219.     m_doc = NULL;
  220.     m_savedState = savedState;
  221.     m_shapeOnCanvas = shapeOnCanvas;
  222.     m_linePositionFrom = 0;
  223.     m_linePositionTo = 0;
  224. }
  225.  
  226. csCommandState::~csCommandState()
  227. {
  228.     if (m_savedState)
  229.     {
  230.         m_savedState->SetCanvas(NULL);
  231.         delete m_savedState;
  232.     }
  233. }
  234.  
  235. bool csCommandState::Do()
  236. {
  237.   switch (m_cmd)
  238.   {
  239.     case ID_CS_CUT:
  240.     {
  241.         // New state is 'nothing' - maybe pass shape ID to state so we know what
  242.         // we're talking about.
  243.         // Then save old shape in m_savedState (actually swap pointers)
  244.  
  245.         wxASSERT( (m_shapeOnCanvas != NULL) );
  246.         wxASSERT( (m_savedState == NULL) ); // new state will be 'nothing'
  247.         wxASSERT( (m_doc != NULL) );
  248.  
  249.         wxShapeCanvas* canvas = m_shapeOnCanvas->GetCanvas();
  250.  
  251.         // In case this is a line
  252.         wxShape* lineFrom = NULL;
  253.         wxShape* lineTo = NULL;
  254.         int attachmentFrom = 0, attachmentTo = 0;
  255.  
  256.         if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
  257.         {
  258.             // Store the from/to info to save in the line shape
  259.             wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
  260.             lineFrom = lineShape->GetFrom();
  261.             lineTo = lineShape->GetTo();
  262.             attachmentFrom = lineShape->GetAttachmentFrom();
  263.             attachmentTo = lineShape->GetAttachmentTo();
  264.  
  265.             m_linePositionFrom = lineFrom->GetLinePosition(lineShape);
  266.             m_linePositionTo = lineTo->GetLinePosition(lineShape);
  267.         }
  268.  
  269.         m_shapeOnCanvas->Select(FALSE);
  270.         ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, FALSE);
  271.  
  272.         m_shapeOnCanvas->Unlink();
  273.         
  274.         m_doc->GetDiagram()->RemoveShape(m_shapeOnCanvas);
  275.  
  276.         m_savedState = m_shapeOnCanvas;
  277.  
  278.         if (m_savedState->IsKindOf(CLASSINFO(wxLineShape)))
  279.         {
  280.             // Restore the from/to info for future reference
  281.             wxLineShape* lineShape = (wxLineShape*) m_savedState;
  282.             lineShape->SetFrom(lineFrom);
  283.             lineShape->SetTo(lineTo);
  284.             lineShape->SetAttachments(attachmentFrom, attachmentTo);
  285.  
  286.             wxClientDC dc(canvas);
  287.             canvas->PrepareDC(dc);
  288.  
  289.             lineFrom->MoveLinks(dc);
  290.             lineTo->MoveLinks(dc);
  291.         }
  292.  
  293.         m_doc->Modify(TRUE);
  294.         m_doc->UpdateAllViews();
  295.         break;
  296.     }
  297.     case ID_CS_ADD_SHAPE:
  298.     case ID_CS_ADD_SHAPE_SELECT:
  299.     {
  300.         // The app has given the command state a new m_savedState
  301.         // shape, which is the new shape to add to the canvas (but
  302.         // not actually added until this point).
  303.         // The new 'saved state' is therefore 'nothing' since there
  304.         // was nothing there before.
  305.  
  306.         wxASSERT( (m_shapeOnCanvas == NULL) );
  307.         wxASSERT( (m_savedState != NULL) );
  308.         wxASSERT( (m_doc != NULL) );
  309.  
  310.         m_shapeOnCanvas = m_savedState;
  311.         m_savedState = NULL;
  312.  
  313.         m_doc->GetDiagram()->AddShape(m_shapeOnCanvas);
  314.         m_shapeOnCanvas->Show(TRUE);
  315.  
  316.         wxClientDC dc(m_shapeOnCanvas->GetCanvas());
  317.         m_shapeOnCanvas->GetCanvas()->PrepareDC(dc);
  318.  
  319.         csEvtHandler *handler = (csEvtHandler *)m_shapeOnCanvas->GetEventHandler();
  320.         m_shapeOnCanvas->FormatText(dc, handler->m_label);
  321.  
  322.         m_shapeOnCanvas->Move(dc, m_shapeOnCanvas->GetX(), m_shapeOnCanvas->GetY());
  323.  
  324.         if (m_cmd == ID_CS_ADD_SHAPE_SELECT)
  325.         {
  326.             m_shapeOnCanvas->Select(TRUE, &dc);
  327.             ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, TRUE);
  328.         }
  329.  
  330.         m_doc->Modify(TRUE);
  331.         m_doc->UpdateAllViews();
  332.         break;
  333.     }
  334.     case ID_CS_ADD_LINE:
  335.     case ID_CS_ADD_LINE_SELECT:
  336.     {
  337.         wxASSERT( (m_shapeOnCanvas == NULL) );
  338.         wxASSERT( (m_savedState != NULL) );
  339.         wxASSERT( (m_doc != NULL) );
  340.  
  341.         wxLineShape *lineShape = (wxLineShape *)m_savedState;
  342.         wxASSERT( (lineShape->GetFrom() != NULL) );
  343.         wxASSERT( (lineShape->GetTo() != NULL) );
  344.  
  345.         m_shapeOnCanvas = m_savedState;
  346.         m_savedState = NULL;
  347.  
  348.         m_doc->GetDiagram()->AddShape(lineShape);
  349.  
  350.         lineShape->GetFrom()->AddLine(lineShape, lineShape->GetTo(),
  351.             lineShape->GetAttachmentFrom(), lineShape->GetAttachmentTo());
  352.       
  353.         lineShape->Show(TRUE);
  354.  
  355.         wxClientDC dc(lineShape->GetCanvas());
  356.         lineShape->GetCanvas()->PrepareDC(dc);
  357.  
  358.         // It won't get drawn properly unless you move both
  359.         // connected images
  360.         lineShape->GetFrom()->Move(dc, lineShape->GetFrom()->GetX(), lineShape->GetFrom()->GetY());
  361.         lineShape->GetTo()->Move(dc, lineShape->GetTo()->GetX(), lineShape->GetTo()->GetY());
  362.  
  363.         if (m_cmd == ID_CS_ADD_LINE_SELECT)
  364.         {
  365.             lineShape->Select(TRUE, &dc);
  366.             ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, TRUE);
  367.         }
  368.  
  369.         m_doc->Modify(TRUE);
  370.         m_doc->UpdateAllViews();
  371.         break;
  372.     }
  373.     case ID_CS_CHANGE_BACKGROUND_COLOUR:
  374.     case ID_CS_MOVE:
  375.     case ID_CS_SIZE:
  376.     case ID_CS_EDIT_PROPERTIES:
  377.     case ID_CS_FONT_CHANGE:
  378.     case ID_CS_ARROW_CHANGE:
  379.     case ID_CS_ROTATE_CLOCKWISE:
  380.     case ID_CS_ROTATE_ANTICLOCKWISE:
  381.     case ID_CS_CHANGE_LINE_ORDERING:
  382.     case ID_CS_CHANGE_LINE_ATTACHMENT:
  383.     case ID_CS_ALIGN:
  384.     case ID_CS_NEW_POINT:
  385.     case ID_CS_CUT_POINT:
  386.     case ID_CS_MOVE_LINE_POINT:
  387.     case ID_CS_STRAIGHTEN:
  388.     case ID_CS_MOVE_LABEL:
  389.     {
  390.         // At this point we have been given a new shape
  391.         // just like the old one but with a changed colour.
  392.         // It's now time to apply that change to the
  393.         // shape on the canvas, saving the old state.
  394.         // NOTE: this is general enough to work with MOST attribute
  395.         // changes!
  396.  
  397.         wxASSERT( (m_shapeOnCanvas != NULL) );
  398.         wxASSERT( (m_savedState != NULL) ); // This is the new shape with changed colour
  399.         wxASSERT( (m_doc != NULL) );
  400.  
  401.         wxClientDC dc(m_shapeOnCanvas->GetCanvas());
  402.         m_shapeOnCanvas->GetCanvas()->PrepareDC(dc);
  403.  
  404.         bool isSelected = m_shapeOnCanvas->Selected();
  405.         if (isSelected)
  406.             m_shapeOnCanvas->Select(FALSE, & dc);
  407.  
  408.         if (m_cmd == ID_CS_SIZE || m_cmd == ID_CS_ROTATE_CLOCKWISE || m_cmd == ID_CS_ROTATE_ANTICLOCKWISE ||
  409.             m_cmd == ID_CS_CHANGE_LINE_ORDERING || m_cmd == ID_CS_CHANGE_LINE_ATTACHMENT)
  410.         {
  411.             m_shapeOnCanvas->Erase(dc);
  412.         }
  413.  
  414.         // TODO: make sure the ID is the same. Or, when applying the new state,
  415.         // don't change the original ID.
  416.         wxShape* tempShape = m_shapeOnCanvas->CreateNewCopy();
  417.  
  418.         // Apply the saved state to the shape on the canvas, by copying.
  419.         m_savedState->CopyWithHandler(*m_shapeOnCanvas);
  420.  
  421.         // Delete this state now it's been used (m_shapeOnCanvas currently holds this state)
  422.         delete m_savedState;
  423.  
  424.         // Remember the previous state
  425.         m_savedState = tempShape;
  426.  
  427.         // Redraw the shape
  428.  
  429.         if (m_cmd == ID_CS_MOVE || m_cmd == ID_CS_ROTATE_CLOCKWISE || m_cmd == ID_CS_ROTATE_ANTICLOCKWISE ||
  430.             m_cmd == ID_CS_ALIGN)
  431.         {
  432.             m_shapeOnCanvas->Move(dc, m_shapeOnCanvas->GetX(), m_shapeOnCanvas->GetY());
  433.  
  434.             csEvtHandler *handler = (csEvtHandler *)m_shapeOnCanvas->GetEventHandler();
  435.             m_shapeOnCanvas->FormatText(dc, handler->m_label);
  436.             m_shapeOnCanvas->Draw(dc);
  437.         }
  438.         else if (m_cmd == ID_CS_CHANGE_LINE_ORDERING)
  439.         {
  440.             m_shapeOnCanvas->MoveLinks(dc);
  441.         }
  442.         else if (m_cmd == ID_CS_CHANGE_LINE_ATTACHMENT)
  443.         {
  444.             wxLineShape *lineShape = (wxLineShape *)m_shapeOnCanvas;
  445.  
  446.             // Have to move both sets of links since we don't know which links
  447.             // have been affected (unless we compared before and after states).
  448.             lineShape->GetFrom()->MoveLinks(dc);
  449.             lineShape->GetTo()->MoveLinks(dc);
  450.         }
  451.         else if (m_cmd == ID_CS_SIZE)
  452.         {
  453.             double width, height;
  454.             m_shapeOnCanvas->GetBoundingBoxMax(&width, &height);
  455.  
  456.             m_shapeOnCanvas->SetSize(width, height);
  457.             m_shapeOnCanvas->Move(dc, m_shapeOnCanvas->GetX(), m_shapeOnCanvas->GetY());
  458.  
  459.             m_shapeOnCanvas->Show(TRUE);
  460.  
  461.             // Recursively redraw links if we have a composite.
  462.             if (m_shapeOnCanvas->GetChildren().Number() > 0)
  463.                 m_shapeOnCanvas->DrawLinks(dc, -1, TRUE);
  464.  
  465.             m_shapeOnCanvas->GetEventHandler()->OnEndSize(width, height);
  466.         }
  467.         else if (m_cmd == ID_CS_EDIT_PROPERTIES || m_cmd == ID_CS_FONT_CHANGE)
  468.         {
  469.             csEvtHandler *handler = (csEvtHandler *)m_shapeOnCanvas->GetEventHandler();
  470.             m_shapeOnCanvas->FormatText(dc, handler->m_label);
  471.             m_shapeOnCanvas->Draw(dc);
  472.         }
  473.         else
  474.         {
  475.             m_shapeOnCanvas->Draw(dc);
  476.         }
  477.  
  478.         if (isSelected)
  479.             m_shapeOnCanvas->Select(TRUE, & dc);
  480.         
  481.         m_doc->Modify(TRUE);
  482.         m_doc->UpdateAllViews();
  483.  
  484.         break;
  485.     }
  486.   }
  487.   return TRUE;
  488. }
  489.  
  490. bool csCommandState::Undo()
  491. {
  492.   switch (m_cmd)
  493.   {
  494.     case ID_CS_CUT:
  495.     {
  496.         wxASSERT( (m_savedState != NULL) );
  497.         wxASSERT( (m_doc != NULL) );
  498.  
  499.         m_doc->GetDiagram()->AddShape(m_savedState);
  500.         m_shapeOnCanvas = m_savedState;
  501.         m_savedState = NULL;
  502.  
  503.         if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
  504.         {
  505.             wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
  506.             lineShape->GetFrom()->AddLine(lineShape, lineShape->GetTo(),
  507.                 lineShape->GetAttachmentFrom(), lineShape->GetAttachmentTo(),
  508.                 m_linePositionFrom, m_linePositionTo);
  509.  
  510.             wxShapeCanvas* canvas = lineShape->GetFrom()->GetCanvas();
  511.  
  512.             wxClientDC dc(canvas);
  513.             canvas->PrepareDC(dc);
  514.  
  515.             lineShape->GetFrom()->MoveLinks(dc);
  516.             lineShape->GetTo()->MoveLinks(dc);
  517.  
  518.         }
  519.         m_shapeOnCanvas->Show(TRUE);
  520.  
  521.         m_doc->Modify(TRUE);
  522.         m_doc->UpdateAllViews();
  523.         break;
  524.     }
  525.     case ID_CS_ADD_SHAPE:
  526.     case ID_CS_ADD_LINE:
  527.     case ID_CS_ADD_SHAPE_SELECT:
  528.     case ID_CS_ADD_LINE_SELECT:
  529.     {
  530.         wxASSERT( (m_shapeOnCanvas != NULL) );
  531.         wxASSERT( (m_savedState == NULL) );
  532.         wxASSERT( (m_doc != NULL) );
  533.  
  534.         // In case this is a line
  535.         wxShape* lineFrom = NULL;
  536.         wxShape* lineTo = NULL;
  537.         int attachmentFrom = 0, attachmentTo = 0;
  538.  
  539.         if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
  540.         {
  541.             // Store the from/to info to save in the line shape
  542.             wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
  543.             lineFrom = lineShape->GetFrom();
  544.             lineTo = lineShape->GetTo();
  545.             attachmentFrom = lineShape->GetAttachmentFrom();
  546.             attachmentTo = lineShape->GetAttachmentTo();
  547.         }
  548.  
  549.         wxClientDC dc(m_shapeOnCanvas->GetCanvas());
  550.         m_shapeOnCanvas->GetCanvas()->PrepareDC(dc);
  551.  
  552.         m_shapeOnCanvas->Select(FALSE, &dc);
  553.         ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, FALSE);
  554.         m_doc->GetDiagram()->RemoveShape(m_shapeOnCanvas);
  555.         m_shapeOnCanvas->Unlink(); // Unlinks the line, if it is a line
  556.  
  557.         if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
  558.         {
  559.             // Restore the from/to info for future reference
  560.             wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
  561.             lineShape->SetFrom(lineFrom);
  562.             lineShape->SetTo(lineTo);
  563.             lineShape->SetAttachments(attachmentFrom, attachmentTo);
  564.         }
  565.  
  566.         m_savedState = m_shapeOnCanvas;
  567.         m_shapeOnCanvas = NULL;
  568.  
  569.         m_doc->Modify(TRUE);
  570.         m_doc->UpdateAllViews();
  571.         break;
  572.     }
  573.     case ID_CS_CHANGE_BACKGROUND_COLOUR:
  574.     case ID_CS_MOVE:
  575.     case ID_CS_SIZE:
  576.     case ID_CS_EDIT_PROPERTIES:
  577.     case ID_CS_FONT_CHANGE:
  578.     case ID_CS_ARROW_CHANGE:
  579.     case ID_CS_ROTATE_CLOCKWISE:
  580.     case ID_CS_ROTATE_ANTICLOCKWISE:
  581.     case ID_CS_CHANGE_LINE_ORDERING:
  582.     case ID_CS_CHANGE_LINE_ATTACHMENT:
  583.     case ID_CS_ALIGN:
  584.     case ID_CS_NEW_POINT:
  585.     case ID_CS_CUT_POINT:
  586.     case ID_CS_MOVE_LINE_POINT:
  587.     case ID_CS_STRAIGHTEN:
  588.     case ID_CS_MOVE_LABEL:
  589.     {
  590.         // Exactly like the Do case; we're just swapping states.
  591.         Do();
  592.         break;
  593.     }
  594.   }
  595.  
  596.     return TRUE;
  597. }
  598.  
  599.