gt:                 density = 1250; // "DENSITY_4K";
context: package it.galgani.codenameone.multiImageCalculator;
  
  import com.codename1.components.SpanLabel;
  import static com.codename1.ui.CN.*;
  import com.codename1.io.Log;
  import com.codename1.ui.Button;
  import com.codename1.ui.Component;
  import com.codename1.ui.Container;
  import com.codename1.ui.FontImage;
  import com.codename1.ui.Form;
  import com.codename1.ui.Dialog;
  import com.codename1.ui.Display;
  import com.codename1.ui.Font;
  import com.codename1.ui.Label;
  import com.codename1.ui.Slider;
  import com.codename1.ui.TextField;
  import com.codename1.ui.layouts.BoxLayout;
  import com.codename1.ui.layouts.FlowLayout;
  import com.codename1.ui.plaf.UIManager;
  import com.codename1.ui.util.Resources;
  import com.codename1.ui.Toolbar;
  import com.codename1.ui.layouts.GridLayout;
  import com.codename1.ui.plaf.Style;
  import com.codename1.ui.table.DefaultTableModel;
  import com.codename1.ui.table.Table;
  import com.codename1.ui.table.TableLayout;
  import com.codename1.ui.table.TableModel;
  
  /**
   * Multi-Image Calculator for Codename One developers
   *
   * @author Francesco Galgani
   */
  public class MultiImageCalculator {
  
      private Form current;
      private Resources theme;
  
      public void init(Object context) {
          theme = UIManager.initFirstTheme("/myTheme");
  
          // Enable Toolbar on all Forms by default
          Toolbar.setGlobalToolbar(true);
  
          // Pro only feature
          // Log.bindCrashProtection(true);
      }
  
      public void start() {
          if (current != null) {
              current.show();
              return;
          }
  
          BoxLayout layout = new BoxLayout(BoxLayout.Y_AXIS);
          Form hi = new Form("Multi-image calculator", layout);
  
          SpanLabel selectWidth = new SpanLabel("Select the desidered width for your multi-image:");
  
          Label value = new Label("Move the cursor on the slider...");
  
          Style thumbStyle = new Style();
          thumbStyle.setFont(Font.createSystemFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_LARGE), true);
  
          Slider slider = new Slider();
          slider.setMaxValue(1000);
          slider.setMinValue(0);
          slider.setProgress(20); // Set  the starting value
          slider.setThumbImage(FontImage.create("|", thumbStyle));
          slider.setEditable(true); // to it works as a slider instead of a progress bar
          slider.addActionListener(e -> {
              Integer valueSelected = slider.getProgress();
              Integer sliderWidth = slider.getWidth();
              /*
              Double inch = sliderWidth.doubleValue() / (slider.getMaxValue() - slider.getMinValue()) * valueSelected / 100.0;
              Integer millimeters = Double.valueOf(inch * 25.4).intValue();
               */
              Double pixelSelected = sliderWidth.doubleValue() / (slider.getMaxValue() - slider.getMinValue()) * valueSelected;
              Double inch = pixelSelected / MultiImageCalculator.getDeviceDPI();
              Integer millimeters = Double.valueOf(inch * 25.4).intValue();
              value.setText("Value selected: " + millimeters.toString() + " mm");
          });
  
          Label imageSize = new Label("Original image size in pixel: ");
          TextField width = new TextField();
          //width.setColumns(6);
          width.setHint("width");
          width.getAllStyles().setFont(Font.createSystemFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM), true);
          TextField height = new TextField();
          //height.setColumns(6);
          height.setHint("height");
          height.getAllStyles().setFont(Font.createSystemFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM), true);
          Button submit = new Button("Calculate");
          Container dimension = new Container(new GridLayout(1, 3));
          dimension.add(width).add(height).add(submit);
  
          SpanLabel suitableFor = new SpanLabel(" ");
  
          Label calculated = new Label("Values to generate a multi-image:");
  
          TableModel model = new DefaultTableModel(new String[]{"Density", "ppi", "Width", "Height"}, new String[][]{
              {"Very Low", "~88", " ", " "},
              {"Low", "~120", " ", " "},
              {"Medium", "~160", " ", " "},
              {"High", "~240", " ", " "},
              {"Very High", "~320", " ", " "},
              {"HD", "~540", " ", " "},
              {"560", "~750", " ", " "},
              {"2HD", "~1000", " ", " "},
              {"4K", "~1250", " ", " "},});
          Table table = new Table(model) {
              @Override
              protected TableLayout.Constraint createCellConstraint(Object value, int row, int column) {
                  TableLayout.Constraint con = super.createCellConstraint(value, row, column);
                  con.setWidthPercentage(25);
                  con.setHorizontalAlign(Component.CENTER);
                  return con;
              }
  
              @Override
              protected Component createCell(Object value, int row, int column, boolean editable) {
                  Component cell;
                  cell = new Label((String) value);
                  Style cellStyle = cell.getAllStyles();
                  cellStyle.setFont(Font.createSystemFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_MEDIUM), true);
                  cellStyle.setFgColor(0x000000);
                  return cell;
              }
          };
  
          submit.addActionListener(e -> {
  
              // Width in millimeters
              Integer millimeters = null;
              try {
                  millimeters = extractInt(value.getText());
              } catch (Exception err) {
                  Log.p("No millimeters value!");
              }
  
              // Original width & height in pixel
              Integer widthOriginal = null;
              Integer heightOriginal = null;
              try {
                  widthOriginal = Integer.valueOf(width.getText());
                  heightOriginal = Integer.valueOf(height.getText());
              } catch (Exception err) {
                  Log.p("No width or height setted!");
              }
  
              if (millimeters != null && widthOriginal != null && heightOriginal != null) {
  
                  Integer newWidth = 0;
                  Integer newHeight = 0;
                  Integer ppi = 0;
  
                  // Convert millimeters to inch
                  Double inch = millimeters / 10.0 / 2.54;
  
                  // Calculate the correct sizes for each ppi
                  int ppiCell = 1;
                  for (int i = 1; i <= 9; i++) {
                      ppiCell += 4;
                      ppi = Integer.valueOf(extractInt(((Label) (table.getComponentAt(ppiCell))).getText()));
                      newWidth = Double.valueOf(inch * ppi).intValue();
                      newHeight = heightOriginal * newWidth / widthOriginal;
                      ((Label) (table.getComponentAt(ppiCell + 1))).setText(newWidth.toString());
                      ((Label) (table.getComponentAt(ppiCell + 2))).setText(newHeight.toString());
                  }
  
                  // calculate original density for QuickAddMultimage
                  Integer originalDensity = Double.valueOf(widthOriginal / inch).intValue();
                  String densityHit = "The density of your image is " + originalDensity + " ppi (";
                  if (originalDensity < 104) {
                      densityHit += "DENSITY_VERY_LOW";
                  } else if (originalDensity < 140) {
                      densityHit += "DENSITY_LOW";
                  } else if (originalDensity < 200) {
                      densityHit += "DENSITY_MEDIUM";
                  } else if (originalDensity < 280) {
                      densityHit += "DENSITY_HIGH";
                  } else if (originalDensity < 430) {
                      densityHit += "DENSITY_VERY_HIGH";
                  } else if (originalDensity < 645) {
                      densityHit += "DENSITY_HD";
                  } else if (originalDensity < 875) {
                      densityHit += "DENSITY_560";
                  } else if (originalDensity < 1125) {
                      densityHit += "DENSITY_2HD";
                  } else {
                      densityHit += "DENSITY_4K";
                  }
                  densityHit += ").";
                  suitableFor.setText(densityHit);
              }
  
              hi.revalidate();
          });
  
          hi.add(selectWidth);
          hi.add(value);
          hi.add(slider);
          hi.addOrientationListener(e -> {
              value.setText("Move the cursor on the slider...");
              hi.revalidate();
          });
          hi.add(imageSize);
          hi.add(dimension);
          hi.add(suitableFor);
          hi.add(calculated);
          hi.add(table);
          hi.show();
      }
  
      public void stop() {
          current = getCurrentForm();
          if (current instanceof Dialog) {
              ((Dialog) current).dispose();
              current = getCurrentForm();
          }
      }
  
      public void destroy() {
      }
  
      static private boolean logDensity = true;
      public static Integer getDeviceDPI() {
          Integer density = 160; // default value if none is available
          switch (Display.getInstance().getDeviceDensity()) {
              case 70:
                  density = 1000; // "DENSITY_2HD";
                  break;
              case 80:
  