From 0ceddb3569968dda1db07850b01e8cb4178fc3bf Mon Sep 17 00:00:00 2001 From: Marko Semet Date: Mon, 25 Dec 2017 18:47:45 +0100 Subject: [PATCH] Init project --- .gitignore | 5 + dub.json | 17 ++ source/drawofpages/draw.d | 68 +++++ source/drawofpages/elements/basetypes.d | 47 +++ source/drawofpages/elements/package.d | 64 +++++ source/drawofpages/gui/drawArea.d | 361 ++++++++++++++++++++++++ source/drawofpages/gui/mainWindow.d | 31 ++ source/drawofpages/gui/package.d | 35 +++ source/drawofpages/package.d | 38 +++ 9 files changed, 666 insertions(+) create mode 100644 dub.json create mode 100644 source/drawofpages/draw.d create mode 100644 source/drawofpages/elements/basetypes.d create mode 100644 source/drawofpages/elements/package.d create mode 100644 source/drawofpages/gui/drawArea.d create mode 100644 source/drawofpages/gui/mainWindow.d create mode 100644 source/drawofpages/gui/package.d create mode 100644 source/drawofpages/package.d diff --git a/.gitignore b/.gitignore index 74b926f..a318e98 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,8 @@ docs/ # Code coverage *.lst +/bin +/bin +/drawofpages.* +/drawofpages.* +/dub.selections.json diff --git a/dub.json b/dub.json new file mode 100644 index 0000000..92ec132 --- /dev/null +++ b/dub.json @@ -0,0 +1,17 @@ +{ + "authors": ["Marko Semet"], + "description": "Take notes with touchscreen input.", + "homepage": "https://marko10000.tk/redirect/drawofpages", + "dependencies": { + "gtk-d": "~>3.7.0", + "structuresd": "~>1.0.0-beta2" + }, + "license": "GPL-3.0", + "name": "drawofpages", + "sourcePaths": [ + "source" + ], + "targetName": "drawofpages", + "targetPath": "bin", + "targetType": "executable" +} diff --git a/source/drawofpages/draw.d b/source/drawofpages/draw.d new file mode 100644 index 0000000..a91d4ee --- /dev/null +++ b/source/drawofpages/draw.d @@ -0,0 +1,68 @@ +/* DrawOfPages: Take notes with touchscreen input. + * Copyright (C) 2017 Marko Semet(Marko10_000) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +module drawofpages.draw; + +private +{ + import structuresd.dimension; +} + +public alias Point2D = Point!2; +public alias Square = Cuboid!2; +public alias Circle = Sphere!2; + +public struct Color { + float r = 0; + float g = 0; + float b = 0; + float a = 1; + + public this(float r, float g, float b) + { + this.r = r; + this.g = g; + this.b = b; + this.a = 1; + } + public this(float r, float g, float b, float a) + { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + public enum RED = Color(1, 0, 0); + public enum GREEN = Color(0, 1, 0); + public enum BLUE = Color(0, 0, 1); + public enum YELLOW = Color(1, 1, 0); + public enum ORANGE = Color(1, 0.5, 0); + public enum CYAN = Color(0, 1, 1); + public enum PURPLE = Color(1, 0, 1); + public enum BLACK = Color(0, 0, 0); + public enum GRAY = Color(0.5, 0.5, 0.5); + public enum WHITE = Color(1, 1, 1); + public enum TRANSPARENT = Color(0, 0, 0, 0); +} + +public interface Draw +{ + void drawCirc(Point2D center, float radius, Color color); + void drawLine(Point2D from, Point2D to, double size, Color color); + void drawRect(Square square, Color color); + void redraw(); +} diff --git a/source/drawofpages/elements/basetypes.d b/source/drawofpages/elements/basetypes.d new file mode 100644 index 0000000..62089f4 --- /dev/null +++ b/source/drawofpages/elements/basetypes.d @@ -0,0 +1,47 @@ +/* DrawOfPages: Take notes with touchscreen input. + * Copyright (C) 2017 Marko Semet(Marko10_000) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +module drawofpages.elements.basetypes; + +private +{ + import std.algorithm.comparison; + import structuresd.dimension; +} + +public struct Line +{ + Point!2 a; + Point!2 b; + double size; + + @nogc + public pure nothrow this(Point!2 a, Point!2 b, double size) + { + this.a = a; + this.b = b; + this.size = size; + } + + @nogc + public pure nothrow T opCast(T)() if(is(T == Cuboid!2)) + { + Cuboid!2 result = Cuboid!2(this.a, this.b); + result.a -= Point!2([this.size, this.size]); + result.b += Point!2([this.size, this.size]); + return result; + } +} diff --git a/source/drawofpages/elements/package.d b/source/drawofpages/elements/package.d new file mode 100644 index 0000000..6a8c631 --- /dev/null +++ b/source/drawofpages/elements/package.d @@ -0,0 +1,64 @@ +/* DrawOfPages: Take notes with touchscreen input. + * Copyright (C) 2017 Marko Semet(Marko10_000) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +module drawofpages.elements; + +private +{ + import drawofpages.draw; + import drawofpages.elements.basetypes; + import drawofpages.gui; + import structuresd.dimension; + import structuresd.dimension.rtree; +} + +public class Interaction : GuiInteraction +{ + private Point2D c; + private Draw draw; + private RTree!(Line, Cuboid!2, 127, 64) data; + + public this(Draw draw) + { + this.draw = draw; + this.data = new RTree!(Line, Cuboid!2, 127, 64); + } + + public void down(Point2D point, CURSOR_TYPE cursor, double pressure, string cursorID) + { + this.c = point; + } + public void contin(Point2D point, CURSOR_TYPE cursor, double pressure, string cursorID) + { + this.draw.drawLine(this.c, point, 2, Color.BLUE); + this.data.insert(Line(Point!2([this.c.dims[0], this.c.dims[1]]), Point!2([point.dims[0], point.dims[1]]), 2)); + this.draw.redraw(); + this.c = point; + } + public void up(Point2D point, CURSOR_TYPE cursor, double pressure, string cursorID) + { + this.draw.drawLine(this.c, point, 2, Color.BLUE); + this.data.insert(Line(Point!2([this.c.dims[0], this.c.dims[1]]), Point!2([point.dims[0], point.dims[1]]), 2)); + this.draw.redraw(); + } + public void redraw(Square area, Draw target) + { + foreach(Line line; this.data.query(area)) + { + target.drawLine(line.a, line.b, line.size, Color.RED); + } + } +} diff --git a/source/drawofpages/gui/drawArea.d b/source/drawofpages/gui/drawArea.d new file mode 100644 index 0000000..760c280 --- /dev/null +++ b/source/drawofpages/gui/drawArea.d @@ -0,0 +1,361 @@ +/* DrawOfPages: Take notes with touchscreen input. + * Copyright (C) 2017 Marko Semet(Marko10_000) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +module drawofpages.gui.drawArea; + +private +{ + import cairo.Context; + import cairo.ImageSurface; + import cairo.Surface; + import drawofpages.draw; + import drawofpages.gui; + import gdk.Device; + import gtk.DrawingArea; + import gdk.Event; + import gtk.Widget; + import std.math; +} + +private final class DrawPart +{ + package ImageSurface surface; + private Context context; + + public Point2D pos; + public double scale; + public Square box; + + pragma(inline, true) + private pure nothrow void updatePoint(ref Point2D p) + { + p = (p - this.pos) * this.scale; + } + pragma(inline, true) + private pure nothrow void updateScale(ref double s) + { + s *= this.scale; + } + + public this(Point2D pos, double scale) + { + this.surface = ImageSurface.create(cairo_format_t.ARGB32, 512, 512); + this.context = Context.create(this.surface); + this.pos = pos; + this.scale = scale; + + // Set background color + this.context.setSourceRgb(1, 1, 1); + this.context.rectangle(0, 0, 512, 512); + this.context.fill(); + + // Box + this.box = Square(pos, pos + Point2D([512 / this.scale, 512 / this.scale])); + } + public ~this() + { + this.surface.destroy; + } + + public void drawLine(Point2D from, Point2D to, double size, Color color) + { + this.updatePoint(from); + this.updatePoint(to); + this.updateScale(size); + + this.context.setSourceRgba(color.r, color.g, color.b, color.a); + this.context.moveTo(from.dims[0], from.dims[1]); + this.context.setLineWidth(size); + this.context.lineTo(to.dims[0], to.dims[1]); + this.context.stroke(); + this.context.moveTo(0, 0); + } +} + +private final class PardDraw : Draw +{ + private DrawPart dp; + + public this(DrawPart dp) + { + this.dp = dp; + } + + public void drawCirc(Point2D center, float radius, Color color) + { + assert(false); + } + public void drawLine(Point2D from, Point2D to, double size, Color color) + { + dp.drawLine(from, to, size, color); + } + public void drawRect(Square square, Color color) + { + assert(false); // TODO: draw rect + } + public void redraw() {} +} + +private final class Grid +{ + public DrawPart[][] parts; + + public Point2D rel; + public Point2D relZero; + public double scale; + public long x; + public long y; + public ulong width; + public ulong height; + + private pure void calcRelZero() + { + this.relZero = Point2D([this.x, this.y]) * this.scale; + } + + public this() + { + this.scale = 1; + this.x = -256; + this.y = -256; + this.rel = Point2D([this.x, this.y]); + this.width = 0; + this.height = 0; + this.parts = new DrawPart[][0]; + this.calcRelZero(); + } + + public void resize(ulong width, ulong height, GuiInteraction interatcion) + { + synchronized + { + ulong partsX = (width - this.x) / 512 + ((width - this.x) % 512 == 0 ? 0 : 1); + ulong partsY = (height - this.y) / 512 + ((height - this.y) % 512 == 0 ? 0 : 1); + DrawPart[][] newParts = new DrawPart[][partsY]; + for(ulong y = 0; y < partsY; y++) + { + if(this.parts.length > y) + { + // Use old data + DrawPart[] old = this.parts[y]; + DrawPart[] tmp = new DrawPart[partsX]; + for(ulong x = 0; x < partsX; x++) + { + if(old.length > x) + { + tmp[x] = old[x]; + } + else + { + tmp[x] = new DrawPart(Point2D([x, y]) * (512 / this.scale) + this.rel, this.scale); + interatcion.redraw(tmp[x].box, new PardDraw(tmp[x])); + } + } + newParts[y] = tmp; + } + else + { + // Gen new array + DrawPart[] tmp = new DrawPart[partsX]; + for(ulong x = 0; x < partsX; x++) + { + tmp[x] = new DrawPart(Point2D([x, y]) * (512 / this.scale) + this.rel, this.scale); + interatcion.redraw(tmp[x].box, new PardDraw(tmp[x])); + } + newParts[y] = tmp; + } + } + + // Set new data + { + DrawPart[][] tmp = this.parts; + this.parts = newParts; + tmp.destroy; + this.width = width; + this.height = height; + } + } + } +} + +private final class DrawHandler : Draw +{ + private DrawElement de; + package Grid grid; + + public this(DrawElement de) + { + this.de = de; + this.grid = new Grid(); + } + + public void drawCirc(Point2D center, float radius, Color color) + { + assert(false); + } + public void drawLine(Point2D from, Point2D to, double size, Color color) + { + foreach(DrawPart[] dps; this.grid.parts) + { + foreach(DrawPart dp; dps) + { + dp.drawLine(from, to, size, color); + } + } + } + public void drawRect(Square square, Color color) + { + assert(false); + } + public void redraw() + { + this.de.queueDraw(); + } + + package void _draw(Context cr) + { + for(long i = 0; i < this.grid.parts.length; i++) + { + DrawPart[] io = this.grid.parts[i]; + for(long j = 0; j < io.length; j++) + { + cr.setSourceSurface(io[j].surface, (j * 512) + (cast(long) this.grid.x), (i * 512) + (cast(long) this.grid.y)); + cr.rectangle((j * 512) + (cast(long) this.grid.x), (i * 512) + (cast(long) this.grid.y), 512, 512); + cr.fill(); + } + } + cr.save(); + cr.destroy; + } +} + +public class DrawElement : DrawingArea +{ + private DrawHandler dh; + private GuiInteraction interatcion = null; + private bool hasDown = false; + + private static pure CURSOR_TYPE _getCursor(GdkInputSource gis) + { + if(gis == GdkInputSource.PEN) + { + return CURSOR_TYPE.PEN; + } + else if(gis == GdkInputSource.ERASER) + { + return CURSOR_TYPE.ERASER; + } + else if(gis == GdkInputSource.MOUSE) + { + return CURSOR_TYPE.MOUSE; + } + return CURSOR_TYPE.HAND; + } + + private struct _pointerData + { + string deviceID = null; + double pressure; + CURSOR_TYPE ctype; + + this(Device device) + { + if(device.getDeviceType() != GdkDeviceType.MASTER) + { + this.deviceID = device.getProductId(); + } + GdkAxisFlags axes = device.getAxes(); + this.pressure = axes.PRESSURE; + this.ctype = _getCursor(device.getSource()); + } + } + + public this() + { + super(); + this.dh = new DrawHandler(this); + this.addOnDraw(delegate bool(Context cr, Widget w) { + synchronized + { + this._draw(cr); + } + return false; + }); + this.addOnButtonPress(delegate bool(Event e, Widget w) { + if(this.interatcion is null) + { + return false; + } + + GdkEventButton* geb = e.button(); + _pointerData tmp = _pointerData(e.getDevice()); + synchronized + { + this.interatcion.down(Point2D([geb.x, geb.y]), tmp.ctype, tmp.pressure, tmp.deviceID); + } + this.hasDown = true; + return false; + }); + this.addOnMotionNotify(delegate bool(Event e, Widget w) { + if((this.interatcion is null) || (!this.hasDown)) + { + return false; + } + + GdkEventMotion* motion = e.motion(); + _pointerData tmp = _pointerData(e.getDevice()); + synchronized + { + this.interatcion.contin(Point2D([motion.x, motion.y]), tmp.ctype, tmp.pressure, tmp.deviceID); + } + return false; + }); + this.addOnButtonRelease(delegate bool(Event e, Widget w) { + if(this.interatcion is null) + { + return false; + } + + GdkEventButton* geb = e.button(); + _pointerData tmp = _pointerData(e.getDevice()); + this.hasDown = false; + synchronized + { + this.interatcion.up(Point2D([geb.x, geb.y]), tmp.ctype, tmp.pressure, tmp.deviceID); + } + return false; + }); + this.addOnSizeAllocate(delegate void(Allocation alloc, Widget w) { + synchronized(this) + { + this.dh.grid.resize(alloc.width, alloc.height, this.interatcion); + } + }); + } + + private void _draw(Context cr) + { + this.dh._draw(cr); + } + public DrawHandler getDrawHanlder() + { + return this.dh; + } + public ref GuiInteraction getGuiInteraction() + { + return this.interatcion; + } +} diff --git a/source/drawofpages/gui/mainWindow.d b/source/drawofpages/gui/mainWindow.d new file mode 100644 index 0000000..4a31aac --- /dev/null +++ b/source/drawofpages/gui/mainWindow.d @@ -0,0 +1,31 @@ +/* DrawOfPages: Take notes with touchscreen input. + * Copyright (C) 2017 Marko Semet(Marko10_000) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +module drawofpages.gui.mainWindow; + +private +{ + import gtk.Window; + import gtk.MainWindow; +} + +public class DBMain : MainWindow +{ + public this() + { + super("Drawbook"); + } +} diff --git a/source/drawofpages/gui/package.d b/source/drawofpages/gui/package.d new file mode 100644 index 0000000..02bd74c --- /dev/null +++ b/source/drawofpages/gui/package.d @@ -0,0 +1,35 @@ +/* DrawOfPages: Take notes with touchscreen input. + * Copyright (C) 2017 Marko Semet(Marko10_000) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +module drawofpages.gui; + +private import drawofpages.draw; + +public enum CURSOR_TYPE +{ + MOUSE, + PEN, + ERASER, + HAND +} + +public interface GuiInteraction +{ + void down(Point2D point, CURSOR_TYPE cursor, double pressure, string cursorID); + void contin(Point2D point, CURSOR_TYPE cursor, double pressure, string cursorID); + void up(Point2D point, CURSOR_TYPE cursor, double pressure, string cursorID); + void redraw(Square square, Draw target); +} diff --git a/source/drawofpages/package.d b/source/drawofpages/package.d new file mode 100644 index 0000000..9e293ac --- /dev/null +++ b/source/drawofpages/package.d @@ -0,0 +1,38 @@ +/* DrawOfPages: Take notes with touchscreen input. + * Copyright (C) 2017 Marko Semet(Marko10_000) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +module drawofpages; + +private import drawofpages.elements; +private import drawofpages.gui.drawArea; +private import drawofpages.draw; +private import gtk.MainWindow; +private import gtk.Main; + + +void main(string[] args) +{ + Main.init(args); + MainWindow win = new MainWindow("Hello World"); + win.setDefaultSize(800, 600); + DrawElement de = new DrawElement(); + de.getDrawHanlder().drawLine(Point2D([50, 50]), Point2D([100, 100]), 5, Color.RED); + de.getGuiInteraction() = new Interaction(de.getDrawHanlder()); + win.add(de); + de.queueDraw(); + win.showAll(); + Main.run(); +}