diff --git a/kicad/dialogs/dialog_template_selector.cpp b/kicad/dialogs/dialog_template_selector.cpp index d1b111a80e..c4d05f2811 100644 --- a/kicad/dialogs/dialog_template_selector.cpp +++ b/kicad/dialogs/dialog_template_selector.cpp @@ -30,96 +30,10 @@ #include #include #include +#include +#include "template_default_html.h" -static const wxString GetWelcomeHtml() -{ - return wxString( - "" - "" - "" - "" - "" - "KiCad Project Template Selector" - "" - "" - "" - "
" - "
" - "
KiCad 📑
" - "
" + _( "Project Template Selector" ) + "
" - "
" - "
" - "

" + _( "Welcome to Template Selection!" ) + "

" - "

" + _( "Choose from a variety of pre-configured project templates to jumpstart your PCB design. Templates provide ready-to-use project structures with common components, libraries, and design rules." ) + "

" - "
" - "
" - "
" - "

→ " + _( "Browse Templates" ) + "

" - "

" + _( "Navigate through the template tabs above to explore different categories of project templates. Each tab contains templates organized by type or complexity." ) + "

" - "
" - "
" - "

→ " + _( "Select a Template" ) + "

" - "

" + _( "Click on any template in the list to " ) + "" + _( "preview its details" ) + ". " + _( "The template information will appear in this panel, showing descriptions, included components, and project structure." ) + "

" - "
" - "
" - "

→ " + _( "Customize Path" ) + "

" - "

" + _( "Use the " ) + "" + _( "folder path field" ) + " " + _( "above to browse custom template directories. Click the folder icon to browse, or the refresh icon to reload templates." ) + "

" - "
" - "
" - "

→ " + _( "Create Project" ) + "

" - "

" + _( "Once you've found the right template, click " ) + "" + _( "OK" ) + " " + _( "to create a new project based on the selected template. Your project will inherit all template settings and files." ) + "

" - "
" - "
" - "
" - "

" + _( "What You Get with Templates" ) + "

" - "
    " - "
  • " + _( "Pre-configured libraries" ) + " " + _( "- Common components and footprints already linked" ) + "
  • " - "
  • " + _( "Design rules" ) + " " + _( "- Appropriate electrical and mechanical constraints" ) + "
  • " - "
  • " + _( "Layer stackups" ) + " " + _( "- Optimized for the intended application" ) + "
  • " - "
  • " + _( "Component placement" ) + " " + _( "- Basic layout and routing guidelines" ) + "
  • " - "
  • " + _( "Documentation" ) + " " + _( "- README files and design notes" ) + "
  • " - "
  • " + _( "Manufacturing files" ) + " " + _( "- Gerber and drill file configurations" ) + "
  • " - "
" - "
" - "
" - "

" + _( "Pro Tips" ) + "

" - "

" + _( "Start Simple:" ) + " " + _( "Begin with basic templates and add more elements as you go." ) + "

" - "

" + _( "Customize Later:" ) + " " + _( "Templates are starting points - you can modify libraries, rules, and layouts after project creation." ) + "

" - "

" + _( "Save Your Own:" ) + " " + _( "Once you develop preferred settings, create a custom template for future projects." ) + "

" - "
" - "
" - "" - "" -); -} +// Welcome / fallback HTML now provided by template_default_html.h TEMPLATE_SELECTION_PANEL::TEMPLATE_SELECTION_PANEL( wxNotebookPage* aParent, const wxString& aPath ) : @@ -182,7 +96,12 @@ void TEMPLATE_WIDGET::SetTemplate( PROJECT_TEMPLATE* aTemplate ) m_staticTitle->SetFont( KIUI::GetInfoFont( this ) ); m_staticTitle->SetLabel( *aTemplate->GetTitle() ); m_staticTitle->Wrap( 100 ); - m_bitmapIcon->SetBitmap( *aTemplate->GetIcon() ); + wxBitmap* icon = aTemplate->GetIcon(); + + if( icon && icon->IsOk() ) + m_bitmapIcon->SetBitmap( *icon ); + else + m_bitmapIcon->SetBitmap( KiBitmap( BITMAPS::icon_kicad ) ); } @@ -229,7 +148,7 @@ void DIALOG_TEMPLATE_SELECTOR::OnPageChange( wxNotebookEvent& event ) DIALOG_TEMPLATE_SELECTOR::DIALOG_TEMPLATE_SELECTOR( wxWindow* aParent, const wxPoint& aPos, const wxSize& aSize, - std::map aTitleDirMap, + std::vector> aTitleDirList, const wxFileName& aDefaultTemplate ) : DIALOG_TEMPLATE_SELECTOR_BASE( aParent, wxID_ANY, _( "Project Template Selector" ), aPos, aSize ) @@ -241,7 +160,7 @@ DIALOG_TEMPLATE_SELECTOR::DIALOG_TEMPLATE_SELECTOR( wxWindow* aParent, const wxP m_defaultTemplatePath = aDefaultTemplate; m_defaultWidget = nullptr; - for( auto& [title, pathFname] : aTitleDirMap ) + for( auto& [title, pathFname] : aTitleDirList ) { pathFname.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS ); wxString path = pathFname.GetFullPath(); // caller ensures this ends with file separator. @@ -291,7 +210,7 @@ DIALOG_TEMPLATE_SELECTOR::DIALOG_TEMPLATE_SELECTOR( wxWindow* aParent, const wxP { wxFileName htmlFile = m_selectedWidget->GetTemplate()->GetHtmlFile(); - if( htmlFile.FileExists() && htmlFile.IsFileReadable() ) + if( htmlFile.FileExists() && htmlFile.IsFileReadable() && htmlFile.GetSize() > 100 /* Basic HTML */ ) m_webviewPanel->LoadURL( wxFileName::FileNameToURL( htmlFile ) ); else m_webviewPanel->SetPage( GetWelcomeHtml() ); @@ -321,21 +240,7 @@ void DIALOG_TEMPLATE_SELECTOR::SetWidget( TEMPLATE_WIDGET* aWidget ) } else { - // Fallback to a simple template info page if no HTML file exists - wxString templateHtml = wxString::Format( - "" - "" - "
" - "

%s

" - "

Template selected. Click OK to create a new project based on this template.

" - "
", - *aWidget->GetTemplate()->GetTitle() - ); - m_webviewPanel->SetPage( templateHtml ); + m_webviewPanel->SetPage( GetTemplateInfoHtml( *aWidget->GetTemplate()->GetTitle() ) ); } } @@ -345,12 +250,21 @@ void DIALOG_TEMPLATE_SELECTOR::AddTemplate( int aPage, PROJECT_TEMPLATE* aTempla TEMPLATE_WIDGET* w = new TEMPLATE_WIDGET( m_panels[aPage]->m_scrolledWindow, this ); w->SetTemplate( aTemplate ); m_panels[aPage]->AddTemplateWidget( w ); + m_allWidgets.push_back( w ); wxFileName base = aTemplate->GetHtmlFile(); base.RemoveLastDir(); - if( m_defaultTemplatePath.IsOk() && base == m_defaultTemplatePath ) + if( !m_defaultWidget || (m_defaultTemplatePath.IsOk() && base == m_defaultTemplatePath) ) m_defaultWidget = w; + + wxString dirName = base.GetDirs().IsEmpty() ? wxString() : base.GetDirs().back(); + + if( dirName.CmpNoCase( "default" ) == 0 ) + { + // Prefer a directory literally named 'default' + m_defaultWidget = w; + } } @@ -359,6 +273,11 @@ PROJECT_TEMPLATE* DIALOG_TEMPLATE_SELECTOR::GetSelectedTemplate() return m_selectedWidget? m_selectedWidget->GetTemplate() : nullptr; } +PROJECT_TEMPLATE* DIALOG_TEMPLATE_SELECTOR::GetDefaultTemplate() +{ + return m_defaultWidget? m_defaultWidget->GetTemplate() : nullptr; +} + void DIALOG_TEMPLATE_SELECTOR::buildPageContent( const wxString& aPath, int aPage ) { diff --git a/kicad/dialogs/dialog_template_selector.h b/kicad/dialogs/dialog_template_selector.h index b4d93c3b42..4a1e28144c 100644 --- a/kicad/dialogs/dialog_template_selector.h +++ b/kicad/dialogs/dialog_template_selector.h @@ -29,7 +29,8 @@ #include #include "project_template.h" -#include +#include +#include #include class DIALOG_TEMPLATE_SELECTOR; @@ -91,13 +92,14 @@ class DIALOG_TEMPLATE_SELECTOR : public DIALOG_TEMPLATE_SELECTOR_BASE { public: DIALOG_TEMPLATE_SELECTOR( wxWindow* aParent, const wxPoint& aPos, const wxSize& aSize, - std::map aTitleDirMap, + std::vector> aTitleDirList, const wxFileName& aDefaultTemplate ); /** * @return the selected template, or NULL */ PROJECT_TEMPLATE* GetSelectedTemplate(); + PROJECT_TEMPLATE* GetDefaultTemplate(); void SetWidget( TEMPLATE_WIDGET* aWidget ); @@ -123,6 +125,8 @@ protected: TEMPLATE_WIDGET* m_selectedWidget; wxFileName m_defaultTemplatePath; TEMPLATE_WIDGET* m_defaultWidget; + // Keep track of all template widgets so we can pick a sensible default + std::vector m_allWidgets; }; #endif diff --git a/kicad/dialogs/template_default_html.h b/kicad/dialogs/template_default_html.h new file mode 100644 index 0000000000..beb4672c42 --- /dev/null +++ b/kicad/dialogs/template_default_html.h @@ -0,0 +1,149 @@ +/* + * KiCad Project Template HTML defaults + * Extracted from dialog_template_selector.cpp to allow reuse and to provide + * a styled fallback page when a template does not supply an info.html. + */ + +#ifndef KICAD_TEMPLATE_DEFAULT_HTML_H +#define KICAD_TEMPLATE_DEFAULT_HTML_H + +#include + +// Uses _() translation macro which is defined globally in KiCad builds. + +// Welcome (no template selected) page. +inline wxString GetWelcomeHtml() +{ + return wxString( + "" + "" + "" + "" + "" + "KiCad Project Template Selector" + "" + "" + "" + "
" + "
" + "
KiCad 📑
" + "
" + _( "Project Template Selector" ) + "
" + "
" + "
" + "

" + _( "Welcome to Template Selection!" ) + "

" + "

" + _( "Choose from a variety of pre-configured project templates to jumpstart your PCB design. Templates provide ready-to-use project structures with common components, libraries, and design rules." ) + "

" + "
" + "
" + "
" + "

→ " + _( "Browse Templates" ) + "

" + "

" + _( "Navigate through the template tabs above to explore different categories of project templates. Each tab contains templates organized by type or complexity." ) + "

" + "
" + "
" + "

→ " + _( "Select a Template" ) + "

" + "

" + _( "Click on any template in the list to " ) + "" + _( "preview its details" ) + ". " + _( "The template information will appear in this panel, showing descriptions, included components, and project structure." ) + "

" + "
" + "
" + "

→ " + _( "Customize Path" ) + "

" + "

" + _( "Use the " ) + "" + _( "folder path field" ) + " " + _( "above to browse custom template directories. Click the folder icon to browse, or the refresh icon to reload templates." ) + "

" + "
" + "
" + "

→ " + _( "Create Project" ) + "

" + "

" + _( "Once you've found the right template, click " ) + "" + _( "OK" ) + " " + _( "to create a new project based on the selected template. Your project will inherit all template settings and files." ) + "

" + "
" + "
" + "
" + "

" + _( "What You Get with Templates" ) + "

" + "
    " + "
  • " + _( "Pre-configured libraries" ) + " " + _( "- Common components and footprints already linked" ) + "
  • " + "
  • " + _( "Design rules" ) + " " + _( "- Appropriate electrical and mechanical constraints" ) + "
  • " + "
  • " + _( "Layer stackups" ) + " " + _( "- Optimized for the intended application" ) + "
  • " + "
  • " + _( "Component placement" ) + " " + _( "- Basic layout and routing guidelines" ) + "
  • " + "
  • " + _( "Documentation" ) + " " + _( "- README files and design notes" ) + "
  • " + "
  • " + _( "Manufacturing files" ) + " " + _( "- Gerber and drill file configurations" ) + "
  • " + "
" + "
" + "
" + "

" + _( "Pro Tips" ) + "

" + "

" + _( "Start Simple:" ) + " " + _( "Begin with basic templates and add more elements as you go." ) + "

" + "

" + _( "Customize Later:" ) + " " + _( "Templates are starting points - you can modify libraries, rules, and layouts after project creation." ) + "

" + "

" + _( "Save Your Own:" ) + " " + _( "Once you develop preferred settings, create a custom template for future projects." ) + "

" + "
" + "
" + "" + "" + ); +} + +// Fallback when a specific template has no meta/info.html. +inline wxString GetTemplateInfoHtml( const wxString& aTemplateName ) +{ + return wxString( + "" + "" + "" + "" + "" + "" + aTemplateName + " - KiCad Template" + "" + "
" + "
" + _( "Template" ) + "

" + aTemplateName + "

" + "

" + _( "This project template doesn't include an info page yet. You can still use it to create a new project." ) + "

" + "
" + "" + _( "To use this template:" ) + "" + "
" + "

1. " + _( "Create the project" ) + "

" + _( "Click OK below. KiCad will create a new project folder populated with the contents of this template." ) + "

" + "

2. " + _( "Open schematic and PCB" ) + "

" + _( "Use the Project Manager tree or launch Schematic and PCB editors to begin designing." ) + "

" + "

3. " + _( "Review libraries & settings" ) + "

" + _( "Confirm symbol/footprint libraries, design rules, and board stackup match your needs." ) + "

" + "
" // steps + "
" // cta + "
" + "" + _( "Add an info page later:" ) + "" + "

" + _( "Create a file at" ) + " meta/info.html " + _( "inside this template's directory to provide rich documentation, images, or guidance." ) + "

" + "

" + _( "You can copy styling from the default pages for consistency." ) + "

" + "
" + "
" + ); +} + +#endif // KICAD_TEMPLATE_DEFAULT_HTML_H diff --git a/kicad/tools/kicad_manager_control.cpp b/kicad/tools/kicad_manager_control.cpp index 3181a6adc2..94773a236a 100644 --- a/kicad/tools/kicad_manager_control.cpp +++ b/kicad/tools/kicad_manager_control.cpp @@ -203,28 +203,28 @@ int KICAD_MANAGER_CONTROL::NewProject( const TOOL_EVENT& aEvent ) } KICAD_SETTINGS* settings = GetAppSettings( "kicad" ); - std::map titleDirMap; + std::vector> titleDirList; wxFileName templatePath; + ENV_VAR_MAP_CITER itUser = Pgm().GetLocalEnvVariables().find( "KICAD_USER_TEMPLATE_DIR" ); + + if( itUser != Pgm().GetLocalEnvVariables().end() && itUser->second.GetValue() != wxEmptyString ) + { + templatePath.AssignDir( itUser->second.GetValue() ); + titleDirList.emplace_back( _( "User Templates" ), templatePath ); + } + std::optional v = ENV_VAR::GetVersionedEnvVarValue( Pgm().GetLocalEnvVariables(), wxT( "TEMPLATE_DIR" ) ); if( v && !v->IsEmpty() ) { templatePath.AssignDir( *v ); - titleDirMap.emplace( _( "System Templates" ), templatePath ); - } - - ENV_VAR_MAP_CITER itUser = Pgm().GetLocalEnvVariables().find( "KICAD_USER_TEMPLATE_DIR" ); - - if( itUser != Pgm().GetLocalEnvVariables().end() && itUser->second.GetValue() != wxEmptyString ) - { - templatePath.AssignDir( itUser->second.GetValue() ); - titleDirMap.emplace( _( "User Templates" ), templatePath ); + titleDirList.emplace_back( _( "System Templates" ), templatePath ); } DIALOG_TEMPLATE_SELECTOR ps( m_frame, settings->m_TemplateWindowPos, settings->m_TemplateWindowSize, - titleDirMap, defaultTemplate ); + titleDirList, defaultTemplate ); int result = ps.ShowModal(); @@ -234,7 +234,12 @@ int KICAD_MANAGER_CONTROL::NewProject( const TOOL_EVENT& aEvent ) if( result != wxID_OK ) return -1; - if( !ps.GetSelectedTemplate() ) + PROJECT_TEMPLATE* selectedTemplate = ps.GetSelectedTemplate(); + + if( !selectedTemplate ) + selectedTemplate = ps.GetDefaultTemplate(); + + if( !selectedTemplate ) { wxMessageBox( _( "No project template was selected. Cannot generate new project." ), _( "Error" ), wxOK | wxICON_ERROR, m_frame ); @@ -288,7 +293,7 @@ int KICAD_MANAGER_CONTROL::NewProject( const TOOL_EVENT& aEvent ) std::vector< wxFileName > destFiles; - if( ps.GetSelectedTemplate()->GetDestinationFiles( fn, destFiles ) ) + if( selectedTemplate->GetDestinationFiles( fn, destFiles ) ) { std::vector overwrittenFiles; @@ -318,7 +323,7 @@ int KICAD_MANAGER_CONTROL::NewProject( const TOOL_EVENT& aEvent ) wxString errorMsg; - if( !ps.GetSelectedTemplate()->CreateProject( fn, &errorMsg ) ) + if( !selectedTemplate->CreateProject( fn, &errorMsg ) ) { DisplayErrorMessage( m_frame, _( "A problem occurred creating new project from template." ), errorMsg ); return -1;