SlideShare a Scribd company logo
1 of 15
Download to read offline
Initial UI Mockup - Part II
Lets dive right in to the code starting with base navigation form
public class BaseNavigationForm extends Form {
public BaseNavigationForm(AppSettings app, Layout l) {
super(app.name.get(), l);
init(app);
}
private void init(AppSettings app) {
Toolbar tb = getToolbar();
tb.addMaterialCommandToSideMenu("Dishes", FontImage.MATERIAL_RESTAURANT_MENU,
e -> new DishListForm(app).show());
tb.addMaterialCommandToSideMenu("Details", FontImage.MATERIAL_DESCRIPTION,
e -> new DetailsForm(app).show());
tb.addMaterialCommandToSideMenu("Billing", FontImage.MATERIAL_CREDIT_CARD, e -> {});
tb.addMaterialCommandToSideMenu("App", FontImage.MATERIAL_PHONE_IPHONE,
e -> new AppForm(app).show());
TextField title = new TextField(app.name.get());
title.setUIID("NavigationTitle");
TextField tagline = new TextField(app.tagline.get());
tagline.setUIID("Tagline");
BaseNavigationForm
Commands
Side menu navigation
commands common to the
top level form
The main class for the top level forms is the base navigation form. Here we have the material commands in the side menu that allow us to navigate to the other top level
forms.
public class BaseNavigationForm extends Form {
public BaseNavigationForm(AppSettings app, Layout l) {
super(app.name.get(), l);
init(app);
}
private void init(AppSettings app) {
Toolbar tb = getToolbar();
tb.addMaterialCommandToSideMenu("Dishes", FontImage.MATERIAL_RESTAURANT_MENU,
e -> new DishListForm(app).show());
tb.addMaterialCommandToSideMenu("Details", FontImage.MATERIAL_DESCRIPTION,
e -> new DetailsForm(app).show());
tb.addMaterialCommandToSideMenu("Billing", FontImage.MATERIAL_CREDIT_CARD, e -> {});
tb.addMaterialCommandToSideMenu("App", FontImage.MATERIAL_PHONE_IPHONE,
e -> new AppForm(app).show());
TextField title = new TextField(app.name.get());
title.setUIID("NavigationTitle");
TextField tagline = new TextField(app.tagline.get());
tagline.setUIID("Tagline");
BaseNavigationForm
UIID
0 Margin
1mm Padding
White 5mm thin font
Left alignment
The title of the forms is really a text field as it’s editable in place. The trick in making a text field feel like a title is to style it as such which is why we created the
NavigationTitle UIID and that style has 0 margin, 1 millimeter of padding with a 5 millimeter white font that’s aligned to the left. 

That looks and feels like a title, one important thing to notice is the left align which doesn’t match the iOS convention. Center aligned text fields are flaky across platforms
so we don’t support them properly, that’s why we use left alignment here.
public class BaseNavigationForm extends Form {
public BaseNavigationForm(AppSettings app, Layout l) {
super(app.name.get(), l);
init(app);
}
private void init(AppSettings app) {
Toolbar tb = getToolbar();
tb.addMaterialCommandToSideMenu("Dishes", FontImage.MATERIAL_RESTAURANT_MENU,
e -> new DishListForm(app).show());
tb.addMaterialCommandToSideMenu("Details", FontImage.MATERIAL_DESCRIPTION,
e -> new DetailsForm(app).show());
tb.addMaterialCommandToSideMenu("Billing", FontImage.MATERIAL_CREDIT_CARD, e -> {});
tb.addMaterialCommandToSideMenu("App", FontImage.MATERIAL_PHONE_IPHONE,
e -> new AppForm(app).show());
TextField title = new TextField(app.name.get());
title.setUIID("NavigationTitle");
TextField tagline = new TextField(app.tagline.get());
tagline.setUIID("Tagline");
BaseNavigationForm
UIID
Derive NavigationTitle
3mm font
The tagline is similarly a text field with the right styling. Technically the styling derives navigation title so we can be in sync with changes to the title style. It just uses a
smaller 3 millimeter font.
public class BaseNavigationForm extends Form {
public BaseNavigationForm(AppSettings app, Layout l) {
super(app.name.get(), l);
init(app);
}
private void init(AppSettings app) {
Toolbar tb = getToolbar();
tb.addMaterialCommandToSideMenu("Dishes", FontImage.MATERIAL_RESTAURANT_MENU,
e -> new DishListForm(app).show());
tb.addMaterialCommandToSideMenu("Details", FontImage.MATERIAL_DESCRIPTION,
e -> new DetailsForm(app).show());
tb.addMaterialCommandToSideMenu("Billing", FontImage.MATERIAL_CREDIT_CARD, e -> {});
tb.addMaterialCommandToSideMenu("App", FontImage.MATERIAL_PHONE_IPHONE,
e -> new AppForm(app).show());
TextField title = new TextField(app.name.get());
title.setUIID("NavigationTitle");
TextField tagline = new TextField(app.tagline.get());
tagline.setUIID("Tagline");
BaseNavigationForm
In case this wasn’t clear these UIID’s map to the title and subtitle of the form right here
Button editBackground = new Button("Edit Background", "EditBackground");
int size = Display.getInstance().convertToPixels(10);
Button logoImage = new Button("", app.getRoundedScaledLogo(), "Container");
Container titleContainer = BoxLayout.encloseY(
title,
tagline,
FlowLayout.encloseCenterMiddle(logoImage));
Button menu = new Button("", "NavigationTitle");
Button preview = new Button("", "NavigationTitle");
FontImage.setMaterialIcon(menu, FontImage.MATERIAL_MENU);
FontImage.setMaterialIcon(preview, FontImage.MATERIAL_PLAY_ARROW);
Container titleWithCommands = BorderLayout.centerEastWest(
titleContainer,
FlowLayout.encloseCenter(preview),
FlowLayout.encloseCenter(menu));
menu.addActionListener(e -> tb.openSideMenu());
ScaleImageLabel sl = new ScaleImageLabel(app.titleBackground.get());
sl.setUIID("TitleBottomSpace");
sl.setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FILL);
if(super.shouldPaintStatusBar()) {
titleWithCommands.getUnselectedStyle().setPaddingUnit(Style.UNIT_TYPE_DIPS);
titleWithCommands.getUnselectedStyle().setPaddingTop(3);
}
tb.setTitleComponent(LayeredLayout.encloseIn(sl,
BorderLayout.south(editBackground), titleWithCommands));
}
BaseNavigationForm
UIID
0 Margin top/right/left
4mm bottom margin
0 Padding
Derive NavigationTitle
Right alignment
thin 2.5mm font
Moving on the edit background UI on the bottom right portion of the form maps to this button which allows us to edit the background image in the title area. You will
notice we use the constructor that accepts the button label and UIID.

The EditBackground UIID is styled to match the navigation title but it also adds padding to the bottom so the text doesn’t appear within the white area. I’ll talk about that
more in the next section… Besides that the other interesting thing about this UIID is the right alignment which we use to make sure it appears to the right of the icon.
Button editBackground = new Button("Edit Background", "EditBackground");
int size = Display.getInstance().convertToPixels(10);
Button logoImage = new Button("", app.getRoundedScaledLogo(), "Container");
Container titleContainer = BoxLayout.encloseY(
title,
tagline,
FlowLayout.encloseCenterMiddle(logoImage));
Button menu = new Button("", "NavigationTitle");
Button preview = new Button("", "NavigationTitle");
FontImage.setMaterialIcon(menu, FontImage.MATERIAL_MENU);
FontImage.setMaterialIcon(preview, FontImage.MATERIAL_PLAY_ARROW);
Container titleWithCommands = BorderLayout.centerEastWest(
titleContainer,
FlowLayout.encloseCenter(preview),
FlowLayout.encloseCenter(menu));
menu.addActionListener(e -> tb.openSideMenu());
ScaleImageLabel sl = new ScaleImageLabel(app.titleBackground.get());
sl.setUIID("TitleBottomSpace");
sl.setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FILL);
if(super.shouldPaintStatusBar()) {
titleWithCommands.getUnselectedStyle().setPaddingUnit(Style.UNIT_TYPE_DIPS);
titleWithCommands.getUnselectedStyle().setPaddingTop(3);
}
tb.setTitleComponent(LayeredLayout.encloseIn(sl,
BorderLayout.south(editBackground), titleWithCommands));
}
BaseNavigationForm
UIID
0 padding sides
1mm padding top/bottom
4mm bottom
The background image is just a scaled image label that stretches all across. We added a 4 millimeter margin to the bottom of this background image and that allows the
icon to “peek” exactly 4 millimeters outside of the bottom portion. This looks decent enough and works well for all resolutions since the size is in millimeters and the icon
is also scaled in millimeters.
Button editBackground = new Button("Edit Background", "EditBackground");
int size = Display.getInstance().convertToPixels(10);
Button logoImage = new Button("", app.getRoundedScaledLogo(), "Container");
Container titleContainer = BoxLayout.encloseY(
title,
tagline,
FlowLayout.encloseCenterMiddle(logoImage));
Button menu = new Button("", "NavigationTitle");
Button preview = new Button("", "NavigationTitle");
FontImage.setMaterialIcon(menu, FontImage.MATERIAL_MENU);
FontImage.setMaterialIcon(preview, FontImage.MATERIAL_PLAY_ARROW);
Container titleWithCommands = BorderLayout.centerEastWest(
titleContainer,
FlowLayout.encloseCenter(preview),
FlowLayout.encloseCenter(menu));
menu.addActionListener(e -> tb.openSideMenu());
ScaleImageLabel sl = new ScaleImageLabel(app.titleBackground.get());
sl.setUIID("TitleBottomSpace");
sl.setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FILL);
if(super.shouldPaintStatusBar()) {
titleWithCommands.getUnselectedStyle().setPaddingUnit(Style.UNIT_TYPE_DIPS);
titleWithCommands.getUnselectedStyle().setPaddingTop(3);
}
tb.setTitleComponent(LayeredLayout.encloseIn(sl,
BorderLayout.south(editBackground), titleWithCommands));
}
BaseNavigationForm
The logo image uses a special rounded scaled logo getter which adapts the logos look to the design of the UI let’s go see how that method works
public class AppSettings implements PropertyBusinessObject {
public final Property<String, AppSettings> name = new Property<>("name", "My Restaurant");
public final Property<String, AppSettings> tagline = new Property<>("tagline", "The place to eat");
public final Property<Image, AppSettings> titleBackground = new Property<>("titleBackground", null);
private Image roundedScaledLogo;
private final PropertyIndex idx = new PropertyIndex(this, "AppSettings", name, tagline, logo,
titleBackground);
@Override
public PropertyIndex getPropertyIndex() {
return idx;
}
public Image getRoundedScaledLogo() {
return roundedScaledLogo;
}
AppSettings
The rounded scaled logo is just an image with no setter, so where is this initialized?
public final Property<Image, AppSettings> logo = new Property<Image, AppSettings>("logo", null) {
public AppSettings set(Image value) {
if(value != null) {
int mm = Display.getInstance().convertToPixels(2f);
int size = Display.getInstance().convertToPixels(11);
GeneralPath gp = new GeneralPath();
float widthF = size; float heightF = size;
gp.moveTo(x + mm, 0);
gp.lineTo(x + widthF - mm, 0);
gp.quadTo(x + widthF, 0, widthF, mm);
gp.lineTo(x + widthF, heightF - mm);
gp.quadTo(x + widthF, heightF, x + widthF - mm, heightF);
gp.lineTo(x + mm, heightF);
gp.quadTo(x, heightF, 0, heightF - radius);
gp.lineTo(x, mm);
gp.quadTo(x, 0, mm, 0);
gp.closePath();
Image mask = Image.createImage(size, size, 0xff000000);
Graphics g = mask.getGraphics();
g.setColor(0xffffff);
g.setAntiAliased(true);
g.fillShape(gp);
Object m = mask.createMask();
roundedScaledLogo = value.fill(size, size).applyMask(m);
}
return super.set(value);
}
};
AppSettings
When we set the property for the logo we automatically generate this image too by drawing the image in the right place. Let’s go over these steps
public final Property<Image, AppSettings> logo = new Property<Image, AppSettings>("logo", null) {
public AppSettings set(Image value) {
if(value != null) {
int mm = Display.getInstance().convertToPixels(2f);
int size = Display.getInstance().convertToPixels(11);
GeneralPath gp = new GeneralPath();
float widthF = size; float heightF = size;
gp.moveTo(x + mm, 0);
gp.lineTo(x + widthF - mm, 0);
gp.quadTo(x + widthF, 0, widthF, mm);
gp.lineTo(x + widthF, heightF - mm);
gp.quadTo(x + widthF, heightF, x + widthF - mm, heightF);
gp.lineTo(x + mm, heightF);
gp.quadTo(x, heightF, 0, heightF - radius);
gp.lineTo(x, mm);
gp.quadTo(x, 0, mm, 0);
gp.closePath();
Image mask = Image.createImage(size, size, 0xff000000);
Graphics g = mask.getGraphics();
g.setColor(0xffffff);
g.setAntiAliased(true);
g.fillShape(gp);
Object m = mask.createMask();
roundedScaledLogo = value.fill(size, size).applyMask(m);
}
return super.set(value);
}
};
AppSettings
We have two important sizes here, mm is the size of the arc in the corner and size is the size of the entire icon. I got these numbers thru trial and error until I got
something that looked satisfactory in the various device densities.
public final Property<Image, AppSettings> logo = new Property<Image, AppSettings>("logo", null) {
public AppSettings set(Image value) {
if(value != null) {
int mm = Display.getInstance().convertToPixels(2f);
int size = Display.getInstance().convertToPixels(11);
GeneralPath gp = new GeneralPath();
float widthF = size; float heightF = size;
gp.moveTo(x + mm, 0);
gp.lineTo(x + widthF - mm, 0);
gp.quadTo(x + widthF, 0, widthF, mm);
gp.lineTo(x + widthF, heightF - mm);
gp.quadTo(x + widthF, heightF, x + widthF - mm, heightF);
gp.lineTo(x + mm, heightF);
gp.quadTo(x, heightF, 0, heightF - radius);
gp.lineTo(x, mm);
gp.quadTo(x, 0, mm, 0);
gp.closePath();
Image mask = Image.createImage(size, size, 0xff000000);
Graphics g = mask.getGraphics();
g.setColor(0xffffff);
g.setAntiAliased(true);
g.fillShape(gp);
Object m = mask.createMask();
roundedScaledLogo = value.fill(size, size).applyMask(m);
}
return super.set(value);
}
};
AppSettings
A general path is a shape object, we can fill, stroke or clip based on a shape. Notice that shape operations can sometimes be expensive in terms of graphics processing
power so while they are very powerful you need to be very aware of what you are trying to do. A general path allows us to define an arbitrary shape we can then use in
the drawing primitives.

This raises the question of why not use the builtin round rect methods within graphics, those don’t allow the same level of customizability and power as the shape API.
They aren’t as consistent across platform either.
public final Property<Image, AppSettings> logo = new Property<Image, AppSettings>("logo", null) {
public AppSettings set(Image value) {
if(value != null) {
int mm = Display.getInstance().convertToPixels(2f);
int size = Display.getInstance().convertToPixels(11);
GeneralPath gp = new GeneralPath();
float widthF = size; float heightF = size;
gp.moveTo(x + mm, 0);
gp.lineTo(x + widthF - mm, 0);
gp.quadTo(x + widthF, 0, widthF, mm);
gp.lineTo(x + widthF, heightF - mm);
gp.quadTo(x + widthF, heightF, x + widthF - mm, heightF);
gp.lineTo(x + mm, heightF);
gp.quadTo(x, heightF, 0, heightF - radius);
gp.lineTo(x, mm);
gp.quadTo(x, 0, mm, 0);
gp.closePath();
Image mask = Image.createImage(size, size, 0xff000000);
Graphics g = mask.getGraphics();
g.setColor(0xffffff);
g.setAntiAliased(true);
g.fillShape(gp);
Object m = mask.createMask();
roundedScaledLogo = value.fill(size, size).applyMask(m);
}
return super.set(value);
}
};
AppSettings
Building the shape is essentialy about moving a virtual pen around and drawing lines, arcs or curves along the path. This is mostly straight forward.
public final Property<Image, AppSettings> logo = new Property<Image, AppSettings>("logo", null) {
public AppSettings set(Image value) {
if(value != null) {
int mm = Display.getInstance().convertToPixels(2f);
int size = Display.getInstance().convertToPixels(11);
GeneralPath gp = new GeneralPath();
float widthF = size; float heightF = size;
gp.moveTo(x + mm, 0);
gp.lineTo(x + widthF - mm, 0);
gp.quadTo(x + widthF, 0, widthF, mm);
gp.lineTo(x + widthF, heightF - mm);
gp.quadTo(x + widthF, heightF, x + widthF - mm, heightF);
gp.lineTo(x + mm, heightF);
gp.quadTo(x, heightF, 0, heightF - radius);
gp.lineTo(x, mm);
gp.quadTo(x, 0, mm, 0);
gp.closePath();
Image mask = Image.createImage(size, size, 0xff000000);
Graphics g = mask.getGraphics();
g.setColor(0xffffff);
g.setAntiAliased(true);
g.fillShape(gp);
Object m = mask.createMask();
roundedScaledLogo = value.fill(size, size).applyMask(m);
}
return super.set(value);
}
};
AppSettings
Here we create a mask from the shape, a mask for the image. We create a solid black image and we fill the shape area with white color then we create a mask. A mask
can be applied to the image to remove the black pieces and leave the white pieces.

This begs the question, why not use shape clipping that I mentioned earlier?

Masking supports anti-aliasing which renders the elements in the corners with a slight alpha channel to make the corner seem smooth. A clip is a binary operation where
a pixel can either be in the clip or it’s outside of the clip so there is no room for interpretation. Using shape clipping won’t look as good!

Furthermore, shape clipping isn’t as portable as masking which is 100% portable to all supported Codename One platforms.
public final Property<Image, AppSettings> logo = new Property<Image, AppSettings>("logo", null) {
public AppSettings set(Image value) {
if(value != null) {
int mm = Display.getInstance().convertToPixels(2f);
int size = Display.getInstance().convertToPixels(11);
GeneralPath gp = new GeneralPath();
float widthF = size; float heightF = size;
gp.moveTo(x + mm, 0);
gp.lineTo(x + widthF - mm, 0);
gp.quadTo(x + widthF, 0, widthF, mm);
gp.lineTo(x + widthF, heightF - mm);
gp.quadTo(x + widthF, heightF, x + widthF - mm, heightF);
gp.lineTo(x + mm, heightF);
gp.quadTo(x, heightF, 0, heightF - radius);
gp.lineTo(x, mm);
gp.quadTo(x, 0, mm, 0);
gp.closePath();
Image mask = Image.createImage(size, size, 0xff000000);
Graphics g = mask.getGraphics();
g.setColor(0xffffff);
g.setAntiAliased(true);
g.fillShape(gp);
Object m = mask.createMask();
roundedScaledLogo = value.fill(size, size).applyMask(m);
}
return super.set(value);
}
};
AppSettings
In the last line of this code we do two separate things. The fill method scales the image but it does that while cropping redundant areas. So if we have an image that isn’t
a square the areas outside will be clipped and the center will remain.

We then apply he mask to the clipped image to create that round effect

More Related Content

Similar to Initial UI Mockup - Part 2 - Transcript.pdf

Sencha touch application v2.00
Sencha touch application v2.00Sencha touch application v2.00
Sencha touch application v2.00
Trịnh Thành
 
Android tutorials8 todo_list
Android tutorials8 todo_listAndroid tutorials8 todo_list
Android tutorials8 todo_list
Vlad Kolesnyk
 
Android tutorials8 todo_list
Android tutorials8 todo_listAndroid tutorials8 todo_list
Android tutorials8 todo_list
Vlad Kolesnyk
 

Similar to Initial UI Mockup - Part 2 - Transcript.pdf (20)

Information about Toggle Button.pdf
Information about Toggle Button.pdfInformation about Toggle Button.pdf
Information about Toggle Button.pdf
 
Extracting ui Design - part 5 - transcript.pdf
Extracting ui Design - part 5 - transcript.pdfExtracting ui Design - part 5 - transcript.pdf
Extracting ui Design - part 5 - transcript.pdf
 
Miscellaneous Features - Part 1.pdf
Miscellaneous Features - Part 1.pdfMiscellaneous Features - Part 1.pdf
Miscellaneous Features - Part 1.pdf
 
Initial UI Mockup - Part 3.pdf
Initial UI Mockup - Part 3.pdfInitial UI Mockup - Part 3.pdf
Initial UI Mockup - Part 3.pdf
 
Android action bar and notifications-chapter16
Android action bar and notifications-chapter16Android action bar and notifications-chapter16
Android action bar and notifications-chapter16
 
Creating a Facebook Clone - Part XVI - Transcript.pdf
Creating a Facebook Clone - Part XVI - Transcript.pdfCreating a Facebook Clone - Part XVI - Transcript.pdf
Creating a Facebook Clone - Part XVI - Transcript.pdf
 
Extracting ui Design - part 4 - transcript.pdf
Extracting ui Design - part 4 - transcript.pdfExtracting ui Design - part 4 - transcript.pdf
Extracting ui Design - part 4 - transcript.pdf
 
Creating a Facebook Clone - Part XV - Transcript.pdf
Creating a Facebook Clone - Part XV - Transcript.pdfCreating a Facebook Clone - Part XV - Transcript.pdf
Creating a Facebook Clone - Part XV - Transcript.pdf
 
Guide to Fix Dropdown Button Not Switching Selected Item | Flutter
Guide to Fix Dropdown Button Not Switching Selected Item | FlutterGuide to Fix Dropdown Button Not Switching Selected Item | Flutter
Guide to Fix Dropdown Button Not Switching Selected Item | Flutter
 
Sencha touch application v2.00
Sencha touch application v2.00Sencha touch application v2.00
Sencha touch application v2.00
 
Extracting ui Design - part 6 - transcript.pdf
Extracting ui Design - part 6 - transcript.pdfExtracting ui Design - part 6 - transcript.pdf
Extracting ui Design - part 6 - transcript.pdf
 
How do I - Create a List of Items - Transcript.pdf
How do I - Create a List of Items - Transcript.pdfHow do I - Create a List of Items - Transcript.pdf
How do I - Create a List of Items - Transcript.pdf
 
Creating a Facebook Clone - Part XXX - Transcript.pdf
Creating a Facebook Clone - Part XXX - Transcript.pdfCreating a Facebook Clone - Part XXX - Transcript.pdf
Creating a Facebook Clone - Part XXX - Transcript.pdf
 
Android tutorials8 todo_list
Android tutorials8 todo_listAndroid tutorials8 todo_list
Android tutorials8 todo_list
 
Intake 38 8
Intake 38 8Intake 38 8
Intake 38 8
 
Android tutorials8 todo_list
Android tutorials8 todo_listAndroid tutorials8 todo_list
Android tutorials8 todo_list
 
Styles - Part 1 - Transcript.pdf
Styles - Part 1 - Transcript.pdfStyles - Part 1 - Transcript.pdf
Styles - Part 1 - Transcript.pdf
 
Object Oriented Programming Session 4 part 2 Slides .pptx
Object Oriented Programming Session 4 part 2 Slides .pptxObject Oriented Programming Session 4 part 2 Slides .pptx
Object Oriented Programming Session 4 part 2 Slides .pptx
 
MDC - Material Design Components & Theming
MDC - Material Design Components & ThemingMDC - Material Design Components & Theming
MDC - Material Design Components & Theming
 
Creating an Uber Clone - Part XXXIX.pdf
Creating an Uber Clone - Part XXXIX.pdfCreating an Uber Clone - Part XXXIX.pdf
Creating an Uber Clone - Part XXXIX.pdf
 

More from ShaiAlmog1

More from ShaiAlmog1 (20)

The Duck Teaches Learn to debug from the masters. Local to production- kill ...
The Duck Teaches  Learn to debug from the masters. Local to production- kill ...The Duck Teaches  Learn to debug from the masters. Local to production- kill ...
The Duck Teaches Learn to debug from the masters. Local to production- kill ...
 
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfcreate-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdf
 
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfcreate-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdf
 
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfcreate-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdf
 
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfcreate-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdf
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdf
 
create-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfcreate-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdf
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdf
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdf
 
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfcreate-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdf
 
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfcreate-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdf
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
 
create-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfcreate-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdf
 
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfCreating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdf
 
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfCreating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdf
 
Creating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfCreating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdf
 
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfCreating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfCreating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfCreating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdf
 
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfCreating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdf
 

Recently uploaded

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Victor Rentea
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 

Recently uploaded (20)

Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 

Initial UI Mockup - Part 2 - Transcript.pdf

  • 1. Initial UI Mockup - Part II Lets dive right in to the code starting with base navigation form
  • 2. public class BaseNavigationForm extends Form { public BaseNavigationForm(AppSettings app, Layout l) { super(app.name.get(), l); init(app); } private void init(AppSettings app) { Toolbar tb = getToolbar(); tb.addMaterialCommandToSideMenu("Dishes", FontImage.MATERIAL_RESTAURANT_MENU, e -> new DishListForm(app).show()); tb.addMaterialCommandToSideMenu("Details", FontImage.MATERIAL_DESCRIPTION, e -> new DetailsForm(app).show()); tb.addMaterialCommandToSideMenu("Billing", FontImage.MATERIAL_CREDIT_CARD, e -> {}); tb.addMaterialCommandToSideMenu("App", FontImage.MATERIAL_PHONE_IPHONE, e -> new AppForm(app).show()); TextField title = new TextField(app.name.get()); title.setUIID("NavigationTitle"); TextField tagline = new TextField(app.tagline.get()); tagline.setUIID("Tagline"); BaseNavigationForm Commands Side menu navigation commands common to the top level form The main class for the top level forms is the base navigation form. Here we have the material commands in the side menu that allow us to navigate to the other top level forms.
  • 3. public class BaseNavigationForm extends Form { public BaseNavigationForm(AppSettings app, Layout l) { super(app.name.get(), l); init(app); } private void init(AppSettings app) { Toolbar tb = getToolbar(); tb.addMaterialCommandToSideMenu("Dishes", FontImage.MATERIAL_RESTAURANT_MENU, e -> new DishListForm(app).show()); tb.addMaterialCommandToSideMenu("Details", FontImage.MATERIAL_DESCRIPTION, e -> new DetailsForm(app).show()); tb.addMaterialCommandToSideMenu("Billing", FontImage.MATERIAL_CREDIT_CARD, e -> {}); tb.addMaterialCommandToSideMenu("App", FontImage.MATERIAL_PHONE_IPHONE, e -> new AppForm(app).show()); TextField title = new TextField(app.name.get()); title.setUIID("NavigationTitle"); TextField tagline = new TextField(app.tagline.get()); tagline.setUIID("Tagline"); BaseNavigationForm UIID 0 Margin 1mm Padding White 5mm thin font Left alignment The title of the forms is really a text field as it’s editable in place. The trick in making a text field feel like a title is to style it as such which is why we created the NavigationTitle UIID and that style has 0 margin, 1 millimeter of padding with a 5 millimeter white font that’s aligned to the left. That looks and feels like a title, one important thing to notice is the left align which doesn’t match the iOS convention. Center aligned text fields are flaky across platforms so we don’t support them properly, that’s why we use left alignment here.
  • 4. public class BaseNavigationForm extends Form { public BaseNavigationForm(AppSettings app, Layout l) { super(app.name.get(), l); init(app); } private void init(AppSettings app) { Toolbar tb = getToolbar(); tb.addMaterialCommandToSideMenu("Dishes", FontImage.MATERIAL_RESTAURANT_MENU, e -> new DishListForm(app).show()); tb.addMaterialCommandToSideMenu("Details", FontImage.MATERIAL_DESCRIPTION, e -> new DetailsForm(app).show()); tb.addMaterialCommandToSideMenu("Billing", FontImage.MATERIAL_CREDIT_CARD, e -> {}); tb.addMaterialCommandToSideMenu("App", FontImage.MATERIAL_PHONE_IPHONE, e -> new AppForm(app).show()); TextField title = new TextField(app.name.get()); title.setUIID("NavigationTitle"); TextField tagline = new TextField(app.tagline.get()); tagline.setUIID("Tagline"); BaseNavigationForm UIID Derive NavigationTitle 3mm font The tagline is similarly a text field with the right styling. Technically the styling derives navigation title so we can be in sync with changes to the title style. It just uses a smaller 3 millimeter font.
  • 5. public class BaseNavigationForm extends Form { public BaseNavigationForm(AppSettings app, Layout l) { super(app.name.get(), l); init(app); } private void init(AppSettings app) { Toolbar tb = getToolbar(); tb.addMaterialCommandToSideMenu("Dishes", FontImage.MATERIAL_RESTAURANT_MENU, e -> new DishListForm(app).show()); tb.addMaterialCommandToSideMenu("Details", FontImage.MATERIAL_DESCRIPTION, e -> new DetailsForm(app).show()); tb.addMaterialCommandToSideMenu("Billing", FontImage.MATERIAL_CREDIT_CARD, e -> {}); tb.addMaterialCommandToSideMenu("App", FontImage.MATERIAL_PHONE_IPHONE, e -> new AppForm(app).show()); TextField title = new TextField(app.name.get()); title.setUIID("NavigationTitle"); TextField tagline = new TextField(app.tagline.get()); tagline.setUIID("Tagline"); BaseNavigationForm In case this wasn’t clear these UIID’s map to the title and subtitle of the form right here
  • 6. Button editBackground = new Button("Edit Background", "EditBackground"); int size = Display.getInstance().convertToPixels(10); Button logoImage = new Button("", app.getRoundedScaledLogo(), "Container"); Container titleContainer = BoxLayout.encloseY( title, tagline, FlowLayout.encloseCenterMiddle(logoImage)); Button menu = new Button("", "NavigationTitle"); Button preview = new Button("", "NavigationTitle"); FontImage.setMaterialIcon(menu, FontImage.MATERIAL_MENU); FontImage.setMaterialIcon(preview, FontImage.MATERIAL_PLAY_ARROW); Container titleWithCommands = BorderLayout.centerEastWest( titleContainer, FlowLayout.encloseCenter(preview), FlowLayout.encloseCenter(menu)); menu.addActionListener(e -> tb.openSideMenu()); ScaleImageLabel sl = new ScaleImageLabel(app.titleBackground.get()); sl.setUIID("TitleBottomSpace"); sl.setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FILL); if(super.shouldPaintStatusBar()) { titleWithCommands.getUnselectedStyle().setPaddingUnit(Style.UNIT_TYPE_DIPS); titleWithCommands.getUnselectedStyle().setPaddingTop(3); } tb.setTitleComponent(LayeredLayout.encloseIn(sl, BorderLayout.south(editBackground), titleWithCommands)); } BaseNavigationForm UIID 0 Margin top/right/left 4mm bottom margin 0 Padding Derive NavigationTitle Right alignment thin 2.5mm font Moving on the edit background UI on the bottom right portion of the form maps to this button which allows us to edit the background image in the title area. You will notice we use the constructor that accepts the button label and UIID. The EditBackground UIID is styled to match the navigation title but it also adds padding to the bottom so the text doesn’t appear within the white area. I’ll talk about that more in the next section… Besides that the other interesting thing about this UIID is the right alignment which we use to make sure it appears to the right of the icon.
  • 7. Button editBackground = new Button("Edit Background", "EditBackground"); int size = Display.getInstance().convertToPixels(10); Button logoImage = new Button("", app.getRoundedScaledLogo(), "Container"); Container titleContainer = BoxLayout.encloseY( title, tagline, FlowLayout.encloseCenterMiddle(logoImage)); Button menu = new Button("", "NavigationTitle"); Button preview = new Button("", "NavigationTitle"); FontImage.setMaterialIcon(menu, FontImage.MATERIAL_MENU); FontImage.setMaterialIcon(preview, FontImage.MATERIAL_PLAY_ARROW); Container titleWithCommands = BorderLayout.centerEastWest( titleContainer, FlowLayout.encloseCenter(preview), FlowLayout.encloseCenter(menu)); menu.addActionListener(e -> tb.openSideMenu()); ScaleImageLabel sl = new ScaleImageLabel(app.titleBackground.get()); sl.setUIID("TitleBottomSpace"); sl.setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FILL); if(super.shouldPaintStatusBar()) { titleWithCommands.getUnselectedStyle().setPaddingUnit(Style.UNIT_TYPE_DIPS); titleWithCommands.getUnselectedStyle().setPaddingTop(3); } tb.setTitleComponent(LayeredLayout.encloseIn(sl, BorderLayout.south(editBackground), titleWithCommands)); } BaseNavigationForm UIID 0 padding sides 1mm padding top/bottom 4mm bottom The background image is just a scaled image label that stretches all across. We added a 4 millimeter margin to the bottom of this background image and that allows the icon to “peek” exactly 4 millimeters outside of the bottom portion. This looks decent enough and works well for all resolutions since the size is in millimeters and the icon is also scaled in millimeters.
  • 8. Button editBackground = new Button("Edit Background", "EditBackground"); int size = Display.getInstance().convertToPixels(10); Button logoImage = new Button("", app.getRoundedScaledLogo(), "Container"); Container titleContainer = BoxLayout.encloseY( title, tagline, FlowLayout.encloseCenterMiddle(logoImage)); Button menu = new Button("", "NavigationTitle"); Button preview = new Button("", "NavigationTitle"); FontImage.setMaterialIcon(menu, FontImage.MATERIAL_MENU); FontImage.setMaterialIcon(preview, FontImage.MATERIAL_PLAY_ARROW); Container titleWithCommands = BorderLayout.centerEastWest( titleContainer, FlowLayout.encloseCenter(preview), FlowLayout.encloseCenter(menu)); menu.addActionListener(e -> tb.openSideMenu()); ScaleImageLabel sl = new ScaleImageLabel(app.titleBackground.get()); sl.setUIID("TitleBottomSpace"); sl.setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FILL); if(super.shouldPaintStatusBar()) { titleWithCommands.getUnselectedStyle().setPaddingUnit(Style.UNIT_TYPE_DIPS); titleWithCommands.getUnselectedStyle().setPaddingTop(3); } tb.setTitleComponent(LayeredLayout.encloseIn(sl, BorderLayout.south(editBackground), titleWithCommands)); } BaseNavigationForm The logo image uses a special rounded scaled logo getter which adapts the logos look to the design of the UI let’s go see how that method works
  • 9. public class AppSettings implements PropertyBusinessObject { public final Property<String, AppSettings> name = new Property<>("name", "My Restaurant"); public final Property<String, AppSettings> tagline = new Property<>("tagline", "The place to eat"); public final Property<Image, AppSettings> titleBackground = new Property<>("titleBackground", null); private Image roundedScaledLogo; private final PropertyIndex idx = new PropertyIndex(this, "AppSettings", name, tagline, logo, titleBackground); @Override public PropertyIndex getPropertyIndex() { return idx; } public Image getRoundedScaledLogo() { return roundedScaledLogo; } AppSettings The rounded scaled logo is just an image with no setter, so where is this initialized?
  • 10. public final Property<Image, AppSettings> logo = new Property<Image, AppSettings>("logo", null) { public AppSettings set(Image value) { if(value != null) { int mm = Display.getInstance().convertToPixels(2f); int size = Display.getInstance().convertToPixels(11); GeneralPath gp = new GeneralPath(); float widthF = size; float heightF = size; gp.moveTo(x + mm, 0); gp.lineTo(x + widthF - mm, 0); gp.quadTo(x + widthF, 0, widthF, mm); gp.lineTo(x + widthF, heightF - mm); gp.quadTo(x + widthF, heightF, x + widthF - mm, heightF); gp.lineTo(x + mm, heightF); gp.quadTo(x, heightF, 0, heightF - radius); gp.lineTo(x, mm); gp.quadTo(x, 0, mm, 0); gp.closePath(); Image mask = Image.createImage(size, size, 0xff000000); Graphics g = mask.getGraphics(); g.setColor(0xffffff); g.setAntiAliased(true); g.fillShape(gp); Object m = mask.createMask(); roundedScaledLogo = value.fill(size, size).applyMask(m); } return super.set(value); } }; AppSettings When we set the property for the logo we automatically generate this image too by drawing the image in the right place. Let’s go over these steps
  • 11. public final Property<Image, AppSettings> logo = new Property<Image, AppSettings>("logo", null) { public AppSettings set(Image value) { if(value != null) { int mm = Display.getInstance().convertToPixels(2f); int size = Display.getInstance().convertToPixels(11); GeneralPath gp = new GeneralPath(); float widthF = size; float heightF = size; gp.moveTo(x + mm, 0); gp.lineTo(x + widthF - mm, 0); gp.quadTo(x + widthF, 0, widthF, mm); gp.lineTo(x + widthF, heightF - mm); gp.quadTo(x + widthF, heightF, x + widthF - mm, heightF); gp.lineTo(x + mm, heightF); gp.quadTo(x, heightF, 0, heightF - radius); gp.lineTo(x, mm); gp.quadTo(x, 0, mm, 0); gp.closePath(); Image mask = Image.createImage(size, size, 0xff000000); Graphics g = mask.getGraphics(); g.setColor(0xffffff); g.setAntiAliased(true); g.fillShape(gp); Object m = mask.createMask(); roundedScaledLogo = value.fill(size, size).applyMask(m); } return super.set(value); } }; AppSettings We have two important sizes here, mm is the size of the arc in the corner and size is the size of the entire icon. I got these numbers thru trial and error until I got something that looked satisfactory in the various device densities.
  • 12. public final Property<Image, AppSettings> logo = new Property<Image, AppSettings>("logo", null) { public AppSettings set(Image value) { if(value != null) { int mm = Display.getInstance().convertToPixels(2f); int size = Display.getInstance().convertToPixels(11); GeneralPath gp = new GeneralPath(); float widthF = size; float heightF = size; gp.moveTo(x + mm, 0); gp.lineTo(x + widthF - mm, 0); gp.quadTo(x + widthF, 0, widthF, mm); gp.lineTo(x + widthF, heightF - mm); gp.quadTo(x + widthF, heightF, x + widthF - mm, heightF); gp.lineTo(x + mm, heightF); gp.quadTo(x, heightF, 0, heightF - radius); gp.lineTo(x, mm); gp.quadTo(x, 0, mm, 0); gp.closePath(); Image mask = Image.createImage(size, size, 0xff000000); Graphics g = mask.getGraphics(); g.setColor(0xffffff); g.setAntiAliased(true); g.fillShape(gp); Object m = mask.createMask(); roundedScaledLogo = value.fill(size, size).applyMask(m); } return super.set(value); } }; AppSettings A general path is a shape object, we can fill, stroke or clip based on a shape. Notice that shape operations can sometimes be expensive in terms of graphics processing power so while they are very powerful you need to be very aware of what you are trying to do. A general path allows us to define an arbitrary shape we can then use in the drawing primitives. This raises the question of why not use the builtin round rect methods within graphics, those don’t allow the same level of customizability and power as the shape API. They aren’t as consistent across platform either.
  • 13. public final Property<Image, AppSettings> logo = new Property<Image, AppSettings>("logo", null) { public AppSettings set(Image value) { if(value != null) { int mm = Display.getInstance().convertToPixels(2f); int size = Display.getInstance().convertToPixels(11); GeneralPath gp = new GeneralPath(); float widthF = size; float heightF = size; gp.moveTo(x + mm, 0); gp.lineTo(x + widthF - mm, 0); gp.quadTo(x + widthF, 0, widthF, mm); gp.lineTo(x + widthF, heightF - mm); gp.quadTo(x + widthF, heightF, x + widthF - mm, heightF); gp.lineTo(x + mm, heightF); gp.quadTo(x, heightF, 0, heightF - radius); gp.lineTo(x, mm); gp.quadTo(x, 0, mm, 0); gp.closePath(); Image mask = Image.createImage(size, size, 0xff000000); Graphics g = mask.getGraphics(); g.setColor(0xffffff); g.setAntiAliased(true); g.fillShape(gp); Object m = mask.createMask(); roundedScaledLogo = value.fill(size, size).applyMask(m); } return super.set(value); } }; AppSettings Building the shape is essentialy about moving a virtual pen around and drawing lines, arcs or curves along the path. This is mostly straight forward.
  • 14. public final Property<Image, AppSettings> logo = new Property<Image, AppSettings>("logo", null) { public AppSettings set(Image value) { if(value != null) { int mm = Display.getInstance().convertToPixels(2f); int size = Display.getInstance().convertToPixels(11); GeneralPath gp = new GeneralPath(); float widthF = size; float heightF = size; gp.moveTo(x + mm, 0); gp.lineTo(x + widthF - mm, 0); gp.quadTo(x + widthF, 0, widthF, mm); gp.lineTo(x + widthF, heightF - mm); gp.quadTo(x + widthF, heightF, x + widthF - mm, heightF); gp.lineTo(x + mm, heightF); gp.quadTo(x, heightF, 0, heightF - radius); gp.lineTo(x, mm); gp.quadTo(x, 0, mm, 0); gp.closePath(); Image mask = Image.createImage(size, size, 0xff000000); Graphics g = mask.getGraphics(); g.setColor(0xffffff); g.setAntiAliased(true); g.fillShape(gp); Object m = mask.createMask(); roundedScaledLogo = value.fill(size, size).applyMask(m); } return super.set(value); } }; AppSettings Here we create a mask from the shape, a mask for the image. We create a solid black image and we fill the shape area with white color then we create a mask. A mask can be applied to the image to remove the black pieces and leave the white pieces. This begs the question, why not use shape clipping that I mentioned earlier? Masking supports anti-aliasing which renders the elements in the corners with a slight alpha channel to make the corner seem smooth. A clip is a binary operation where a pixel can either be in the clip or it’s outside of the clip so there is no room for interpretation. Using shape clipping won’t look as good!
 Furthermore, shape clipping isn’t as portable as masking which is 100% portable to all supported Codename One platforms.
  • 15. public final Property<Image, AppSettings> logo = new Property<Image, AppSettings>("logo", null) { public AppSettings set(Image value) { if(value != null) { int mm = Display.getInstance().convertToPixels(2f); int size = Display.getInstance().convertToPixels(11); GeneralPath gp = new GeneralPath(); float widthF = size; float heightF = size; gp.moveTo(x + mm, 0); gp.lineTo(x + widthF - mm, 0); gp.quadTo(x + widthF, 0, widthF, mm); gp.lineTo(x + widthF, heightF - mm); gp.quadTo(x + widthF, heightF, x + widthF - mm, heightF); gp.lineTo(x + mm, heightF); gp.quadTo(x, heightF, 0, heightF - radius); gp.lineTo(x, mm); gp.quadTo(x, 0, mm, 0); gp.closePath(); Image mask = Image.createImage(size, size, 0xff000000); Graphics g = mask.getGraphics(); g.setColor(0xffffff); g.setAntiAliased(true); g.fillShape(gp); Object m = mask.createMask(); roundedScaledLogo = value.fill(size, size).applyMask(m); } return super.set(value); } }; AppSettings In the last line of this code we do two separate things. The fill method scales the image but it does that while cropping redundant areas. So if we have an image that isn’t a square the areas outside will be clipped and the center will remain.
 We then apply he mask to the clipped image to create that round effect