1 /**
2 Grimoire
3 Copyright (c) 2017 Enalye
4 
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising
7 from the use of this software.
8 
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute
11 it freely, subject to the following restrictions:
12 
13 	1. The origin of this software must not be misrepresented;
14 	   you must not claim that you wrote the original software.
15 	   If you use this software in a product, an acknowledgment
16 	   in the product documentation would be appreciated but
17 	   is not required.
18 
19 	2. Altered source versions must be plainly marked as such,
20 	   and must not be misrepresented as being the original software.
21 
22 	3. This notice may not be removed or altered from any source distribution.
23 */
24 
25 module ui.save;
26 
27 import std.file;
28 import std.path;
29 import std.conv: to;
30 
31 import core.all;
32 import common.all;
33 
34 import ui.widget;
35 import ui.modal;
36 import ui.button;
37 import ui.list.vlist;
38 import ui.inputfield;
39 
40 private {
41 	InStream _loadedStream = null;
42 }
43 
44 void setSaveWindow(Widget callbackWidget, string callbackId, OutStream stream, string path, string extension) {
45 	path = buildNormalizedPath(absolutePath(path));
46 	if(!extension.length)
47 		throw new Exception("Cannot save without a file extension");
48 	auto modal = new SaveWindow(stream, path, extension);
49 	modal.setCallback(callbackWidget, callbackId);
50 	setModalWindow(modal);
51 }
52 
53 void setLoadWindow(Widget callbackWidget, string callbackId, string path, string extension) {
54 	InStream stream = new InStream;
55 	path = buildNormalizedPath(absolutePath(path));
56 	if(!extension.length)
57 		throw new Exception("Cannot save without a file extension");
58 	auto modal = new LoadWindow(stream, path, extension);
59 	modal.setCallback(callbackWidget, callbackId);
60 	_loadedStream = null;
61 	setModalWindow(modal);
62 }
63 
64 InStream getLoadedStream() {
65 	return _loadedStream;
66 }
67 
68 class SaveWindow: ModalWindow {
69 	private {
70 		OutStream _stream;
71 		string _path, _extension;
72 		InputField _inputField;
73 	}
74 
75 	this(OutStream stream, string path, string extension) {
76 		super("Saving", Vec2f(250f, 25f));
77 		_stream = stream;
78 		_path = path;
79 		_extension = extension;
80 		_inputField = new InputField(layout.size, "Sans Titre", true);
81 		layout.addChild(_inputField);
82 	}
83 
84 	override void onEvent(Event event) {
85 		super.onEvent(event);
86 		if(event.type == EventType.Callback) {
87 			if(event.id == "apply") {
88 				string fullPath = buildPath(_path, setExtension(_inputField.text, _extension));
89 				if(!isValidPath(fullPath))
90 					throw new Exception("Error saving file: invalid path \'" ~ fullPath ~ "\'");
91 				write(fullPath, _stream.data);
92 				triggerCallback();
93 			}
94 		}
95 	}
96 
97 	override void update(float deltaTime) {
98 		super.update(deltaTime);
99 		applyBtn.isLocked = (_inputField.text.length == 0L);
100 	}
101 }
102 
103 class LoadWindow: ModalWindow {
104 	private {
105 		InStream _stream;
106 		string[] _files;
107 		VList _list;
108 	}
109 
110 	this(InStream stream, string path, string extension) {
111 		super("Loading", Vec2f(250f, 200f));
112 		_stream = stream;
113 		_list = new VList(layout.size);
114 		foreach(file; dirEntries(path, "*." ~ extension, SpanMode.depth)) {
115 			_files ~= file;
116 			string relativeFileName = stripExtension(baseName(file));
117 			auto btn = new TextButton(relativeFileName);
118 			_list.addChild(btn);
119 		}
120 		layout.addChild(_list);
121 	}
122 
123 	override void onEvent(Event event) {
124 		super.onEvent(event);
125 
126 		if(event.type == EventType.Callback) {
127 			if(event.id == "apply") {
128 				if(_list.selected < _files.length) {
129 					string fileName = _files[_list.selected];
130 					if(!exists(fileName))
131 						throw new Exception("Error saving file: invalid path \'" ~ fileName ~ "\'");
132 					_stream.set(cast(ubyte[])(read(fileName)));
133 					if(_stream.length)
134 						_loadedStream = _stream;
135 					else
136 						_loadedStream = null;
137 					triggerCallback();
138 				}
139 			}
140 		}
141 	}
142 
143 	override void update(float deltaTime) {
144 		super.update(deltaTime);
145 		applyBtn.isLocked = (_files.length == 0L);
146 	}
147 }