ACC SHELL
/**
* File: modules/Progress.ycp
* Module: Progress
* Summary: Progress bar
* Authors: Petr Blahos <pblahos@suse.cz>
*
* $Id: Progress.ycp 51223 2008-09-17 12:14:36Z lslezak $
*
* Functions for progress bar.<br>
* <pre>
* Dialog Title
*
* [x] Stage 1
* [x] Stage 2
* => Stage 3
* - Stage 4
* - Stage 5
*
* Progress Title
* [============================90%=======================------]
*
* </pre>
* Example of progress bar usage (don't forget the translation marks in your code):
* Progress bar supposes main wizard dialog is created.<pre>
* Progress::Simple ("Some progress bar", "Progress runs here...", 3, "");
* Progress::NextStep (); // the 1st one does nothing!
* Progress::NextStep ();
* Progress::NextStep ();
* Progress::NextStep ();</pre>
*
* Another example:<pre>
* Progress::New ("Complex progress bar", " ", 100, [
* "Stage1", "Stage2", "Stage3",
* ], [
* "Stage 1 ...", "Stage 2 ...", "Stage 3 ...", "Finished",
* ], "Help text");
* Progress::NextStage ();
* Progress::NextStageStep (20);
* Progress::Stage (0, "I am back", 2);
* Progress::Title ("Still in stage 0");
* Progress::NextStageStep (90);
* Progress::Finish ();</pre>
*
* It is possible to add a detailed subprogress above the main progress bar:
*
* <pre>
* // create a standard progress
* Progress::New(...);
*
* // add a subprogress with 42 steps
* Progress::SubprogressType(`progress, 42);
* Progress::SubprogressTitle("Subprogress label");
*
* // set the subprogress value
* Progress::SubprogressValue(12);
* Progress::SubprogressValue(24);
*
* // remove the subprogress (it's only for the current task/stage)
* Progress::SubprogressType(`none, nil);
*
* // next stage
* Progress::NextStage();
* </pre>
*
* See also hand made documentation.
* <a href="../Progress.html">Progress.html</a>
*/
{
module "Progress";
textdomain "base";
import "CommandLine";
import "Wizard";
import "Mode";
import "Directory";
import "FileUtils";
/********************************************************************
// !!! IMPORTANT !!!
// If you add here a new variable which is valid only for the current
// progress do not forget to add it to PushState() and PopState()
// functions which are are used for nested progresses!
********************************************************************/
// Number of stages.
integer stages = 0;
// Number of steps
integer steps = 0;
// Current stage
integer current_stage = 0;
// Current step
integer current_step = 0;
// list of stage-titles
list titles = [];
// is progress bar used?
boolean visible = true;
// superior progress (stages) bar
integer super_steps = 0;
integer super_step = 0;
list super_stages = [];
// remember the last max. value of the subprogress bar
integer last_subprogress_max = 0;
integer progress_running = 0;
// remember cumulated number of steps for nested progresses
integer progress_max = 0;
integer progress_val = 0;
global boolean IsRunning()
{
//Check if any progress bar exists. If it does not, we're not running
//(querying progress counter is not enough, a module ran previously
//might have failed to reset the counter properly)
return ( (progress_running > 0) && (UI::WidgetExists(`progress_replace_point) == true) );
}
// forward declaration
global symbol CurrentSubprogressType();
// stack with the running progresses
// the top of the stack is the end of the list
list<map> progress_stack = [];
// push the current progress into the stack
void PushState()
{
symbol current_subprogress = CurrentSubprogressType();
map state = $[
// global variable
"stages" : stages,
"steps" : steps,
"current_step" : current_step,
"current_stage" : current_stage,
"titles" : titles,
"last_subprogress_max" : last_subprogress_max,
"visible" : visible,
// state of the widgets
"subprogress_type" : current_subprogress,
"progress_label" : (string)UI::QueryWidget(`id(`pb), `Label),
"progress_value" : (integer)UI::QueryWidget(`id(`pb), `Value),
"progress_max" : progress_max,
"progress_val" : progress_val
];
if (current_subprogress == `progress)
{
state["subprogress_label"] = (string)UI::QueryWidget(`id(`subprogress_progress), `Label);
state["subprogress_value"] = (integer)UI::QueryWidget(`id(`subprogress_progress), `Value);
}
else if (current_subprogress == `tick)
{
state["subprogress_label"] = (string)UI::QueryWidget(`id(`subprogress_tick), `Label);
}
y2milestone("Current state: %1", state);
progress_stack = add(progress_stack, state);
}
// forward declarations
global void SubprogressTitle(string title);
global void SubprogressValue(integer value);
global void SubprogressType(symbol type, integer max_value);
// pop the progress state from the stack and set it
void PopState()
{
// pop the config
map state = progress_stack[size(progress_stack) - 1]:$[];
progress_stack = remove(progress_stack, size(progress_stack) - 1);
y2milestone("setting up the previous state: %1", state);
// refresh the variables
stages = state["stages"]:0;
steps = state["steps"]:0;
current_step = state["current_step"]:0;
current_stage = state["current_stage"]:0;
titles = state["titles"]:[];
last_subprogress_max = state["last_subprogress_max"]:0;
progress_max = state["progress_max"]:0;
progress_val = state["progress_val"]:0;
integer pb_value = state["progress_value"]:0;
pb_value = (pb_value == nil) ? 0 : pb_value + 1;
// refresh the progress widget, add one step for the embedded progress
UI::ReplaceWidget(`id(`progress_replace_point),
`ProgressBar(`id(`pb), state["progress_label"]:"", steps, pb_value)
);
symbol type = state["subprogress_type"]:`none;
SubprogressType(type, last_subprogress_max);
if (type == `progress || type == `tick)
{
SubprogressTitle(state["subprogress_label"]:"");
SubprogressValue(state["subprogress_value"]:0);
}
}
// return size of the progress stack
integer StackSize()
{
return size(progress_stack);
}
// return the value on the top of the stack
// the stack is not changed
map TopState()
{
return progress_stack[size(progress_stack) - 1]:$[];
}
/**
* Sets progress bar state:
* on = normal operation, off = All Progress:: calls return immediatelly.
* @param state on or off
* @return previous state
*/
global define boolean set (boolean state) {
boolean prev = visible;
visible = state;
return prev;
}
/**
* Returns currently selected visibility status of all UI-modifying Progress:: functions.
*
* @return boolean whether the progress bar is used
* @see Progress::set
* @see Progress::off
* @see Progress::on
*/
global define boolean status () {
return visible;
}
/**
* Turns progress bar off. All Progress:: calls return immediatelly.
* @deprecated set
*/
global define void off () {
// no "deprecated" warning
// because it is ok to use this function in testsuites
visible = false;
}
/**
* Turns progress bar on after calling Progress::off.
* @deprecated set
*/
global define void on () {
y2warning (-1, "Deprecated function. Use Progress::set instead");
visible = true;
}
/**
* @param kind `todo, `current or `done
* @return UI mark for stages
*/
any Mark (symbol kind) {
if (kind == `todo)
return "-";
if (kind == `current)
return UI::Glyph (`BulletArrowRight);
if (kind == `done)
return UI::Glyph (`CheckMark);
return "?@%!";
}
/**
* @param i stage number
* @return widget `id(...) for the marker
*/
term MarkId (integer i) {
return `id (sformat ("mark_stage_%1",i));
}
string IconId (integer i) {
return sformat ("mark_icon_%1",i);
}
string FallbackIconInvisible () {
return Directory::icondir + "32x32/apps/yast-sudo.png";
}
string FallbackIconVisible () {
return Directory::icondir + "32x32/apps/yast-scripts.png";
}
list <string> global_invisible_icons_definition = [];
list <string> global_visible_icons_definition = [];
boolean use_icons_in_progress = false;
boolean has_icon_progress_bar = false;
string NormalizeIconPath (string one_icon, boolean visible) {
if (one_icon == nil || one_icon == "")
one_icon = (visible == true ? FallbackIconVisible() : FallbackIconInvisible());
if (! regexpmatch (one_icon, "\.[pP][nN][gG]$") && ! regexpmatch (one_icon, "\.[jJ][pP][gG]$")) {
one_icon = one_icon + ".png";
}
// relative path (to Directory::icondir)
if (regexpmatch (one_icon, "/") && ! regexpmatch (one_icon, "^/")) {
one_icon = Directory::icondir + one_icon;
// hopefully you know what you do
// just image name
} else if (! regexpmatch (one_icon, "/")) {
one_icon = Directory::icondir + "32x32/apps/" + one_icon;
}
if (! FileUtils::Exists (one_icon)) {
y2error ("Image %1 doesn't exist, using fallback", one_icon);
one_icon = (visible == true ? FallbackIconVisible() : FallbackIconInvisible());
}
return one_icon;
}
define term GenerateIdleIcons (integer number_of_stages) {
map display_info = UI::GetDisplayInfo();
boolean can_display_images = (display_info["HasImageSupport"]:false == true);
if (! can_display_images) return `Empty();
term ret = `HBox (`HSpacing (2));
integer i = -1;
string one_icon = "";
number_of_stages = number_of_stages - 1;
while (i < number_of_stages) {
i = i + 1;
one_icon = NormalizeIconPath (global_visible_icons_definition[i]:nil, false);
ret = add (ret, `Image (`id (IconId (i)), `opt (`disabled), one_icon, "[X]"));
ret = add (ret, `HSpacing (2));
}
return ret;
}
/**
* New complex progress bar with stages.
* @param window_title title of the window
* @param progress_title title of the progress bar. Pass at least " "
* (one space) if you want some progress bar title.
* @param length number of steps. If 0, no progress bar is created,
* there are only stages and bottom title. THIS IS NOT
* NUMBER OF STAGES!
* @param stg list of strings - stage names. If it is nil, then there
* are no stages.
* @param tits Titles corresponding to stages. When stage changes,
* progress bar title changes to one of these titles. May
* be nil/empty.
* @param help_text help text
*/
global define void New (string window_title, string progress_title, integer length, list<string> stg, list tits, string help_text) ``{
if (!visible)
return ;
if (Mode::commandline ())
return;
// a progress is already running, remember the current status
if (IsRunning())
{
PushState();
}
y2milestone("Progress::New(%1, %2, %3)", window_title, length, stg);
integer orig_current_step = current_step;
steps = length;
stages = size (stg);
titles = tits;
current_step = -1;
current_stage = -1;
if (length < size(stg))
{
y2warning("Number of stages (%1) is greater than number of steps (%2)", size(stg), length);
}
if (progress_title == "")
{
// Reserve space for future progress bar labels. The ProgressBar
// widget will suppress the label above the progress bar if the
// initial label string is empty.
progress_title = " ";
}
// do not replace the UI, there is a progress already running
if (IsRunning())
{
progress_max = progress_max * steps;
if (StackSize() == 1)
{
progress_val = orig_current_step * steps;
}
else
{
map prev_state = TopState();
integer prev_progress_val = prev_state["progress_val"]:0;
progress_val = prev_progress_val * steps;
}
// set the maximum value of the progress bar
UI::ReplaceWidget(`id(`progress_replace_point), `ProgressBar(`id(`pb), progress_title, progress_max, progress_val));
y2debug("New progress: %1/%2", progress_val, progress_max);
// increase the reference counter
progress_running = progress_running + 1;
return;
}
else
{
progress_max = steps;
}
term bar = `VBox( // progressbar only
`ProgressBar(`id(`pb),progress_title,length,0)
);
if (0 != stages)
{ // version with stages
bar = `VBox (`VSpacing (1));
integer i = 0;
any label_heading = Mark (`todo);
term items = `VBox ();
foreach (string item, stg, ``{
items = add (items,
`HBox (
`HSpacing (1),
// check_ycp wants this text to be translatable. I do not know why.
// HSquash + MinWidth(4) reserves a defined space for 'mark' plus 'emtpy space'
// see bnc #395752
`HSquash (`MinWidth (4, `Heading (MarkId (i), label_heading))),
`Label (item),
`HStretch()
)
);
i = i+1;
});
bar = add (bar, `Left (`HBox (
`HSquash (items)
)));
if (0 != steps)
{ // stages and progress
term progress_icons = `Empty ();
if (use_icons_in_progress == true) {
y2milestone ("Using icons in progress");
progress_icons = GenerateIdleIcons (length);
has_icon_progress_bar = true;
} else {
y2milestone ("No progress icons defined");
has_icon_progress_bar = false;
}
bar = add (bar, `VBox (
`VStretch (),
progress_icons,
`ReplacePoint(`id(`subprogress_replace_point), `Empty()),
`ReplacePoint(`id(`progress_replace_point), `ProgressBar(`id (`pb), progress_title, length, 0)),
`VSpacing (2)
));
}
else
{ // stages only
bar = add (bar, `VBox (
`VStretch (),
`ReplacePoint(`id(`subprogress_replace_point), `Empty()),
`ReplacePoint(`id(`progress_replace_point), `Label (`id (`pb), `opt (`hstretch), progress_title)),
`VSpacing (2)
));
}
}
// patch from Michal Srb https://bugzilla.novell.com/show_bug.cgi?id=406890#c7
if (! Mode::test() && UI::WidgetExists (`id (`contents))) UI::ReplaceWidget (`id (`contents), bar);
if (! UI::WizardCommand(`SetDialogHeading( window_title ) ) )
{
UI::ChangeWidget (`id (`title), `Value, window_title);
}
if ("" != help_text && nil != help_text)
{
Wizard::SetHelpText (help_text);
}
Wizard::DisableBackButton ();
Wizard::DisableNextButton ();
progress_running = progress_running + 1;
}
/**
* Get current subprogress type
* @return symbol Current type of the subprogress widget - can be `progress, `tick or `none
*/
global symbol CurrentSubprogressType()
{
symbol ret = `none;
if (!visible || Mode::commandline())
{
return ret;
}
// is there the subprogress progress widget?
if (UI::WidgetExists(`subprogress_progress) == true)
{
ret = `progress;
}
// or is there the tick subprogress widget?
else if (UI::WidgetExists(`subprogress_tick) == true)
{
ret = `tick;
}
return ret;
}
/**
* Set value of the subprogress
* @param value Current value of the subprogress, if a tick subprogress is running the value is ignored and the next tick is displayed
*/
global void SubprogressValue(integer value)
{
if (!visible || Mode::commandline())
{
return;
}
symbol current_type = CurrentSubprogressType();
// normal progress
if (current_type == `progress)
{
UI::ChangeWidget (`id(`subprogress_progress), `Value, value);
}
// tick progress
else if (current_type == `tick)
{
UI::ChangeWidget(`id(`subprogress_tick), `Alive, true);
}
else
{
y2warning("No subprogress is defined, cannot set the value!");
}
}
/**
* Create (or remove) a new subprogress above the progress bar, can be use for detailed progress of the current task
* @param type type of the subprogress widget, can be `progress (standard progress),
* `tick (tick progress) or `none (no subprogress, intended for removing the progress bar from the dialog)
* @param max_value maximum value for `progress type, for the other types it is not relevant (use any integer value or nil)
*/
global void SubprogressType(symbol type, integer max_value)
{
if (!visible || Mode::commandline())
{
return;
}
y2debug("SubprogressType: type: %1, max_value: %2", type, max_value);
if (type == CurrentSubprogressType())
{
if (type == `progress)
{
// just reset the current value of the progress bar if the requested progress is the same
if (max_value == last_subprogress_max)
{
y2milestone("Resetting the subprogressbar...");
SubprogressValue(0);
return;
}
}
else if (type == `tick)
{
// just restart the animation
UI::ChangeWidget(`id(`subprogress_tick), `Alive, true);
}
else
{
y2milestone("Subprogress initialization skipped");
return;
}
}
term widget = `Empty();
if (type == `progress)
{
widget = `ProgressBar (`id (`subprogress_progress), " ", max_value, 0);
}
else if (type == `tick)
{
widget = `BusyIndicator(`id(`subprogress_tick), " ", 3000);
}
else if (type == `none)
{
widget = `Empty();
}
else
{
y2error("Unknown subprogress type: %1", type);
}
y2debug("widget: %1", widget);
UI::ReplaceWidget(`id(`subprogress_replace_point), widget);
// remember the max. value
last_subprogress_max = max_value;
}
/**
* Set the label of the subprogress
* @param title New label for the subprogress
*/
global void SubprogressTitle(string title)
{
if (!visible || Mode::commandline())
{
return;
}
symbol current_type = CurrentSubprogressType();
if (current_type == `progress)
{
UI::ChangeWidget (`id(`subprogress_progress), `Label, title);
}
else if (current_type == `tick)
{
UI::ChangeWidget (`id(`subprogress_tick), `Label, title);
}
else
{
y2warning("No subprogress is defined, cannot set the label!");
}
}
/**
* Function adds icon-support to progress dialog.
* Parameters are the same as for Progress::New() function with one parameter added.
*
* @param string window_title
* @param string progress_title
* @param integer length
* @param list<string> stg
* @param list tits
* @param string help_textmap
*
* @param list <list <string> > icons_definition
*
* @struct icons_definition = $[
* [ // first 'visible'
* "/path/to/icon-highlighted.png"
* "/path/to/another-icon-highlighted.png",
* ]
* [ // then 'invisible'
* "/path/to/icon-gryscale.png",
* nil, // fallback icon will be used
* ],
* ]
*
* @see Function Progress::New()
*/
global define void NewProgressIcons (string window_title, string progress_title,
integer length, list<string> stg, list tits, string help_textmap, list <list <string> > icons_definition) {
global_visible_icons_definition = icons_definition[0]:[];
global_invisible_icons_definition = icons_definition[1]:[];
use_icons_in_progress = true;
New (window_title, progress_title, length, stg, tits, help_textmap);
use_icons_in_progress = false;
}
/**
* Create simple progress bar with no stages, only with progress bar.
* @param window_title Title of the window.
* @param progress_title Title of the progress bar.
* @param length Number of steps.
* @param help_text Help text.
*/
global define void Simple (string window_title, string progress_title, integer length, string help_text) ``{
New (window_title, progress_title, length, [], [], help_text);
}
integer last_highlighted_icon = -1;
/**
* Highlights a progress icon (changes the dimmed one
* into a normal one).
*
* @param integer current step ID
*/
void HighlightProgressIcon (integer step_id) {
if (has_icon_progress_bar) {
if (last_highlighted_icon == nil) last_highlighted_icon = -1;
// some steps might have been skipped, change all (not changed yet)
// icons one by one
while (last_highlighted_icon < step_id) {
last_highlighted_icon = last_highlighted_icon + 1;
string icon_id = IconId (last_highlighted_icon);
if (UI::WidgetExists (`id (icon_id)) == true) {
UI::ChangeWidget (`id (icon_id), `Enabled, true);
}
}
}
}
/**
* Uses current_step
*/
void UpdateProgressBar () {
if (current_step > steps)
{
y2error (-2, "Progress bar has only %1 steps, not %2.", steps, current_step);
return ;
}
integer progress_value = current_step;
// do not change icons in a nested progress
if (StackSize() == 0)
{
HighlightProgressIcon (current_step);
}
else
{
// recalculate the progress bar value according to the parent progress
map prev_state = TopState();
integer prev_step = prev_state["current_step"]:0;
progress_value = (prev_step * steps) + (current_step > 0 ? current_step : 0);
}
y2debug("New progress value: %1, current_step: %2/%3 (%4%%)", progress_value, current_step, steps,
100.0 * progress_value / progress_max);
UI::ChangeWidget (`id (`pb), `Value, progress_value);
}
/**
* the bar is either `ProgressBar or `Label
* @param s title
*/
void SetProgressBarTitle (string s) {
UI::ChangeWidget (`id (`pb), 0 == steps ? `Value : `Label, s);
}
/**
* Some people say it is the best operating system ever. But now to the
* function. Advances progress bar value by 1.
*/
global define void NextStep () ``{
if (!visible || Mode::commandline () || 0 == steps)
return ;
current_step = current_step + 1;
UpdateProgressBar ();
}
/**
* Advance stage, advance step by 1 and set progress bar caption to
* that defined in New.
*/
global define void NextStage () ``{
if (!visible)
return ;
NextStep ();
if (0 == stages || current_stage > stages)
{
y2error ("Non-existing stage requested.");
return ;
}
current_stage = current_stage + 1;
// do not update the UI in a nested progress
if (StackSize() > 0)
{
return;
}
if ( Mode::commandline ())
{
if (current_stage < stages && current_stage < size (titles))
{
CommandLine::PrintVerbose(titles[current_stage]:"");
}
return;
}
if (current_stage > 0)
{
UI::ChangeWidget (MarkId (current_stage-1), `Value, Mark (`done));
}
// we may be past the last stage
if (current_stage < stages )
{
if (current_stage < size (titles))
{
SetProgressBarTitle (titles[current_stage]:"");
}
UI::ChangeWidget (MarkId (current_stage), `Value, Mark (`current));
}
}
/**
* Changes progress bar value to st.
* @param st new value
*/
global define void Step (integer st) ``{
if (!visible || Mode::commandline () || 0 == steps)
return ;
if (st < 0 || st > steps) return;
current_step = st;
UpdateProgressBar ();
}
/**
* Go to stage st, change progress bar title to title and set progress
* bar step to step.
* @param st New stage.
* @param title New title for progress bar. If nil, title specified in
* New is used.
* @param step New step or -1 if step should not change.
*/
global define void Stage (integer st, string title, integer step) ``{
if (!visible)
return ;
if (-1 != step)
{
Step (step);
}
// another progress is running
// do not change the current stage, calculate the target step
if (StackSize() > 0)
{
UpdateProgressBar();
return;
}
if (!Mode::commandline () && current_stage >= 0)
{
UI::ChangeWidget(MarkId (current_stage), `Value,
Mark (st > current_stage ? `done: `todo));
}
current_stage = st;
string s = "";
if (current_stage < size (titles))
{
s = titles[current_stage]:"";
}
if (nil != title)
{
s = title;
}
if (current_stage < size (titles))
{
if (Mode::commandline ())
{
CommandLine::PrintVerbose (s);
return;
}
else
{
SetProgressBarTitle (s);
}
}
if (current_stage < stages)
{
UI::ChangeWidget(MarkId (current_stage), `Value, Mark (`current));
}
}
/**
* Jumps to the next stage and sets step to st.
* @param st new progress bar value
*/
global define void NextStageStep (integer st) ``{
if (!visible || Mode::commandline ())
return ;
NextStage ();
Step (st);
}
/**
* Change progress bar title.
* @param t new title. Use ""(empty string) if you want an empty progress bar.
*/
global define void Title (string t) ``{
if (visible && ! Mode::commandline ())
SetProgressBarTitle (t);
}
/**
* Moves progress bar to the end and marks all stages as completed.
*/
global define void Finish () ``{
if (!visible || Mode::commandline ())
return ;
// decrease the reference counter
progress_running = progress_running - 1;
// set the previous state
if (StackSize() > 0)
{
PopState();
return;
}
if (0 != stages)
{
while (current_stage < stages)
NextStage ();
}
if (0 != steps)
{
current_step = steps;
UpdateProgressBar ();
}
SetProgressBarTitle (" ");
}
/**
* Creates a higher-level progress bar made of stages. Currently it is
* placed instead of help text.
* @param title title of the progress...
* @param stages list of stage descriptions
*/
global define void OpenSuperior (string title, list<string> stages)
{
if (UI::HasSpecialWidget(`Wizard))
{
Wizard::OpenAcceptAbortStepsDialog();
UI::WizardCommand(`AddStepHeading(title));
integer idx = 0;
super_steps = size (stages);
super_step = -1;
foreach (string s, stages,
{
string id = sformat ("super_progress_%1", idx);
UI::WizardCommand (`AddStep (s, id));
});
UI::WizardCommand(`UpdateSteps() );
}
else // old behaviour
{
term left = `VBox (`VStretch ());
term right = `VBox (`VStretch ());
integer idx = 0;
super_steps = size (stages);
super_step = -1;
foreach (string i, stages,
{
string id = sformat ("super_progress_%1", idx);
left = add (left, `Heading (`id (id), "- "));
right = add (right, `Label (`opt (`hstretch), i));
left = add (left, `VStretch ());
right = add (right, `VStretch ());
idx = idx + 1;
});
left = add (left, `HSpacing (4));
right = add (right, `HStretch ());
Wizard::ReplaceHelp (`VBox (
`HBox (
`HSpacing (1),
`Frame (
title,
`HBox (`HSpacing (1), left, right)
)
),
`VSpacing (0.5)
)
);
}
}
/**
* Replaces stages of superior progress by an empty help text.
*/
global define void CloseSuperior () ``{
if (UI::HasSpecialWidget(`Wizard))
{
UI::CloseDialog();
}
else
{
Wizard::RestoreHelp ("");
}
super_steps = 0;
super_step = 0;
}
/**
* Make one step in a superior progress bar.
*/
global define void StepSuperior () ``{
if (super_step >= 0 && super_step < super_steps)
{
if (!UI::HasSpecialWidget(`Wizard))
{
UI::ChangeWidget (`id (sformat ("super_progress_%1", super_step)), `Value, UI::Glyph (`CheckMark));
}
}
super_step = super_step + 1;
if (super_step >= super_steps)
{
return;
}
if (UI::HasSpecialWidget(`Wizard))
{
UI::WizardCommand (`SetCurrentStep (sformat ("super_progress_%1", super_step)));
}
else
{
UI::ChangeWidget (`id (sformat ("super_progress_%1", super_step)), `Value, UI::Glyph (`BulletArrowRight));
}
}
/* EOF */
}
ACC SHELL 2018