2525import com .codename1 .ui .RadioButton ;
2626import com .codename1 .ui .TextArea ;
2727import com .codename1 .ui .TextField ;
28+ import com .codename1 .ui .events .FocusListener ;
2829import com .codename1 .ui .layouts .BorderLayout ;
2930import com .codename1 .ui .layouts .BoxLayout ;
3031import com .codename1 .ui .layouts .GridLayout ;
@@ -53,6 +54,8 @@ public void runApp() {
5354 final ProjectOptions .PreviewLanguage [] previewLanguage = new ProjectOptions .PreviewLanguage []{ProjectOptions .PreviewLanguage .ENGLISH };
5455 final ProjectOptions .JavaVersion [] javaVersion = new ProjectOptions .JavaVersion []{ProjectOptions .JavaVersion .JAVA_8 };
5556 final String [] customThemeCss = new String []{"" };
57+ final String [] lastValidCustomThemeCss = new String []{"" };
58+ final TextArea [] customCssEditorRef = new TextArea [1 ];
5659 final RadioButton [] templateButtons = new RadioButton [Template .values ().length ];
5760 final SpanLabel summaryLabel = new SpanLabel ();
5861 final TemplatePreviewPanel previewPanel = new TemplatePreviewPanel (selectedTemplate [0 ]);
@@ -75,10 +78,15 @@ public void runApp() {
7578
7679 final Runnable refresh = new Runnable () {
7780 public void run () {
81+ String liveCustomCss = "" ;
82+ if (customCssEditorRef [0 ] != null && customCssEditorRef [0 ].getText () != null ) {
83+ liveCustomCss = customCssEditorRef [0 ].getText ();
84+ }
85+ customThemeCss [0 ] = liveCustomCss ;
7886 ProjectOptions options = new ProjectOptions (
7987 selectedThemeMode [0 ], selectedAccent [0 ], roundedButtons [0 ],
8088 includeLocalizationBundles [0 ], previewLanguage [0 ], javaVersion [0 ],
81- customThemeCss [ 0 ]
89+ liveCustomCss
8290 );
8391 customCssValid [0 ] = true ;
8492 customCssError .setText ("" );
@@ -87,11 +95,20 @@ public void run() {
8795 try {
8896 previewPanel .setTemplate (selectedTemplate [0 ]);
8997 previewPanel .setOptions (options );
98+ lastValidCustomThemeCss [0 ] = liveCustomCss ;
9099 } catch (IllegalArgumentException cssErr ) {
91100 customCssValid [0 ] = false ;
92101 customCssError .setText ("Custom CSS Error: " + cssErr .getMessage ());
93102 customCssError .setHidden (false );
94103 customCssError .setVisible (true );
104+ // Keep the preview responsive to theme toggles while the current CSS is invalid.
105+ ProjectOptions fallbackOptions = new ProjectOptions (
106+ selectedThemeMode [0 ], selectedAccent [0 ], roundedButtons [0 ],
107+ includeLocalizationBundles [0 ], previewLanguage [0 ], javaVersion [0 ],
108+ lastValidCustomThemeCss [0 ]
109+ );
110+ previewPanel .setTemplate (selectedTemplate [0 ]);
111+ previewPanel .setOptions (fallbackOptions );
95112 }
96113 boolean canCustomizeTheme = supportsLivePreview (selectedTemplate [0 ]);
97114 if (themePanelRef [0 ] != null ) {
@@ -117,7 +134,7 @@ public void run() {
117134 createTemplateSelector (selectedTemplate , templateButtons , refresh )
118135 );
119136 final Container idePanel = createIdeSelectorPanel (selectedIde , refresh );
120- final Container themePanel = createThemeOptionsPanel (selectedThemeMode , selectedAccent , roundedButtons , customThemeCss , customCssError , refresh );
137+ final Container themePanel = createThemeOptionsPanel (selectedThemeMode , selectedAccent , roundedButtons , customThemeCss , customCssEditorRef , customCssError , refresh );
121138 final Container localizationPanel = createLocalizationPanel (includeLocalizationBundles , previewLanguage , refresh , previewPanel );
122139 final Container javaPanel = createJavaOptionsPanel (javaVersion , refresh );
123140 themePanelRef [0 ] = themePanel ;
@@ -153,10 +170,14 @@ public void run() {
153170 }
154171 String appName = appNameField .getText () == null ? "" : appNameField .getText ().trim ();
155172 String packageName = packageField .getText () == null ? "" : packageField .getText ().trim ();
173+ String liveCustomCss = "" ;
174+ if (customCssEditorRef [0 ] != null && customCssEditorRef [0 ].getText () != null ) {
175+ liveCustomCss = customCssEditorRef [0 ].getText ();
176+ }
156177 ProjectOptions options = new ProjectOptions (
157178 selectedThemeMode [0 ], selectedAccent [0 ], roundedButtons [0 ],
158179 includeLocalizationBundles [0 ], previewLanguage [0 ], javaVersion [0 ],
159- customThemeCss [ 0 ]
180+ liveCustomCss
160181 );
161182 GeneratorModel .create (selectedIde [0 ], selectedTemplate [0 ], appName , packageName , options ).generate ();
162183 });
@@ -281,6 +302,7 @@ private Container createThemeOptionsPanel(ProjectOptions.ThemeMode[] selectedThe
281302 ProjectOptions .Accent [] selectedAccent ,
282303 boolean [] roundedButtons ,
283304 String [] customThemeCss ,
305+ TextArea [] customCssEditorRef ,
284306 Label customCssError ,
285307 Runnable onSelectionChanged ) {
286308 Container modeRow = new Container (new GridLayout (1 , 2 ));
@@ -336,9 +358,18 @@ private Container createThemeOptionsPanel(ProjectOptions.ThemeMode[] selectedThe
336358 cssEditor .setUIID ("InitializrField" );
337359 cssEditor .setHint ("/* Appended to generated theme.css */\n Button {\n border-radius: 0;\n }" );
338360 cssEditor .setGrowByContent (true );
339- cssEditor .addDataChangedListener ((type , index ) -> {
340- customThemeCss [0 ] = cssEditor .getText ();
341- onSelectionChanged .run ();
361+ customCssEditorRef [0 ] = cssEditor ;
362+ cssEditor .addDataChangedListener ((type , index ) -> onSelectionChanged .run ());
363+ cssEditor .addActionListener (e -> onSelectionChanged .run ());
364+ cssEditor .addFocusListener (new FocusListener () {
365+ @ Override
366+ public void focusGained (Component cmp ) {
367+ }
368+
369+ @ Override
370+ public void focusLost (Component cmp ) {
371+ onSelectionChanged .run ();
372+ }
342373 });
343374
344375 return BoxLayout .encloseY (
0 commit comments