Common: Add ProgressCallback class

This commit is contained in:
Connor McLaughlin 2020-03-12 13:54:27 +10:00
parent 8f39a0f154
commit 8028b7b4a3
5 changed files with 524 additions and 0 deletions

View file

@ -41,6 +41,8 @@ add_library(common
null_audio_stream.cpp null_audio_stream.cpp
null_audio_stream.h null_audio_stream.h
rectangle.h rectangle.h
progress_callback.cpp
progress_callback.h
state_wrapper.cpp state_wrapper.cpp
state_wrapper.h state_wrapper.h
string.cpp string.cpp

View file

@ -60,6 +60,7 @@
<ClInclude Include="log.h" /> <ClInclude Include="log.h" />
<ClInclude Include="md5_digest.h" /> <ClInclude Include="md5_digest.h" />
<ClInclude Include="null_audio_stream.h" /> <ClInclude Include="null_audio_stream.h" />
<ClInclude Include="progress_callback.h" />
<ClInclude Include="rectangle.h" /> <ClInclude Include="rectangle.h" />
<ClInclude Include="cd_subchannel_replacement.h" /> <ClInclude Include="cd_subchannel_replacement.h" />
<ClInclude Include="state_wrapper.h" /> <ClInclude Include="state_wrapper.h" />
@ -94,6 +95,7 @@
<ClCompile Include="log.cpp" /> <ClCompile Include="log.cpp" />
<ClCompile Include="md5_digest.cpp" /> <ClCompile Include="md5_digest.cpp" />
<ClCompile Include="null_audio_stream.cpp" /> <ClCompile Include="null_audio_stream.cpp" />
<ClCompile Include="progress_callback.cpp" />
<ClCompile Include="state_wrapper.cpp" /> <ClCompile Include="state_wrapper.cpp" />
<ClCompile Include="cd_xa.cpp" /> <ClCompile Include="cd_xa.cpp" />
<ClCompile Include="string.cpp" /> <ClCompile Include="string.cpp" />

View file

@ -51,6 +51,7 @@
<Filter>d3d11</Filter> <Filter>d3d11</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="hash_combine.h" /> <ClInclude Include="hash_combine.h" />
<ClInclude Include="progress_callback.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="jit_code_buffer.cpp" /> <ClCompile Include="jit_code_buffer.cpp" />
@ -98,6 +99,7 @@
<Filter>d3d11</Filter> <Filter>d3d11</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="cd_image_chd.cpp" /> <ClCompile Include="cd_image_chd.cpp" />
<ClCompile Include="progress_callback.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Natvis Include="bitfield.natvis" /> <Natvis Include="bitfield.natvis" />

View file

@ -0,0 +1,397 @@
#include "progress_callback.h"
#include "assert.h"
#include "byte_stream.h"
#include "log.h"
#include <cmath>
#include <cstdio>
#include <limits>
Log_SetChannel(ProgressCallback);
ProgressCallback::~ProgressCallback() {}
void ProgressCallback::SetFormattedStatusText(const char* Format, ...)
{
SmallString str;
va_list ap;
va_start(ap, Format);
str.FormatVA(Format, ap);
va_end(ap);
SetStatusText(str);
}
void ProgressCallback::DisplayFormattedError(const char* format, ...)
{
SmallString str;
va_list ap;
va_start(ap, format);
str.FormatVA(format, ap);
va_end(ap);
DisplayError(str);
}
void ProgressCallback::DisplayFormattedWarning(const char* format, ...)
{
SmallString str;
va_list ap;
va_start(ap, format);
str.FormatVA(format, ap);
va_end(ap);
DisplayWarning(str);
}
void ProgressCallback::DisplayFormattedInformation(const char* format, ...)
{
SmallString str;
va_list ap;
va_start(ap, format);
str.FormatVA(format, ap);
va_end(ap);
DisplayInformation(str);
}
void ProgressCallback::DisplayFormattedDebugMessage(const char* format, ...)
{
SmallString str;
va_list ap;
va_start(ap, format);
str.FormatVA(format, ap);
va_end(ap);
DisplayDebugMessage(str);
}
void ProgressCallback::DisplayFormattedModalError(const char* format, ...)
{
SmallString str;
va_list ap;
va_start(ap, format);
str.FormatVA(format, ap);
va_end(ap);
ModalError(str);
}
bool ProgressCallback::DisplayFormattedModalConfirmation(const char* format, ...)
{
SmallString str;
va_list ap;
va_start(ap, format);
str.FormatVA(format, ap);
va_end(ap);
return ModalConfirmation(str);
}
void ProgressCallback::UpdateProgressFromStream(ByteStream* pStream)
{
u32 streamSize = (u32)pStream->GetSize();
u32 streamPosition = (u32)pStream->GetPosition();
SetProgressRange(streamSize);
SetProgressValue(streamPosition);
}
class NullProgressCallbacks final : public ProgressCallback
{
public:
void PushState() override {}
void PopState() override {}
bool IsCancelled() const override { return false; }
bool IsCancellable() const override { return false; }
void SetCancellable(bool cancellable) override {}
void SetStatusText(const char* statusText) override {}
void SetProgressRange(u32 range) override {}
void SetProgressValue(u32 value) override {}
void IncrementProgressValue() override {}
void DisplayError(const char* message) override { Log_ErrorPrint(message); }
void DisplayWarning(const char* message) override { Log_WarningPrint(message); }
void DisplayInformation(const char* message) override { Log_InfoPrint(message); }
void DisplayDebugMessage(const char* message) override { Log_DevPrint(message); }
void ModalError(const char* message) override { Log_ErrorPrint(message); }
bool ModalConfirmation(const char* message) override
{
Log_InfoPrint(message);
return false;
}
u32 ModalPrompt(const char* message, u32 nOptions, ...) override
{
DebugAssert(nOptions > 0);
Log_InfoPrint(message);
return 0;
}
};
static NullProgressCallbacks s_nullProgressCallbacks;
ProgressCallback* ProgressCallback::NullProgressCallback = &s_nullProgressCallbacks;
BaseProgressCallback::BaseProgressCallback()
: m_cancellable(false), m_cancelled(false), m_progress_range(1), m_progress_value(0), m_base_progress_value(0),
m_saved_state(NULL)
{
}
BaseProgressCallback::~BaseProgressCallback()
{
State* pNextState = m_saved_state;
while (pNextState != NULL)
{
State* pCurrentState = pNextState;
pNextState = pCurrentState->next_saved_state;
delete pCurrentState;
}
}
void BaseProgressCallback::PushState()
{
State* pNewState = new State;
pNewState->cancellable = m_cancellable;
pNewState->status_text = m_status_text;
pNewState->progress_range = m_progress_range;
pNewState->progress_value = m_progress_value;
pNewState->base_progress_value = m_base_progress_value;
pNewState->next_saved_state = m_saved_state;
m_saved_state = pNewState;
}
void BaseProgressCallback::PopState()
{
DebugAssert(m_saved_state);
State* state = m_saved_state;
m_saved_state = nullptr;
// impose the current position into the previous range
const u32 new_progress_value =
(m_progress_range != 0) ?
static_cast<u32>(((float)m_progress_value / (float)m_progress_range) * (float)state->progress_range) :
state->progress_value;
SetCancellable(state->cancellable);
SetStatusText(state->status_text);
SetProgressRange(state->progress_range);
SetProgressValue(new_progress_value);
m_base_progress_value = state->base_progress_value;
m_saved_state = state->next_saved_state;
delete state;
}
bool BaseProgressCallback::IsCancelled() const
{
return m_cancelled;
}
bool BaseProgressCallback::IsCancellable() const
{
return m_cancellable;
}
void BaseProgressCallback::SetCancellable(bool cancellable)
{
m_cancellable = cancellable;
}
void BaseProgressCallback::SetStatusText(const char* text)
{
m_status_text = text;
}
void BaseProgressCallback::SetProgressRange(u32 range)
{
if (m_saved_state)
{
// impose the previous range on this range
m_progress_range = m_saved_state->progress_range * range;
m_base_progress_value = m_progress_value = m_saved_state->progress_value * range;
}
else
{
m_progress_range = range;
m_progress_value = 0;
m_base_progress_value = 0;
}
}
void BaseProgressCallback::SetProgressValue(u32 value)
{
m_progress_value = m_base_progress_value + value;
}
void BaseProgressCallback::IncrementProgressValue()
{
SetProgressValue((m_progress_value - m_base_progress_value) + 1);
}
ConsoleProgressCallback::ConsoleProgressCallback()
: BaseProgressCallback(), m_last_percent_complete(std::numeric_limits<float>::infinity()),
m_last_bar_length(0xFFFFFFFF)
{
}
ConsoleProgressCallback::~ConsoleProgressCallback()
{
Clear();
}
void ConsoleProgressCallback::PushState()
{
BaseProgressCallback::PushState();
}
void ConsoleProgressCallback::PopState()
{
BaseProgressCallback::PopState();
Redraw(false);
}
void ConsoleProgressCallback::SetCancellable(bool cancellable)
{
BaseProgressCallback::SetCancellable(cancellable);
Redraw(false);
}
void ConsoleProgressCallback::SetStatusText(const char* text)
{
BaseProgressCallback::SetStatusText(text);
Redraw(false);
}
void ConsoleProgressCallback::SetProgressRange(u32 range)
{
u32 last_range = m_progress_range;
BaseProgressCallback::SetProgressRange(range);
if (m_progress_range != last_range)
Redraw(false);
}
void ConsoleProgressCallback::SetProgressValue(u32 value)
{
u32 lastValue = m_progress_value;
BaseProgressCallback::SetProgressValue(value);
if (m_progress_value != lastValue)
Redraw(true);
}
void ConsoleProgressCallback::Clear()
{
SmallString message;
for (u32 i = 0; i < COLUMNS; i++)
message.AppendCharacter(' ');
message.AppendCharacter('\r');
std::fwrite(message.GetCharArray(), message.GetLength(), 1, stderr);
std::fflush(stderr);
}
void ConsoleProgressCallback::Redraw(bool update_value_only)
{
float percent_complete = (m_progress_range > 0) ? ((float)m_progress_value / (float)m_progress_range) * 100.0f : 0.0f;
if (percent_complete > 100.0f)
percent_complete = 100.0f;
const u32 current_length = m_status_text.GetLength() + 14;
const u32 max_bar_length = (current_length < COLUMNS) ? COLUMNS - current_length : 0;
const u32 current_bar_length =
(max_bar_length > 0) ? (static_cast<u32>(percent_complete / 100.0f * (float)max_bar_length)) : 0;
if (update_value_only && (current_bar_length == m_last_bar_length) &&
std::abs(percent_complete - m_last_percent_complete) < 0.01f)
{
return;
}
m_last_bar_length = current_bar_length;
m_last_percent_complete = percent_complete;
SmallString message;
message.AppendString(m_status_text);
message.AppendFormattedString(" [%.2f%%]", percent_complete);
if (max_bar_length > 0)
{
message.AppendString(" |");
u32 i;
for (i = 0; i < current_bar_length; i++)
message.AppendCharacter('=');
for (; i < max_bar_length; i++)
message.AppendCharacter(' ');
message.AppendString("|");
}
message.AppendCharacter('\r');
std::fwrite(message.GetCharArray(), message.GetLength(), 1, stderr);
std::fflush(stderr);
}
void ConsoleProgressCallback::DisplayError(const char* message)
{
Clear();
Log_ErrorPrint(message);
Redraw(false);
}
void ConsoleProgressCallback::DisplayWarning(const char* message)
{
Clear();
Log_WarningPrint(message);
Redraw(false);
}
void ConsoleProgressCallback::DisplayInformation(const char* message)
{
Clear();
Log_InfoPrint(message);
Redraw(false);
}
void ConsoleProgressCallback::DisplayDebugMessage(const char* message)
{
Clear();
Log_DevPrint(message);
Redraw(false);
}
void ConsoleProgressCallback::ModalError(const char* message)
{
Clear();
Log_ErrorPrint(message);
Redraw(false);
}
bool ConsoleProgressCallback::ModalConfirmation(const char* message)
{
Clear();
Log_InfoPrint(message);
Redraw(false);
return false;
}
u32 ConsoleProgressCallback::ModalPrompt(const char* message, u32 num_options, ...)
{
Clear();
DebugAssert(num_options > 0);
Log_InfoPrint(message);
Redraw(false);
return 0;
}

View file

@ -0,0 +1,121 @@
#pragma once
#include "string.h"
#include "types.h"
class ByteStream;
class ProgressCallback
{
public:
virtual ~ProgressCallback();
virtual void PushState() = 0;
virtual void PopState() = 0;
virtual bool IsCancelled() const = 0;
virtual bool IsCancellable() const = 0;
virtual void SetCancellable(bool cancellable) = 0;
virtual void SetStatusText(const char* text) = 0;
virtual void SetProgressRange(u32 range) = 0;
virtual void SetProgressValue(u32 value) = 0;
virtual void IncrementProgressValue() = 0;
void SetFormattedStatusText(const char* Format, ...);
virtual void DisplayError(const char* message) = 0;
virtual void DisplayWarning(const char* message) = 0;
virtual void DisplayInformation(const char* message) = 0;
virtual void DisplayDebugMessage(const char* message) = 0;
virtual void ModalError(const char* message) = 0;
virtual bool ModalConfirmation(const char* message) = 0;
virtual u32 ModalPrompt(const char* message, u32 num_options, ...) = 0;
void DisplayFormattedError(const char* format, ...);
void DisplayFormattedWarning(const char* format, ...);
void DisplayFormattedInformation(const char* format, ...);
void DisplayFormattedDebugMessage(const char* format, ...);
void DisplayFormattedModalError(const char* format, ...);
bool DisplayFormattedModalConfirmation(const char* format, ...);
void UpdateProgressFromStream(ByteStream* stream);
public:
static ProgressCallback* NullProgressCallback;
};
class BaseProgressCallback : public ProgressCallback
{
public:
BaseProgressCallback();
virtual ~BaseProgressCallback();
virtual void PushState() override;
virtual void PopState() override;
virtual bool IsCancelled() const override;
virtual bool IsCancellable() const override;
virtual void SetCancellable(bool cancellable) override;
virtual void SetStatusText(const char* text) override;
virtual void SetProgressRange(u32 range) override;
virtual void SetProgressValue(u32 value) override;
virtual void IncrementProgressValue() override;
protected:
struct State
{
State* next_saved_state;
String status_text;
u32 progress_range;
u32 progress_value;
u32 base_progress_value;
bool cancellable;
};
bool m_cancellable;
bool m_cancelled;
String m_status_text;
u32 m_progress_range;
u32 m_progress_value;
u32 m_base_progress_value;
State* m_saved_state;
};
class ConsoleProgressCallback : public BaseProgressCallback
{
public:
static const u32 COLUMNS = 78;
public:
ConsoleProgressCallback();
~ConsoleProgressCallback();
virtual void PushState() override;
virtual void PopState() override;
virtual void SetCancellable(bool cancellable) override;
virtual void SetStatusText(const char* text) override;
virtual void SetProgressRange(u32 range) override;
virtual void SetProgressValue(u32 value) override;
virtual void DisplayError(const char* message) override;
virtual void DisplayWarning(const char* message) override;
virtual void DisplayInformation(const char* message) override;
virtual void DisplayDebugMessage(const char* message) override;
virtual void ModalError(const char* message) override;
virtual bool ModalConfirmation(const char* message) override;
virtual u32 ModalPrompt(const char* message, u32 num_options, ...) override;
private:
void Clear();
void Redraw(bool update_value_only);
float m_last_percent_complete;
u32 m_last_bar_length;
};