2daedit/source/app.d

327 lines
7.2 KiB
D
Raw Normal View History

2014-11-16 22:48:56 +00:00
import std.stdio;
2014-11-18 10:46:07 +00:00
import std.file;
2014-11-16 22:48:56 +00:00
import std.string;
import std.conv : to;
import gtk.Main;
import gtk.MainWindow;
import gtk.TreeView;
import gtk.ListStore;
import gtk.TreeViewColumn;
import gtk.TreeIter;
import gtk.Label;
import gtk.Entry;
import gtk.CellRenderer;
import gtk.CellRendererText;
2014-11-17 22:25:13 +00:00
import gtk.VBox;
2014-11-18 13:06:26 +00:00
import gtk.Statusbar;
2014-11-17 14:12:57 +00:00
import gtk.Button;
2014-11-18 13:53:05 +00:00
import gtk.ScrolledWindow;
2014-11-18 10:46:07 +00:00
2014-11-18 13:06:26 +00:00
import gtk.HBox;
2014-11-18 10:46:07 +00:00
2014-11-16 22:48:56 +00:00
void main(string[] args)
{
Main.init(args);
2014-11-17 14:49:53 +00:00
//Window
2014-11-16 23:05:09 +00:00
auto window = new MainWindow("2DA-Edit");
2014-11-16 22:48:56 +00:00
2014-11-17 22:25:13 +00:00
auto cont = new VBox(false, 0);
window.add(cont);
2014-11-18 14:20:39 +00:00
cont.setSizeRequest(300, 200);
2014-11-17 22:25:13 +00:00
2014-11-18 10:46:07 +00:00
auto buttonSave = new Button("document-save-symbolic", GtkIconSize.MENU);
2014-11-18 13:53:05 +00:00
buttonSave.setTooltipText("Save");
2014-11-18 10:46:07 +00:00
auto buttonOpen = new Button("document-open-symbolic", GtkIconSize.MENU);
2014-11-18 13:53:05 +00:00
buttonOpen.setTooltipText("Open 2DA");
2014-11-18 13:06:26 +00:00
auto buttonInsert = new Button("format-text-direction-ltr-symbolic", GtkIconSize.SMALL_TOOLBAR);
2014-11-18 13:53:05 +00:00
buttonInsert.setTooltipText("Insert row after");
2014-11-18 13:06:26 +00:00
auto buttonDelete = new Button("user-trash-symbolic", GtkIconSize.SMALL_TOOLBAR);
2014-11-18 13:53:05 +00:00
buttonDelete.setTooltipText("Delete row");
2014-11-18 13:06:26 +00:00
auto buttonRenumber = new Button("view-list-symbolic", GtkIconSize.SMALL_TOOLBAR);
2014-11-18 13:53:05 +00:00
buttonRenumber.setTooltipText("Renumber all rows");
2014-11-18 10:46:07 +00:00
2014-11-17 22:25:13 +00:00
version(Windows){
//Menu bar
import gtk.HBox;
auto cont2 = new HBox(false, 0);
cont.packStart(cont2, false, false, 0);
2014-11-18 10:46:07 +00:00
cont2.packStart(buttonOpen, false, false, 0);
cont2.packEnd(buttonSave, false, false, 0);
2014-11-17 22:25:13 +00:00
}
else{
//Header bar
import gtk.HeaderBar;
auto header = new HeaderBar();
window.setTitlebar(header);
header.setTitle("2DAEdit");
header.setProperty("show-close-button", true);
2014-11-16 22:48:56 +00:00
2014-11-18 10:46:07 +00:00
header.packStart(buttonOpen);
header.packEnd(buttonSave);
}
2014-11-16 22:48:56 +00:00
2014-11-18 13:06:26 +00:00
//Status bar
auto statusbar = new HBox(false, 0);
cont.packEnd(statusbar, false, false, 5);
statusbar.packStart(buttonRenumber, false, false, 5);
statusbar.packStart(buttonInsert, false, false, 5);
statusbar.packStart(buttonDelete, false, false, 5);
2014-11-17 14:49:53 +00:00
//TreeView to display database
2014-11-18 13:53:05 +00:00
auto scroll = new ScrolledWindow(PolicyType.AUTOMATIC, PolicyType.AUTOMATIC);
cont.packEnd(scroll, true, true, 0);
2014-11-18 10:46:07 +00:00
auto tree = new TreeView();
2014-11-18 13:53:05 +00:00
scroll.add(tree);
2014-11-17 14:49:53 +00:00
2014-11-16 22:48:56 +00:00
tree.setHeadersVisible(true);
tree.setEnableSearch(true);
2014-11-17 10:50:11 +00:00
tree.setProperty("enable-grid-lines", GtkTreeViewGridLines.VERTICAL);
2014-11-17 12:52:50 +00:00
tree.setProperty("tooltip-column", 0);
tree.setProperty("reorderable", true);
tree.setProperty("headers-clickable", true);
2014-11-18 10:46:07 +00:00
//Configure button callbacks
buttonSave.addOnClicked((Button){
Save(tree);
});
buttonOpen.addOnClicked((Button){
import gtk.Dialog;
import gtk.FileChooserDialog;
auto fc = new FileChooserDialog("Open 2DA", window, FileChooserAction.OPEN);
auto res = fc.run();
if(res==GtkResponseType.OK){
string filename = fc.getFilename();
version(Windows) Open(filename, tree, cast(Object)window);
else Open(filename, tree, cast(Object)header);
2014-11-18 10:46:07 +00:00
}
fc.destroy();
});
2014-11-18 13:41:47 +00:00
buttonInsert.addOnClicked((Button){
TreeIter it = tree.getSelectedIter();
auto store = cast(ListStore)tree.getModel();
if(store !is null){
store.insertAfter(it, it);
store.setValue(it, 0, 0);
foreach(i ; 1..store.getNColumns()){
store.setValue(it, cast(int)i, "_");
}
}
});
buttonDelete.addOnClicked((Button){
TreeIter it = tree.getSelectedIter();
auto store = cast(ListStore)tree.getModel();
if(store !is null)
store.remove(it);
});
buttonRenumber.addOnClicked((Button){
auto store = cast(ListStore)tree.getModel();
if(store !is null){
TreeIter it = new TreeIter();
if(store.getIterFirst(it)){
int id = 0;
do{
store.setValue(it, 0, id++);
}while(store.iterNext(it));
}
}
});
2014-11-18 10:46:07 +00:00
//Open if exists
if(args.length>=2 && exists(args[1])){
version(Windows) Open(args[1], tree, cast(Object)window);
else Open(args[1], tree, cast(Object)header);
2014-11-18 10:46:07 +00:00
}
window.showAll();
Main.run();
}
void Save(ref TreeView tree){
auto store = cast(ListStore)tree.getModel();
if(store !is null){
2014-11-18 14:20:39 +00:00
auto file = File(openedFile, "w");
foreach(i ; 0..tree.getNColumns)
file.write(tree.getColumn(i).getTitle, "\t");
file.write("\n");
2014-11-18 10:46:07 +00:00
TreeIter it = new TreeIter();
2014-11-18 13:41:47 +00:00
if(store.getIterFirst(it)){
do{
2014-11-18 14:20:39 +00:00
file.write(store.getValueInt(it, 0));
2014-11-18 13:41:47 +00:00
foreach(i ; 1..store.getNColumns()){
2014-11-18 14:20:39 +00:00
file.write("\t\"",store.getValueString(it, i),"\"");
2014-11-18 13:41:47 +00:00
}
2014-11-18 14:20:39 +00:00
file.write("\n");
2014-11-18 13:41:47 +00:00
}while(store.iterNext(it));
2014-11-18 14:20:39 +00:00
file.flush();
file.close();
writeln("File written: ",openedFile);
2014-11-18 13:41:47 +00:00
}
2014-11-18 10:46:07 +00:00
}
else
writeln("Nothing to save !");
}
2014-11-18 14:20:39 +00:00
string openedFile;
void Open(string file, ref TreeView tree, Object header){
2014-11-18 10:46:07 +00:00
auto twoda = new TwoDA(file);
2014-11-18 14:20:39 +00:00
openedFile = file;
version(Windows) (cast(Window)header).setTitle(file);
else{
import gtk.HeaderBar;
(cast(HeaderBar)header).setSubtitle(file);
}
2014-11-18 10:46:07 +00:00
//Delete old store
auto oldstore = cast(ListStore)tree.getModel();
if(oldstore !is null)
oldstore.destroy();
//Remove columns from TreeView
foreach(i ; 0..tree.getNColumns)
tree.removeColumn(tree.getColumn(0));
//Set store types
GType type[];
2014-11-18 13:23:38 +00:00
type~=GType.INT;
foreach(i;1..twoda.header.length)type~=GType.STRING;
2014-11-18 10:46:07 +00:00
//Create new store
auto store = new ListStore(type);
tree.setModel(store);
2014-11-17 14:49:53 +00:00
//Setup TreeView columns
2014-11-16 22:48:56 +00:00
foreach(index, s ; twoda.header){
2014-11-18 13:23:38 +00:00
CellRendererText cr = new CellRendererText();
cr.setProperty("editable", true);
2014-11-16 22:48:56 +00:00
if(index==0){
2014-11-17 11:10:47 +00:00
cr.setProperty("background-rgba", cast(ulong)(new GdkRGBA(0.36, 0.13, 0.4, 1.0)));
2014-11-17 10:50:11 +00:00
cr.setProperty("background-set", true);
2014-11-18 13:23:38 +00:00
cr.addOnEdited((string path, string newval, CellRendererText crt){
try{
int n = newval.to!int;
TreeIter t = new TreeIter(tree.getModel(), path);
store.setValue(t, cast(int)crt.getData("colnumber"), n);
}
catch(Exception e){
writeln("Not a number");
}
2014-11-17 10:50:11 +00:00
2014-11-18 13:23:38 +00:00
});
}
else{
2014-11-17 10:50:11 +00:00
cr.addOnEdited((string path, string newval, CellRendererText crt){
TreeIter t = new TreeIter(tree.getModel(), path);
store.setValue(t, cast(int)crt.getData("colnumber"), newval);
});
2014-11-16 22:48:56 +00:00
}
2014-11-18 13:23:38 +00:00
2014-11-17 10:50:11 +00:00
cr.setData("colnumber", cast(void*)cast(int)index);
2014-11-16 22:48:56 +00:00
2014-11-17 10:50:11 +00:00
auto col = new TreeViewColumn(s, cr, "text", cast(int)index);
2014-11-16 22:48:56 +00:00
col.setResizable(true);
2014-11-17 14:49:53 +00:00
//col.setReorderable(true);
2014-11-16 22:48:56 +00:00
tree.appendColumn(col);
}
2014-11-17 14:49:53 +00:00
//Fill database
2014-11-17 10:50:11 +00:00
TreeIter iter = new TreeIter();
2014-11-16 22:48:56 +00:00
for(int i=0 ; i<=twoda.lastLine ; i++){
2014-11-17 10:50:11 +00:00
store.append(iter);
2014-11-16 22:48:56 +00:00
store.setValue(iter, 0, i);
if(i in twoda.values){
foreach(index, v ; twoda.values[i]){
2014-11-17 10:50:11 +00:00
store.setValue(iter, cast(int)index+1, v);
2014-11-16 22:48:56 +00:00
}
}
else{
foreach(index ; 1..twoda.header.length){
2014-11-17 10:50:11 +00:00
store.setValue(iter, cast(int)index+1, "_");
2014-11-16 22:48:56 +00:00
}
}
}
2014-11-17 14:49:53 +00:00
//Autosize columns
2014-11-16 22:48:56 +00:00
tree.columnsAutosize();
2014-11-18 13:06:26 +00:00
tree.setSizeRequest(50, 50);
2014-11-16 22:48:56 +00:00
}
class TwoDA{
import std.regex;
import std.file;
this(string filepath){
lastLine = 0;
foreach(index, line ; readText(filepath).splitLines()){
string data[];
auto results = matchAll(line, rgxField);
foreach(res ; results){
string s;
if(res[0][0]=='"') data~= res[2];
else data~= res[1];
}
if(index==0){
header = data;
//writeln(header);
}
else{
int nLine = data[0].to!int;
values[nLine] = data[1..$];
//writeln(values[nLine]);
if(nLine > lastLine)
lastLine = nLine;
}
}
}
string[] header;
string[][uint] values;
uint lastLine;
enum rgxField = ctRegex!"(?:\\b([^\\s]+?)\\b|\"([^\"]+?)\")";
}