From ce878bef710c6d1e6881949c82b1293fb8435715 Mon Sep 17 00:00:00 2001 From: Scott Main <> Date: Sun, 26 Apr 2009 15:51:58 -0700 Subject: [PATCH] AI 147804: add new doc about Dialogs BUG=1800118 Automated import of CL 147804 --- docs/html/guide/topics/ui/dialogs.jd | 650 ++++++++++++++++++ docs/html/images/dialog_buttons.png | Bin 0 -> 3701 bytes docs/html/images/dialog_custom.png | Bin 0 -> 4018 bytes docs/html/images/dialog_list.png | Bin 0 -> 3830 bytes docs/html/images/dialog_progress_bar.png | Bin 0 -> 2562 bytes docs/html/images/dialog_progress_spinning.png | Bin 0 -> 2648 bytes docs/html/images/dialog_singlechoicelist.png | Bin 0 -> 5071 bytes 7 files changed, 650 insertions(+) create mode 100644 docs/html/guide/topics/ui/dialogs.jd create mode 100755 docs/html/images/dialog_buttons.png create mode 100755 docs/html/images/dialog_custom.png create mode 100755 docs/html/images/dialog_list.png create mode 100755 docs/html/images/dialog_progress_bar.png create mode 100755 docs/html/images/dialog_progress_spinning.png create mode 100755 docs/html/images/dialog_singlechoicelist.png diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd new file mode 100644 index 0000000000000..c0c0b1bc58da4 --- /dev/null +++ b/docs/html/guide/topics/ui/dialogs.jd @@ -0,0 +1,650 @@ +page.title=Creating Dialogs +parent.title=User Interface +parent.link=index.html +@jd:body + +
+
+

Key classes

+
    +
  1. {@link android.app.Dialog}
  2. +
+

In this document

+
    +
  1. Showing a Dialog
  2. +
  3. Dismissing a Dialog
  4. +
  5. Creating an AlertDialog +
      +
    1. Adding buttons
    2. +
    3. Adding a list
    4. +
    +
  6. +
  7. Creating a ProgressDialog +
      +
    1. Showing a progress bar
    2. +
    +
  8. +
  9. Creating a Custom Dialog
  10. +
+
+
+ +

A dialog is usually a small window that appears in front of the current Activity. +The underlying Activity loses focus and the dialog accepts all user interaction. +Dialogs are normally used +for notifications and short activities that directly relate to the application in progress.

+ +

The Android API supports the following types of {@link android.app.Dialog} objects:

+
+
{@link android.app.AlertDialog}
+
A dialog that can manage zero, one, two, or three buttons, and/or a list of + selectable items that can include checkboxes or radio buttons. The AlertDialog + is capable of constructing most dialog user interfaces and is the suggested dialog type. + See Creating an AlertDialog below.
+
{@link android.app.ProgressDialog}
+
A dialog that displays a progress wheel or progress bar. Because it's an extension of + the AlertDialog, it also supports buttons. + See Creating a ProgressDialog below.
+
{@link android.app.DatePickerDialog}
+
A dialog that allows the user to select a date. See the + Hello DatePicker tutorial.
+
{@link android.app.TimePickerDialog}
+
A dialog that allows the user to select a time. See the + Hello TimePicker tutorial.
+
+ +

If you would like to customize your own dialog, you can extend the +base {@link android.app.Dialog} object or any of the subclasses listed above and define a new layout. +See the section on Creating a Custom Dialog below.

+ + +

Showing a Dialog

+ +

A dialog is always created and displayed as a part of an {@link android.app.Activity}. +You should normally create dialogs from within your Activity's +{@link android.app.Activity#onCreateDialog(int)} callback method. +When you use this callback, the Android system automatically manages the state of +each dialog and hooks them to the Activity, effectively making it the "owner" of each dialog. +As such, each dialog inherits certain properties from the Activity. For example, when a dialog +is open, the Menu key reveals the options menu defined for the Activity and the volume +keys modify the audio stream used by the Activity.

+ +

Note: If you decide to create a dialog outside of the +onCreateDialog() method, it will not be attached to an Activity. You can, however, +attach it to an Activity with {@link android.app.Dialog#setOwnerActivity(Activity)}.

+ +

When you want to show a dialog, call +{@link android.app.Activity#showDialog(int)} and pass it an integer that uniquely identifies the +dialog that you want to display.

+ +

When a dialog is requested for the first time, Android calls +{@link android.app.Activity#onCreateDialog(int)} from your Activity, which is +where you should instantiate the {@link android.app.Dialog}. This callback method +is passed the same ID that you passed to {@link android.app.Activity#showDialog(int)}. +After you create the Dialog, return the object at the end of the method.

+ +

Before the dialog is displayed, Android also calls the optional callback method +{@link android.app.Activity#onPrepareDialog(int,Dialog)}. Define this method if you want to change +any properties of the dialog each time it is opened. This method is called +every time a dialog is opened, whereas {@link android.app.Activity#onCreateDialog(int)} is only +called the very first time a dialog is opened. If you don't define +{@link android.app.Activity#onPrepareDialog(int,Dialog) onPrepareDialog()}, then the dialog will +remain the same as it was the previous time it was opened. This method is also passed the dialog's +ID, along with the Dialog object you created in {@link android.app.Activity#onCreateDialog(int) +onCreateDialog()}.

+ +

The best way to define the {@link android.app.Activity#onCreateDialog(int)} and +{@link android.app.Activity#onPrepareDialog(int,Dialog)} callback methods is with a +switch statement that checks the id parameter that's passed into the method. +Each case should check for a unique dialog ID and then create and define the respective Dialog. +For example, imagine a game that uses two different dialogs: one to indicate that the game +has paused and another to indicate that the game is over. First, define an integer ID for +each dialog:

+
+static final int DIALOG_PAUSED_ID = 0;
+static final int DIALOG_GAMEOVER_ID = 1;
+
+ +

Then, define the {@link android.app.Activity#onCreateDialog(int)} callback with a +switch case for each ID:

+
+protected Dialog onCreateDialog(int id) {
+    Dialog dialog;
+    switch(id) {
+    case DIALOG_PAUSED_ID:
+        // do the work to define the pause Dialog
+        break;
+    case DIALOG_GAMEOVER_ID:
+        // do the work to define the game over Dialog
+        break;
+    default:
+        dialog = null;
+    }
+    return dialog;
+}
+
+ +

Note: In this example, there's no code inside +the case statements because the procedure for defining your Dialog is outside the scope +of this section. See the section below about Creating an AlertDialog, +offers code suitable for this example.

+ +

When it's time to show one of the dialogs, call {@link android.app.Activity#showDialog(int)} +with the ID of a dialog:

+
+showDialog(DIALOG_PAUSED_ID);
+
+ + +

Dismissing a Dialog

+ +

When you're ready to close your dialog, you can dismiss it by calling +{@link android.app.Dialog#dismiss()} on the Dialog object. +If necessary, you can also call {@link android.app.Activity#dismissDialog(int)} from the +Activity, which effectively calls {@link android.app.Dialog#dismiss()} on the +Dialog for you.

+ +

If you are using {@link android.app.Activity#onCreateDialog(int)} to manage the state +of your dialogs (as discussed in the previous section), then every time your dialog is +dismissed, the state of the Dialog +object is retained by the Activity. If you decide that you will no longer need this object or +it's important that the state is cleared, then you should call +{@link android.app.Activity#removeDialog(int)}. This will remove any internal references +to the object and if the dialog is showing, it will dismiss it.

+ +

Using dismiss listeners

+ +

If you'd like your applcation to perform some procedures the moment that a dialog is dismissed, +then you should attach an on-dismiss listener to your Dialog.

+ +

First define the {@link android.content.DialogInterface.OnDismissListener} interface. +This interface has just one method, +{@link android.content.DialogInterface.OnDismissListener#onDismiss(DialogInterface)}, which +will be called when the dialog is dismissed. +Then simply pass your OnDismissListener implementation to +{@link android.app.Dialog#setOnDismissListener(DialogInterface.OnDismissListener) +setOnDismissListener()}.

+ +

However, note that dialogs can also be "cancelled." This is a special case that indicates +the dialog was explicitly cancelled by the user. This will occur if the user presses the +"back" button to close the dialog, or if the dialog explicitly calls {@link android.app.Dialog#cancel()} +(perhaps from a "Cancel" button in the dialog). When a dialog is cancelled, +the OnDismissListener will still be notified, but if you'd like to be informed that the dialog +was explicitly cancelled (and not dismissed normally), then you should register +an {@link android.content.DialogInterface.OnCancelListener} with +{@link android.app.Dialog#setOnCancelListener(DialogInterface.OnCancelListener) +setOnCancelListener()}.

+ + +

Creating an AlertDialog

+ +

An {@link android.app.AlertDialog} is an extension of the {@link android.app.Dialog} +class. It is capable of constructing most dialog user interfaces and is the suggested dialog type. +You should use it for dialogs that use any of the following features:

+ + +

To create an AlertDialog, use the {@link android.app.AlertDialog.Builder} subclass. +Get a Builder with {@link android.app.AlertDialog.Builder#AlertDialog.Builder(Context)} and +then use the class's public methods to define all of the +AlertDialog properties. After you're done with the Builder, retrieve the +AlertDialog object with {@link android.app.AlertDialog.Builder#create()}.

+ +

The following topics show how to define various properties of the AlertDialog using the +AlertDialog.Builder class. If you use any of the following sample code inside your +{@link android.app.Activity#onCreateDialog(int) onCreateDialog()} callback method, +you can return the resulting Dialog object to display the dialog.

+ + +

Adding buttons

+ + + +

To create an AlertDialog with side-by-side buttons like the one shown in the screenshot to the right, +use the set...Button() methods:

+ +
+AlertDialog.Builder builder = new AlertDialog.Builder(this);
+builder.setMessage("Are you sure you want to exit?")
+       .setCancelable(false)
+       .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
+           public void onClick(DialogInterface dialog, int id) {
+                MyActivity.this.finish();
+           }
+       })
+       .setNegativeButton("No", new DialogInterface.OnClickListener() {
+           public void onClick(DialogInterface dialog, int id) {
+                dialog.cancel();
+           }
+       });
+AlertDialog alert = builder.create();
+
+ +

First, add a message for the dialog with +{@link android.app.AlertDialog.Builder#setMessage(CharSequence)}. Then, begin +method-chaining and set the dialog +to be not cancelable (so the user cannot close the dialog with the back button) +with {@link android.app.AlertDialog.Builder#setCancelable(boolean)}. For each button, +use one of the set...Button() methods, such as +{@link android.app.AlertDialog.Builder#setPositiveButton(CharSequence,DialogInterface.OnClickListener) +setPositiveButton()}, that accepts the name for the button and a +{@link android.content.DialogInterface.OnClickListener} that defines the action to take +when the user selects the button.

+ +

Note: You can only add one of each button type to the +AlertDialog. That is, you cannot have more than one "positive" button. This limits the number +of possible buttons to three: positive, neutral, and negative. These names are technically irrelevant to the +actual functionality of your buttons, but should help you keep track of which one does what.

+ + +

Adding a list

+ + + +

To create an AlertDialog with a list of selectable items like the one shown to the right, +use the setItems() method:

+ +
+final CharSequence[] items = {"Red", "Green", "Blue"};
+
+AlertDialog.Builder builder = new AlertDialog.Builder(this);
+builder.setTitle("Pick a color");
+builder.setItems(items, new DialogInterface.OnClickListener() {
+    public void onClick(DialogInterface dialog, int item) {
+        Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show();
+    }
+});
+AlertDialog alert = builder.create();
+
+ +

First, add a title to the dialog with +{@link android.app.AlertDialog.Builder#setTitle(CharSequence)}. +Then, add a list of selectable items with +{@link android.app.AlertDialog.Builder#setItems(CharSequence[],DialogInterface.OnClickListener) +setItems()}, which accepts the array of items to display and a +{@link android.content.DialogInterface.OnClickListener} that defines the action to take +when the user selects an item.

+ + +

Adding checkboxes and radio buttons

+ + + +

To create a list of multiple-choice items (checkboxes) or +single-choice items (radio buttons) inside the dialog, use the +{@link android.app.AlertDialog.Builder#setMultiChoiceItems(Cursor,String,String, +DialogInterface.OnMultiChoiceClickListener) setMultiChoiceItems()} and +{@link android.app.AlertDialog.Builder#setSingleChoiceItems(int,int,DialogInterface.OnClickListener) +setSingleChoiceItems()} methods, respectively. +If you create one of these selectable lists in the +{@link android.app.Activity#onCreateDialog(int) onCreateDialog()} callback method, +Android manages the state of the list for you. As long as the Activity is active, +the dialog remembers the items that were previously selected, but when the user exits the +Activity, the selection is lost. + +

Note: To save the selection when the user leaves or +pauses the Activity, you must properly save and restore the setting throughout +the Activity Lifecycle. +To permanently save the selections, even when the Activity process is completely shutdown, +you need to save the settings +with one of the Data +Storage techniques.

+ +

To create an AlertDialog with a list of single-choice items like the one shown to the right, +use the same code from the previous example, but replace the setItems() method with +{@link android.app.AlertDialog.Builder#setSingleChoiceItems(int,int,DialogInterface.OnClickListener) +setSingleChoiceItems()}:

+ +
+final CharSequence[] items = {"Red", "Green", "Blue"};
+
+AlertDialog.Builder builder = new AlertDialog.Builder(this);
+builder.setTitle("Pick a color");
+builder.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
+    public void onClick(DialogInterface dialog, int item) {
+        Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show();
+    }
+});
+AlertDialog alert = builder.create();
+
+ +

The second parameter in the +{@link android.app.AlertDialog.Builder#setSingleChoiceItems(CharSequence[],int,DialogInterface.OnClickListener) +setSingleChoiceItems()} method is an integer value for the checkedItem, which indicates the +zero-based list position of the default selected item. Use "-1" to indicate that no item should be +selected by default.

+ + +

Creating a ProgressDialog

+ + + +

A {@link android.app.ProgressDialog} is an extension of the {@link android.app.AlertDialog} +class that can display a progress animation in the form of a spinning wheel, for a task with +progress that's undefined, or a progress bar, for a task that has a defined progression. +The dialog can also provide buttons, such as one to cancel a download.

+ +

Opening a progress dialog can be as simple as calling +{@link android.app.ProgressDialog#show(Context,CharSequence,CharSequence) +ProgressDialog.show()}. For example, the progress dialog shown to the right can be +easily achieved without managing the dialog through the +{@link android.app.Activity#onCreateDialog(int)} callback, +as shown here:

+ +
+ProgressDialog dialog = ProgressDialog.show(MyActivity.this, "", 
+                        "Loading. Please wait...", true);
+
+ +

The first parameter is the application {@link android.content.Context}, +the second is a title for the dialog (left empty), the third is the message, +and the last parameter is whether the progress +is indeterminate (this is only relevant when creating a progress bar, which is +discussed in the next section). +

+ +

The default style of a progress dialog is the spinning wheel. +If you want to create a progress bar that shows the loading progress with granularity, +some more code is required, as discussed in the next section.

+ + +

Showing a progress bar

+ + + +

To show the progression with an animated progress bar:

+ +
    +
  1. Initialize the + ProgressDialog with the class constructor, + {@link android.app.ProgressDialog#ProgressDialog(Context)}.
  2. +
  3. Set the progress style to "STYLE_HORIZONTAL" with + {@link android.app.ProgressDialog#setProgressStyle(int)} and + set any other properties, such as the message.
  4. +
  5. When you're ready to show the dialog, call + {@link android.app.Dialog#show()} or return the ProgressDialog from the + {@link android.app.Activity#onCreateDialog(int)} callback.
  6. +
  7. You can increment the amount of progress displayed + in the bar by calling either {@link android.app.ProgressDialog#setProgress(int)} with a value for + the total percentage completed so far or {@link android.app.ProgressDialog#incrementProgressBy(int)} + with an incremental value to add to the total percentage completed so far.
  8. +
+ +

For example, your setup might look like this:

+
+ProgressDialog progressDialog;
+progressDialog = new ProgressDialog(mContext);
+progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+progressDialog.setMessage("Loading...");
+progressDialog.setCancelable(false);
+
+ +

The setup is simple. Most of the code needed to create a progress dialog is actually +involved in the process that updates it. You might find that it's +necessary to create a second thread in your application for this work and then report the progress +back to the Activity's UI thread with a {@link android.os.Handler} object. +If you're not familiar with using additional +threads with a Handler, see the example Activity below that uses a second thread to +increment a progress dialog managed by the Activity.

+ + + + +
+ + + Example ProgressDialog with a second thread +
+

This example uses a second thread to track the progress of a process (which actually just +counts up to 100). The thread sends a {@link android.os.Message} back to the main +Activity through a {@link android.os.Handler} each time progress is made. The main Activity then updates the +ProgressDialog.

+ +
+package com.example.progressdialog;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+
+public class NotificationTest extends Activity {
+    static final int PROGRESS_DIALOG = 0;
+    Button button;
+    ProgressThread progressThread;
+    ProgressDialog progressDialog;
+   
+    /** Called when the activity is first created. */
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+
+        // Setup the button that starts the progress dialog
+        button = (Button) findViewById(R.id.progressDialog);
+        button.setOnClickListener(new OnClickListener(){
+            public void onClick(View v) {
+                showDialog(PROGRESS_DIALOG);
+            }
+        }); 
+    }
+   
+    protected Dialog onCreateDialog(int id) {
+        switch(id) {
+        case PROGRESS_DIALOG:
+            progressDialog = new ProgressDialog(NotificationTest.this);
+            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+            progressDialog.setMessage("Loading...");
+            progressThread = new ProgressThread(handler);
+            progressThread.start();
+            return progressDialog;
+        default:
+            return null;
+        }
+    }
+
+    // Define the Handler that receives messages from the thread and update the progress
+    final Handler handler = new Handler() {
+        public void handleMessage(Message msg) {
+            int total = msg.getData().getInt("total");
+            progressDialog.setProgress(total);
+            if (total >= 100){
+                dismissDialog(PROGRESS_DIALOG);
+                progressThread.setState(ProgressThread.STATE_DONE);
+            }
+        }
+    };
+
+    /** Nested class that performs progress calculations (counting) */
+    private class ProgressThread extends Thread {
+        Handler mHandler;
+        final static int STATE_DONE = 0;
+        final static int STATE_RUNNING = 1;
+        int mState;
+        int total;
+       
+        ProgressThread(Handler h) {
+            mHandler = h;
+        }
+       
+        public void run() {
+            mState = STATE_RUNNING;   
+            total = 0;
+            while (mState == STATE_RUNNING) {
+                try {
+                    Thread.sleep(100);
+                } catch (InterruptedException e) {
+                    Log.e("ERROR", "Thread Interrupted");
+                }
+                Message msg = mHandler.obtainMessage();
+                Bundle b = new Bundle();
+                b.putInt("total", total);
+                msg.setData(b);
+                mHandler.sendMessage(msg);
+                total++;
+            }
+        }
+        
+        /* sets the current state for the thread,
+         * used to stop the thread */
+        public void setState(int state) {
+            mState = state;
+        }
+    }
+}
+
+
+
+ + + +

Creating a Custom Dialog

+ + + +

If you want a customized design for a dialog, you can create your own layout +for the dialog window with layout and widget elements. +After you've defined your layout, pass the root View object or +layout resource ID to {@link android.app.Dialog#setContentView(View)}.

+ +

For example, to create the dialog shown to the right:

+ +
    +
  1. Create an XML layout saved as custom_dialog.xml: +
    +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    +              android:id="@+id/layout_root"
    +              android:orientation="horizontal"
    +              android:layout_width="fill_parent"
    +              android:layout_height="fill_parent"
    +              android:padding="10dp"
    +              >
    +    <ImageView android:id="@+id/image"
    +               android:layout_width="wrap_content"
    +               android:layout_height="fill_parent"
    +               android:layout_marginRight="10dp"
    +               />
    +    <TextView android:id="@+id/text"
    +              android:layout_width="wrap_content"
    +              android:layout_height="fill_parent"
    +              android:textColor="#FFF"
    +              />
    +</LinearLayout>
    +
    + +

    This XML defines an {@link android.widget.ImageView} and a {@link android.widget.TextView} + inside a {@link android.widget.LinearLayout}.

    +
  2. Set the above layout as the dialog's content view and define the content + for the ImageView and TextView elements:

    +
    +Context mContext = getApplicationContext();
    +Dialog dialog = new Dialog(mContext);
    +
    +dialog.setContentView(R.layout.custom_dialog);
    +dialog.setTitle("Custom Dialog");
    +
    +TextView text = (TextView) dialog.findViewById(R.id.text);
    +text.setText("Hello, this is a custom dialog!");
    +ImageView image = (ImageView) dialog.findViewById(R.id.image);
    +image.setImageResource(R.drawable.android);
    +
    + +

    After you instantiate the Dialog, set your custom layout as the dialog's content view with + {@link android.app.Dialog#setContentView(int)}, passing it the layout resource ID. + Now that the Dialog has a defined layout, you can capture View objects from the layout with + {@link android.app.Dialog#findViewById(int)} and modify their content.

    +
  3. + +
  4. That's it. You can now show the dialog as described in + Showing A Dialog.
  5. +
+ +

A dialog made with the base Dialog class must have a title. If you don't call +{@link android.app.Dialog#setTitle(CharSequence) setTitle()}, then the space used for the title +remains empty, but still visible. If you don't want +a title at all, then you should create your custom dialog using the +{@link android.app.AlertDialog} class. However, because an AlertDialog is created easiest with +the {@link android.app.AlertDialog.Builder} class, you do not have access to the +{@link android.app.Dialog#setContentView(int)} method used above. Instead, you must use +{@link android.app.AlertDialog.Builder#setView(View)}. This method accepts a {@link android.view.View} object, +so you need to inflate the layout's root View object from +XML.

+ +

To inflate the XML layout, retrieve the {@link android.view.LayoutInflater} with +{@link android.app.Activity#getLayoutInflater()} +(or {@link android.content.Context#getSystemService(String) getSystemService()}), +and then call +{@link android.view.LayoutInflater#inflate(int, ViewGroup)}, where the first parameter +is the layout resource ID and the second is the ID of the root View. At this point, you can use +the inflated layout to find View objects in the layout and define the content for the +ImageView and TextView elements. Then instantiate the AlertDialog.Builder and set the +inflated layout for the dialog with {@link android.app.AlertDialog.Builder#setView(View)}.

+ +

Here's an example, creating a custom layout in an AlertDialog:

+ +
+AlertDialog.Builder builder;
+AlertDialog alertDialog;
+
+Context mContext = getApplicationContext();
+LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER);
+View layout = inflater.inflate(R.layout.custom_dialog,
+                               (ViewGroup) findViewById(R.id.layout_root));
+
+TextView text = (TextView) layout.findViewById(R.id.text);
+text.setText("Hello, this is a custom dialog!");
+ImageView image = (ImageView) layout.findViewById(R.id.image);
+image.setImageResource(R.drawable.android);
+
+builder = new AlertDialog.Builder(mContext);
+builder.setView(layout);
+alertDialog = builder.create();
+
+ +

Using an AlertDialog for your custom layout lets you +take advantage of built-in AlertDialog features like managed buttons, +selectable lists, a title, an icon and so on.

+ +

For more information, refer to the reference documentation for the +{@link android.app.Dialog} and {@link android.app.AlertDialog.Builder} +classes.

+ + + diff --git a/docs/html/images/dialog_buttons.png b/docs/html/images/dialog_buttons.png new file mode 100755 index 0000000000000000000000000000000000000000..81aaec4a6ce5a1be77f29a10d09eacea938b1fde GIT binary patch literal 3701 zcmV-*4vO)KP)!nwJ*_44&ZM@0Yo|2R81(9qDXuCDIt?%dnlLPSFR{QQA|fd&W$Iy^dDU0jNa zij|a=WMyPjR#ev3*5>Bs2@472Q-1*0R;g{OiHV)t65oDq@<)_VqvGKr)X+u)zsBu zWMZVEq&z-6-rU}*s;WRjK*h$zT3lM=;^QkWD^5^O=H%v_oSfO$*$NB_(9Y20;^flO z(%ISB$H>Rt-rhz@M!>{tHtgfup($z9GGU(~( zpr4?fo}Jg!*Do?JnwpwkU|#t4_)=6-%F4>d#Kye5yxiQ}n3es*_us;H_K78V;F z8*6N9zP`Tp^7hiu((mu@x45^Kl$I?pEw8Mv+S}UO*xS6jyr`$BoSvM6goDP$#w;!@ zC@d(rwYY$Pfa~k)prW8CDkz|ypu)kzo}HewwzT~E{Ca$P_4M`f@A9IcqMDhSmX?;j zyuQG{z;kqSE-^0P;oy~*m4=6gla!MxEh-io7IboSHa9jA6A`blujAz7$;!$3`1$ws z_o=C=H8(Zx?CyMjeAU*~`1JVy{Qnpi7{S895fu?MH#GP6_xAVp{r&x@si>%^sGOUe zz{0?Ne|_!i?Y6bH{`~%skC1+Se&68V3kwV7<>mPJ_{_}A&dts=HZ<<-?#s)|XJ==5 zd3lVCjNRVd_V)I!u&zZ%MSXsK$jZp~`1i!a#5gxNU|(Q0IW-_3Ak)*+o1B|$Y;3!{ zyYKMt!^FdxmYMhS_obz!9UvWhdwYwEi)3SD4-^lnsHyGg?e6LB|NZ~h*w^>=_m`NL zz{9{87#IWy1UWo800030|NjgO3~nK+`Tzh63rR#lRCwC#oDEzP=N-op2&L&I;~)W( z5F&&alj9&n-a-#z2-ElqR8Cm0xHF?5vDR9OibIN1iB(5Usjk?y)(I=6wpvGN*OySS z#TJFOsc2iac6H8fEiK(!x0&PIa|b#_!b^L#3!nV>B>6md&-42~-#pL%xg+GkFZSY; zP^@3|r759mzl&1?@{j3vmZD+=oWR41aS}c2R9*<_XslA$t;P(lj|~wMGim&ac0V! zMEV!JnkW)krU1yXR}`A?!k552_nB5L_Qh_1l`anf6dGFy(YxWIS7YFf^?4y zf{AY=2Q=oJhYqYk0RyDuE1e@p#4-}(+8j9tEB@339B?N>;ZBqdz&xWkC^{huM=1&! zTIEo1dbo%qh?9a)C(ayajzK6>MA&u^>jG*)PF##2;5ev&pF_ZDr)oV8D%ngC1WvKX zSpz06iZBjOMUblXwq9Arjtj)(Kx{LP3Y3Ugj}_~kN}Y(4#>4ri#)jLyuZ0` z%i*lE#*%q=*SRPh`>~%LmW9EqLlntmm`vOx%qJjLhoQ}j9_6v2z<6{{A#caxQHrT4_| z)R!w{A<^J%Kc{En&ivbIvtI@rJQq~?*whjmW_SjgOtL#Q3Tx(J5?17D(bUbzFC$e> ziVQq$?mdFF-UsXA)4pVS{w4uI_7CqvR5;7^rX%9*MzJ)iS1BkWDTx1mdF8#+wF!;l zYIO?A9JS9WLI0dF8(e)^&3I6V5vRxwCa&K2 z_4-8>j#9OmsX|yY!fcaTwMf5&q^?ykoUzfod%kQ|X}i@%xui=p%QrX#0}k7#dzc}} zV@ITX!H=YlI=1NOS}1nZe6VfSsZtVn#AIq$>e3cK_ViOpw*!zU0D{8`NpRU}Ylu!? zmMq(5?wT*Q?`w5T|2@UzNb5ek?nI7R^XoK%Y8r}L=}#XfiJfYu3ZdT-L5#cnUY#Ql za$kZ$c66FJWClSB9;!MS%?J5Q<{nsGRk>xLg$P!kG$1W^fe``GrH3P}Lq$i|Y0B>Z zc>PZ+!kKPK3=!{`%NI~&$`X@dW2H16fI!g44TaL1_TMHJJd{=nKnf{xTWU+~Y6!F- zV)7XfyXI64K@G>e+i|&pz^2vo_!OxrO zLv>)yAOo{@+V}jhRlhaOTo`NyEf|nM0}Ogd?D`L$b7UjgnbilT78@7QDw+*pdrQ?0 zP{k$nQ;rXE_0(!wdYT}}^oJ!O6$Gl;q6pauGfOBOpJzXpJ>Rf0A2YslsxV{LJrGXy z?-1;;Vr1?|xVPOhE5&n-qr>aogrl<$ahvFJ%l{nV)Xn(~shbJtQRy-<2Cv|1VHOztw znfOvZSjpj(bQRmwr~pHb!s%8FLHOw=Z8meU)uu>P!$m|ZWu~Q6Vlsj=$le1bC@zP&)ze%!t z35YL8d?4RdvUfNTZ_@4>PdRcJ=X;Z|s?gCv7H9R(_9mtNrG50NwK%Io$cW1i|34I7 z7RP^70Lq;6nkSG{q42KRnH{a1sUtIUm?I{RL)+H47+@K9Z@XuZ%(E8`ReZ^rrZrxe zrWOkGTKz6WpW)QDepg=Hy{~!7k>kRy@Y&}LvKP6M;e1K?p_rKMekuDF8eZhkc60Bv z?X7b>gTx#%(Hv{JcIoz*ul%{Tt&?tQo#T0G@gyp)BmNs&KAR^^=i2s5zS=X$5nlf% zMy?|U&U`&itxDqBHX18R^|)#s;U#~9aUC(pz9LnvmvU`eE?&+X9udoEAmI?#5zp>@ zJyosMaBW+I6!APJI{-1cxQ-Z62|#iDf4L~g45QMH-w6l)R zlx(BpH`ct*9mo=`m0sCMKTv*h>kR^VaK@RQ(lr^@_<_KL0Pd#NqNgf^@l_wC%+HU$ zF;j~U{i=c#Bc(o)pNaIilM=0TV+MO`mGm zOus)jcmlVnU(8KSHujBQ@#e1!=#>xB%i`Xg$f}jHd+cPF?xk-TS2WE$Xy)-dBuNx>}F0y&!`3Rb*s*!VkF6KN1oWBLC(8*M`(&oP3Nk+rKlm?W)*4V@<7H znx_K-wg!CuTaNVkpXtVD0SH8fa%uas09q5P=8g5?gEjH9fSPu@qsz|6-lIP5`IE-u{b8|#)zvRozs!-UU+#8Wm(NyLT}hP58tFw;p`m9llJkOz=;_#qbw=bRU-}elcw$Fg)^)n!9OxX3_d)4qad9tgq{8=tx~>u#EhcDGMT{ABkJKf5nrv(>YUZZCS%o zUdOKFqOt?iIn;r&U#O37cr<9xJz_+dZ(=9P)&G3Brzf)K2$zbC?1^N>sV(sAx#Q@& zUnIImd=vYU-0gNJinLGU=Du>%g!Re<^u`-+x@sc~vu<5hqUitq=So*aBlnM7x+J=a#Cs&NSgzYFCKq`l$7s9WQYeD*rk2zXA*ZBJc{o TLC4V$00000NkvXXu0mjf$tp_F literal 0 HcmV?d00001 diff --git a/docs/html/images/dialog_custom.png b/docs/html/images/dialog_custom.png new file mode 100755 index 0000000000000000000000000000000000000000..b2523fd5c8922c5a4562adc7e6ebf05a6acda21d GIT binary patch literal 4018 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 Y02UjTkRUU2&j0`b07*qoM6N<$f@#0=`Tzg` literal 0 HcmV?d00001 diff --git a/docs/html/images/dialog_list.png b/docs/html/images/dialog_list.png new file mode 100755 index 0000000000000000000000000000000000000000..f2736bf4218dfdb39b5edbe7bf8d0ac068b182a8 GIT binary patch literal 3830 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 literal 0 HcmV?d00001 diff --git a/docs/html/images/dialog_progress_bar.png b/docs/html/images/dialog_progress_bar.png new file mode 100755 index 0000000000000000000000000000000000000000..3e74419f8976b5aedcbde75b5d17d264e8ec1fd7 GIT binary patch literal 2562 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 literal 0 HcmV?d00001