1 /**
2 Copyright: Copyright (c) 2015-2017 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 module voxelman.utils.linebuffer;
7 
8 struct LineBuffer
9 {
10 	import derelict.imgui.imgui;
11 	import std.array : empty;
12 	import std.format : formattedWrite;
13 	import voxelman.container.buffer;
14 
15 	Buffer!char lines;
16 	Buffer!size_t lineSizes;
17 	bool scrollToBottom;
18 
19 	void clear()
20 	{
21 		lines.clear();
22 		lineSizes.clear();
23 	}
24 
25 	void put(in char[] str)
26 	{
27 		import std.regex : ctRegex, splitter;
28 		import std.algorithm : map;
29 		import std.range;
30 
31 		if (str.empty) return;
32 		auto splittedLines = splitter(str, ctRegex!"(\r\n|\r|\n|\v|\f)");
33 
34 		foreach(first; splittedLines.takeOne())
35 		{
36 			lines.put(first);
37 			if (!lineSizes.data.empty)
38 			{
39 				lineSizes.data[$-1] += first.length;
40 			}
41 			else
42 			{
43 				lineSizes.put(first.length);
44 			}
45 		}
46 
47 		// process other lines
48 		foreach(line; splittedLines.drop(1))
49 		{
50 			++lineSizes.data[$-1];
51 			lines.put("\n");
52 			lines.put(line);
53 			lineSizes.put(line.length);
54 		}
55 
56 		lines.stealthPut('\0');
57 
58 		scrollToBottom = true;
59 	}
60 
61 	void putf(Args...)(const(char)[] fmt, Args args)
62 	{
63 		formattedWrite(&this, fmt, args);
64 	}
65 
66 	void putfln(Args...)(const(char)[] fmt, Args args)
67 	{
68 		formattedWrite(&this, fmt, args);
69 		put("\n");
70 	}
71 
72 	void putln(const(char)[] str)
73 	{
74 		put(str);
75 		put("\n");
76 	}
77 
78 	void draw()
79 	{
80 		char* lineStart = lines.data.ptr;
81 		foreach(lineSize; lineSizes.data)
82 		if (lineSize > 0)
83 		{
84 			igPushTextWrapPos(igGetWindowContentRegionWidth());
85 			igTextUnformatted(lineStart, lineStart+lineSize);
86 			igPopTextWrapPos();
87 			lineStart += lineSize;
88 		}
89 
90 		if (scrollToBottom)
91 			igSetScrollHere(1.0f);
92 		scrollToBottom = false;
93 	}
94 
95 	void drawSelectable()
96 	{
97 		igPushStyleVarVec(ImGuiStyleVar_FramePadding, ImVec2(6,6));
98 
99 		ImVec2 size;
100 		igGetContentRegionAvail(&size);
101 		size.x -= 12;
102 		size.y -= 12;
103 
104 		igPushStyleColor(ImGuiCol_FrameBg, ImVec4(0, 0, 0, 0));
105 		if (lines.data.length)
106 			igInputTextMultiline("##multiline", lines.data.ptr, lines.data.length, size, ImGuiInputTextFlags_ReadOnly);
107 		else
108 		{
109 			char[1] str;
110 			igInputTextMultiline("##multiline", str.ptr, 0, size, ImGuiInputTextFlags_ReadOnly);
111 		}
112 		igPopStyleColor();
113 
114 		igPopStyleVar();
115 
116 		if (scrollToBottom)
117 			igSetScrollHere(1.0f);
118 		scrollToBottom = false;
119 	}
120 }