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.

502 lines
17 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2013 CERN
  5. * Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
  6. * @author Jean-Pierre Charras, jp.charras at wanadoo.fr
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. #include <project.h>
  26. #include <scintilla_tricks.h>
  27. #include <tool/tool_manager.h>
  28. #include <page_layout/ws_draw_item.h>
  29. #include <page_layout/ws_data_item.h>
  30. #include <page_layout/ws_data_model.h>
  31. #include <view/view.h>
  32. #include "properties_frame.h"
  33. #include "pl_draw_panel_gal.h"
  34. #include "pl_editor_frame.h"
  35. #include "tools/pl_selection_tool.h"
  36. PROPERTIES_FRAME::PROPERTIES_FRAME( PL_EDITOR_FRAME* aParent ) :
  37. PANEL_PROPERTIES_BASE( aParent ),
  38. m_scintillaTricks( nullptr )
  39. {
  40. m_parent = aParent;
  41. m_stcText->SetUseVerticalScrollBar( false );
  42. m_stcText->SetUseHorizontalScrollBar( false );
  43. m_scintillaTricks = new SCINTILLA_TRICKS( m_stcText, wxT( "{}" ) );
  44. wxFont infoFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
  45. infoFont.SetSymbolicSize( wxFONTSIZE_SMALL );
  46. m_staticTextSizeInfo->SetFont( infoFont );
  47. infoFont.SetSymbolicSize( wxFONTSIZE_X_SMALL );
  48. m_staticTextInfoThickness->SetFont( infoFont );
  49. m_buttonOK->SetDefault();
  50. m_stcText->Bind( wxEVT_STC_CHARADDED, &PROPERTIES_FRAME::onScintillaCharAdded, this );
  51. }
  52. PROPERTIES_FRAME::~PROPERTIES_FRAME()
  53. {
  54. delete m_scintillaTricks;
  55. }
  56. void PROPERTIES_FRAME::OnPageChanged( wxNotebookEvent& event )
  57. {
  58. if( event.GetSelection() == 0 )
  59. m_buttonOK->SetDefault();
  60. else
  61. m_buttonGeneralOptsOK->SetDefault();
  62. event.Skip();
  63. }
  64. wxSize PROPERTIES_FRAME::GetMinSize() const
  65. {
  66. return wxSize( 150, -1 );
  67. }
  68. // Data transfert from general properties to widgets
  69. void PROPERTIES_FRAME::CopyPrmsFromGeneralToPanel()
  70. {
  71. WS_DATA_MODEL& model = WS_DATA_MODEL::GetTheInstance();
  72. wxString msg;
  73. // Set default parameters
  74. msg.Printf( wxT("%.3f"), model.m_DefaultLineWidth );
  75. m_textCtrlDefaultLineWidth->SetValue( msg );
  76. msg.Printf( wxT("%.3f"), model.m_DefaultTextSize.x );
  77. m_textCtrlDefaultTextSizeX->SetValue( msg );
  78. msg.Printf( wxT("%.3f"), model.m_DefaultTextSize.y );
  79. m_textCtrlDefaultTextSizeY->SetValue( msg );
  80. msg.Printf( wxT("%.3f"), model.m_DefaultTextThickness );
  81. m_textCtrlDefaultTextThickness->SetValue( msg );
  82. // Set page margins values
  83. msg.Printf( wxT("%.3f"), model.GetRightMargin() );
  84. m_textCtrlRightMargin->SetValue( msg );
  85. msg.Printf( wxT("%.3f"), model.GetBottomMargin() );
  86. m_textCtrlDefaultBottomMargin->SetValue( msg );
  87. msg.Printf( wxT("%.3f"), model.GetLeftMargin() );
  88. m_textCtrlLeftMargin->SetValue( msg );
  89. msg.Printf( wxT("%.3f"), model.GetTopMargin() );
  90. m_textCtrlTopMargin->SetValue( msg );
  91. }
  92. // Data transfert from widgets to general properties
  93. bool PROPERTIES_FRAME::CopyPrmsFromPanelToGeneral()
  94. {
  95. WS_DATA_MODEL& model = WS_DATA_MODEL::GetTheInstance();
  96. wxString msg;
  97. // Import default parameters from widgets
  98. msg = m_textCtrlDefaultLineWidth->GetValue();
  99. model.m_DefaultLineWidth = DoubleValueFromString( EDA_UNITS::UNSCALED, msg );
  100. msg = m_textCtrlDefaultTextSizeX->GetValue();
  101. model.m_DefaultTextSize.x = DoubleValueFromString( EDA_UNITS::UNSCALED, msg );
  102. msg = m_textCtrlDefaultTextSizeY->GetValue();
  103. model.m_DefaultTextSize.y = DoubleValueFromString( EDA_UNITS::UNSCALED, msg );
  104. msg = m_textCtrlDefaultTextThickness->GetValue();
  105. model.m_DefaultTextThickness = DoubleValueFromString( EDA_UNITS::UNSCALED, msg );
  106. // Get page margins values
  107. msg = m_textCtrlRightMargin->GetValue();
  108. model.SetRightMargin( DoubleValueFromString( EDA_UNITS::UNSCALED, msg ) );
  109. msg = m_textCtrlDefaultBottomMargin->GetValue();
  110. model.SetBottomMargin( DoubleValueFromString( EDA_UNITS::UNSCALED, msg ) );
  111. // cordinates of the left top corner are the left and top margins
  112. msg = m_textCtrlLeftMargin->GetValue();
  113. model.SetLeftMargin( DoubleValueFromString( EDA_UNITS::UNSCALED, msg ) );
  114. msg = m_textCtrlTopMargin->GetValue();
  115. model.SetTopMargin( DoubleValueFromString( EDA_UNITS::UNSCALED, msg ) );
  116. return true;
  117. }
  118. // Data transfert from item to widgets in properties frame
  119. void PROPERTIES_FRAME::CopyPrmsFromItemToPanel( WS_DATA_ITEM* aItem )
  120. {
  121. if( !aItem )
  122. {
  123. m_SizerItemProperties->Show( false );
  124. return;
  125. }
  126. wxString msg;
  127. // Set parameters common to all WS_DATA_ITEM types
  128. m_staticTextType->SetLabel( aItem->GetClassName() );
  129. m_textCtrlComment->SetValue( aItem->m_Info );
  130. switch( aItem->GetPage1Option() )
  131. {
  132. default:
  133. case ALL_PAGES: m_choicePageOpt->SetSelection( 0 ); break;
  134. case FIRST_PAGE_ONLY: m_choicePageOpt->SetSelection( 1 ); break;
  135. case SUBSEQUENT_PAGES: m_choicePageOpt->SetSelection( 2 ); break;
  136. }
  137. // Position/ start point
  138. msg.Printf( wxT("%.3f"), aItem->m_Pos.m_Pos.x );
  139. m_textCtrlPosX->SetValue( msg );
  140. msg.Printf( wxT("%.3f"), aItem->m_Pos.m_Pos.y );
  141. m_textCtrlPosY->SetValue( msg );
  142. switch( aItem->m_Pos.m_Anchor )
  143. {
  144. case RB_CORNER: m_comboBoxCornerPos->SetSelection( 2 ); break;
  145. case RT_CORNER: m_comboBoxCornerPos->SetSelection( 0 ); break;
  146. case LB_CORNER: m_comboBoxCornerPos->SetSelection( 3 ); break;
  147. case LT_CORNER: m_comboBoxCornerPos->SetSelection( 1 ); break;
  148. }
  149. // End point
  150. msg.Printf( wxT("%.3f"), aItem->m_End.m_Pos.x );
  151. m_textCtrlEndX->SetValue( msg );
  152. msg.Printf( wxT("%.3f"), aItem->m_End.m_Pos.y );
  153. m_textCtrlEndY->SetValue( msg );
  154. switch( aItem->m_End.m_Anchor )
  155. {
  156. case RB_CORNER: m_comboBoxCornerEnd->SetSelection( 2 ); break;
  157. case RT_CORNER: m_comboBoxCornerEnd->SetSelection( 0 ); break;
  158. case LB_CORNER: m_comboBoxCornerEnd->SetSelection( 3 ); break;
  159. case LT_CORNER: m_comboBoxCornerEnd->SetSelection( 1 ); break;
  160. }
  161. msg.Printf( wxT("%.3f"), aItem->m_LineWidth );
  162. m_textCtrlThickness->SetValue( msg );
  163. // Now, set prms more specific to WS_DATA_ITEM types
  164. // For a given type, disable widgets which are not relevant,
  165. // and be sure widgets which are relevant are enabled
  166. if( aItem->GetType() == WS_DATA_ITEM::WS_TEXT )
  167. {
  168. WS_DATA_ITEM_TEXT* item = (WS_DATA_ITEM_TEXT*) aItem;
  169. item->m_FullText = item->m_TextBase;
  170. // Replace our '\' 'n' sequence by the EOL char
  171. item->ReplaceAntiSlashSequence();
  172. m_stcText->SetValue( item->m_FullText );
  173. msg.Printf( wxT("%d"), item->m_IncrementLabel );
  174. m_textCtrlTextIncrement->SetValue( msg );
  175. // Rotation (poly and text)
  176. msg.Printf( wxT("%.3f"), item->m_Orient );
  177. m_textCtrlRotation->SetValue( msg );
  178. // Constraints:
  179. msg.Printf( wxT("%.3f"), item->m_BoundingBoxSize.x );
  180. m_textCtrlConstraintX->SetValue( msg );
  181. msg.Printf( wxT("%.3f"), item->m_BoundingBoxSize.y );
  182. m_textCtrlConstraintY->SetValue( msg );
  183. // Font Options
  184. m_checkBoxBold->SetValue( item->m_Bold );
  185. m_checkBoxItalic->SetValue( item->m_Italic );
  186. switch( item->m_Hjustify )
  187. {
  188. case GR_TEXT_HJUSTIFY_LEFT: m_choiceHjustify->SetSelection( 0 ); break;
  189. case GR_TEXT_HJUSTIFY_CENTER: m_choiceHjustify->SetSelection( 1 ); break;
  190. case GR_TEXT_HJUSTIFY_RIGHT: m_choiceHjustify->SetSelection( 2 ); break;
  191. }
  192. switch( item->m_Vjustify )
  193. {
  194. case GR_TEXT_VJUSTIFY_TOP: m_choiceVjustify->SetSelection( 0 ); break;
  195. case GR_TEXT_VJUSTIFY_CENTER: m_choiceVjustify->SetSelection( 1 ); break;
  196. case GR_TEXT_VJUSTIFY_BOTTOM: m_choiceVjustify->SetSelection( 2 ); break;
  197. }
  198. // Text size
  199. msg.Printf( wxT("%.3f"), item->m_TextSize.x );
  200. m_textCtrlTextSizeX->SetValue( msg );
  201. msg.Printf( wxT("%.3f"), item->m_TextSize.y );
  202. m_textCtrlTextSizeY->SetValue( msg );
  203. }
  204. if( aItem->GetType() == WS_DATA_ITEM::WS_POLYPOLYGON )
  205. {
  206. WS_DATA_ITEM_POLYGONS* item = (WS_DATA_ITEM_POLYGONS*) aItem;
  207. // Rotation (poly and text)
  208. msg.Printf( wxT("%.3f"), item->m_Orient );
  209. m_textCtrlRotation->SetValue( msg );
  210. }
  211. if( aItem->GetType() == WS_DATA_ITEM::WS_BITMAP )
  212. {
  213. WS_DATA_ITEM_BITMAP* item = (WS_DATA_ITEM_BITMAP*) aItem;
  214. // select definition in PPI
  215. msg.Printf( wxT("%d"), item->GetPPI() );
  216. m_textCtrlBitmapPPI->SetValue( msg );
  217. }
  218. m_SizerItemProperties->Show( true );
  219. m_SizerTextOptions->Show( aItem->GetType() == WS_DATA_ITEM::WS_TEXT );
  220. m_SizerEndPosition->Show( aItem->GetType() == WS_DATA_ITEM::WS_SEGMENT
  221. || aItem->GetType() == WS_DATA_ITEM::WS_RECT );
  222. m_SizerLineThickness->Show( aItem->GetType() != WS_DATA_ITEM::WS_BITMAP );
  223. // Polygons have no defaut value for line width
  224. m_staticTextInfoThickness->Show( aItem->GetType() != WS_DATA_ITEM::WS_POLYPOLYGON );
  225. m_SizerRotation->Show( aItem->GetType() == WS_DATA_ITEM::WS_TEXT
  226. || aItem->GetType() == WS_DATA_ITEM::WS_POLYPOLYGON );
  227. m_SizerPPI->Show( aItem->GetType() == WS_DATA_ITEM::WS_BITMAP );
  228. m_staticTextInclabel->Show( aItem->GetType() == WS_DATA_ITEM::WS_TEXT );
  229. m_textCtrlTextIncrement->Show( aItem->GetType() == WS_DATA_ITEM::WS_TEXT );
  230. // Repeat parameters
  231. msg.Printf( wxT("%d"), aItem->m_RepeatCount );
  232. m_textCtrlRepeatCount->SetValue( msg );
  233. msg.Printf( wxT("%.3f"), aItem->m_IncrementVector.x );
  234. m_textCtrlStepX->SetValue( msg );
  235. msg.Printf( wxT("%.3f"), aItem->m_IncrementVector.y );
  236. m_textCtrlStepY->SetValue( msg );
  237. // The number of widgets was modified
  238. m_swItemProperties->Layout();
  239. m_swItemProperties->Refresh();
  240. }
  241. // Event function called by clicking on the OK button
  242. void PROPERTIES_FRAME::OnAcceptPrms( wxCommandEvent& event )
  243. {
  244. PL_SELECTION_TOOL* selTool = m_parent->GetToolManager()->GetTool<PL_SELECTION_TOOL>();
  245. PL_SELECTION& selection = selTool->GetSelection();
  246. m_parent->SaveCopyInUndoList();
  247. WS_DRAW_ITEM_BASE* drawItem = (WS_DRAW_ITEM_BASE*) selection.Front();
  248. if( drawItem )
  249. {
  250. WS_DATA_ITEM* dataItem = drawItem->GetPeer();
  251. CopyPrmsFromPanelToItem( dataItem );
  252. // Be sure what is displayed is what is set for item
  253. // (mainly, texts can be modified if they contain "\n")
  254. CopyPrmsFromItemToPanel( dataItem );
  255. m_parent->GetCanvas()->GetView()->Update( drawItem );
  256. }
  257. CopyPrmsFromPanelToGeneral();
  258. // Refresh values, exactly as they are converted, to avoid any mistake
  259. CopyPrmsFromGeneralToPanel();
  260. m_parent->OnModify();
  261. // Rebuild the draw list with the new parameters
  262. m_parent->GetCanvas()->DisplayWorksheet();
  263. m_parent->GetCanvas()->Refresh();
  264. }
  265. void PROPERTIES_FRAME::OnSetDefaultValues( wxCommandEvent& event )
  266. {
  267. WS_DATA_MODEL& model = WS_DATA_MODEL::GetTheInstance();
  268. model.m_DefaultTextSize = DSIZE( TB_DEFAULT_TEXTSIZE, TB_DEFAULT_TEXTSIZE );
  269. model.m_DefaultLineWidth = 0.15;
  270. model.m_DefaultTextThickness = 0.15;
  271. CopyPrmsFromGeneralToPanel();
  272. // Rebuild the draw list with the new parameters
  273. m_parent->GetCanvas()->DisplayWorksheet();
  274. m_parent->GetCanvas()->Refresh();
  275. }
  276. // Data transfert from properties frame to item parameters
  277. bool PROPERTIES_FRAME::CopyPrmsFromPanelToItem( WS_DATA_ITEM* aItem )
  278. {
  279. if( aItem == NULL )
  280. return false;
  281. wxString msg;
  282. // Import common parameters:
  283. aItem->m_Info = m_textCtrlComment->GetValue();
  284. switch( m_choicePageOpt->GetSelection() )
  285. {
  286. default:
  287. case 0: aItem->SetPage1Option( ALL_PAGES ); break;
  288. case 1: aItem->SetPage1Option( FIRST_PAGE_ONLY ); break;
  289. case 2: aItem->SetPage1Option( SUBSEQUENT_PAGES ); break;
  290. }
  291. // Import thickness
  292. msg = m_textCtrlThickness->GetValue();
  293. aItem->m_LineWidth = DoubleValueFromString( EDA_UNITS::UNSCALED, msg );
  294. // Import Start point
  295. msg = m_textCtrlPosX->GetValue();
  296. aItem->m_Pos.m_Pos.x = DoubleValueFromString( EDA_UNITS::UNSCALED, msg );
  297. msg = m_textCtrlPosY->GetValue();
  298. aItem->m_Pos.m_Pos.y = DoubleValueFromString( EDA_UNITS::UNSCALED, msg );
  299. switch( m_comboBoxCornerPos->GetSelection() )
  300. {
  301. case 2: aItem->m_Pos.m_Anchor = RB_CORNER; break;
  302. case 0: aItem->m_Pos.m_Anchor = RT_CORNER; break;
  303. case 3: aItem->m_Pos.m_Anchor = LB_CORNER; break;
  304. case 1: aItem->m_Pos.m_Anchor = LT_CORNER; break;
  305. }
  306. // Import End point
  307. msg = m_textCtrlEndX->GetValue();
  308. aItem->m_End.m_Pos.x = DoubleValueFromString( EDA_UNITS::UNSCALED, msg );
  309. msg = m_textCtrlEndY->GetValue();
  310. aItem->m_End.m_Pos.y = DoubleValueFromString( EDA_UNITS::UNSCALED, msg );
  311. switch( m_comboBoxCornerEnd->GetSelection() )
  312. {
  313. case 2: aItem->m_End.m_Anchor = RB_CORNER; break;
  314. case 0: aItem->m_End.m_Anchor = RT_CORNER; break;
  315. case 3: aItem->m_End.m_Anchor = LB_CORNER; break;
  316. case 1: aItem->m_End.m_Anchor = LT_CORNER; break;
  317. }
  318. // Import Repeat prms
  319. long itmp;
  320. msg = m_textCtrlRepeatCount->GetValue();
  321. msg.ToLong( &itmp );
  322. aItem->m_RepeatCount = itmp;
  323. msg = m_textCtrlStepX->GetValue();
  324. aItem->m_IncrementVector.x = DoubleValueFromString( EDA_UNITS::UNSCALED, msg );
  325. msg = m_textCtrlStepY->GetValue();
  326. aItem->m_IncrementVector.y = DoubleValueFromString( EDA_UNITS::UNSCALED, msg );
  327. if( aItem->GetType() == WS_DATA_ITEM::WS_TEXT )
  328. {
  329. WS_DATA_ITEM_TEXT* item = (WS_DATA_ITEM_TEXT*) aItem;
  330. item->m_TextBase = m_stcText->GetValue();
  331. msg = m_textCtrlTextIncrement->GetValue();
  332. msg.ToLong( &itmp );
  333. item->m_IncrementLabel = itmp;
  334. item->m_Bold = m_checkBoxBold->IsChecked();
  335. item->m_Italic = m_checkBoxItalic->IsChecked();
  336. switch( m_choiceHjustify->GetSelection() )
  337. {
  338. case 0: item->m_Hjustify = GR_TEXT_HJUSTIFY_LEFT; break;
  339. case 1: item->m_Hjustify = GR_TEXT_HJUSTIFY_CENTER; break;
  340. case 2: item->m_Hjustify = GR_TEXT_HJUSTIFY_RIGHT; break;
  341. }
  342. switch( m_choiceVjustify->GetSelection() )
  343. {
  344. case 0: item->m_Vjustify = GR_TEXT_VJUSTIFY_TOP; break;
  345. case 1: item->m_Vjustify = GR_TEXT_VJUSTIFY_CENTER; break;
  346. case 2: item->m_Vjustify = GR_TEXT_VJUSTIFY_BOTTOM; break;
  347. }
  348. msg = m_textCtrlRotation->GetValue();
  349. item->m_Orient = DoubleValueFromString( EDA_UNITS::UNSCALED, msg );
  350. // Import text size
  351. msg = m_textCtrlTextSizeX->GetValue();
  352. item->m_TextSize.x = DoubleValueFromString( EDA_UNITS::UNSCALED, msg );
  353. msg = m_textCtrlTextSizeY->GetValue();
  354. item->m_TextSize.y = DoubleValueFromString( EDA_UNITS::UNSCALED, msg );
  355. // Import constraints:
  356. msg = m_textCtrlConstraintX->GetValue();
  357. item->m_BoundingBoxSize.x = DoubleValueFromString( EDA_UNITS::UNSCALED, msg );
  358. msg = m_textCtrlConstraintY->GetValue();
  359. item->m_BoundingBoxSize.y = DoubleValueFromString( EDA_UNITS::UNSCALED, msg );
  360. }
  361. if( aItem->GetType() == WS_DATA_ITEM::WS_POLYPOLYGON )
  362. {
  363. WS_DATA_ITEM_POLYGONS* item = (WS_DATA_ITEM_POLYGONS*) aItem;
  364. msg = m_textCtrlRotation->GetValue();
  365. item->m_Orient = DoubleValueFromString( EDA_UNITS::UNSCALED, msg );
  366. }
  367. if( aItem->GetType() == WS_DATA_ITEM::WS_BITMAP )
  368. {
  369. WS_DATA_ITEM_BITMAP* item = (WS_DATA_ITEM_BITMAP*) aItem;
  370. // Set definition in PPI
  371. long value;
  372. msg = m_textCtrlBitmapPPI->GetValue();
  373. if( msg.ToLong( &value ) )
  374. item->SetPPI( (int)value );
  375. }
  376. return true;
  377. }
  378. void PROPERTIES_FRAME::onScintillaCharAdded( wxStyledTextEvent &aEvent )
  379. {
  380. wxArrayString autocompleteTokens;
  381. int pos = m_stcText->GetCurrentPos();
  382. int start = m_stcText->WordStartPosition( pos, true );
  383. wxString partial;
  384. if( start >= 2
  385. && m_stcText->GetCharAt( start-2 ) == '$'
  386. && m_stcText->GetCharAt( start-1 ) == '{' )
  387. {
  388. WS_DRAW_ITEM_LIST::GetTextVars( &autocompleteTokens );
  389. partial = m_stcText->GetTextRange( start, pos );
  390. for( std::pair<wxString, wxString> entry : m_parent->Prj().GetTextVars() )
  391. autocompleteTokens.push_back( entry.first );
  392. }
  393. m_scintillaTricks->DoAutocomplete( partial, autocompleteTokens );
  394. m_stcText->SetFocus();
  395. }