xref: /reactos/base/setup/usetup/progress.c (revision 426598c6)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS text-mode setup
4  * FILE:            base/setup/usetup/progress.c
5  * PURPOSE:         Partition list functions
6  * PROGRAMMER:
7  */
8 
9 /* INCLUDES *****************************************************************/
10 
11 #include "usetup.h"
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* FUNCTIONS ****************************************************************/
17 
18 static
19 BOOLEAN NTAPI
20 UpdateProgressPercentage(
21     IN PPROGRESSBAR Bar,
22     IN BOOLEAN AlwaysUpdate,
23     OUT PSTR Buffer,
24     IN SIZE_T cchBufferSize)
25 {
26     // static PCSTR ProgressFormatText;
27     ULONG OldProgress = Bar->Progress;
28 
29     /* Calculate the new percentage */
30     if (Bar->StepCount == 0)
31         Bar->Progress = 0;
32     else
33         Bar->Progress = ((100 * Bar->CurrentStep + (Bar->StepCount / 2)) / Bar->StepCount);
34 
35     /* Build the progress string if it has changed */
36     if ( Bar->ProgressFormatText &&
37         (AlwaysUpdate || (Bar->Progress != OldProgress)) )
38     {
39         RtlStringCchPrintfA(Buffer, cchBufferSize,
40                             Bar->ProgressFormatText, Bar->Progress);
41         return TRUE;
42     }
43     return FALSE;
44 }
45 
46 static
47 VOID
48 DrawBorder(
49     IN PPROGRESSBAR Bar)
50 {
51     COORD coPos;
52     DWORD Written;
53     SHORT i;
54 
55     /* draw upper left corner */
56     coPos.X = Bar->Left;
57     coPos.Y = Bar->Top + 1;
58     FillConsoleOutputCharacterA(StdOutput,
59                                 CharUpperLeftCorner, // '+',
60                                 1,
61                                 coPos,
62                                 &Written);
63 
64     /* draw upper edge */
65     coPos.X = Bar->Left + 1;
66     coPos.Y = Bar->Top + 1;
67     FillConsoleOutputCharacterA(StdOutput,
68                                 CharHorizontalLine, // '-',
69                                 Bar->Right - Bar->Left - 1,
70                                 coPos,
71                                 &Written);
72 
73     /* draw upper right corner */
74     coPos.X = Bar->Right;
75     coPos.Y = Bar->Top + 1;
76     FillConsoleOutputCharacterA(StdOutput,
77                                 CharUpperRightCorner, // '+',
78                                 1,
79                                 coPos,
80                                 &Written);
81 
82     /* draw left and right edge */
83     for (i = Bar->Top + 2; i < Bar->Bottom; i++)
84     {
85         coPos.X = Bar->Left;
86         coPos.Y = i;
87         FillConsoleOutputCharacterA(StdOutput,
88                                     CharVerticalLine, // '|',
89                                     1,
90                                     coPos,
91                                     &Written);
92 
93         coPos.X = Bar->Right;
94         FillConsoleOutputCharacterA(StdOutput,
95                                     CharVerticalLine, //'|',
96                                     1,
97                                     coPos,
98                                     &Written);
99     }
100 
101     /* draw lower left corner */
102     coPos.X = Bar->Left;
103     coPos.Y = Bar->Bottom;
104     FillConsoleOutputCharacterA(StdOutput,
105                                 CharLowerLeftCorner, // '+',
106                                 1,
107                                 coPos,
108                                 &Written);
109 
110     /* draw lower edge */
111     coPos.X = Bar->Left + 1;
112     coPos.Y = Bar->Bottom;
113     FillConsoleOutputCharacterA(StdOutput,
114                                 CharHorizontalLine, // '-',
115                                 Bar->Right - Bar->Left - 1,
116                                 coPos,
117                                 &Written);
118 
119     /* draw lower right corner */
120     coPos.X = Bar->Right;
121     coPos.Y = Bar->Bottom;
122     FillConsoleOutputCharacterA(StdOutput,
123                                 CharLowerRightCorner, // '+',
124                                 1,
125                                 coPos,
126                                 &Written);
127 }
128 
129 static
130 VOID
131 DrawThickBorder(
132     IN PPROGRESSBAR Bar)
133 {
134     COORD coPos;
135     DWORD Written;
136     SHORT i;
137 
138     /* draw upper left corner */
139     coPos.X = Bar->Left;
140     coPos.Y = Bar->Top + 1;
141     FillConsoleOutputCharacterA(StdOutput,
142                                 CharDoubleUpperLeftCorner, // '+',
143                                 1,
144                                 coPos,
145                                 &Written);
146 
147     /* draw upper edge */
148     coPos.X = Bar->Left + 1;
149     coPos.Y = Bar->Top + 1;
150     FillConsoleOutputCharacterA(StdOutput,
151                                 CharDoubleHorizontalLine, // '-',
152                                 Bar->Right - Bar->Left - 1,
153                                 coPos,
154                                 &Written);
155 
156     /* draw upper right corner */
157     coPos.X = Bar->Right;
158     coPos.Y = Bar->Top + 1;
159     FillConsoleOutputCharacterA(StdOutput,
160                                 CharDoubleUpperRightCorner, // '+',
161                                 1,
162                                 coPos,
163                                 &Written);
164 
165     /* draw left and right edge */
166     for (i = Bar->Top + 2; i < Bar->Bottom; i++)
167     {
168         coPos.X = Bar->Left;
169         coPos.Y = i;
170         FillConsoleOutputCharacterA(StdOutput,
171                                     CharDoubleVerticalLine, // '|',
172                                     1,
173                                     coPos,
174                                     &Written);
175 
176         coPos.X = Bar->Right;
177         FillConsoleOutputCharacterA(StdOutput,
178                                     CharDoubleVerticalLine, //'|',
179                                     1,
180                                     coPos,
181                                     &Written);
182     }
183 
184     /* draw lower left corner */
185     coPos.X = Bar->Left;
186     coPos.Y = Bar->Bottom;
187     FillConsoleOutputCharacterA(StdOutput,
188                                 CharDoubleLowerLeftCorner, // '+',
189                                 1,
190                                 coPos,
191                                 &Written);
192 
193     /* draw lower edge */
194     coPos.X = Bar->Left + 1;
195     coPos.Y = Bar->Bottom;
196     FillConsoleOutputCharacterA(StdOutput,
197                                 CharDoubleHorizontalLine, // '-',
198                                 Bar->Right - Bar->Left - 1,
199                                 coPos,
200                                 &Written);
201 
202     /* draw lower right corner */
203     coPos.X = Bar->Right;
204     coPos.Y = Bar->Bottom;
205     FillConsoleOutputCharacterA(StdOutput,
206                                 CharDoubleLowerRightCorner, // '+',
207                                 1,
208                                 coPos,
209                                 &Written);
210 }
211 
212 static
213 VOID
214 DrawProgressBar(
215     IN PPROGRESSBAR Bar)
216 {
217     COORD coPos;
218     DWORD Written;
219     PROGRESSBAR BarBorder = *Bar;
220     CHAR TextBuffer[256];
221 
222     /* Draw the progress bar "border" border */
223     if (Bar->DoubleEdge)
224     {
225         BarBorder.Top -= 5;
226         BarBorder.Bottom += 2;
227         BarBorder.Right += 5;
228         BarBorder.Left -= 5;
229         DrawThickBorder(&BarBorder);
230     }
231 
232     /* Draw the progress bar border */
233     DrawBorder(Bar);
234 
235     /* Display the description text */
236     if (Bar->DescriptionText)
237         CONSOLE_SetTextXY(Bar->TextTop, Bar->TextRight, Bar->DescriptionText);
238 
239     /* Always update and display the progress */
240     if (Bar->UpdateProgressProc &&
241         Bar->UpdateProgressProc(Bar, TRUE, TextBuffer, ARRAYSIZE(TextBuffer)))
242     {
243         coPos.X = Bar->Left + (Bar->Width - (USHORT)strlen(TextBuffer) + 1) / 2;
244         coPos.Y = Bar->Top;
245         WriteConsoleOutputCharacterA(StdOutput,
246                                      TextBuffer,
247                                      strlen(TextBuffer),
248                                      coPos,
249                                      &Written);
250     }
251 
252     /* Draw the empty bar */
253     coPos.X = Bar->Left + 1;
254     for (coPos.Y = Bar->Top + 2; coPos.Y <= Bar->Bottom - 1; coPos.Y++)
255     {
256         FillConsoleOutputAttribute(StdOutput,
257                                    Bar->ProgressColour,
258                                    Bar->Width - 2,
259                                    coPos,
260                                    &Written);
261 
262         FillConsoleOutputCharacterA(StdOutput,
263                                     ' ',
264                                     Bar->Width - 2,
265                                     coPos,
266                                     &Written);
267     }
268 }
269 
270 
271 PPROGRESSBAR
272 CreateProgressBarEx(
273     IN SHORT Left,
274     IN SHORT Top,
275     IN SHORT Right,
276     IN SHORT Bottom,
277     IN SHORT TextTop,
278     IN SHORT TextRight,
279     IN BOOLEAN DoubleEdge,
280     IN SHORT ProgressColour,
281     IN ULONG StepCount,
282     IN PCSTR DescriptionText OPTIONAL,
283     IN PCSTR ProgressFormatText OPTIONAL,
284     IN PUPDATE_PROGRESS UpdateProgressProc OPTIONAL)
285 {
286     PPROGRESSBAR Bar;
287 
288     Bar = (PPROGRESSBAR)RtlAllocateHeap(ProcessHeap,
289                                         0,
290                                         sizeof(PROGRESSBAR));
291     if (Bar == NULL)
292         return NULL;
293 
294     Bar->Left = Left;
295     Bar->Top = Top;
296     Bar->Right = Right;
297     Bar->Bottom = Bottom;
298     Bar->TextTop = TextTop;
299     Bar->TextRight = TextRight;
300 
301     Bar->Width = Bar->Right - Bar->Left + 1;
302 
303     Bar->DoubleEdge = DoubleEdge;
304     Bar->ProgressColour = ProgressColour;
305     Bar->DescriptionText = DescriptionText;
306     Bar->ProgressFormatText = ProgressFormatText;
307 
308     Bar->UpdateProgressProc = UpdateProgressProc;
309 
310     /* Reset the progress bar counts and initially draw it */
311     ProgressSetStepCount(Bar, StepCount);
312 
313     return Bar;
314 }
315 
316 PPROGRESSBAR
317 CreateProgressBar(
318     IN SHORT Left,
319     IN SHORT Top,
320     IN SHORT Right,
321     IN SHORT Bottom,
322     IN SHORT TextTop,
323     IN SHORT TextRight,
324     IN BOOLEAN DoubleEdge,
325     IN PCSTR DescriptionText OPTIONAL)
326 {
327     /* Call the Ex variant of the function */
328     return CreateProgressBarEx(Left, Top, Right, Bottom,
329                                TextTop, TextRight,
330                                DoubleEdge,
331                                FOREGROUND_YELLOW | BACKGROUND_BLUE,
332                                0,
333                                DescriptionText,
334                                "%-3lu%%",
335                                UpdateProgressPercentage);
336 }
337 
338 VOID
339 DestroyProgressBar(
340     IN OUT PPROGRESSBAR Bar)
341 {
342     RtlFreeHeap(ProcessHeap, 0, Bar);
343 }
344 
345 
346 VOID
347 ProgressSetStepCount(
348     IN PPROGRESSBAR Bar,
349     IN ULONG StepCount)
350 {
351     Bar->CurrentStep = 0;
352     Bar->StepCount = StepCount;
353 
354     Bar->Progress = 0;
355     Bar->Pos = 0;
356 
357     DrawProgressBar(Bar);
358 }
359 
360 VOID
361 ProgressNextStep(
362     IN PPROGRESSBAR Bar)
363 {
364     ProgressSetStep(Bar, Bar->CurrentStep + 1);
365 }
366 
367 VOID
368 ProgressSetStep(
369     IN PPROGRESSBAR Bar,
370     IN ULONG Step)
371 {
372     COORD coPos;
373     DWORD Written;
374     ULONG NewPos;
375     CHAR TextBuffer[256];
376 
377     if (Step > Bar->StepCount)
378         return;
379 
380     Bar->CurrentStep = Step;
381 
382     /* Update the progress and redraw it if it has changed */
383     if (Bar->UpdateProgressProc &&
384         Bar->UpdateProgressProc(Bar, FALSE, TextBuffer, ARRAYSIZE(TextBuffer)))
385     {
386         coPos.X = Bar->Left + (Bar->Width - (USHORT)strlen(TextBuffer) + 1) / 2;
387         coPos.Y = Bar->Top;
388         WriteConsoleOutputCharacterA(StdOutput,
389                                      TextBuffer,
390                                      strlen(TextBuffer),
391                                      coPos,
392                                      &Written);
393     }
394 
395     /* Calculate the bar position */
396     NewPos = (((Bar->Width - 2) * 2 * Bar->CurrentStep + (Bar->StepCount / 2)) / Bar->StepCount);
397 
398     /* Redraw the bar if it has changed */
399     if (Bar->Pos != NewPos)
400     {
401         Bar->Pos = NewPos;
402 
403         for (coPos.Y = Bar->Top + 2; coPos.Y <= Bar->Bottom - 1; coPos.Y++)
404         {
405             coPos.X = Bar->Left + 1;
406             FillConsoleOutputCharacterA(StdOutput,
407                                         CharBlock,
408                                         Bar->Pos / 2,
409                                         coPos,
410                                         &Written);
411             coPos.X += Bar->Pos / 2;
412 
413             if (NewPos & 1)
414             {
415                 FillConsoleOutputCharacterA(StdOutput,
416                                             CharHalfBlock,
417                                             1,
418                                             coPos,
419                                             &Written);
420                 coPos.X++;
421             }
422 
423             if (coPos.X <= Bar->Right - 1)
424             {
425                 FillConsoleOutputCharacterA(StdOutput,
426                                             ' ',
427                                             Bar->Right - coPos.X,
428                                             coPos,
429                                             &Written);
430             }
431         }
432     }
433 }
434 
435 /* EOF */
436