mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-16 06:05:58 -06:00
341 lines
6.1 KiB
C++
341 lines
6.1 KiB
C++
#include "CtrlLib.h"
|
|
|
|
namespace Upp {
|
|
|
|
CH_STYLE(ProgressIndicator, Style, StyleDefault)
|
|
{
|
|
classic = GUI_GlobalStyle() == GUISTYLE_CLASSIC;
|
|
hlook = CtrlsImg::PI();
|
|
hchunk = CtrlsImg::PIC();
|
|
vlook = CtrlsImg::VPI();
|
|
vchunk = CtrlsImg::VPIC();
|
|
bound = false;
|
|
nomargins = false;
|
|
}
|
|
|
|
Rect ProgressIndicator::GetMargins()
|
|
{
|
|
if(style->classic || percent || !IsNull(color))
|
|
return ChMargins(ViewEdge());
|
|
Size sz = GetSize();
|
|
Rect r = ChMargins(sz.cx > sz.cy ? style->hlook : style->vlook);
|
|
if(style->nomargins)
|
|
r.left = r.right = r.top = r.bottom = 0;
|
|
return r;
|
|
}
|
|
|
|
Size ProgressIndicator::GetMsz()
|
|
{
|
|
Size sz = GetSize();
|
|
Rect mg = GetMargins();
|
|
sz.cx -= mg.left + mg.right;
|
|
sz.cy -= mg.top + mg.bottom;
|
|
return sz;
|
|
}
|
|
|
|
void ProgressIndicator::Paint(Draw& w) {
|
|
Size sz = GetSize();
|
|
Size msz = GetMsz();
|
|
int p0 = 0;
|
|
int p = pxp;
|
|
if(total <= 0) {
|
|
int l = max(msz.cx, msz.cy) & ~7;
|
|
p0 = pxp - l / 4;
|
|
p = min(p - p0, max(msz.cx, msz.cy) - p0);
|
|
if(style->bound && p0 < 0) {
|
|
p += p0;
|
|
p0 = 0;
|
|
}
|
|
}
|
|
if(style->classic || percent || !IsNull(color)) {
|
|
ChPaintEdge(w, sz, ViewEdge());
|
|
Rect mg = GetMargins();
|
|
sz -= Size(mg.left + mg.right, mg.top + mg.bottom);
|
|
Rect r1, r2, r3;
|
|
r1 = r2 = r3 = RectC(mg.left, mg.top, sz.cx, sz.cy);
|
|
w.Clip(r1);
|
|
if(sz.cx > sz.cy) {
|
|
r1.right = r2.left = min(p, sz.cx) + mg.left + p0;
|
|
r3.right = mg.left + p0;
|
|
}
|
|
else {
|
|
r2.bottom = r1.top = sz.cy - min(p, sz.cy) + mg.top - p0;
|
|
r3.top = r3.bottom - p0;
|
|
}
|
|
w.DrawRect(r1, Nvl(color, SColorHighlight()));
|
|
w.DrawRect(r2, SColorPaper);
|
|
w.DrawRect(r3, SColorPaper);
|
|
if(percent) {
|
|
String pt = Format("%d %%", (int)(100L * actual / max(total, 1)));
|
|
Size psz = GetTextSize(pt, font);
|
|
int px = (sz.cx - psz.cx) / 2 + 2;
|
|
int py = (sz.cy - psz.cy) / 2 + 2;
|
|
w.Clip(r1);
|
|
w.DrawText(px, py, pt,font, SColorLight);
|
|
w.End();
|
|
w.Clip(r2);
|
|
w.DrawText(px, py, pt, font, SColorText);
|
|
w.End();
|
|
}
|
|
w.End();
|
|
}
|
|
else {
|
|
Rect r = GetMargins();
|
|
if(sz.cx > sz.cy) {
|
|
ChPaint(this, w, sz, style->hlook);
|
|
w.Clip(r.left, r.top, sz.cx - r.left - r.right, sz.cy - r.top - r.bottom);
|
|
ChPaintNoCache(this, w, r.left + p0, r.top, p, sz.cy - r.top - r.bottom, style->hchunk);
|
|
}
|
|
else {
|
|
ChPaint(this, w, sz, style->vlook);
|
|
w.Clip(r.left, r.top, sz.cx - r.left - r.right, sz.cy - r.top - r.bottom);
|
|
ChPaintNoCache(this, w, r.left, sz.cy - r.bottom - p - p0, sz.cx - r.left - r.right, p, style->vchunk);
|
|
}
|
|
w.End();
|
|
}
|
|
}
|
|
|
|
void ProgressIndicator::Layout() {
|
|
Set(actual, total);
|
|
}
|
|
|
|
void ProgressIndicator::Set(int _actual, int _total) {
|
|
actual = _actual;
|
|
total = _total;
|
|
Size sz = GetMsz();
|
|
int p;
|
|
if(total <= 0) {
|
|
int l = max(1, max(sz.cx, sz.cy) & ~7);
|
|
int p = msecs() / 15 % (l + l / 4);
|
|
if(pxp != p) {
|
|
pxp = p;
|
|
Refresh();
|
|
}
|
|
return;
|
|
}
|
|
else {
|
|
int l = max(1, max(sz.cx, sz.cy));
|
|
p = total ? min(iscale(actual, l, total), l) : 0;
|
|
}
|
|
if(p != pxp) {
|
|
pxp = p;
|
|
Refresh();
|
|
}
|
|
}
|
|
|
|
ProgressIndicator::ProgressIndicator() {
|
|
style = &StyleDefault();
|
|
font = StdFont();
|
|
Transparent();
|
|
NoWantFocus();
|
|
total = actual = 0;
|
|
percent = false;
|
|
color = Null;
|
|
pxp = 0;
|
|
}
|
|
|
|
ProgressIndicator::~ProgressIndicator() {}
|
|
|
|
void Progress::Reset() {
|
|
pos = 0;
|
|
total = 0;
|
|
cancel = false;
|
|
granularity = 50;
|
|
show_delay = 250;
|
|
|
|
set_time = show_time = msecs(); // + 300;
|
|
}
|
|
|
|
void Progress::Init() {
|
|
CtrlLayout(*this, t_("Working..."));
|
|
stop <<= callback(this, &Progress::Cancel);
|
|
info.SetAlign(ALIGN_CENTER);
|
|
owner = NULL;
|
|
Reset();
|
|
}
|
|
|
|
Progress::Progress() {
|
|
Init();
|
|
}
|
|
|
|
Progress::Progress(Ctrl *owner) {
|
|
Init();
|
|
SetOwner(owner);
|
|
}
|
|
|
|
Progress::Progress(const char *s, int total) {
|
|
Init();
|
|
text = s;
|
|
SetTotal(total);
|
|
}
|
|
|
|
Progress::Progress(Ctrl *owner, const char *s, int total) {
|
|
Init();
|
|
text = s;
|
|
SetTotal(total);
|
|
SetOwner(owner);
|
|
}
|
|
|
|
Progress::~Progress() {}
|
|
|
|
void Progress::Create() {
|
|
if(IsPainting() || IsOpen() || cancel)
|
|
return;
|
|
stop.Hide();
|
|
if(owner)
|
|
Open(owner);
|
|
else
|
|
Open();
|
|
if(IsOpen()) { // in some context, e.g. headless skeleton, window does not open - need prevent infinite recursion here
|
|
SetFocus();
|
|
Show();
|
|
modality.Begin(this);
|
|
if(total) Set(pos, total);
|
|
Setxt();
|
|
Sync();
|
|
Process();
|
|
}
|
|
}
|
|
|
|
void Progress::Process()
|
|
{
|
|
if(!IsMainThread())
|
|
return;
|
|
if(!IsOpen()) {
|
|
dword t = msecs();
|
|
if((int)(t - show_time) >= show_delay) {
|
|
Create();
|
|
show_time = t;
|
|
}
|
|
}
|
|
if(IsOpen()) {
|
|
GuiSleep(0);
|
|
ProcessEvents();
|
|
}
|
|
}
|
|
|
|
void Progress::SetText(const String& s)
|
|
{
|
|
Mutex::Lock __(mtx);
|
|
text = s;
|
|
Setxt();
|
|
}
|
|
|
|
String FitText(const String& src, int cx, Font font)
|
|
{
|
|
String r = src;
|
|
int n = (GetTextSize(r, font).cx - cx) / font['W'] / 2;
|
|
while(cx > 0 && GetTextSize(r, font).cx > cx && n > 0 && 2 * n < src.GetCount()) {
|
|
r = src;
|
|
r.Remove(r.GetCount() / 2 - n, 2 * n);
|
|
r.Insert(r.GetCount() / 2, "...");
|
|
n++;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
void Progress::Setxt0()
|
|
{
|
|
info = FitText(Format(text, pos), info.GetSize().cx, StdFont());
|
|
}
|
|
|
|
void Progress::Setxt()
|
|
{
|
|
if(!IsMainThread())
|
|
return;
|
|
|
|
Setxt0();
|
|
|
|
Process();
|
|
}
|
|
|
|
void Progress::Set(int apos, int atotal) {
|
|
{
|
|
Mutex::Lock __(mtx);
|
|
pos = apos;
|
|
total = atotal;
|
|
}
|
|
if(!IsMainThread())
|
|
return;
|
|
dword t = msecs();
|
|
if(abs((int)(t - set_time)) < granularity)
|
|
return;
|
|
set_time = t;
|
|
while(atotal > 30000) {
|
|
atotal >>= 8;
|
|
apos >>= 8;
|
|
}
|
|
pi.Set(apos, atotal);
|
|
Setxt();
|
|
Sync();
|
|
|
|
Process();
|
|
}
|
|
|
|
void Progress::SetTotal(int atotal) {
|
|
Set(pos, atotal);
|
|
}
|
|
|
|
void Progress::SetPos(int apos) {
|
|
Set(apos, total);
|
|
}
|
|
|
|
void Progress::Step(int n)
|
|
{
|
|
Mutex::Lock __(mtx);
|
|
Set(pos + n, total);
|
|
}
|
|
|
|
void Progress::Close()
|
|
{
|
|
modality.End();
|
|
TopWindow::Close();
|
|
}
|
|
|
|
void Progress::Layout()
|
|
{
|
|
Setxt0();
|
|
}
|
|
|
|
void Progress::Cancel() {
|
|
cancel = true;
|
|
Close();
|
|
}
|
|
|
|
bool Progress::Canceled()
|
|
{
|
|
if(IsMainThread()) {
|
|
stop.Show();
|
|
Process();
|
|
}
|
|
return cancel;
|
|
}
|
|
|
|
bool Progress::SetCanceled(int pos, int total)
|
|
{
|
|
if(IsMainThread())
|
|
stop.Show();
|
|
Mutex::Lock __(mtx);
|
|
Set(pos, total);
|
|
return cancel;
|
|
}
|
|
|
|
bool Progress::SetPosCanceled(int pos)
|
|
{
|
|
if(IsMainThread())
|
|
stop.Show();
|
|
Mutex::Lock __(mtx);
|
|
Set(pos, total);
|
|
return cancel;
|
|
}
|
|
|
|
bool Progress::StepCanceled(int n)
|
|
{
|
|
if(IsMainThread())
|
|
stop.Show();
|
|
Mutex::Lock __(mtx);
|
|
Step(n);
|
|
return cancel;
|
|
}
|
|
|
|
}
|