KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_about.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2010 Rafael Sokolowski <[email protected]>
5 * Copyright (C) 2017-2021 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
25
26#include <config.h>
27#include <string>
28
29#include <build_version.h>
30
31#include <wx/clipbrd.h>
32#include <wx/msgdlg.h>
33#include <wx/hyperlink.h>
34
35/* All KiCad icons are linked into shared library 'libbitmaps.a'.
36 * Icons:
37 * preference_xpm; // Icon for 'Developers' tab
38 * editor_xpm; // Icon for 'Doc Writers' tab
39 * color_materials_xpm; // Icon for 'Artists' tab
40 * language_xpm; // Icon for 'Translators' tab
41 * right_xpm; // Right arrow icon for list items
42 * info_xpm; // Bulb for description tab
43 * tools_xpm; // Sheet of paper icon for license info tab
44 */
45#include <bitmaps.h>
46#include <build_version.h>
48#include <tool/tool_manager.h>
49
50#include "dialog_about.h"
51
52
54 : DIALOG_ABOUT_BASE( aParent ), m_info( aAppInfo )
55{
56 wxASSERT( aParent != nullptr );
57
58 SetEvtHandlerEnabled( false );
59 // TODO: Change these to 16x16 versions when available
60 m_images = new wxImageList( 24, 24, false, 9 );
61
62 m_images->Add( KiBitmap( BITMAPS::info ) ); // INFORMATION
63 m_images->Add( KiBitmap( BITMAPS::recent ) ); // VERSION
64 m_images->Add( KiBitmap( BITMAPS::preference ) ); // DEVELOPERS
65 m_images->Add( KiBitmap( BITMAPS::editor ) ); // DOCWRITERS
66 m_images->Add( KiBitmap( BITMAPS::library ) ); // LIBRARIANS
67 m_images->Add( KiBitmap( BITMAPS::color_materials ) ); // ARTISTS
68 m_images->Add( KiBitmap( BITMAPS::language ) ); // TRANSLATORS
69 m_images->Add( KiBitmap( BITMAPS::zip ) ); // PACKAGERS
70 m_images->Add( KiBitmap( BITMAPS::tools ) ); // LICENSE
71
72 m_notebook->SetImageList( m_images );
73
74 if( m_info.GetAppIcon().IsOk() )
75 {
76 SetIcon( m_info.GetAppIcon() );
77 m_bitmapApp->SetBitmap( m_info.GetAppIcon() );
78 }
79 else
80 {
81 wxIcon icon;
82
83 if( IsNightlyVersion() )
84 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_nightly ) );
85 else
86 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad ) );
87
88 SetIcon( icon );
89 m_bitmapApp->SetBitmap( icon );
90 }
91
92 m_titleName = aParent->GetAboutTitle();
96 m_staticTextBuildVersion->SetLabel( wxS( "Version: " ) + m_info.GetBuildVersion() );
98
99 SetTitle( wxString::Format( _( "About %s" ), m_titleName ) );
101
102 SetEvtHandlerEnabled( true );
103 GetSizer()->SetSizeHints( this );
104 SetFocus();
105 Centre();
106}
107
108
110{
111 delete m_images;
112}
113
114
116{
117 // three columns with vertical and horizontal extra space of two pixels
118 wxFlexGridSizer* fgSizer = new wxFlexGridSizer( 3, 2, 2 );
119 fgSizer->SetFlexibleDirection( wxHORIZONTAL );
120 fgSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
121
122 return fgSizer;
123}
124
125
127{
128 createNotebookHtmlPage( m_notebook, _( "About" ), IMAGES::INFORMATION,
130
131 wxString version = GetVersionInfoData( m_untranslatedTitleName, true );
132
133 createNotebookHtmlPage( m_notebook, _( "Version" ), IMAGES::VERSION, version, true );
134
135 createNotebookPageByCategory( m_notebook, _( "Developers" ) , IMAGES::DEVELOPERS,
137 createNotebookPage( m_notebook, _( "Doc Writers" ), IMAGES::DOCWRITERS,
139
140 createNotebookPageByCategory( m_notebook, _( "Librarians" ), IMAGES::LIBRARIANS,
142
143 createNotebookPageByCategory( m_notebook, _( "Artists" ), IMAGES::ARTISTS,
144 m_info.GetArtists() );
145 createNotebookPageByCategory( m_notebook, _( "Translators" ), IMAGES::TRANSLATORS,
147 createNotebookPageByCategory( m_notebook, _( "Packagers" ), IMAGES::PACKAGERS,
149
150 createNotebookHtmlPage( m_notebook, _( "License" ), IMAGES::LICENSE, m_info.GetLicense() );
151}
152
153void DIALOG_ABOUT::createNotebookPage( wxNotebook* aParent, const wxString& aCaption,
154 IMAGES aIconIndex, const CONTRIBUTORS& aContributors )
155{
156 wxPanel* outerPanel = new wxPanel( aParent );
157 wxBoxSizer* outerSizer = new wxBoxSizer( wxVERTICAL );
158
159 wxBoxSizer* bSizer = new wxBoxSizer( wxHORIZONTAL );
160
161 wxScrolledWindow* m_scrolledWindow1 = new wxScrolledWindow( outerPanel, wxID_ANY,
162 wxDefaultPosition,
163 wxDefaultSize,
164 wxHSCROLL|wxVSCROLL );
165 m_scrolledWindow1->SetScrollRate( 5, 5 );
166
167 /* Panel for additional space at the left,
168 * but can also be used to show an additional bitmap.
169 */
170 wxPanel* panel1 = new wxPanel( m_scrolledWindow1 );
171
172 wxFlexGridSizer* fgSizer1 = createFlexGridSizer();
173
174 for( size_t i=0; i<aContributors.GetCount(); ++i )
175 {
176 CONTRIBUTOR* contributor = &aContributors.Item( i );
177
178 // Icon at first column
179 wxStaticBitmap* m_bitmap1 = createStaticBitmap( m_scrolledWindow1, contributor->GetIcon() );
180 fgSizer1->Add( m_bitmap1, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 5 );
181
182 // Name of contributor at second column
183 if ( contributor->GetName() != wxEmptyString )
184 {
185 wxStaticText* m_staticText1 = new wxStaticText( m_scrolledWindow1, wxID_ANY,
186 contributor->GetName(),
187 wxDefaultPosition, wxDefaultSize, 0 );
188 m_staticText1->Wrap( -1 );
189 fgSizer1->Add( m_staticText1, 0, wxALIGN_LEFT|wxBOTTOM, 2 );
190 }
191 else
192 {
193 fgSizer1->AddSpacer( 5 );
194 }
195
196 // Email address of contributor at third column
197 if ( contributor->GetExtra() != wxEmptyString )
198 {
199 wxStaticText* hyperlink = wxStaticTextRef( m_scrolledWindow1,
200 contributor->GetExtra() );
201 fgSizer1->Add( hyperlink, 0, wxALIGN_LEFT|wxBOTTOM, 2 );
202 }
203 else
204 {
205 fgSizer1->AddSpacer( 5 );
206 }
207 }
208
209 bSizer->Add( panel1, 1, wxEXPAND|wxALL, 10 );
210 bSizer->Add( fgSizer1, 7, wxEXPAND|wxALL, 10 ); // adjust width of panel with first int value
211 m_scrolledWindow1->SetSizer( bSizer );
212 m_scrolledWindow1->Layout();
213 bSizer->Fit( m_scrolledWindow1 );
214
215 outerSizer->Add( m_scrolledWindow1, 1, wxEXPAND, 0 );
216 outerPanel->SetSizer( outerSizer );
217
218 aParent->AddPage( outerPanel, aCaption, false, static_cast<int>( aIconIndex ) );
219}
220
221
222void DIALOG_ABOUT::createNotebookPageByCategory( wxNotebook* aParent, const wxString& aCaption,
223 IMAGES aIconIndex,
224 const CONTRIBUTORS& aContributors )
225{
226 // The left justification between wxStaticText and wxHyperlinkCtrl is different so
227 // we must pad to make the alignment look decent.
228 //
229 // @todo Just make all of the contributor lists HTML so the alignment is consistent.
230 wxString padding;
231
232 // Of course the padding is different depending on the platform so we adjust the
233 // padding accordingly.
234#if defined( __WXGTK__ )
235 padding += wxS( " " );
236#endif
237 wxPanel* outerPanel = new wxPanel( aParent );
238 wxBoxSizer* outerSizer = new wxBoxSizer( wxVERTICAL );
239
240 wxBoxSizer* bSizer = new wxBoxSizer( wxHORIZONTAL );
241
242 wxScrolledWindow* m_scrolledWindow1 = new wxScrolledWindow( outerPanel, wxID_ANY,
243 wxDefaultPosition,
244 wxDefaultSize,
245 wxHSCROLL|wxVSCROLL );
246 m_scrolledWindow1->SetScrollRate( 5, 5 );
247
248 /* Panel for additional space at the left,
249 * but can also be used to show an additional bitmap.
250 */
251 wxPanel* panel1 = new wxPanel( m_scrolledWindow1 );
252
253 wxFlexGridSizer* fgSizer1 = createFlexGridSizer();
254
255 for( size_t i=0; i < aContributors.GetCount(); ++i )
256 {
257 CONTRIBUTOR* contributor = &aContributors.Item( i );
258
259 wxBitmap* icon = contributor->GetIcon();
260 wxString category = contributor->GetCategory();
261
262 /* to construct the next row we expect to have
263 * a category and a contributor that was not considered up to now
264 */
265 if( ( category != wxEmptyString ) && !( contributor->IsChecked() ) )
266 {
267 // Icon at first column
268 wxStaticBitmap* m_bitmap1 = createStaticBitmap( m_scrolledWindow1, icon );
269 fgSizer1->Add( m_bitmap1, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 5 );
270
271 // Category name at second column
272 wxStaticText* m_staticText1 = new wxStaticText( m_scrolledWindow1, wxID_ANY,
273 contributor->GetCategory() + wxT( ":" ),
274 wxDefaultPosition, wxDefaultSize, 0 );
275 m_staticText1->SetFont( m_staticText1->GetFont().Bold() );
276 m_staticText1->Wrap( -1 );
277 fgSizer1->Add( m_staticText1, 0, wxALIGN_LEFT|wxBOTTOM|wxEXPAND, 2 );
278
279 // Nothing at third column
280 fgSizer1->AddSpacer( 5 );
281
282 // Now, all contributors of the same category will follow
283 for( size_t j=0; j < aContributors.GetCount(); ++j )
284 {
285 CONTRIBUTOR* sub_contributor = &aContributors.Item( j );
286
287 if ( sub_contributor->GetCategory() == category )
288 {
289 // First column is empty
290 fgSizer1->AddSpacer( 5 );
291
292 wxControl* ctrl;
293
294 // No URL supplied, display normal text control
295 if( sub_contributor->GetUrl().IsEmpty() )
296 {
297 ctrl = new wxStaticText( m_scrolledWindow1, wxID_ANY,
298 padding + wxT( "• " ) + sub_contributor->GetName(),
299 wxDefaultPosition,
300 wxDefaultSize, 0 );
301 }
302 else
303 {
304 // Display a hyperlink control instead
305 ctrl = new wxHyperlinkCtrl( m_scrolledWindow1, wxID_ANY,
306 wxT( "• " ) + sub_contributor->GetName(),
307 sub_contributor->GetUrl(),
308 wxDefaultPosition,
309 wxDefaultSize,
310 wxBORDER_NONE | wxHL_CONTEXTMENU | wxHL_ALIGN_LEFT );
311 }
312
313 m_staticText1->Wrap( -1 );
314
315 fgSizer1->Add( ctrl, 0, wxALIGN_LEFT|wxBOTTOM, 2 );
316
317 // Email address of contributor at third column
318 if( sub_contributor->GetExtra() != wxEmptyString )
319 {
320 wxStaticText* mail = wxStaticTextRef( m_scrolledWindow1,
321 sub_contributor->GetExtra() );
322 fgSizer1->Add( mail, 0, wxALIGN_LEFT|wxBOTTOM, 2 );
323 }
324 else
325 {
326 fgSizer1->AddSpacer( 5 );
327 }
328
329 /* this contributor was added to the GUI,
330 * thus can be ignored next time
331 */
332 sub_contributor->SetChecked( true );
333 }
334 }
335 }
336 else
337 {
338 continue;
339 }
340 }
341
342 /* Now, lets list the remaining contributors that have not been considered
343 * because they were not assigned to any category.
344 */
345 for ( size_t k=0; k < aContributors.GetCount(); ++k )
346 {
347 CONTRIBUTOR* contributor = &aContributors.Item( k );
348
349 if ( contributor->IsChecked() )
350 continue;
351
352 // Icon at first column
353 wxStaticBitmap* m_bitmap1 = createStaticBitmap( m_scrolledWindow1, contributor->GetIcon() );
354 fgSizer1->Add( m_bitmap1, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 5 );
355
356 // Name of contributor at second column
357 if( contributor->GetName() != wxEmptyString )
358 {
359 wxStaticText* m_staticText1 = new wxStaticText( m_scrolledWindow1, wxID_ANY,
360 contributor->GetName(),
361 wxDefaultPosition, wxDefaultSize, 0 );
362 m_staticText1->Wrap( -1 );
363 fgSizer1->Add( m_staticText1, 0, wxALIGN_LEFT|wxBOTTOM, 2 );
364 }
365 else
366 {
367 fgSizer1->AddSpacer( 5 );
368 }
369
370 // Email address of contributor at third column
371 if ( contributor->GetExtra() != wxEmptyString )
372 {
373 wxStaticText* mail = wxStaticTextRef( m_scrolledWindow1, contributor->GetExtra() );
374 fgSizer1->Add( mail, 0, wxALIGN_LEFT|wxBOTTOM, 2 );
375 }
376 else
377 {
378 fgSizer1->AddSpacer( 5 );
379 }
380 }
381
382 bSizer->Add( panel1, 1, wxEXPAND|wxALL, 10 );
383 bSizer->Add( fgSizer1, 7, wxEXPAND|wxALL, 10 ); // adjust width of panel with first int value
384 m_scrolledWindow1->SetSizer( bSizer );
385 m_scrolledWindow1->Layout();
386 bSizer->Fit( m_scrolledWindow1 );
387
388 outerSizer->Add( m_scrolledWindow1, 1, wxEXPAND, 0 );
389 outerPanel->SetSizer( outerSizer );
390
391 aParent->AddPage( outerPanel, aCaption, false, static_cast<int>( aIconIndex ) );
392}
393
394
395void DIALOG_ABOUT::createNotebookHtmlPage( wxNotebook* aParent, const wxString& aCaption,
396 IMAGES aIconIndex, const wxString& html,
397 bool aSelection )
398{
399 wxPanel* panel = new wxPanel( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
400 wxTAB_TRAVERSAL );
401
402 wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
403
404 int flags = aSelection ? wxHW_SCROLLBAR_AUTO : ( wxHW_SCROLLBAR_AUTO | wxHW_NO_SELECTION );
405
406 // the HTML page is going to be created with previously created HTML content
407 HTML_WINDOW* htmlWindow = new HTML_WINDOW( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize,
408 flags );
409
410 // HTML font set to font properties as they are used for widgets to have an unique look
411 // under different platforms with HTML
412 wxFont font = GetFont();
413 htmlWindow->SetStandardFonts( font.GetPointSize(), font.GetFaceName(), font.GetFaceName() );
414 htmlWindow->SetPage( html );
415
416 // the HTML window shall not be used to open external links, thus this task is delegated
417 // to users default browser
418 htmlWindow->Connect( wxEVT_COMMAND_HTML_LINK_CLICKED,
419 wxHtmlLinkEventHandler( DIALOG_ABOUT::onHtmlLinkClicked ), NULL, this );
420
421 // no additional space around the HTML window as it is also the case by the other notebook pages
422 bSizer->Add( htmlWindow, 1, wxEXPAND, 0 );
423 panel->SetSizer( bSizer );
424
425 aParent->AddPage( panel, aCaption, false, static_cast<int>( aIconIndex ) );
426}
427
428
429wxStaticText* DIALOG_ABOUT::wxStaticTextRef( wxScrolledWindow* aParent, const wxString& aReference )
430{
431 wxStaticText* text = new wxStaticText( aParent, wxID_ANY,
432 wxT( "(" ) + aReference + wxT( ")" ) );
433
434 return text;
435}
436
437
438wxStaticBitmap* DIALOG_ABOUT::createStaticBitmap( wxScrolledWindow* aParent, wxBitmap* aIcon )
439{
440 wxStaticBitmap* bitmap = new wxStaticBitmap( aParent, wxID_ANY, wxNullBitmap,
441 wxDefaultPosition, wxDefaultSize, 0 );
442
443 if( aIcon )
444 bitmap->SetBitmap( *aIcon );
445 else
446 bitmap->SetBitmap( KiBitmapBundle( BITMAPS::right ) );
447
448 return bitmap;
449}
450
451
452void DIALOG_ABOUT::onHtmlLinkClicked( wxHtmlLinkEvent& event )
453{
454 ::wxLaunchDefaultBrowser( event.GetLinkInfo().GetHref() );
455}
456
457
458void DIALOG_ABOUT::onCopyVersionInfo( wxCommandEvent& event )
459{
460 wxLogNull doNotLog; // disable logging of failed clipboard actions
461
462 if( !wxTheClipboard->Open() )
463 {
464 wxMessageBox( _( "Could not open clipboard to write version information." ),
465 _( "Clipboard Error" ), wxOK | wxICON_EXCLAMATION, this );
466 return;
467 }
468
469 wxString msg_version = GetVersionInfoData( m_untranslatedTitleName );
470
471 wxTheClipboard->SetData( new wxTextDataObject( msg_version ) );
472 wxTheClipboard->Flush(); // Allow clipboard data to be available after KiCad closes
473 wxTheClipboard->Close();
474 m_btCopyVersionInfo->SetLabel( _( "Copied..." ) );
475}
476
477
478void DIALOG_ABOUT::onDonateClick( wxCommandEvent& event )
479{
480 if( TOOL_MANAGER* mgr = static_cast<EDA_BASE_FRAME*>( GetParent() )->GetToolManager() )
481 mgr->RunAction( "common.SuiteControl.donate" );
482}
483
484
485void DIALOG_ABOUT::onReportBug( wxCommandEvent& event )
486{
487 if( TOOL_MANAGER* mgr = static_cast<EDA_BASE_FRAME*>( GetParent() )->GetToolManager() )
488 mgr->RunAction( "common.SuiteControl.reportBug" );
489}
490
491
492void DIALOG_ABOUT::OnNotebookPageChanged( wxNotebookEvent& aEvent )
493{
494 // Work around wxMac issue where the notebook pages are blank
495#ifdef __WXMAC__
496 int page = aEvent.GetSelection();
497
498 if( page >= 0 )
499 m_notebook->ChangeSelection( static_cast<unsigned>( page ) );
500#endif
501}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap)
Definition: bitmap.cpp:110
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:104
wxString GetVersionInfoData(const wxString &aTitle, bool aHtml, bool aBrief)
Create a version info string for bug reports and the about dialog.
bool IsNightlyVersion()
Check if the build is meant to be nightly.
An object of this class is meant to be used to store application specific information like who has co...
Definition: aboutinfo.h:45
CONTRIBUTORS GetPackagers()
Definition: aboutinfo.h:91
CONTRIBUTORS GetLibrarians()
Definition: aboutinfo.h:88
wxString GetCopyright()
Definition: aboutinfo.h:100
wxString & GetLibVersion()
Definition: aboutinfo.h:112
CONTRIBUTORS GetDevelopers()
Definition: aboutinfo.h:86
CONTRIBUTORS GetDocWriters()
Definition: aboutinfo.h:87
wxString & GetBuildVersion()
Definition: aboutinfo.h:106
wxString & GetDescription()
Definition: aboutinfo.h:94
CONTRIBUTORS GetTranslators()
Definition: aboutinfo.h:90
CONTRIBUTORS GetArtists()
Definition: aboutinfo.h:89
wxIcon & GetAppIcon()
Wrapper to manage memory allocation for bitmaps.
Definition: aboutinfo.h:115
wxString & GetLicense()
Definition: aboutinfo.h:97
A contributor, a person which was involved in the development of the application or which has contrib...
Definition: aboutinfo.h:161
wxString & GetName()
Definition: aboutinfo.h:191
wxString & GetUrl()
Definition: aboutinfo.h:193
wxString & GetExtra()
Definition: aboutinfo.h:192
wxString & GetCategory()
Definition: aboutinfo.h:194
wxBitmap * GetIcon()
Definition: aboutinfo.h:195
bool IsChecked()
Definition: aboutinfo.h:197
void SetChecked(bool status)
Definition: aboutinfo.h:196
Class DIALOG_ABOUT_BASE.
wxStaticText * m_staticTextBuildVersion
wxStaticBitmap * m_bitmapApp
wxStaticText * m_staticTextCopyright
wxStaticText * m_staticTextLibVersion
wxButton * m_btCopyVersionInfo
wxNotebook * m_notebook
wxStaticText * m_staticTextAppTitle
void OnNotebookPageChanged(wxNotebookEvent &aEvent) override
wxString m_titleName
Definition: dialog_about.h:57
wxImageList * m_images
Definition: dialog_about.h:56
wxString m_untranslatedTitleName
Definition: dialog_about.h:58
void createNotebookPage(wxNotebook *aParent, const wxString &aCaption, IMAGES aIconIndex, const CONTRIBUTORS &aContributors)
void createNotebooks()
ABOUT_APP_INFO & m_info
Definition: dialog_about.h:60
void createNotebookPageByCategory(wxNotebook *aParent, const wxString &aCaption, IMAGES aIconIndex, const CONTRIBUTORS &aContributors)
DIALOG_ABOUT(EDA_BASE_FRAME *aParent, ABOUT_APP_INFO &aAppInfo)
wxStaticBitmap * createStaticBitmap(wxScrolledWindow *aParent, wxBitmap *icon)
void onCopyVersionInfo(wxCommandEvent &event) override
void onHtmlLinkClicked(wxHtmlLinkEvent &event)
wxFlexGridSizer * createFlexGridSizer()
void onReportBug(wxCommandEvent &event) override
wxStaticText * wxStaticTextRef(wxScrolledWindow *aParent, const wxString &aReference)
void onDonateClick(wxCommandEvent &event) override
void createNotebookHtmlPage(wxNotebook *aParent, const wxString &aCaption, IMAGES aIconIndex, const wxString &aHtmlMessage, bool aSelection=false)
The base frame for deriving all KiCad main window classes.
const wxString & GetUntranslatedAboutTitle() const
const wxString & GetAboutTitle() const
Add dark theme support to wxHtmlWindow.
Definition: html_window.h:34
bool SetPage(const wxString &aSource) override
Definition: html_window.cpp:38
Master controller class:
Definition: tool_manager.h:57
IMAGES
Definition: dialog_about.h:37
#define _(s)