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.misc;
10 import std.conv : to;
11 
12 /// To scroll a line, by an xOffset
13 ///
14 /// Can be used to scroll to right, or to left (by making xOffset negative).
15 /// Can also be used to fill an empty line with empty space (`' '`) to make it fill width, if `line.length < width`
16 ///
17 /// Arguments:
18 /// * `line` is the full line
19 /// * `xOffset` is the number of characters scrolled right
20 /// * `width` is the number of characters that are to be displayed
21 ///
22 /// Returns: the text that should be displayed
23 dstring scrollHorizontal(dstring line, int xOffset, uint width, dchar spaceChar = ' '){
24 	dchar[] r;
25 	r.length = width;
26 	r[] = spaceChar;
27 	for (uint i = xOffset < 0 ? -xOffset : 0; i + xOffset < line.length && i < width; i ++)
28 		r[i] = line[i + xOffset];
29 	return cast(dstring)r;
30 }
31 ///
32 unittest{
33 	assert("0123456789".scrollHorizontal(5, 2) == "56");
34 	assert("0123456789".scrollHorizontal(0,10) == "0123456789");
35 	assert("0123456789".scrollHorizontal(10,4) == "    ");
36 	assert("0123456789".scrollHorizontal(-5,4) == "    ");
37 	assert("0123456789".scrollHorizontal(-5,6) == "     0");
38 	assert("0123456789".scrollHorizontal(-1,11) == " 0123456789");
39 	assert("0123456789".scrollHorizontal(-5,10) == "     01234");
40 }
41 
42 /// ditto
43 dchar[] scrollHorizontal(dchar[] line, int xOffset, uint width){
44 	return cast(dchar[])(cast(dstring)line).scrollHorizontal(xOffset, width);
45 }
46 /// ditto
47 char[] scrollHorizontal(char[] line, int xOffset, uint width){
48 	return cast(char[])(cast(dstring)line).scrollHorizontal(xOffset, width);
49 }
50 
51 /// Adjusts offset (aka _scrollX or _scrollY) in scrolling so the selected character is visible TODO: FIX THIS
52 ///
53 /// Arguemnts:
54 /// * `selected` is the character on which the cursor is. If it's >lineWidth, `selected=lineWidth`
55 /// * `size` is the width/height (depending on if it's horizontal or vertical scrolling) of the space where the line is to be displayed
56 /// * `offset` is the variable storing the offset (_xOffset or _yOffset)
57 void adjustScrollingOffset(ref uint selected, uint size, uint lineWidth, ref uint offset){
58 	// if selected is outside size, it shouldn't be
59 	if (selected > lineWidth)
60 		selected = lineWidth;
61 	// range of characters' index that's visible (1 is inclusive, 2 is not)
62 	uint visible1, visible2;
63 	visible1 = offset;
64 	visible2 = offset + size;
65 	if (selected < visible1 || selected >= visible2){
66 		if (selected < visible1){
67 			// scroll back
68 			offset = selected;
69 		}else if (selected >= visible2){
70 			// scroll ahead
71 			offset = selected+1 - size;
72 		}
73 	}
74 }
75 
76 /// Center-aligns text
77 ///
78 /// If `text.length > width`, the exceeding characters are removed
79 ///
80 /// Returns: the text center aligned in a string
81 dstring centerAlignText(dstring text, uint width, dchar fill = ' '){
82 	dchar[] r;
83 	r.length = width;
84 	if (text.length < width){
85 		uint offset = (width - cast(uint)text.length)/2;
86 		r[0 .. offset] = fill;
87 		r[offset .. offset+text.length][] = text;
88 		r[offset+text.length .. r.length] = fill;
89 	}else
90 		r[] = text[0 .. r.length];
91 	return cast(dstring)r;
92 }
93 ///
94 unittest{
95 	assert("qwr".centerAlignText(7) == "  qwr  ");
96 	assert("qwerty".centerAlignText(6) == "qwerty");
97 	assert("qwerty".centerAlignText(5) == "qwert");
98 }
99 
100 /// Returns: size after considering minimum and maximum allowed
101 ///
102 /// if `min==0`, it is ignored. if `max==0`, it is ignored
103 uint getLimitedSize(uint calculated, uint min, uint max){
104 	if (min && calculated < min)
105 		return min;
106 	if (max && calculated > max)
107 		return max;
108 	return calculated;
109 }