/* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores * CA 94065 USA or visit www.oracle.com if you need additional information or * have any questions. */ package com.codename1.ui; import com.codename1.io.Log; import com.codename1.ui.animations.Transition; import com.codename1.ui.events.ActionEvent; import com.codename1.ui.geom.Dimension; import com.codename1.ui.geom.Rectangle; import com.codename1.ui.layouts.BorderLayout; import com.codename1.ui.layouts.FlowLayout; import com.codename1.ui.layouts.GridLayout; import com.codename1.ui.layouts.Layout; import com.codename1.ui.plaf.Border; import com.codename1.ui.plaf.LookAndFeel; import com.codename1.ui.plaf.Style; import com.codename1.ui.plaf.UIManager; import java.util.Hashtable; import java.util.Map; /** * <p>A dialog is a form that occupies a part of the screen and appears as a modal * entity to the developer. Dialogs allow us to prompt users for information and * rely on the information being available on the next line after the show method.</p> * <p>Modality indicates that a dialog will block the calling thread even if the * calling thread is the EDT. Notice that a dialog will not release the block * until dispose is called even if show() from another form is called! Events are still performed thanks * to the {@link com.codename1.ui.Display#invokeAndBlock(java.lang.Runnable)} capability of the * <code>Display</code> class.</p> * <p>To determine the size of the dialog use the show method that accepts 4 integer * values, notice that these values accept margin from the four sides rather than x, y, width * and height values!</p> * <p>It's important to style a <code>Dialog</code> using {@link Dialog#getDialogStyle()} or * {@link Dialog#setDialogUIID(java.lang.String)} methods rather than styling the dialog object directly.</p> * <p> * The <code>Dialog</code> class also includes support for popup dialog which is a dialog type that is positioned * next to a component or screen area and points an arrow at that location. * </p> * * <p>Typical dialog usage looks like this:</p> * <script src="https://gist.github.com/codenameone/bbf5378aec028230ce93.js"></script> * * <p>See this sample for showing a dialog at the bottom of the screen:</p> * <script src="https://gist.github.com/codenameone/60ca2cc54eea0cb12ede.js"></script> * <img src="https://www.codenameone.com/img/developer-guide/components-dialog-modal-south.png" alt="Dialog South" /> * * @author Shai Almog * @see Display#invokeAndBlock(java.lang.Runnable) */ public class Dialog extends Form { /** * Indicates whether the dialog has been disposed */ private boolean disposed; /** * Constant indicating the type of alert to indicate the sound to play or * icon if none are explicitly set */ public static final int TYPE_NONE = 0; /** * Constant indicating the type of alert to indicate the sound to play or * icon if none are explicitly set */ public static final int TYPE_ALARM = 1; /** * Constant indicating the type of alert to indicate the sound to play or * icon if none are explicitly set */ public static final int TYPE_CONFIRMATION = 2; /** * Constant indicating the type of alert to indicate the sound to play or * icon if none are explicitly set */ public static final int TYPE_ERROR = 3; /** * Constant indicating the type of alert to indicate the sound to play or * icon if none are explicitly set */ public static final int TYPE_INFO = 4; /** * Constant indicating the type of alert to indicate the sound to play or * icon if none are explicitly set */ public static final int TYPE_WARNING = 5; /** * Indicates the time in which the alert should be disposed */ private long time; /** * Indicates the last command selected by the user in this form */ private Command lastCommandPressed; /** * Indicates that this is a menu preventing getCurrent() from ever returning this class */ private boolean menu; private int dialogType; private int top = -1; private int bottom; private int left; private int right; private boolean includeTitle; private String position; /** * Indicates whether Codename One should try to automatically adjust a showing dialog size * when a screen size change event occurs */ private static boolean autoAdjustDialogSize = true; /** * Default screen orientation position for the upcoming dialog. By default * the dialog will be shown at hardcoded coordinates, this method allows us * to pack the dialog appropriately in one of the border layout based locations * see BorderLayout for futher details. */ private static String defaultDialogPosition; /** * Default screen orientation position for the upcoming dialog. By default * the dialog will be shown at hardcoded coordinates, this method allows us * to pack the dialog appropriately in one of the border layout based locations * see BorderLayout for futher details. */ private String dialogPosition = defaultDialogPosition; /** * Allows a developer to indicate his interest that the dialog should no longer * scroll on its own but rather rely on the scrolling properties of internal * scrollable containers. This flag only affects the static show methods within * this class. */ private static boolean disableStaticDialogScrolling; /** * Determines whether the execution of a command on this dialog implicitly * disposes the dialog. This defaults to true which is a sensible default for * simple dialogs. */ private boolean autoDispose = true; private boolean modal = true; private Command[] buttonCommands; private boolean disposeOnRotation; /** * The default type for dialogs */ private static int defaultDialogType = TYPE_INFO; /** * Places commands as buttons at the bottom of the standard static dialogs rather than * as softbuttons. This is especially appropriate for devices such as touch devices and * devices without the common softbuttons (e.g. blackberries). * The default value is false */ private static boolean commandsAsButtons = true; private boolean disposeWhenPointerOutOfBounds = false; private boolean pressedOutOfBounds; /** * Returns true if the dialog was disposed automatically due to device rotation */ private boolean disposedDueToRotation; private Label dialogTitle; private Container dialogContentPane; /** * Indicates if we want to enforce directional bias for the popup dialog. If null this field is ignored but if * its set to a value it biases the system towards a fixed direction for the popup dialog. */ private Boolean popupDirectionBiasPortrait; /** * Dialog background can be blurred using a Gaussian blur effect, this sets the radius of the Gaussian * blur. -1 is a special case value that indicates that no blurring should take effect and the default tint mode * only should be used */ private static float defaultBlurBackgroundRadius = -1; /** * Dialog background can be blurred using a Gaussian blur effect, this sets the radius of the Gaussian * blur. -1 is a special case value that indicates that no blurring should take effect and the default tint mode * only should be used */ private float blurBackgroundRadius = defaultBlurBackgroundRadius; /** * Constructs a Dialog with a title * * @param title the title of the dialog */ public Dialog(String title) { this(); setTitle(title); } /** * Constructs a Dialog with a title * * @param title the title of the dialog * @param lm the layout for the dialog */ public Dialog(String title, Layout lm) { this(lm); setTitle(title); } /** * Disabling ad padding for dialogs */ void initAdPadding(Display d) { } /** * Constructs a Dialog * */ public Dialog() { this("Dialog", "DialogTitle"); } /** * Constructs a Dialog with a layout * * @param lm the layout manager */ public Dialog(Layout lm) { this("Dialog", "DialogTitle", lm); } Dialog(String dialogUIID, String dialogTitleUIID) { super(); initImpl(dialogUIID, dialogTitleUIID, null); } Dialog(String dialogUIID, String dialogTitleUIID, Layout lm) { super(); initImpl(dialogUIID, dialogTitleUIID, lm); } private void initImpl(String dialogUIID, String dialogTitleUIID, Layout lm) { super.getContentPane().setUIID(dialogUIID); super.getTitleComponent().setText(""); super.getTitleComponent().setVisible(false); super.getTitleArea().setVisible(false); super.getTitleArea().setUIID("Container"); lockStyleImages(getUnselectedStyle()); titleArea.setVisible(false); if(lm != null) { dialogContentPane = new Container(lm); } else { dialogContentPane = new Container(); } dialogContentPane.setUIID("DialogContentPane"); dialogTitle = new Label("", dialogTitleUIID); super.getContentPane().setLayout(new BorderLayout()); super.getContentPane().addComponent(BorderLayout.NORTH, dialogTitle); super.getContentPane().addComponent(BorderLayout.CENTER, dialogContentPane); super.getContentPane().setScrollable(false); super.getContentPane().setAlwaysTensile(false); super.getStyle().setBgTransparency(0); super.getStyle().setBgImage(null); super.getStyle().setBorder(null); setSmoothScrolling(false); deregisterAnimated(this); } /** * Overriden to disable the toolbar in dialogs <br> * {@inheritDoc} */ @Override protected final void initGlobalToolbar() { } public Container getContentPane() { return dialogContentPane; } /** * {@inheritDoc} */ public Layout getLayout() { return dialogContentPane.getLayout(); } /** * {@inheritDoc} */ public String getTitle() { return dialogTitle.getText(); } /** * {@inheritDoc} */ public void addComponent(Component cmp) { dialogContentPane.addComponent(cmp); } /** * {@inheritDoc} */ public void addComponent(Object constraints, Component cmp) { dialogContentPane.addComponent(constraints, cmp); } /** * {@inheritDoc} */ public void addComponent(int index, Object constraints, Component cmp) { dialogContentPane.addComponent(index, constraints, cmp); } /** * {@inheritDoc} */ public void addComponent(int index, Component cmp) { dialogContentPane.addComponent(index, cmp); } /** * {@inheritDoc} */ public void removeAll() { dialogContentPane.removeAll(); } /** * {@inheritDoc} */ public void removeComponent(Component cmp) { dialogContentPane.removeComponent(cmp); } /** * {@inheritDoc} */ public Label getTitleComponent() { return dialogTitle; } /** * {@inheritDoc} */ public Style getTitleStyle() { return dialogTitle.getStyle(); } /** * {@inheritDoc} */ public void setLayout(Layout layout) { dialogContentPane.setLayout(layout); } void updateIcsIconCommandBehavior() { // don't set the app icon to the dialog title } /** * {@inheritDoc} */ public void setTitle(String title) { dialogTitle.setText(title); } /** * {@inheritDoc} */ public void setTitleComponent(Label title) { super.getContentPane().removeComponent(dialogTitle); dialogTitle = title; super.getContentPane().addComponent(BorderLayout.NORTH, dialogTitle); } /** * Returns the container that actually implements the dialog positioning. * This container is normally not accessible via the Codename One API. * * @return internal dialog container useful for various calculations. */ public Container getDialogComponent() { return super.getContentPane(); } /** * {@inheritDoc} */ public void setTitleComponent(Label title, Transition t) { super.getContentPane().replace(dialogTitle, title, t); dialogTitle = title; } /** * Simple setter to set the Dialog Style * * @param style */ public void setDialogStyle(Style style){ super.getContentPane().setUnselectedStyle(style); } /** * Simple setter to set the Dialog uiid * * @param uiid the id for the dialog */ public void setDialogUIID(String uiid){ super.getContentPane().setUIID(uiid); } /** * Returns the uiid of the dialog * * @return the uiid of the dialog */ public String getDialogUIID(){ return super.getContentPane().getUIID(); } /** * Simple getter to get the Dialog Style * * @return the style of the dialog */ public Style getDialogStyle(){ return super.getContentPane().getStyle(); } /** * Initialize the default transition for the dialogs overriding the forms * transition * * @param laf the default transition for the dialog */ protected void initLaf(UIManager uim) { super.initLaf(uim); setTransitionOutAnimator(uim.getLookAndFeel().getDefaultDialogTransitionOut()); setTransitionInAnimator(uim.getLookAndFeel().getDefaultDialogTransitionIn()); } /** * This method shows the form as a modal alert allowing us to produce a behavior * of an alert/dialog box. This method will block the calling thread even if the * calling thread is the EDT. Notice that this method will not release the block * until dispose is called even if show() from another form is called! * <p>Modal dialogs Allow the forms "content" to "hang in mid air" this is especially useful for * dialogs where you would want the underlying form to "peek" from behind the * form. * * @param top space in pixels between the top of the screen and the form * @param bottom space in pixels between the bottom of the screen and the form * @param left space in pixels between the left of the screen and the form * @param right space in pixels between the right of the screen and the form * @param includeTitle whether the title should hang in the top of the screen or * be glued onto the content pane * @return the last command pressed by the user if such a command exists * @deprecated use the version that doesn't accept the include title, the includeTitle * feature is no longer supported */ public Command show(int top, int bottom, int left, int right, boolean includeTitle) { return show(top, bottom, left, right, includeTitle, true); } /** * <p>This method shows the form as a modal alert allowing us to produce a behavior * of an alert/dialog box. This method will block the calling thread even if the * calling thread is the EDT. Notice that this method will not release the block * until dispose is called even if show() from another form is called!</p> * <p>Modal dialogs Allow the forms "content" to "hang in mid air" this is especially useful for * dialogs where you would want the underlying form to "peek" from behind the * form. </p> * See this sample for showing a dialog at the bottom of the screen: * <script src="https://gist.github.com/codenameone/60ca2cc54eea0cb12ede.js"></script> * * @param top space in pixels between the top of the screen and the form * @param bottom space in pixels between the bottom of the screen and the form * @param left space in pixels between the left of the screen and the form * @param right space in pixels between the right of the screen and the form * @return the last command pressed by the user if such a command exists */ public Command show(int top, int bottom, int left, int right) { return show(top, bottom, left, right, false, true); } /** * This method shows the form as a modal alert allowing us to produce a behavior * of an alert/dialog box. This method will block the calling thread even if the * calling thread is the EDT. Notice that this method will not release the block * until dispose is called even if show() from another form is called! * <p>Modal dialogs Allow the forms "content" to "hang in mid air" this is especially useful for * dialogs where you would want the underlying form to "peek" from behind the * form. * * @param top space in pixels between the top of the screen and the form * @param bottom space in pixels between the bottom of the screen and the form * @param left space in pixels between the left of the screen and the form * @param right space in pixels between the right of the screen and the form * @param includeTitle whether the title should hang in the top of the screen or * be glued onto the content pane * @param modal indicates the dialog should be modal set to false for modeless dialog * which is useful for some use cases * @return the last command pressed by the user if such a command exists * @deprecated use showAtPosition, the includeTitle flag is no longer supported */ public Command show(int top, int bottom, int left, int right, boolean includeTitle, boolean modal) { this.top = top; this.bottom = bottom; if(isRTL()){ this.left = right; this.right = left; }else{ this.left = left; this.right = right; } //this.includeTitle = includeTitle; setDisposed(false); this.modal = modal; lastCommandPressed = null; showModal(this.top, this.bottom, this.left, this.right, includeTitle, modal, false); return lastCommandPressed; } /** * This method shows the form as a modal alert allowing us to produce a behavior * of an alert/dialog box. This method will block the calling thread even if the * calling thread is the EDT. Notice that this method will not release the block * until dispose is called even if show() from another form is called! * <p>Modal dialogs Allow the forms "content" to "hang in mid air" this is especially useful for * dialogs where you would want the underlying form to "peek" from behind the * form. * * @param top space in pixels between the top of the screen and the form * @param bottom space in pixels between the bottom of the screen and the form * @param left space in pixels between the left of the screen and the form * @param right space in pixels between the right of the screen and the form * @param modal indicates the dialog should be modal set to false for modeless dialog * which is useful for some use cases * @return the last command pressed by the user if such a command exists */ public Command showAtPosition(int top, int bottom, int left, int right, boolean modal) { this.top = top; this.bottom = bottom; if(isRTL()){ this.left = right; this.right = left; }else{ this.left = left; this.right = right; } //this.includeTitle = includeTitle; setDisposed(false); this.modal = modal; lastCommandPressed = null; showModal(this.top, this.bottom, this.left, this.right, false, modal, false); return lastCommandPressed; } /** * Disable title bar status for iOS 7 which breaks dialogs */ void initTitleBarStatus() { } /** * Indicates the time (in milliseconds) afterwhich the dialog will be disposed * implicitly * * @param time a milliseconds time used to dispose the dialog */ public void setTimeout(long time) { this.time = System.currentTimeMillis() + time; super.registerAnimatedInternal(this); } /** * Shows a modal prompt dialog with the given title and text. * * @param title The title for the dialog optionally null; * @param text the text displayed in the dialog * @param type the type of the alert one of TYPE_WARNING, TYPE_INFO, * TYPE_ERROR, TYPE_CONFIRMATION or TYPE_ALARM * @param icon the icon for the dialog, can be null * @param okText the text to appear in the command dismissing the dialog * @param cancelText optionally null for a text to appear in the cancel command * for canceling the dialog * @return true if the ok command was pressed or if cancelText is null. False otherwise. */ public static boolean show(String title, String text, int type, Image icon, String okText, String cancelText) { return show(title, text, type, icon, okText, cancelText, 0); } /** * {@inheritDoc} */ void sizeChangedInternal(int w, int h) { if(disposeOnRotation) { disposedDueToRotation = true; dispose(); Form frm = getPreviousForm(); if(frm != null){ frm.sizeChangedInternal(w, h); } return; } autoAdjust(w, h); super.sizeChangedInternal(w, h); Form frm = getPreviousForm(); if(frm != null){ frm.sizeChangedInternal(w, h); } } /** * Auto adjust size of the dialog. * This method is triggered from a sizeChanged event. * * @param w width of the screen * @param h height of the screen */ protected void autoAdjust(int w, int h) { if (autoAdjustDialogSize) { growOrShrinkImpl(w, h); } } /** * Shows a modal prompt dialog with the given title and text. * * @param title The title for the dialog optionally null; * @param text the text displayed in the dialog * @param type the type of the alert one of TYPE_WARNING, TYPE_INFO, * TYPE_ERROR, TYPE_CONFIRMATION or TYPE_ALARM * @param icon the icon for the dialog, can be null * @param okText the text to appear in the command dismissing the dialog * @param cancelText optionally null for a text to appear in the cancel command * for canceling the dialog * @param timeout a timeout after which null would be returned if timeout is 0 inifinite time is used * @return true if the ok command was pressed or if cancelText is null. False otherwise. */ public static boolean show(String title, String text, int type, Image icon, String okText, String cancelText, long timeout) { Command[] cmds; Command okCommand = new Command(okText); if (cancelText != null) { cmds = new Command[]{new Command(cancelText), okCommand}; } else { cmds = new Command[]{okCommand}; } return show(title, text, okCommand, cmds, type, icon, timeout) == okCommand; } /** * Shows a modal prompt dialog with the given title and text. * * @param title The title for the dialog optionally null; * @param text the text displayed in the dialog * @param cmds commands that are added to the form any click on any command * will dispose the form * @param type the type of the alert one of TYPE_WARNING, TYPE_INFO, * TYPE_ERROR, TYPE_CONFIRMATION or TYPE_ALARM * @param icon the icon for the dialog, can be null * @param timeout a timeout after which null would be returned if timeout is 0 inifinite time is used * @return the command pressed by the user */ public static Command show(String title, String text, Command[] cmds, int type, Image icon, long timeout) { return show(title, text, null, cmds, type, icon, timeout); } /** * Shows a modal prompt dialog with the given title and text. * * @param title The title for the dialog optionally null; * @param text the text displayed in the dialog * @param defaultCommand command to be assigned as the default command or null * @param cmds commands that are added to the form any click on any command * will dispose the form * @param type the type of the alert one of TYPE_WARNING, TYPE_INFO, * TYPE_ERROR, TYPE_CONFIRMATION or TYPE_ALARM * @param icon the icon for the dialog, can be null * @param timeout a timeout after which null would be returned if timeout is 0 inifinite time is used * @return the command pressed by the user */ public static Command show(String title, String text, Command defaultCommand, Command[] cmds, int type, Image icon, long timeout) { return show(title, text, defaultCommand, cmds, type, icon, timeout, null); } /** * Shows a modal prompt dialog with the given title and text. * * @param title The title for the dialog optionally null; * @param text the text displayed in the dialog * @param cmds commands that are added to the form any click on any command * will dispose the form * @param type the type of the alert one of TYPE_WARNING, TYPE_INFO, * TYPE_ERROR, TYPE_CONFIRMATION or TYPE_ALARM * @param icon the icon for the dialog, can be null * @param timeout a timeout after which null would be returned if timeout is 0 inifinite time is used * @param transition the transition installed when the dialog enters/leaves * @return the command pressed by the user */ public static Command show(String title, String text, Command[] cmds, int type, Image icon, long timeout, Transition transition) { return show(title, text, null, cmds, type, icon, timeout, transition); } /** * Shows a modal prompt dialog with the given title and text. * * @param title The title for the dialog optionally null; * @param text the text displayed in the dialog * @param defaultCommand command to be assigned as the default command or null * @param cmds commands that are added to the form any click on any command * will dispose the form * @param type the type of the alert one of TYPE_WARNING, TYPE_INFO, * TYPE_ERROR, TYPE_CONFIRMATION or TYPE_ALARM * @param icon the icon for the dialog, can be null * @param timeout a timeout after which null would be returned if timeout is 0 inifinite time is used * @param transition the transition installed when the dialog enters/leaves * @return the command pressed by the user */ public static Command show(String title, String text, Command defaultCommand, Command[] cmds, int type, Image icon, long timeout, Transition transition) { Map<String, String> h = UIManager.getInstance().getBundle(); if(h != null && text != null) { Object o = h.get(text); if(o != null) { text = (String)o; } } TextArea t = new TextArea(text, 3, 30); t.setUIID("DialogBody"); t.setEditable(false); return show(title, t, defaultCommand, cmds, type, icon, timeout, transition); } /** * Shows a modal prompt dialog with the given title and text. * * @param title The title for the dialog optionally null; * @param text the text displayed in the dialog * @param okText the text to appear in the command dismissing the dialog * @param cancelText optionally null for a text to appear in the cancel command * for canceling the dialog * @return true if the ok command was pressed or if cancelText is null. False otherwise. */ public static boolean show(String title, String text, String okText, String cancelText) { return show(title, text, defaultDialogType, null, okText, cancelText); } /** * Shows a modal dialog with the given component as its "body" placed in the * center. * * @param title title for the dialog * @param body component placed in the center of the dialog * @param cmds commands that are added to the form any click on any command * will dispose the form * @return the command pressed by the user */ public static Command show(String title, Component body, Command... cmds) { return show(title, body, cmds, defaultDialogType, null); } /** * Shows a modal dialog with the given component as its "body" placed in the * center. * * @param title title for the dialog * @param body component placed in the center of the dialog * @param cmds commands that are added to the form any click on any command * will dispose the form * @param type the type of the alert one of TYPE_WARNING, TYPE_INFO, * TYPE_ERROR, TYPE_CONFIRMATION or TYPE_ALARM * @param icon the icon for the dialog, can be null * @return the command pressed by the user */ public static Command show(String title, Component body, Command[] cmds, int type, Image icon) { return show(title, body, cmds, type, icon, 0); } /** * Shows a modal dialog with the given component as its "body" placed in the * center. * * @param title title for the dialog * @param body component placed in the center of the dialog * @param cmds commands that are added to the form any click on any command * will dispose the form * @param type the type of the alert one of TYPE_WARNING, TYPE_INFO, * TYPE_ERROR, TYPE_CONFIRMATION or TYPE_ALARM * @param icon the icon for the dialog, can be null * @param timeout a timeout after which null would be returned if timeout is 0 inifinite time is used * @return the command pressed by the user */ public static Command show(String title, Component body, Command[] cmds, final int type, Image icon, long timeout) { return show(title, body, cmds, type, icon, timeout, null); } /** * Shows a modal dialog with the given component as its "body" placed in the * center. * * @param title title for the dialog * @param body component placed in the center of the dialog * @param cmds commands that are added to the form any click on any command * will dispose the form * @param type the type of the alert one of TYPE_WARNING, TYPE_INFO, * TYPE_ERROR, TYPE_CONFIRMATION or TYPE_ALARM * @param icon the icon for the dialog, can be null * @param timeout a timeout after which null would be returned if timeout is 0 infinite time is used * @param transition the transition installed when the dialog enters/leaves * @return the command pressed by the user */ public static Command show(String title, Component body, Command[] cmds, int type, Image icon, long timeout, Transition transition) { return show(title, body, null, cmds, type, icon, timeout, transition); } private void addButtonBar(Container c) { super.getContentPane().addComponent(BorderLayout.SOUTH, c); } /** * Places the given commands in the dialog command area, this is very useful for touch devices. * * @param cmds the commands to place * @deprecated this method shouldn't be invoked externally, it should have been private */ public void placeButtonCommands(Command[] cmds) { buttonCommands = cmds; Container buttonArea; if(getUIManager().isThemeConstant("dlgCommandGridBool", false)) { buttonArea = new Container(new GridLayout(1, cmds.length)); } else { buttonArea = new Container(new FlowLayout(CENTER)); } buttonArea.setUIID("DialogCommandArea"); String uiid = getUIManager().getThemeConstant("dlgButtonCommandUIID", null); addButtonBar(buttonArea); if(cmds.length > 0) { String lineColor = getUIManager().getThemeConstant("dlgInvisibleButtons", null); if(cmds.length > 3) { lineColor = null; } int largest = Integer.parseInt(getUIManager().getThemeConstant("dlgCommandButtonSizeInt", "0")); for(int iter = 0 ; iter < cmds.length ; iter++) { Button b = new Button(cmds[iter]); if(uiid != null) { b.setUIID(uiid); } largest = Math.max(b.getPreferredW(), largest); if(lineColor != null && lineColor.length() > 0) { int color = Integer.parseInt(lineColor, 16); Border brd = null; if(iter < cmds.length - 1) { brd = Border.createCompoundBorder(Border.createLineBorder(1, color), null, null, Border.createLineBorder(1, color)); } else { brd = Border.createCompoundBorder(Border.createLineBorder(1, color), null, null, null); } b.getUnselectedStyle().setBorder(brd); b.getSelectedStyle().setBorder(brd); b.getPressedStyle().setBorder(brd); } buttonArea.addComponent(b); } for(int iter = 0 ; iter < cmds.length ; iter++) { buttonArea.getComponentAt(iter).setPreferredW(largest); } buttonArea.getComponentAt(0).requestFocus(); } } /** * {@inheritDoc} */ public void keyReleased(int keyCode) { if(commandsAsButtons) { if(MenuBar.isLSK(keyCode)) { if(buttonCommands != null && buttonCommands.length > 0) { dispatchCommand(buttonCommands[0], new ActionEvent(buttonCommands[0],ActionEvent.Type.KeyRelease)); return; } } if(MenuBar.isRSK(keyCode)) { if(buttonCommands != null && buttonCommands.length > 1) { dispatchCommand(buttonCommands[1], new ActionEvent(buttonCommands[1],ActionEvent.Type.KeyRelease)); return; } } } super.keyReleased(keyCode); } /** * Shows a modal dialog with the given component as its "body" placed in the * center. * * @param title title for the dialog * @param body component placed in the center of the dialog * @param defaultCommand command to be assigned as the default command or null * @param cmds commands that are added to the form any click on any command * will dispose the form * @param type the type of the alert one of TYPE_WARNING, TYPE_INFO, * TYPE_ERROR, TYPE_CONFIRMATION or TYPE_ALARM * @param icon the icon for the dialog, can be null * @param timeout a timeout after which null would be returned if timeout is 0 inifinite time is used * @param transition the transition installed when the dialog enters/leaves * @return the command pressed by the user */ public static Command show(String title, Component body, Command defaultCommand, Command[] cmds, int type, Image icon, long timeout, Transition transition) { Dialog dialog = new Dialog(title); dialog.dialogType = type; dialog.setTransitionInAnimator(transition); dialog.setTransitionOutAnimator(transition); dialog.lastCommandPressed = null; dialog.setLayout(new BorderLayout()); if(cmds != null) { if(commandsAsButtons) { dialog.placeButtonCommands(cmds); } else { for(int iter = 0 ; iter < cmds.length ; iter++) { dialog.addCommand(cmds[iter]); } } // maps the first command to back if(cmds.length == 1 || cmds.length == 2) { dialog.setBackCommand(cmds[0]); } } if(defaultCommand != null) { dialog.setDefaultCommand(defaultCommand); } dialog.addComponent(BorderLayout.CENTER, body); if (icon != null) { dialog.addComponent(BorderLayout.EAST, new Label(icon)); } if (timeout != 0) { dialog.setTimeout(timeout); } if(body.isScrollable() || disableStaticDialogScrolling){ dialog.setScrollable(false); } dialog.show(); return dialog.lastCommandPressed; } /** * {@inheritDoc} */ protected void onShow() { if (dialogType > 0) { Display.getInstance().playDialogSound(dialogType); } } void onShowCompletedImpl() { pressedOutOfBounds = false; disposedDueToRotation = false; onShowCompleted(); if(isDisposed()) { disposeImpl(); } if (showListener != null) { showListener.fireActionEvent(new ActionEvent(this,ActionEvent.Type.Show)); } } /** * {@inheritDoc} */ public void showBack() { showImpl(true); } /** * {@inheritDoc} */ public void setScrollable(boolean scrollable) { getContentPane().setScrollable(scrollable); } /** * The default version of show modal shows the dialog occupying the center portion * of the screen. */ public void show() { showImpl(false); } /** * The default version of show modal shows the dialog occupying the center portion * of the screen. */ private void showImpl(boolean reverse) { if(modal && Display.isInitialized() && Display.getInstance().isMinimized()){ Log.p("Modal dialogs cannot be displayed on a minimized app"); return; } // this behavior allows a use case where dialogs of various sizes are layered // one on top of the other setDisposed(false); if(top > -1) { show(top, bottom, left, right, includeTitle, modal); } else { if(modal) { if(getDialogPosition() == null) { super.showModal(reverse); } else { showPacked(getDialogPosition(), true); } } else { showModeless(); } } } /** * Shows a modeless dialog which is useful for some simpler use cases such as * progress indication etc... */ public void showModeless() { // this behavior allows a use case where dialogs of various sizes are layered // one on top of the other modal = false; setDisposed(false); if(top > -1) { show(top, bottom, left, right, includeTitle, false); } else { if(getDialogPosition() == null) { showDialog(false, false); } else { showPacked(getDialogPosition(), false); } } } void showModal(int top, int bottom, int left, int right, boolean includeTitle, boolean modal, boolean reverse) { if(Display.isInitialized() && Display.getInstance().isMinimized()){ Log.p("Modal dialogs cannot be displayed on a minimized app"); return; } this.top = top; this.bottom = bottom; this.left = left; this.right = right; // hide the title if no text is there to allow the styles of the dialog title to disappear if(dialogTitle != null && getUIManager().isThemeConstant("hideEmptyTitleBool", false)) { boolean b = dialogTitle.getText().length() > 0; getTitleArea().setVisible(b); getTitleComponent().setVisible(b); } super.showModal(top, bottom, left, right, includeTitle, modal, reverse); } /** * A popup dialog is shown with the context of a component and its selection, it is disposed seamlessly if the back button is pressed * or if the user touches outside its bounds. It can optionally provide an arrow in the theme to point at the context component. The popup * dialog has the PopupDialog style by default. * * @param c the context component which is used to position the dialog and can also be pointed at * @return the command that might have been triggered by the user within the dialog if commands are placed in the dialog */ public Command showPopupDialog(Component c) { Rectangle componentPos = c.getSelectedRect(); componentPos.setX(componentPos.getX() - c.getScrollX()); componentPos.setY(componentPos.getY() - c.getScrollY()); return showPopupDialog(componentPos); } /** * A popup dialog is shown with the context of a component and its selection, it is disposed seamlessly if the back button is pressed * or if the user touches outside its bounds. It can optionally provide an arrow in the theme to point at the context component. The popup * dialog has the PopupDialog style by default. * * @param rect the screen rectangle to which the popup should point * @return the command that might have been triggered by the user within the dialog if commands are placed in the dialog */ public Command showPopupDialog(Rectangle rect) { if(getDialogUIID().equals("Dialog")) { setDialogUIID("PopupDialog"); if(getTitleComponent().getUIID().equals("DialogTitle")) { getTitleComponent().setUIID("PopupDialogTitle"); } getContentPane().setUIID("PopupContentPane"); } disposeOnRotation = true; disposeWhenPointerOutOfBounds = true; Command backCommand = null; if(getBackCommand() == null) { backCommand = new Command("Back"); setBackCommand(backCommand); } Component contentPane = super.getContentPane(); Label title = super.getTitleComponent(); int menuHeight = calcMenuHeight(); UIManager manager = getUIManager(); // hide the title if no text is there to allow the styles of the dialog title to disappear, we need this code here since otherwise the // preferred size logic of the dialog won't work with large title borders if(dialogTitle != null && manager.isThemeConstant("hideEmptyTitleBool", false)) { boolean b = getTitle().length() > 0; getTitleArea().setVisible(b); getTitleComponent().setVisible(b); if(!b && manager.isThemeConstant("shrinkPopupTitleBool", true)) { getTitleComponent().setPreferredSize(new Dimension(0,0)); getTitleComponent().getStyle().setBorder(null); getTitleArea().setPreferredSize(new Dimension(0,0)); if(getContentPane().getClientProperty("$ENLARGED_POP") == null) { getContentPane().putClientProperty("$ENLARGED_POP", Boolean.TRUE); int cpPaddingTop = getContentPane().getStyle().getPaddingTop(); int titlePT = getTitleComponent().getStyle().getPaddingTop(); byte[] pu = getContentPane().getStyle().getPaddingUnit(); if(pu == null){ pu = new byte[4]; } pu[0] = Style.UNIT_TYPE_PIXELS; getContentPane().getStyle().setPaddingUnit(pu); int pop = Display.getInstance().convertToPixels(manager.getThemeConstant("popupNoTitleAddPaddingInt", 1), false); getContentPane().getStyle().setPadding(TOP, pop + cpPaddingTop + titlePT); } } } // allows a text area to recalculate its preferred size if embedded within a dialog revalidate(); Style contentPaneStyle = getDialogStyle(); boolean restoreArrow = false; if(manager.isThemeConstant(getDialogUIID()+ "ArrowBool", false)) { Image t = manager.getThemeImageConstant(getDialogUIID() + "ArrowTopImage"); Image b = manager.getThemeImageConstant(getDialogUIID() + "ArrowBottomImage"); Image l = manager.getThemeImageConstant(getDialogUIID() + "ArrowLeftImage"); Image r = manager.getThemeImageConstant(getDialogUIID() + "ArrowRightImage"); Border border = contentPaneStyle.getBorder(); if(border != null) { border.setImageBorderSpecialTile(t, b, l, r, rect); restoreArrow = true; } } int prefHeight = contentPane.getPreferredH(); int prefWidth = contentPane.getPreferredW(); if(contentPaneStyle.getBorder() != null) { prefWidth = Math.max(contentPaneStyle.getBorder().getMinimumWidth(), prefWidth); prefHeight = Math.max(contentPaneStyle.getBorder().getMinimumHeight(), prefHeight); } prefWidth += getUIManager().getLookAndFeel().getVerticalScrollWidth(); int availableHeight = Display.getInstance().getDisplayHeight() - menuHeight - title.getPreferredH(); int availableWidth = Display.getInstance().getDisplayWidth(); int width = Math.min(availableWidth, prefWidth); int x = 0; int y = 0; Command result; boolean showPortrait; if(popupDirectionBiasPortrait != null) { showPortrait = popupDirectionBiasPortrait.booleanValue(); } else { showPortrait = Display.getInstance().isPortrait(); } // if we don't have enough space then disregard device orientation if(showPortrait) { if(availableHeight < (availableWidth - rect.getWidth()) / 2) { showPortrait = false; } } else { if(availableHeight / 2 > availableWidth - rect.getWidth()) { showPortrait = true; } } if(showPortrait) { if(width < availableWidth) { int idealX = rect.getX() - width / 2 + rect.getSize().getWidth() / 2; // if the ideal position is less than 0 just use 0 if(idealX > 0) { // if the idealX is too far to the right just align to the right if(idealX + width > availableWidth) { x = availableWidth - width; } else { x = idealX; } } } if(rect.getY() < availableHeight / 2) { // popup downwards y = rect.getY() + rect.getSize().getHeight(); int height = Math.min(prefHeight, availableHeight - y); result = show(y, availableHeight - height - y, x, availableWidth - width - x, true, true); } else { // popup upwards int height = Math.min(prefHeight, availableHeight - (availableHeight - rect.getY())); y = rect.getY() - height; result = show(y, availableHeight - height - y, x, availableWidth - width - x, true, true); } } else { int height = Math.min(prefHeight, availableHeight); if(height < availableHeight) { int idealY = rect.getY() - height / 2 + rect.getSize().getHeight() / 2; // if the ideal position is less than 0 just use 0 if(idealY > 0) { // if the idealY is too far up just align to the top if(idealY + height > availableHeight) { y = availableHeight - height; } else { y = idealY; } } } if(prefWidth > rect.getX()) { // popup right x = rect.getX() + rect.getSize().getWidth(); if(x + prefWidth > availableWidth){ x = availableWidth - prefWidth; } width = Math.min(prefWidth, availableWidth - x); result = show(y, availableHeight - height - y, Math.max(0, x), Math.max(0, availableWidth - width - x), true, true); } else { // popup left width = Math.min(prefWidth, availableWidth - (availableWidth - rect.getX())); x = rect.getX() - width; result = show(y, availableHeight - height - y, Math.max(0, x), Math.max(0, availableWidth - width - x), true, true); } } if(restoreArrow) { contentPaneStyle.getBorder().clearImageBorderSpecialTile(); } if(result == backCommand) { return null; } return result; } private int calcMenuHeight() { if(getSoftButtonCount() > 1) { Component menuBar = getSoftButton(0).getParent(); Style menuStyle = menuBar.getStyle(); return menuBar.getPreferredH() + menuStyle.getVerticalMargins(); } return 0; } /** * Convenience method to show a dialog sized to match its content. * * @param position one of the values from the BorderLayout class e.g. BorderLayout.CENTER, BorderLayout.NORTH etc. * @param modal whether the dialog should be modal or modaless * @return the command selected if the dialog is modal and disposed via a command */ public Command showPacked(String position, boolean modal) { return showPackedImpl(position, modal, false); } /** * Convenience method to show a dialog stretched to one of the sides * * @param position one of the values from the BorderLayout class except for center e.g. BorderLayout.NORTH, BorderLayout.EAST etc. * @param modal whether the dialog should be modal or modaless * @return the command selected if the dialog is modal and disposed via a command */ public Command showStretched(String position, boolean modal) { return showPackedImpl(position, modal, true); } /** * Convenience method to show a dialog stretched to one of the sides * * @param position one of the values from the BorderLayout class except for center e.g. BorderLayout.NORTH, BorderLayout.EAST etc. * @param modal whether the dialog should be modal or modaless * @return the command selected if the dialog is modal and disposed via a command * @deprecated due to typo use showStretched instead */ public Command showStetched(String position, boolean modal) { return showPackedImpl(position, modal, true); } /** * Returns the preferred size of the dialog, this allows developers to position a dialog * manually in arbitrary positions. * * @return the preferred size of this dialog */ public Dimension getDialogPreferredSize() { Component contentPane = super.getContentPane(); Style contentPaneStyle = getDialogStyle(); int width = Display.getInstance().getDisplayWidth(); int prefHeight = contentPane.getPreferredH(); int prefWidth = contentPane.getPreferredW(); prefWidth = Math.min(prefWidth, width); if(contentPaneStyle.getBorder() != null) { prefWidth = Math.max(contentPaneStyle.getBorder().getMinimumWidth(), prefWidth); prefHeight = Math.max(contentPaneStyle.getBorder().getMinimumHeight(), prefHeight); } return new Dimension(prefWidth, prefHeight); } /** * Convenience method to show a dialog sized to match its content. * * @param position one of the values from the BorderLayout class e.g. BorderLayout.CENTER, BorderLayout.NORTH etc. * @param modal whether the dialog should be modal or modaless * @return the command selected if the dialog is modal and disposed via a command */ private Command showPackedImpl(String position, boolean modal, boolean stretch) { if(getTitle() == null) { setTitle(""); } this.position = position; int height = Display.getInstance().getDisplayHeight(); int width = Display.getInstance().getDisplayWidth(); if(top > -1){ refreshTheme(); } Component contentPane = super.getContentPane(); Component title = super.getTitleComponent(); // hide the title if no text is there to allow the styles of the dialog title to disappear, we need this code here since otherwise the // preferred size logic of the dialog won't work with large title borders if(dialogTitle != null && getUIManager().isThemeConstant("hideEmptyTitleBool", false)) { boolean b = getTitle().length() > 0; getTitleArea().setVisible(b); getTitleComponent().setVisible(b); } Style contentPaneStyle = getDialogStyle(); int menuHeight = calcMenuHeight(); // allows a text area to recalculate its preferred size if embedded within a dialog revalidate(); int prefHeight = contentPane.getPreferredH(); int prefWidth = contentPane.getPreferredW(); prefWidth = Math.min(prefWidth, width); if(contentPaneStyle.getBorder() != null) { prefWidth = Math.max(contentPaneStyle.getBorder().getMinimumWidth(), prefWidth); prefHeight = Math.max(contentPaneStyle.getBorder().getMinimumHeight(), prefHeight); } height = height - menuHeight - title.getPreferredH(); int topBottom = Math.max(0, (height - prefHeight) / 2); int leftRight = Math.max(0, (width - prefWidth) / 2); if(position.equals(BorderLayout.CENTER)) { show(topBottom, topBottom, leftRight, leftRight, true, modal); return lastCommandPressed; } if(position.equals(BorderLayout.EAST)) { if(stretch) { show(0, 0, Math.max(0, width - prefWidth), 0, true, modal); } else { show(topBottom, topBottom, Math.max(0, width - prefWidth), 0, true, modal); } return lastCommandPressed; } if(position.equals(BorderLayout.WEST)) { if(stretch) { show(0, 0, 0, Math.max(0, width - prefWidth), true, modal); } else { show(topBottom, topBottom, 0, Math.max(0, width - prefWidth), true, modal); } return lastCommandPressed; } if(position.equals(BorderLayout.NORTH)) { if(stretch) { show(0, Math.max(0, height - prefHeight), 0, 0, true, modal); } else { show(0, Math.max(0, height - prefHeight), leftRight, leftRight, true, modal); } return lastCommandPressed; } if(position.equals(BorderLayout.SOUTH)) { if(stretch) { show(Math.max(0, height - prefHeight), 0, 0, 0, true, modal); } else { show(Math.max(0, height - prefHeight), 0, leftRight, leftRight, true, modal); } return lastCommandPressed; } throw new IllegalArgumentException("Unknown position: " + position); } /** * Closes the current form and returns to the previous form, releasing the * EDT in the process */ public void dispose() { if(isDisposed()){ return; } setDisposed(true); // the dispose parent method might send us back to the form while the command // within the dialog might be directing us to another form causing a "blip" if(!menu) { super.dispose(); } } /** * Shows a modal dialog and returns the command pressed within the modal dialog * * @return last command pressed in the modal dialog */ public Command showDialog() { lastCommandPressed = null; show(); return lastCommandPressed; } /** * Invoked to allow subclasses of form to handle a command from one point * rather than implementing many command instances * * @param cmd the action command */ protected void actionCommand(Command cmd) { // this is important... In a case of nested dialogs based on commands/events a command might be // blocked by a different dialog, so when that dialog is disposed (as a result of a command) going // back to this dialog will block that command from proceeding and it can be fired again later // E.g.: // Dialog A has a command which triggers dialog B on top. // User presses Cancel in dialog B // Dialog A is shown as a result of dialog B dispose method // Cancel command event firing is blocked since the dialog B dispose method is now blocking on dialog A show()... // When dialog A is disposed using the OK command the OK command is sent correctly and causes dispose // EDT is released which also releases the Cancel for dialog B to keep processing... // Cancel for dialog B proceeds in the event chain reaching this method.... // lastCommandPressed can be overrwritten if this check isn't made!!! if(!autoDispose || lastCommandPressed == null) { lastCommandPressed = cmd; } if(menu || (autoDispose && cmd.isDisposesDialog())) { dispose(); } } /** * {@inheritDoc} */ public boolean animate() { isTimedOut(); return false; } private boolean isTimedOut(){ if (time != 0 && System.currentTimeMillis() >= time) { time = 0; dispose(); deregisterAnimatedInternal(this); return true; } return false; } /** * Indicates that this is a menu preventing getCurrent() from ever returning this class */ boolean isMenu() { return menu; } /** * Indicates that this is a menu preventing getCurrent() from ever returning this class */ void setMenu(boolean menu) { this.menu = menu; } /** * Prevent a menu from adding the select button */ void addSelectCommand() { if (!menu) { getMenuBar().addSelectCommand(getSelectCommandText()); } } /** * Allows us to indicate disposed state for dialogs */ boolean isDisposed() { return disposed || isTimedOut(); } /** * Allows us to indicate disposed state for dialogs */ void setDisposed(boolean disposed) { this.disposed = disposed; } /** * Determines whether the execution of a command on this dialog implicitly * disposes the dialog. This defaults to true which is a sensible default for * simple dialogs. * * @return true if this dialog disposes on any command */ public boolean isAutoDispose() { return autoDispose; } /** * Determines whether the execution of a command on this dialog implicitly * disposes the dialog. This defaults to true which is a sensible default for * simple dialogs. * * @param autoDispose true if this dialog disposes on any command */ public void setAutoDispose(boolean autoDispose) { this.autoDispose = autoDispose; } /** * Default screen orientation position for the upcoming dialog. By default * the dialog will be shown at hardcoded coordinates, this method allows us * to pack the dialog appropriately in one of the border layout based locations * see BorderLayout for futher details. * * @param p for dialogs on the sceen using BorderLayout orientation tags */ public static void setDefaultDialogPosition(String p) { defaultDialogPosition = p; } /** * Default screen orientation position for the upcoming dialog. By default * the dialog will be shown at hardcoded coordinates, this method allows us * to pack the dialog appropriately in one of the border layout based locations * see BorderLayout for futher details. * * @return position for dialogs on the sceen using BorderLayout orientation tags */ public static String getDefaultDialogPosition() { return defaultDialogPosition; } /** * The type of the dialog can be one of TYPE_WARNING, TYPE_INFO, * TYPE_ERROR, TYPE_CONFIRMATION or TYPE_ALARM * * @return can be one of TYPE_WARNING, TYPE_INFO, * TYPE_ERROR, TYPE_CONFIRMATION or TYPE_ALARM */ public int getDialogType() { return dialogType; } /** * The type of the dialog can be one of TYPE_WARNING, TYPE_INFO, * TYPE_ERROR, TYPE_CONFIRMATION or TYPE_ALARM * * @param dialogType can be one of TYPE_WARNING, TYPE_INFO, * TYPE_ERROR, TYPE_CONFIRMATION or TYPE_ALARM */ public void setDialogType(int dialogType) { this.dialogType = dialogType; } /** * The default type for dialogs * * @param d the default type for the dialog */ public static void setDefaultDialogType(int d) { defaultDialogType = d; } /** * The default type for dialogs * * @return the default type for the dialog */ public static int getDefaultDialogType() { return defaultDialogType; } /** * Indicates whether Codename One should try to automatically adjust a showing dialog size * when a screen size change event occurs * * @param a true to indicate that Codename One should make a "best effort" to resize the dialog */ public static void setAutoAdjustDialogSize(boolean a) { autoAdjustDialogSize = a; } /** * Indicates whether Codename One should try to automatically adjust a showing dialog size * when a screen size change event occurs * * @return true to indicate that Codename One should make a "best effort" to resize the dialog */ public static boolean isAutoAdjustDialogSize() { return autoAdjustDialogSize; } /** * Allows a developer to indicate his interest that the dialog should no longer * scroll on its own but rather rely on the scrolling properties of internal * scrollable containers. This flag only affects the static show methods within * this class. * * @param d indicates whether scrolling should be active or not */ public static void setDisableStaticDialogScrolling(boolean d) { disableStaticDialogScrolling = d; } /** * Allows a developer to indicate his interest that the dialog should no longer * scroll on its own but rather rely on the scrolling properties of internal * scrollable containers. This flag only affects the static show methods within * this class. * * @return true if scrolling should be activated, false otherwise */ public static boolean isDisableStaticDialogScrolling() { return disableStaticDialogScrolling; } /** * Places commands as buttons at the bottom of the standard static dialogs rather than * as softbuttons. This is especially appropriate for devices such as touch devices and * devices without the common softbuttons (e.g. blackberries). * The default value is false * * @param c true to place commands as buttons and not as softbutton keys */ public static void setCommandsAsButtons(boolean c) { commandsAsButtons = c; } /** * Places commands as buttons at the bottom of the standard static dialogs rather than * as softbuttons. This is especially appropriate for devices such as touch devices and * devices without the common softbuttons (e.g. blackberries). * The default value is false * * @return true if commands are placed as buttons and not as softbutton keys */ public static boolean isCommandsAsButtons() { return commandsAsButtons; } /** * This flag indicates if the dialog should be disposed if a pointer * released event occurred out of the dialog content. * * @param disposeWhenPointerOutOfBounds */ public void setDisposeWhenPointerOutOfBounds(boolean disposeWhenPointerOutOfBounds) { this.disposeWhenPointerOutOfBounds = disposeWhenPointerOutOfBounds; } /** * This flag indicates if the dialog should be disposed if a pointer * released event occurred out of the dialog content. * * @return true if the dialog should dispose */ public boolean isDisposeWhenPointerOutOfBounds() { return disposeWhenPointerOutOfBounds; } /** * {@inheritDoc} */ public void pointerReleased(int x, int y) { super.pointerReleased(x, y); if(disposeWhenPointerOutOfBounds && pressedOutOfBounds && !getTitleComponent().contains(x, y) && !getContentPane().contains(x, y) && !getMenuBar().contains(x, y)){ dispose(); } } /** * {@inheritDoc} */ public void pointerPressed(int x, int y) { super.pointerPressed(x, y); if(!getTitleComponent().contains(x, y) && !getContentPane().contains(x, y) && !getMenuBar().contains(x, y)){ pressedOutOfBounds = true; }else{ pressedOutOfBounds = false; } } /** * Returns true if a dialog that was disposed did it because of a pointer out of bounds * @return true when a dialog was disposed due to pointer out of bounds. */ public boolean wasDisposedDueToOutOfBoundsTouch() { return pressedOutOfBounds; } /** * Screen orientation position for the upcoming dialog. By default * the dialog will be shown at hardcoded coordinates, this method allows us * to pack the dialog appropriately in one of the border layout based locations * see BorderLayout for futher details. * @return the dialogPosition */ public String getDialogPosition() { return dialogPosition; } /** * Screen orientation position for the upcoming dialog. By default * the dialog will be shown at hardcoded coordinates, this method allows us * to pack the dialog appropriately in one of the border layout based locations * see BorderLayout for futher details. * @param dialogPosition the dialogPosition to set */ public void setDialogPosition(String dialogPosition) { this.dialogPosition = dialogPosition; } /** * {@inheritDoc} */ void repaint(Component cmp) { if(getParent() != null){ super.repaint(cmp); return; } if (isVisible() && !disposed) { Display.getInstance().repaint(cmp); } } /** * Allows a dialog component to grow or shrink to its new preferred size */ public void growOrShrink() { getDialogComponent().setShouldCalcPreferredSize(true); growOrShrinkImpl(Display.getInstance().getDisplayWidth(), Display.getInstance().getDisplayHeight()); forceRevalidate(); } private void growOrShrinkImpl(int w, int h) { Component contentPane = super.getContentPane(); Component title = super.getTitleComponent(); int prefHeight = contentPane.getPreferredH(); int prefWidth = contentPane.getPreferredW(); Style contentPaneStyle = contentPane.getStyle(); Style titleStyle = title.getStyle(); // if the dialog is packed we can scale it far more accurately based on intention if (position != null) { int menuHeight = 0; if (getSoftButtonCount() > 1) { Component menuBar = getSoftButton(0).getParent(); Style menuStyle = menuBar.getStyle(); menuHeight = menuBar.getPreferredH() + menuStyle.getVerticalMargins(); } prefWidth = Math.min(prefWidth, w); h = h - menuHeight - title.getPreferredH();// - titleStyle.getMargin(false, TOP) - titleStyle.getMargin(false, BOTTOM); int topBottom = Math.max(0, (h - prefHeight) / 2); int leftRight = Math.max(0, (w - prefWidth) / 2); int top = topBottom, bottom = topBottom; int left = leftRight, right = leftRight; if (position.equals(BorderLayout.EAST)) { left = Math.max(0, w - prefWidth); right = 0; } else { if (position.equals(BorderLayout.WEST)) { right = 0; left = Math.max(0, w - prefWidth); } else { if (position.equals(BorderLayout.NORTH)) { top = 0; bottom = Math.max(0, h - prefHeight); } else { if (position.equals(BorderLayout.SOUTH)) { top = Math.max(0, h - prefHeight); bottom = 0; } } } } titleStyle.setMargin(Component.TOP, 0, true); titleStyle.setMargin(Component.BOTTOM, 0, true); titleStyle.setMargin(Component.LEFT, 0, true); titleStyle.setMargin(Component.RIGHT, 0, true); contentPaneStyle.setMargin(Component.TOP, top, true); contentPaneStyle.setMargin(Component.BOTTOM, bottom, true); contentPaneStyle.setMargin(Component.LEFT, left, true); contentPaneStyle.setMargin(Component.RIGHT, right, true); return; } else { int oldW = getWidth(); int oldH = getHeight(); if (oldW != w || oldH != h) { // try to preserve the old size of the dialog if we still have room for it... if(prefWidth <= w && prefHeight <= h) { float oldLeftRightDistRatio = 1; if(left + right != 0) { oldLeftRightDistRatio = ((float)left) / ((float)left + right); } float oldTopBottomDistRatio = 1; if(left + right != 0) { oldTopBottomDistRatio = ((float)top) / ((float)top + bottom); } top = Math.max(0, (int)((h - prefHeight) * oldTopBottomDistRatio)); left = Math.max(0, (int)((w - prefWidth) * oldLeftRightDistRatio)); bottom = Math.max(0, (h - prefHeight) - top); right = Math.max(0, (w - prefWidth) - left); titleStyle.setMargin(Component.TOP, 0, true); titleStyle.setMargin(Component.BOTTOM, 0, true); titleStyle.setMargin(Component.LEFT, 0, true); titleStyle.setMargin(Component.RIGHT, 0, true); contentPaneStyle.setMargin(Component.TOP, top, true); contentPaneStyle.setMargin(Component.BOTTOM, bottom, true); contentPaneStyle.setMargin(Component.LEFT, left, true); contentPaneStyle.setMargin(Component.RIGHT, right, true); return; } else { float ratioW = ((float) w) / ((float) oldW); float ratioH = ((float) h) / ((float) oldH); Style s = getDialogStyle(); s.setMargin(TOP, (int) (s.getMarginTop() * ratioH)); s.setMargin(BOTTOM, (int) (s.getMarginBottom() * ratioH)); s.setMargin(LEFT, (int) (s.getMarginLeft(isRTL()) * ratioW)); s.setMargin(RIGHT, (int) (s.getMarginRight(isRTL()) * ratioW)); titleStyle.setMargin(TOP, (int) (titleStyle.getMarginTop() * ratioH)); titleStyle.setMargin(LEFT, (int) (titleStyle.getMarginLeft(isRTL()) * ratioW)); titleStyle.setMargin(RIGHT, (int) (titleStyle.getMarginRight(isRTL()) * ratioW)); return; } } } } /** * Indicates if we want to enforce directional bias for the popup dialog. If null this field is ignored but if * its set to a value it biases the system towards a fixed direction for the popup dialog. * @return the popupDirectionBiasPortrait */ public Boolean getPopupDirectionBiasPortrait() { return popupDirectionBiasPortrait; } /** * Indicates if we want to enforce directional bias for the popup dialog. If null this field is ignored but if * its set to a value it biases the system towards a fixed direction for the popup dialog. * @param popupDirectionBiasPortrait the popupDirectionBiasPortrait to set */ public void setPopupDirectionBiasPortrait(Boolean popupDirectionBiasPortrait) { this.popupDirectionBiasPortrait = popupDirectionBiasPortrait; } /** * Returns true if the dialog was disposed automatically due to device rotation * @return the disposedDueToRotation value */ public boolean wasDisposedDueToRotation() { return disposedDueToRotation; } /** * Dialog background can be blurred using a Gaussian blur effect, this sets the radius of the Gaussian * blur. -1 is a special case value that indicates that no blurring should take effect and the default tint mode * only should be used * @return the blurBackgroundRadius */ public float getBlurBackgroundRadius() { return blurBackgroundRadius; } /** * Dialog background can be blurred using a Gaussian blur effect, this sets the radius of the Gaussian * blur. -1 is a special case value that indicates that no blurring should take effect and the default tint mode * only should be used. Notice that this value can be set using the theme constant: {@code dialogBlurRadiusInt} * @param blurBackgroundRadius the blurBackgroundRadius to set */ public void setBlurBackgroundRadius(float blurBackgroundRadius) { this.blurBackgroundRadius = blurBackgroundRadius; } /** * Dialog background can be blurred using a Gaussian blur effect, this sets the radius of the Gaussian * blur. -1 is a special case value that indicates that no blurring should take effect and the default tint mode * only should be used * @return the defaultBlurBackgroundRadius */ public static float getDefaultBlurBackgroundRadius() { return defaultBlurBackgroundRadius; } /** * Dialog background can be blurred using a Gaussian blur effect, this sets the radius of the Gaussian * blur. -1 is a special case value that indicates that no blurring should take effect and the default tint mode * only should be used. Notice that this value can be set using the theme constant: {@code dialogBlurRadiusInt} * @param aDefaultBlurBackgroundRadius the defaultBlurBackgroundRadius to set */ public static void setDefaultBlurBackgroundRadius(float aDefaultBlurBackgroundRadius) { defaultBlurBackgroundRadius = aDefaultBlurBackgroundRadius; } /** * In case of a blur effect we need to do something different... * {@inheritDoc} */ void initDialogBgPainter(Painter p, Form previousForm) { if(getBlurBackgroundRadius() > 0 && Display.impl.isGaussianBlurSupported()) { Image img = Image.createImage(previousForm.getWidth(), previousForm.getHeight()); Graphics g = img.getGraphics(); previousForm.paintComponent(g, true); img = Display.getInstance().gaussianBlurImage(img, blurBackgroundRadius); getUnselectedStyle().setBgImage(img); getUnselectedStyle().setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FILL); } else { super.initDialogBgPainter(p, previousForm); } } }