You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

373 lines
12 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include <pl_editor_frame.h>
  24. #include <class_draw_panel_gal.h>
  25. #include <pl_editor_id.h>
  26. #include <confirm.h>
  27. #include <view/view_group.h>
  28. #include <view/view_controls.h>
  29. #include <view/view.h>
  30. #include <tool/tool_manager.h>
  31. #include <tools/pl_actions.h>
  32. #include <tools/pl_selection_tool.h>
  33. #include <tools/pl_drawing_tools.h>
  34. #include <bitmaps.h>
  35. #include <ws_draw_item.h>
  36. #include <ws_data_item.h>
  37. #include <invoke_pl_editor_dialog.h>
  38. // Drawing tool actions
  39. TOOL_ACTION PL_ACTIONS::drawLine( "plEditor.InteractiveDrawing.drawLine",
  40. AS_GLOBAL, 0,
  41. _( "Add Line" ), _( "Add a line" ),
  42. add_graphical_segments_xpm, AF_ACTIVATE );
  43. TOOL_ACTION PL_ACTIONS::drawRectangle( "plEditor.InteractiveDrawing.drawRectangle",
  44. AS_GLOBAL, 0,
  45. _( "Add Rectangle" ), _( "Add a rectangle" ),
  46. add_rectangle_xpm, AF_ACTIVATE );
  47. TOOL_ACTION PL_ACTIONS::placeText( "plEditor.InteractiveDrawing.placeText",
  48. AS_GLOBAL, 0,
  49. _( "Add Text" ), _( "Add a text item" ),
  50. text_xpm, AF_ACTIVATE );
  51. TOOL_ACTION PL_ACTIONS::placeImage( "plEditor.InteractiveDrawing.placeImage",
  52. AS_GLOBAL, 0,
  53. _( "Add Bitmap" ), _( "Add a bitmap image" ),
  54. image_xpm, AF_ACTIVATE );
  55. TOOL_ACTION PL_ACTIONS::addLine( "plEditor.InteractiveDrawing.addLine",
  56. AS_GLOBAL, 0,
  57. _( "Add Line" ), _( "Add a line" ),
  58. add_dashed_line_xpm, AF_ACTIVATE );
  59. TOOL_ACTION PL_ACTIONS::addRectangle( "plEditor.InteractiveDrawing.addRectangle",
  60. AS_GLOBAL, 0,
  61. _( "Add Rectangle" ), _( "Add a rectangle" ),
  62. add_rectangle_xpm, AF_ACTIVATE );
  63. TOOL_ACTION PL_ACTIONS::addText( "plEditor.InteractiveDrawing.addText",
  64. AS_GLOBAL, 0,
  65. _( "Add Text" ), _( "Add a text item" ),
  66. text_xpm, AF_ACTIVATE );
  67. TOOL_ACTION PL_ACTIONS::addImage( "plEditor.InteractiveDrawing.addImage",
  68. AS_GLOBAL, 0,
  69. _( "Add Bitmap" ), _( "Add a bitmap image" ),
  70. image_xpm, AF_ACTIVATE );
  71. PL_DRAWING_TOOLS::PL_DRAWING_TOOLS() :
  72. TOOL_INTERACTIVE( "plEditor.InteractiveDrawing" ),
  73. m_frame( nullptr ),
  74. m_selectionTool( nullptr ),
  75. m_menu( *this )
  76. {
  77. }
  78. bool PL_DRAWING_TOOLS::Init()
  79. {
  80. m_frame = getEditFrame<PL_EDITOR_FRAME>();
  81. m_selectionTool = m_toolMgr->GetTool<PL_SELECTION_TOOL>();
  82. auto& ctxMenu = m_menu.GetMenu();
  83. // cancel current tool goes in main context menu at the top if present
  84. ctxMenu.AddItem( ACTIONS::cancelInteractive, SELECTION_CONDITIONS::ShowAlways, 1 );
  85. ctxMenu.AddSeparator( SELECTION_CONDITIONS::ShowAlways, 1 );
  86. // Finally, add the standard zoom/grid items
  87. m_menu.AddStandardSubMenus( m_frame );
  88. return true;
  89. }
  90. void PL_DRAWING_TOOLS::Reset( RESET_REASON aReason )
  91. {
  92. if( aReason == MODEL_RELOAD )
  93. m_frame = getEditFrame<PL_EDITOR_FRAME>();
  94. }
  95. int PL_DRAWING_TOOLS::PlaceItem( const TOOL_EVENT& aEvent )
  96. {
  97. bool isText;
  98. bool isImmediate = false;
  99. if( aEvent.IsAction( &PL_ACTIONS::placeText ) )
  100. {
  101. isText = true;
  102. m_frame->SetToolID( ID_PL_TEXT_TOOL, wxCURSOR_PENCIL, _( "Add text" ) );
  103. }
  104. else if( aEvent.IsAction( &PL_ACTIONS::placeImage ) )
  105. {
  106. isText = false;
  107. m_frame->SetToolID( ID_PL_IMAGE_TOOL, wxCURSOR_PENCIL, _( "Add image" ) );
  108. }
  109. else if( aEvent.IsAction( & PL_ACTIONS::addText ) )
  110. {
  111. isText = true;
  112. isImmediate = true;
  113. }
  114. else if( aEvent.IsAction( & PL_ACTIONS::addImage ) )
  115. {
  116. isText = false;
  117. isImmediate = true;
  118. }
  119. else
  120. wxCHECK_MSG( false, 0, "Unknown action in PL_DRAWING_TOOLS::PlaceItem()" );
  121. VECTOR2I cursorPos;
  122. WS_DRAW_ITEM_BASE* item = nullptr;
  123. m_toolMgr->RunAction( PL_ACTIONS::clearSelection, true );
  124. getViewControls()->ShowCursor( true );
  125. Activate();
  126. // Main loop: keep receiving events
  127. while( OPT_TOOL_EVENT evt = Wait() )
  128. {
  129. cursorPos = getViewControls()->GetCursorPosition( !evt->Modifier( MD_ALT ) );
  130. if( TOOL_EVT_UTILS::IsCancelInteractive( evt.get() ) )
  131. {
  132. if( item )
  133. {
  134. m_toolMgr->RunAction( PL_ACTIONS::clearSelection, true );
  135. delete item;
  136. item = nullptr;
  137. // There's nothing to roll-back, but we still need to pop the undo stack
  138. m_frame->RollbackFromUndo();
  139. if( !evt->IsActivate() && !isImmediate )
  140. continue;
  141. }
  142. break;
  143. }
  144. else if( evt->IsClick( BUT_LEFT ) || ( isImmediate && !item ) )
  145. {
  146. // First click creates...
  147. if( !item )
  148. {
  149. m_frame->SaveCopyInUndoList();
  150. m_toolMgr->RunAction( PL_ACTIONS::clearSelection, true );
  151. WS_DATA_ITEM* dataItem;
  152. dataItem = m_frame->AddPageLayoutItem( isText ? WS_DATA_ITEM::WS_TEXT
  153. : WS_DATA_ITEM::WS_BITMAP );
  154. item = dataItem->GetDrawItems()[0];
  155. item->SetFlags( IS_NEW | IS_MOVED );
  156. m_selectionTool->AddItemToSel( item );
  157. }
  158. // ... and second click places:
  159. else
  160. {
  161. item->GetPeer()->MoveStartPointToUi( (wxPoint) cursorPos );
  162. item->SetPosition( item->GetPeer()->GetStartPosUi( 0 ) );
  163. item->ClearEditFlags();
  164. getView()->Update( item );
  165. item = nullptr;
  166. m_frame->OnModify();
  167. if( isImmediate )
  168. break;
  169. }
  170. }
  171. else if( evt->IsClick( BUT_RIGHT ) )
  172. {
  173. // Warp after context menu only if dragging...
  174. if( !item )
  175. m_toolMgr->VetoContextMenuMouseWarp();
  176. m_menu.ShowContextMenu( m_selectionTool->GetSelection() );
  177. }
  178. else if( item && ( evt->IsAction( &PL_ACTIONS::refreshPreview ) || evt->IsMotion() ) )
  179. {
  180. item->GetPeer()->MoveStartPointToUi( (wxPoint) cursorPos );
  181. item->SetPosition( item->GetPeer()->GetStartPosUi( 0 ) );
  182. getView()->Update( item );
  183. }
  184. // Enable autopanning and cursor capture only when there is an item to be placed
  185. getViewControls()->SetAutoPan( !!item );
  186. getViewControls()->CaptureCursor( !!item );
  187. }
  188. m_frame->SetNoToolSelected();
  189. return 0;
  190. }
  191. int PL_DRAWING_TOOLS::DrawShape( const TOOL_EVENT& aEvent )
  192. {
  193. // We might be running as the same shape in another co-routine. Make sure that one
  194. // gets whacked.
  195. m_toolMgr->DeactivateTool();
  196. bool isDrawLine;
  197. bool isImmediate = false;
  198. if( aEvent.IsAction( &PL_ACTIONS::drawLine ) )
  199. {
  200. isDrawLine = true;
  201. m_frame->SetToolID( ID_PL_LINE_TOOL, wxCURSOR_PENCIL, _( "Draw line" ) );
  202. }
  203. else if( aEvent.IsAction( &PL_ACTIONS::drawRectangle ) )
  204. {
  205. isDrawLine = false;
  206. m_frame->SetToolID( ID_PL_RECTANGLE_TOOL, wxCURSOR_PENCIL, _( "Draw rectangle" ) );
  207. }
  208. else if( aEvent.IsAction( &PL_ACTIONS::addLine ) )
  209. {
  210. isDrawLine = true;
  211. isImmediate = true;
  212. }
  213. else if( aEvent.IsAction( &PL_ACTIONS::addRectangle ) )
  214. {
  215. isDrawLine = false;
  216. isImmediate = true;
  217. }
  218. else
  219. wxCHECK_MSG( false, 0, "Unknown action in PL_DRAWING_TOOLS::DrawShape()" );
  220. m_toolMgr->RunAction( PL_ACTIONS::clearSelection, true );
  221. getViewControls()->ShowCursor( true );
  222. Activate();
  223. WS_DRAW_ITEM_BASE* item = nullptr;
  224. // Main loop: keep receiving events
  225. while( auto evt = Wait() )
  226. {
  227. VECTOR2I cursorPos = getViewControls()->GetCursorPosition( !evt->Modifier( MD_ALT ) );
  228. if( TOOL_EVT_UTILS::IsCancelInteractive( evt.get() ) )
  229. {
  230. m_toolMgr->RunAction( PL_ACTIONS::clearSelection, true );
  231. if( item )
  232. {
  233. item = nullptr;
  234. m_frame->RollbackFromUndo();
  235. if( !evt->IsActivate() && !isImmediate )
  236. continue;
  237. }
  238. break;
  239. }
  240. else if( evt->IsClick( BUT_LEFT ) || ( isImmediate && !item ) )
  241. {
  242. if( !item ) // start drawing
  243. {
  244. m_frame->SaveCopyInUndoList();
  245. m_toolMgr->RunAction( PL_ACTIONS::clearSelection, true );
  246. WS_DATA_ITEM::WS_ITEM_TYPE dataType;
  247. if( isDrawLine )
  248. dataType = WS_DATA_ITEM::WS_SEGMENT;
  249. else
  250. dataType = WS_DATA_ITEM::WS_RECT;
  251. WS_DATA_ITEM* dataItem = m_frame->AddPageLayoutItem( dataType );
  252. dataItem->MoveToUi( (wxPoint) cursorPos );
  253. item = dataItem->GetDrawItems()[0];
  254. item->SetFlags( IS_NEW );
  255. m_selectionTool->AddItemToSel( item );
  256. }
  257. else // finish drawing
  258. {
  259. item->ClearEditFlags();
  260. item = nullptr;
  261. m_frame->OnModify();
  262. if( isImmediate )
  263. {
  264. m_toolMgr->RunAction( ACTIONS::activatePointEditor );
  265. break;
  266. }
  267. }
  268. }
  269. else if( evt->IsAction( &PL_ACTIONS::refreshPreview ) || evt->IsMotion() )
  270. {
  271. if( item )
  272. {
  273. item->GetPeer()->MoveEndPointToUi( (wxPoint) cursorPos );
  274. item->SetEnd( item->GetPeer()->GetEndPosUi( 0 ) );
  275. getView()->Update( item );
  276. }
  277. }
  278. else if( evt->IsClick( BUT_RIGHT ) )
  279. {
  280. // Warp after context menu only if dragging...
  281. if( !item )
  282. m_toolMgr->VetoContextMenuMouseWarp();
  283. m_menu.ShowContextMenu( m_selectionTool->GetSelection() );
  284. }
  285. // Enable autopanning and cursor capture only when there is a shape being drawn
  286. getViewControls()->SetAutoPan( !!item );
  287. getViewControls()->CaptureCursor( !!item );
  288. }
  289. m_frame->SetNoToolSelected();
  290. return 0;
  291. }
  292. void PL_DRAWING_TOOLS::setTransitions()
  293. {
  294. Go( &PL_DRAWING_TOOLS::DrawShape, PL_ACTIONS::drawLine.MakeEvent() );
  295. Go( &PL_DRAWING_TOOLS::DrawShape, PL_ACTIONS::drawRectangle.MakeEvent() );
  296. Go( &PL_DRAWING_TOOLS::PlaceItem, PL_ACTIONS::placeText.MakeEvent() );
  297. Go( &PL_DRAWING_TOOLS::PlaceItem, PL_ACTIONS::placeImage.MakeEvent() );
  298. Go( &PL_DRAWING_TOOLS::DrawShape, PL_ACTIONS::addLine.MakeEvent() );
  299. Go( &PL_DRAWING_TOOLS::DrawShape, PL_ACTIONS::addRectangle.MakeEvent() );
  300. Go( &PL_DRAWING_TOOLS::PlaceItem, PL_ACTIONS::addText.MakeEvent() );
  301. Go( &PL_DRAWING_TOOLS::PlaceItem, PL_ACTIONS::addImage.MakeEvent() );
  302. }