1 /** 2 * Consoleur: a package for interaction with character-oriented terminal emulators 3 * 4 * Copyright: Maxim Freck, 2017. 5 * Authors: Maxim Freck <maxim@freck.pp.ru> 6 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 */ 8 module consoleur.cli.progress; 9 10 class Progress 11 { 12 import std.stdio: stderr, stdout, writef, writeln; 13 import consoleur.core, consoleur.cursor, consoleur.screen, consoleur.cli.util; 14 public: 15 16 /******* 17 * Constructor 18 * 19 * Params: 20 * title = Progress bar title 21 */ 22 this(string title = "") 23 { 24 stdout.flush(); 25 savePosition(); 26 setTitle(title); 27 } 28 29 /******* 30 * Sets new progress bar title 31 * 32 * Params: 33 * title = Progress bar title 34 */ 35 void setTitle(string title) 36 { 37 this.title = title; 38 } 39 40 /******* 41 * Sets new progress bar percents 42 * 43 * Params: 44 * pct = Percent 45 */ 46 void setPercent(int pct) 47 { 48 if (isAttyOut()) { 49 setPercentTty(pct); 50 } else { 51 setPercentRedirected(pct); 52 } 53 } 54 55 private: 56 enum FILLED_PERCENT = 0; 57 enum EMPTY_PERCENT = 1; 58 enum OPEN_BAR = 2; 59 enum CLOSE_BAR = 3; 60 61 string title; 62 ubyte filledColor = 0; 63 int row; 64 65 wchar[4] blocks = ['█', '░', '┨', '┠']; 66 67 wchar[] spinner = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; 68 69 ///Spinner examples 70 //wchar[] spinner = ['▖','▘','▝','▗']; 71 //wchar[] spinner = ['▌','▀','▐','▄']; 72 //wchar[] spinner = ['▉','▊','▋','▌','▍','▎','▏','▎','▍','▌','▋','▊','▉']; 73 //wchar[] spinner = ['▁','▃','▄','▅','▆','▇','█','▇','▆','▅','▄','▃']; 74 //wchar[] spinner = ['☱','☲','☴']; 75 //wchar[] spinner = ['⠋','⠙','⠹','⠸','⠼','⠴','⠦','⠧','⠇','⠏']; 76 //wchar[] spinner = ['⠋','⠙','⠚','⠞','⠖','⠦','⠴','⠲','⠳','⠓']; 77 //wchar[] spinner = ['⠄','⠆','⠇','⠋','⠙','⠸','⠰','⠠','⠰','⠸','⠙','⠋','⠇','⠆']; 78 //wchar[] spinner = ['⠋','⠙','⠚','⠒','⠂','⠂','⠒','⠲','⠴','⠦','⠖','⠒','⠐','⠐','⠒','⠓','⠋']; 79 //wchar[] spinner = ['⠁','⠉','⠙','⠚','⠒','⠂','⠂','⠒','⠲','⠴','⠤','⠄','⠄','⠤','⠴','⠲','⠒','⠂','⠂','⠒','⠚','⠙','⠉','⠁']; 80 //wchar[] spinner = ['⠈','⠉','⠋','⠓','⠒','⠐','⠐','⠒','⠖','⠦','⠤','⠠','⠠','⠤','⠦','⠖','⠒','⠐','⠐','⠒','⠓','⠋','⠉','⠈']; 81 //wchar[] spinner = ['⠁','⠁','⠉','⠙','⠚','⠒','⠂','⠂','⠒','⠲','⠴','⠤','⠄','⠄','⠤','⠠','⠠','⠤','⠦','⠖','⠒','⠐','⠐','⠒','⠓','⠋','⠉','⠈','⠈']; 82 //wchar[] spinner = ['⢄','⢂','⢁','⡁','⡈','⡐','⡠']; 83 //wchar[] spinner = ['⢹','⢺','⢼','⣸','⣇','⡧','⡗','⡏']; 84 //wchar[] spinner = ['⣾','⣽','⣻','⢿','⡿','⣟','⣯','⣷']; 85 //wchar[] spinner = ['⠁','⠂','⠄','⡀','⢀','⠠','⠐','⠈']; 86 87 void setPercentTty(int pct) 88 { 89 if (pct < 0) pct = 0; 90 if (pct > 100) pct = 100; 91 92 93 if (row > 0) { 94 moveCursorTo(Point(row, 1)); 95 } else { 96 saveCursorPosition(); 97 } 98 99 uint width = cast(uint)(getScreenSize().col - 11 - title.length); 100 uint done = cast(uint)((width*pct)/100); 101 102 writef(" %s %c %c%s%s%c%3s%% ", 103 title, 104 progressSymbol(pct), 105 blocks[OPEN_BAR], 106 repeat(blocks[FILLED_PERCENT], done), 107 repeat(blocks[EMPTY_PERCENT], width - done), 108 blocks[CLOSE_BAR], 109 pct, 110 ); 111 stdout.flush(); 112 113 if (row <= 0) restoreCursorPosition(); 114 } 115 116 void setPercentRedirected(int pct) 117 { 118 import std.conv: to; 119 writeln(title~to!string(pct)); 120 } 121 122 void savePosition() 123 { 124 if (!isAttyOut()) return; 125 126 import std.stdio: writeln; 127 128 immutable pos = getCursorPosition(); 129 row = pos.row; 130 if (pos.col > 1) { 131 auto window = getScreenSize(); 132 if(window.row == row) { 133 writeln(); 134 } else { 135 row+=1; 136 } 137 } 138 } 139 140 wchar progressSymbol(int percent) 141 { 142 return spinner[percent % spinner.length]; 143 } 144 }