1 /++
2 	Contains functions that might be useful in making new widgets, 
3 	like for formatting text.
4 +/
5 module qui.utils;
6 
7 import qui.qui;
8 
9 import utils.baseconv;
10 import utils.misc;
11 import std.conv : to;
12 
13 /// To scroll a line, by an xOffset
14 /// 
15 /// Can be used to scroll to right, or to left (by making xOffset negative).  
16 /// Can also be used to fill an empty line with empty space (`' '`) to make it fill width, if `line.length < width`
17 /// 
18 /// Arguments:
19 /// * `line` is the full line  
20 /// * `xOffset` is the number of characters scrolled right  
21 /// * `width` is the number of characters that are to be displayed
22 /// 
23 /// Returns: the text that should be displayed
24 dstring scrollHorizontal(dstring line, integer xOffset, uinteger width){
25 	dchar[] r;
26 	if (xOffset == 0){
27 		// in case it has to do nothing, 
28 		r = cast(dchar[])line[0 .. width > line.length ? line.length : width].dup;
29 	}else if (xOffset > 0){
30 		// only do something if it's not scrolled too far for the line to be even displayed
31 		if (xOffset < line.length){
32 			r = cast(dchar[])line[xOffset .. line.length].dup;
33 		}
34 	}else if (xOffset < 0){
35 		// only do something if it's not scrolled too far for the line to be even displayed
36 		if (cast(integer)(line.length) + xOffset > 0){
37 			r.length = xOffset * -1;
38 			r[] = ' ';
39 			r = r ~ cast(dchar[])line.dup;
40 		}
41 	}
42 	if (r.length < width){
43 		uinteger filledLength = r.length;
44 		r.length = width;
45 		r[filledLength .. r.length] = ' ';
46 	}else if (r.length > width){
47 		r.length = width;
48 	}
49 	return cast(dstring)r;
50 }
51 /// 
52 unittest{
53 	assert("0123456789".scrollHorizontal(5, 2) == "56");
54 	assert("0123456789".scrollHorizontal(0,10) == "0123456789");
55 	assert("0123456789".scrollHorizontal(10,4) == "    ");
56 	assert("0123456789".scrollHorizontal(-5,4) == "    ");
57 	assert("0123456789".scrollHorizontal(-5,6) == "     0");
58 	assert("0123456789".scrollHorizontal(-1,11) == " 0123456789");
59 	assert("0123456789".scrollHorizontal(-5,10) == "     01234");
60 }
61 
62 /// ditto
63 dchar[] scrollHorizontal(dchar[] line, integer xOffset, uinteger width){
64 	return cast(dchar[])(cast(dstring)line).scrollHorizontal(xOffset, width);
65 }
66 /// ditto
67 char[] scrollHorizontal(char[] line, integer xOffset, uinteger width){
68 	return cast(char[])(cast(dstring)line).scrollHorizontal(xOffset, width);
69 }
70 
71 /// Adjusts offset (aka _scrollX or _scrollY) in scrolling so the selected character is visible TODO: FIX THIS
72 /// 
73 /// Arguemnts:
74 /// * `selected` is the character on which the cursor is. If it's >lineWidth, `selected=lineWidth`
75 /// * `size` is the width/height (depending on if it's horizontal or vertical scrolling) of the space where the line is to be displayed
76 /// * `offset` is the variable storing the offset (_xOffset or _yOffset)
77 void adjustScrollingOffset(ref uinteger selected, uinteger size, uinteger lineWidth, ref uinteger offset){
78 	// if selected is outside size, it shouldn't be
79 	if (selected > lineWidth){
80 		selected = lineWidth;
81 	}
82 	// range of characters' index that's visible (1 is inclusive, 2 is not)
83 	uinteger visible1, visible2;
84 	visible1 = offset;
85 	visible2 = offset + size;
86 	if (selected < visible1 || selected >= visible2){
87 		if (selected < visible1){
88 			// scroll back
89 			offset = selected;
90 		}else if (selected >= visible2){
91 			// scroll ahead
92 			offset = selected+1 - (size);
93 		}
94 	}
95 }
96 
97 /// Center-aligns text
98 /// 
99 /// If `text.length > width`, the exceeding characters are removed
100 /// 
101 /// Returns: the text center aligned in a string
102 dstring centerAlignText(dstring text, uinteger width, dchar fill = ' '){
103 	dchar[] r;
104 	if (text.length < width){
105 		r.length = width;
106 		uinteger offset = (width - text.length)/2;
107 		r[0 .. offset] = fill;
108 		r[offset .. offset+text.length][] = text;
109 		r[offset+text.length .. r.length] = fill;
110 	}else{
111 		r = cast(dchar[])text[0 .. width].dup;
112 	}
113 	return cast(dstring)r;
114 }
115 ///
116 unittest{
117 	assert("qwr".centerAlignText(7) == "  qwr  ");
118 }
119 
120 /// To calculate size of widgets using their sizeRatio
121 deprecated uinteger ratioToRaw(uinteger selectedRatio, uinteger ratioTotal, uinteger total){
122 	uinteger r;
123 	r = cast(uinteger)((cast(float)selectedRatio/cast(float)ratioTotal)*total);
124 	return r;
125 }