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.

609 lines
20 KiB

5 years ago
5 years ago
5 years ago
5 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2004-2018 Jean-Pierre Charras jp.charras at wanadoo.fr
  5. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include <widgets/bitmap_button.h>
  25. #include <widgets/font_choice.h>
  26. #include <dialog_text_properties.h>
  27. #include <confirm.h>
  28. #include <board_commit.h>
  29. #include <board.h>
  30. #include <footprint.h>
  31. #include <pcb_text.h>
  32. #include <project.h>
  33. #include <pcb_edit_frame.h>
  34. #include <pcb_layer_box_selector.h>
  35. #include <wx/valnum.h>
  36. #include <scintilla_tricks.h>
  37. DIALOG_TEXT_PROPERTIES::DIALOG_TEXT_PROPERTIES( PCB_BASE_EDIT_FRAME* aParent, PCB_TEXT* aText ) :
  38. DIALOG_TEXT_PROPERTIES_BASE( aParent ),
  39. m_frame( aParent ),
  40. m_item( aText ),
  41. m_textWidth( aParent, m_SizeXLabel, m_SizeXCtrl, m_SizeXUnits ),
  42. m_textHeight( aParent, m_SizeYLabel, m_SizeYCtrl, m_SizeYUnits ),
  43. m_thickness( aParent, m_ThicknessLabel, m_ThicknessCtrl, m_ThicknessUnits ),
  44. m_posX( aParent, m_PositionXLabel, m_PositionXCtrl, m_PositionXUnits ),
  45. m_posY( aParent, m_PositionYLabel, m_PositionYCtrl, m_PositionYUnits ),
  46. m_orientation( aParent, m_OrientLabel, m_OrientCtrl, nullptr )
  47. {
  48. wxString title;
  49. // Configure display origin transforms
  50. if( m_item->GetParentFootprint() )
  51. {
  52. m_posX.SetCoordType( ORIGIN_TRANSFORMS::REL_X_COORD );
  53. m_posY.SetCoordType( ORIGIN_TRANSFORMS::REL_Y_COORD );
  54. }
  55. else
  56. {
  57. m_posX.SetCoordType( ORIGIN_TRANSFORMS::ABS_X_COORD );
  58. m_posY.SetCoordType( ORIGIN_TRANSFORMS::ABS_Y_COORD );
  59. }
  60. m_MultiLineText->SetEOLMode( wxSTC_EOL_LF );
  61. #ifdef _WIN32
  62. // Without this setting, on Windows, some esoteric unicode chars create display issue
  63. // in a wxStyledTextCtrl.
  64. // for SetTechnology() info, see https://www.scintilla.org/ScintillaDoc.html#SCI_SETTECHNOLOGY
  65. m_MultiLineText->SetTechnology(wxSTC_TECHNOLOGY_DIRECTWRITE);
  66. #endif
  67. m_scintillaTricks = new SCINTILLA_TRICKS( m_MultiLineText, wxT( "{}" ), false,
  68. // onAcceptFn
  69. [this]( wxKeyEvent& aEvent )
  70. {
  71. wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
  72. },
  73. // onCharFn
  74. [this]( wxStyledTextEvent& aEvent )
  75. {
  76. m_scintillaTricks->DoTextVarAutocomplete(
  77. // getTokensFn
  78. [this]( const wxString& xRef, wxArrayString* tokens )
  79. {
  80. m_frame->GetContextualTextVars( m_item, xRef, tokens );
  81. } );
  82. } );
  83. // A hack which causes Scintilla to auto-size the text editor canvas
  84. // See: https://github.com/jacobslusser/ScintillaNET/issues/216
  85. m_MultiLineText->SetScrollWidth( 1 );
  86. m_MultiLineText->SetScrollWidthTracking( true );
  87. if( m_item->GetParentFootprint() )
  88. {
  89. m_PositionXLabel->SetLabel( _( "Offset X:" ) );
  90. m_PositionYLabel->SetLabel( _( "Offset Y:" ) );
  91. if( m_item->Type() == PCB_FIELD_T )
  92. {
  93. PCB_FIELD* field = static_cast<PCB_FIELD*>( m_item );
  94. if( field->IsReference() )
  95. {
  96. title = _( "Footprint Reference Properties" );
  97. m_TextLabel->SetLabel( _( "Reference:" ) );
  98. }
  99. else if( field->IsValue() )
  100. {
  101. title = _( "Footprint Value Properties" );
  102. m_TextLabel->SetLabel( _( "Value:" ) );
  103. }
  104. else
  105. {
  106. title = _( "Footprint Field Properties" );
  107. m_TextLabel->SetLabel( _( "Text:" ) );
  108. }
  109. }
  110. else
  111. {
  112. title = _( "Footprint Text Properties" );
  113. m_TextLabel->SetLabel( _( "Text:" ) );
  114. m_Visible->Show( false );
  115. }
  116. SetInitialFocus( m_SingleLineText );
  117. m_MultiLineSizer->Show( false );
  118. // Do not allow locking items in the footprint editor
  119. m_cbLocked->Show( false );
  120. m_tabOrder = {
  121. m_SingleLineText,
  122. m_LayerSelectionCtrl,
  123. m_SizeXCtrl,
  124. m_SizeYCtrl,
  125. m_ThicknessCtrl,
  126. m_Visible,
  127. m_cbKnockout,
  128. m_KeepUpright,
  129. m_PositionXCtrl,
  130. m_PositionYCtrl,
  131. m_OrientCtrl,
  132. m_sdbSizerOK,
  133. m_sdbSizerCancel
  134. };
  135. }
  136. else
  137. {
  138. title = _( "Text Properties" );
  139. SetInitialFocus( m_MultiLineText );
  140. m_SingleLineSizer->Show( false );
  141. m_Visible->Show( false );
  142. m_KeepUpright->Show( false );
  143. m_statusLine->Show( false );
  144. m_tabOrder = {
  145. m_MultiLineText,
  146. m_cbLocked,
  147. m_LayerSelectionCtrl,
  148. m_SizeXCtrl,
  149. m_SizeYCtrl,
  150. m_ThicknessCtrl,
  151. m_cbKnockout,
  152. m_PositionXCtrl,
  153. m_PositionYCtrl,
  154. m_OrientCtrl,
  155. m_sdbSizerOK,
  156. m_sdbSizerCancel
  157. };
  158. }
  159. m_bold->SetIsCheckButton();
  160. m_bold->SetBitmap( KiBitmapBundle( BITMAPS::text_bold ) );
  161. m_italic->SetIsCheckButton();
  162. m_italic->SetBitmap( KiBitmapBundle( BITMAPS::text_italic ) );
  163. m_separator1->SetIsSeparator();
  164. m_alignLeft->SetIsRadioButton();
  165. m_alignLeft->SetBitmap( KiBitmapBundle( BITMAPS::text_align_left ) );
  166. m_alignCenter->SetIsRadioButton();
  167. m_alignCenter->SetBitmap( KiBitmapBundle( BITMAPS::text_align_center ) );
  168. m_alignRight->SetIsRadioButton();
  169. m_alignRight->SetBitmap( KiBitmapBundle( BITMAPS::text_align_right ) );
  170. m_separator2->SetIsSeparator();
  171. m_valignBottom->SetIsRadioButton();
  172. m_valignBottom->SetBitmap( KiBitmapBundle( BITMAPS::text_valign_bottom ) );
  173. m_valignCenter->SetIsRadioButton();
  174. m_valignCenter->SetBitmap( KiBitmapBundle( BITMAPS::text_valign_center ) );
  175. m_valignTop->SetIsRadioButton();
  176. m_valignTop->SetBitmap( KiBitmapBundle( BITMAPS::text_valign_top ) );
  177. m_separator3->SetIsSeparator();
  178. m_mirrored->SetIsCheckButton();
  179. m_mirrored->SetBitmap( KiBitmapBundle( BITMAPS::text_mirrored ) );
  180. m_autoTextThickness->SetIsCheckButton();
  181. m_autoTextThickness->SetBitmap( KiBitmapBundle( BITMAPS::edit_cmp_symb_links ) );
  182. SetTitle( title );
  183. m_hash_key = title;
  184. // Configure the layers list selector. Note that footprints are built outside the current
  185. // board and so we may need to show all layers if the text is on an unactivated layer.
  186. if( !m_frame->GetBoard()->IsLayerEnabled( m_item->GetLayer() ) )
  187. m_LayerSelectionCtrl->ShowNonActivatedLayers( true );
  188. m_LayerSelectionCtrl->SetLayersHotkeys( false );
  189. m_LayerSelectionCtrl->SetBoardFrame( m_frame );
  190. m_LayerSelectionCtrl->Resync();
  191. m_orientation.SetUnits( EDA_UNITS::DEGREES );
  192. m_orientation.SetPrecision( 3 );
  193. // Set predefined rotations in combo dropdown, according to the locale floating point
  194. // separator notation
  195. double rot_list[] = { 0.0, 90.0, -90.0, 180.0 };
  196. for( size_t ii = 0; ii < m_OrientCtrl->GetCount() && ii < 4; ++ii )
  197. m_OrientCtrl->SetString( ii, wxString::Format( wxT( "%.1f" ), rot_list[ii] ) );
  198. // Set font sizes
  199. m_statusLine->SetFont( KIUI::GetInfoFont( this ) );
  200. SetupStandardButtons();
  201. // wxTextCtrls fail to generate wxEVT_CHAR events when the wxTE_MULTILINE flag is set,
  202. // so we have to listen to wxEVT_CHAR_HOOK events instead.
  203. Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TEXT_PROPERTIES::OnCharHook ),
  204. nullptr, this );
  205. finishDialogSettings();
  206. }
  207. DIALOG_TEXT_PROPERTIES::~DIALOG_TEXT_PROPERTIES()
  208. {
  209. Disconnect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TEXT_PROPERTIES::OnCharHook ),
  210. nullptr, this );
  211. delete m_scintillaTricks;
  212. }
  213. void PCB_BASE_EDIT_FRAME::ShowTextPropertiesDialog( PCB_TEXT* aText )
  214. {
  215. DIALOG_TEXT_PROPERTIES dlg( this, aText );
  216. // QuasiModal required for Scintilla auto-complete
  217. dlg.ShowQuasiModal();
  218. }
  219. void DIALOG_TEXT_PROPERTIES::OnSetFocusText( wxFocusEvent& event )
  220. {
  221. if( m_item->Type() == PCB_FIELD_T && static_cast<PCB_FIELD*>( m_item )->IsReference() )
  222. {
  223. #ifdef __WXGTK__
  224. // Force an update of the text control before setting the text selection
  225. // This is needed because GTK seems to ignore the selection on first update
  226. //
  227. // Note that we can't do this on OSX as it tends to provoke Apple's
  228. // "[NSAlert runModal] may not be invoked inside of transaction begin/commit pair"
  229. // bug. See: https://bugs.launchpad.net/kicad/+bug/1837225
  230. m_SingleLineText->Update();
  231. #endif
  232. KIUI::SelectReferenceNumber( static_cast<wxTextEntry*>( m_SingleLineText ) );
  233. }
  234. else
  235. m_SingleLineText->SetSelection( -1, -1 );
  236. event.Skip();
  237. }
  238. bool DIALOG_TEXT_PROPERTIES::TransferDataToWindow()
  239. {
  240. BOARD* board = m_frame->GetBoard();
  241. FOOTPRINT* parentFP = m_item->GetParentFootprint();
  242. wxString text = m_item->GetText();
  243. // show text variable cross-references in a human-readable format
  244. text = board->ConvertKIIDsToCrossReferences( UnescapeString( text ) );
  245. if( m_SingleLineText->IsShown() )
  246. {
  247. m_SingleLineText->SetValue( text );
  248. if( m_item->Type() == PCB_FIELD_T && static_cast<PCB_FIELD*>( m_item )->IsReference() )
  249. KIUI::SelectReferenceNumber( static_cast<wxTextEntry*>( m_SingleLineText ) );
  250. else
  251. m_SingleLineText->SetSelection( -1, -1 );
  252. }
  253. else if( m_MultiLineText->IsShown() )
  254. {
  255. m_MultiLineText->SetValue( text );
  256. m_MultiLineText->SetSelection( -1, -1 );
  257. m_MultiLineText->EmptyUndoBuffer();
  258. }
  259. if( parentFP )
  260. {
  261. m_statusLine->SetLabel( wxString::Format( _( "Footprint %s (%s), %s, rotated %.1f deg"),
  262. parentFP->GetReference(),
  263. parentFP->GetValue(),
  264. parentFP->IsFlipped() ? _( "back side (mirrored)" )
  265. : _( "front side" ),
  266. parentFP->GetOrientation().AsDegrees() ) );
  267. }
  268. else
  269. {
  270. m_statusLine->Show( false );
  271. }
  272. m_cbLocked->SetValue( m_item->IsLocked() );
  273. m_LayerSelectionCtrl->SetLayerSelection( m_item->GetLayer() );
  274. m_cbKnockout->SetValue( m_item->IsKnockout() );
  275. m_fontCtrl->SetFontSelection( m_item->GetFont() );
  276. m_textWidth.SetValue( m_item->GetTextSize().x );
  277. m_textHeight.SetValue( m_item->GetTextSize().y );
  278. if( m_item->GetAutoThickness() )
  279. {
  280. m_autoTextThickness->Check( m_item->GetAutoThickness() );
  281. m_thickness.SetValue( m_item->GetEffectiveTextPenWidth() );
  282. m_thickness.Enable( false );
  283. }
  284. else
  285. {
  286. m_thickness.SetValue( m_item->GetTextThickness() );
  287. }
  288. m_posX.SetValue( m_item->GetFPRelativePosition().x );
  289. m_posY.SetValue( m_item->GetFPRelativePosition().y );
  290. if( m_Visible->IsShown() )
  291. m_Visible->SetValue( m_item->IsVisible() );
  292. if( m_KeepUpright->IsShown() )
  293. m_KeepUpright->SetValue( m_item->IsKeepUpright() );
  294. m_bold->Check( m_item->IsBold() );
  295. m_italic->Check( m_item->IsItalic() );
  296. switch ( m_item->GetHorizJustify() )
  297. {
  298. case GR_TEXT_H_ALIGN_LEFT: m_alignLeft->Check( true ); break;
  299. case GR_TEXT_H_ALIGN_CENTER: m_alignCenter->Check( true ); break;
  300. case GR_TEXT_H_ALIGN_RIGHT: m_alignRight->Check( true ); break;
  301. case GR_TEXT_H_ALIGN_INDETERMINATE: break;
  302. }
  303. switch ( m_item->GetVertJustify() )
  304. {
  305. case GR_TEXT_V_ALIGN_BOTTOM: m_valignBottom->Check( true ); break;
  306. case GR_TEXT_V_ALIGN_CENTER: m_valignCenter->Check( true ); break;
  307. case GR_TEXT_V_ALIGN_TOP: m_valignTop->Check( true ); break;
  308. case GR_TEXT_V_ALIGN_INDETERMINATE: break;
  309. }
  310. m_mirrored->Check( m_item->IsMirrored() );
  311. EDA_ANGLE orientation = m_item->GetTextAngle();
  312. m_orientation.SetAngleValue( orientation.Normalize180() );
  313. return DIALOG_TEXT_PROPERTIES_BASE::TransferDataToWindow();
  314. }
  315. void DIALOG_TEXT_PROPERTIES::onFontSelected( wxCommandEvent & aEvent )
  316. {
  317. if( KIFONT::FONT::IsStroke( aEvent.GetString() ) )
  318. {
  319. m_thickness.Show( true );
  320. m_autoTextThickness->Show( true );
  321. int textSize = std::min( m_textWidth.GetValue(), m_textHeight.GetValue() );
  322. int thickness = m_thickness.GetValue();
  323. m_bold->Check( abs( thickness - GetPenSizeForBold( textSize ) )
  324. < abs( thickness - GetPenSizeForNormal( textSize ) ) );
  325. }
  326. else
  327. {
  328. m_thickness.Show( false );
  329. m_autoTextThickness->Show( false );
  330. }
  331. }
  332. void DIALOG_TEXT_PROPERTIES::onBoldToggle( wxCommandEvent & aEvent )
  333. {
  334. int textSize = std::min( m_textWidth.GetValue(), m_textHeight.GetValue() );
  335. if( aEvent.IsChecked() )
  336. m_thickness.ChangeValue( GetPenSizeForBold( textSize ) );
  337. else
  338. m_thickness.ChangeValue( GetPenSizeForNormal( textSize ) );
  339. aEvent.Skip();
  340. }
  341. void DIALOG_TEXT_PROPERTIES::onAlignButton( wxCommandEvent& aEvent )
  342. {
  343. for( BITMAP_BUTTON* btn : { m_alignLeft, m_alignCenter, m_alignRight } )
  344. {
  345. if( btn->IsChecked() && btn != aEvent.GetEventObject() )
  346. btn->Check( false );
  347. }
  348. }
  349. void DIALOG_TEXT_PROPERTIES::onValignButton( wxCommandEvent& aEvent )
  350. {
  351. for( BITMAP_BUTTON* btn : { m_valignBottom, m_valignCenter, m_valignTop } )
  352. {
  353. if( btn->IsChecked() && btn != aEvent.GetEventObject() )
  354. btn->Check( false );
  355. }
  356. }
  357. void DIALOG_TEXT_PROPERTIES::onThickness( wxCommandEvent& event )
  358. {
  359. int textSize = std::min( m_textWidth.GetValue(), m_textHeight.GetValue() );
  360. int thickness = m_thickness.GetValue();
  361. m_bold->Check( abs( thickness - GetPenSizeForBold( textSize ) )
  362. < abs( thickness - GetPenSizeForNormal( textSize ) ) );
  363. }
  364. void DIALOG_TEXT_PROPERTIES::onTextSize( wxCommandEvent& aEvent )
  365. {
  366. if( m_autoTextThickness->IsChecked() )
  367. {
  368. int textSize = std::min( m_textWidth.GetValue(), m_textHeight.GetValue() );
  369. int thickness;
  370. // Calculate the "best" thickness from text size and bold option:
  371. if( m_bold->IsChecked() )
  372. thickness = GetPenSizeForBold( textSize );
  373. else
  374. thickness = GetPenSizeForNormal( textSize );
  375. m_thickness.SetValue( thickness );
  376. }
  377. }
  378. void DIALOG_TEXT_PROPERTIES::onAutoTextThickness( wxCommandEvent& aEvent )
  379. {
  380. if( aEvent.IsChecked() )
  381. {
  382. m_autoTextThickness->Check( true );
  383. wxCommandEvent dummy;
  384. onTextSize( dummy );
  385. m_thickness.Enable( false );
  386. }
  387. else
  388. {
  389. m_thickness.Enable( true );
  390. }
  391. }
  392. bool DIALOG_TEXT_PROPERTIES::TransferDataFromWindow()
  393. {
  394. if( !DIALOG_TEXT_PROPERTIES_BASE::TransferDataFromWindow() )
  395. return false;
  396. int minSize = pcbIUScale.mmToIU( TEXT_MIN_SIZE_MM );
  397. int maxSize = pcbIUScale.mmToIU( TEXT_MAX_SIZE_MM );
  398. if( !m_textWidth.Validate( minSize, maxSize ) || !m_textHeight.Validate( minSize, maxSize ) )
  399. return false;
  400. BOARD* board = m_frame->GetBoard();
  401. BOARD_COMMIT commit( m_frame );
  402. commit.Modify( m_item );
  403. // If no other command in progress, prepare undo command
  404. // (for a command in progress, will be made later, at the completion of command)
  405. bool pushCommit = ( m_item->GetEditFlags() == 0 );
  406. // Set IN_EDIT flag to force undo/redo/abort proper operation and avoid new calls to
  407. // SaveCopyInUndoList for the same text if is moved, and then rotated, edited, etc....
  408. if( !pushCommit )
  409. m_item->SetFlags( IN_EDIT );
  410. // Set the new text content
  411. if( m_SingleLineText->IsShown() )
  412. {
  413. if( !m_SingleLineText->GetValue().IsEmpty() )
  414. {
  415. // convert any text variable cross-references to their UUIDs
  416. wxString txt = board->ConvertCrossReferencesToKIIDs( m_SingleLineText->GetValue() );
  417. m_item->SetText( txt );
  418. }
  419. }
  420. else if( m_MultiLineText->IsShown() )
  421. {
  422. if( !m_MultiLineText->GetValue().IsEmpty() )
  423. {
  424. // convert any text variable cross-references to their UUIDs
  425. wxString txt = board->ConvertCrossReferencesToKIIDs( m_MultiLineText->GetValue() );
  426. #ifdef __WXMAC__
  427. // On macOS CTRL+Enter produces '\r' instead of '\n' regardless of EOL setting.
  428. // Replace it now.
  429. txt.Replace( wxT( "\r" ), wxT( "\n" ) );
  430. #elif defined( __WINDOWS__ )
  431. // On Windows, a new line is coded as \r\n. We use only \n in kicad files and in
  432. // drawing routines so strip the \r char.
  433. txt.Replace( wxT( "\r" ), wxT( "" ) );
  434. #endif
  435. m_item->SetText( EscapeString( txt, CTX_QUOTED_STR ) );
  436. }
  437. }
  438. m_item->SetLocked( m_cbLocked->GetValue() );
  439. m_item->SetLayer( ToLAYER_ID( m_LayerSelectionCtrl->GetLayerSelection() ) );
  440. m_item->SetIsKnockout( m_cbKnockout->GetValue() );
  441. if( m_fontCtrl->HaveFontSelection() )
  442. {
  443. m_item->SetFont( m_fontCtrl->GetFontSelection( m_bold->IsChecked(),
  444. m_italic->IsChecked() ) );
  445. }
  446. m_item->SetTextSize( VECTOR2I( m_textWidth.GetValue(), m_textHeight.GetValue() ) );
  447. if( m_autoTextThickness->IsChecked() )
  448. {
  449. m_item->SetAutoThickness( true );
  450. }
  451. else
  452. {
  453. m_item->SetTextThickness( m_thickness.GetValue() );
  454. // Test for acceptable values for thickness and size and clamp if fails
  455. int maxPenWidth = ClampTextPenSize( m_item->GetTextThickness(), m_item->GetTextSize() );
  456. if( m_item->GetTextThickness() > maxPenWidth )
  457. {
  458. DisplayError( this, _( "The text thickness is too large for the text size.\n"
  459. "It will be clamped." ) );
  460. m_item->SetTextThickness( maxPenWidth );
  461. }
  462. }
  463. m_item->SetFPRelativePosition( VECTOR2I( m_posX.GetValue(), m_posY.GetValue() ) );
  464. m_item->SetTextAngle( m_orientation.GetAngleValue().Normalize() );
  465. if( m_Visible->IsShown() )
  466. m_item->SetVisible( m_Visible->GetValue() );
  467. if( m_KeepUpright->IsShown() )
  468. m_item->SetKeepUpright( m_KeepUpright->GetValue() );
  469. m_item->SetBoldFlag( m_bold->IsChecked() );
  470. m_item->SetItalicFlag( m_italic->IsChecked() );
  471. if( m_alignLeft->IsChecked() )
  472. m_item->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  473. else if( m_alignCenter->IsChecked() )
  474. m_item->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
  475. else
  476. m_item->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  477. if( m_valignBottom->IsChecked() )
  478. m_item->SetVertJustify ( GR_TEXT_V_ALIGN_BOTTOM );
  479. else if( m_valignCenter->IsChecked() )
  480. m_item->SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
  481. else
  482. m_item->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
  483. m_item->SetMirrored( m_mirrored->IsChecked() );
  484. if( pushCommit )
  485. commit.Push( _( "Edit Text Properties" ) );
  486. return true;
  487. }
  488. void DIALOG_TEXT_PROPERTIES::onMultiLineTCLostFocus( wxFocusEvent& event )
  489. {
  490. if( m_scintillaTricks )
  491. m_scintillaTricks->CancelAutocomplete();
  492. event.Skip();
  493. }