3636import com .codename1 .ui .plaf .UIManager ;
3737import com .codename1 .ui .util .Resources ;
3838import com .codename1 .io .Log ;
39+ import com .codename1 .io .Preferences ;
3940import com .codename1 .io .Properties ;
4041import com .codename1 .io .Storage ;
4142import com .codename1 .io .Util ;
4849import com .codename1 .ui .Graphics ;
4950import com .codename1 .ui .Image ;
5051import com .codename1 .ui .Tabs ;
52+ import com .codename1 .ui .TextArea ;
5153import com .codename1 .ui .TextField ;
5254import com .codename1 .ui .Toolbar ;
5355import com .codename1 .ui .events .ActionEvent ;
5860import com .codename1 .ui .plaf .Style ;
5961import com .codename1 .ui .spinner .Picker ;
6062import com .codename1 .ui .util .ImageIO ;
63+ import com .codename1 .ui .validation .NumericConstraint ;
64+ import com .codename1 .ui .validation .RegexConstraint ;
65+ import com .codename1 .ui .validation .Validator ;
6166import com .codename1 .util .Base64 ;
6267import java .io .ByteArrayOutputStream ;
6368import java .io .IOException ;
@@ -85,7 +90,37 @@ interface ImageSettings {
8590 Image getSkinImage ();
8691 }
8792
88- private ImageSettings createImageSettings (String imageFile ) {
93+ private void autoSave (TextArea ta , String preferencesKey ) {
94+ String val = Preferences .get (preferencesKey , null );
95+ if (val != null ) {
96+ ta .setText (val );
97+ }
98+ ta .addActionListener (e -> {
99+ Preferences .set (preferencesKey , ta .getText ());
100+ });
101+ }
102+
103+ private void autoSave (OnOffSwitch o , String preferencesKey ) {
104+ boolean val = Preferences .get (preferencesKey , o .isValue ());
105+ if (val != o .isValue ()) {
106+ o .setValue (val );
107+ }
108+ o .addActionListener (e -> {
109+ Preferences .set (preferencesKey , o .isValue ());
110+ });
111+ }
112+
113+ private void autoSave (Picker p , String preferencesKey ) {
114+ String val = Preferences .get (preferencesKey , null );
115+ if (val != null ) {
116+ p .setSelectedString (val );
117+ }
118+ p .addActionListener (e -> {
119+ Preferences .set (preferencesKey , p .getSelectedString ());
120+ });
121+ }
122+
123+ private ImageSettings createImageSettings (String imageFile , String prefix , Validator vl ) {
89124 Image img = null ;
90125 try {
91126 img = Image .createImage (Display .getInstance ().getResourceAsStream (getClass (), imageFile ));
@@ -98,19 +133,37 @@ private ImageSettings createImageSettings(String imageFile) {
98133 Display .getInstance ().openGallery ((ee ) -> {
99134 if (ee != null && ee .getSource () != null ) {
100135 try {
101- sl .setIcon (Image .createImage ((String )ee .getSource ()));
136+ String fileName = (String )ee .getSource ();
137+ sl .setIcon (Image .createImage (fileName ));
102138 sl .getParent ().revalidate ();
139+ Util .copy (FileSystemStorage .getInstance ().openInputStream (fileName ),
140+ Storage .getInstance ().createOutputStream (prefix + ".png" ));
103141 } catch (IOException err ) {
104142 ToastBar .showErrorMessage ("Error Loading Image: " + err );
105143 }
106144 }
107145 }, Display .GALLERY_IMAGE );
108146 });
147+ if (Storage .getInstance ().exists (prefix + ".png" )) {
148+ try (InputStream is = Storage .getInstance ().createInputStream (prefix + ".png" )) {
149+ sl .setIcon (Image .createImage (is ));
150+ } catch (IOException err ) {
151+ Log .e (err );
152+ }
153+ }
109154
110155 final TextField screenWidthPixels = new TextField ("320" , "Width" , 8 , TextField .NUMERIC );
111156 final TextField screenHeightPixels = new TextField ("480" , "Height" , 8 , TextField .NUMERIC );
112157 final TextField screenPositionX = new TextField ("40" , "X" , 8 , TextField .NUMERIC );
113158 final TextField screenPositionY = new TextField ("40" , "Y" , 8 , TextField .NUMERIC );
159+ autoSave (screenWidthPixels , prefix + "Width" );
160+ autoSave (screenHeightPixels , prefix + "Height" );
161+ autoSave (screenPositionX , prefix + "X" );
162+ autoSave (screenPositionY , prefix + "Y" );
163+ vl .addConstraint (screenWidthPixels , new NumericConstraint (false , 20 , 5000 , "Screen size must be a valid integer in the 20-5000 range" )).
164+ addConstraint (screenHeightPixels , new NumericConstraint (false , 20 , 5000 , "Screen size must be a valid integer in the 20-5000 range" )).
165+ addConstraint (screenPositionX , new NumericConstraint (false , 20 , 5000 , "Screen size must be a valid integer in the 20-5000 range" )).
166+ addConstraint (screenPositionY , new NumericConstraint (false , 20 , 5000 , "Screen size must be a valid integer in the 20-5000 range" ));
114167
115168 Button aim = new Button ();
116169 FontImage .setMaterialIcon (aim , FontImage .MATERIAL_PAN_TOOL );
@@ -297,50 +350,64 @@ public void start() {
297350 return ;
298351 }
299352 Form skinDesignerForm = new Form ("Skin Designer" , new BorderLayout ());
353+ Validator vl = new Validator ();
300354 final Tabs details = new Tabs ();
301355 Style titleCommand = UIManager .getInstance ().getComponentStyle ("Command" );
302- ImageSettings imPortrait = createImageSettings ("/skin.png" );
303- ImageSettings imLandscape = createImageSettings ("/skin_l.png" );
356+ ImageSettings imPortrait = createImageSettings ("/skin.png" , "port" , vl );
357+ ImageSettings imLandscape = createImageSettings ("/skin_l.png" , "lan" , vl );
304358
305359 skinDesignerForm .add (BorderLayout .CENTER , details );
306360
307361 Picker nativeTheme = new Picker ();
308362 nativeTheme .setStrings (NATIVE_THEMES );
309363 nativeTheme .setSelectedString (NATIVE_THEMES [0 ]);
310364 nativeTheme .setRenderingPrototype ("XXXXXXXXXXXXXXXXXXX" );
365+ autoSave (nativeTheme , "nativeTheme" );
311366
312367 Picker platformName = new Picker ();
313368 platformName .setStrings ("ios" , "and" , "win" ,"rim" , "se" );
314369 platformName .setSelectedString ("ios" );
315370 platformName .setRenderingPrototype ("XXXX" );
371+ autoSave (platformName , "platformName" );
316372
317373 OnOffSwitch tablet = new OnOffSwitch ();
318374 tablet .setValue (false );
375+ autoSave (tablet , "tablet" );
319376
320377 TextField systemFontFamily = new TextField ("Helvetica" , "System Font Family" , 20 , TextField .ANY );
321378 TextField proportionalFontFamily = new TextField ("Helvetica" , "Proportional Font Family" , 20 , TextField .ANY );
322379 TextField monospaceFontFamily = new TextField ("Courier" , "Monospace Font Family" , 20 , TextField .ANY );
380+ autoSave (systemFontFamily , "systemFontFamily" );
381+ autoSave (proportionalFontFamily , "proportionalFontFamily" );
382+ autoSave (monospaceFontFamily , "monospaceFontFamily" );
323383
324384 TextField smallFontSize = new TextField ("11" , "Small Font Size" , 20 , TextField .NUMERIC );
325385 TextField mediumFontSize = new TextField ("14" , "Medium Font Size" , 20 , TextField .NUMERIC );
326386 TextField largeFontSize = new TextField ("20" , "Large Font Size" , 20 , TextField .NUMERIC );
387+ autoSave (smallFontSize , "smallFontSize" );
388+ autoSave (mediumFontSize , "mediumFontSize" );
389+ autoSave (largeFontSize , "largeFontSize" );
327390
328391 TextField pixelRatio = new TextField ("6.4173236936575" , "Pixel Ratio - pixels per millimeter" , 20 , TextField .DECIMAL );
392+ autoSave (pixelRatio , "pixelRatio" );
329393
330394 Picker overrideNamePrimary = new Picker ();
331395 overrideNamePrimary .setStrings ("phone" , "tablet" , "desktop" );
332396 overrideNamePrimary .setSelectedString ("phone" );
333397 overrideNamePrimary .setRenderingPrototype ("XXXXXXXX" );
398+ autoSave (overrideNamePrimary , "overrideNamePrimary" );
334399
335400 Picker overrideNameSecondary = new Picker ();
336401 overrideNameSecondary .setStrings ("ios" , "android" , "windows" );
337402 overrideNameSecondary .setSelectedString ("ios" );
338403 overrideNameSecondary .setRenderingPrototype ("XXXXXXXX" );
404+ autoSave (overrideNameSecondary , "overrideNameSecondary" );
339405
340406 Picker overrideNameLast = new Picker ();
341407 overrideNameLast .setStrings ("iphone" , "ipad" , "android-phone" , "android-tablet" , "desktop" );
342408 overrideNameLast .setSelectedString ("iphone" );
343409 overrideNameLast .setRenderingPrototype ("XXXXXXXX" );
410+ autoSave (overrideNameLast , "overrideNameLast" );
344411
345412
346413 Container settingsContainer = BoxLayout .encloseY (
@@ -381,10 +448,15 @@ public void start() {
381448 details .setTabSelectedIcon (0 , portraitIconSel );
382449 details .setTabSelectedIcon (1 , landscapeIconSel );
383450 details .setTabSelectedIcon (2 , settingsIconSel );
384-
451+ vl .addConstraint (smallFontSize , new NumericConstraint (false , 5 , 400 , "Font size must be a valid integer in the 5-400 range" )).
452+ addConstraint (mediumFontSize , new NumericConstraint (false , 5 , 400 , "Font size must be a valid integer in the 5-400 range" )).
453+ addConstraint (largeFontSize , new NumericConstraint (false , 5 , 400 , "Font size must be a valid integer in the 5-400 range" )).
454+ addConstraint (pixelRatio , new NumericConstraint (true , 0.1 , 60 , "PixelRatio is a positive decimal size in the range of 0.1 to 60" )).
455+ setShowErrorMessageForFocusedComponent (true );
456+
385457 ShouldExecute s = NativeLookup .create (ShouldExecute .class );
386458 if (s != null && s .isSupported ()) {
387- skinDesignerForm .getToolbar ().addCommandToRightBar ("" ,
459+ Command saveCommand = skinDesignerForm .getToolbar ().addCommandToRightBar ("" ,
388460 FontImage .createMaterial (FontImage .MATERIAL_SAVE , titleCommand ), e -> {
389461 byte [] data = createSkinFile (imPortrait , imLandscape , nativeTheme , platformName , tablet , systemFontFamily ,
390462 proportionalFontFamily , monospaceFontFamily , smallFontSize , mediumFontSize , largeFontSize ,
@@ -403,6 +475,7 @@ public void start() {
403475 }
404476 }
405477 });
478+ vl .addSubmitButtons (skinDesignerForm .getToolbar ().findCommandComponent (saveCommand ));
406479 }
407480
408481 if (Display .getInstance ().isNativeShareSupported ()) {
0 commit comments