1.. currentmodule:: dialog 2 3:class:`Dialog` class overview 4============================== 5 6Initializing a :class:`Dialog` instance 7--------------------------------------- 8 9Since all widgets in pythondialog are implemented as methods of the 10:class:`Dialog` class, a pythondialog-based application usually starts by 11creating a :class:`!Dialog` instance. 12 13.. autoclass:: Dialog 14 :members: __init__ 15 16.. _autowidgetsize: 17 18.. rubric:: About the *autowidgetsize* option 19 20The *autowidgetsize* option should be convenient in situations where figuring 21out suitable widget size parameters is a burden, for instance when developing 22little scripts that don't need too much visual polishing, when a widget is 23used to display data, the size of which is not easily predictable, or simply 24when one doesn't want to hardcode the widget size. 25 26This option is implemented in the following way: for a given size parameter 27(for instance, *width*) of a given widget, the default value in the 28widget-producing method is now ``None`` if it previously had a non-zero 29default. At runtime, if the value seen by the widget-producing method is not 30``None``, it is used as is; on the contrary, if that value is ``None``, it is 31automatically replaced with: 32 33 - ``0`` if the :class:`Dialog` instance has been initialized with 34 *autowidgetsize* set to ``True``; 35 - the old default otherwise, in order to preserve backward-comptability. 36 37.. note:: 38 39 - the *autowidgetsize* option is currently marked as experimental, please 40 give some feedback; 41 - you may encounter questionable results if you only set one of the *width* 42 and *height* parameters to ``0`` for a given widget (seen in 43 :program:`dialog` 1.2-20140219). 44 45.. warning:: 46 47 You should not explicitly pass ``None`` for a size parameter such as *width* 48 or *height*. If you want a fixed size, specify it directly (as an int); 49 otherwise, either use the *autowidgetsize* option or set the parameter to 50 ``0`` (e.g., ``width=0``). 51 52 53.. _passing-dialog-common-options: 54 55Passing :program:`dialog` "common options" 56------------------------------------------ 57 58Every widget method has a \*\*kwargs argument allowing you to pass 59:term:`common options <dialog common options>` (see the :manpage:`dialog(1)` 60manual page) to :program:`dialog` for this widget call. For instance, if *d* 61is a :class:`Dialog` instance, you can write:: 62 63 d.checklist(args, ..., title="A Great Title", no_shadow=True) 64 65The *no_shadow* option is worth looking at: 66 67 #. It is an option that takes no argument as far as :program:`dialog` is 68 concerned (unlike the :option:`--title` option, for instance). When you 69 list it as a keyword argument, the option is really passed to 70 :program:`dialog` only if the value you gave it evaluates to ``True`` in 71 a boolean context. For instance, ``no_shadow=True`` will cause 72 :option:`--no-shadow` to be passed to :program:`dialog` whereas 73 ``no_shadow=False`` will cause this option not to be passed to 74 :program:`dialog` at all. 75 76 #. It is an option that has a hyphen (``-``) in its name, which you must 77 change into an underscore (``_``) to pass it as a Python keyword 78 argument. Therefore, :option:`--no-shadow` is passed by giving a 79 ``no_shadow=True`` keyword argument to :class:`Dialog` methods (the 80 leading two dashes are also consistently removed). 81 82.. note:: 83 84 When :meth:`Dialog.__init__` is called with 85 :samp:`{pass_args_via_file}=True` (or without any explicit setting for this 86 option, and the pythondialog as well as :program:`dialog` versions are 87 recent enough so that the option is enabled by default), then the options 88 are not directly passed to :program:`dialog`. Instead, all options are 89 written to a temporary file which :program:`dialog` is pointed to via 90 :option:`--file`. This ensures better confidentiality with respect to other 91 users of the same computer. 92 93 94.. versionadded:: 2.14 95 Support for the *default_button* and *no_tags* common options. 96 97.. versionadded:: 3.0 98 Proper support for the *extra_button*, *item_help* and *help_status* common 99 options. 100 101 102Return value of widget-producing methods 103---------------------------------------- 104 105Most :class:`Dialog` methods that create a widget (actually: all methods that 106supervise the exit of a widget) return a value which fits into one of these 107categories: 108 109 #. The return value is a :term:`Dialog exit code` (see below). 110 111 #. The return value is a sequence whose first element is a Dialog exit code 112 (the rest of the sequence being related to what the user entered in the 113 widget). 114 115For instance, :meth:`Dialog.yesno` returns a single Dialog exit code that will 116typically be :attr:`Dialog.OK` or :attr:`Dialog.CANCEL`, depending on the 117button chosen by the user. However, :meth:`Dialog.checklist` returns a tuple 118of the form :samp:`({code}, [{tag}, ...])` whose first element is a Dialog 119exit code and second element lists all tags for the entries selected by the 120user. 121 122.. _Dialog-exit-code: 123 124"Dialog exit code" (high-level) 125^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 126 127A :dfn:`Dialog exit code`, or :dfn:`high-level exit code`, is a string 128indicating how/why a widget-producing method ended. Most widgets return one of 129the :term:`standard Dialog exit codes <standard Dialog exit code>`: ``"ok"``, 130``"cancel"``, ``"esc"``, ``"help"``, ``"extra"`` and ``"timeout"``, 131respectively available as :attr:`Dialog.OK`, :attr:`Dialog.CANCEL`, 132:attr:`Dialog.ESC`, :attr:`Dialog.HELP`, :attr:`Dialog.EXTRA` and 133:attr:`Dialog.TIMEOUT`, *i.e.,* attributes of the :class:`Dialog` class. 134However, some widgets may return additional, non-standard exit codes; for 135instance, the :meth:`~Dialog.inputmenu` widget may return ``"accepted"`` or 136``"renamed"`` in addition to the standard Dialog exit codes. 137 138When getting a Dialog exit code from a widget-producing method, user code 139should compare it with :attr:`Dialog.OK` and friends (or equivalently, with 140``"ok"`` and friends) using the ``==`` operator. This allows to easily replace 141:attr:`Dialog.OK` and friends with objects that compare the same with ``"ok"`` 142and ``u"ok"`` in Python 2, for instance. 143 144The following attributes of the :class:`Dialog` class hold the :term:`standard 145Dialog exit codes <standard Dialog exit code>`: 146 147.. autoattribute:: Dialog.OK 148 149.. autoattribute:: Dialog.CANCEL 150 151.. autoattribute:: Dialog.ESC 152 153.. autoattribute:: Dialog.EXTRA 154 155.. autoattribute:: Dialog.HELP 156 157.. autoattribute:: Dialog.TIMEOUT 158 159The following attributes are obsolete and should not be used in pythondialog 1603.0 and later: 161 162.. autoattribute:: Dialog.DIALOG_OK 163 164.. autoattribute:: Dialog.DIALOG_CANCEL 165 166.. autoattribute:: Dialog.DIALOG_ESC 167 168.. autoattribute:: Dialog.DIALOG_EXTRA 169 170.. autoattribute:: Dialog.DIALOG_HELP 171 172.. autoattribute:: Dialog.DIALOG_ITEM_HELP 173 174.. _dialog-exit-status: 175 176"dialog exit status" (low-level) 177^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 178 179When returning from a widget call, the :term:`Dialog exit code` is normally 180derived by pythondialog from an integer called :dfn:`dialog exit status`, or 181:dfn:`low-level exit code`. This integer is returned by the :program:`dialog` 182backend upon exit. The different possible values for the dialog exit status 183are referred to as ``DIALOG_OK``, ``DIALOG_CANCEL``, ``DIALOG_ESC``, 184``DIALOG_ERROR``, ``DIALOG_EXTRA``, ``DIALOG_HELP``, ``DIALOG_ITEM_HELP`` 185and ``DIALOG_TIMEOUT`` in the :manpage:`dialog(1)` manual page. 186 187.. note:: 188 189 - ``DIALOG_HELP`` and ``DIALOG_ITEM_HELP`` both map to :attr:`Dialog.HELP` 190 in pythondialog, because they both correspond to the same user action and 191 the difference brings no information that the caller does not already 192 have; 193 194 - ``DIALOG_ERROR`` has no counterpart as a :class:`Dialog` attribute, 195 because it is automatically translated into a :exc:`DialogError` exception 196 when received. 197 198In pythondialog 2.x, the low-level exit codes were available as the 199``DIALOG_OK``, ``DIALOG_CANCEL``, etc. attributes of :class:`Dialog` 200instances. For compatibility, the :class:`Dialog` class has attributes of the 201same names that are mapped to :attr:`Dialog.OK`, :attr:`Dialog.CANCEL`, etc., 202but their use is deprecated as of pythondialog 3.0. 203 204 205Adding an Extra button 206---------------------- 207 208With most widgets, it is possible to add a supplementary button called 209:dfn:`Extra button`. To do that, you simply have to use ``extra_button=True`` 210(keyword argument) in the widget call. By default, the button text is "Extra", 211but you can specify another string with the *extra_label* keyword argument. 212 213When the widget exits, you know if the :guilabel:`Extra` button was pressed if 214the :term:`Dialog exit code` is :attr:`Dialog.EXTRA` (``"extra"``). Normally, 215the rest of the return value is the same as if the widget had been closed with 216:guilabel:`OK`. Therefore, if the widget normally returns a list of three 217integers, for instance, you can expect to get the same information if 218:guilabel:`Extra` is pressed instead of :guilabel:`OK`. 219 220.. note:: 221 222 This feature can be particularly useful in combination with the *yes_label*, 223 *no_label*, *help_button* and *help_label* :term:`common options <dialog 224 common options>` to provide a completely different set of buttons than the 225 default for a given widget. 226 227 228Providing on-line help facilities 229--------------------------------- 230 231With most :program:`dialog` widgets, it is possible to provide online help to 232the final user. At the time of this writing (October 2014), there are three 233main options governing these help facilities in the :program:`dialog` backend: 234:option:`--help-button`, :option:`--item-help` and :option:`--help-status`. 235Since :program:`dialog` 1.2-20130902, there is also :option:`--help-tags` that 236modifies the way :option:`--item-help` works. As explained previously 237(:ref:`passing-dialog-common-options`), in order to use these options in 238pythondialog, you can pass the *help_button*, *item_help*, *help_status* and 239*help_tags* keyword arguments to :class:`Dialog` widget-producing methods. 240 241Adding a :guilabel:`Help` button 242^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 243In order to provide a :guilabel:`Help` button in addition to the normal 244buttons of a widget, you can pass ``help_button=True`` (keyword argument) to 245the corresponding :class:`Dialog` method. For instance, if *d* is a 246:class:`Dialog` instance, you can write:: 247 248 code = d.yesno("<text>", height=10, width=40, help_button=True) 249 250or:: 251 252 code, answer = d.inputbox("<text>", init="<init>", 253 help_button=True) 254 255When the method returns, the :term:`Dialog exit code` is :attr:`Dialog.HELP` 256(i.e., the string ``"help"``) if the user pressed the :guilabel:`Help` button. 257Apart from that, it works exactly as if ``help_button=True`` had not been 258used. In the last example, if the user presses the :guilabel:`Help` button, 259*answer* will contain the user input, just as if :guilabel:`OK` had been 260pressed. Similarly, if you write:: 261 262 code, t = d.checklist( 263 "<text>", height=0, width=0, list_height=0, 264 choices=[ ("Tag 1", "Item 1", False), 265 ("Tag 2", "Item 2", True), 266 ("Tag 3", "Item 3", True) ], 267 help_button=True) 268 269and find that ``code == Dialog.HELP``, then *t* contains the tag string for 270the highlighted item when the :guilabel:`Help` button was pressed. 271 272Finally, note that it is possible to choose the text written on the 273:guilabel:`Help` button by supplying a string as the *help_label* keyword 274argument. 275 276.. _providing-inline-per-item-help: 277 278Providing inline per-item help 279^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 280In addition to, or instead of the :guilabel:`Help` button, you can provide 281:dfn:`item-specific help` that is normally displayed at the bottom of the 282widget. This can be done by passing the ``item_help=True`` keyword argument to 283the widget-producing method and by including the item-specific help strings in 284the appropriate argument. 285 286For widgets where item-specific help makes sense (i.e., there are several 287elements that can be highlighted), there is usually a parameter, often called 288*elements*, *choices*, *nodes*..., that must be provided as an iterable 289describing the various lines/items/nodes/... that can be highlighted in the 290widget. When ``item_help=True`` is passed, every element of this iterable must 291be completed with a string which is the :dfn:`item-help string` of the element 292(using :manpage:`dialog(1)` terminology). For instance, the following call 293with no inline per-item help support:: 294 295 code, t = d.checklist( 296 "<text>", height=0, width=0, list_height=0, 297 choices=[ ("Tag 1", "Item 1", False), 298 ("Tag 2", "Item 2", True), 299 ("Tag 3", "Item 3", True) ], 300 help_button=True) 301 302can be altered this way to provide inline item-specific help:: 303 304 code, t = d.checklist( 305 "<text>", height=0, width=0, list_height=0, 306 choices=[ ("Tag 1", "Item 1", False, "Help 1"), 307 ("Tag 2", "Item 2", True, "Help 2"), 308 ("Tag 3", "Item 3", True, "Help 3") ], 309 help_button=True, item_help=True, help_tags=True) 310 311With this modification, the item-help string for the highlighted item is 312displayed in the bottom line of the screen and updated as the user highlights 313other items. 314 315If you don't want a :guilabel:`Help` button, just use ``item_help=True`` 316without ``help_button=True`` (*help_tags* doesn't matter in this case). Then, 317you have the inline help at the bottom of the screen, and the following 318discussion about the return value can be ignored. 319 320If the user chooses the :guilabel:`Help` button, *code* will be equal to 321:attr:`Dialog.HELP` (``"help"``) and *t* will contain the tag string 322corresponding to the highlighted item when the :guilabel:`Help` button was 323pressed (``"Tag 1/2/3"`` in the example). This is because of the *help_tags* 324option; without it (or with ``help_tags=False``), *t* would have contained the 325:term:`item-help string` of the highlighted choice (``"Help 1/2/3"`` in the 326example). 327 328If you remember what was said earlier, if ``item_help=True`` had not been used 329in the previous example, *t* would still contain the tag of the highlighted 330choice if the user closed the widget with the :guilabel:`Help` button. This is 331the same as when using ``item_help=True`` in combination with 332``help_tags=True``; however, you would get the :term:`item-help string` 333instead if *help_tags* were ``False`` (which is the default, as in the 334:program:`dialog` backend, and in order to preserve compatibility with the 335:meth:`Dialog.menu` implementation that is several years old). 336 337Therefore, I recommend for consistency to use ``help_tags=True`` whenever 338possible when specifying ``item_help=True``. This makes ``"--help-tags"`` a 339good candidate for use with :meth:`Dialog.add_persistent_args` to avoid 340repeating it over and over. However, there are two cases where 341``help_tags=True`` cannot be used: 342 343 - when the version of the :program:`dialog` backend is lower than 344 1.2-20130902 (the :option:`--help-tags` option was added in this version); 345 - when using empty or otherwise identical tags for presentation purposes 346 (unless you don't need to tell which element was highlighted when the 347 :guilabel:`Help` button was pressed, in which case it doesn't matter to be 348 unable to discriminate between the tags). 349 350Getting the widget status before the :guilabel:`Help` button was pressed 351^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 352Typically, when the user chooses :guilabel:`Help` in a widget, the application 353will display a dialog box such as :meth:`~Dialog.textbox`, 354:meth:`~Dialog.msgbox` or :meth:`~Dialog.scrollbox` and redisplay the original 355widget afterwards. For simple widgets such as :meth:`~Dialog.inputbox`, when 356the :term:`Dialog exit code` is equal to :attr:`Dialog.HELP`, the return value 357contains enough information to redisplay the widget in the same state it had 358when :guilabel:`Help` was chosen. However, for more complex widgets such as 359:meth:`~Dialog.radiolist` (resp. :meth:`~Dialog.checklist`, or 360:meth:`~Dialog.form` and its derivatives), knowing the highlighted item is not 361enough to restore the widget state after processing the help request: one 362needs to know the checked item (resp. list of checked items, or form contents). 363 364This is where the *help_status* keyword argument becomes useful. Example:: 365 366 code, t = d.checklist( 367 "<text>", height=0, width=0, list_height=0, 368 choices=[ ("Tag 1", "Item 1", False), 369 ("Tag 2", "Item 2", True), 370 ("Tag 3", "Item 3", True) ], 371 help_button=True, help_status=True) 372 373When :guilabel:`Help` is chosen, ``code == Dialog.HELP`` and *t* is a tuple of 374the form :samp:`({tag}, {selected_tags}, {choices})` where: 375 376 - *tag* gives the tag string of the highlighted item (which would be the 377 value of *t* if *help_status* were set to ``False``); 378 - *selected_tags* is the... list of selected tags (note that highlighting 379 and selecting an item are different things!); 380 - *choices* is a list built from the original *choices* argument of the 381 :meth:`~Dialog.checklist` call and from the list of selected tags, that 382 can be used as is to create a widget with the same items and selection 383 state as the original widget had when :guilabel:`Help` was chosen. 384 385Normally, pythondialog should always provide something similar to the last 386item in the previous example in order to make it as easy as possible to 387redisplay the widget in the appropriate state. To know precisely what is 388returned with ``help_status=True``, the best way is probably to experiment 389and/or read the code (by the way, there are many examples of widgets with 390various combinations of the *help_button*, *item_help* and *help_status* 391keyword arguments in the demo). 392 393.. note:: 394 395 The various options related to help support are not mutually exclusive; they 396 may be used together to provide good help support. 397 398It is also worth noting that the documentation of the various widget-producing 399methods is written, in most cases, under the assumption that the widget was 400closed "normally" (typically, with the :guilabel:`OK` or :guilabel:`Extra` 401button). For instance, a widget documentation may state that the method 402returns a tuple of the form :samp:`({code}, {tag})` where *tag* is ..., but 403actually, if using ``item_help=True`` with ``help_tags=False``, the *tag* may 404very well be an :term:`item-help string`, and if using ``help_status=True``, 405it is likely to be a structured object such as a tuple or list. Of course, 406handling all these possible variations for all widgets would be a tedious task 407and would probably significantly degrade the readability of said 408documentation. 409 410.. versionadded:: 3.0 411 Proper support for the *item_help* and *help_status* common options. 412 413 414Screen-related methods 415---------------------- 416 417Getting the terminal size: 418 419.. automethod:: Dialog.maxsize 420 421.. automethod:: Dialog.set_background_title 422 423Obsolete methods 424^^^^^^^^^^^^^^^^ 425 426.. automethod:: Dialog.setBackgroundTitle 427 428.. automethod:: Dialog.clear 429 430 431Checking the versions of pythondialog and its backend 432----------------------------------------------------- 433 434Version of pythondialog 435^^^^^^^^^^^^^^^^^^^^^^^ 436 437.. autoclass:: VersionInfo 438 :members: 439 :special-members: 440 441.. autodata:: version_info 442 :annotation: 443 444.. autodata:: __version__ 445 :annotation: 446 447 448Version of the backend 449^^^^^^^^^^^^^^^^^^^^^^ 450 451The :class:`Dialog` constructor retrieves the version string of the 452:program:`dialog` backend and stores it as an instance of a 453:class:`BackendVersion` subclass into the 454:attr:`Dialog.cached_backend_version` attribute. This allows doing things such 455as (*d* being a :class:`Dialog` instance):: 456 457 if d.compat == "dialog" and \ 458 d.cached_backend_version >= DialogBackendVersion("1.2-20130902"): 459 ... 460 461in a reliable way, allowing to fix the parsing and comparison algorithms right 462in the appropriate :class:`BackendVersion` subclass, should the 463:program:`dialog`-like backend versioning scheme change in unforeseen ways. 464 465As :program:`Xdialog` seems to be dead and not to support 466:option:`--print-version`, the :attr:`Dialog.cached_backend_version` attribute 467is set to ``None`` in :program:`Xdialog`-compatibility mode (2013-09-12). 468Should this ever change, one should define an :class:`XDialogBackendVersion` 469class to handle the particularities of the :program:`Xdialog` versioning 470scheme. 471 472.. attribute:: Dialog.cached_backend_version 473 474 Instance of a :class:`BackendVersion` subclass; it is initialized by the 475 :class:`Dialog` constructor and used to store the backend version, avoiding 476 the need to repeatedly call ``dialog --print-version`` or a similar 477 command, depending on the backend. 478 479 When using the :program:`dialog` backend, 480 :attr:`Dialog.cached_backend_version` is a :class:`DialogBackendVersion` 481 instance. 482 483.. automethod:: Dialog.backend_version 484 485 486Enabling debug facilities 487------------------------- 488 489.. automethod:: Dialog.setup_debug 490 491 492Miscellaneous methods 493--------------------- 494 495.. automethod:: Dialog.add_persistent_args 496 497.. note:: 498 499 When :meth:`Dialog.__init__` is called with 500 :samp:`{pass_args_via_file}=True` (or without any explicit setting for this 501 option, and the pythondialog as well as :program:`dialog` versions are 502 recent enough so that the option is enabled by default), then the arguments 503 are not directly passed to :program:`dialog`. Instead, all arguments are 504 written to a temporary file which :program:`dialog` is pointed to via 505 :option:`--file`. This ensures better confidentiality with respect to other 506 users of the same computer. 507 508.. automethod:: Dialog.dash_escape 509 510.. automethod:: Dialog.dash_escape_nf 511 512.. _examples-of-dash-escaping: 513 514A contrived example using these methods could be the following, which sets a 515weird background title starting with two dashes (``--My little program``) for 516the life duration of a :class:`Dialog` instance *d*:: 517 518 d.add_persistent_args(d.dash_escape_nf( 519 ["--backtitle", "--My little program"])) 520 521or, equivalently:: 522 523 d.add_persistent_args(["--backtitle"] 524 + d.dash_escape(["--My little program"])) 525