Create status dialog window to interrupt long-time operations.

Such dialog allows:
  * show status of operation;
  * control operation using dialog buttons (Abort, Suspend, Resume, etc).

Status dialog is raised after specified delay after operation start.
If operation duration is less than delay, the status dialog is not raised.

Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
This commit is contained in:
Andrew Borodin 2013-03-10 14:31:33 +04:00
parent 62faec3a61
commit 55e604901f
2 changed files with 184 additions and 0 deletions

View File

@ -56,6 +56,9 @@ static WDialog *last_query_dlg;
static int sel_pos = 0;
static const guint64 status_msg_delay_threshold = G_USEC_PER_SEC / 100; /* 0.01 s */
/* --------------------------------------------------------------------------------------------- */
/*** file scope functions ************************************************************************/
/* --------------------------------------------------------------------------------------------- */
@ -516,3 +519,153 @@ input_expand_dialog (const char *header, const char *text,
}
/* --------------------------------------------------------------------------------------------- */
/**
* Create status message window object and initialize it
*
* @param title window title
* @param delay initial delay to raise window in seconds
* @param init_cb callback to initialize user-defined part of status message
* @param update_cb callback to update of status message
* @param deinit_cb callback to deinitialize user-defined part of status message
*
* @return newly allocate status message window
*/
status_msg_t *
status_msg_create (const char *title, double delay, status_msg_cb init_cb,
status_msg_update_cb update_cb, status_msg_cb deinit_cb)
{
status_msg_t *sm;
sm = g_try_new (status_msg_t, 1);
status_msg_init (sm, title, delay, init_cb, update_cb, deinit_cb);
return sm;
}
/* --------------------------------------------------------------------------------------------- */
/**
* Destroy status message window object
*
* @param sm status message window object
*/
void
status_msg_destroy (status_msg_t * sm)
{
status_msg_deinit (sm);
g_free (sm);
}
/* --------------------------------------------------------------------------------------------- */
/**
* Initialize already created status message window object
*
* @param sm status message window object
* @param title window title
* @param delay initial delay to raise window in seconds
* @param init_cb callback to initialize user-defined part of status message
* @param update_cb callback to update of status message
* @param deinit_cb callback to deinitialize user-defined part of status message
*/
void
status_msg_init (status_msg_t * sm, const char *title, double delay, status_msg_cb init_cb,
status_msg_update_cb update_cb, status_msg_cb deinit_cb)
{
sm->dlg = dlg_create (TRUE, 0, 0, 7, min (max (40, COLS / 2), COLS), dialog_colors,
NULL, NULL, NULL, title, DLG_CENTER);
sm->delay = delay * G_USEC_PER_SEC;
sm->block = FALSE;
sm->init = init_cb;
sm->update = update_cb;
sm->deinit = deinit_cb;
if (sm->init != NULL)
sm->init (sm);
if (sm->delay > status_msg_delay_threshold)
sm->timer = mc_timer_new ();
else
{
sm->timer = NULL;
/* We will manage the dialog without any help, that's why we have to call init_dlg */
dlg_init (sm->dlg);
}
}
/* --------------------------------------------------------------------------------------------- */
/**
* Deinitialize status message window object
*
* @param sm status message window object
*/
void
status_msg_deinit (status_msg_t * sm)
{
if (sm == NULL)
return;
if (sm->deinit != NULL)
sm->deinit (sm);
if (sm->timer != NULL)
mc_timer_destroy (sm->timer);
/* close and destroy dialog */
dlg_run_done (sm->dlg);
dlg_destroy (sm->dlg);
}
/* --------------------------------------------------------------------------------------------- */
/**
* Update status message window
*
* @param sm status message window object
*
* @return value of pressed key
*/
int
status_msg_common_update (status_msg_t * sm)
{
int c;
Gpm_Event event;
if (sm == NULL)
return B_ENTER;
if (sm->timer != NULL)
{
if (mc_timer_elapsed (sm->timer) > sm->delay)
{
mc_timer_destroy (sm->timer); /* we not need the timer anymore */
sm->timer = NULL;
if (sm->dlg != NULL)
dlg_init (sm->dlg);
}
return B_ENTER;
}
/* This should not happen, but... */
if (sm->dlg == NULL)
return B_ENTER;
event.x = -1; /* Don't show the GPM cursor */
c = tty_get_event (&event, FALSE, sm->block);
if (c == EV_NONE)
return B_ENTER;
/* Reinitialize by non-B_CANCEL value to avoid old values
after events other than selecting a button */
sm->dlg->ret_value = B_ENTER;
dlg_process_event (sm->dlg, c, &event);
return sm->dlg->ret_value;
}
/* --------------------------------------------------------------------------------------------- */

View File

@ -5,6 +5,8 @@
#ifndef MC__WTOOLS_H
#define MC__WTOOLS_H
#include "lib/timer.h"
/*** typedefs(not structures) and defined constants **********************************************/
/* Pass this as def_text to request a password */
@ -13,6 +15,12 @@
/* Use this as header for message() - it expands to "Error" */
#define MSG_ERROR ((char *) -1)
typedef struct status_msg_t status_msg_t;
#define STATUS_MSG(x) ((status_msg_t *)(x))
typedef void (*status_msg_cb) (status_msg_t * sm);
typedef int (*status_msg_update_cb) (status_msg_t * sm);
/*** enums ***************************************************************************************/
/* flags for message() and query_dialog() */
@ -25,6 +33,21 @@ enum
/*** structures declarations (and typedefs of structures)*****************************************/
/* Base class for status message of long-time operations.
Useful to show progress of long-time operaions and interrupt it. */
struct status_msg_t
{
WDialog *dlg; /* pointer to status message dialog */
guint64 delay; /* delay before raise the 'dlg' in microseconds */
mc_timer_t *timer; /* timer to measure 'delay' */
gboolean block; /* how to get event using tty_get_event() */
status_msg_cb init; /* callback to init derived classes */
status_msg_update_cb update; /* callback to update dlg */
status_msg_cb deinit; /* callback to deinit deribed clesses */
};
/*** global variables defined in .c file *********************************************************/
/*** declarations of public functions ************************************************************/
@ -52,6 +75,14 @@ void message (int flags, const char *title, const char *text, ...)
gboolean mc_error_message (GError ** mcerror);
status_msg_t *status_msg_create (const char *title, double delay, status_msg_cb init_cb,
status_msg_update_cb update_cb, status_msg_cb deinit_cb);
void status_msg_destroy (status_msg_t * sm);
void status_msg_init (status_msg_t * sm, const char *title, double delay, status_msg_cb init_cb,
status_msg_update_cb update_cb, status_msg_cb deinit_cb);
void status_msg_deinit (status_msg_t * sm);
int status_msg_common_update (status_msg_t * sm);
/*** inline functions ****************************************************************************/
#endif /* MC__WTOOLS_H */