diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..66c032c --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +.dub +docs.json +__dummy.html +docs/ +/todo-d +todo-d.so +todo-d.dylib +todo-d.dll +todo-d.a +todo-d.lib +todo-d-test-* +*.exe +*.o +*.obj +*.lst diff --git a/README.md b/README.md index b3b2679..fe63ac4 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ # todo-d A simple to-do list, implemented as a desktop application in D. + +This project is built using GTK-D, and as such, please ensure that you've installed the necessary prerequisites to be able to build and run this application. diff --git a/dub.json b/dub.json new file mode 100644 index 0000000..7edeced --- /dev/null +++ b/dub.json @@ -0,0 +1,12 @@ +{ + "authors": [ + "Andrew Lalis" + ], + "copyright": "Copyright © 2022, Andrew Lalis", + "dependencies": { + "gtk-d": "~>3.10.0" + }, + "description": "A simple to-do list, implemented as a desktop application in D.", + "license": "MIT", + "name": "todo-d" +} \ No newline at end of file diff --git a/dub.selections.json b/dub.selections.json new file mode 100644 index 0000000..fd7260a --- /dev/null +++ b/dub.selections.json @@ -0,0 +1,6 @@ +{ + "fileVersion": 1, + "versions": { + "gtk-d": "3.10.0" + } +} diff --git a/source/app.d b/source/app.d new file mode 100644 index 0000000..c73ff1b --- /dev/null +++ b/source/app.d @@ -0,0 +1,16 @@ +import std.stdio; + +import model; +import view : setupUI; + +import gtk.MainWindow; +import gtk.Main; + +void main(string[] args) { + Main.init(args); + MainWindow window = new MainWindow("To-Do"); + window.setDefaultSize(300, 500); + setupUI(window); + window.showAll(); + Main.run(); +} diff --git a/source/model.d b/source/model.d new file mode 100644 index 0000000..ea01d83 --- /dev/null +++ b/source/model.d @@ -0,0 +1,6 @@ +module model; + +struct ToDoItem { + string text; + int priority; +} \ No newline at end of file diff --git a/source/view.d b/source/view.d new file mode 100644 index 0000000..b545e0a --- /dev/null +++ b/source/view.d @@ -0,0 +1,105 @@ +module view; + +import model; + +import gtk.Box; +import gtk.ListBox; +import gtk.ListBoxRow; +import gtk.Label; +import gtk.CheckButton; +import gtk.Window; +import gtk.ScrolledWindow; +import gtk.Entry; +import gtk.Button; + +// Yes, I use global items for my application. + +ListBox todoList; +Entry todoEntry; + +ToDoItem[] items = []; + +void setupUI(Window w) { + todoList = new ListBox(); + todoEntry = new Entry(); + + auto vbox = new Box(GtkOrientation.VERTICAL, 5); + + todoList.setSelectionMode(GtkSelectionMode.NONE); + + vbox.packStart(new ScrolledWindow(todoList), true, true, 5); + + auto addBox = new Box(GtkOrientation.HORIZONTAL, 5); + addBox.packStart(todoEntry, true, true, 0); + Button addButton = new Button("Add"); + addButton.addOnClicked(delegate(Button b) {addItem();}); + addBox.packEnd(addButton, false, false, 0); + vbox.packEnd(addBox, false, false, 0); + + w.add(vbox); +} + +void addItem() { + import std.algorithm; + import std.string; + string text = todoEntry.getText().strip; + if (text.length == 0) return; + int maxPrio = -1_000_000; + foreach (item; items) { + maxPrio = max(maxPrio, item.priority); + } + ToDoItem newItem = ToDoItem(text, maxPrio + 1); + items ~= newItem; + todoEntry.setText(""); + normalizePriorities(); + refreshList(); +} + +void normalizePriorities() { + int prio = 1; + foreach (item; items) { + item.priority = prio++; + } +} + +void removeItem(int prio) { + import std.algorithm; + import std.array; + ToDoItem[] newItems = items.filter!(item => item.priority != prio).array; + items = newItems; + normalizePriorities(); + refreshList(); +} + +void refreshList() { + todoList.removeAll(); + foreach (item; items) { + auto widget = new ToDoItemWidget(item); + auto row = new ListBoxRow(); + row.add(widget); + todoList.add(row); + } + todoList.showAll(); +} + +class ToDoItemWidget : Box { + private ToDoItem item; + + this(ToDoItem item) { + super(GtkOrientation.HORIZONTAL, 5); + this.item = item; + CheckButton button = new CheckButton(); + Label label = new Label(item.text); + label.setLineWrap(true); + label.setHalign(GtkAlign.START); + label.setValign(GtkAlign.CENTER); + this.packStart(button, false, false, 0); + + Button removeButton = new Button("Remove"); + removeButton.addOnClicked(delegate(Button b) { + removeItem(item.priority); + }); + this.packEnd(removeButton, false, false, 0); + this.packEnd(label, true, true, 0); + } +} \ No newline at end of file