Added resources.
This commit is contained in:
parent
11080210c1
commit
710379c19f
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<gresources>
|
||||||
|
<gresource prefix="/ui">
|
||||||
|
<file>todo-ui.glade</file>
|
||||||
|
</gresource>
|
||||||
|
</gresources>
|
95
source/app.d
95
source/app.d
|
@ -1,16 +1,99 @@
|
||||||
import std.stdio;
|
|
||||||
|
|
||||||
import model;
|
import model;
|
||||||
import view : setupUI;
|
import std.stdio;
|
||||||
|
|
||||||
import gtk.MainWindow;
|
import gtk.MainWindow;
|
||||||
import gtk.Main;
|
import gtk.Main;
|
||||||
|
import gtk.Builder;
|
||||||
|
import gtk.Application;
|
||||||
|
import gtk.ApplicationWindow;
|
||||||
|
import gtk.Entry;
|
||||||
|
import gtk.Box;
|
||||||
|
import gtk.ListBox;
|
||||||
|
import gtk.ListBoxRow;
|
||||||
|
import gtk.Label;
|
||||||
|
import gtk.CheckButton;
|
||||||
|
import gtk.ToggleButton;
|
||||||
|
import gtk.Button;
|
||||||
|
|
||||||
|
class ToDoItemWidget : Box {
|
||||||
|
this(ToDoItem item, ToDoModel todoModel) {
|
||||||
|
super(GtkOrientation.HORIZONTAL, 5);
|
||||||
|
CheckButton button = new CheckButton();
|
||||||
|
button.setActive(item.checked);
|
||||||
|
button.addOnToggled(delegate(ToggleButton b) {
|
||||||
|
item.checked = b.getActive();
|
||||||
|
});
|
||||||
|
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(StockID.REMOVE);
|
||||||
|
removeButton.addOnClicked(delegate(Button b) {
|
||||||
|
todoModel.removeItem(item.priority);
|
||||||
|
});
|
||||||
|
this.packEnd(removeButton, false, false, 0);
|
||||||
|
|
||||||
|
if (todoModel.canIncrement(item)) {
|
||||||
|
Button upButton = new Button(StockID.GO_UP, delegate(Button b) {
|
||||||
|
todoModel.incrementPriority(item);
|
||||||
|
});
|
||||||
|
this.packEnd(upButton, false, false, 0);
|
||||||
|
}
|
||||||
|
if (todoModel.canDecrement(item)) {
|
||||||
|
Button downButton = new Button(StockID.GO_DOWN, delegate(Button b) {
|
||||||
|
todoModel.decrementPriority(item);
|
||||||
|
});
|
||||||
|
this.packEnd(downButton, false, false, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.packEnd(label, true, true, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry taskEntry;
|
||||||
|
ListBox taskList;
|
||||||
|
|
||||||
|
ToDoModel todoModel;
|
||||||
|
|
||||||
void main(string[] args) {
|
void main(string[] args) {
|
||||||
Main.init(args);
|
Main.init(args);
|
||||||
MainWindow window = new MainWindow("To-Do");
|
Builder builder = new Builder("todo-ui.glade");
|
||||||
window.setDefaultSize(300, 500);
|
|
||||||
setupUI(window);
|
builder.addCallbackSymbol("onAddTask", &addTask);
|
||||||
|
builder.addCallbackSymbol("onWindowDestroy", &onWindowDestroy);
|
||||||
|
builder.addCallbackSymbol("onQuitMenuActivated", &onWindowDestroy);
|
||||||
|
builder.connectSignals(null);
|
||||||
|
|
||||||
|
taskList = cast(ListBox) builder.getObject("taskList");
|
||||||
|
taskEntry = cast(Entry) builder.getObject("addTaskEntry");
|
||||||
|
|
||||||
|
todoModel = new ToDoModel();
|
||||||
|
import std.functional : toDelegate;
|
||||||
|
todoModel.addListener(ModelUpdateListener.of(toDelegate(&itemsUpdated)));
|
||||||
|
|
||||||
|
ApplicationWindow window = cast(ApplicationWindow) builder.getObject("window");
|
||||||
window.showAll();
|
window.showAll();
|
||||||
Main.run();
|
Main.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void itemsUpdated(ToDoItem[] items) {
|
||||||
|
taskList.removeAll();
|
||||||
|
foreach (item; items) {
|
||||||
|
auto widget = new ToDoItemWidget(item, todoModel);
|
||||||
|
auto row = new ListBoxRow();
|
||||||
|
row.add(widget);
|
||||||
|
taskList.add(row);
|
||||||
|
}
|
||||||
|
taskList.showAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern (C) void addTask() {
|
||||||
|
todoModel.addItem(taskEntry.getText());
|
||||||
|
taskEntry.setText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
extern (C) void onWindowDestroy() {
|
||||||
|
Main.quit();
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,92 @@
|
||||||
module model;
|
module model;
|
||||||
|
|
||||||
struct ToDoItem {
|
class ToDoItem {
|
||||||
string text;
|
string text;
|
||||||
int priority;
|
int priority;
|
||||||
|
bool checked;
|
||||||
|
this(string text, int priority, bool checked) {
|
||||||
|
this.text = text;
|
||||||
|
this.priority = priority;
|
||||||
|
this.checked = checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ModelUpdateListener {
|
||||||
|
void itemsUpdated(ToDoItem[] items);
|
||||||
|
|
||||||
|
static ModelUpdateListener of(void delegate(ToDoItem[]) dg) {
|
||||||
|
return new class ModelUpdateListener {
|
||||||
|
void itemsUpdated(ToDoItem[] items) {
|
||||||
|
dg(items);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ToDoModel {
|
||||||
|
private ToDoItem[] items;
|
||||||
|
private ModelUpdateListener[] listeners;
|
||||||
|
|
||||||
|
void addListener(ModelUpdateListener listener) {
|
||||||
|
listeners ~= listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addItem(string text) {
|
||||||
|
addItem(new ToDoItem(text, 1_000_000, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void addItem(ToDoItem item) {
|
||||||
|
items ~= item;
|
||||||
|
normalizePrio();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeItem(int prio) {
|
||||||
|
import std.algorithm;
|
||||||
|
size_t idx = prio - 1; // Assume prio is normalized to start at 1.
|
||||||
|
items = items.remove(idx);
|
||||||
|
normalizePrio();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canIncrement(ToDoItem item) {
|
||||||
|
return item.priority > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void incrementPriority(ToDoItem item) {
|
||||||
|
size_t idx = item.priority - 1;
|
||||||
|
if (idx == 0) return;
|
||||||
|
ToDoItem higher = items[idx - 1];
|
||||||
|
item.priority -= 1;
|
||||||
|
higher.priority += 1;
|
||||||
|
items[idx - 1] = item;
|
||||||
|
items[idx] = higher;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canDecrement(ToDoItem item) {
|
||||||
|
return item.priority < items.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void decrementPriority(ToDoItem item) {
|
||||||
|
size_t idx = item.priority - 1;
|
||||||
|
if (idx + 1 >= items.length) return;
|
||||||
|
ToDoItem lower = items[idx + 1];
|
||||||
|
item.priority += 1;
|
||||||
|
lower.priority -= 1;
|
||||||
|
items[idx + 1] = item;
|
||||||
|
items[idx] = lower;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void normalizePrio() {
|
||||||
|
int prio = 1;
|
||||||
|
foreach (item; items) {
|
||||||
|
item.priority = prio++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyListeners() {
|
||||||
|
foreach (l; listeners) l.itemsUpdated(this.items);
|
||||||
|
}
|
||||||
}
|
}
|
105
source/view.d
105
source/view.d
|
@ -1,105 +0,0 @@
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,234 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Generated with glade 3.22.2 -->
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="3.10"/>
|
||||||
|
<object class="GtkApplicationWindow" id="window">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="window_position">center</property>
|
||||||
|
<signal name="destroy" handler="onWindowDestroy" swapped="no"/>
|
||||||
|
<child type="titlebar">
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkMenuBar">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkMenuItem">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">_File</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<child type="submenu">
|
||||||
|
<object class="GtkMenu">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="newMenuItem">
|
||||||
|
<property name="label">gtk-new</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="openMenuItem">
|
||||||
|
<property name="label">gtk-open</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem">
|
||||||
|
<property name="label">gtk-save</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem">
|
||||||
|
<property name="label">gtk-save-as</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSeparatorMenuItem">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="quitMenuItem">
|
||||||
|
<property name="label">gtk-quit</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="activate" handler="onQuitMenuActivated" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkMenuItem">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">_Edit</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<child type="submenu">
|
||||||
|
<object class="GtkMenu">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem">
|
||||||
|
<property name="label">gtk-cut</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem">
|
||||||
|
<property name="label">gtk-copy</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem">
|
||||||
|
<property name="label">gtk-paste</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem">
|
||||||
|
<property name="label">gtk-delete</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkMenuItem">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">_Help</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<child type="submenu">
|
||||||
|
<object class="GtkMenu">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem">
|
||||||
|
<property name="label">gtk-about</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="shadow_type">in</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkViewport">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBox" id="taskList">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="selection_mode">none</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="addTaskEntry">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="addTaskButton">
|
||||||
|
<property name="label">gtk-add</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<property name="always_show_image">True</property>
|
||||||
|
<signal name="clicked" handler="onAddTask" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="pack_type">end</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
Loading…
Reference in New Issue