Skip to content

Commit

Permalink
Merge pull request #7 from JAAdrian/develop
Browse files Browse the repository at this point in the history
New Release v3.3.0
  • Loading branch information
JAAdrian authored Feb 28, 2021
2 parents 3c71d26 + c1ea16c commit 5e9e294
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 82 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3.3.0] - 2021-02-28
### Added
- Optional switch to completely disable the bar's progress and printing functionality via `IsActive`. If `false`, the progress bar is disabled. The default is `true`.

## [3.2.0] - 2020-11-13
### Added
- Optional switch to override default MATLAB font in Windows by `OverrideDefaultFont` property. If `true` and while the bar is not released, MATLAB's code font will be changed programmatically to `Courier New`
Expand Down
168 changes: 87 additions & 81 deletions ProgressBar.m
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
properties (Constant)
% Tag every timer with this to find it properly
TIMER_TAG_NAME = 'ProgressBar';
VERSION = '3.2.0';
VERSION = '3.3.0';
end

properties (Nontunable)
Expand All @@ -68,6 +68,10 @@
end

properties (Logical, Nontunable)
% Boolean whether to activate progress bar at all
% useful for non-interactive / batch / hpc usage
IsActive = true;

% Boolean whether to use Unicode symbols or ASCII hash symbols (i.e. #)
UseUnicode = true;

Expand Down Expand Up @@ -113,7 +117,7 @@

% The maximum length of the title string without banner cycling
MAX_TITLE_LENGTH = 20;

OVERRIDE_FONT_NAME = 'Courier New';
end

Expand Down Expand Up @@ -236,54 +240,56 @@
end

function [] = setupImpl(obj)
% get a new tic object
obj.TicObject = tic;

% workaround for issue "Bar Gets Longer With Each Iteration" on windows systems
s = settings;
if obj.OverrideDefaultFont && ispc()
% store current font to reset the code font back to this value in the release() method
obj.CurrentFont = s.matlab.fonts.codefont.Name.ActiveValue;
if obj.IsActive
% get a new tic object
obj.TicObject = tic;

% change to Courier New which is shipped by every Windows distro since Windows 3.1
s.matlab.fonts.codefont.Name.TemporaryValue = ob.OVERRIDE_FONT_NAME;
end

% add a new timer object with the standard tag name and hide it
obj.TimerObject = timer(...
'Tag', obj.TIMER_TAG_NAME, ...
'ObjectVisibility', 'off' ...
);

% if the bar should not be printed in every iteration setup the
% timer to the desired update rate
if obj.HasFiniteUpdateRate
obj.setupTimer();
end

% if 'Total' is known setup the bar correspondingly and compute
% some constant values
if obj.HasTotalIterations
% initialize the progress bar and pre-compute some measures
obj.setupBar();
obj.computeBlockFractions();
end

obj.CurrentTitleState = obj.Title;
if length(obj.Title) > obj.MAX_TITLE_LENGTH
obj.CurrentTitleState = [obj.CurrentTitleState, ' -- '];
end

% if the bar is used in a parallel setup start the timer right now
if obj.IsParallel
obj.startTimer();
end

% if this is a nested bar hit return
if obj.IsThisBarNested
fprintf(1, '\n');
% workaround for issue "Bar Gets Longer With Each Iteration" on windows systems
s = settings;
if obj.OverrideDefaultFont && ispc()
% store current font to reset the code font back to this value in the release() method
obj.CurrentFont = s.matlab.fonts.codefont.Name.ActiveValue;

% change to Courier New which is shipped by every Windows distro since Windows 3.1
s.matlab.fonts.codefont.Name.TemporaryValue = ob.OVERRIDE_FONT_NAME;
end

% add a new timer object with the standard tag name and hide it
obj.TimerObject = timer(...
'Tag', obj.TIMER_TAG_NAME, ...
'ObjectVisibility', 'off' ...
);

% if the bar should not be printed in every iteration setup the
% timer to the desired update rate
if obj.HasFiniteUpdateRate
obj.setupTimer();
end

% if 'Total' is known setup the bar correspondingly and compute
% some constant values
if obj.HasTotalIterations
% initialize the progress bar and pre-compute some measures
obj.setupBar();
obj.computeBlockFractions();
end

obj.CurrentTitleState = obj.Title;
if length(obj.Title) > obj.MAX_TITLE_LENGTH
obj.CurrentTitleState = [obj.CurrentTitleState, ' -- '];
end

% if the bar is used in a parallel setup start the timer right now
if obj.IsParallel
obj.startTimer();
end

% if this is a nested bar hit return
if obj.IsThisBarNested
fprintf(1, '\n');
end
obj.printProgressBar();
end
obj.printProgressBar();
end

function [] = stepImpl(obj, stepSize, wasSuccessful, shouldPrintNextProgBar)
Expand Down Expand Up @@ -338,38 +344,39 @@
{'scalar', 'binary', 'nonnan', 'nonempty'} ...
);


% increment the iteration counter
obj.incrementIterationCounter(stepSize);

% if the timer was stopped before, because no update was given,
% start it now again.
if ~obj.IsTimerRunning && obj.HasFiniteUpdateRate
obj.startTimer();
end

% if the iteration was not successful print a message saying so.
if ~wasSuccessful
infoMsg = sprintf('Iteration %i was not successful!', ...
obj.IterationCounter);
obj.printMessage(infoMsg, shouldPrintNextProgBar);
end

% when the bar should be updated in every iteration, do this with
% each time calling update()
if ~obj.HasFiniteUpdateRate
obj.printProgressBar();
end

% stop the timer after the last iteration if an update rate is
% used. The first condition is needed to prevent the if-statement
% to fail if obj.Total is empty. This happens when no total number
% of iterations was passed / is known.
if ~isempty(obj.Total) ...
&& obj.IterationCounter == obj.Total ...
&& obj.HasFiniteUpdateRate
if obj.IsActive
% increment the iteration counter
obj.incrementIterationCounter(stepSize);

obj.stopTimer();
% if the timer was stopped before, because no update was given,
% start it now again.
if ~obj.IsTimerRunning && obj.HasFiniteUpdateRate
obj.startTimer();
end

% if the iteration was not successful print a message saying so.
if ~wasSuccessful
infoMsg = sprintf('Iteration %i was not successful!', ...
obj.IterationCounter);
obj.printMessage(infoMsg, shouldPrintNextProgBar);
end

% when the bar should be updated in every iteration, do this with
% each time calling update()
if ~obj.HasFiniteUpdateRate
obj.printProgressBar();
end

% stop the timer after the last iteration if an update rate is
% used. The first condition is needed to prevent the if-statement
% to fail if obj.Total is empty. This happens when no total number
% of iterations was passed / is known.
if ~isempty(obj.Total) ...
&& obj.IterationCounter == obj.Total ...
&& obj.HasFiniteUpdateRate

obj.stopTimer();
end
end
end

Expand Down Expand Up @@ -482,7 +489,7 @@
else
unitString = 'it';

if obj.HasItPerSecBelow1
if obj.HasItPerSecBelow1
fractionString = {'s', 'it'};
else
fractionString = {'it', 's'};
Expand Down Expand Up @@ -857,4 +864,3 @@ function deleteAllTimers()

end


3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ Several projects exist on MATLAB's [File Exchange](https://www.mathworks.com/mat
- [x] linear ETA estimate over all last iterations
- [x] support parfor loops provided by the Parallel Computing Toolbox
- [x] show s/it if it/sec < 1
- [ ] have a template functionality like in [minibar](https://github.com/canassa/minibar). Maybe use `regexprep()`?
- [x] override MATLAB's default non-UTF font if `OverrideDefaultFont` is `true`. This will switch the font for the command line to `Courier New` for the lifetime of the bar. Default is `false`
- [x] disable the progress bar if `IsActive` is `false`. This will disable the functionality completely and can be used in situations in which the bar is not beneficial (e.g. if the bar is used in a sub-application of a processing cluster). Default is `true`.


**Note**:
Expand Down
24 changes: 24 additions & 0 deletions demos/disableBar.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
% This script will show how the bar can be programmatically disabled.
%
% Author: J.-A. Adrian (JA) <jensalrik.adrian AT gmail.com>
%

clear;
close all;

addpath('..');

numIterations = 25;


%% This Will Show the Bar
for iIteration = progress(1:numIterations)
pause(0.1);
end


%% This Will Disable the Bar
for iIteration = progress(1:numIterations, 'IsActive', false)
fprintf('New iteration...\n');
pause(0.1);
end
12 changes: 12 additions & 0 deletions tests/ProgressBar_test.m
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,18 @@ function canRunWithoutUpdateTimer(testCase)
testCase.verifyTrue(contains(firstBar, '1/2it'));
testCase.verifyTrue(contains(secondBar, '2/2it'));
end


function canBeDisabled(testCase)
unit = testCase.getUnit(2, 'IsActive', false);

firstBar = evalc('unit([], [], [])');
secondBar = evalc('unit([], [], [])');
unit.release();

testCase.verifyEmpty(firstBar);
testCase.verifyEmpty(secondBar);
end
end


Expand Down
7 changes: 7 additions & 0 deletions tests/progress_test.m
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ function simpleCall(testCase)
testCase.verifyTrue(contains(str, '100%'));
testCase.verifyTrue(contains(str, '1/1it'));
end


function disabledProgress(testCase)
str = evalc('for k = progress(1, ''IsActive'', false); end;');

testCase.verifyEmpty(str);
end
end

end

0 comments on commit 5e9e294

Please sign in to comment.